/[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 2596 by schoenebeck, Thu Jun 5 19:39:12 2014 UTC revision 2879 by schoenebeck, Tue Apr 19 14:07:53 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 22  namespace LinuxSampler { Line 22  namespace LinuxSampler {
22          int note = args->arg(0)->asInt()->evalInt();          int note = args->arg(0)->asInt()->evalInt();
23          int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;          int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;
24          int sampleoffset = (args->argsCount() >= 3) ? args->arg(2)->asInt()->evalInt() : 0;          int sampleoffset = (args->argsCount() >= 3) ? args->arg(2)->asInt()->evalInt() : 0;
25          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
26    
27          if (note < 0 || note > 127) {          if (note < 0 || note > 127) {
28              errMsg("play_note(): argument 1 is an invalid note number");              errMsg("play_note(): argument 1 is an invalid note number");
29              return errorResult();              return errorResult(0);
30          }          }
31    
32          if (velocity < 0 || velocity > 127) {          if (velocity < 0 || velocity > 127) {
33              errMsg("play_note(): argument 2 is an invalid velocity value");              errMsg("play_note(): argument 2 is an invalid velocity value");
34              return errorResult();              return errorResult(0);
35          }          }
36    
37          if (sampleoffset < 0) {          if (sampleoffset < 0) {
38              errMsg("play_note(): argument 3 may not be a negative sample offset");              errMsg("play_note(): argument 3 may not be a negative sample offset");
39              return errorResult();              return errorResult(0);
40          } else if (sampleoffset != 0) {          } else if (sampleoffset != 0) {
41              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");
42          }          }
43    
44          if (duration < -1) {          if (duration < -1) {
45              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");
46              return errorResult();              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");  
47          }          }
48    
49          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
50              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
51    
52          Event e = m_vm->m_event->cause;          Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
53            e.Init(); // clear IDs
54          e.Type = Event::type_note_on;          e.Type = Event::type_note_on;
55          e.Param.Note.Key = note;          e.Param.Note.Key = note;
56          e.Param.Note.Velocity = velocity;          e.Param.Note.Velocity = velocity;
57            // make this new note dependent to the life time of the original note
58            if (duration == -1) {
59                if (m_vm->currentVMEventHandler()->eventHandlerType() != VM_EVENT_HANDLER_NOTE) {
60                    errMsg("play_note(): -1 for argument 4 may only be used for note event handlers");
61                    return errorResult(0);
62                }
63                e.Param.Note.ParentNoteID = m_vm->m_event->cause.Param.Note.ID;
64            }
65    
66            const note_id_t id = pEngineChannel->ScheduleNoteMicroSec(&e, 0);
67    
68            // if a duration is supplied (and note-on event was scheduled
69            // successfully above), then schedule a subsequent note-off event
70            if (id && duration > 0) {
71                e.Type = Event::type_note_off;
72                e.Param.Note.Velocity = 127;
73                pEngineChannel->ScheduleEventMicroSec(&e, duration);
74            }
75    
76            // even if id is null, don't return an errorResult() here, because that
77            // would abort the script, and under heavy load it may be considerable
78            // that ScheduleNoteMicroSec() fails above, so simply ignore that
79            return successResult( ScriptID::fromNoteID(id) );
80        }
81    
82        InstrumentScriptVMFunction_set_controller::InstrumentScriptVMFunction_set_controller(InstrumentScriptVM* parent)
83            : m_vm(parent)
84        {
85        }
86    
87        VMFnResult* InstrumentScriptVMFunction_set_controller::exec(VMFnArgs* args) {
88            int controller = args->arg(0)->asInt()->evalInt();
89            int value      = args->arg(1)->asInt()->evalInt();
90    
91            AbstractEngineChannel* pEngineChannel =
92                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
93    
94            Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
95            e.Init(); // clear IDs
96            if (controller == CTRL_TABLE_IDX_AFTERTOUCH) {
97                e.Type = Event::type_channel_pressure;
98                e.Param.ChannelPressure.Value = value & 127;
99            } else if (controller == CTRL_TABLE_IDX_PITCHBEND) {
100                e.Type = Event::type_pitchbend;
101                e.Param.Pitch.Pitch = value;
102            } else if (controller >= 0 && controller <= 127) {
103                e.Type = Event::type_control_change;
104                e.Param.CC.Controller = controller;
105                e.Param.CC.Value = value;
106            } else {
107                errMsg("set_controller(): argument 1 is an invalid controller");
108                return errorResult();
109            }
110    
111            const event_id_t id = pEngineChannel->ScheduleEventMicroSec(&e, 0);
112    
113            // even if id is null, don't return an errorResult() here, because that
114            // would abort the script, and under heavy load it may be considerable
115            // that ScheduleEventMicroSec() fails above, so simply ignore that
116            return successResult( ScriptID::fromEventID(id) );
117        }    
118    
119        InstrumentScriptVMFunction_ignore_event::InstrumentScriptVMFunction_ignore_event(InstrumentScriptVM* parent)
120            : m_vm(parent)
121        {
122        }
123    
124        bool InstrumentScriptVMFunction_ignore_event::acceptsArgType(int iArg, ExprType_t type) const {
125            return type == INT_EXPR || type == INT_ARR_EXPR;
126        }
127    
128        VMFnResult* InstrumentScriptVMFunction_ignore_event::exec(VMFnArgs* args) {
129            AbstractEngineChannel* pEngineChannel =
130                    static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
131    
132            if (args->arg(0)->exprType() == INT_EXPR) {
133                const ScriptID id = args->arg(0)->asInt()->evalInt();
134                if (!id) {
135                    wrnMsg("ignore_event(): event ID argument may not be zero");
136                    // not errorResult(), because that would abort the script, not intentional in this case
137                    return successResult();
138                }
139                pEngineChannel->IgnoreEventByScriptID(id);
140            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
141                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
142                for (int i = 0; i < ids->arraySize(); ++i) {
143                    const ScriptID id = ids->evalIntElement(i);    
144                    pEngineChannel->IgnoreEventByScriptID(id);
145                }
146            }
147    
148            return successResult();
149        }
150    
151        InstrumentScriptVMFunction_ignore_controller::InstrumentScriptVMFunction_ignore_controller(InstrumentScriptVM* parent)
152            : m_vm(parent)
153        {
154        }
155    
156        VMFnResult* InstrumentScriptVMFunction_ignore_controller::exec(VMFnArgs* args) {
157            const ScriptID id = (args->argsCount() >= 1) ? args->arg(0)->asInt()->evalInt() : m_vm->m_event->id;
158            if (!id && args->argsCount() >= 1) {
159                wrnMsg("ignore_controller(): event ID argument may not be zero");
160                return successResult();
161            }
162    
163            AbstractEngineChannel* pEngineChannel =
164                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
165    
166            pEngineChannel->IgnoreEventByScriptID(id);
167    
168            return successResult();
169        }
170    
171        InstrumentScriptVMFunction_note_off::InstrumentScriptVMFunction_note_off(InstrumentScriptVM* parent)
172            : m_vm(parent)
173        {
174        }
175    
176        bool InstrumentScriptVMFunction_note_off::acceptsArgType(int iArg, ExprType_t type) const {
177            return type == INT_EXPR || type == INT_ARR_EXPR;
178        }
179    
180        VMFnResult* InstrumentScriptVMFunction_note_off::exec(VMFnArgs* args) {
181            AbstractEngineChannel* pEngineChannel =
182                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
183    
184            int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;
185            if (velocity < 0 || velocity > 127) {
186                errMsg("note_off(): argument 2 is an invalid velocity value");
187                return errorResult();
188            }
189    
190            if (args->arg(0)->exprType() == INT_EXPR) {
191                const ScriptID id = args->arg(0)->asInt()->evalInt();  
192                if (!id) {
193                    wrnMsg("note_off(): note ID for argument 1 may not be zero");
194                    return successResult();
195                }
196                if (!id.isNoteID()) {
197                    wrnMsg("note_off(): argument 1 is not a note ID");
198                    return successResult();
199                }
200    
201                NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
202                if (!pNote) return successResult();
203    
204                Event e = pNote->cause;
205                e.Init(); // clear IDs
206                e.CopyTimeFrom(m_vm->m_event->cause); // set fragment time for "now"
207                e.Type = Event::type_note_off;
208                e.Param.Note.Velocity = velocity;
209    
210                pEngineChannel->ScheduleEventMicroSec(&e, 0);
211            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
212                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
213                for (int i = 0; i < ids->arraySize(); ++i) {
214                    const ScriptID id = ids->evalIntElement(i);
215                    if (!id || !id.isNoteID()) continue;
216    
217                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
218                    if (!pNote) continue;
219    
220                    Event e = pNote->cause;
221                    e.Init(); // clear IDs
222                    e.CopyTimeFrom(m_vm->m_event->cause); // set fragment time for "now"
223                    e.Type = Event::type_note_off;
224                    e.Param.Note.Velocity = velocity;
225    
226                    pEngineChannel->ScheduleEventMicroSec(&e, 0);
227                }
228            }
229    
230            return successResult();
231        }
232    
233        InstrumentScriptVMFunction_set_event_mark::InstrumentScriptVMFunction_set_event_mark(InstrumentScriptVM* parent)
234            : m_vm(parent)
235        {
236        }
237    
238        VMFnResult* InstrumentScriptVMFunction_set_event_mark::exec(VMFnArgs* args) {
239            const ScriptID id = args->arg(0)->asInt()->evalInt();
240            const int groupID = args->arg(1)->asInt()->evalInt();
241    
242          pEngineChannel->ScheduleEvent(&e, duration);          if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
243                errMsg("set_event_mark(): argument 2 is an invalid group id");
244                return errorResult();
245            }
246    
247            AbstractEngineChannel* pEngineChannel =
248                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
249    
250            // check if the event/note still exists
251            switch (id.type()) {
252                case ScriptID::EVENT: {
253                    RTList<Event>::Iterator itEvent = pEngineChannel->pEngine->EventByID( id.eventID() );
254                    if (!itEvent) return successResult();
255                    break;
256                }
257                case ScriptID::NOTE: {
258                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
259                    if (!pNote) return successResult();
260                    break;
261                }
262            }
263    
264            pEngineChannel->pScript->eventGroups[groupID].insert(id);
265    
266          return successResult();          return successResult();
267      }      }
268    
269        InstrumentScriptVMFunction_delete_event_mark::InstrumentScriptVMFunction_delete_event_mark(InstrumentScriptVM* parent)
270            : m_vm(parent)
271        {
272        }
273    
274        VMFnResult* InstrumentScriptVMFunction_delete_event_mark::exec(VMFnArgs* args) {
275            const ScriptID id = args->arg(0)->asInt()->evalInt();
276            const int groupID = args->arg(1)->asInt()->evalInt();
277    
278            if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
279                errMsg("delete_event_mark(): argument 2 is an invalid group id");
280                return errorResult();
281            }
282    
283            AbstractEngineChannel* pEngineChannel =
284                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
285    
286            pEngineChannel->pScript->eventGroups[groupID].erase(id);
287    
288            return successResult();
289        }
290    
291        InstrumentScriptVMFunction_by_marks::InstrumentScriptVMFunction_by_marks(InstrumentScriptVM* parent)
292            : m_vm(parent)
293        {
294        }
295    
296        int InstrumentScriptVMFunction_by_marks::Result::arraySize() const {
297            return eventGroup->size();
298        }
299    
300        int InstrumentScriptVMFunction_by_marks::Result::evalIntElement(uint i) {
301            return (*eventGroup)[i];
302        }
303    
304        VMFnResult* InstrumentScriptVMFunction_by_marks::errorResult() {
305            m_result.eventGroup = NULL;
306            m_result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
307            return &m_result;
308        }
309    
310        VMFnResult* InstrumentScriptVMFunction_by_marks::successResult(EventGroup* eventGroup) {
311            m_result.eventGroup = eventGroup;
312            m_result.flags = STMT_SUCCESS;
313            return &m_result;
314        }
315    
316        VMFnResult* InstrumentScriptVMFunction_by_marks::exec(VMFnArgs* args) {
317            int groupID = args->arg(0)->asInt()->evalInt();
318    
319            if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
320                errMsg("by_marks(): argument is an invalid group id");
321                return errorResult();
322            }
323    
324            AbstractEngineChannel* pEngineChannel =
325                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
326    
327            return successResult( &pEngineChannel->pScript->eventGroups[groupID] );
328        }
329    
330  } // namespace LinuxSampler  } // namespace LinuxSampler

Legend:
Removed from v.2596  
changed lines
  Added in v.2879

  ViewVC Help
Powered by ViewVC