/[svn]/linuxsampler/trunk/src/engines/common/InstrumentScriptVMFunctions.cpp
ViewVC logotype

Diff of /linuxsampler/trunk/src/engines/common/InstrumentScriptVMFunctions.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2629 by schoenebeck, Thu Jun 12 18:25:11 2014 UTC revision 2879 by schoenebeck, Tue Apr 19 14:07:53 2016 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (c) 2014 Christian Schoenebeck   * Copyright (c) 2014-2016 Christian Schoenebeck
3   *   *
4   * http://www.linuxsampler.org   * http://www.linuxsampler.org
5   *   *
# Line 22  namespace LinuxSampler { Line 22  namespace LinuxSampler {
22          int note = args->arg(0)->asInt()->evalInt();          int note = args->arg(0)->asInt()->evalInt();
23          int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;          int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;
24          int sampleoffset = (args->argsCount() >= 3) ? args->arg(2)->asInt()->evalInt() : 0;          int sampleoffset = (args->argsCount() >= 3) ? args->arg(2)->asInt()->evalInt() : 0;
25          int duration = (args->argsCount() >= 4) ? args->arg(3)->asInt()->evalInt() : 0; //TODO: once -1 is implemented, it might be a better default value instead of 0          int duration = (args->argsCount() >= 4) ? args->arg(3)->asInt()->evalInt() : 0; //TODO: -1 might be a better default value instead of 0
26    
27          if (note < 0 || note > 127) {          if (note < 0 || note > 127) {
28              errMsg("play_note(): argument 1 is an invalid note number");              errMsg("play_note(): argument 1 is an invalid note number");
29              return errorResult(-1);              return errorResult(0);
30          }          }
31    
32          if (velocity < 0 || velocity > 127) {          if (velocity < 0 || velocity > 127) {
33              errMsg("play_note(): argument 2 is an invalid velocity value");              errMsg("play_note(): argument 2 is an invalid velocity value");
34              return errorResult(-1);              return errorResult(0);
35          }          }
36    
37          if (sampleoffset < 0) {          if (sampleoffset < 0) {
38              errMsg("play_note(): argument 3 may not be a negative sample offset");              errMsg("play_note(): argument 3 may not be a negative sample offset");
39              return errorResult(-1);              return errorResult(0);
40          } else if (sampleoffset != 0) {          } else if (sampleoffset != 0) {
41              wrnMsg("play_note(): argument 3 does not support a sample offset other than 0 yet");              wrnMsg("play_note(): argument 3 does not support a sample offset other than 0 yet");
42          }          }
43    
44          if (duration < -1) {          if (duration < -1) {
45              errMsg("play_note(): argument 4 must be a duration value of at least -1 or higher");              errMsg("play_note(): argument 4 must be a duration value of at least -1 or higher");
46              return errorResult(-1);              return errorResult(0);
         } else if (duration == -1) {  
             wrnMsg("play_note(): argument 4 does not support special value -1 as duration yet");  
         } else if (duration != 0) {  
             wrnMsg("play_note(): argument 4 does not support any other value as 0 as duration yet");  
47          }          }
48    
49          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
50              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
51    
52          Event e = m_vm->m_event->cause;          Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
53            e.Init(); // clear IDs
54          e.Type = Event::type_note_on;          e.Type = Event::type_note_on;
55          e.Param.Note.Key = note;          e.Param.Note.Key = note;
56          e.Param.Note.Velocity = velocity;          e.Param.Note.Velocity = velocity;
57          memset(&e.Format, 0, sizeof(e.Format)); // init format speific stuff with zero          // make this new note dependent to the life time of the original note
58            if (duration == -1) {
59                if (m_vm->currentVMEventHandler()->eventHandlerType() != VM_EVENT_HANDLER_NOTE) {
60                    errMsg("play_note(): -1 for argument 4 may only be used for note event handlers");
61                    return errorResult(0);
62                }
63                e.Param.Note.ParentNoteID = m_vm->m_event->cause.Param.Note.ID;
64            }
65    
66            const note_id_t id = pEngineChannel->ScheduleNoteMicroSec(&e, 0);
67    
68          int id = pEngineChannel->ScheduleEvent(&e, duration);          // if a duration is supplied (and note-on event was scheduled
69            // successfully above), then schedule a subsequent note-off event
70            if (id && duration > 0) {
71                e.Type = Event::type_note_off;
72                e.Param.Note.Velocity = 127;
73                pEngineChannel->ScheduleEventMicroSec(&e, duration);
74            }
75    
76          return successResult(id);          // even if id is null, don't return an errorResult() here, because that
77            // would abort the script, and under heavy load it may be considerable
78            // that ScheduleNoteMicroSec() fails above, so simply ignore that
79            return successResult( ScriptID::fromNoteID(id) );
80      }      }
81    
82      InstrumentScriptVMFunction_set_controller::InstrumentScriptVMFunction_set_controller(InstrumentScriptVM* parent)      InstrumentScriptVMFunction_set_controller::InstrumentScriptVMFunction_set_controller(InstrumentScriptVM* parent)
# Line 76  namespace LinuxSampler { Line 91  namespace LinuxSampler {
91          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
92              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
93    
94          Event e = m_vm->m_event->cause;          Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
95          memset(&e.Format, 0, sizeof(e.Format)); // init format speific stuff with zero          e.Init(); // clear IDs
96          if (controller == CTRL_TABLE_IDX_AFTERTOUCH) {          if (controller == CTRL_TABLE_IDX_AFTERTOUCH) {
97              e.Type = Event::type_channel_pressure;              e.Type = Event::type_channel_pressure;
98              e.Param.ChannelPressure.Value = value & 127;              e.Param.ChannelPressure.Value = value & 127;
# Line 93  namespace LinuxSampler { Line 108  namespace LinuxSampler {
108              return errorResult();              return errorResult();
109          }          }
110    
111          int id = pEngineChannel->ScheduleEvent(&e, 0);          const event_id_t id = pEngineChannel->ScheduleEventMicroSec(&e, 0);
112    
113          return successResult(id);          // even if id is null, don't return an errorResult() here, because that
114            // would abort the script, and under heavy load it may be considerable
115            // that ScheduleEventMicroSec() fails above, so simply ignore that
116            return successResult( ScriptID::fromEventID(id) );
117      }          }    
118    
119      InstrumentScriptVMFunction_ignore_event::InstrumentScriptVMFunction_ignore_event(InstrumentScriptVM* parent)      InstrumentScriptVMFunction_ignore_event::InstrumentScriptVMFunction_ignore_event(InstrumentScriptVM* parent)
# Line 103  namespace LinuxSampler { Line 121  namespace LinuxSampler {
121      {      {
122      }      }
123    
124      VMFnResult* InstrumentScriptVMFunction_ignore_event::exec(VMFnArgs* args) {      bool InstrumentScriptVMFunction_ignore_event::acceptsArgType(int iArg, ExprType_t type) const {
125          int id = args->arg(0)->asInt()->evalInt();          return type == INT_EXPR || type == INT_ARR_EXPR;
126          if (id < 0) {      }
             wrnMsg("ignore_event(): argument may not be a negative event ID");  
             return successResult();  
         }  
127    
128        VMFnResult* InstrumentScriptVMFunction_ignore_event::exec(VMFnArgs* args) {
129          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
130              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);                  static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
131    
132          pEngineChannel->IgnoreEvent(id);          if (args->arg(0)->exprType() == INT_EXPR) {
133                const ScriptID id = args->arg(0)->asInt()->evalInt();
134                if (!id) {
135                    wrnMsg("ignore_event(): event ID argument may not be zero");
136                    // not errorResult(), because that would abort the script, not intentional in this case
137                    return successResult();
138                }
139                pEngineChannel->IgnoreEventByScriptID(id);
140            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
141                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
142                for (int i = 0; i < ids->arraySize(); ++i) {
143                    const ScriptID id = ids->evalIntElement(i);    
144                    pEngineChannel->IgnoreEventByScriptID(id);
145                }
146            }
147    
148          return successResult();          return successResult();
149      }      }
# Line 124  namespace LinuxSampler { Line 154  namespace LinuxSampler {
154      }      }
155    
156      VMFnResult* InstrumentScriptVMFunction_ignore_controller::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_ignore_controller::exec(VMFnArgs* args) {
157          int id = (args->argsCount() >= 1) ? args->arg(0)->asInt()->evalInt() : m_vm->m_event->id;          const ScriptID id = (args->argsCount() >= 1) ? args->arg(0)->asInt()->evalInt() : m_vm->m_event->id;
158          if (id < 0) {          if (!id && args->argsCount() >= 1) {
159              wrnMsg("ignore_controller(): argument may not be a negative event ID");              wrnMsg("ignore_controller(): event ID argument may not be zero");
160              return successResult();              return successResult();
161          }          }
162    
163          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
164              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
165    
166          pEngineChannel->IgnoreEvent(id);          pEngineChannel->IgnoreEventByScriptID(id);
167    
168          return successResult();          return successResult();
169      }      }
# Line 143  namespace LinuxSampler { Line 173  namespace LinuxSampler {
173      {      {
174      }      }
175    
176        bool InstrumentScriptVMFunction_note_off::acceptsArgType(int iArg, ExprType_t type) const {
177            return type == INT_EXPR || type == INT_ARR_EXPR;
178        }
179    
180      VMFnResult* InstrumentScriptVMFunction_note_off::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_note_off::exec(VMFnArgs* args) {
181          int id = args->arg(0)->asInt()->evalInt();          AbstractEngineChannel* pEngineChannel =
182                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
183    
184          int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;          int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;
185            if (velocity < 0 || velocity > 127) {
186                errMsg("note_off(): argument 2 is an invalid velocity value");
187                return errorResult();
188            }
189    
190          if (id < 0) {          if (args->arg(0)->exprType() == INT_EXPR) {
191              wrnMsg("note_off(): argument 1 may not be a negative event ID");              const ScriptID id = args->arg(0)->asInt()->evalInt();  
192              return successResult();              if (!id) {
193                    wrnMsg("note_off(): note ID for argument 1 may not be zero");
194                    return successResult();
195                }
196                if (!id.isNoteID()) {
197                    wrnMsg("note_off(): argument 1 is not a note ID");
198                    return successResult();
199                }
200    
201                NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
202                if (!pNote) return successResult();
203    
204                Event e = pNote->cause;
205                e.Init(); // clear IDs
206                e.CopyTimeFrom(m_vm->m_event->cause); // set fragment time for "now"
207                e.Type = Event::type_note_off;
208                e.Param.Note.Velocity = velocity;
209    
210                pEngineChannel->ScheduleEventMicroSec(&e, 0);
211            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
212                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
213                for (int i = 0; i < ids->arraySize(); ++i) {
214                    const ScriptID id = ids->evalIntElement(i);
215                    if (!id || !id.isNoteID()) continue;
216    
217                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
218                    if (!pNote) continue;
219    
220                    Event e = pNote->cause;
221                    e.Init(); // clear IDs
222                    e.CopyTimeFrom(m_vm->m_event->cause); // set fragment time for "now"
223                    e.Type = Event::type_note_off;
224                    e.Param.Note.Velocity = velocity;
225    
226                    pEngineChannel->ScheduleEventMicroSec(&e, 0);
227                }
228          }          }
229    
230          if (velocity < 0 || velocity > 127) {          return successResult();
231              errMsg("note_off(): argument 2 is an invalid velocity value");      }
232    
233        InstrumentScriptVMFunction_set_event_mark::InstrumentScriptVMFunction_set_event_mark(InstrumentScriptVM* parent)
234            : m_vm(parent)
235        {
236        }
237    
238        VMFnResult* InstrumentScriptVMFunction_set_event_mark::exec(VMFnArgs* args) {
239            const ScriptID id = args->arg(0)->asInt()->evalInt();
240            const int groupID = args->arg(1)->asInt()->evalInt();
241    
242            if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
243                errMsg("set_event_mark(): argument 2 is an invalid group id");
244              return errorResult();              return errorResult();
245          }          }
246    
247          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
248              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
249    
250          RTList<Event>::Iterator itEvent = pEngineChannel->pEngine->EventByID(id);          // check if the event/note still exists
251          if (!itEvent) return successResult();          switch (id.type()) {
252                case ScriptID::EVENT: {
253                    RTList<Event>::Iterator itEvent = pEngineChannel->pEngine->EventByID( id.eventID() );
254                    if (!itEvent) return successResult();
255                    break;
256                }
257                case ScriptID::NOTE: {
258                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
259                    if (!pNote) return successResult();
260                    break;
261                }
262            }
263    
264            pEngineChannel->pScript->eventGroups[groupID].insert(id);
265    
266          Event e = *itEvent;          return successResult();
267          e.Type = Event::type_note_off;      }
         e.Param.Note.Velocity = velocity;  
         memset(&e.Format, 0, sizeof(e.Format)); // init format speific stuff with zero  
268    
269          int releaseEventID = pEngineChannel->ScheduleEvent(&e, 0);      InstrumentScriptVMFunction_delete_event_mark::InstrumentScriptVMFunction_delete_event_mark(InstrumentScriptVM* parent)
270            : m_vm(parent)
271        {
272        }
273    
274        VMFnResult* InstrumentScriptVMFunction_delete_event_mark::exec(VMFnArgs* args) {
275            const ScriptID id = args->arg(0)->asInt()->evalInt();
276            const int groupID = args->arg(1)->asInt()->evalInt();
277    
278            if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
279                errMsg("delete_event_mark(): argument 2 is an invalid group id");
280                return errorResult();
281            }
282    
283            AbstractEngineChannel* pEngineChannel =
284                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
285    
286            pEngineChannel->pScript->eventGroups[groupID].erase(id);
287    
288          return successResult();          return successResult();
289      }      }
290    
291        InstrumentScriptVMFunction_by_marks::InstrumentScriptVMFunction_by_marks(InstrumentScriptVM* parent)
292            : m_vm(parent)
293        {
294        }
295    
296        int InstrumentScriptVMFunction_by_marks::Result::arraySize() const {
297            return eventGroup->size();
298        }
299    
300        int InstrumentScriptVMFunction_by_marks::Result::evalIntElement(uint i) {
301            return (*eventGroup)[i];
302        }
303    
304        VMFnResult* InstrumentScriptVMFunction_by_marks::errorResult() {
305            m_result.eventGroup = NULL;
306            m_result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
307            return &m_result;
308        }
309    
310        VMFnResult* InstrumentScriptVMFunction_by_marks::successResult(EventGroup* eventGroup) {
311            m_result.eventGroup = eventGroup;
312            m_result.flags = STMT_SUCCESS;
313            return &m_result;
314        }
315    
316        VMFnResult* InstrumentScriptVMFunction_by_marks::exec(VMFnArgs* args) {
317            int groupID = args->arg(0)->asInt()->evalInt();
318    
319            if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
320                errMsg("by_marks(): argument is an invalid group id");
321                return errorResult();
322            }
323    
324            AbstractEngineChannel* pEngineChannel =
325                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
326    
327            return successResult( &pEngineChannel->pScript->eventGroups[groupID] );
328        }
329    
330  } // namespace LinuxSampler  } // namespace LinuxSampler

Legend:
Removed from v.2629  
changed lines
  Added in v.2879

  ViewVC Help
Powered by ViewVC