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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2879 - (show 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 /*
2 * Copyright (c) 2014-2016 Christian Schoenebeck
3 *
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 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) {
28 errMsg("play_note(): argument 1 is an invalid note number");
29 return errorResult(0);
30 }
31
32 if (velocity < 0 || velocity > 127) {
33 errMsg("play_note(): argument 2 is an invalid velocity value");
34 return errorResult(0);
35 }
36
37 if (sampleoffset < 0) {
38 errMsg("play_note(): argument 3 may not be a negative sample offset");
39 return errorResult(0);
40 } 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 return errorResult(0);
47 }
48
49 AbstractEngineChannel* pEngineChannel =
50 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
51
52 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;
55 e.Param.Note.Key = note;
56 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 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();
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

  ViewVC Help
Powered by ViewVC