/[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 2953 - (show annotations) (download)
Sat Jul 16 11:24:39 2016 UTC (2 years, 11 months ago) by schoenebeck
File size: 43053 byte(s)
* NKSP: Implemented built-in script function "change_attack()".
* NKSP: Implemented built-in script function "change_decay()".
* NKSP: Implemented built-in script function "change_release()".
* Bumped version (2.0.0.svn19).

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 // play_note() function
17
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 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) {
30 errMsg("play_note(): argument 1 is an invalid note number");
31 return errorResult(0);
32 }
33
34 if (velocity < 0 || velocity > 127) {
35 errMsg("play_note(): argument 2 is an invalid velocity value");
36 return errorResult(0);
37 }
38
39 if (sampleoffset < 0) {
40 errMsg("play_note(): argument 3 may not be a negative sample offset");
41 return errorResult(0);
42 } 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 return errorResult(0);
49 }
50
51 AbstractEngineChannel* pEngineChannel =
52 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
53
54 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
55 e.Init(); // clear IDs
56 e.Type = Event::type_play_note;
57 e.Param.Note.Key = note;
58 e.Param.Note.Velocity = velocity;
59 // 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 // if a duration is supplied (and play-note event was scheduled
71 // successfully above), then schedule a subsequent stop-note event
72 if (id && duration > 0) {
73 e.Type = Event::type_stop_note;
74 e.Param.Note.ID = id;
75 e.Param.Note.Velocity = 127;
76 pEngineChannel->ScheduleEventMicroSec(&e, duration);
77 }
78
79 // even if id is null, don't return an errorResult() here, because that
80 // would abort the script, and under heavy load it may be considerable
81 // that ScheduleNoteMicroSec() fails above, so simply ignore that
82 return successResult( ScriptID::fromNoteID(id) );
83 }
84
85 // set_controller() function
86
87 InstrumentScriptVMFunction_set_controller::InstrumentScriptVMFunction_set_controller(InstrumentScriptVM* parent)
88 : m_vm(parent)
89 {
90 }
91
92 VMFnResult* InstrumentScriptVMFunction_set_controller::exec(VMFnArgs* args) {
93 int controller = args->arg(0)->asInt()->evalInt();
94 int value = args->arg(1)->asInt()->evalInt();
95
96 AbstractEngineChannel* pEngineChannel =
97 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
98
99 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
100 e.Init(); // clear IDs
101 if (controller == CTRL_TABLE_IDX_AFTERTOUCH) {
102 e.Type = Event::type_channel_pressure;
103 e.Param.ChannelPressure.Value = value & 127;
104 } else if (controller == CTRL_TABLE_IDX_PITCHBEND) {
105 e.Type = Event::type_pitchbend;
106 e.Param.Pitch.Pitch = value;
107 } else if (controller >= 0 && controller <= 127) {
108 e.Type = Event::type_control_change;
109 e.Param.CC.Controller = controller;
110 e.Param.CC.Value = value;
111 } else {
112 errMsg("set_controller(): argument 1 is an invalid controller");
113 return errorResult();
114 }
115
116 const event_id_t id = pEngineChannel->ScheduleEventMicroSec(&e, 0);
117
118 // even if id is null, don't return an errorResult() here, because that
119 // would abort the script, and under heavy load it may be considerable
120 // that ScheduleEventMicroSec() fails above, so simply ignore that
121 return successResult( ScriptID::fromEventID(id) );
122 }
123
124 // ignore_event() function
125
126 InstrumentScriptVMFunction_ignore_event::InstrumentScriptVMFunction_ignore_event(InstrumentScriptVM* parent)
127 : m_vm(parent)
128 {
129 }
130
131 bool InstrumentScriptVMFunction_ignore_event::acceptsArgType(int iArg, ExprType_t type) const {
132 return type == INT_EXPR || type == INT_ARR_EXPR;
133 }
134
135 VMFnResult* InstrumentScriptVMFunction_ignore_event::exec(VMFnArgs* args) {
136 AbstractEngineChannel* pEngineChannel =
137 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
138
139 if (args->arg(0)->exprType() == INT_EXPR) {
140 const ScriptID id = args->arg(0)->asInt()->evalInt();
141 if (!id) {
142 wrnMsg("ignore_event(): event ID argument may not be zero");
143 // not errorResult(), because that would abort the script, not intentional in this case
144 return successResult();
145 }
146 pEngineChannel->IgnoreEventByScriptID(id);
147 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
148 VMIntArrayExpr* ids = args->arg(0)->asIntArray();
149 for (int i = 0; i < ids->arraySize(); ++i) {
150 const ScriptID id = ids->evalIntElement(i);
151 pEngineChannel->IgnoreEventByScriptID(id);
152 }
153 }
154
155 return successResult();
156 }
157
158 // ignore_controller() function
159
160 InstrumentScriptVMFunction_ignore_controller::InstrumentScriptVMFunction_ignore_controller(InstrumentScriptVM* parent)
161 : m_vm(parent)
162 {
163 }
164
165 VMFnResult* InstrumentScriptVMFunction_ignore_controller::exec(VMFnArgs* args) {
166 const ScriptID id = (args->argsCount() >= 1) ? args->arg(0)->asInt()->evalInt() : m_vm->m_event->id;
167 if (!id && args->argsCount() >= 1) {
168 wrnMsg("ignore_controller(): event ID argument may not be zero");
169 return successResult();
170 }
171
172 AbstractEngineChannel* pEngineChannel =
173 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
174
175 pEngineChannel->IgnoreEventByScriptID(id);
176
177 return successResult();
178 }
179
180 // note_off() function
181
182 InstrumentScriptVMFunction_note_off::InstrumentScriptVMFunction_note_off(InstrumentScriptVM* parent)
183 : m_vm(parent)
184 {
185 }
186
187 bool InstrumentScriptVMFunction_note_off::acceptsArgType(int iArg, ExprType_t type) const {
188 return type == INT_EXPR || type == INT_ARR_EXPR;
189 }
190
191 VMFnResult* InstrumentScriptVMFunction_note_off::exec(VMFnArgs* args) {
192 AbstractEngineChannel* pEngineChannel =
193 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
194
195 int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;
196 if (velocity < 0 || velocity > 127) {
197 errMsg("note_off(): argument 2 is an invalid velocity value");
198 return errorResult();
199 }
200
201 if (args->arg(0)->exprType() == INT_EXPR) {
202 const ScriptID id = args->arg(0)->asInt()->evalInt();
203 if (!id) {
204 wrnMsg("note_off(): note ID for argument 1 may not be zero");
205 return successResult();
206 }
207 if (!id.isNoteID()) {
208 wrnMsg("note_off(): argument 1 is not a note ID");
209 return successResult();
210 }
211
212 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
213 if (!pNote) return successResult();
214
215 Event e = pNote->cause;
216 e.Init(); // clear IDs
217 e.CopyTimeFrom(m_vm->m_event->cause); // set fragment time for "now"
218 e.Type = Event::type_stop_note;
219 e.Param.Note.ID = id.noteID();
220 e.Param.Note.Key = pNote->hostKey;
221 e.Param.Note.Velocity = velocity;
222
223 pEngineChannel->ScheduleEventMicroSec(&e, 0);
224 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
225 VMIntArrayExpr* ids = args->arg(0)->asIntArray();
226 for (int i = 0; i < ids->arraySize(); ++i) {
227 const ScriptID id = ids->evalIntElement(i);
228 if (!id || !id.isNoteID()) continue;
229
230 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
231 if (!pNote) continue;
232
233 Event e = pNote->cause;
234 e.Init(); // clear IDs
235 e.CopyTimeFrom(m_vm->m_event->cause); // set fragment time for "now"
236 e.Type = Event::type_stop_note;
237 e.Param.Note.ID = id.noteID();
238 e.Param.Note.Key = pNote->hostKey;
239 e.Param.Note.Velocity = velocity;
240
241 pEngineChannel->ScheduleEventMicroSec(&e, 0);
242 }
243 }
244
245 return successResult();
246 }
247
248 // set_event_mark() function
249
250 InstrumentScriptVMFunction_set_event_mark::InstrumentScriptVMFunction_set_event_mark(InstrumentScriptVM* parent)
251 : m_vm(parent)
252 {
253 }
254
255 VMFnResult* InstrumentScriptVMFunction_set_event_mark::exec(VMFnArgs* args) {
256 const ScriptID id = args->arg(0)->asInt()->evalInt();
257 const int groupID = args->arg(1)->asInt()->evalInt();
258
259 if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
260 errMsg("set_event_mark(): argument 2 is an invalid group id");
261 return errorResult();
262 }
263
264 AbstractEngineChannel* pEngineChannel =
265 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
266
267 // check if the event/note still exists
268 switch (id.type()) {
269 case ScriptID::EVENT: {
270 RTList<Event>::Iterator itEvent = pEngineChannel->pEngine->EventByID( id.eventID() );
271 if (!itEvent) return successResult();
272 break;
273 }
274 case ScriptID::NOTE: {
275 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
276 if (!pNote) return successResult();
277 break;
278 }
279 }
280
281 pEngineChannel->pScript->eventGroups[groupID].insert(id);
282
283 return successResult();
284 }
285
286 // delete_event_mark() function
287
288 InstrumentScriptVMFunction_delete_event_mark::InstrumentScriptVMFunction_delete_event_mark(InstrumentScriptVM* parent)
289 : m_vm(parent)
290 {
291 }
292
293 VMFnResult* InstrumentScriptVMFunction_delete_event_mark::exec(VMFnArgs* args) {
294 const ScriptID id = args->arg(0)->asInt()->evalInt();
295 const int groupID = args->arg(1)->asInt()->evalInt();
296
297 if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
298 errMsg("delete_event_mark(): argument 2 is an invalid group id");
299 return errorResult();
300 }
301
302 AbstractEngineChannel* pEngineChannel =
303 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
304
305 pEngineChannel->pScript->eventGroups[groupID].erase(id);
306
307 return successResult();
308 }
309
310 // by_marks() function
311
312 InstrumentScriptVMFunction_by_marks::InstrumentScriptVMFunction_by_marks(InstrumentScriptVM* parent)
313 : m_vm(parent)
314 {
315 }
316
317 int InstrumentScriptVMFunction_by_marks::Result::arraySize() const {
318 return eventGroup->size();
319 }
320
321 int InstrumentScriptVMFunction_by_marks::Result::evalIntElement(uint i) {
322 return (*eventGroup)[i];
323 }
324
325 VMFnResult* InstrumentScriptVMFunction_by_marks::errorResult() {
326 m_result.eventGroup = NULL;
327 m_result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
328 return &m_result;
329 }
330
331 VMFnResult* InstrumentScriptVMFunction_by_marks::successResult(EventGroup* eventGroup) {
332 m_result.eventGroup = eventGroup;
333 m_result.flags = STMT_SUCCESS;
334 return &m_result;
335 }
336
337 VMFnResult* InstrumentScriptVMFunction_by_marks::exec(VMFnArgs* args) {
338 int groupID = args->arg(0)->asInt()->evalInt();
339
340 if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
341 errMsg("by_marks(): argument is an invalid group id");
342 return errorResult();
343 }
344
345 AbstractEngineChannel* pEngineChannel =
346 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
347
348 return successResult( &pEngineChannel->pScript->eventGroups[groupID] );
349 }
350
351 // change_vol() function
352
353 InstrumentScriptVMFunction_change_vol::InstrumentScriptVMFunction_change_vol(InstrumentScriptVM* parent)
354 : m_vm(parent)
355 {
356 }
357
358 bool InstrumentScriptVMFunction_change_vol::acceptsArgType(int iArg, ExprType_t type) const {
359 if (iArg == 0)
360 return type == INT_EXPR || type == INT_ARR_EXPR;
361 else
362 return INT_EXPR;
363 }
364
365 VMFnResult* InstrumentScriptVMFunction_change_vol::exec(VMFnArgs* args) {
366 int volume = args->arg(1)->asInt()->evalInt(); // volume change in milli dB
367 bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;
368
369 AbstractEngineChannel* pEngineChannel =
370 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
371
372 if (args->arg(0)->exprType() == INT_EXPR) {
373 const ScriptID id = args->arg(0)->asInt()->evalInt();
374 if (!id) {
375 wrnMsg("change_vol(): note ID for argument 1 may not be zero");
376 return successResult();
377 }
378 if (!id.isNoteID()) {
379 wrnMsg("change_vol(): argument 1 is not a note ID");
380 return successResult();
381 }
382
383 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
384 if (!pNote) return successResult();
385
386 const float fVolumeLin = RTMath::DecibelToLinRatio(float(volume) / 1000.f);
387 // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
388 /*if (relative)
389 pNote->Override.Volume *= fVolumeLin;
390 else
391 pNote->Override.Volume = fVolumeLin;*/
392
393 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
394 e.Init(); // clear IDs
395 e.Type = Event::type_note_synth_param;
396 e.Param.NoteSynthParam.NoteID = id.noteID();
397 e.Param.NoteSynthParam.Type = Event::synth_param_volume;
398 e.Param.NoteSynthParam.Delta = fVolumeLin;
399 e.Param.NoteSynthParam.Relative = relative;
400
401 pEngineChannel->ScheduleEventMicroSec(&e, 0);
402 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
403 VMIntArrayExpr* ids = args->arg(0)->asIntArray();
404 for (int i = 0; i < ids->arraySize(); ++i) {
405 const ScriptID id = ids->evalIntElement(i);
406 if (!id || !id.isNoteID()) continue;
407
408 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
409 if (!pNote) continue;
410
411 const float fVolumeLin = RTMath::DecibelToLinRatio(float(volume) / 1000.f);
412 // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
413 /*if (relative)
414 pNote->Override.Volume *= fVolumeLin;
415 else
416 pNote->Override.Volume = fVolumeLin;*/
417
418 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
419 e.Init(); // clear IDs
420 e.Type = Event::type_note_synth_param;
421 e.Param.NoteSynthParam.NoteID = id.noteID();
422 e.Param.NoteSynthParam.Type = Event::synth_param_volume;
423 e.Param.NoteSynthParam.Delta = fVolumeLin;
424 e.Param.NoteSynthParam.Relative = relative;
425
426 pEngineChannel->ScheduleEventMicroSec(&e, 0);
427 }
428 }
429
430 return successResult();
431 }
432
433 // change_tune() function
434
435 InstrumentScriptVMFunction_change_tune::InstrumentScriptVMFunction_change_tune(InstrumentScriptVM* parent)
436 : m_vm(parent)
437 {
438 }
439
440 bool InstrumentScriptVMFunction_change_tune::acceptsArgType(int iArg, ExprType_t type) const {
441 if (iArg == 0)
442 return type == INT_EXPR || type == INT_ARR_EXPR;
443 else
444 return INT_EXPR;
445 }
446
447 VMFnResult* InstrumentScriptVMFunction_change_tune::exec(VMFnArgs* args) {
448 int tune = args->arg(1)->asInt()->evalInt(); // tuning change in milli cents
449 bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;
450
451 AbstractEngineChannel* pEngineChannel =
452 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
453
454 if (args->arg(0)->exprType() == INT_EXPR) {
455 const ScriptID id = args->arg(0)->asInt()->evalInt();
456 if (!id) {
457 wrnMsg("change_tune(): note ID for argument 1 may not be zero");
458 return successResult();
459 }
460 if (!id.isNoteID()) {
461 wrnMsg("change_tune(): argument 1 is not a note ID");
462 return successResult();
463 }
464
465 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
466 if (!pNote) return successResult();
467
468 const float fFreqRatio = RTMath::CentsToFreqRatioUnlimited(float(tune) / 1000.f);
469 // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
470 /*if (relative)
471 pNote->Override.Pitch *= fFreqRatio;
472 else
473 pNote->Override.Pitch = fFreqRatio;*/
474
475 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
476 e.Init(); // clear IDs
477 e.Type = Event::type_note_synth_param;
478 e.Param.NoteSynthParam.NoteID = id.noteID();
479 e.Param.NoteSynthParam.Type = Event::synth_param_pitch;
480 e.Param.NoteSynthParam.Delta = fFreqRatio;
481 e.Param.NoteSynthParam.Relative = relative;
482
483 pEngineChannel->ScheduleEventMicroSec(&e, 0);
484 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
485 VMIntArrayExpr* ids = args->arg(0)->asIntArray();
486 for (int i = 0; i < ids->arraySize(); ++i) {
487 const ScriptID id = ids->evalIntElement(i);
488 if (!id || !id.isNoteID()) continue;
489
490 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
491 if (!pNote) continue;
492
493 const float fFreqRatio = RTMath::CentsToFreqRatioUnlimited(float(tune) / 1000.f);
494 // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
495 /*if (relative)
496 pNote->Override.Pitch *= fFreqRatio;
497 else
498 pNote->Override.Pitch = fFreqRatio;*/
499
500 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
501 e.Init(); // clear IDs
502 e.Type = Event::type_note_synth_param;
503 e.Param.NoteSynthParam.NoteID = id.noteID();
504 e.Param.NoteSynthParam.Type = Event::synth_param_pitch;
505 e.Param.NoteSynthParam.Delta = fFreqRatio;
506 e.Param.NoteSynthParam.Relative = relative;
507
508 pEngineChannel->ScheduleEventMicroSec(&e, 0);
509 }
510 }
511
512 return successResult();
513 }
514
515 // change_pan() function
516
517 InstrumentScriptVMFunction_change_pan::InstrumentScriptVMFunction_change_pan(InstrumentScriptVM* parent)
518 : m_vm(parent)
519 {
520 }
521
522 bool InstrumentScriptVMFunction_change_pan::acceptsArgType(int iArg, ExprType_t type) const {
523 if (iArg == 0)
524 return type == INT_EXPR || type == INT_ARR_EXPR;
525 else
526 return INT_EXPR;
527 }
528
529 VMFnResult* InstrumentScriptVMFunction_change_pan::exec(VMFnArgs* args) {
530 int pan = args->arg(1)->asInt()->evalInt();
531 bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;
532
533 if (pan > 1000) {
534 wrnMsg("change_pan(): argument 2 may not be larger than 1000");
535 pan = 1000;
536 } else if (pan < -1000) {
537 wrnMsg("change_pan(): argument 2 may not be smaller than -1000");
538 pan = -1000;
539 }
540
541 AbstractEngineChannel* pEngineChannel =
542 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
543
544 if (args->arg(0)->exprType() == INT_EXPR) {
545 const ScriptID id = args->arg(0)->asInt()->evalInt();
546 if (!id) {
547 wrnMsg("change_pan(): note ID for argument 1 may not be zero");
548 return successResult();
549 }
550 if (!id.isNoteID()) {
551 wrnMsg("change_pan(): argument 1 is not a note ID");
552 return successResult();
553 }
554
555 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
556 if (!pNote) return successResult();
557
558 const float fPan = float(pan) / 1000.f;
559 // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
560 /*if (relative) {
561 pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);
562 } else {
563 pNote->Override.Pan = fPan;
564 pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() calls on same note with 'relative' being set
565 }*/
566
567 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
568 e.Init(); // clear IDs
569 e.Type = Event::type_note_synth_param;
570 e.Param.NoteSynthParam.NoteID = id.noteID();
571 e.Param.NoteSynthParam.Type = Event::synth_param_pan;
572 e.Param.NoteSynthParam.Delta = fPan;
573 e.Param.NoteSynthParam.Relative = relative;
574
575 pEngineChannel->ScheduleEventMicroSec(&e, 0);
576 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
577 VMIntArrayExpr* ids = args->arg(0)->asIntArray();
578 for (int i = 0; i < ids->arraySize(); ++i) {
579 const ScriptID id = ids->evalIntElement(i);
580 if (!id || !id.isNoteID()) continue;
581
582 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
583 if (!pNote) continue;
584
585 const float fPan = float(pan) / 1000.f;
586 // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
587 /*if (relative) {
588 pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);
589 } else {
590 pNote->Override.Pan = fPan;
591 pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() calls on same note with 'relative' being set
592 }*/
593
594 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
595 e.Init(); // clear IDs
596 e.Type = Event::type_note_synth_param;
597 e.Param.NoteSynthParam.NoteID = id.noteID();
598 e.Param.NoteSynthParam.Type = Event::synth_param_pan;
599 e.Param.NoteSynthParam.Delta = fPan;
600 e.Param.NoteSynthParam.Relative = relative;
601
602 pEngineChannel->ScheduleEventMicroSec(&e, 0);
603 }
604 }
605
606 return successResult();
607 }
608
609 #define VM_FILTER_PAR_MAX_VALUE 1000000
610 #define VM_EG_PAR_MAX_VALUE 1000000
611
612 // change_cutoff() function
613
614 InstrumentScriptVMFunction_change_cutoff::InstrumentScriptVMFunction_change_cutoff(InstrumentScriptVM* parent)
615 : m_vm(parent)
616 {
617 }
618
619 bool InstrumentScriptVMFunction_change_cutoff::acceptsArgType(int iArg, ExprType_t type) const {
620 if (iArg == 0)
621 return type == INT_EXPR || type == INT_ARR_EXPR;
622 else
623 return INT_EXPR;
624 }
625
626 VMFnResult* InstrumentScriptVMFunction_change_cutoff::exec(VMFnArgs* args) {
627 int cutoff = args->arg(1)->asInt()->evalInt();
628 if (cutoff > VM_FILTER_PAR_MAX_VALUE) {
629 wrnMsg("change_cutoff(): argument 2 may not be larger than 1000000");
630 cutoff = VM_FILTER_PAR_MAX_VALUE;
631 } else if (cutoff < 0) {
632 wrnMsg("change_cutoff(): argument 2 may not be negative");
633 cutoff = 0;
634 }
635
636 AbstractEngineChannel* pEngineChannel =
637 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
638
639 if (args->arg(0)->exprType() == INT_EXPR) {
640 const ScriptID id = args->arg(0)->asInt()->evalInt();
641 if (!id) {
642 wrnMsg("change_cutoff(): note ID for argument 1 may not be zero");
643 return successResult();
644 }
645 if (!id.isNoteID()) {
646 wrnMsg("change_cutoff(): argument 1 is not a note ID");
647 return successResult();
648 }
649
650 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
651 if (!pNote) return successResult();
652
653 const float fCutoff = float(cutoff) / float(VM_FILTER_PAR_MAX_VALUE);
654
655 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
656 e.Init(); // clear IDs
657 e.Type = Event::type_note_synth_param;
658 e.Param.NoteSynthParam.NoteID = id.noteID();
659 e.Param.NoteSynthParam.Type = Event::synth_param_cutoff;
660 e.Param.NoteSynthParam.Delta = fCutoff;
661 e.Param.NoteSynthParam.Relative = false;
662
663 pEngineChannel->ScheduleEventMicroSec(&e, 0);
664 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
665 VMIntArrayExpr* ids = args->arg(0)->asIntArray();
666 for (int i = 0; i < ids->arraySize(); ++i) {
667 const ScriptID id = ids->evalIntElement(i);
668 if (!id || !id.isNoteID()) continue;
669
670 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
671 if (!pNote) continue;
672
673 const float fCutoff = float(cutoff) / float(VM_FILTER_PAR_MAX_VALUE);
674
675 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
676 e.Init(); // clear IDs
677 e.Type = Event::type_note_synth_param;
678 e.Param.NoteSynthParam.NoteID = id.noteID();
679 e.Param.NoteSynthParam.Type = Event::synth_param_cutoff;
680 e.Param.NoteSynthParam.Delta = fCutoff;
681 e.Param.NoteSynthParam.Relative = false;
682
683 pEngineChannel->ScheduleEventMicroSec(&e, 0);
684 }
685 }
686
687 return successResult();
688 }
689
690 // change_reso() function
691
692 InstrumentScriptVMFunction_change_reso::InstrumentScriptVMFunction_change_reso(InstrumentScriptVM* parent)
693 : m_vm(parent)
694 {
695 }
696
697 bool InstrumentScriptVMFunction_change_reso::acceptsArgType(int iArg, ExprType_t type) const {
698 if (iArg == 0)
699 return type == INT_EXPR || type == INT_ARR_EXPR;
700 else
701 return INT_EXPR;
702 }
703
704 VMFnResult* InstrumentScriptVMFunction_change_reso::exec(VMFnArgs* args) {
705 int resonance = args->arg(1)->asInt()->evalInt();
706 if (resonance > VM_FILTER_PAR_MAX_VALUE) {
707 wrnMsg("change_reso(): argument 2 may not be larger than 1000000");
708 resonance = VM_FILTER_PAR_MAX_VALUE;
709 } else if (resonance < 0) {
710 wrnMsg("change_reso(): argument 2 may not be negative");
711 resonance = 0;
712 }
713
714 AbstractEngineChannel* pEngineChannel =
715 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
716
717 if (args->arg(0)->exprType() == INT_EXPR) {
718 const ScriptID id = args->arg(0)->asInt()->evalInt();
719 if (!id) {
720 wrnMsg("change_reso(): note ID for argument 1 may not be zero");
721 return successResult();
722 }
723 if (!id.isNoteID()) {
724 wrnMsg("change_reso(): argument 1 is not a note ID");
725 return successResult();
726 }
727
728 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
729 if (!pNote) return successResult();
730
731 const float fResonance = float(resonance) / float(VM_FILTER_PAR_MAX_VALUE);
732
733 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
734 e.Init(); // clear IDs
735 e.Type = Event::type_note_synth_param;
736 e.Param.NoteSynthParam.NoteID = id.noteID();
737 e.Param.NoteSynthParam.Type = Event::synth_param_resonance;
738 e.Param.NoteSynthParam.Delta = fResonance;
739 e.Param.NoteSynthParam.Relative = false;
740
741 pEngineChannel->ScheduleEventMicroSec(&e, 0);
742 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
743 VMIntArrayExpr* ids = args->arg(0)->asIntArray();
744 for (int i = 0; i < ids->arraySize(); ++i) {
745 const ScriptID id = ids->evalIntElement(i);
746 if (!id || !id.isNoteID()) continue;
747
748 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
749 if (!pNote) continue;
750
751 const float fResonance = float(resonance) / float(VM_FILTER_PAR_MAX_VALUE);
752
753 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
754 e.Init(); // clear IDs
755 e.Type = Event::type_note_synth_param;
756 e.Param.NoteSynthParam.NoteID = id.noteID();
757 e.Param.NoteSynthParam.Type = Event::synth_param_resonance;
758 e.Param.NoteSynthParam.Delta = fResonance;
759 e.Param.NoteSynthParam.Relative = false;
760
761 pEngineChannel->ScheduleEventMicroSec(&e, 0);
762 }
763 }
764
765 return successResult();
766 }
767
768 // change_attack() function
769
770 InstrumentScriptVMFunction_change_attack::InstrumentScriptVMFunction_change_attack(InstrumentScriptVM* parent)
771 : m_vm(parent)
772 {
773 }
774
775 bool InstrumentScriptVMFunction_change_attack::acceptsArgType(int iArg, ExprType_t type) const {
776 if (iArg == 0)
777 return type == INT_EXPR || type == INT_ARR_EXPR;
778 else
779 return INT_EXPR;
780 }
781
782 VMFnResult* InstrumentScriptVMFunction_change_attack::exec(VMFnArgs* args) {
783 int attack = args->arg(1)->asInt()->evalInt();
784 if (attack > VM_EG_PAR_MAX_VALUE) {
785 wrnMsg("change_attack(): argument 2 may not be larger than 1000000");
786 attack = VM_EG_PAR_MAX_VALUE;
787 } else if (attack < 0) {
788 wrnMsg("change_attack(): argument 2 may not be negative");
789 attack = 0;
790 }
791 const float fAttack = float(attack) / float(VM_EG_PAR_MAX_VALUE);
792
793 AbstractEngineChannel* pEngineChannel =
794 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
795
796 if (args->arg(0)->exprType() == INT_EXPR) {
797 const ScriptID id = args->arg(0)->asInt()->evalInt();
798 if (!id) {
799 wrnMsg("change_attack(): note ID for argument 1 may not be zero");
800 return successResult();
801 }
802 if (!id.isNoteID()) {
803 wrnMsg("change_attack(): argument 1 is not a note ID");
804 return successResult();
805 }
806
807 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
808 if (!pNote) return successResult();
809
810 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
811 e.Init(); // clear IDs
812 e.Type = Event::type_note_synth_param;
813 e.Param.NoteSynthParam.NoteID = id.noteID();
814 e.Param.NoteSynthParam.Type = Event::synth_param_attack;
815 e.Param.NoteSynthParam.Delta = fAttack;
816 e.Param.NoteSynthParam.Relative = false;
817
818 pEngineChannel->ScheduleEventMicroSec(&e, 0);
819 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
820 VMIntArrayExpr* ids = args->arg(0)->asIntArray();
821 for (int i = 0; i < ids->arraySize(); ++i) {
822 const ScriptID id = ids->evalIntElement(i);
823 if (!id || !id.isNoteID()) continue;
824
825 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
826 if (!pNote) continue;
827
828 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
829 e.Init(); // clear IDs
830 e.Type = Event::type_note_synth_param;
831 e.Param.NoteSynthParam.NoteID = id.noteID();
832 e.Param.NoteSynthParam.Type = Event::synth_param_attack;
833 e.Param.NoteSynthParam.Delta = fAttack;
834 e.Param.NoteSynthParam.Relative = false;
835
836 pEngineChannel->ScheduleEventMicroSec(&e, 0);
837 }
838 }
839
840 return successResult();
841 }
842
843 // change_decay() function
844
845 InstrumentScriptVMFunction_change_decay::InstrumentScriptVMFunction_change_decay(InstrumentScriptVM* parent)
846 : m_vm(parent)
847 {
848 }
849
850 bool InstrumentScriptVMFunction_change_decay::acceptsArgType(int iArg, ExprType_t type) const {
851 if (iArg == 0)
852 return type == INT_EXPR || type == INT_ARR_EXPR;
853 else
854 return INT_EXPR;
855 }
856
857 VMFnResult* InstrumentScriptVMFunction_change_decay::exec(VMFnArgs* args) {
858 int decay = args->arg(1)->asInt()->evalInt();
859 if (decay > VM_EG_PAR_MAX_VALUE) {
860 wrnMsg("change_decay(): argument 2 may not be larger than 1000000");
861 decay = VM_EG_PAR_MAX_VALUE;
862 } else if (decay < 0) {
863 wrnMsg("change_decay(): argument 2 may not be negative");
864 decay = 0;
865 }
866 const float fDecay = float(decay) / float(VM_EG_PAR_MAX_VALUE);
867
868 AbstractEngineChannel* pEngineChannel =
869 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
870
871 if (args->arg(0)->exprType() == INT_EXPR) {
872 const ScriptID id = args->arg(0)->asInt()->evalInt();
873 if (!id) {
874 wrnMsg("change_decay(): note ID for argument 1 may not be zero");
875 return successResult();
876 }
877 if (!id.isNoteID()) {
878 wrnMsg("change_decay(): argument 1 is not a note ID");
879 return successResult();
880 }
881
882 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
883 if (!pNote) return successResult();
884
885 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
886 e.Init(); // clear IDs
887 e.Type = Event::type_note_synth_param;
888 e.Param.NoteSynthParam.NoteID = id.noteID();
889 e.Param.NoteSynthParam.Type = Event::synth_param_decay;
890 e.Param.NoteSynthParam.Delta = fDecay;
891 e.Param.NoteSynthParam.Relative = false;
892
893 pEngineChannel->ScheduleEventMicroSec(&e, 0);
894 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
895 VMIntArrayExpr* ids = args->arg(0)->asIntArray();
896 for (int i = 0; i < ids->arraySize(); ++i) {
897 const ScriptID id = ids->evalIntElement(i);
898 if (!id || !id.isNoteID()) continue;
899
900 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
901 if (!pNote) continue;
902
903 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
904 e.Init(); // clear IDs
905 e.Type = Event::type_note_synth_param;
906 e.Param.NoteSynthParam.NoteID = id.noteID();
907 e.Param.NoteSynthParam.Type = Event::synth_param_decay;
908 e.Param.NoteSynthParam.Delta = fDecay;
909 e.Param.NoteSynthParam.Relative = false;
910
911 pEngineChannel->ScheduleEventMicroSec(&e, 0);
912 }
913 }
914
915 return successResult();
916 }
917
918 // change_release() function
919
920 InstrumentScriptVMFunction_change_release::InstrumentScriptVMFunction_change_release(InstrumentScriptVM* parent)
921 : m_vm(parent)
922 {
923 }
924
925 bool InstrumentScriptVMFunction_change_release::acceptsArgType(int iArg, ExprType_t type) const {
926 if (iArg == 0)
927 return type == INT_EXPR || type == INT_ARR_EXPR;
928 else
929 return INT_EXPR;
930 }
931
932 VMFnResult* InstrumentScriptVMFunction_change_release::exec(VMFnArgs* args) {
933 int release = args->arg(1)->asInt()->evalInt();
934 if (release > VM_EG_PAR_MAX_VALUE) {
935 wrnMsg("change_release(): argument 2 may not be larger than 1000000");
936 release = VM_EG_PAR_MAX_VALUE;
937 } else if (release < 0) {
938 wrnMsg("change_release(): argument 2 may not be negative");
939 release = 0;
940 }
941 const float fRelease = float(release) / float(VM_EG_PAR_MAX_VALUE);
942
943 AbstractEngineChannel* pEngineChannel =
944 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
945
946 if (args->arg(0)->exprType() == INT_EXPR) {
947 const ScriptID id = args->arg(0)->asInt()->evalInt();
948 if (!id) {
949 wrnMsg("change_release(): note ID for argument 1 may not be zero");
950 return successResult();
951 }
952 if (!id.isNoteID()) {
953 wrnMsg("change_release(): argument 1 is not a note ID");
954 return successResult();
955 }
956
957 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
958 if (!pNote) return successResult();
959
960 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
961 e.Init(); // clear IDs
962 e.Type = Event::type_note_synth_param;
963 e.Param.NoteSynthParam.NoteID = id.noteID();
964 e.Param.NoteSynthParam.Type = Event::synth_param_release;
965 e.Param.NoteSynthParam.Delta = fRelease;
966 e.Param.NoteSynthParam.Relative = false;
967
968 pEngineChannel->ScheduleEventMicroSec(&e, 0);
969 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
970 VMIntArrayExpr* ids = args->arg(0)->asIntArray();
971 for (int i = 0; i < ids->arraySize(); ++i) {
972 const ScriptID id = ids->evalIntElement(i);
973 if (!id || !id.isNoteID()) continue;
974
975 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
976 if (!pNote) continue;
977
978 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
979 e.Init(); // clear IDs
980 e.Type = Event::type_note_synth_param;
981 e.Param.NoteSynthParam.NoteID = id.noteID();
982 e.Param.NoteSynthParam.Type = Event::synth_param_release;
983 e.Param.NoteSynthParam.Delta = fRelease;
984 e.Param.NoteSynthParam.Relative = false;
985
986 pEngineChannel->ScheduleEventMicroSec(&e, 0);
987 }
988 }
989
990 return successResult();
991 }
992
993 // event_status() function
994
995 InstrumentScriptVMFunction_event_status::InstrumentScriptVMFunction_event_status(InstrumentScriptVM* parent)
996 : m_vm(parent)
997 {
998 }
999
1000 VMFnResult* InstrumentScriptVMFunction_event_status::exec(VMFnArgs* args) {
1001 AbstractEngineChannel* pEngineChannel =
1002 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1003
1004 const ScriptID id = args->arg(0)->asInt()->evalInt();
1005 if (!id) {
1006 wrnMsg("event_status(): note ID for argument 1 may not be zero");
1007 return successResult(EVENT_STATUS_INACTIVE);
1008 }
1009 if (!id.isNoteID()) {
1010 wrnMsg("event_status(): argument 1 is not a note ID");
1011 return successResult(EVENT_STATUS_INACTIVE);
1012 }
1013
1014 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1015 return successResult(pNote ? EVENT_STATUS_NOTE_QUEUE : EVENT_STATUS_INACTIVE);
1016 }
1017
1018 // wait() function (overrides core wait() implementation)
1019
1020 InstrumentScriptVMFunction_wait::InstrumentScriptVMFunction_wait(InstrumentScriptVM* parent)
1021 : CoreVMFunction_wait(parent)
1022 {
1023 }
1024
1025 VMFnResult* InstrumentScriptVMFunction_wait::exec(VMFnArgs* args) {
1026 InstrumentScriptVM* m_vm = (InstrumentScriptVM*) vm;
1027
1028 // this might be set by passing 1 with the 2nd argument of built-in stop_wait() function
1029 if (m_vm->m_event->ignoreAllWaitCalls) return successResult();
1030
1031 return CoreVMFunction_wait::exec(args);
1032 }
1033
1034 // stop_wait() function
1035
1036 InstrumentScriptVMFunction_stop_wait::InstrumentScriptVMFunction_stop_wait(InstrumentScriptVM* parent)
1037 : m_vm(parent)
1038 {
1039 }
1040
1041 VMFnResult* InstrumentScriptVMFunction_stop_wait::exec(VMFnArgs* args) {
1042 AbstractEngineChannel* pEngineChannel =
1043 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1044
1045 const script_callback_id_t id = args->arg(0)->asInt()->evalInt();
1046 if (!id) {
1047 wrnMsg("stop_wait(): callback ID for argument 1 may not be zero");
1048 return successResult();
1049 }
1050
1051 RTList<ScriptEvent>::Iterator itCallback = pEngineChannel->ScriptCallbackByID(id);
1052 if (!itCallback) return successResult(); // ignore if callback is i.e. not alive anymore
1053
1054 const bool disableWaitForever =
1055 (args->argsCount() >= 2) ? (args->arg(1)->asInt()->evalInt() == 1) : false;
1056
1057 pEngineChannel->ScheduleResumeOfScriptCallback(
1058 itCallback, m_vm->m_event->cause.SchedTime(), disableWaitForever
1059 );
1060
1061 return successResult();
1062 }
1063
1064 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC