/[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 2938 - (hide annotations) (download)
Mon Jul 11 17:10:40 2016 UTC (7 years, 8 months ago) by schoenebeck
File size: 32016 byte(s)
* Fixed behavior of built-in instrument script functions play_note()
  and note_off(), which must be distinguished engine internally
  from "real" MIDI note on/off events in order to avoid
  misbehaviors like hanging notes.
* Bumped version (2.0.0.svn13).

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    
611     // change_cutoff() function
612    
613     InstrumentScriptVMFunction_change_cutoff::InstrumentScriptVMFunction_change_cutoff(InstrumentScriptVM* parent)
614     : m_vm(parent)
615     {
616     }
617    
618     bool InstrumentScriptVMFunction_change_cutoff::acceptsArgType(int iArg, ExprType_t type) const {
619     if (iArg == 0)
620     return type == INT_EXPR || type == INT_ARR_EXPR;
621     else
622     return INT_EXPR;
623     }
624    
625     VMFnResult* InstrumentScriptVMFunction_change_cutoff::exec(VMFnArgs* args) {
626     int cutoff = args->arg(1)->asInt()->evalInt();
627     if (cutoff > VM_FILTER_PAR_MAX_VALUE) {
628     wrnMsg("change_cutoff(): argument 2 may not be larger than 1000000");
629     cutoff = VM_FILTER_PAR_MAX_VALUE;
630     } else if (cutoff < 0) {
631     wrnMsg("change_cutoff(): argument 2 may not be negative");
632     cutoff = 0;
633     }
634    
635     AbstractEngineChannel* pEngineChannel =
636     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
637    
638     if (args->arg(0)->exprType() == INT_EXPR) {
639     const ScriptID id = args->arg(0)->asInt()->evalInt();
640     if (!id) {
641     wrnMsg("change_cutoff(): note ID for argument 1 may not be zero");
642     return successResult();
643     }
644     if (!id.isNoteID()) {
645     wrnMsg("change_cutoff(): argument 1 is not a note ID");
646     return successResult();
647     }
648    
649     NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
650     if (!pNote) return successResult();
651    
652     const float fCutoff = float(cutoff) / float(VM_FILTER_PAR_MAX_VALUE);
653    
654     Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
655     e.Init(); // clear IDs
656     e.Type = Event::type_note_synth_param;
657     e.Param.NoteSynthParam.NoteID = id.noteID();
658     e.Param.NoteSynthParam.Type = Event::synth_param_cutoff;
659     e.Param.NoteSynthParam.Delta = fCutoff;
660     e.Param.NoteSynthParam.Relative = false;
661    
662     pEngineChannel->ScheduleEventMicroSec(&e, 0);
663     } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
664     VMIntArrayExpr* ids = args->arg(0)->asIntArray();
665     for (int i = 0; i < ids->arraySize(); ++i) {
666     const ScriptID id = ids->evalIntElement(i);
667     if (!id || !id.isNoteID()) continue;
668    
669     NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
670     if (!pNote) continue;
671    
672     const float fCutoff = float(cutoff) / float(VM_FILTER_PAR_MAX_VALUE);
673    
674     Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
675     e.Init(); // clear IDs
676     e.Type = Event::type_note_synth_param;
677     e.Param.NoteSynthParam.NoteID = id.noteID();
678     e.Param.NoteSynthParam.Type = Event::synth_param_cutoff;
679     e.Param.NoteSynthParam.Delta = fCutoff;
680     e.Param.NoteSynthParam.Relative = false;
681    
682     pEngineChannel->ScheduleEventMicroSec(&e, 0);
683     }
684     }
685    
686     return successResult();
687     }
688    
689     // change_reso() function
690    
691     InstrumentScriptVMFunction_change_reso::InstrumentScriptVMFunction_change_reso(InstrumentScriptVM* parent)
692     : m_vm(parent)
693     {
694     }
695    
696     bool InstrumentScriptVMFunction_change_reso::acceptsArgType(int iArg, ExprType_t type) const {
697     if (iArg == 0)
698     return type == INT_EXPR || type == INT_ARR_EXPR;
699     else
700     return INT_EXPR;
701     }
702    
703     VMFnResult* InstrumentScriptVMFunction_change_reso::exec(VMFnArgs* args) {
704     int resonance = args->arg(1)->asInt()->evalInt();
705     if (resonance > VM_FILTER_PAR_MAX_VALUE) {
706     wrnMsg("change_reso(): argument 2 may not be larger than 1000000");
707     resonance = VM_FILTER_PAR_MAX_VALUE;
708     } else if (resonance < 0) {
709     wrnMsg("change_reso(): argument 2 may not be negative");
710     resonance = 0;
711     }
712    
713     AbstractEngineChannel* pEngineChannel =
714     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
715    
716     if (args->arg(0)->exprType() == INT_EXPR) {
717     const ScriptID id = args->arg(0)->asInt()->evalInt();
718     if (!id) {
719     wrnMsg("change_reso(): note ID for argument 1 may not be zero");
720     return successResult();
721     }
722     if (!id.isNoteID()) {
723     wrnMsg("change_reso(): argument 1 is not a note ID");
724     return successResult();
725     }
726    
727     NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
728     if (!pNote) return successResult();
729    
730     const float fResonance = float(resonance) / float(VM_FILTER_PAR_MAX_VALUE);
731    
732     Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
733     e.Init(); // clear IDs
734     e.Type = Event::type_note_synth_param;
735     e.Param.NoteSynthParam.NoteID = id.noteID();
736     e.Param.NoteSynthParam.Type = Event::synth_param_resonance;
737     e.Param.NoteSynthParam.Delta = fResonance;
738     e.Param.NoteSynthParam.Relative = false;
739    
740     pEngineChannel->ScheduleEventMicroSec(&e, 0);
741     } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
742     VMIntArrayExpr* ids = args->arg(0)->asIntArray();
743     for (int i = 0; i < ids->arraySize(); ++i) {
744     const ScriptID id = ids->evalIntElement(i);
745     if (!id || !id.isNoteID()) continue;
746    
747     NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
748     if (!pNote) continue;
749    
750     const float fResonance = float(resonance) / float(VM_FILTER_PAR_MAX_VALUE);
751    
752     Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
753     e.Init(); // clear IDs
754     e.Type = Event::type_note_synth_param;
755     e.Param.NoteSynthParam.NoteID = id.noteID();
756     e.Param.NoteSynthParam.Type = Event::synth_param_resonance;
757     e.Param.NoteSynthParam.Delta = fResonance;
758     e.Param.NoteSynthParam.Relative = false;
759    
760     pEngineChannel->ScheduleEventMicroSec(&e, 0);
761     }
762     }
763    
764     return successResult();
765     }
766    
767     // event_status() function
768    
769     InstrumentScriptVMFunction_event_status::InstrumentScriptVMFunction_event_status(InstrumentScriptVM* parent)
770     : m_vm(parent)
771     {
772     }
773    
774     VMFnResult* InstrumentScriptVMFunction_event_status::exec(VMFnArgs* args) {
775     AbstractEngineChannel* pEngineChannel =
776     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
777    
778     const ScriptID id = args->arg(0)->asInt()->evalInt();
779     if (!id) {
780     wrnMsg("event_status(): note ID for argument 1 may not be zero");
781     return successResult(EVENT_STATUS_INACTIVE);
782     }
783     if (!id.isNoteID()) {
784     wrnMsg("event_status(): argument 1 is not a note ID");
785     return successResult(EVENT_STATUS_INACTIVE);
786     }
787    
788     NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
789     return successResult(pNote ? EVENT_STATUS_NOTE_QUEUE : EVENT_STATUS_INACTIVE);
790     }
791    
792 schoenebeck 2596 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC