/[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 2630 by schoenebeck, Fri Jun 13 15:01:06 2014 UTC revision 2953 by schoenebeck, Sat Jul 16 11:24:39 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 12  Line 12 
12  #include "../AbstractEngineChannel.h"  #include "../AbstractEngineChannel.h"
13    
14  namespace LinuxSampler {  namespace LinuxSampler {
15        
16        // play_note() function
17    
18      InstrumentScriptVMFunction_play_note::InstrumentScriptVMFunction_play_note(InstrumentScriptVM* parent)      InstrumentScriptVMFunction_play_note::InstrumentScriptVMFunction_play_note(InstrumentScriptVM* parent)
19          : m_vm(parent)          : m_vm(parent)
# Line 22  namespace LinuxSampler { Line 24  namespace LinuxSampler {
24          int note = args->arg(0)->asInt()->evalInt();          int note = args->arg(0)->asInt()->evalInt();
25          int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;          int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;
26          int sampleoffset = (args->argsCount() >= 3) ? args->arg(2)->asInt()->evalInt() : 0;          int sampleoffset = (args->argsCount() >= 3) ? args->arg(2)->asInt()->evalInt() : 0;
27          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
28    
29          if (note < 0 || note > 127) {          if (note < 0 || note > 127) {
30              errMsg("play_note(): argument 1 is an invalid note number");              errMsg("play_note(): argument 1 is an invalid note number");
31              return errorResult(-1);              return errorResult(0);
32          }          }
33    
34          if (velocity < 0 || velocity > 127) {          if (velocity < 0 || velocity > 127) {
35              errMsg("play_note(): argument 2 is an invalid velocity value");              errMsg("play_note(): argument 2 is an invalid velocity value");
36              return errorResult(-1);              return errorResult(0);
37          }          }
38    
39          if (sampleoffset < 0) {          if (sampleoffset < 0) {
40              errMsg("play_note(): argument 3 may not be a negative sample offset");              errMsg("play_note(): argument 3 may not be a negative sample offset");
41              return errorResult(-1);              return errorResult(0);
42          } else if (sampleoffset != 0) {          } else if (sampleoffset != 0) {
43              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");
44          }          }
45    
46          if (duration < -1) {          if (duration < -1) {
47              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");
48              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");  
49          }          }
50    
51          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
52              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
53    
54          Event e = m_vm->m_event->cause;          Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
55          e.Type = Event::type_note_on;          e.Init(); // clear IDs
56            e.Type = Event::type_play_note;
57          e.Param.Note.Key = note;          e.Param.Note.Key = note;
58          e.Param.Note.Velocity = velocity;          e.Param.Note.Velocity = velocity;
59          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
60            if (duration == -1) {
61                if (m_vm->currentVMEventHandler()->eventHandlerType() != VM_EVENT_HANDLER_NOTE) {
62                    errMsg("play_note(): -1 for argument 4 may only be used for note event handlers");
63                    return errorResult(0);
64                }
65                e.Param.Note.ParentNoteID = m_vm->m_event->cause.Param.Note.ID;
66            }
67    
68          int id = pEngineChannel->ScheduleEvent(&e, duration);          const note_id_t id = pEngineChannel->ScheduleNoteMicroSec(&e, 0);
69    
70          return successResult(id);          // if a duration is supplied (and play-note event was scheduled
71            // successfully above), then schedule a subsequent stop-note event
72            if (id && duration > 0) {
73                e.Type = Event::type_stop_note;
74                e.Param.Note.ID = id;
75                e.Param.Note.Velocity = 127;
76                pEngineChannel->ScheduleEventMicroSec(&e, duration);
77            }
78    
79            // even if id is null, don't return an errorResult() here, because that
80            // would abort the script, and under heavy load it may be considerable
81            // that ScheduleNoteMicroSec() fails above, so simply ignore that
82            return successResult( ScriptID::fromNoteID(id) );
83      }      }
84    
85        // set_controller() function
86    
87      InstrumentScriptVMFunction_set_controller::InstrumentScriptVMFunction_set_controller(InstrumentScriptVM* parent)      InstrumentScriptVMFunction_set_controller::InstrumentScriptVMFunction_set_controller(InstrumentScriptVM* parent)
88          : m_vm(parent)          : m_vm(parent)
89      {      {
# Line 76  namespace LinuxSampler { Line 96  namespace LinuxSampler {
96          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
97              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
98    
99          Event e = m_vm->m_event->cause;          Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
100          memset(&e.Format, 0, sizeof(e.Format)); // init format speific stuff with zero          e.Init(); // clear IDs
101          if (controller == CTRL_TABLE_IDX_AFTERTOUCH) {          if (controller == CTRL_TABLE_IDX_AFTERTOUCH) {
102              e.Type = Event::type_channel_pressure;              e.Type = Event::type_channel_pressure;
103              e.Param.ChannelPressure.Value = value & 127;              e.Param.ChannelPressure.Value = value & 127;
# Line 93  namespace LinuxSampler { Line 113  namespace LinuxSampler {
113              return errorResult();              return errorResult();
114          }          }
115    
116          int id = pEngineChannel->ScheduleEvent(&e, 0);          const event_id_t id = pEngineChannel->ScheduleEventMicroSec(&e, 0);
117    
118          return successResult(id);          // even if id is null, don't return an errorResult() here, because that
119      }              // would abort the script, and under heavy load it may be considerable
120            // that ScheduleEventMicroSec() fails above, so simply ignore that
121            return successResult( ScriptID::fromEventID(id) );
122        }
123    
124        // ignore_event() function
125    
126      InstrumentScriptVMFunction_ignore_event::InstrumentScriptVMFunction_ignore_event(InstrumentScriptVM* parent)      InstrumentScriptVMFunction_ignore_event::InstrumentScriptVMFunction_ignore_event(InstrumentScriptVM* parent)
127          : m_vm(parent)          : m_vm(parent)
# Line 112  namespace LinuxSampler { Line 137  namespace LinuxSampler {
137                  static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);                  static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
138    
139          if (args->arg(0)->exprType() == INT_EXPR) {          if (args->arg(0)->exprType() == INT_EXPR) {
140              int id = args->arg(0)->asInt()->evalInt();              const ScriptID id = args->arg(0)->asInt()->evalInt();
141              if (id < 0) {              if (!id) {
142                  wrnMsg("ignore_event(): argument may not be a negative event ID");                  wrnMsg("ignore_event(): event ID argument may not be zero");
143                    // not errorResult(), because that would abort the script, not intentional in this case
144                  return successResult();                  return successResult();
145              }              }
146              pEngineChannel->IgnoreEvent(id);              pEngineChannel->IgnoreEventByScriptID(id);
147          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
148              VMIntArrayExpr* ids = args->arg(0)->asIntArray();              VMIntArrayExpr* ids = args->arg(0)->asIntArray();
149              for (int i = 0; i < ids->arraySize(); ++i) {              for (int i = 0; i < ids->arraySize(); ++i) {
150                  int id = ids->evalIntElement(i);                  const ScriptID id = ids->evalIntElement(i);    
151                  pEngineChannel->IgnoreEvent(id);                  pEngineChannel->IgnoreEventByScriptID(id);
152              }              }
153          }          }
154    
155          return successResult();          return successResult();
156      }      }
157    
158        // ignore_controller() function
159    
160      InstrumentScriptVMFunction_ignore_controller::InstrumentScriptVMFunction_ignore_controller(InstrumentScriptVM* parent)      InstrumentScriptVMFunction_ignore_controller::InstrumentScriptVMFunction_ignore_controller(InstrumentScriptVM* parent)
161          : m_vm(parent)          : m_vm(parent)
162      {      {
163      }      }
164    
165      VMFnResult* InstrumentScriptVMFunction_ignore_controller::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_ignore_controller::exec(VMFnArgs* args) {
166          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;
167          if (id < 0) {          if (!id && args->argsCount() >= 1) {
168              wrnMsg("ignore_controller(): argument may not be a negative event ID");              wrnMsg("ignore_controller(): event ID argument may not be zero");
169              return successResult();              return successResult();
170          }          }
171    
172          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
173              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
174    
175          pEngineChannel->IgnoreEvent(id);          pEngineChannel->IgnoreEventByScriptID(id);
176    
177          return successResult();          return successResult();
178      }      }
179    
180        // note_off() function
181    
182      InstrumentScriptVMFunction_note_off::InstrumentScriptVMFunction_note_off(InstrumentScriptVM* parent)      InstrumentScriptVMFunction_note_off::InstrumentScriptVMFunction_note_off(InstrumentScriptVM* parent)
183          : m_vm(parent)          : m_vm(parent)
184      {      {
# Line 169  namespace LinuxSampler { Line 199  namespace LinuxSampler {
199          }          }
200    
201          if (args->arg(0)->exprType() == INT_EXPR) {          if (args->arg(0)->exprType() == INT_EXPR) {
202              int id = args->arg(0)->asInt()->evalInt();                const ScriptID id = args->arg(0)->asInt()->evalInt();  
203              if (id < 0) {              if (!id) {
204                  wrnMsg("note_off(): argument 1 may not be a negative event ID");                  wrnMsg("note_off(): note ID for argument 1 may not be zero");
205                    return successResult();
206                }
207                if (!id.isNoteID()) {
208                    wrnMsg("note_off(): argument 1 is not a note ID");
209                  return successResult();                  return successResult();
210              }              }
211    
212              RTList<Event>::Iterator itEvent = pEngineChannel->pEngine->EventByID(id);              NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
213              if (!itEvent) return successResult();              if (!pNote) return successResult();
214    
215              Event e = *itEvent;              Event e = pNote->cause;
216              e.Type = Event::type_note_off;              e.Init(); // clear IDs
217                e.CopyTimeFrom(m_vm->m_event->cause); // set fragment time for "now"
218                e.Type = Event::type_stop_note;
219                e.Param.Note.ID = id.noteID();
220                e.Param.Note.Key = pNote->hostKey;
221              e.Param.Note.Velocity = velocity;              e.Param.Note.Velocity = velocity;
             memset(&e.Format, 0, sizeof(e.Format)); // init format speific stuff with zero  
222    
223              int releaseEventID = pEngineChannel->ScheduleEvent(&e, 0);              pEngineChannel->ScheduleEventMicroSec(&e, 0);
224          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
225              VMIntArrayExpr* ids = args->arg(0)->asIntArray();              VMIntArrayExpr* ids = args->arg(0)->asIntArray();
226              for (int i = 0; i < ids->arraySize(); ++i) {              for (int i = 0; i < ids->arraySize(); ++i) {
227                  int id = ids->evalIntElement(i);                  const ScriptID id = ids->evalIntElement(i);
228                    if (!id || !id.isNoteID()) continue;
229    
230                  RTList<Event>::Iterator itEvent = pEngineChannel->pEngine->EventByID(id);                  NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
231                  if (!itEvent) continue;                  if (!pNote) continue;
232    
233                  Event e = *itEvent;                  Event e = pNote->cause;
234                  e.Type = Event::type_note_off;                  e.Init(); // clear IDs
235                    e.CopyTimeFrom(m_vm->m_event->cause); // set fragment time for "now"
236                    e.Type = Event::type_stop_note;
237                    e.Param.Note.ID = id.noteID();
238                    e.Param.Note.Key = pNote->hostKey;
239                  e.Param.Note.Velocity = velocity;                  e.Param.Note.Velocity = velocity;
                 memset(&e.Format, 0, sizeof(e.Format)); // init format speific stuff with zero  
240    
241                  int releaseEventID = pEngineChannel->ScheduleEvent(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
242              }              }
243          }          }
244    
245          return successResult();          return successResult();
246      }      }
247    
248        // set_event_mark() function
249    
250      InstrumentScriptVMFunction_set_event_mark::InstrumentScriptVMFunction_set_event_mark(InstrumentScriptVM* parent)      InstrumentScriptVMFunction_set_event_mark::InstrumentScriptVMFunction_set_event_mark(InstrumentScriptVM* parent)
251          : m_vm(parent)          : m_vm(parent)
252      {      {
253      }      }
254    
255      VMFnResult* InstrumentScriptVMFunction_set_event_mark::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_set_event_mark::exec(VMFnArgs* args) {
256          int eventID = args->arg(0)->asInt()->evalInt();          const ScriptID id = args->arg(0)->asInt()->evalInt();
257          int groupID = args->arg(1)->asInt()->evalInt();          const int groupID = args->arg(1)->asInt()->evalInt();
258    
259          if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {          if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
260              errMsg("set_event_mark(): argument 2 is an invalid group id");              errMsg("set_event_mark(): argument 2 is an invalid group id");
# Line 221  namespace LinuxSampler { Line 264  namespace LinuxSampler {
264          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
265              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
266    
267          RTList<Event>::Iterator itEvent = pEngineChannel->pEngine->EventByID(eventID);          // check if the event/note still exists
268          if (!itEvent) return successResult();          switch (id.type()) {
269                case ScriptID::EVENT: {
270                    RTList<Event>::Iterator itEvent = pEngineChannel->pEngine->EventByID( id.eventID() );
271                    if (!itEvent) return successResult();
272                    break;
273                }
274                case ScriptID::NOTE: {
275                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
276                    if (!pNote) return successResult();
277                    break;
278                }
279            }
280    
281          pEngineChannel->pScript->eventGroups[groupID].insert(eventID);          pEngineChannel->pScript->eventGroups[groupID].insert(id);
282    
283          return successResult();          return successResult();
284      }      }
285    
286        // delete_event_mark() function
287    
288      InstrumentScriptVMFunction_delete_event_mark::InstrumentScriptVMFunction_delete_event_mark(InstrumentScriptVM* parent)      InstrumentScriptVMFunction_delete_event_mark::InstrumentScriptVMFunction_delete_event_mark(InstrumentScriptVM* parent)
289          : m_vm(parent)          : m_vm(parent)
290      {      {
291      }      }
292    
293      VMFnResult* InstrumentScriptVMFunction_delete_event_mark::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_delete_event_mark::exec(VMFnArgs* args) {
294          int eventID = args->arg(0)->asInt()->evalInt();          const ScriptID id = args->arg(0)->asInt()->evalInt();
295          int groupID = args->arg(1)->asInt()->evalInt();          const int groupID = args->arg(1)->asInt()->evalInt();
296    
297          if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {          if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
298              errMsg("delete_event_mark(): argument 2 is an invalid group id");              errMsg("delete_event_mark(): argument 2 is an invalid group id");
# Line 246  namespace LinuxSampler { Line 302  namespace LinuxSampler {
302          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
303              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
304    
305          pEngineChannel->pScript->eventGroups[groupID].erase(eventID);          pEngineChannel->pScript->eventGroups[groupID].erase(id);
306    
307          return successResult();          return successResult();
308      }      }
309    
310        // by_marks() function
311    
312      InstrumentScriptVMFunction_by_marks::InstrumentScriptVMFunction_by_marks(InstrumentScriptVM* parent)      InstrumentScriptVMFunction_by_marks::InstrumentScriptVMFunction_by_marks(InstrumentScriptVM* parent)
313          : m_vm(parent)          : m_vm(parent)
314      {      {
# Line 290  namespace LinuxSampler { Line 348  namespace LinuxSampler {
348          return successResult( &pEngineChannel->pScript->eventGroups[groupID] );          return successResult( &pEngineChannel->pScript->eventGroups[groupID] );
349      }      }
350    
351        // change_vol() function
352    
353        InstrumentScriptVMFunction_change_vol::InstrumentScriptVMFunction_change_vol(InstrumentScriptVM* parent)
354            : m_vm(parent)
355        {
356        }
357    
358        bool InstrumentScriptVMFunction_change_vol::acceptsArgType(int iArg, ExprType_t type) const {
359            if (iArg == 0)
360                return type == INT_EXPR || type == INT_ARR_EXPR;
361            else
362                return INT_EXPR;
363        }
364    
365        VMFnResult* InstrumentScriptVMFunction_change_vol::exec(VMFnArgs* args) {
366            int volume = args->arg(1)->asInt()->evalInt(); // volume change in milli dB
367            bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;
368    
369            AbstractEngineChannel* pEngineChannel =
370                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
371    
372            if (args->arg(0)->exprType() == INT_EXPR) {
373                const ScriptID id = args->arg(0)->asInt()->evalInt();
374                if (!id) {
375                    wrnMsg("change_vol(): note ID for argument 1 may not be zero");
376                    return successResult();
377                }
378                if (!id.isNoteID()) {
379                    wrnMsg("change_vol(): argument 1 is not a note ID");
380                    return successResult();
381                }
382    
383                NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
384                if (!pNote) return successResult();
385    
386                const float fVolumeLin = RTMath::DecibelToLinRatio(float(volume) / 1000.f);
387                // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
388                /*if (relative)
389                    pNote->Override.Volume *= fVolumeLin;
390                else
391                    pNote->Override.Volume = fVolumeLin;*/
392    
393                Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
394                e.Init(); // clear IDs
395                e.Type = Event::type_note_synth_param;
396                e.Param.NoteSynthParam.NoteID   = id.noteID();
397                e.Param.NoteSynthParam.Type     = Event::synth_param_volume;
398                e.Param.NoteSynthParam.Delta    = fVolumeLin;
399                e.Param.NoteSynthParam.Relative = relative;
400    
401                pEngineChannel->ScheduleEventMicroSec(&e, 0);
402            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
403                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
404                for (int i = 0; i < ids->arraySize(); ++i) {
405                    const ScriptID id = ids->evalIntElement(i);
406                    if (!id || !id.isNoteID()) continue;
407    
408                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
409                    if (!pNote) continue;
410    
411                    const float fVolumeLin = RTMath::DecibelToLinRatio(float(volume) / 1000.f);
412                    // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
413                    /*if (relative)
414                        pNote->Override.Volume *= fVolumeLin;
415                    else
416                        pNote->Override.Volume = fVolumeLin;*/
417    
418                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
419                    e.Init(); // clear IDs
420                    e.Type = Event::type_note_synth_param;
421                    e.Param.NoteSynthParam.NoteID   = id.noteID();
422                    e.Param.NoteSynthParam.Type     = Event::synth_param_volume;
423                    e.Param.NoteSynthParam.Delta    = fVolumeLin;
424                    e.Param.NoteSynthParam.Relative = relative;
425    
426                    pEngineChannel->ScheduleEventMicroSec(&e, 0);
427                }
428            }
429    
430            return successResult();
431        }
432    
433        // change_tune() function
434    
435        InstrumentScriptVMFunction_change_tune::InstrumentScriptVMFunction_change_tune(InstrumentScriptVM* parent)
436            : m_vm(parent)
437        {
438        }
439    
440        bool InstrumentScriptVMFunction_change_tune::acceptsArgType(int iArg, ExprType_t type) const {
441            if (iArg == 0)
442                return type == INT_EXPR || type == INT_ARR_EXPR;
443            else
444                return INT_EXPR;
445        }
446    
447        VMFnResult* InstrumentScriptVMFunction_change_tune::exec(VMFnArgs* args) {
448            int tune = args->arg(1)->asInt()->evalInt(); // tuning change in milli cents
449            bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;
450    
451            AbstractEngineChannel* pEngineChannel =
452                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
453    
454            if (args->arg(0)->exprType() == INT_EXPR) {
455                const ScriptID id = args->arg(0)->asInt()->evalInt();
456                if (!id) {
457                    wrnMsg("change_tune(): note ID for argument 1 may not be zero");
458                    return successResult();
459                }
460                if (!id.isNoteID()) {
461                    wrnMsg("change_tune(): argument 1 is not a note ID");
462                    return successResult();
463                }
464    
465                NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
466                if (!pNote) return successResult();
467    
468                const float fFreqRatio = RTMath::CentsToFreqRatioUnlimited(float(tune) / 1000.f);
469                // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
470                /*if (relative)
471                    pNote->Override.Pitch *= fFreqRatio;
472                else
473                    pNote->Override.Pitch = fFreqRatio;*/
474    
475                Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
476                e.Init(); // clear IDs
477                e.Type = Event::type_note_synth_param;
478                e.Param.NoteSynthParam.NoteID   = id.noteID();
479                e.Param.NoteSynthParam.Type     = Event::synth_param_pitch;
480                e.Param.NoteSynthParam.Delta    = fFreqRatio;
481                e.Param.NoteSynthParam.Relative = relative;
482    
483                pEngineChannel->ScheduleEventMicroSec(&e, 0);
484            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
485                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
486                for (int i = 0; i < ids->arraySize(); ++i) {
487                    const ScriptID id = ids->evalIntElement(i);
488                    if (!id || !id.isNoteID()) continue;
489    
490                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
491                    if (!pNote) continue;
492    
493                    const float fFreqRatio = RTMath::CentsToFreqRatioUnlimited(float(tune) / 1000.f);
494                    // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
495                    /*if (relative)
496                        pNote->Override.Pitch *= fFreqRatio;
497                    else
498                        pNote->Override.Pitch = fFreqRatio;*/
499    
500                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
501                    e.Init(); // clear IDs
502                    e.Type = Event::type_note_synth_param;
503                    e.Param.NoteSynthParam.NoteID   = id.noteID();
504                    e.Param.NoteSynthParam.Type     = Event::synth_param_pitch;
505                    e.Param.NoteSynthParam.Delta    = fFreqRatio;
506                    e.Param.NoteSynthParam.Relative = relative;
507    
508                    pEngineChannel->ScheduleEventMicroSec(&e, 0);
509                }
510            }
511    
512            return successResult();
513        }
514    
515        // change_pan() function
516    
517        InstrumentScriptVMFunction_change_pan::InstrumentScriptVMFunction_change_pan(InstrumentScriptVM* parent)
518            : m_vm(parent)
519        {
520        }
521    
522        bool InstrumentScriptVMFunction_change_pan::acceptsArgType(int iArg, ExprType_t type) const {
523            if (iArg == 0)
524                return type == INT_EXPR || type == INT_ARR_EXPR;
525            else
526                return INT_EXPR;
527        }
528    
529        VMFnResult* InstrumentScriptVMFunction_change_pan::exec(VMFnArgs* args) {
530            int pan = args->arg(1)->asInt()->evalInt();
531            bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;
532    
533            if (pan > 1000) {
534                wrnMsg("change_pan(): argument 2 may not be larger than 1000");
535                pan = 1000;
536            } else if (pan < -1000) {
537                wrnMsg("change_pan(): argument 2 may not be smaller than -1000");
538                pan = -1000;
539            }
540    
541            AbstractEngineChannel* pEngineChannel =
542                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
543    
544            if (args->arg(0)->exprType() == INT_EXPR) {
545                const ScriptID id = args->arg(0)->asInt()->evalInt();
546                if (!id) {
547                    wrnMsg("change_pan(): note ID for argument 1 may not be zero");
548                    return successResult();
549                }
550                if (!id.isNoteID()) {
551                    wrnMsg("change_pan(): argument 1 is not a note ID");
552                    return successResult();
553                }
554    
555                NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
556                if (!pNote) return successResult();
557    
558                const float fPan = float(pan) / 1000.f;
559                // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
560                /*if (relative) {
561                    pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);
562                } else {
563                    pNote->Override.Pan = fPan;
564                    pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() calls on same note with 'relative' being set
565                }*/
566    
567                Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
568                e.Init(); // clear IDs
569                e.Type = Event::type_note_synth_param;
570                e.Param.NoteSynthParam.NoteID   = id.noteID();
571                e.Param.NoteSynthParam.Type     = Event::synth_param_pan;
572                e.Param.NoteSynthParam.Delta    = fPan;
573                e.Param.NoteSynthParam.Relative = relative;
574    
575                pEngineChannel->ScheduleEventMicroSec(&e, 0);
576            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
577                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
578                for (int i = 0; i < ids->arraySize(); ++i) {
579                    const ScriptID id = ids->evalIntElement(i);
580                    if (!id || !id.isNoteID()) continue;
581    
582                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
583                    if (!pNote) continue;
584    
585                    const float fPan = float(pan) / 1000.f;
586                    // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
587                    /*if (relative) {
588                        pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);
589                    } else {
590                        pNote->Override.Pan = fPan;
591                        pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() calls on same note with 'relative' being set
592                    }*/
593    
594                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
595                    e.Init(); // clear IDs
596                    e.Type = Event::type_note_synth_param;
597                    e.Param.NoteSynthParam.NoteID   = id.noteID();
598                    e.Param.NoteSynthParam.Type     = Event::synth_param_pan;
599                    e.Param.NoteSynthParam.Delta    = fPan;
600                    e.Param.NoteSynthParam.Relative = relative;
601    
602                    pEngineChannel->ScheduleEventMicroSec(&e, 0);
603                }
604            }
605    
606            return successResult();
607        }
608    
609        #define VM_FILTER_PAR_MAX_VALUE 1000000
610        #define VM_EG_PAR_MAX_VALUE 1000000
611    
612        // change_cutoff() function
613    
614        InstrumentScriptVMFunction_change_cutoff::InstrumentScriptVMFunction_change_cutoff(InstrumentScriptVM* parent)
615            : m_vm(parent)
616        {
617        }
618    
619        bool InstrumentScriptVMFunction_change_cutoff::acceptsArgType(int iArg, ExprType_t type) const {
620            if (iArg == 0)
621                return type == INT_EXPR || type == INT_ARR_EXPR;
622            else
623                return INT_EXPR;
624        }
625    
626        VMFnResult* InstrumentScriptVMFunction_change_cutoff::exec(VMFnArgs* args) {
627            int cutoff = args->arg(1)->asInt()->evalInt();
628            if (cutoff > VM_FILTER_PAR_MAX_VALUE) {
629                wrnMsg("change_cutoff(): argument 2 may not be larger than 1000000");
630                cutoff = VM_FILTER_PAR_MAX_VALUE;
631            } else if (cutoff < 0) {
632                wrnMsg("change_cutoff(): argument 2 may not be negative");
633                cutoff = 0;
634            }
635    
636            AbstractEngineChannel* pEngineChannel =
637                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
638    
639            if (args->arg(0)->exprType() == INT_EXPR) {
640                const ScriptID id = args->arg(0)->asInt()->evalInt();
641                if (!id) {
642                    wrnMsg("change_cutoff(): note ID for argument 1 may not be zero");
643                    return successResult();
644                }
645                if (!id.isNoteID()) {
646                    wrnMsg("change_cutoff(): argument 1 is not a note ID");
647                    return successResult();
648                }
649    
650                NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
651                if (!pNote) return successResult();
652    
653                const float fCutoff = float(cutoff) / float(VM_FILTER_PAR_MAX_VALUE);
654    
655                Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
656                e.Init(); // clear IDs
657                e.Type = Event::type_note_synth_param;
658                e.Param.NoteSynthParam.NoteID   = id.noteID();
659                e.Param.NoteSynthParam.Type     = Event::synth_param_cutoff;
660                e.Param.NoteSynthParam.Delta    = fCutoff;
661                e.Param.NoteSynthParam.Relative = false;
662    
663                pEngineChannel->ScheduleEventMicroSec(&e, 0);
664            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
665                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
666                for (int i = 0; i < ids->arraySize(); ++i) {
667                    const ScriptID id = ids->evalIntElement(i);
668                    if (!id || !id.isNoteID()) continue;
669    
670                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
671                    if (!pNote) continue;
672    
673                    const float fCutoff = float(cutoff) / float(VM_FILTER_PAR_MAX_VALUE);
674    
675                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
676                    e.Init(); // clear IDs
677                    e.Type = Event::type_note_synth_param;
678                    e.Param.NoteSynthParam.NoteID   = id.noteID();
679                    e.Param.NoteSynthParam.Type     = Event::synth_param_cutoff;
680                    e.Param.NoteSynthParam.Delta    = fCutoff;
681                    e.Param.NoteSynthParam.Relative = false;
682    
683                    pEngineChannel->ScheduleEventMicroSec(&e, 0);
684                }
685            }
686    
687            return successResult();
688        }
689    
690        // change_reso() function
691        
692        InstrumentScriptVMFunction_change_reso::InstrumentScriptVMFunction_change_reso(InstrumentScriptVM* parent)
693            : m_vm(parent)
694        {
695        }
696    
697        bool InstrumentScriptVMFunction_change_reso::acceptsArgType(int iArg, ExprType_t type) const {
698            if (iArg == 0)
699                return type == INT_EXPR || type == INT_ARR_EXPR;
700            else
701                return INT_EXPR;
702        }
703    
704        VMFnResult* InstrumentScriptVMFunction_change_reso::exec(VMFnArgs* args) {
705            int resonance = args->arg(1)->asInt()->evalInt();
706            if (resonance > VM_FILTER_PAR_MAX_VALUE) {
707                wrnMsg("change_reso(): argument 2 may not be larger than 1000000");
708                resonance = VM_FILTER_PAR_MAX_VALUE;
709            } else if (resonance < 0) {
710                wrnMsg("change_reso(): argument 2 may not be negative");
711                resonance = 0;
712            }
713    
714            AbstractEngineChannel* pEngineChannel =
715                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
716    
717            if (args->arg(0)->exprType() == INT_EXPR) {
718                const ScriptID id = args->arg(0)->asInt()->evalInt();
719                if (!id) {
720                    wrnMsg("change_reso(): note ID for argument 1 may not be zero");
721                    return successResult();
722                }
723                if (!id.isNoteID()) {
724                    wrnMsg("change_reso(): argument 1 is not a note ID");
725                    return successResult();
726                }
727    
728                NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
729                if (!pNote) return successResult();
730    
731                const float fResonance = float(resonance) / float(VM_FILTER_PAR_MAX_VALUE);
732    
733                Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
734                e.Init(); // clear IDs
735                e.Type = Event::type_note_synth_param;
736                e.Param.NoteSynthParam.NoteID   = id.noteID();
737                e.Param.NoteSynthParam.Type     = Event::synth_param_resonance;
738                e.Param.NoteSynthParam.Delta    = fResonance;
739                e.Param.NoteSynthParam.Relative = false;
740    
741                pEngineChannel->ScheduleEventMicroSec(&e, 0);
742            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
743                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
744                for (int i = 0; i < ids->arraySize(); ++i) {
745                    const ScriptID id = ids->evalIntElement(i);
746                    if (!id || !id.isNoteID()) continue;
747    
748                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
749                    if (!pNote) continue;
750    
751                    const float fResonance = float(resonance) / float(VM_FILTER_PAR_MAX_VALUE);
752    
753                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
754                    e.Init(); // clear IDs
755                    e.Type = Event::type_note_synth_param;
756                    e.Param.NoteSynthParam.NoteID   = id.noteID();
757                    e.Param.NoteSynthParam.Type     = Event::synth_param_resonance;
758                    e.Param.NoteSynthParam.Delta    = fResonance;
759                    e.Param.NoteSynthParam.Relative = false;
760    
761                    pEngineChannel->ScheduleEventMicroSec(&e, 0);
762                }
763            }
764    
765            return successResult();
766        }
767        
768        // change_attack() function
769    
770        InstrumentScriptVMFunction_change_attack::InstrumentScriptVMFunction_change_attack(InstrumentScriptVM* parent)
771            : m_vm(parent)
772        {
773        }
774    
775        bool InstrumentScriptVMFunction_change_attack::acceptsArgType(int iArg, ExprType_t type) const {
776            if (iArg == 0)
777                return type == INT_EXPR || type == INT_ARR_EXPR;
778            else
779                return INT_EXPR;
780        }
781    
782        VMFnResult* InstrumentScriptVMFunction_change_attack::exec(VMFnArgs* args) {
783            int attack = args->arg(1)->asInt()->evalInt();
784            if (attack > VM_EG_PAR_MAX_VALUE) {
785                wrnMsg("change_attack(): argument 2 may not be larger than 1000000");
786                attack = VM_EG_PAR_MAX_VALUE;
787            } else if (attack < 0) {
788                wrnMsg("change_attack(): argument 2 may not be negative");
789                attack = 0;
790            }
791            const float fAttack = float(attack) / float(VM_EG_PAR_MAX_VALUE);
792    
793            AbstractEngineChannel* pEngineChannel =
794                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
795    
796            if (args->arg(0)->exprType() == INT_EXPR) {
797                const ScriptID id = args->arg(0)->asInt()->evalInt();
798                if (!id) {
799                    wrnMsg("change_attack(): note ID for argument 1 may not be zero");
800                    return successResult();
801                }
802                if (!id.isNoteID()) {
803                    wrnMsg("change_attack(): argument 1 is not a note ID");
804                    return successResult();
805                }
806    
807                NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
808                if (!pNote) return successResult();            
809    
810                Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
811                e.Init(); // clear IDs
812                e.Type = Event::type_note_synth_param;
813                e.Param.NoteSynthParam.NoteID   = id.noteID();
814                e.Param.NoteSynthParam.Type     = Event::synth_param_attack;
815                e.Param.NoteSynthParam.Delta    = fAttack;
816                e.Param.NoteSynthParam.Relative = false;
817    
818                pEngineChannel->ScheduleEventMicroSec(&e, 0);
819            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
820                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
821                for (int i = 0; i < ids->arraySize(); ++i) {
822                    const ScriptID id = ids->evalIntElement(i);
823                    if (!id || !id.isNoteID()) continue;
824    
825                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
826                    if (!pNote) continue;
827    
828                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
829                    e.Init(); // clear IDs
830                    e.Type = Event::type_note_synth_param;
831                    e.Param.NoteSynthParam.NoteID   = id.noteID();
832                    e.Param.NoteSynthParam.Type     = Event::synth_param_attack;
833                    e.Param.NoteSynthParam.Delta    = fAttack;
834                    e.Param.NoteSynthParam.Relative = false;
835    
836                    pEngineChannel->ScheduleEventMicroSec(&e, 0);
837                }
838            }
839    
840            return successResult();
841        }
842    
843        // change_decay() function
844        
845        InstrumentScriptVMFunction_change_decay::InstrumentScriptVMFunction_change_decay(InstrumentScriptVM* parent)
846            : m_vm(parent)
847        {
848        }
849    
850        bool InstrumentScriptVMFunction_change_decay::acceptsArgType(int iArg, ExprType_t type) const {
851            if (iArg == 0)
852                return type == INT_EXPR || type == INT_ARR_EXPR;
853            else
854                return INT_EXPR;
855        }
856    
857        VMFnResult* InstrumentScriptVMFunction_change_decay::exec(VMFnArgs* args) {
858            int decay = args->arg(1)->asInt()->evalInt();
859            if (decay > VM_EG_PAR_MAX_VALUE) {
860                wrnMsg("change_decay(): argument 2 may not be larger than 1000000");
861                decay = VM_EG_PAR_MAX_VALUE;
862            } else if (decay < 0) {
863                wrnMsg("change_decay(): argument 2 may not be negative");
864                decay = 0;
865            }
866            const float fDecay = float(decay) / float(VM_EG_PAR_MAX_VALUE);
867    
868            AbstractEngineChannel* pEngineChannel =
869                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
870    
871            if (args->arg(0)->exprType() == INT_EXPR) {
872                const ScriptID id = args->arg(0)->asInt()->evalInt();
873                if (!id) {
874                    wrnMsg("change_decay(): note ID for argument 1 may not be zero");
875                    return successResult();
876                }
877                if (!id.isNoteID()) {
878                    wrnMsg("change_decay(): argument 1 is not a note ID");
879                    return successResult();
880                }
881    
882                NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
883                if (!pNote) return successResult();            
884    
885                Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
886                e.Init(); // clear IDs
887                e.Type = Event::type_note_synth_param;
888                e.Param.NoteSynthParam.NoteID   = id.noteID();
889                e.Param.NoteSynthParam.Type     = Event::synth_param_decay;
890                e.Param.NoteSynthParam.Delta    = fDecay;
891                e.Param.NoteSynthParam.Relative = false;
892    
893                pEngineChannel->ScheduleEventMicroSec(&e, 0);
894            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
895                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
896                for (int i = 0; i < ids->arraySize(); ++i) {
897                    const ScriptID id = ids->evalIntElement(i);
898                    if (!id || !id.isNoteID()) continue;
899    
900                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
901                    if (!pNote) continue;
902    
903                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
904                    e.Init(); // clear IDs
905                    e.Type = Event::type_note_synth_param;
906                    e.Param.NoteSynthParam.NoteID   = id.noteID();
907                    e.Param.NoteSynthParam.Type     = Event::synth_param_decay;
908                    e.Param.NoteSynthParam.Delta    = fDecay;
909                    e.Param.NoteSynthParam.Relative = false;
910    
911                    pEngineChannel->ScheduleEventMicroSec(&e, 0);
912                }
913            }
914    
915            return successResult();
916        }
917    
918        // change_release() function
919        
920        InstrumentScriptVMFunction_change_release::InstrumentScriptVMFunction_change_release(InstrumentScriptVM* parent)
921            : m_vm(parent)
922        {
923        }
924    
925        bool InstrumentScriptVMFunction_change_release::acceptsArgType(int iArg, ExprType_t type) const {
926            if (iArg == 0)
927                return type == INT_EXPR || type == INT_ARR_EXPR;
928            else
929                return INT_EXPR;
930        }
931    
932        VMFnResult* InstrumentScriptVMFunction_change_release::exec(VMFnArgs* args) {
933            int release = args->arg(1)->asInt()->evalInt();
934            if (release > VM_EG_PAR_MAX_VALUE) {
935                wrnMsg("change_release(): argument 2 may not be larger than 1000000");
936                release = VM_EG_PAR_MAX_VALUE;
937            } else if (release < 0) {
938                wrnMsg("change_release(): argument 2 may not be negative");
939                release = 0;
940            }
941            const float fRelease = float(release) / float(VM_EG_PAR_MAX_VALUE);
942    
943            AbstractEngineChannel* pEngineChannel =
944                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
945    
946            if (args->arg(0)->exprType() == INT_EXPR) {
947                const ScriptID id = args->arg(0)->asInt()->evalInt();
948                if (!id) {
949                    wrnMsg("change_release(): note ID for argument 1 may not be zero");
950                    return successResult();
951                }
952                if (!id.isNoteID()) {
953                    wrnMsg("change_release(): argument 1 is not a note ID");
954                    return successResult();
955                }
956    
957                NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
958                if (!pNote) return successResult();            
959    
960                Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
961                e.Init(); // clear IDs
962                e.Type = Event::type_note_synth_param;
963                e.Param.NoteSynthParam.NoteID   = id.noteID();
964                e.Param.NoteSynthParam.Type     = Event::synth_param_release;
965                e.Param.NoteSynthParam.Delta    = fRelease;
966                e.Param.NoteSynthParam.Relative = false;
967    
968                pEngineChannel->ScheduleEventMicroSec(&e, 0);
969            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
970                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
971                for (int i = 0; i < ids->arraySize(); ++i) {
972                    const ScriptID id = ids->evalIntElement(i);
973                    if (!id || !id.isNoteID()) continue;
974    
975                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
976                    if (!pNote) continue;
977    
978                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
979                    e.Init(); // clear IDs
980                    e.Type = Event::type_note_synth_param;
981                    e.Param.NoteSynthParam.NoteID   = id.noteID();
982                    e.Param.NoteSynthParam.Type     = Event::synth_param_release;
983                    e.Param.NoteSynthParam.Delta    = fRelease;
984                    e.Param.NoteSynthParam.Relative = false;
985    
986                    pEngineChannel->ScheduleEventMicroSec(&e, 0);
987                }
988            }
989    
990            return successResult();
991        }
992    
993        // event_status() function
994    
995        InstrumentScriptVMFunction_event_status::InstrumentScriptVMFunction_event_status(InstrumentScriptVM* parent)
996            : m_vm(parent)
997        {
998        }
999    
1000        VMFnResult* InstrumentScriptVMFunction_event_status::exec(VMFnArgs* args) {
1001            AbstractEngineChannel* pEngineChannel =
1002                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1003    
1004            const ScriptID id = args->arg(0)->asInt()->evalInt();
1005            if (!id) {
1006                wrnMsg("event_status(): note ID for argument 1 may not be zero");
1007                return successResult(EVENT_STATUS_INACTIVE);
1008            }
1009            if (!id.isNoteID()) {
1010                wrnMsg("event_status(): argument 1 is not a note ID");
1011                return successResult(EVENT_STATUS_INACTIVE);
1012            }
1013    
1014            NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1015            return successResult(pNote ? EVENT_STATUS_NOTE_QUEUE : EVENT_STATUS_INACTIVE);
1016        }
1017    
1018        // wait() function (overrides core wait() implementation)
1019    
1020        InstrumentScriptVMFunction_wait::InstrumentScriptVMFunction_wait(InstrumentScriptVM* parent)
1021            : CoreVMFunction_wait(parent)
1022        {    
1023        }
1024    
1025        VMFnResult* InstrumentScriptVMFunction_wait::exec(VMFnArgs* args) {
1026            InstrumentScriptVM* m_vm = (InstrumentScriptVM*) vm;
1027    
1028            // this might be set by passing 1 with the 2nd argument of built-in stop_wait() function
1029            if (m_vm->m_event->ignoreAllWaitCalls) return successResult();
1030    
1031            return CoreVMFunction_wait::exec(args);
1032        }
1033    
1034        // stop_wait() function
1035    
1036        InstrumentScriptVMFunction_stop_wait::InstrumentScriptVMFunction_stop_wait(InstrumentScriptVM* parent)
1037            : m_vm(parent)
1038        {    
1039        }
1040    
1041        VMFnResult* InstrumentScriptVMFunction_stop_wait::exec(VMFnArgs* args) {
1042            AbstractEngineChannel* pEngineChannel =
1043                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1044    
1045            const script_callback_id_t id = args->arg(0)->asInt()->evalInt();
1046            if (!id) {
1047                wrnMsg("stop_wait(): callback ID for argument 1 may not be zero");
1048                return successResult();
1049            }
1050    
1051            RTList<ScriptEvent>::Iterator itCallback = pEngineChannel->ScriptCallbackByID(id);
1052            if (!itCallback) return successResult(); // ignore if callback is i.e. not alive anymore
1053    
1054            const bool disableWaitForever =
1055                (args->argsCount() >= 2) ? (args->arg(1)->asInt()->evalInt() == 1) : false;
1056    
1057            pEngineChannel->ScheduleResumeOfScriptCallback(
1058                itCallback, m_vm->m_event->cause.SchedTime(), disableWaitForever
1059            );
1060    
1061            return successResult();
1062        }
1063    
1064  } // namespace LinuxSampler  } // namespace LinuxSampler

Legend:
Removed from v.2630  
changed lines
  Added in v.2953

  ViewVC Help
Powered by ViewVC