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

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

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

revision 2629 by schoenebeck, Thu Jun 12 18:25:11 2014 UTC revision 2935 by schoenebeck, Sun Jul 10 14:24:13 2016 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (c) 2014 Christian Schoenebeck   * Copyright (c) 2014-2016 Christian Schoenebeck
3   *   *
4   * http://www.linuxsampler.org   * http://www.linuxsampler.org
5   *   *
# Line 12  Line 12 
12  #include "../AbstractEngineChannel.h"  #include "../AbstractEngineChannel.h"
13    
14  namespace LinuxSampler {  namespace LinuxSampler {
15        
16        // play_note() function
17    
18      InstrumentScriptVMFunction_play_note::InstrumentScriptVMFunction_play_note(InstrumentScriptVM* parent)      InstrumentScriptVMFunction_play_note::InstrumentScriptVMFunction_play_note(InstrumentScriptVM* parent)
19          : m_vm(parent)          : m_vm(parent)
# Line 22  namespace LinuxSampler { Line 24  namespace LinuxSampler {
24          int note = args->arg(0)->asInt()->evalInt();          int note = args->arg(0)->asInt()->evalInt();
25          int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;          int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;
26          int sampleoffset = (args->argsCount() >= 3) ? args->arg(2)->asInt()->evalInt() : 0;          int sampleoffset = (args->argsCount() >= 3) ? args->arg(2)->asInt()->evalInt() : 0;
27          int duration = (args->argsCount() >= 4) ? args->arg(3)->asInt()->evalInt() : 0; //TODO: once -1 is implemented, it might be a better default value instead of 0          int duration = (args->argsCount() >= 4) ? args->arg(3)->asInt()->evalInt() : 0; //TODO: -1 might be a better default value instead of 0
28    
29          if (note < 0 || note > 127) {          if (note < 0 || note > 127) {
30              errMsg("play_note(): argument 1 is an invalid note number");              errMsg("play_note(): argument 1 is an invalid note number");
31              return errorResult(-1);              return errorResult(0);
32          }          }
33    
34          if (velocity < 0 || velocity > 127) {          if (velocity < 0 || velocity > 127) {
35              errMsg("play_note(): argument 2 is an invalid velocity value");              errMsg("play_note(): argument 2 is an invalid velocity value");
36              return errorResult(-1);              return errorResult(0);
37          }          }
38    
39          if (sampleoffset < 0) {          if (sampleoffset < 0) {
40              errMsg("play_note(): argument 3 may not be a negative sample offset");              errMsg("play_note(): argument 3 may not be a negative sample offset");
41              return errorResult(-1);              return errorResult(0);
42          } else if (sampleoffset != 0) {          } else if (sampleoffset != 0) {
43              wrnMsg("play_note(): argument 3 does not support a sample offset other than 0 yet");              wrnMsg("play_note(): argument 3 does not support a sample offset other than 0 yet");
44          }          }
45    
46          if (duration < -1) {          if (duration < -1) {
47              errMsg("play_note(): argument 4 must be a duration value of at least -1 or higher");              errMsg("play_note(): argument 4 must be a duration value of at least -1 or higher");
48              return errorResult(-1);              return errorResult(0);
         } else if (duration == -1) {  
             wrnMsg("play_note(): argument 4 does not support special value -1 as duration yet");  
         } else if (duration != 0) {  
             wrnMsg("play_note(): argument 4 does not support any other value as 0 as duration yet");  
49          }          }
50    
51          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
52              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
53    
54          Event e = m_vm->m_event->cause;          Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
55            e.Init(); // clear IDs
56          e.Type = Event::type_note_on;          e.Type = Event::type_note_on;
57          e.Param.Note.Key = note;          e.Param.Note.Key = note;
58          e.Param.Note.Velocity = velocity;          e.Param.Note.Velocity = velocity;
59          memset(&e.Format, 0, sizeof(e.Format)); // init format speific stuff with zero          // make this new note dependent to the life time of the original note
60            if (duration == -1) {
61                if (m_vm->currentVMEventHandler()->eventHandlerType() != VM_EVENT_HANDLER_NOTE) {
62                    errMsg("play_note(): -1 for argument 4 may only be used for note event handlers");
63                    return errorResult(0);
64                }
65                e.Param.Note.ParentNoteID = m_vm->m_event->cause.Param.Note.ID;
66            }
67    
68            const note_id_t id = pEngineChannel->ScheduleNoteMicroSec(&e, 0);
69    
70          int id = pEngineChannel->ScheduleEvent(&e, duration);          // 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                e.Type = Event::type_note_off;
74                e.Param.Note.Velocity = 127;
75                pEngineChannel->ScheduleEventMicroSec(&e, duration);
76            }
77    
78          return successResult(id);          // 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      }      }
83    
84        // set_controller() function
85    
86      InstrumentScriptVMFunction_set_controller::InstrumentScriptVMFunction_set_controller(InstrumentScriptVM* parent)      InstrumentScriptVMFunction_set_controller::InstrumentScriptVMFunction_set_controller(InstrumentScriptVM* parent)
87          : m_vm(parent)          : m_vm(parent)
88      {      {
# Line 76  namespace LinuxSampler { Line 95  namespace LinuxSampler {
95          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
96              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
97    
98          Event e = m_vm->m_event->cause;          Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
99          memset(&e.Format, 0, sizeof(e.Format)); // init format speific stuff with zero          e.Init(); // clear IDs
100          if (controller == CTRL_TABLE_IDX_AFTERTOUCH) {          if (controller == CTRL_TABLE_IDX_AFTERTOUCH) {
101              e.Type = Event::type_channel_pressure;              e.Type = Event::type_channel_pressure;
102              e.Param.ChannelPressure.Value = value & 127;              e.Param.ChannelPressure.Value = value & 127;
# Line 93  namespace LinuxSampler { Line 112  namespace LinuxSampler {
112              return errorResult();              return errorResult();
113          }          }
114    
115          int id = pEngineChannel->ScheduleEvent(&e, 0);          const event_id_t id = pEngineChannel->ScheduleEventMicroSec(&e, 0);
116    
117            // 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        }
122    
123          return successResult(id);      // ignore_event() function
     }      
124    
125      InstrumentScriptVMFunction_ignore_event::InstrumentScriptVMFunction_ignore_event(InstrumentScriptVM* parent)      InstrumentScriptVMFunction_ignore_event::InstrumentScriptVMFunction_ignore_event(InstrumentScriptVM* parent)
126          : m_vm(parent)          : m_vm(parent)
127      {      {
128      }      }
129    
130      VMFnResult* InstrumentScriptVMFunction_ignore_event::exec(VMFnArgs* args) {      bool InstrumentScriptVMFunction_ignore_event::acceptsArgType(int iArg, ExprType_t type) const {
131          int id = args->arg(0)->asInt()->evalInt();          return type == INT_EXPR || type == INT_ARR_EXPR;
132          if (id < 0) {      }
             wrnMsg("ignore_event(): argument may not be a negative event ID");  
             return successResult();  
         }  
133    
134        VMFnResult* InstrumentScriptVMFunction_ignore_event::exec(VMFnArgs* args) {
135          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
136              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);                  static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
137    
138          pEngineChannel->IgnoreEvent(id);          if (args->arg(0)->exprType() == INT_EXPR) {
139                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                    return successResult();
144                }
145                pEngineChannel->IgnoreEventByScriptID(id);
146            } 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                    const ScriptID id = ids->evalIntElement(i);    
150                    pEngineChannel->IgnoreEventByScriptID(id);
151                }
152            }
153    
154          return successResult();          return successResult();
155      }      }
156    
157        // ignore_controller() function
158    
159      InstrumentScriptVMFunction_ignore_controller::InstrumentScriptVMFunction_ignore_controller(InstrumentScriptVM* parent)      InstrumentScriptVMFunction_ignore_controller::InstrumentScriptVMFunction_ignore_controller(InstrumentScriptVM* parent)
160          : m_vm(parent)          : m_vm(parent)
161      {      {
162      }      }
163    
164      VMFnResult* InstrumentScriptVMFunction_ignore_controller::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_ignore_controller::exec(VMFnArgs* args) {
165          int id = (args->argsCount() >= 1) ? args->arg(0)->asInt()->evalInt() : m_vm->m_event->id;          const ScriptID id = (args->argsCount() >= 1) ? args->arg(0)->asInt()->evalInt() : m_vm->m_event->id;
166          if (id < 0) {          if (!id && args->argsCount() >= 1) {
167              wrnMsg("ignore_controller(): argument may not be a negative event ID");              wrnMsg("ignore_controller(): event ID argument may not be zero");
168              return successResult();              return successResult();
169          }          }
170    
171          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
172              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
173    
174          pEngineChannel->IgnoreEvent(id);          pEngineChannel->IgnoreEventByScriptID(id);
175    
176          return successResult();          return successResult();
177      }      }
178    
179        // note_off() function
180    
181      InstrumentScriptVMFunction_note_off::InstrumentScriptVMFunction_note_off(InstrumentScriptVM* parent)      InstrumentScriptVMFunction_note_off::InstrumentScriptVMFunction_note_off(InstrumentScriptVM* parent)
182          : m_vm(parent)          : m_vm(parent)
183      {      {
184      }      }
185    
186        bool InstrumentScriptVMFunction_note_off::acceptsArgType(int iArg, ExprType_t type) const {
187            return type == INT_EXPR || type == INT_ARR_EXPR;
188        }
189    
190      VMFnResult* InstrumentScriptVMFunction_note_off::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_note_off::exec(VMFnArgs* args) {
191          int id = args->arg(0)->asInt()->evalInt();          AbstractEngineChannel* pEngineChannel =
192                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
193    
194          int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;          int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;
195            if (velocity < 0 || velocity > 127) {
196                errMsg("note_off(): argument 2 is an invalid velocity value");
197                return errorResult();
198            }
199    
200          if (id < 0) {          if (args->arg(0)->exprType() == INT_EXPR) {
201              wrnMsg("note_off(): argument 1 may not be a negative event ID");              const ScriptID id = args->arg(0)->asInt()->evalInt();  
202              return successResult();              if (!id) {
203                    wrnMsg("note_off(): note ID for argument 1 may not be zero");
204                    return successResult();
205                }
206                if (!id.isNoteID()) {
207                    wrnMsg("note_off(): argument 1 is not a note ID");
208                    return successResult();
209                }
210    
211                NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
212                if (!pNote) return successResult();
213    
214                Event e = pNote->cause;
215                e.Init(); // clear IDs
216                e.CopyTimeFrom(m_vm->m_event->cause); // set fragment time for "now"
217                e.Type = Event::type_note_off;
218                e.Param.Note.Velocity = velocity;
219    
220                pEngineChannel->ScheduleEventMicroSec(&e, 0);
221            } 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                    const ScriptID id = ids->evalIntElement(i);
225                    if (!id || !id.isNoteID()) continue;
226    
227                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
228                    if (!pNote) continue;
229    
230                    Event e = pNote->cause;
231                    e.Init(); // clear IDs
232                    e.CopyTimeFrom(m_vm->m_event->cause); // set fragment time for "now"
233                    e.Type = Event::type_note_off;
234                    e.Param.Note.Velocity = velocity;
235    
236                    pEngineChannel->ScheduleEventMicroSec(&e, 0);
237                }
238          }          }
239    
240          if (velocity < 0 || velocity > 127) {          return successResult();
241              errMsg("note_off(): argument 2 is an invalid velocity value");      }
242    
243        // set_event_mark() function
244    
245        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            const ScriptID id = args->arg(0)->asInt()->evalInt();
252            const int groupID = args->arg(1)->asInt()->evalInt();
253    
254            if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
255                errMsg("set_event_mark(): argument 2 is an invalid group id");
256              return errorResult();              return errorResult();
257          }          }
258    
259          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
260              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
261    
262          RTList<Event>::Iterator itEvent = pEngineChannel->pEngine->EventByID(id);          // check if the event/note still exists
263          if (!itEvent) return successResult();          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    
276          Event e = *itEvent;          pEngineChannel->pScript->eventGroups[groupID].insert(id);
         e.Type = Event::type_note_off;  
         e.Param.Note.Velocity = velocity;  
         memset(&e.Format, 0, sizeof(e.Format)); // init format speific stuff with zero  
277    
278          int releaseEventID = pEngineChannel->ScheduleEvent(&e, 0);          return successResult();
279        }
280    
281        // delete_event_mark() function
282    
283        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            const ScriptID id = args->arg(0)->asInt()->evalInt();
290            const int groupID = args->arg(1)->asInt()->evalInt();
291    
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            pEngineChannel->pScript->eventGroups[groupID].erase(id);
301    
302          return successResult();          return successResult();
303      }      }
304    
305        // by_marks() function
306    
307        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        // 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        #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  } // namespace LinuxSampler  } // namespace LinuxSampler

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

  ViewVC Help
Powered by ViewVC