/[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 2879 - (hide annotations) (download)
Tue Apr 19 14:07:53 2016 UTC (7 years, 11 months ago) by schoenebeck
File size: 12856 byte(s)
* All engines: Active voices are now internally grouped to "Note" objects,
  instead of being directly assigned to a keyboard key. This allows more
  fine graded processing of voices, which is i.e. required for certain
  instrument script features.
* Built-in script function "play_note()": Added support for passing
  special value -1 for "duration-us" argument, which will cause the
  triggered note to be released once the original note was released.
* Bumped version (2.0.0.svn3).

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    
16     InstrumentScriptVMFunction_play_note::InstrumentScriptVMFunction_play_note(InstrumentScriptVM* parent)
17     : m_vm(parent)
18     {
19     }
20    
21     VMFnResult* InstrumentScriptVMFunction_play_note::exec(VMFnArgs* args) {
22     int note = args->arg(0)->asInt()->evalInt();
23     int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;
24     int sampleoffset = (args->argsCount() >= 3) ? args->arg(2)->asInt()->evalInt() : 0;
25 schoenebeck 2879 int duration = (args->argsCount() >= 4) ? args->arg(3)->asInt()->evalInt() : 0; //TODO: -1 might be a better default value instead of 0
26 schoenebeck 2596
27     if (note < 0 || note > 127) {
28     errMsg("play_note(): argument 1 is an invalid note number");
29 schoenebeck 2879 return errorResult(0);
30 schoenebeck 2596 }
31    
32     if (velocity < 0 || velocity > 127) {
33     errMsg("play_note(): argument 2 is an invalid velocity value");
34 schoenebeck 2879 return errorResult(0);
35 schoenebeck 2596 }
36    
37     if (sampleoffset < 0) {
38     errMsg("play_note(): argument 3 may not be a negative sample offset");
39 schoenebeck 2879 return errorResult(0);
40 schoenebeck 2596 } else if (sampleoffset != 0) {
41     wrnMsg("play_note(): argument 3 does not support a sample offset other than 0 yet");
42     }
43    
44     if (duration < -1) {
45     errMsg("play_note(): argument 4 must be a duration value of at least -1 or higher");
46 schoenebeck 2879 return errorResult(0);
47 schoenebeck 2596 }
48    
49     AbstractEngineChannel* pEngineChannel =
50     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
51    
52 schoenebeck 2879 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
53     e.Init(); // clear IDs
54 schoenebeck 2596 e.Type = Event::type_note_on;
55     e.Param.Note.Key = note;
56     e.Param.Note.Velocity = velocity;
57 schoenebeck 2879 // 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 schoenebeck 2596
66 schoenebeck 2879 const note_id_t id = pEngineChannel->ScheduleNoteMicroSec(&e, 0);
67 schoenebeck 2596
68 schoenebeck 2879 // 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 schoenebeck 2871 e.Type = Event::type_note_off;
72     e.Param.Note.Velocity = 127;
73     pEngineChannel->ScheduleEventMicroSec(&e, duration);
74     }
75    
76 schoenebeck 2879 // 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 schoenebeck 2598 }
81    
82 schoenebeck 2600 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 schoenebeck 2879 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
95     e.Init(); // clear IDs
96 schoenebeck 2600 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 schoenebeck 2879 const event_id_t id = pEngineChannel->ScheduleEventMicroSec(&e, 0);
112 schoenebeck 2600
113 schoenebeck 2879 // 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 schoenebeck 2600 }
118    
119 schoenebeck 2598 InstrumentScriptVMFunction_ignore_event::InstrumentScriptVMFunction_ignore_event(InstrumentScriptVM* parent)
120     : m_vm(parent)
121     {
122     }
123    
124 schoenebeck 2630 bool InstrumentScriptVMFunction_ignore_event::acceptsArgType(int iArg, ExprType_t type) const {
125     return type == INT_EXPR || type == INT_ARR_EXPR;
126     }
127    
128 schoenebeck 2598 VMFnResult* InstrumentScriptVMFunction_ignore_event::exec(VMFnArgs* args) {
129     AbstractEngineChannel* pEngineChannel =
130 schoenebeck 2630 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
131 schoenebeck 2598
132 schoenebeck 2630 if (args->arg(0)->exprType() == INT_EXPR) {
133 schoenebeck 2879 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 schoenebeck 2630 return successResult();
138     }
139 schoenebeck 2879 pEngineChannel->IgnoreEventByScriptID(id);
140 schoenebeck 2630 } 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 schoenebeck 2879 const ScriptID id = ids->evalIntElement(i);
144     pEngineChannel->IgnoreEventByScriptID(id);
145 schoenebeck 2630 }
146     }
147 schoenebeck 2598
148 schoenebeck 2596 return successResult();
149     }
150    
151 schoenebeck 2598 InstrumentScriptVMFunction_ignore_controller::InstrumentScriptVMFunction_ignore_controller(InstrumentScriptVM* parent)
152     : m_vm(parent)
153     {
154     }
155    
156     VMFnResult* InstrumentScriptVMFunction_ignore_controller::exec(VMFnArgs* args) {
157 schoenebeck 2879 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 schoenebeck 2598 return successResult();
161     }
162    
163     AbstractEngineChannel* pEngineChannel =
164     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
165    
166 schoenebeck 2879 pEngineChannel->IgnoreEventByScriptID(id);
167 schoenebeck 2598
168     return successResult();
169     }
170    
171 schoenebeck 2629 InstrumentScriptVMFunction_note_off::InstrumentScriptVMFunction_note_off(InstrumentScriptVM* parent)
172     : m_vm(parent)
173     {
174     }
175    
176 schoenebeck 2630 bool InstrumentScriptVMFunction_note_off::acceptsArgType(int iArg, ExprType_t type) const {
177     return type == INT_EXPR || type == INT_ARR_EXPR;
178     }
179    
180 schoenebeck 2629 VMFnResult* InstrumentScriptVMFunction_note_off::exec(VMFnArgs* args) {
181 schoenebeck 2630 AbstractEngineChannel* pEngineChannel =
182     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
183    
184 schoenebeck 2629 int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;
185 schoenebeck 2630 if (velocity < 0 || velocity > 127) {
186     errMsg("note_off(): argument 2 is an invalid velocity value");
187     return errorResult();
188     }
189 schoenebeck 2629
190 schoenebeck 2630 if (args->arg(0)->exprType() == INT_EXPR) {
191 schoenebeck 2879 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 schoenebeck 2630 return successResult();
195     }
196 schoenebeck 2879 if (!id.isNoteID()) {
197     wrnMsg("note_off(): argument 1 is not a note ID");
198     return successResult();
199     }
200 schoenebeck 2630
201 schoenebeck 2879 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
202     if (!pNote) return successResult();
203 schoenebeck 2630
204 schoenebeck 2879 Event e = pNote->cause;
205     e.Init(); // clear IDs
206     e.CopyTimeFrom(m_vm->m_event->cause); // set fragment time for "now"
207 schoenebeck 2630 e.Type = Event::type_note_off;
208     e.Param.Note.Velocity = velocity;
209    
210 schoenebeck 2879 pEngineChannel->ScheduleEventMicroSec(&e, 0);
211 schoenebeck 2630 } 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 schoenebeck 2879 const ScriptID id = ids->evalIntElement(i);
215     if (!id || !id.isNoteID()) continue;
216 schoenebeck 2630
217 schoenebeck 2879 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
218     if (!pNote) continue;
219 schoenebeck 2630
220 schoenebeck 2879 Event e = pNote->cause;
221     e.Init(); // clear IDs
222     e.CopyTimeFrom(m_vm->m_event->cause); // set fragment time for "now"
223 schoenebeck 2630 e.Type = Event::type_note_off;
224     e.Param.Note.Velocity = velocity;
225    
226 schoenebeck 2879 pEngineChannel->ScheduleEventMicroSec(&e, 0);
227 schoenebeck 2630 }
228 schoenebeck 2629 }
229    
230 schoenebeck 2630 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 schoenebeck 2879 const ScriptID id = args->arg(0)->asInt()->evalInt();
240     const int groupID = args->arg(1)->asInt()->evalInt();
241 schoenebeck 2630
242     if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
243     errMsg("set_event_mark(): argument 2 is an invalid group id");
244 schoenebeck 2629 return errorResult();
245     }
246    
247     AbstractEngineChannel* pEngineChannel =
248     static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
249    
250 schoenebeck 2879 // 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 schoenebeck 2629
264 schoenebeck 2879 pEngineChannel->pScript->eventGroups[groupID].insert(id);
265 schoenebeck 2629
266 schoenebeck 2630 return successResult();
267     }
268 schoenebeck 2629
269 schoenebeck 2630 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 schoenebeck 2879 const ScriptID id = args->arg(0)->asInt()->evalInt();
276     const int groupID = args->arg(1)->asInt()->evalInt();
277 schoenebeck 2630
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 schoenebeck 2879 pEngineChannel->pScript->eventGroups[groupID].erase(id);
287 schoenebeck 2630
288 schoenebeck 2629 return successResult();
289     }
290    
291 schoenebeck 2630 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 schoenebeck 2596 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC