/[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 2935 - (show annotations) (download)
Sun Jul 10 14:24:13 2016 UTC (16 months, 1 week ago) by schoenebeck
File size: 31786 byte(s)
* NKSP: Added & implemented built-in script function "change_cutoff()".
* NKSP: Added & implemented built-in script function "change_reso()".
* NKSP: Added & implemented built-in script function "event_status()".
* NKSP: Added built-in script constants "$EVENT_STATUS_INACTIVE" and
  "$EVENT_STATUS_NOTE_QUEUE" both for being used as flags for
  built-in "event_status()" script function.
* NKSP language: Added support for bitwise operators ".or.", ".and."
  and ".not.".
* NKSP language scanner: Fixed IDs matching to require at least one
  character (i.e. when matching function names or variable names).
* NKSP language scanner: disabled unusued rules.
* Bumped version (2.0.0.svn12).

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_note_on;
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 note-on event was scheduled
71 // successfully above), then schedule a subsequent note-off event
72 if (id && duration > 0) {
73 e.Type = Event::type_note_off;
74 e.Param.Note.Velocity = 127;
75 pEngineChannel->ScheduleEventMicroSec(&e, duration);
76 }
77
78 // even if id is null, don't return an errorResult() here, because that
79 // would abort the script, and under heavy load it may be considerable
80 // that ScheduleNoteMicroSec() fails above, so simply ignore that
81 return successResult( ScriptID::fromNoteID(id) );
82 }
83
84 // set_controller() function
85
86 InstrumentScriptVMFunction_set_controller::InstrumentScriptVMFunction_set_controller(InstrumentScriptVM* parent)
87 : m_vm(parent)
88 {
89 }
90
91 VMFnResult* InstrumentScriptVMFunction_set_controller::exec(VMFnArgs* args) {
92 int controller = args->arg(0)->asInt()->evalInt();
93 int value = args->arg(1)->asInt()->evalInt();
94
95 AbstractEngineChannel* pEngineChannel =
96 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
97
98 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
99 e.Init(); // clear IDs
100 if (controller == CTRL_TABLE_IDX_AFTERTOUCH) {
101 e.Type = Event::type_channel_pressure;
102 e.Param.ChannelPressure.Value = value & 127;
103 } else if (controller == CTRL_TABLE_IDX_PITCHBEND) {
104 e.Type = Event::type_pitchbend;
105 e.Param.Pitch.Pitch = value;
106 } else if (controller >= 0 && controller <= 127) {
107 e.Type = Event::type_control_change;
108 e.Param.CC.Controller = controller;
109 e.Param.CC.Value = value;
110 } else {
111 errMsg("set_controller(): argument 1 is an invalid controller");
112 return errorResult();
113 }
114
115 const event_id_t id = pEngineChannel->ScheduleEventMicroSec(&e, 0);
116
117 // even if id is null, don't return an errorResult() here, because that
118 // would abort the script, and under heavy load it may be considerable
119 // that ScheduleEventMicroSec() fails above, so simply ignore that
120 return successResult( ScriptID::fromEventID(id) );
121 }
122
123 // ignore_event() function
124
125 InstrumentScriptVMFunction_ignore_event::InstrumentScriptVMFunction_ignore_event(InstrumentScriptVM* parent)
126 : m_vm(parent)
127 {
128 }
129
130 bool InstrumentScriptVMFunction_ignore_event::acceptsArgType(int iArg, ExprType_t type) const {
131 return type == INT_EXPR || type == INT_ARR_EXPR;
132 }
133
134 VMFnResult* InstrumentScriptVMFunction_ignore_event::exec(VMFnArgs* args) {
135 AbstractEngineChannel* pEngineChannel =
136 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
137
138 if (args->arg(0)->exprType() == INT_EXPR) {
139 const ScriptID id = args->arg(0)->asInt()->evalInt();
140 if (!id) {
141 wrnMsg("ignore_event(): event ID argument may not be zero");
142 // not errorResult(), because that would abort the script, not intentional in this case
143 return successResult();
144 }
145 pEngineChannel->IgnoreEventByScriptID(id);
146 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
147 VMIntArrayExpr* ids = args->arg(0)->asIntArray();
148 for (int i = 0; i < ids->arraySize(); ++i) {
149 const ScriptID id = ids->evalIntElement(i);
150 pEngineChannel->IgnoreEventByScriptID(id);
151 }
152 }
153
154 return successResult();
155 }
156
157 // ignore_controller() function
158
159 InstrumentScriptVMFunction_ignore_controller::InstrumentScriptVMFunction_ignore_controller(InstrumentScriptVM* parent)
160 : m_vm(parent)
161 {
162 }
163
164 VMFnResult* InstrumentScriptVMFunction_ignore_controller::exec(VMFnArgs* args) {
165 const ScriptID id = (args->argsCount() >= 1) ? args->arg(0)->asInt()->evalInt() : m_vm->m_event->id;
166 if (!id && args->argsCount() >= 1) {
167 wrnMsg("ignore_controller(): event ID argument may not be zero");
168 return successResult();
169 }
170
171 AbstractEngineChannel* pEngineChannel =
172 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
173
174 pEngineChannel->IgnoreEventByScriptID(id);
175
176 return successResult();
177 }
178
179 // note_off() function
180
181 InstrumentScriptVMFunction_note_off::InstrumentScriptVMFunction_note_off(InstrumentScriptVM* parent)
182 : m_vm(parent)
183 {
184 }
185
186 bool InstrumentScriptVMFunction_note_off::acceptsArgType(int iArg, ExprType_t type) const {
187 return type == INT_EXPR || type == INT_ARR_EXPR;
188 }
189
190 VMFnResult* InstrumentScriptVMFunction_note_off::exec(VMFnArgs* args) {
191 AbstractEngineChannel* pEngineChannel =
192 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
193
194 int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;
195 if (velocity < 0 || velocity > 127) {
196 errMsg("note_off(): argument 2 is an invalid velocity value");
197 return errorResult();
198 }
199
200 if (args->arg(0)->exprType() == INT_EXPR) {
201 const ScriptID id = args->arg(0)->asInt()->evalInt();
202 if (!id) {
203 wrnMsg("note_off(): note ID for argument 1 may not be zero");
204 return successResult();
205 }
206 if (!id.isNoteID()) {
207 wrnMsg("note_off(): argument 1 is not a note ID");
208 return successResult();
209 }
210
211 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
212 if (!pNote) return successResult();
213
214 Event e = pNote->cause;
215 e.Init(); // clear IDs
216 e.CopyTimeFrom(m_vm->m_event->cause); // set fragment time for "now"
217 e.Type = Event::type_note_off;
218 e.Param.Note.Velocity = velocity;
219
220 pEngineChannel->ScheduleEventMicroSec(&e, 0);
221 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
222 VMIntArrayExpr* ids = args->arg(0)->asIntArray();
223 for (int i = 0; i < ids->arraySize(); ++i) {
224 const ScriptID id = ids->evalIntElement(i);
225 if (!id || !id.isNoteID()) continue;
226
227 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
228 if (!pNote) continue;
229
230 Event e = pNote->cause;
231 e.Init(); // clear IDs
232 e.CopyTimeFrom(m_vm->m_event->cause); // set fragment time for "now"
233 e.Type = Event::type_note_off;
234 e.Param.Note.Velocity = velocity;
235
236 pEngineChannel->ScheduleEventMicroSec(&e, 0);
237 }
238 }
239
240 return successResult();
241 }
242
243 // set_event_mark() function
244
245 InstrumentScriptVMFunction_set_event_mark::InstrumentScriptVMFunction_set_event_mark(InstrumentScriptVM* parent)
246 : m_vm(parent)
247 {
248 }
249
250 VMFnResult* InstrumentScriptVMFunction_set_event_mark::exec(VMFnArgs* args) {
251 const ScriptID id = args->arg(0)->asInt()->evalInt();
252 const int groupID = args->arg(1)->asInt()->evalInt();
253
254 if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
255 errMsg("set_event_mark(): argument 2 is an invalid group id");
256 return errorResult();
257 }
258
259 AbstractEngineChannel* pEngineChannel =
260 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
261
262 // check if the event/note still exists
263 switch (id.type()) {
264 case ScriptID::EVENT: {
265 RTList<Event>::Iterator itEvent = pEngineChannel->pEngine->EventByID( id.eventID() );
266 if (!itEvent) return successResult();
267 break;
268 }
269 case ScriptID::NOTE: {
270 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
271 if (!pNote) return successResult();
272 break;
273 }
274 }
275
276 pEngineChannel->pScript->eventGroups[groupID].insert(id);
277
278 return successResult();
279 }
280
281 // delete_event_mark() function
282
283 InstrumentScriptVMFunction_delete_event_mark::InstrumentScriptVMFunction_delete_event_mark(InstrumentScriptVM* parent)
284 : m_vm(parent)
285 {
286 }
287
288 VMFnResult* InstrumentScriptVMFunction_delete_event_mark::exec(VMFnArgs* args) {
289 const ScriptID id = args->arg(0)->asInt()->evalInt();
290 const int groupID = args->arg(1)->asInt()->evalInt();
291
292 if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
293 errMsg("delete_event_mark(): argument 2 is an invalid group id");
294 return errorResult();
295 }
296
297 AbstractEngineChannel* pEngineChannel =
298 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
299
300 pEngineChannel->pScript->eventGroups[groupID].erase(id);
301
302 return successResult();
303 }
304
305 // by_marks() function
306
307 InstrumentScriptVMFunction_by_marks::InstrumentScriptVMFunction_by_marks(InstrumentScriptVM* parent)
308 : m_vm(parent)
309 {
310 }
311
312 int InstrumentScriptVMFunction_by_marks::Result::arraySize() const {
313 return eventGroup->size();
314 }
315
316 int InstrumentScriptVMFunction_by_marks::Result::evalIntElement(uint i) {
317 return (*eventGroup)[i];
318 }
319
320 VMFnResult* InstrumentScriptVMFunction_by_marks::errorResult() {
321 m_result.eventGroup = NULL;
322 m_result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
323 return &m_result;
324 }
325
326 VMFnResult* InstrumentScriptVMFunction_by_marks::successResult(EventGroup* eventGroup) {
327 m_result.eventGroup = eventGroup;
328 m_result.flags = STMT_SUCCESS;
329 return &m_result;
330 }
331
332 VMFnResult* InstrumentScriptVMFunction_by_marks::exec(VMFnArgs* args) {
333 int groupID = args->arg(0)->asInt()->evalInt();
334
335 if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
336 errMsg("by_marks(): argument is an invalid group id");
337 return errorResult();
338 }
339
340 AbstractEngineChannel* pEngineChannel =
341 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
342
343 return successResult( &pEngineChannel->pScript->eventGroups[groupID] );
344 }
345
346 // change_vol() function
347
348 InstrumentScriptVMFunction_change_vol::InstrumentScriptVMFunction_change_vol(InstrumentScriptVM* parent)
349 : m_vm(parent)
350 {
351 }
352
353 bool InstrumentScriptVMFunction_change_vol::acceptsArgType(int iArg, ExprType_t type) const {
354 if (iArg == 0)
355 return type == INT_EXPR || type == INT_ARR_EXPR;
356 else
357 return INT_EXPR;
358 }
359
360 VMFnResult* InstrumentScriptVMFunction_change_vol::exec(VMFnArgs* args) {
361 int volume = args->arg(1)->asInt()->evalInt(); // volume change in milli dB
362 bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;
363
364 AbstractEngineChannel* pEngineChannel =
365 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
366
367 if (args->arg(0)->exprType() == INT_EXPR) {
368 const ScriptID id = args->arg(0)->asInt()->evalInt();
369 if (!id) {
370 wrnMsg("change_vol(): note ID for argument 1 may not be zero");
371 return successResult();
372 }
373 if (!id.isNoteID()) {
374 wrnMsg("change_vol(): argument 1 is not a note ID");
375 return successResult();
376 }
377
378 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
379 if (!pNote) return successResult();
380
381 const float fVolumeLin = RTMath::DecibelToLinRatio(float(volume) / 1000.f);
382 // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
383 /*if (relative)
384 pNote->Override.Volume *= fVolumeLin;
385 else
386 pNote->Override.Volume = fVolumeLin;*/
387
388 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
389 e.Init(); // clear IDs
390 e.Type = Event::type_note_synth_param;
391 e.Param.NoteSynthParam.NoteID = id.noteID();
392 e.Param.NoteSynthParam.Type = Event::synth_param_volume;
393 e.Param.NoteSynthParam.Delta = fVolumeLin;
394 e.Param.NoteSynthParam.Relative = relative;
395
396 pEngineChannel->ScheduleEventMicroSec(&e, 0);
397 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
398 VMIntArrayExpr* ids = args->arg(0)->asIntArray();
399 for (int i = 0; i < ids->arraySize(); ++i) {
400 const ScriptID id = ids->evalIntElement(i);
401 if (!id || !id.isNoteID()) continue;
402
403 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
404 if (!pNote) continue;
405
406 const float fVolumeLin = RTMath::DecibelToLinRatio(float(volume) / 1000.f);
407 // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
408 /*if (relative)
409 pNote->Override.Volume *= fVolumeLin;
410 else
411 pNote->Override.Volume = fVolumeLin;*/
412
413 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
414 e.Init(); // clear IDs
415 e.Type = Event::type_note_synth_param;
416 e.Param.NoteSynthParam.NoteID = id.noteID();
417 e.Param.NoteSynthParam.Type = Event::synth_param_volume;
418 e.Param.NoteSynthParam.Delta = fVolumeLin;
419 e.Param.NoteSynthParam.Relative = relative;
420
421 pEngineChannel->ScheduleEventMicroSec(&e, 0);
422 }
423 }
424
425 return successResult();
426 }
427
428 // change_tune() function
429
430 InstrumentScriptVMFunction_change_tune::InstrumentScriptVMFunction_change_tune(InstrumentScriptVM* parent)
431 : m_vm(parent)
432 {
433 }
434
435 bool InstrumentScriptVMFunction_change_tune::acceptsArgType(int iArg, ExprType_t type) const {
436 if (iArg == 0)
437 return type == INT_EXPR || type == INT_ARR_EXPR;
438 else
439 return INT_EXPR;
440 }
441
442 VMFnResult* InstrumentScriptVMFunction_change_tune::exec(VMFnArgs* args) {
443 int tune = args->arg(1)->asInt()->evalInt(); // tuning change in milli cents
444 bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;
445
446 AbstractEngineChannel* pEngineChannel =
447 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
448
449 if (args->arg(0)->exprType() == INT_EXPR) {
450 const ScriptID id = args->arg(0)->asInt()->evalInt();
451 if (!id) {
452 wrnMsg("change_tune(): note ID for argument 1 may not be zero");
453 return successResult();
454 }
455 if (!id.isNoteID()) {
456 wrnMsg("change_tune(): argument 1 is not a note ID");
457 return successResult();
458 }
459
460 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
461 if (!pNote) return successResult();
462
463 const float fFreqRatio = RTMath::CentsToFreqRatioUnlimited(float(tune) / 1000.f);
464 // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
465 /*if (relative)
466 pNote->Override.Pitch *= fFreqRatio;
467 else
468 pNote->Override.Pitch = fFreqRatio;*/
469
470 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
471 e.Init(); // clear IDs
472 e.Type = Event::type_note_synth_param;
473 e.Param.NoteSynthParam.NoteID = id.noteID();
474 e.Param.NoteSynthParam.Type = Event::synth_param_pitch;
475 e.Param.NoteSynthParam.Delta = fFreqRatio;
476 e.Param.NoteSynthParam.Relative = relative;
477
478 pEngineChannel->ScheduleEventMicroSec(&e, 0);
479 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
480 VMIntArrayExpr* ids = args->arg(0)->asIntArray();
481 for (int i = 0; i < ids->arraySize(); ++i) {
482 const ScriptID id = ids->evalIntElement(i);
483 if (!id || !id.isNoteID()) continue;
484
485 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
486 if (!pNote) continue;
487
488 const float fFreqRatio = RTMath::CentsToFreqRatioUnlimited(float(tune) / 1000.f);
489 // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
490 /*if (relative)
491 pNote->Override.Pitch *= fFreqRatio;
492 else
493 pNote->Override.Pitch = fFreqRatio;*/
494
495 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
496 e.Init(); // clear IDs
497 e.Type = Event::type_note_synth_param;
498 e.Param.NoteSynthParam.NoteID = id.noteID();
499 e.Param.NoteSynthParam.Type = Event::synth_param_pitch;
500 e.Param.NoteSynthParam.Delta = fFreqRatio;
501 e.Param.NoteSynthParam.Relative = relative;
502
503 pEngineChannel->ScheduleEventMicroSec(&e, 0);
504 }
505 }
506
507 return successResult();
508 }
509
510 // change_pan() function
511
512 InstrumentScriptVMFunction_change_pan::InstrumentScriptVMFunction_change_pan(InstrumentScriptVM* parent)
513 : m_vm(parent)
514 {
515 }
516
517 bool InstrumentScriptVMFunction_change_pan::acceptsArgType(int iArg, ExprType_t type) const {
518 if (iArg == 0)
519 return type == INT_EXPR || type == INT_ARR_EXPR;
520 else
521 return INT_EXPR;
522 }
523
524 VMFnResult* InstrumentScriptVMFunction_change_pan::exec(VMFnArgs* args) {
525 int pan = args->arg(1)->asInt()->evalInt();
526 bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;
527
528 if (pan > 1000) {
529 wrnMsg("change_pan(): argument 2 may not be larger than 1000");
530 pan = 1000;
531 } else if (pan < -1000) {
532 wrnMsg("change_pan(): argument 2 may not be smaller than -1000");
533 pan = -1000;
534 }
535
536 AbstractEngineChannel* pEngineChannel =
537 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
538
539 if (args->arg(0)->exprType() == INT_EXPR) {
540 const ScriptID id = args->arg(0)->asInt()->evalInt();
541 if (!id) {
542 wrnMsg("change_pan(): note ID for argument 1 may not be zero");
543 return successResult();
544 }
545 if (!id.isNoteID()) {
546 wrnMsg("change_pan(): argument 1 is not a note ID");
547 return successResult();
548 }
549
550 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
551 if (!pNote) return successResult();
552
553 const float fPan = float(pan) / 1000.f;
554 // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
555 /*if (relative) {
556 pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);
557 } else {
558 pNote->Override.Pan = fPan;
559 pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() calls on same note with 'relative' being set
560 }*/
561
562 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
563 e.Init(); // clear IDs
564 e.Type = Event::type_note_synth_param;
565 e.Param.NoteSynthParam.NoteID = id.noteID();
566 e.Param.NoteSynthParam.Type = Event::synth_param_pan;
567 e.Param.NoteSynthParam.Delta = fPan;
568 e.Param.NoteSynthParam.Relative = relative;
569
570 pEngineChannel->ScheduleEventMicroSec(&e, 0);
571 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
572 VMIntArrayExpr* ids = args->arg(0)->asIntArray();
573 for (int i = 0; i < ids->arraySize(); ++i) {
574 const ScriptID id = ids->evalIntElement(i);
575 if (!id || !id.isNoteID()) continue;
576
577 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
578 if (!pNote) continue;
579
580 const float fPan = float(pan) / 1000.f;
581 // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior
582 /*if (relative) {
583 pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);
584 } else {
585 pNote->Override.Pan = fPan;
586 pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() calls on same note with 'relative' being set
587 }*/
588
589 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
590 e.Init(); // clear IDs
591 e.Type = Event::type_note_synth_param;
592 e.Param.NoteSynthParam.NoteID = id.noteID();
593 e.Param.NoteSynthParam.Type = Event::synth_param_pan;
594 e.Param.NoteSynthParam.Delta = fPan;
595 e.Param.NoteSynthParam.Relative = relative;
596
597 pEngineChannel->ScheduleEventMicroSec(&e, 0);
598 }
599 }
600
601 return successResult();
602 }
603
604 #define VM_FILTER_PAR_MAX_VALUE 1000000
605
606 // change_cutoff() function
607
608 InstrumentScriptVMFunction_change_cutoff::InstrumentScriptVMFunction_change_cutoff(InstrumentScriptVM* parent)
609 : m_vm(parent)
610 {
611 }
612
613 bool InstrumentScriptVMFunction_change_cutoff::acceptsArgType(int iArg, ExprType_t type) const {
614 if (iArg == 0)
615 return type == INT_EXPR || type == INT_ARR_EXPR;
616 else
617 return INT_EXPR;
618 }
619
620 VMFnResult* InstrumentScriptVMFunction_change_cutoff::exec(VMFnArgs* args) {
621 int cutoff = args->arg(1)->asInt()->evalInt();
622 if (cutoff > VM_FILTER_PAR_MAX_VALUE) {
623 wrnMsg("change_cutoff(): argument 2 may not be larger than 1000000");
624 cutoff = VM_FILTER_PAR_MAX_VALUE;
625 } else if (cutoff < 0) {
626 wrnMsg("change_cutoff(): argument 2 may not be negative");
627 cutoff = 0;
628 }
629
630 AbstractEngineChannel* pEngineChannel =
631 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
632
633 if (args->arg(0)->exprType() == INT_EXPR) {
634 const ScriptID id = args->arg(0)->asInt()->evalInt();
635 if (!id) {
636 wrnMsg("change_cutoff(): note ID for argument 1 may not be zero");
637 return successResult();
638 }
639 if (!id.isNoteID()) {
640 wrnMsg("change_cutoff(): argument 1 is not a note ID");
641 return successResult();
642 }
643
644 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
645 if (!pNote) return successResult();
646
647 const float fCutoff = float(cutoff) / float(VM_FILTER_PAR_MAX_VALUE);
648
649 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
650 e.Init(); // clear IDs
651 e.Type = Event::type_note_synth_param;
652 e.Param.NoteSynthParam.NoteID = id.noteID();
653 e.Param.NoteSynthParam.Type = Event::synth_param_cutoff;
654 e.Param.NoteSynthParam.Delta = fCutoff;
655 e.Param.NoteSynthParam.Relative = false;
656
657 pEngineChannel->ScheduleEventMicroSec(&e, 0);
658 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
659 VMIntArrayExpr* ids = args->arg(0)->asIntArray();
660 for (int i = 0; i < ids->arraySize(); ++i) {
661 const ScriptID id = ids->evalIntElement(i);
662 if (!id || !id.isNoteID()) continue;
663
664 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
665 if (!pNote) continue;
666
667 const float fCutoff = float(cutoff) / float(VM_FILTER_PAR_MAX_VALUE);
668
669 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
670 e.Init(); // clear IDs
671 e.Type = Event::type_note_synth_param;
672 e.Param.NoteSynthParam.NoteID = id.noteID();
673 e.Param.NoteSynthParam.Type = Event::synth_param_cutoff;
674 e.Param.NoteSynthParam.Delta = fCutoff;
675 e.Param.NoteSynthParam.Relative = false;
676
677 pEngineChannel->ScheduleEventMicroSec(&e, 0);
678 }
679 }
680
681 return successResult();
682 }
683
684 // change_reso() function
685
686 InstrumentScriptVMFunction_change_reso::InstrumentScriptVMFunction_change_reso(InstrumentScriptVM* parent)
687 : m_vm(parent)
688 {
689 }
690
691 bool InstrumentScriptVMFunction_change_reso::acceptsArgType(int iArg, ExprType_t type) const {
692 if (iArg == 0)
693 return type == INT_EXPR || type == INT_ARR_EXPR;
694 else
695 return INT_EXPR;
696 }
697
698 VMFnResult* InstrumentScriptVMFunction_change_reso::exec(VMFnArgs* args) {
699 int resonance = args->arg(1)->asInt()->evalInt();
700 if (resonance > VM_FILTER_PAR_MAX_VALUE) {
701 wrnMsg("change_reso(): argument 2 may not be larger than 1000000");
702 resonance = VM_FILTER_PAR_MAX_VALUE;
703 } else if (resonance < 0) {
704 wrnMsg("change_reso(): argument 2 may not be negative");
705 resonance = 0;
706 }
707
708 AbstractEngineChannel* pEngineChannel =
709 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
710
711 if (args->arg(0)->exprType() == INT_EXPR) {
712 const ScriptID id = args->arg(0)->asInt()->evalInt();
713 if (!id) {
714 wrnMsg("change_reso(): note ID for argument 1 may not be zero");
715 return successResult();
716 }
717 if (!id.isNoteID()) {
718 wrnMsg("change_reso(): argument 1 is not a note ID");
719 return successResult();
720 }
721
722 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
723 if (!pNote) return successResult();
724
725 const float fResonance = float(resonance) / float(VM_FILTER_PAR_MAX_VALUE);
726
727 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
728 e.Init(); // clear IDs
729 e.Type = Event::type_note_synth_param;
730 e.Param.NoteSynthParam.NoteID = id.noteID();
731 e.Param.NoteSynthParam.Type = Event::synth_param_resonance;
732 e.Param.NoteSynthParam.Delta = fResonance;
733 e.Param.NoteSynthParam.Relative = false;
734
735 pEngineChannel->ScheduleEventMicroSec(&e, 0);
736 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
737 VMIntArrayExpr* ids = args->arg(0)->asIntArray();
738 for (int i = 0; i < ids->arraySize(); ++i) {
739 const ScriptID id = ids->evalIntElement(i);
740 if (!id || !id.isNoteID()) continue;
741
742 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
743 if (!pNote) continue;
744
745 const float fResonance = float(resonance) / float(VM_FILTER_PAR_MAX_VALUE);
746
747 Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
748 e.Init(); // clear IDs
749 e.Type = Event::type_note_synth_param;
750 e.Param.NoteSynthParam.NoteID = id.noteID();
751 e.Param.NoteSynthParam.Type = Event::synth_param_resonance;
752 e.Param.NoteSynthParam.Delta = fResonance;
753 e.Param.NoteSynthParam.Relative = false;
754
755 pEngineChannel->ScheduleEventMicroSec(&e, 0);
756 }
757 }
758
759 return successResult();
760 }
761
762 // event_status() function
763
764 InstrumentScriptVMFunction_event_status::InstrumentScriptVMFunction_event_status(InstrumentScriptVM* parent)
765 : m_vm(parent)
766 {
767 }
768
769 VMFnResult* InstrumentScriptVMFunction_event_status::exec(VMFnArgs* args) {
770 AbstractEngineChannel* pEngineChannel =
771 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
772
773 const ScriptID id = args->arg(0)->asInt()->evalInt();
774 if (!id) {
775 wrnMsg("event_status(): note ID for argument 1 may not be zero");
776 return successResult(EVENT_STATUS_INACTIVE);
777 }
778 if (!id.isNoteID()) {
779 wrnMsg("event_status(): argument 1 is not a note ID");
780 return successResult(EVENT_STATUS_INACTIVE);
781 }
782
783 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
784 return successResult(pNote ? EVENT_STATUS_NOTE_QUEUE : EVENT_STATUS_INACTIVE);
785 }
786
787 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC