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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2953 - (hide annotations) (download)
Sat Jul 16 11:24:39 2016 UTC (7 years, 9 months ago) by schoenebeck
File size: 43053 byte(s)
* NKSP: Implemented built-in script function "change_attack()".
* NKSP: Implemented built-in script function "change_decay()".
* NKSP: Implemented built-in script function "change_release()".
* Bumped version (2.0.0.svn19).

1 schoenebeck 2596 /*
2 schoenebeck 2871 * Copyright (c) 2014-2016 Christian Schoenebeck
3 schoenebeck 2596 *
4     * http://www.linuxsampler.org
5     *
6     * This file is part of LinuxSampler and released under the same terms.
7     * See README file for details.
8     */
9    
10     #include "InstrumentScriptVMFunctions.h"
11     #include "InstrumentScriptVM.h"
12     #include "../AbstractEngineChannel.h"
13    
14     namespace LinuxSampler {
15 schoenebeck 2931
16     // play_note() function
17 schoenebeck 2596
18     InstrumentScriptVMFunction_play_note::InstrumentScriptVMFunction_play_note(InstrumentScriptVM* parent)
19     : m_vm(parent)
20     {
21     }
22    
23     VMFnResult* InstrumentScriptVMFunction_play_note::exec(VMFnArgs* args) {
24     int note = args->arg(0)->asInt()->evalInt();
25     int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;
26     int sampleoffset = (args->argsCount() >= 3) ? args->arg(2)->asInt()->evalInt() : 0;
27 schoenebeck 2879 int duration = (args->argsCount() >= 4) ? args->arg(3)->asInt()->evalInt() : 0; //TODO: -1 might be a better default value instead of 0
28 schoenebeck 2596
29     if (note < 0 || note > 127) {
30     errMsg("play_note(): argument 1 is an invalid note number");
31 schoenebeck 2879 return errorResult(0);
32 schoenebeck 2596 }
33    
34     if (velocity < 0 || velocity > 127) {
35     errMsg("play_note(): argument 2 is an invalid velocity value");
36 schoenebeck 2879 return errorResult(0);
37 schoenebeck 2596 }
38    
39     if (sampleoffset < 0) {
40     errMsg("play_note(): argument 3 may not be a negative sample offset");
41 schoenebeck 2879 return errorResult(0);
42 schoenebeck 2596 } else if (sampleoffset != 0) {
43     wrnMsg("play_note(): argument 3 does not support a sample offset other than 0 yet");
44     }
45    
46     if (duration < -1) {
47     errMsg("play_note(): argument 4 must be a duration value of at least -1 or higher");
48 schoenebeck 2879 return errorResult(0);
49 schoenebeck 2596 }
50    
51     AbstractEngineChannel* pEngineChannel =
52     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
53    
54 schoenebeck 2879 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
55     e.Init(); // clear IDs
56 schoenebeck 2938 e.Type = Event::type_play_note;
57 schoenebeck 2596 e.Param.Note.Key = note;
58     e.Param.Note.Velocity = velocity;
59 schoenebeck 2879 // 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 schoenebeck 2596
68 schoenebeck 2879 const note_id_t id = pEngineChannel->ScheduleNoteMicroSec(&e, 0);
69 schoenebeck 2596
70 schoenebeck 2938 // if a duration is supplied (and play-note event was scheduled
71     // successfully above), then schedule a subsequent stop-note event
72 schoenebeck 2879 if (id && duration > 0) {
73 schoenebeck 2938 e.Type = Event::type_stop_note;
74     e.Param.Note.ID = id;
75 schoenebeck 2871 e.Param.Note.Velocity = 127;
76     pEngineChannel->ScheduleEventMicroSec(&e, duration);
77     }
78    
79 schoenebeck 2879 // 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 schoenebeck 2598 }
84    
85 schoenebeck 2931 // set_controller() function
86    
87 schoenebeck 2600 InstrumentScriptVMFunction_set_controller::InstrumentScriptVMFunction_set_controller(InstrumentScriptVM* parent)
88     : m_vm(parent)
89     {
90     }
91    
92     VMFnResult* InstrumentScriptVMFunction_set_controller::exec(VMFnArgs* args) {
93     int controller = args->arg(0)->asInt()->evalInt();
94     int value = args->arg(1)->asInt()->evalInt();
95    
96     AbstractEngineChannel* pEngineChannel =
97     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
98    
99 schoenebeck 2879 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
100     e.Init(); // clear IDs
101 schoenebeck 2600 if (controller == CTRL_TABLE_IDX_AFTERTOUCH) {
102     e.Type = Event::type_channel_pressure;
103     e.Param.ChannelPressure.Value = value & 127;
104     } else if (controller == CTRL_TABLE_IDX_PITCHBEND) {
105     e.Type = Event::type_pitchbend;
106     e.Param.Pitch.Pitch = value;
107     } else if (controller >= 0 && controller <= 127) {
108     e.Type = Event::type_control_change;
109     e.Param.CC.Controller = controller;
110     e.Param.CC.Value = value;
111     } else {
112     errMsg("set_controller(): argument 1 is an invalid controller");
113     return errorResult();
114     }
115    
116 schoenebeck 2879 const event_id_t id = pEngineChannel->ScheduleEventMicroSec(&e, 0);
117 schoenebeck 2600
118 schoenebeck 2879 // 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 schoenebeck 2931 }
123 schoenebeck 2600
124 schoenebeck 2931 // ignore_event() function
125    
126 schoenebeck 2598 InstrumentScriptVMFunction_ignore_event::InstrumentScriptVMFunction_ignore_event(InstrumentScriptVM* parent)
127     : m_vm(parent)
128     {
129     }
130    
131 schoenebeck 2630 bool InstrumentScriptVMFunction_ignore_event::acceptsArgType(int iArg, ExprType_t type) const {
132     return type == INT_EXPR || type == INT_ARR_EXPR;
133     }
134    
135 schoenebeck 2598 VMFnResult* InstrumentScriptVMFunction_ignore_event::exec(VMFnArgs* args) {
136     AbstractEngineChannel* pEngineChannel =
137 schoenebeck 2630 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
138 schoenebeck 2598
139 schoenebeck 2630 if (args->arg(0)->exprType() == INT_EXPR) {
140 schoenebeck 2879 const ScriptID id = args->arg(0)->asInt()->evalInt();
141     if (!id) {
142     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 schoenebeck 2630 return successResult();
145     }
146 schoenebeck 2879 pEngineChannel->IgnoreEventByScriptID(id);
147 schoenebeck 2630 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
148     VMIntArrayExpr* ids = args->arg(0)->asIntArray();
149     for (int i = 0; i < ids->arraySize(); ++i) {
150 schoenebeck 2879 const ScriptID id = ids->evalIntElement(i);
151     pEngineChannel->IgnoreEventByScriptID(id);
152 schoenebeck 2630 }
153     }
154 schoenebeck 2598
155 schoenebeck 2596 return successResult();
156     }
157    
158 schoenebeck 2931 // ignore_controller() function
159    
160 schoenebeck 2598 InstrumentScriptVMFunction_ignore_controller::InstrumentScriptVMFunction_ignore_controller(InstrumentScriptVM* parent)
161     : m_vm(parent)
162     {
163     }
164    
165     VMFnResult* InstrumentScriptVMFunction_ignore_controller::exec(VMFnArgs* args) {
166 schoenebeck 2879 const ScriptID id = (args->argsCount() >= 1) ? args->arg(0)->asInt()->evalInt() : m_vm->m_event->id;
167     if (!id && args->argsCount() >= 1) {
168     wrnMsg("ignore_controller(): event ID argument may not be zero");
169 schoenebeck 2598 return successResult();
170     }
171    
172     AbstractEngineChannel* pEngineChannel =
173     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
174    
175 schoenebeck 2879 pEngineChannel->IgnoreEventByScriptID(id);
176 schoenebeck 2598
177     return successResult();
178     }
179    
180 schoenebeck 2931 // note_off() function
181    
182 schoenebeck 2629 InstrumentScriptVMFunction_note_off::InstrumentScriptVMFunction_note_off(InstrumentScriptVM* parent)
183     : m_vm(parent)
184     {
185     }
186    
187 schoenebeck 2630 bool InstrumentScriptVMFunction_note_off::acceptsArgType(int iArg, ExprType_t type) const {
188     return type == INT_EXPR || type == INT_ARR_EXPR;
189     }
190    
191 schoenebeck 2629 VMFnResult* InstrumentScriptVMFunction_note_off::exec(VMFnArgs* args) {
192 schoenebeck 2630 AbstractEngineChannel* pEngineChannel =
193     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
194    
195 schoenebeck 2629 int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;
196 schoenebeck 2630 if (velocity < 0 || velocity > 127) {
197     errMsg("note_off(): argument 2 is an invalid velocity value");
198     return errorResult();
199     }
200 schoenebeck 2629
201 schoenebeck 2630 if (args->arg(0)->exprType() == INT_EXPR) {
202 schoenebeck 2879 const ScriptID id = args->arg(0)->asInt()->evalInt();
203     if (!id) {
204     wrnMsg("note_off(): note ID for argument 1 may not be zero");
205 schoenebeck 2630 return successResult();
206     }
207 schoenebeck 2879 if (!id.isNoteID()) {
208     wrnMsg("note_off(): argument 1 is not a note ID");
209     return successResult();
210     }
211 schoenebeck 2630
212 schoenebeck 2879 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
213     if (!pNote) return successResult();
214 schoenebeck 2630
215 schoenebeck 2879 Event e = pNote->cause;
216     e.Init(); // clear IDs
217     e.CopyTimeFrom(m_vm->m_event->cause); // set fragment time for "now"
218 schoenebeck 2938 e.Type = Event::type_stop_note;
219     e.Param.Note.ID = id.noteID();
220     e.Param.Note.Key = pNote->hostKey;
221 schoenebeck 2630 e.Param.Note.Velocity = velocity;
222    
223 schoenebeck 2879 pEngineChannel->ScheduleEventMicroSec(&e, 0);
224 schoenebeck 2630 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
225     VMIntArrayExpr* ids = args->arg(0)->asIntArray();
226     for (int i = 0; i < ids->arraySize(); ++i) {
227 schoenebeck 2879 const ScriptID id = ids->evalIntElement(i);
228     if (!id || !id.isNoteID()) continue;
229 schoenebeck 2630
230 schoenebeck 2879 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
231     if (!pNote) continue;
232 schoenebeck 2630
233 schoenebeck 2879 Event e = pNote->cause;
234     e.Init(); // clear IDs
235     e.CopyTimeFrom(m_vm->m_event->cause); // set fragment time for "now"
236 schoenebeck 2938 e.Type = Event::type_stop_note;
237     e.Param.Note.ID = id.noteID();
238     e.Param.Note.Key = pNote->hostKey;
239 schoenebeck 2630 e.Param.Note.Velocity = velocity;
240    
241 schoenebeck 2879 pEngineChannel->ScheduleEventMicroSec(&e, 0);
242 schoenebeck 2630 }
243 schoenebeck 2629 }
244    
245 schoenebeck 2630 return successResult();
246     }
247    
248 schoenebeck 2931 // set_event_mark() function
249    
250 schoenebeck 2630 InstrumentScriptVMFunction_set_event_mark::InstrumentScriptVMFunction_set_event_mark(InstrumentScriptVM* parent)
251     : m_vm(parent)
252     {
253     }
254    
255     VMFnResult* InstrumentScriptVMFunction_set_event_mark::exec(VMFnArgs* args) {
256 schoenebeck 2879 const ScriptID id = args->arg(0)->asInt()->evalInt();
257     const int groupID = args->arg(1)->asInt()->evalInt();
258 schoenebeck 2630
259     if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
260     errMsg("set_event_mark(): argument 2 is an invalid group id");
261 schoenebeck 2629 return errorResult();
262     }
263    
264     AbstractEngineChannel* pEngineChannel =
265     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
266    
267 schoenebeck 2879 // check if the event/note still exists
268     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 schoenebeck 2629
281 schoenebeck 2879 pEngineChannel->pScript->eventGroups[groupID].insert(id);
282 schoenebeck 2629
283 schoenebeck 2630 return successResult();
284     }
285 schoenebeck 2629
286 schoenebeck 2931 // delete_event_mark() function
287    
288 schoenebeck 2630 InstrumentScriptVMFunction_delete_event_mark::InstrumentScriptVMFunction_delete_event_mark(InstrumentScriptVM* parent)
289     : m_vm(parent)
290     {
291     }
292    
293     VMFnResult* InstrumentScriptVMFunction_delete_event_mark::exec(VMFnArgs* args) {
294 schoenebeck 2879 const ScriptID id = args->arg(0)->asInt()->evalInt();
295     const int groupID = args->arg(1)->asInt()->evalInt();
296 schoenebeck 2630
297     if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
298     errMsg("delete_event_mark(): argument 2 is an invalid group id");
299     return errorResult();
300     }
301    
302     AbstractEngineChannel* pEngineChannel =
303     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
304    
305 schoenebeck 2879 pEngineChannel->pScript->eventGroups[groupID].erase(id);
306 schoenebeck 2630
307 schoenebeck 2629 return successResult();
308     }
309    
310 schoenebeck 2931 // by_marks() function
311    
312 schoenebeck 2630 InstrumentScriptVMFunction_by_marks::InstrumentScriptVMFunction_by_marks(InstrumentScriptVM* parent)
313     : m_vm(parent)
314     {
315     }
316    
317     int InstrumentScriptVMFunction_by_marks::Result::arraySize() const {
318     return eventGroup->size();
319     }
320    
321     int InstrumentScriptVMFunction_by_marks::Result::evalIntElement(uint i) {
322     return (*eventGroup)[i];
323     }
324    
325     VMFnResult* InstrumentScriptVMFunction_by_marks::errorResult() {
326     m_result.eventGroup = NULL;
327     m_result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
328     return &m_result;
329     }
330    
331     VMFnResult* InstrumentScriptVMFunction_by_marks::successResult(EventGroup* eventGroup) {
332     m_result.eventGroup = eventGroup;
333     m_result.flags = STMT_SUCCESS;
334     return &m_result;
335     }
336    
337     VMFnResult* InstrumentScriptVMFunction_by_marks::exec(VMFnArgs* args) {
338     int groupID = args->arg(0)->asInt()->evalInt();
339    
340     if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
341     errMsg("by_marks(): argument is an invalid group id");
342     return errorResult();
343     }
344    
345     AbstractEngineChannel* pEngineChannel =
346     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
347    
348     return successResult( &pEngineChannel->pScript->eventGroups[groupID] );
349     }
350    
351 schoenebeck 2931 // 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 schoenebeck 2935 #define VM_FILTER_PAR_MAX_VALUE 1000000
610 schoenebeck 2953 #define VM_EG_PAR_MAX_VALUE 1000000
611 schoenebeck 2935
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 schoenebeck 2953
768     // change_attack() function
769 schoenebeck 2935
770 schoenebeck 2953 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 schoenebeck 2935 // 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 schoenebeck 2948 // 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 schoenebeck 2596 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC