/[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 2938 - (show annotations) (download)
Mon Jul 11 17:10:40 2016 UTC (7 years, 8 months ago) by schoenebeck
File size: 32016 byte(s)
* Fixed behavior of built-in instrument script functions play_note()
  and note_off(), which must be distinguished engine internally
  from "real" MIDI note on/off events in order to avoid
  misbehaviors like hanging notes.
* Bumped version (2.0.0.svn13).

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
611 // change_cutoff() function
612
613 InstrumentScriptVMFunction_change_cutoff::InstrumentScriptVMFunction_change_cutoff(InstrumentScriptVM* parent)
614 : m_vm(parent)
615 {
616 }
617
618 bool InstrumentScriptVMFunction_change_cutoff::acceptsArgType(int iArg, ExprType_t type) const {
619 if (iArg == 0)
620 return type == INT_EXPR || type == INT_ARR_EXPR;
621 else
622 return INT_EXPR;
623 }
624
625 VMFnResult* InstrumentScriptVMFunction_change_cutoff::exec(VMFnArgs* args) {
626 int cutoff = args->arg(1)->asInt()->evalInt();
627 if (cutoff > VM_FILTER_PAR_MAX_VALUE) {
628 wrnMsg("change_cutoff(): argument 2 may not be larger than 1000000");
629 cutoff = VM_FILTER_PAR_MAX_VALUE;
630 } else if (cutoff < 0) {
631 wrnMsg("change_cutoff(): argument 2 may not be negative");
632 cutoff = 0;
633 }
634
635 AbstractEngineChannel* pEngineChannel =
636 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
637
638 if (args->arg(0)->exprType() == INT_EXPR) {
639 const ScriptID id = args->arg(0)->asInt()->evalInt();
640 if (!id) {
641 wrnMsg("change_cutoff(): note ID for argument 1 may not be zero");
642 return successResult();
643 }
644 if (!id.isNoteID()) {
645 wrnMsg("change_cutoff(): argument 1 is not a note ID");
646 return successResult();
647 }
648
649 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
650 if (!pNote) return successResult();
651
652 const float fCutoff = float(cutoff) / float(VM_FILTER_PAR_MAX_VALUE);
653
654 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
655 e.Init(); // clear IDs
656 e.Type = Event::type_note_synth_param;
657 e.Param.NoteSynthParam.NoteID = id.noteID();
658 e.Param.NoteSynthParam.Type = Event::synth_param_cutoff;
659 e.Param.NoteSynthParam.Delta = fCutoff;
660 e.Param.NoteSynthParam.Relative = false;
661
662 pEngineChannel->ScheduleEventMicroSec(&e, 0);
663 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
664 VMIntArrayExpr* ids = args->arg(0)->asIntArray();
665 for (int i = 0; i < ids->arraySize(); ++i) {
666 const ScriptID id = ids->evalIntElement(i);
667 if (!id || !id.isNoteID()) continue;
668
669 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
670 if (!pNote) continue;
671
672 const float fCutoff = float(cutoff) / float(VM_FILTER_PAR_MAX_VALUE);
673
674 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
675 e.Init(); // clear IDs
676 e.Type = Event::type_note_synth_param;
677 e.Param.NoteSynthParam.NoteID = id.noteID();
678 e.Param.NoteSynthParam.Type = Event::synth_param_cutoff;
679 e.Param.NoteSynthParam.Delta = fCutoff;
680 e.Param.NoteSynthParam.Relative = false;
681
682 pEngineChannel->ScheduleEventMicroSec(&e, 0);
683 }
684 }
685
686 return successResult();
687 }
688
689 // change_reso() function
690
691 InstrumentScriptVMFunction_change_reso::InstrumentScriptVMFunction_change_reso(InstrumentScriptVM* parent)
692 : m_vm(parent)
693 {
694 }
695
696 bool InstrumentScriptVMFunction_change_reso::acceptsArgType(int iArg, ExprType_t type) const {
697 if (iArg == 0)
698 return type == INT_EXPR || type == INT_ARR_EXPR;
699 else
700 return INT_EXPR;
701 }
702
703 VMFnResult* InstrumentScriptVMFunction_change_reso::exec(VMFnArgs* args) {
704 int resonance = args->arg(1)->asInt()->evalInt();
705 if (resonance > VM_FILTER_PAR_MAX_VALUE) {
706 wrnMsg("change_reso(): argument 2 may not be larger than 1000000");
707 resonance = VM_FILTER_PAR_MAX_VALUE;
708 } else if (resonance < 0) {
709 wrnMsg("change_reso(): argument 2 may not be negative");
710 resonance = 0;
711 }
712
713 AbstractEngineChannel* pEngineChannel =
714 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
715
716 if (args->arg(0)->exprType() == INT_EXPR) {
717 const ScriptID id = args->arg(0)->asInt()->evalInt();
718 if (!id) {
719 wrnMsg("change_reso(): note ID for argument 1 may not be zero");
720 return successResult();
721 }
722 if (!id.isNoteID()) {
723 wrnMsg("change_reso(): argument 1 is not a note ID");
724 return successResult();
725 }
726
727 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
728 if (!pNote) return successResult();
729
730 const float fResonance = float(resonance) / float(VM_FILTER_PAR_MAX_VALUE);
731
732 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
733 e.Init(); // clear IDs
734 e.Type = Event::type_note_synth_param;
735 e.Param.NoteSynthParam.NoteID = id.noteID();
736 e.Param.NoteSynthParam.Type = Event::synth_param_resonance;
737 e.Param.NoteSynthParam.Delta = fResonance;
738 e.Param.NoteSynthParam.Relative = false;
739
740 pEngineChannel->ScheduleEventMicroSec(&e, 0);
741 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
742 VMIntArrayExpr* ids = args->arg(0)->asIntArray();
743 for (int i = 0; i < ids->arraySize(); ++i) {
744 const ScriptID id = ids->evalIntElement(i);
745 if (!id || !id.isNoteID()) continue;
746
747 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
748 if (!pNote) continue;
749
750 const float fResonance = float(resonance) / float(VM_FILTER_PAR_MAX_VALUE);
751
752 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
753 e.Init(); // clear IDs
754 e.Type = Event::type_note_synth_param;
755 e.Param.NoteSynthParam.NoteID = id.noteID();
756 e.Param.NoteSynthParam.Type = Event::synth_param_resonance;
757 e.Param.NoteSynthParam.Delta = fResonance;
758 e.Param.NoteSynthParam.Relative = false;
759
760 pEngineChannel->ScheduleEventMicroSec(&e, 0);
761 }
762 }
763
764 return successResult();
765 }
766
767 // event_status() function
768
769 InstrumentScriptVMFunction_event_status::InstrumentScriptVMFunction_event_status(InstrumentScriptVM* parent)
770 : m_vm(parent)
771 {
772 }
773
774 VMFnResult* InstrumentScriptVMFunction_event_status::exec(VMFnArgs* args) {
775 AbstractEngineChannel* pEngineChannel =
776 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
777
778 const ScriptID id = args->arg(0)->asInt()->evalInt();
779 if (!id) {
780 wrnMsg("event_status(): note ID for argument 1 may not be zero");
781 return successResult(EVENT_STATUS_INACTIVE);
782 }
783 if (!id.isNoteID()) {
784 wrnMsg("event_status(): argument 1 is not a note ID");
785 return successResult(EVENT_STATUS_INACTIVE);
786 }
787
788 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
789 return successResult(pNote ? EVENT_STATUS_NOTE_QUEUE : EVENT_STATUS_INACTIVE);
790 }
791
792 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC