/[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 2935 - (hide annotations) (download)
Sun Jul 10 14:24:13 2016 UTC (17 months ago) by schoenebeck
File size: 31786 byte(s)
* NKSP: Added & implemented built-in script function "change_cutoff()".
* NKSP: Added & implemented built-in script function "change_reso()".
* NKSP: Added & implemented built-in script function "event_status()".
* NKSP: Added built-in script constants "$EVENT_STATUS_INACTIVE" and
  "$EVENT_STATUS_NOTE_QUEUE" both for being used as flags for
  built-in "event_status()" script function.
* NKSP language: Added support for bitwise operators ".or.", ".and."
  and ".not.".
* NKSP language scanner: Fixed IDs matching to require at least one
  character (i.e. when matching function names or variable names).
* NKSP language scanner: disabled unusued rules.
* Bumped version (2.0.0.svn12).

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 2596 e.Type = Event::type_note_on;
57     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 2879 // if a duration is supplied (and note-on event was scheduled
71     // successfully above), then schedule a subsequent note-off event
72     if (id && duration > 0) {
73 schoenebeck 2871 e.Type = Event::type_note_off;
74     e.Param.Note.Velocity = 127;
75     pEngineChannel->ScheduleEventMicroSec(&e, duration);
76     }
77    
78 schoenebeck 2879 // even if id is null, don't return an errorResult() here, because that
79     // would abort the script, and under heavy load it may be considerable
80     // that ScheduleNoteMicroSec() fails above, so simply ignore that
81     return successResult( ScriptID::fromNoteID(id) );
82 schoenebeck 2598 }
83    
84 schoenebeck 2931 // set_controller() function
85    
86 schoenebeck 2600 InstrumentScriptVMFunction_set_controller::InstrumentScriptVMFunction_set_controller(InstrumentScriptVM* parent)
87     : m_vm(parent)
88     {
89     }
90    
91     VMFnResult* InstrumentScriptVMFunction_set_controller::exec(VMFnArgs* args) {
92     int controller = args->arg(0)->asInt()->evalInt();
93     int value = args->arg(1)->asInt()->evalInt();
94    
95     AbstractEngineChannel* pEngineChannel =
96     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
97    
98 schoenebeck 2879 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
99     e.Init(); // clear IDs
100 schoenebeck 2600 if (controller == CTRL_TABLE_IDX_AFTERTOUCH) {
101     e.Type = Event::type_channel_pressure;
102     e.Param.ChannelPressure.Value = value & 127;
103     } else if (controller == CTRL_TABLE_IDX_PITCHBEND) {
104     e.Type = Event::type_pitchbend;
105     e.Param.Pitch.Pitch = value;
106     } else if (controller >= 0 && controller <= 127) {
107     e.Type = Event::type_control_change;
108     e.Param.CC.Controller = controller;
109     e.Param.CC.Value = value;
110     } else {
111     errMsg("set_controller(): argument 1 is an invalid controller");
112     return errorResult();
113     }
114    
115 schoenebeck 2879 const event_id_t id = pEngineChannel->ScheduleEventMicroSec(&e, 0);
116 schoenebeck 2600
117 schoenebeck 2879 // even if id is null, don't return an errorResult() here, because that
118     // would abort the script, and under heavy load it may be considerable
119     // that ScheduleEventMicroSec() fails above, so simply ignore that
120     return successResult( ScriptID::fromEventID(id) );
121 schoenebeck 2931 }
122 schoenebeck 2600
123 schoenebeck 2931 // ignore_event() function
124    
125 schoenebeck 2598 InstrumentScriptVMFunction_ignore_event::InstrumentScriptVMFunction_ignore_event(InstrumentScriptVM* parent)
126     : m_vm(parent)
127     {
128     }
129    
130 schoenebeck 2630 bool InstrumentScriptVMFunction_ignore_event::acceptsArgType(int iArg, ExprType_t type) const {
131     return type == INT_EXPR || type == INT_ARR_EXPR;
132     }
133    
134 schoenebeck 2598 VMFnResult* InstrumentScriptVMFunction_ignore_event::exec(VMFnArgs* args) {
135     AbstractEngineChannel* pEngineChannel =
136 schoenebeck 2630 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
137 schoenebeck 2598
138 schoenebeck 2630 if (args->arg(0)->exprType() == INT_EXPR) {
139 schoenebeck 2879 const ScriptID id = args->arg(0)->asInt()->evalInt();
140     if (!id) {
141     wrnMsg("ignore_event(): event ID argument may not be zero");
142     // not errorResult(), because that would abort the script, not intentional in this case
143 schoenebeck 2630 return successResult();
144     }
145 schoenebeck 2879 pEngineChannel->IgnoreEventByScriptID(id);
146 schoenebeck 2630 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
147     VMIntArrayExpr* ids = args->arg(0)->asIntArray();
148     for (int i = 0; i < ids->arraySize(); ++i) {
149 schoenebeck 2879 const ScriptID id = ids->evalIntElement(i);
150     pEngineChannel->IgnoreEventByScriptID(id);
151 schoenebeck 2630 }
152     }
153 schoenebeck 2598
154 schoenebeck 2596 return successResult();
155     }
156    
157 schoenebeck 2931 // ignore_controller() function
158    
159 schoenebeck 2598 InstrumentScriptVMFunction_ignore_controller::InstrumentScriptVMFunction_ignore_controller(InstrumentScriptVM* parent)
160     : m_vm(parent)
161     {
162     }
163    
164     VMFnResult* InstrumentScriptVMFunction_ignore_controller::exec(VMFnArgs* args) {
165 schoenebeck 2879 const ScriptID id = (args->argsCount() >= 1) ? args->arg(0)->asInt()->evalInt() : m_vm->m_event->id;
166     if (!id && args->argsCount() >= 1) {
167     wrnMsg("ignore_controller(): event ID argument may not be zero");
168 schoenebeck 2598 return successResult();
169     }
170    
171     AbstractEngineChannel* pEngineChannel =
172     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
173    
174 schoenebeck 2879 pEngineChannel->IgnoreEventByScriptID(id);
175 schoenebeck 2598
176     return successResult();
177     }
178    
179 schoenebeck 2931 // note_off() function
180    
181 schoenebeck 2629 InstrumentScriptVMFunction_note_off::InstrumentScriptVMFunction_note_off(InstrumentScriptVM* parent)
182     : m_vm(parent)
183     {
184     }
185    
186 schoenebeck 2630 bool InstrumentScriptVMFunction_note_off::acceptsArgType(int iArg, ExprType_t type) const {
187     return type == INT_EXPR || type == INT_ARR_EXPR;
188     }
189    
190 schoenebeck 2629 VMFnResult* InstrumentScriptVMFunction_note_off::exec(VMFnArgs* args) {
191 schoenebeck 2630 AbstractEngineChannel* pEngineChannel =
192     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
193    
194 schoenebeck 2629 int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;
195 schoenebeck 2630 if (velocity < 0 || velocity > 127) {
196     errMsg("note_off(): argument 2 is an invalid velocity value");
197     return errorResult();
198     }
199 schoenebeck 2629
200 schoenebeck 2630 if (args->arg(0)->exprType() == INT_EXPR) {
201 schoenebeck 2879 const ScriptID id = args->arg(0)->asInt()->evalInt();
202     if (!id) {
203     wrnMsg("note_off(): note ID for argument 1 may not be zero");
204 schoenebeck 2630 return successResult();
205     }
206 schoenebeck 2879 if (!id.isNoteID()) {
207     wrnMsg("note_off(): argument 1 is not a note ID");
208     return successResult();
209     }
210 schoenebeck 2630
211 schoenebeck 2879 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
212     if (!pNote) return successResult();
213 schoenebeck 2630
214 schoenebeck 2879 Event e = pNote->cause;
215     e.Init(); // clear IDs
216     e.CopyTimeFrom(m_vm->m_event->cause); // set fragment time for "now"
217 schoenebeck 2630 e.Type = Event::type_note_off;
218     e.Param.Note.Velocity = velocity;
219    
220 schoenebeck 2879 pEngineChannel->ScheduleEventMicroSec(&e, 0);
221 schoenebeck 2630 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
222     VMIntArrayExpr* ids = args->arg(0)->asIntArray();
223     for (int i = 0; i < ids->arraySize(); ++i) {
224 schoenebeck 2879 const ScriptID id = ids->evalIntElement(i);
225     if (!id || !id.isNoteID()) continue;
226 schoenebeck 2630
227 schoenebeck 2879 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
228     if (!pNote) continue;
229 schoenebeck 2630
230 schoenebeck 2879 Event e = pNote->cause;
231     e.Init(); // clear IDs
232     e.CopyTimeFrom(m_vm->m_event->cause); // set fragment time for "now"
233 schoenebeck 2630 e.Type = Event::type_note_off;
234     e.Param.Note.Velocity = velocity;
235    
236 schoenebeck 2879 pEngineChannel->ScheduleEventMicroSec(&e, 0);
237 schoenebeck 2630 }
238 schoenebeck 2629 }
239    
240 schoenebeck 2630 return successResult();
241     }
242    
243 schoenebeck 2931 // set_event_mark() function
244    
245 schoenebeck 2630 InstrumentScriptVMFunction_set_event_mark::InstrumentScriptVMFunction_set_event_mark(InstrumentScriptVM* parent)
246     : m_vm(parent)
247     {
248     }
249    
250     VMFnResult* InstrumentScriptVMFunction_set_event_mark::exec(VMFnArgs* args) {
251 schoenebeck 2879 const ScriptID id = args->arg(0)->asInt()->evalInt();
252     const int groupID = args->arg(1)->asInt()->evalInt();
253 schoenebeck 2630
254     if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
255     errMsg("set_event_mark(): argument 2 is an invalid group id");
256 schoenebeck 2629 return errorResult();
257     }
258    
259     AbstractEngineChannel* pEngineChannel =
260     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
261    
262 schoenebeck 2879 // check if the event/note still exists
263     switch (id.type()) {
264     case ScriptID::EVENT: {
265     RTList<Event>::Iterator itEvent = pEngineChannel->pEngine->EventByID( id.eventID() );
266     if (!itEvent) return successResult();
267     break;
268     }
269     case ScriptID::NOTE: {
270     NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
271     if (!pNote) return successResult();
272     break;
273     }
274     }
275 schoenebeck 2629
276 schoenebeck 2879 pEngineChannel->pScript->eventGroups[groupID].insert(id);
277 schoenebeck 2629
278 schoenebeck 2630 return successResult();
279     }
280 schoenebeck 2629
281 schoenebeck 2931 // delete_event_mark() function
282    
283 schoenebeck 2630 InstrumentScriptVMFunction_delete_event_mark::InstrumentScriptVMFunction_delete_event_mark(InstrumentScriptVM* parent)
284     : m_vm(parent)
285     {
286     }
287    
288     VMFnResult* InstrumentScriptVMFunction_delete_event_mark::exec(VMFnArgs* args) {
289 schoenebeck 2879 const ScriptID id = args->arg(0)->asInt()->evalInt();
290     const int groupID = args->arg(1)->asInt()->evalInt();
291 schoenebeck 2630
292     if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
293     errMsg("delete_event_mark(): argument 2 is an invalid group id");
294     return errorResult();
295     }
296    
297     AbstractEngineChannel* pEngineChannel =
298     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
299    
300 schoenebeck 2879 pEngineChannel->pScript->eventGroups[groupID].erase(id);
301 schoenebeck 2630
302 schoenebeck 2629 return successResult();
303     }
304    
305 schoenebeck 2931 // by_marks() function
306    
307 schoenebeck 2630 InstrumentScriptVMFunction_by_marks::InstrumentScriptVMFunction_by_marks(InstrumentScriptVM* parent)
308     : m_vm(parent)
309     {
310     }
311    
312     int InstrumentScriptVMFunction_by_marks::Result::arraySize() const {
313     return eventGroup->size();
314     }
315    
316     int InstrumentScriptVMFunction_by_marks::Result::evalIntElement(uint i) {
317     return (*eventGroup)[i];
318     }
319    
320     VMFnResult* InstrumentScriptVMFunction_by_marks::errorResult() {
321     m_result.eventGroup = NULL;
322     m_result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
323     return &m_result;
324     }
325    
326     VMFnResult* InstrumentScriptVMFunction_by_marks::successResult(EventGroup* eventGroup) {
327     m_result.eventGroup = eventGroup;
328     m_result.flags = STMT_SUCCESS;
329     return &m_result;
330     }
331    
332     VMFnResult* InstrumentScriptVMFunction_by_marks::exec(VMFnArgs* args) {
333     int groupID = args->arg(0)->asInt()->evalInt();
334    
335     if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
336     errMsg("by_marks(): argument is an invalid group id");
337     return errorResult();
338     }
339    
340     AbstractEngineChannel* pEngineChannel =
341     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
342    
343     return successResult( &pEngineChannel->pScript->eventGroups[groupID] );
344     }
345    
346 schoenebeck 2931 // change_vol() function
347    
348     InstrumentScriptVMFunction_change_vol::InstrumentScriptVMFunction_change_vol(InstrumentScriptVM* parent)
349     : m_vm(parent)
350     {
351     }
352    
353     bool InstrumentScriptVMFunction_change_vol::acceptsArgType(int iArg, ExprType_t type) const {
354     if (iArg == 0)
355     return type == INT_EXPR || type == INT_ARR_EXPR;
356     else
357     return INT_EXPR;
358     }
359    
360     VMFnResult* InstrumentScriptVMFunction_change_vol::exec(VMFnArgs* args) {
361     int volume = args->arg(1)->asInt()->evalInt(); // volume change in milli dB
362     bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;
363    
364     AbstractEngineChannel* pEngineChannel =
365     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
366    
367     if (args->arg(0)->exprType() == INT_EXPR) {
368     const ScriptID id = args->arg(0)->asInt()->evalInt();
369     if (!id) {
370     wrnMsg("change_vol(): note ID for argument 1 may not be zero");
371     return successResult();
372     }
373     if (!id.isNoteID()) {
374     wrnMsg("change_vol(): argument 1 is not a note ID");
375     return successResult();
376     }
377    
378     NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
379     if (!pNote) return successResult();
380    
381     const float fVolumeLin = RTMath::DecibelToLinRatio(float(volume) / 1000.f);
382     // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
383     /*if (relative)
384     pNote->Override.Volume *= fVolumeLin;
385     else
386     pNote->Override.Volume = fVolumeLin;*/
387    
388     Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
389     e.Init(); // clear IDs
390     e.Type = Event::type_note_synth_param;
391     e.Param.NoteSynthParam.NoteID = id.noteID();
392     e.Param.NoteSynthParam.Type = Event::synth_param_volume;
393     e.Param.NoteSynthParam.Delta = fVolumeLin;
394     e.Param.NoteSynthParam.Relative = relative;
395    
396     pEngineChannel->ScheduleEventMicroSec(&e, 0);
397     } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
398     VMIntArrayExpr* ids = args->arg(0)->asIntArray();
399     for (int i = 0; i < ids->arraySize(); ++i) {
400     const ScriptID id = ids->evalIntElement(i);
401     if (!id || !id.isNoteID()) continue;
402    
403     NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
404     if (!pNote) continue;
405    
406     const float fVolumeLin = RTMath::DecibelToLinRatio(float(volume) / 1000.f);
407     // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
408     /*if (relative)
409     pNote->Override.Volume *= fVolumeLin;
410     else
411     pNote->Override.Volume = fVolumeLin;*/
412    
413     Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
414     e.Init(); // clear IDs
415     e.Type = Event::type_note_synth_param;
416     e.Param.NoteSynthParam.NoteID = id.noteID();
417     e.Param.NoteSynthParam.Type = Event::synth_param_volume;
418     e.Param.NoteSynthParam.Delta = fVolumeLin;
419     e.Param.NoteSynthParam.Relative = relative;
420    
421     pEngineChannel->ScheduleEventMicroSec(&e, 0);
422     }
423     }
424    
425     return successResult();
426     }
427    
428     // change_tune() function
429    
430     InstrumentScriptVMFunction_change_tune::InstrumentScriptVMFunction_change_tune(InstrumentScriptVM* parent)
431     : m_vm(parent)
432     {
433     }
434    
435     bool InstrumentScriptVMFunction_change_tune::acceptsArgType(int iArg, ExprType_t type) const {
436     if (iArg == 0)
437     return type == INT_EXPR || type == INT_ARR_EXPR;
438     else
439     return INT_EXPR;
440     }
441    
442     VMFnResult* InstrumentScriptVMFunction_change_tune::exec(VMFnArgs* args) {
443     int tune = args->arg(1)->asInt()->evalInt(); // tuning change in milli cents
444     bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;
445    
446     AbstractEngineChannel* pEngineChannel =
447     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
448    
449     if (args->arg(0)->exprType() == INT_EXPR) {
450     const ScriptID id = args->arg(0)->asInt()->evalInt();
451     if (!id) {
452     wrnMsg("change_tune(): note ID for argument 1 may not be zero");
453     return successResult();
454     }
455     if (!id.isNoteID()) {
456     wrnMsg("change_tune(): argument 1 is not a note ID");
457     return successResult();
458     }
459    
460     NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
461     if (!pNote) return successResult();
462    
463     const float fFreqRatio = RTMath::CentsToFreqRatioUnlimited(float(tune) / 1000.f);
464     // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
465     /*if (relative)
466     pNote->Override.Pitch *= fFreqRatio;
467     else
468     pNote->Override.Pitch = fFreqRatio;*/
469    
470     Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
471     e.Init(); // clear IDs
472     e.Type = Event::type_note_synth_param;
473     e.Param.NoteSynthParam.NoteID = id.noteID();
474     e.Param.NoteSynthParam.Type = Event::synth_param_pitch;
475     e.Param.NoteSynthParam.Delta = fFreqRatio;
476     e.Param.NoteSynthParam.Relative = relative;
477    
478     pEngineChannel->ScheduleEventMicroSec(&e, 0);
479     } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
480     VMIntArrayExpr* ids = args->arg(0)->asIntArray();
481     for (int i = 0; i < ids->arraySize(); ++i) {
482     const ScriptID id = ids->evalIntElement(i);
483     if (!id || !id.isNoteID()) continue;
484    
485     NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
486     if (!pNote) continue;
487    
488     const float fFreqRatio = RTMath::CentsToFreqRatioUnlimited(float(tune) / 1000.f);
489     // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
490     /*if (relative)
491     pNote->Override.Pitch *= fFreqRatio;
492     else
493     pNote->Override.Pitch = fFreqRatio;*/
494    
495     Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
496     e.Init(); // clear IDs
497     e.Type = Event::type_note_synth_param;
498     e.Param.NoteSynthParam.NoteID = id.noteID();
499     e.Param.NoteSynthParam.Type = Event::synth_param_pitch;
500     e.Param.NoteSynthParam.Delta = fFreqRatio;
501     e.Param.NoteSynthParam.Relative = relative;
502    
503     pEngineChannel->ScheduleEventMicroSec(&e, 0);
504     }
505     }
506    
507     return successResult();
508     }
509    
510     // change_pan() function
511    
512     InstrumentScriptVMFunction_change_pan::InstrumentScriptVMFunction_change_pan(InstrumentScriptVM* parent)
513     : m_vm(parent)
514     {
515     }
516    
517     bool InstrumentScriptVMFunction_change_pan::acceptsArgType(int iArg, ExprType_t type) const {
518     if (iArg == 0)
519     return type == INT_EXPR || type == INT_ARR_EXPR;
520     else
521     return INT_EXPR;
522     }
523    
524     VMFnResult* InstrumentScriptVMFunction_change_pan::exec(VMFnArgs* args) {
525     int pan = args->arg(1)->asInt()->evalInt();
526     bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;
527    
528     if (pan > 1000) {
529     wrnMsg("change_pan(): argument 2 may not be larger than 1000");
530     pan = 1000;
531     } else if (pan < -1000) {
532     wrnMsg("change_pan(): argument 2 may not be smaller than -1000");
533     pan = -1000;
534     }
535    
536     AbstractEngineChannel* pEngineChannel =
537     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
538    
539     if (args->arg(0)->exprType() == INT_EXPR) {
540     const ScriptID id = args->arg(0)->asInt()->evalInt();
541     if (!id) {
542     wrnMsg("change_pan(): note ID for argument 1 may not be zero");
543     return successResult();
544     }
545     if (!id.isNoteID()) {
546     wrnMsg("change_pan(): argument 1 is not a note ID");
547     return successResult();
548     }
549    
550     NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
551     if (!pNote) return successResult();
552    
553     const float fPan = float(pan) / 1000.f;
554     // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
555     /*if (relative) {
556     pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);
557     } else {
558     pNote->Override.Pan = fPan;
559     pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() calls on same note with 'relative' being set
560     }*/
561    
562     Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
563     e.Init(); // clear IDs
564     e.Type = Event::type_note_synth_param;
565     e.Param.NoteSynthParam.NoteID = id.noteID();
566     e.Param.NoteSynthParam.Type = Event::synth_param_pan;
567     e.Param.NoteSynthParam.Delta = fPan;
568     e.Param.NoteSynthParam.Relative = relative;
569    
570     pEngineChannel->ScheduleEventMicroSec(&e, 0);
571     } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
572     VMIntArrayExpr* ids = args->arg(0)->asIntArray();
573     for (int i = 0; i < ids->arraySize(); ++i) {
574     const ScriptID id = ids->evalIntElement(i);
575     if (!id || !id.isNoteID()) continue;
576    
577     NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
578     if (!pNote) continue;
579    
580     const float fPan = float(pan) / 1000.f;
581     // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
582     /*if (relative) {
583     pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);
584     } else {
585     pNote->Override.Pan = fPan;
586     pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() calls on same note with 'relative' being set
587     }*/
588    
589     Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
590     e.Init(); // clear IDs
591     e.Type = Event::type_note_synth_param;
592     e.Param.NoteSynthParam.NoteID = id.noteID();
593     e.Param.NoteSynthParam.Type = Event::synth_param_pan;
594     e.Param.NoteSynthParam.Delta = fPan;
595     e.Param.NoteSynthParam.Relative = relative;
596    
597     pEngineChannel->ScheduleEventMicroSec(&e, 0);
598     }
599     }
600    
601     return successResult();
602     }
603    
604 schoenebeck 2935 #define VM_FILTER_PAR_MAX_VALUE 1000000
605    
606     // change_cutoff() function
607    
608     InstrumentScriptVMFunction_change_cutoff::InstrumentScriptVMFunction_change_cutoff(InstrumentScriptVM* parent)
609     : m_vm(parent)
610     {
611     }
612    
613     bool InstrumentScriptVMFunction_change_cutoff::acceptsArgType(int iArg, ExprType_t type) const {
614     if (iArg == 0)
615     return type == INT_EXPR || type == INT_ARR_EXPR;
616     else
617     return INT_EXPR;
618     }
619    
620     VMFnResult* InstrumentScriptVMFunction_change_cutoff::exec(VMFnArgs* args) {
621     int cutoff = args->arg(1)->asInt()->evalInt();
622     if (cutoff > VM_FILTER_PAR_MAX_VALUE) {
623     wrnMsg("change_cutoff(): argument 2 may not be larger than 1000000");
624     cutoff = VM_FILTER_PAR_MAX_VALUE;
625     } else if (cutoff < 0) {
626     wrnMsg("change_cutoff(): argument 2 may not be negative");
627     cutoff = 0;
628     }
629    
630     AbstractEngineChannel* pEngineChannel =
631     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
632    
633     if (args->arg(0)->exprType() == INT_EXPR) {
634     const ScriptID id = args->arg(0)->asInt()->evalInt();
635     if (!id) {
636     wrnMsg("change_cutoff(): note ID for argument 1 may not be zero");
637     return successResult();
638     }
639     if (!id.isNoteID()) {
640     wrnMsg("change_cutoff(): argument 1 is not a note ID");
641     return successResult();
642     }
643    
644     NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
645     if (!pNote) return successResult();
646    
647     const float fCutoff = float(cutoff) / float(VM_FILTER_PAR_MAX_VALUE);
648    
649     Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
650     e.Init(); // clear IDs
651     e.Type = Event::type_note_synth_param;
652     e.Param.NoteSynthParam.NoteID = id.noteID();
653     e.Param.NoteSynthParam.Type = Event::synth_param_cutoff;
654     e.Param.NoteSynthParam.Delta = fCutoff;
655     e.Param.NoteSynthParam.Relative = false;
656    
657     pEngineChannel->ScheduleEventMicroSec(&e, 0);
658     } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
659     VMIntArrayExpr* ids = args->arg(0)->asIntArray();
660     for (int i = 0; i < ids->arraySize(); ++i) {
661     const ScriptID id = ids->evalIntElement(i);
662     if (!id || !id.isNoteID()) continue;
663    
664     NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
665     if (!pNote) continue;
666    
667     const float fCutoff = float(cutoff) / float(VM_FILTER_PAR_MAX_VALUE);
668    
669     Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
670     e.Init(); // clear IDs
671     e.Type = Event::type_note_synth_param;
672     e.Param.NoteSynthParam.NoteID = id.noteID();
673     e.Param.NoteSynthParam.Type = Event::synth_param_cutoff;
674     e.Param.NoteSynthParam.Delta = fCutoff;
675     e.Param.NoteSynthParam.Relative = false;
676    
677     pEngineChannel->ScheduleEventMicroSec(&e, 0);
678     }
679     }
680    
681     return successResult();
682     }
683    
684     // change_reso() function
685    
686     InstrumentScriptVMFunction_change_reso::InstrumentScriptVMFunction_change_reso(InstrumentScriptVM* parent)
687     : m_vm(parent)
688     {
689     }
690    
691     bool InstrumentScriptVMFunction_change_reso::acceptsArgType(int iArg, ExprType_t type) const {
692     if (iArg == 0)
693     return type == INT_EXPR || type == INT_ARR_EXPR;
694     else
695     return INT_EXPR;
696     }
697    
698     VMFnResult* InstrumentScriptVMFunction_change_reso::exec(VMFnArgs* args) {
699     int resonance = args->arg(1)->asInt()->evalInt();
700     if (resonance > VM_FILTER_PAR_MAX_VALUE) {
701     wrnMsg("change_reso(): argument 2 may not be larger than 1000000");
702     resonance = VM_FILTER_PAR_MAX_VALUE;
703     } else if (resonance < 0) {
704     wrnMsg("change_reso(): argument 2 may not be negative");
705     resonance = 0;
706     }
707    
708     AbstractEngineChannel* pEngineChannel =
709     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
710    
711     if (args->arg(0)->exprType() == INT_EXPR) {
712     const ScriptID id = args->arg(0)->asInt()->evalInt();
713     if (!id) {
714     wrnMsg("change_reso(): note ID for argument 1 may not be zero");
715     return successResult();
716     }
717     if (!id.isNoteID()) {
718     wrnMsg("change_reso(): argument 1 is not a note ID");
719     return successResult();
720     }
721    
722     NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
723     if (!pNote) return successResult();
724    
725     const float fResonance = float(resonance) / float(VM_FILTER_PAR_MAX_VALUE);
726    
727     Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
728     e.Init(); // clear IDs
729     e.Type = Event::type_note_synth_param;
730     e.Param.NoteSynthParam.NoteID = id.noteID();
731     e.Param.NoteSynthParam.Type = Event::synth_param_resonance;
732     e.Param.NoteSynthParam.Delta = fResonance;
733     e.Param.NoteSynthParam.Relative = false;
734    
735     pEngineChannel->ScheduleEventMicroSec(&e, 0);
736     } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
737     VMIntArrayExpr* ids = args->arg(0)->asIntArray();
738     for (int i = 0; i < ids->arraySize(); ++i) {
739     const ScriptID id = ids->evalIntElement(i);
740     if (!id || !id.isNoteID()) continue;
741    
742     NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
743     if (!pNote) continue;
744    
745     const float fResonance = float(resonance) / float(VM_FILTER_PAR_MAX_VALUE);
746    
747     Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
748     e.Init(); // clear IDs
749     e.Type = Event::type_note_synth_param;
750     e.Param.NoteSynthParam.NoteID = id.noteID();
751     e.Param.NoteSynthParam.Type = Event::synth_param_resonance;
752     e.Param.NoteSynthParam.Delta = fResonance;
753     e.Param.NoteSynthParam.Relative = false;
754    
755     pEngineChannel->ScheduleEventMicroSec(&e, 0);
756     }
757     }
758    
759     return successResult();
760     }
761    
762     // event_status() function
763    
764     InstrumentScriptVMFunction_event_status::InstrumentScriptVMFunction_event_status(InstrumentScriptVM* parent)
765     : m_vm(parent)
766     {
767     }
768    
769     VMFnResult* InstrumentScriptVMFunction_event_status::exec(VMFnArgs* args) {
770     AbstractEngineChannel* pEngineChannel =
771     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
772    
773     const ScriptID id = args->arg(0)->asInt()->evalInt();
774     if (!id) {
775     wrnMsg("event_status(): note ID for argument 1 may not be zero");
776     return successResult(EVENT_STATUS_INACTIVE);
777     }
778     if (!id.isNoteID()) {
779     wrnMsg("event_status(): argument 1 is not a note ID");
780     return successResult(EVENT_STATUS_INACTIVE);
781     }
782    
783     NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
784     return successResult(pNote ? EVENT_STATUS_NOTE_QUEUE : EVENT_STATUS_INACTIVE);
785     }
786    
787 schoenebeck 2596 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC