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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 3557 by schoenebeck, Sun Aug 18 00:06:04 2019 UTC revision 3561 by schoenebeck, Fri Aug 23 11:44:00 2019 UTC
# Line 10  Line 10 
10  #include "InstrumentScriptVMFunctions.h"  #include "InstrumentScriptVMFunctions.h"
11  #include "InstrumentScriptVM.h"  #include "InstrumentScriptVM.h"
12  #include "../AbstractEngineChannel.h"  #include "../AbstractEngineChannel.h"
13    #include "../../common/global_private.h"
14    
15  namespace LinuxSampler {  namespace LinuxSampler {
16            
# Line 375  namespace LinuxSampler { Line 376  namespace LinuxSampler {
376              return type == INT_EXPR;              return type == INT_EXPR;
377      }      }
378    
379        bool InstrumentScriptVMFunction_change_vol::acceptsArgUnitType(vmint iArg, StdUnit_t type) const {
380            if (iArg == 1)
381                return type == VM_NO_UNIT || type == VM_BEL;
382            else
383                return type == VM_NO_UNIT;
384        }
385    
386        bool InstrumentScriptVMFunction_change_vol::acceptsArgUnitPrefix(vmint iArg) const {
387            return iArg == 1;
388        }
389    
390        bool InstrumentScriptVMFunction_change_vol::acceptsArgFinal(vmint iArg) const {
391            return iArg == 1;
392        }
393    
394      VMFnResult* InstrumentScriptVMFunction_change_vol::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_vol::exec(VMFnArgs* args) {
395          vmint volume = args->arg(1)->asInt()->evalInt(); // volume change in milli dB          vmint volume   = args->arg(1)->asInt()->evalInt(VM_MILLI,VM_DECI); // volume change in milli dB
396            bool isFinal   = args->arg(1)->asInt()->isFinal();
397            StdUnit_t unit = args->arg(1)->asInt()->unitType();
398          bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;          bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;
399          const float fVolumeLin = RTMath::DecibelToLinRatio(float(volume) / 1000.f);          const float fVolumeLin = RTMath::DecibelToLinRatio(float(volume) / 1000.f);
400    
# Line 404  namespace LinuxSampler { Line 422  namespace LinuxSampler {
422                  pNote->Override.VolumeTime <= DEFAULT_NOTE_VOLUME_TIME_S)                  pNote->Override.VolumeTime <= DEFAULT_NOTE_VOLUME_TIME_S)
423              {              {
424                  if (relative)                  if (relative)
425                      pNote->Override.Volume *= fVolumeLin;                      pNote->Override.Volume.Value *= fVolumeLin;
426                  else                  else
427                      pNote->Override.Volume = fVolumeLin;                      pNote->Override.Volume.Value = fVolumeLin;
428                    pNote->Override.Volume.Final = isFinal;
429              } else { // otherwise schedule the volume change ...              } else { // otherwise schedule the volume change ...
430                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
431                  e.Init(); // clear IDs                  e.Init(); // clear IDs
# Line 414  namespace LinuxSampler { Line 433  namespace LinuxSampler {
433                  e.Param.NoteSynthParam.NoteID   = id.noteID();                  e.Param.NoteSynthParam.NoteID   = id.noteID();
434                  e.Param.NoteSynthParam.Type     = Event::synth_param_volume;                  e.Param.NoteSynthParam.Type     = Event::synth_param_volume;
435                  e.Param.NoteSynthParam.Delta    = fVolumeLin;                  e.Param.NoteSynthParam.Delta    = fVolumeLin;
436                  e.Param.NoteSynthParam.Relative = relative;                  e.Param.NoteSynthParam.Scope = Event::scopeBy_FinalRelativeUnit(
437                        isFinal, relative, unit
438                    );
439                  pEngineChannel->ScheduleEventMicroSec(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
440              }              }
441          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
# Line 434  namespace LinuxSampler { Line 454  namespace LinuxSampler {
454                      pNote->Override.VolumeTime <= DEFAULT_NOTE_VOLUME_TIME_S)                      pNote->Override.VolumeTime <= DEFAULT_NOTE_VOLUME_TIME_S)
455                  {                  {
456                      if (relative)                      if (relative)
457                          pNote->Override.Volume *= fVolumeLin;                          pNote->Override.Volume.Value *= fVolumeLin;
458                      else                      else
459                          pNote->Override.Volume = fVolumeLin;                          pNote->Override.Volume.Value = fVolumeLin;
460                        pNote->Override.Volume.Final = isFinal;
461                  } else { // otherwise schedule the volume change ...                  } else { // otherwise schedule the volume change ...
462                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
463                      e.Init(); // clear IDs                      e.Init(); // clear IDs
# Line 444  namespace LinuxSampler { Line 465  namespace LinuxSampler {
465                      e.Param.NoteSynthParam.NoteID   = id.noteID();                      e.Param.NoteSynthParam.NoteID   = id.noteID();
466                      e.Param.NoteSynthParam.Type     = Event::synth_param_volume;                      e.Param.NoteSynthParam.Type     = Event::synth_param_volume;
467                      e.Param.NoteSynthParam.Delta    = fVolumeLin;                      e.Param.NoteSynthParam.Delta    = fVolumeLin;
468                      e.Param.NoteSynthParam.Relative = relative;                      e.Param.NoteSynthParam.Scope = Event::scopeBy_FinalRelativeUnit(
469                            isFinal, relative, unit
470                        );
471                      pEngineChannel->ScheduleEventMicroSec(&e, 0);                      pEngineChannel->ScheduleEventMicroSec(&e, 0);
472                  }                  }
473              }              }
# Line 468  namespace LinuxSampler { Line 490  namespace LinuxSampler {
490              return type == INT_EXPR;              return type == INT_EXPR;
491      }      }
492    
493        bool InstrumentScriptVMFunction_change_tune::acceptsArgUnitPrefix(vmint iArg) const {
494            return iArg == 1;
495        }
496    
497        bool InstrumentScriptVMFunction_change_tune::acceptsArgFinal(vmint iArg) const {
498            return iArg == 1;
499        }
500    
501      VMFnResult* InstrumentScriptVMFunction_change_tune::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_tune::exec(VMFnArgs* args) {
502          vmint tune = args->arg(1)->asInt()->evalInt(); // tuning change in milli cents          vmint tune     = args->arg(1)->asInt()->evalInt(VM_MILLI,VM_CENTI); // tuning change in milli cents
503            bool isFinal   = args->arg(1)->asInt()->isFinal();
504            StdUnit_t unit = args->arg(1)->asInt()->unitType();
505          bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;          bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;
506          const float fFreqRatio = RTMath::CentsToFreqRatioUnlimited(float(tune) / 1000.f);          const float fFreqRatio = RTMath::CentsToFreqRatioUnlimited(float(tune) / 1000.f);
507    
# Line 497  namespace LinuxSampler { Line 529  namespace LinuxSampler {
529                  pNote->Override.PitchTime <= DEFAULT_NOTE_PITCH_TIME_S)                  pNote->Override.PitchTime <= DEFAULT_NOTE_PITCH_TIME_S)
530              {              {
531                  if (relative)                  if (relative)
532                      pNote->Override.Pitch *= fFreqRatio;                      pNote->Override.Pitch.Value *= fFreqRatio;
533                  else                  else
534                      pNote->Override.Pitch = fFreqRatio;                      pNote->Override.Pitch.Value = fFreqRatio;
535                    pNote->Override.Pitch.Final = isFinal;
536              } else { // otherwise schedule tuning change ...              } else { // otherwise schedule tuning change ...
537                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
538                  e.Init(); // clear IDs                  e.Init(); // clear IDs
# Line 507  namespace LinuxSampler { Line 540  namespace LinuxSampler {
540                  e.Param.NoteSynthParam.NoteID   = id.noteID();                  e.Param.NoteSynthParam.NoteID   = id.noteID();
541                  e.Param.NoteSynthParam.Type     = Event::synth_param_pitch;                  e.Param.NoteSynthParam.Type     = Event::synth_param_pitch;
542                  e.Param.NoteSynthParam.Delta    = fFreqRatio;                  e.Param.NoteSynthParam.Delta    = fFreqRatio;
543                  e.Param.NoteSynthParam.Relative = relative;                  e.Param.NoteSynthParam.Scope = Event::scopeBy_FinalRelativeUnit(
544                        isFinal, relative, unit
545                    );
546                  pEngineChannel->ScheduleEventMicroSec(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
547              }              }
548          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
# Line 527  namespace LinuxSampler { Line 561  namespace LinuxSampler {
561                      pNote->Override.PitchTime <= DEFAULT_NOTE_PITCH_TIME_S)                      pNote->Override.PitchTime <= DEFAULT_NOTE_PITCH_TIME_S)
562                  {                  {
563                      if (relative)                      if (relative)
564                          pNote->Override.Pitch *= fFreqRatio;                          pNote->Override.Pitch.Value *= fFreqRatio;
565                      else                      else
566                          pNote->Override.Pitch = fFreqRatio;                          pNote->Override.Pitch.Value = fFreqRatio;
567                        pNote->Override.Pitch.Final = isFinal;
568                  } else { // otherwise schedule tuning change ...                  } else { // otherwise schedule tuning change ...
569                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
570                      e.Init(); // clear IDs                      e.Init(); // clear IDs
# Line 537  namespace LinuxSampler { Line 572  namespace LinuxSampler {
572                      e.Param.NoteSynthParam.NoteID   = id.noteID();                      e.Param.NoteSynthParam.NoteID   = id.noteID();
573                      e.Param.NoteSynthParam.Type     = Event::synth_param_pitch;                      e.Param.NoteSynthParam.Type     = Event::synth_param_pitch;
574                      e.Param.NoteSynthParam.Delta    = fFreqRatio;                      e.Param.NoteSynthParam.Delta    = fFreqRatio;
575                      e.Param.NoteSynthParam.Relative = relative;                      e.Param.NoteSynthParam.Scope = Event::scopeBy_FinalRelativeUnit(
576                            isFinal, relative, unit
577                        );
578                      pEngineChannel->ScheduleEventMicroSec(&e, 0);                      pEngineChannel->ScheduleEventMicroSec(&e, 0);
579                  }                  }
580              }              }
# Line 561  namespace LinuxSampler { Line 597  namespace LinuxSampler {
597              return type == INT_EXPR;              return type == INT_EXPR;
598      }      }
599    
600        bool InstrumentScriptVMFunction_change_pan::acceptsArgFinal(vmint iArg) const {
601            return iArg == 1;
602        }
603    
604      VMFnResult* InstrumentScriptVMFunction_change_pan::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_pan::exec(VMFnArgs* args) {
605          vmint pan = args->arg(1)->asInt()->evalInt();          vmint pan    = args->arg(1)->asInt()->evalInt();
606            bool isFinal = args->arg(1)->asInt()->isFinal();
607          bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;          bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;
608    
609          if (pan > 1000) {          if (pan > 1000) {
# Line 595  namespace LinuxSampler { Line 636  namespace LinuxSampler {
636              // then immediately apply the panning to Note object              // then immediately apply the panning to Note object
637              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
638                  if (relative) {                  if (relative) {
639                      pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);                      pNote->Override.Pan.Value = RTMath::RelativeSummedAvg(pNote->Override.Pan.Value, fPan, ++pNote->Override.Pan.Sources);
640                  } else {                  } else {
641                      pNote->Override.Pan = fPan;                      pNote->Override.Pan.Value = fPan;
642                      pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() calls on same note with 'relative' being set                      pNote->Override.Pan.Sources = 1; // only relevant on subsequent change_pan() calls on same note with 'relative' being set
643                  }                  }
644                    pNote->Override.Pan.Final = isFinal;
645              } else { // otherwise schedule panning change ...              } else { // otherwise schedule panning change ...
646                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
647                  e.Init(); // clear IDs                  e.Init(); // clear IDs
# Line 607  namespace LinuxSampler { Line 649  namespace LinuxSampler {
649                  e.Param.NoteSynthParam.NoteID   = id.noteID();                  e.Param.NoteSynthParam.NoteID   = id.noteID();
650                  e.Param.NoteSynthParam.Type     = Event::synth_param_pan;                  e.Param.NoteSynthParam.Type     = Event::synth_param_pan;
651                  e.Param.NoteSynthParam.Delta    = fPan;                  e.Param.NoteSynthParam.Delta    = fPan;
652                  e.Param.NoteSynthParam.Relative = relative;                  e.Param.NoteSynthParam.Scope = Event::scopeBy_FinalRelativeUnit(
653                        isFinal, relative, false
654                    );
655                  pEngineChannel->ScheduleEventMicroSec(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
656              }              }
657          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
# Line 624  namespace LinuxSampler { Line 667  namespace LinuxSampler {
667                  // then immediately apply the panning to Note object                  // then immediately apply the panning to Note object
668                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
669                      if (relative) {                      if (relative) {
670                          pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);                          pNote->Override.Pan.Value = RTMath::RelativeSummedAvg(pNote->Override.Pan.Value, fPan, ++pNote->Override.Pan.Sources);
671                      } else {                      } else {
672                          pNote->Override.Pan = fPan;                          pNote->Override.Pan.Value = fPan;
673                          pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() calls on same note with 'relative' being set                          pNote->Override.Pan.Sources = 1; // only relevant on subsequent change_pan() calls on same note with 'relative' being set
674                      }                      }
675                        pNote->Override.Pan.Final = isFinal;
676                  } else { // otherwise schedule panning change ...                  } else { // otherwise schedule panning change ...
677                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
678                      e.Init(); // clear IDs                      e.Init(); // clear IDs
# Line 636  namespace LinuxSampler { Line 680  namespace LinuxSampler {
680                      e.Param.NoteSynthParam.NoteID   = id.noteID();                      e.Param.NoteSynthParam.NoteID   = id.noteID();
681                      e.Param.NoteSynthParam.Type     = Event::synth_param_pan;                      e.Param.NoteSynthParam.Type     = Event::synth_param_pan;
682                      e.Param.NoteSynthParam.Delta    = fPan;                      e.Param.NoteSynthParam.Delta    = fPan;
683                      e.Param.NoteSynthParam.Relative = relative;                      e.Param.NoteSynthParam.Scope = Event::scopeBy_FinalRelativeUnit(
684                            isFinal, relative, false
685                        );
686                      pEngineChannel->ScheduleEventMicroSec(&e, 0);                      pEngineChannel->ScheduleEventMicroSec(&e, 0);
687                  }                  }
688              }              }
# Line 647  namespace LinuxSampler { Line 692  namespace LinuxSampler {
692      }      }
693    
694      #define VM_FILTER_PAR_MAX_VALUE 1000000      #define VM_FILTER_PAR_MAX_VALUE 1000000
695        #define VM_FILTER_PAR_MAX_HZ 30000
696      #define VM_EG_PAR_MAX_VALUE 1000000      #define VM_EG_PAR_MAX_VALUE 1000000
697    
698      // change_cutoff() function      // change_cutoff() function
# Line 663  namespace LinuxSampler { Line 709  namespace LinuxSampler {
709              return type == INT_EXPR;              return type == INT_EXPR;
710      }      }
711    
712        bool InstrumentScriptVMFunction_change_cutoff::acceptsArgUnitType(vmint iArg, StdUnit_t type) const {
713            if (iArg == 1)
714                return type == VM_NO_UNIT || type == VM_HERTZ;
715            else
716                return type == VM_NO_UNIT;
717        }
718    
719        bool InstrumentScriptVMFunction_change_cutoff::acceptsArgUnitPrefix(vmint iArg) const {
720            return iArg == 1;
721        }
722    
723        bool InstrumentScriptVMFunction_change_cutoff::acceptsArgFinal(vmint iArg) const {
724            return iArg == 1;
725        }
726    
727      VMFnResult* InstrumentScriptVMFunction_change_cutoff::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_cutoff::exec(VMFnArgs* args) {
728          vmint cutoff = args->arg(1)->asInt()->evalInt();          vmint cutoff   = args->arg(1)->asInt()->evalInt(VM_NO_PREFIX);
729          if (cutoff > VM_FILTER_PAR_MAX_VALUE) {          bool isFinal   = args->arg(1)->asInt()->isFinal();
730              wrnMsg("change_cutoff(): argument 2 may not be larger than 1000000");          StdUnit_t unit = args->arg(1)->asInt()->unitType();
731            if (!unit && cutoff > VM_FILTER_PAR_MAX_VALUE) {
732                wrnMsg("change_cutoff(): argument 2 may not be larger than " strfy(VM_FILTER_PAR_MAX_VALUE));
733              cutoff = VM_FILTER_PAR_MAX_VALUE;              cutoff = VM_FILTER_PAR_MAX_VALUE;
734            } else if (unit && cutoff > VM_FILTER_PAR_MAX_HZ) {
735                wrnMsg("change_cutoff(): argument 2 may not be larger than " strfy(VM_FILTER_PAR_MAX_HZ) " Hz");
736                cutoff = VM_FILTER_PAR_MAX_HZ;
737          } else if (cutoff < 0) {          } else if (cutoff < 0) {
738              wrnMsg("change_cutoff(): argument 2 may not be negative");              wrnMsg("change_cutoff(): argument 2 may not be negative");
739              cutoff = 0;              cutoff = 0;
740          }          }
741          const float fCutoff = float(cutoff) / float(VM_FILTER_PAR_MAX_VALUE);          const float fCutoff =
742                (unit) ? cutoff : float(cutoff) / float(VM_FILTER_PAR_MAX_VALUE);
743    
744            if (unit && !isFinal) {
745                wrnMsg("change_cutoff(): you must pass argument 2 as 'final' value when using Hz as unit");
746                return successResult();
747            }
748    
749          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
750              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
# Line 694  namespace LinuxSampler { Line 766  namespace LinuxSampler {
766              // if change_cutoff() was called immediately after note was triggered              // if change_cutoff() was called immediately after note was triggered
767              // then immediately apply cutoff to Note object              // then immediately apply cutoff to Note object
768              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
769                  pNote->Override.Cutoff = fCutoff;                  pNote->Override.Cutoff.Value = fCutoff;
770                    pNote->Override.Cutoff.Scope = NoteBase::scopeBy_FinalUnit(isFinal, unit);
771              } else { // otherwise schedule cutoff change ...              } else { // otherwise schedule cutoff change ...
772                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
773                  e.Init(); // clear IDs                  e.Init(); // clear IDs
# Line 702  namespace LinuxSampler { Line 775  namespace LinuxSampler {
775                  e.Param.NoteSynthParam.NoteID   = id.noteID();                  e.Param.NoteSynthParam.NoteID   = id.noteID();
776                  e.Param.NoteSynthParam.Type     = Event::synth_param_cutoff;                  e.Param.NoteSynthParam.Type     = Event::synth_param_cutoff;
777                  e.Param.NoteSynthParam.Delta    = fCutoff;                  e.Param.NoteSynthParam.Delta    = fCutoff;
778                  e.Param.NoteSynthParam.Relative = false;                  e.Param.NoteSynthParam.Scope = Event::scopeBy_FinalRelativeUnit(
779                        isFinal, false, unit
780                    );
781                  pEngineChannel->ScheduleEventMicroSec(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
782              }              }
783          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
# Line 718  namespace LinuxSampler { Line 792  namespace LinuxSampler {
792                  // if change_cutoff() was called immediately after note was triggered                  // if change_cutoff() was called immediately after note was triggered
793                  // then immediately apply cutoff to Note object                  // then immediately apply cutoff to Note object
794                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
795                      pNote->Override.Cutoff = fCutoff;                      pNote->Override.Cutoff.Value = fCutoff;
796                        pNote->Override.Cutoff.Scope = NoteBase::scopeBy_FinalUnit(isFinal, unit);
797                  } else { // otherwise schedule cutoff change ...                  } else { // otherwise schedule cutoff change ...
798                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
799                      e.Init(); // clear IDs                      e.Init(); // clear IDs
# Line 726  namespace LinuxSampler { Line 801  namespace LinuxSampler {
801                      e.Param.NoteSynthParam.NoteID   = id.noteID();                      e.Param.NoteSynthParam.NoteID   = id.noteID();
802                      e.Param.NoteSynthParam.Type     = Event::synth_param_cutoff;                      e.Param.NoteSynthParam.Type     = Event::synth_param_cutoff;
803                      e.Param.NoteSynthParam.Delta    = fCutoff;                      e.Param.NoteSynthParam.Delta    = fCutoff;
804                      e.Param.NoteSynthParam.Relative = false;                      e.Param.NoteSynthParam.Scope = Event::scopeBy_FinalRelativeUnit(
805                            isFinal, false, unit
806                        );
807                      pEngineChannel->ScheduleEventMicroSec(&e, 0);                      pEngineChannel->ScheduleEventMicroSec(&e, 0);
808                  }                  }
809              }              }
# Line 750  namespace LinuxSampler { Line 826  namespace LinuxSampler {
826              return type == INT_EXPR;              return type == INT_EXPR;
827      }      }
828    
829        bool InstrumentScriptVMFunction_change_reso::acceptsArgFinal(vmint iArg) const {
830            return iArg == 1;
831        }
832    
833      VMFnResult* InstrumentScriptVMFunction_change_reso::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_reso::exec(VMFnArgs* args) {
834          vmint resonance = args->arg(1)->asInt()->evalInt();          vmint resonance = args->arg(1)->asInt()->evalInt();
835            bool isFinal    = args->arg(1)->asInt()->isFinal();
836          if (resonance > VM_FILTER_PAR_MAX_VALUE) {          if (resonance > VM_FILTER_PAR_MAX_VALUE) {
837              wrnMsg("change_reso(): argument 2 may not be larger than 1000000");              wrnMsg("change_reso(): argument 2 may not be larger than 1000000");
838              resonance = VM_FILTER_PAR_MAX_VALUE;              resonance = VM_FILTER_PAR_MAX_VALUE;
# Line 781  namespace LinuxSampler { Line 862  namespace LinuxSampler {
862              // if change_reso() was called immediately after note was triggered              // if change_reso() was called immediately after note was triggered
863              // then immediately apply resonance to Note object              // then immediately apply resonance to Note object
864              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
865                  pNote->Override.Resonance = fResonance;                  pNote->Override.Resonance.Value = fResonance;
866                    pNote->Override.Resonance.Final = isFinal;
867              } else { // otherwise schedule resonance change ...              } else { // otherwise schedule resonance change ...
868                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
869                  e.Init(); // clear IDs                  e.Init(); // clear IDs
# Line 789  namespace LinuxSampler { Line 871  namespace LinuxSampler {
871                  e.Param.NoteSynthParam.NoteID   = id.noteID();                  e.Param.NoteSynthParam.NoteID   = id.noteID();
872                  e.Param.NoteSynthParam.Type     = Event::synth_param_resonance;                  e.Param.NoteSynthParam.Type     = Event::synth_param_resonance;
873                  e.Param.NoteSynthParam.Delta    = fResonance;                  e.Param.NoteSynthParam.Delta    = fResonance;
874                  e.Param.NoteSynthParam.Relative = false;                  e.Param.NoteSynthParam.Scope = Event::scopeBy_FinalRelativeUnit(
875                        isFinal, false, false
876                    );
877                  pEngineChannel->ScheduleEventMicroSec(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
878              }              }
879          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
# Line 805  namespace LinuxSampler { Line 888  namespace LinuxSampler {
888                  // if change_reso() was called immediately after note was triggered                  // if change_reso() was called immediately after note was triggered
889                  // then immediately apply resonance to Note object                  // then immediately apply resonance to Note object
890                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
891                      pNote->Override.Resonance = fResonance;                      pNote->Override.Resonance.Value = fResonance;
892                        pNote->Override.Resonance.Final = isFinal;
893                  } else { // otherwise schedule resonance change ...                  } else { // otherwise schedule resonance change ...
894                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
895                      e.Init(); // clear IDs                      e.Init(); // clear IDs
# Line 813  namespace LinuxSampler { Line 897  namespace LinuxSampler {
897                      e.Param.NoteSynthParam.NoteID   = id.noteID();                      e.Param.NoteSynthParam.NoteID   = id.noteID();
898                      e.Param.NoteSynthParam.Type     = Event::synth_param_resonance;                      e.Param.NoteSynthParam.Type     = Event::synth_param_resonance;
899                      e.Param.NoteSynthParam.Delta    = fResonance;                      e.Param.NoteSynthParam.Delta    = fResonance;
900                      e.Param.NoteSynthParam.Relative = false;                      e.Param.NoteSynthParam.Scope = Event::scopeBy_FinalRelativeUnit(
901                            isFinal, false, false
902                        );
903                      pEngineChannel->ScheduleEventMicroSec(&e, 0);                      pEngineChannel->ScheduleEventMicroSec(&e, 0);
904                  }                  }
905              }              }
# Line 837  namespace LinuxSampler { Line 922  namespace LinuxSampler {
922              return type == INT_EXPR;              return type == INT_EXPR;
923      }      }
924    
925        bool InstrumentScriptVMFunction_change_attack::acceptsArgUnitType(vmint iArg, StdUnit_t type) const {
926            if (iArg == 1)
927                return type == VM_NO_UNIT || type == VM_SECOND;
928            else
929                return type == VM_NO_UNIT;
930        }
931    
932        bool InstrumentScriptVMFunction_change_attack::acceptsArgUnitPrefix(vmint iArg) const {
933            return iArg == 1;
934        }
935    
936        bool InstrumentScriptVMFunction_change_attack::acceptsArgFinal(vmint iArg) const {
937            return iArg == 1;
938        }
939    
940      VMFnResult* InstrumentScriptVMFunction_change_attack::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_attack::exec(VMFnArgs* args) {
941          vmint attack = args->arg(1)->asInt()->evalInt();          vmint attack   = args->arg(1)->asInt()->evalInt(VM_MICRO);
942            bool isFinal   = args->arg(1)->asInt()->isFinal();
943            StdUnit_t unit = args->arg(1)->asInt()->unitType();
944          // note: intentionally not checking against a max. value here!          // note: intentionally not checking against a max. value here!
945          // (to allow i.e. passing 2000000 for doubling the attack time)          // (to allow i.e. passing 2000000 for doubling the attack time)
946          if (attack < 0) {          if (attack < 0) {
# Line 847  namespace LinuxSampler { Line 949  namespace LinuxSampler {
949          }          }
950          const float fAttack = float(attack) / float(VM_EG_PAR_MAX_VALUE);          const float fAttack = float(attack) / float(VM_EG_PAR_MAX_VALUE);
951    
952            if (unit && !isFinal) {
953                wrnMsg("change_attack(): you must pass argument 2 as 'final' value when using seconds as unit");
954                return successResult();
955            }
956    
957          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
958              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
959    
# Line 867  namespace LinuxSampler { Line 974  namespace LinuxSampler {
974              // if change_attack() was called immediately after note was triggered              // if change_attack() was called immediately after note was triggered
975              // then immediately apply attack to Note object              // then immediately apply attack to Note object
976              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
977                  pNote->Override.Attack = fAttack;                  pNote->Override.Attack.Value = fAttack;
978                    pNote->Override.Attack.Scope = NoteBase::scopeBy_FinalUnit(isFinal, unit);
979              } else { // otherwise schedule attack change ...              } else { // otherwise schedule attack change ...
980                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
981                  e.Init(); // clear IDs                  e.Init(); // clear IDs
# Line 875  namespace LinuxSampler { Line 983  namespace LinuxSampler {
983                  e.Param.NoteSynthParam.NoteID   = id.noteID();                  e.Param.NoteSynthParam.NoteID   = id.noteID();
984                  e.Param.NoteSynthParam.Type     = Event::synth_param_attack;                  e.Param.NoteSynthParam.Type     = Event::synth_param_attack;
985                  e.Param.NoteSynthParam.Delta    = fAttack;                  e.Param.NoteSynthParam.Delta    = fAttack;
986                  e.Param.NoteSynthParam.Relative = false;                  e.Param.NoteSynthParam.Scope = Event::scopeBy_FinalRelativeUnit(
987                        isFinal, false, unit
988                    );
989                  pEngineChannel->ScheduleEventMicroSec(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
990              }              }
991          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
# Line 891  namespace LinuxSampler { Line 1000  namespace LinuxSampler {
1000                  // if change_attack() was called immediately after note was triggered                  // if change_attack() was called immediately after note was triggered
1001                  // then immediately apply attack to Note object                  // then immediately apply attack to Note object
1002                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1003                      pNote->Override.Attack = fAttack;                      pNote->Override.Attack.Value = fAttack;
1004                        pNote->Override.Attack.Scope = NoteBase::scopeBy_FinalUnit(isFinal, unit);
1005                  } else { // otherwise schedule attack change ...                  } else { // otherwise schedule attack change ...
1006                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1007                      e.Init(); // clear IDs                      e.Init(); // clear IDs
# Line 899  namespace LinuxSampler { Line 1009  namespace LinuxSampler {
1009                      e.Param.NoteSynthParam.NoteID   = id.noteID();                      e.Param.NoteSynthParam.NoteID   = id.noteID();
1010                      e.Param.NoteSynthParam.Type     = Event::synth_param_attack;                      e.Param.NoteSynthParam.Type     = Event::synth_param_attack;
1011                      e.Param.NoteSynthParam.Delta    = fAttack;                      e.Param.NoteSynthParam.Delta    = fAttack;
1012                      e.Param.NoteSynthParam.Relative = false;                      e.Param.NoteSynthParam.Scope = Event::scopeBy_FinalRelativeUnit(
1013                            isFinal, false, unit
1014                        );
1015                      pEngineChannel->ScheduleEventMicroSec(&e, 0);                      pEngineChannel->ScheduleEventMicroSec(&e, 0);
1016                  }                  }
1017              }              }
# Line 923  namespace LinuxSampler { Line 1034  namespace LinuxSampler {
1034              return type == INT_EXPR;              return type == INT_EXPR;
1035      }      }
1036    
1037        bool InstrumentScriptVMFunction_change_decay::acceptsArgUnitType(vmint iArg, StdUnit_t type) const {
1038            if (iArg == 1)
1039                return type == VM_NO_UNIT || type == VM_SECOND;
1040            else
1041                return type == VM_NO_UNIT;
1042        }
1043    
1044        bool InstrumentScriptVMFunction_change_decay::acceptsArgUnitPrefix(vmint iArg) const {
1045            return iArg == 1;
1046        }
1047    
1048        bool InstrumentScriptVMFunction_change_decay::acceptsArgFinal(vmint iArg) const {
1049            return iArg == 1;
1050        }
1051    
1052      VMFnResult* InstrumentScriptVMFunction_change_decay::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_decay::exec(VMFnArgs* args) {
1053          vmint decay = args->arg(1)->asInt()->evalInt();          vmint decay    = args->arg(1)->asInt()->evalInt(VM_MICRO);
1054            bool isFinal   = args->arg(1)->asInt()->isFinal();
1055            StdUnit_t unit = args->arg(1)->asInt()->unitType();
1056          // note: intentionally not checking against a max. value here!          // note: intentionally not checking against a max. value here!
1057          // (to allow i.e. passing 2000000 for doubling the decay time)          // (to allow i.e. passing 2000000 for doubling the decay time)
1058          if (decay < 0) {          if (decay < 0) {
# Line 933  namespace LinuxSampler { Line 1061  namespace LinuxSampler {
1061          }          }
1062          const float fDecay = float(decay) / float(VM_EG_PAR_MAX_VALUE);          const float fDecay = float(decay) / float(VM_EG_PAR_MAX_VALUE);
1063    
1064            if (unit && !isFinal) {
1065                wrnMsg("change_decay(): you must pass argument 2 as 'final' value when using seconds as unit");
1066                return successResult();
1067            }
1068    
1069          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
1070              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1071    
# Line 953  namespace LinuxSampler { Line 1086  namespace LinuxSampler {
1086              // if change_decay() was called immediately after note was triggered              // if change_decay() was called immediately after note was triggered
1087              // then immediately apply decay to Note object              // then immediately apply decay to Note object
1088              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1089                  pNote->Override.Decay = fDecay;                  pNote->Override.Decay.Value = fDecay;
1090                    pNote->Override.Decay.Scope = NoteBase::scopeBy_FinalUnit(isFinal, unit);
1091              } else { // otherwise schedule decay change ...              } else { // otherwise schedule decay change ...
1092                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1093                  e.Init(); // clear IDs                  e.Init(); // clear IDs
# Line 961  namespace LinuxSampler { Line 1095  namespace LinuxSampler {
1095                  e.Param.NoteSynthParam.NoteID   = id.noteID();                  e.Param.NoteSynthParam.NoteID   = id.noteID();
1096                  e.Param.NoteSynthParam.Type     = Event::synth_param_decay;                  e.Param.NoteSynthParam.Type     = Event::synth_param_decay;
1097                  e.Param.NoteSynthParam.Delta    = fDecay;                  e.Param.NoteSynthParam.Delta    = fDecay;
1098                  e.Param.NoteSynthParam.Relative = false;                  e.Param.NoteSynthParam.Scope = Event::scopeBy_FinalRelativeUnit(
1099                        isFinal, false, unit
1100                    );
1101                  pEngineChannel->ScheduleEventMicroSec(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
1102              }              }
1103          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
# Line 977  namespace LinuxSampler { Line 1112  namespace LinuxSampler {
1112                  // if change_decay() was called immediately after note was triggered                  // if change_decay() was called immediately after note was triggered
1113                  // then immediately apply decay to Note object                  // then immediately apply decay to Note object
1114                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1115                      pNote->Override.Decay = fDecay;                      pNote->Override.Decay.Value = fDecay;
1116                        pNote->Override.Decay.Scope = NoteBase::scopeBy_FinalUnit(isFinal, unit);
1117                  } else { // otherwise schedule decay change ...                  } else { // otherwise schedule decay change ...
1118                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1119                      e.Init(); // clear IDs                      e.Init(); // clear IDs
# Line 985  namespace LinuxSampler { Line 1121  namespace LinuxSampler {
1121                      e.Param.NoteSynthParam.NoteID   = id.noteID();                      e.Param.NoteSynthParam.NoteID   = id.noteID();
1122                      e.Param.NoteSynthParam.Type     = Event::synth_param_decay;                      e.Param.NoteSynthParam.Type     = Event::synth_param_decay;
1123                      e.Param.NoteSynthParam.Delta    = fDecay;                      e.Param.NoteSynthParam.Delta    = fDecay;
1124                      e.Param.NoteSynthParam.Relative = false;                      e.Param.NoteSynthParam.Scope = Event::scopeBy_FinalRelativeUnit(
1125                            isFinal, false, unit
1126                        );
1127                      pEngineChannel->ScheduleEventMicroSec(&e, 0);                      pEngineChannel->ScheduleEventMicroSec(&e, 0);
1128                  }                  }
1129              }              }
# Line 1009  namespace LinuxSampler { Line 1146  namespace LinuxSampler {
1146              return type == INT_EXPR;              return type == INT_EXPR;
1147      }      }
1148    
1149        bool InstrumentScriptVMFunction_change_release::acceptsArgUnitType(vmint iArg, StdUnit_t type) const {
1150            if (iArg == 1)
1151                return type == VM_NO_UNIT || type == VM_SECOND;
1152            else
1153                return type == VM_NO_UNIT;
1154        }
1155    
1156        bool InstrumentScriptVMFunction_change_release::acceptsArgUnitPrefix(vmint iArg) const {
1157            return iArg == 1;
1158        }
1159    
1160        bool InstrumentScriptVMFunction_change_release::acceptsArgFinal(vmint iArg) const {
1161            return iArg == 1;
1162        }
1163    
1164      VMFnResult* InstrumentScriptVMFunction_change_release::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_release::exec(VMFnArgs* args) {
1165          vmint release = args->arg(1)->asInt()->evalInt();          vmint release  = args->arg(1)->asInt()->evalInt(VM_MICRO);
1166            bool isFinal   = args->arg(1)->asInt()->isFinal();
1167            StdUnit_t unit = args->arg(1)->asInt()->unitType();
1168          // note: intentionally not checking against a max. value here!          // note: intentionally not checking against a max. value here!
1169          // (to allow i.e. passing 2000000 for doubling the release time)          // (to allow i.e. passing 2000000 for doubling the release time)
1170          if (release < 0) {          if (release < 0) {
# Line 1019  namespace LinuxSampler { Line 1173  namespace LinuxSampler {
1173          }          }
1174          const float fRelease = float(release) / float(VM_EG_PAR_MAX_VALUE);          const float fRelease = float(release) / float(VM_EG_PAR_MAX_VALUE);
1175    
1176            if (unit && !isFinal) {
1177                wrnMsg("change_release(): you must pass argument 2 as 'final' value when using seconds as unit");
1178                return successResult();
1179            }
1180    
1181          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
1182              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1183    
# Line 1039  namespace LinuxSampler { Line 1198  namespace LinuxSampler {
1198              // if change_release() was called immediately after note was triggered              // if change_release() was called immediately after note was triggered
1199              // then immediately apply relase to Note object              // then immediately apply relase to Note object
1200              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1201                  pNote->Override.Release = fRelease;                  pNote->Override.Release.Value = fRelease;
1202                    pNote->Override.Release.Scope = NoteBase::scopeBy_FinalUnit(isFinal, unit);
1203              } else { // otherwise schedule release change ...              } else { // otherwise schedule release change ...
1204                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1205                  e.Init(); // clear IDs                  e.Init(); // clear IDs
# Line 1047  namespace LinuxSampler { Line 1207  namespace LinuxSampler {
1207                  e.Param.NoteSynthParam.NoteID   = id.noteID();                  e.Param.NoteSynthParam.NoteID   = id.noteID();
1208                  e.Param.NoteSynthParam.Type     = Event::synth_param_release;                  e.Param.NoteSynthParam.Type     = Event::synth_param_release;
1209                  e.Param.NoteSynthParam.Delta    = fRelease;                  e.Param.NoteSynthParam.Delta    = fRelease;
1210                  e.Param.NoteSynthParam.Relative = false;                  e.Param.NoteSynthParam.Scope = Event::scopeBy_FinalRelativeUnit(
1211                        isFinal, false, unit
1212                    );
1213                  pEngineChannel->ScheduleEventMicroSec(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
1214              }              }
1215          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
# Line 1063  namespace LinuxSampler { Line 1224  namespace LinuxSampler {
1224                  // if change_release() was called immediately after note was triggered                  // if change_release() was called immediately after note was triggered
1225                  // then immediately apply relase to Note object                  // then immediately apply relase to Note object
1226                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1227                      pNote->Override.Release = fRelease;                      pNote->Override.Release.Value = fRelease;
1228                        pNote->Override.Release.Scope = NoteBase::scopeBy_FinalUnit(isFinal, unit);
1229                  } else { // otherwise schedule release change ...                  } else { // otherwise schedule release change ...
1230                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1231                      e.Init(); // clear IDs                      e.Init(); // clear IDs
# Line 1071  namespace LinuxSampler { Line 1233  namespace LinuxSampler {
1233                      e.Param.NoteSynthParam.NoteID   = id.noteID();                      e.Param.NoteSynthParam.NoteID   = id.noteID();
1234                      e.Param.NoteSynthParam.Type     = Event::synth_param_release;                      e.Param.NoteSynthParam.Type     = Event::synth_param_release;
1235                      e.Param.NoteSynthParam.Delta    = fRelease;                      e.Param.NoteSynthParam.Delta    = fRelease;
1236                      e.Param.NoteSynthParam.Relative = false;                      e.Param.NoteSynthParam.Scope = Event::scopeBy_FinalRelativeUnit(
1237                            isFinal, false, unit
1238                        );
1239                      pEngineChannel->ScheduleEventMicroSec(&e, 0);                      pEngineChannel->ScheduleEventMicroSec(&e, 0);
1240                  }                  }
1241              }              }
# Line 1090  namespace LinuxSampler { Line 1253  namespace LinuxSampler {
1253              return type == INT_EXPR;              return type == INT_EXPR;
1254      }      }
1255    
1256        bool VMChangeSynthParamFunction::acceptsArgUnitType(vmint iArg, StdUnit_t type) const {
1257            if (iArg == 1)
1258                return type == VM_NO_UNIT || type == m_unit;
1259            else
1260                return type == VM_NO_UNIT;
1261        }
1262    
1263        bool VMChangeSynthParamFunction::acceptsArgUnitPrefix(vmint iArg) const {
1264            return m_unit && iArg == 1;
1265        }
1266    
1267        bool VMChangeSynthParamFunction::acceptsArgFinal(vmint iArg) const {
1268            return (m_acceptFinal) ? (iArg == 1) : false;
1269        }
1270    
1271        inline static void setNoteParamScopeBy_FinalUnit(NoteBase::Param& param, const bool bFinal, const StdUnit_t unit) {
1272            param.Scope = NoteBase::scopeBy_FinalUnit(bFinal, unit);
1273        }
1274    
1275        inline static void setNoteParamScopeBy_FinalUnit(NoteBase::Norm& param, const bool bFinal, const StdUnit_t unit) {
1276            param.Final = bFinal;
1277        }
1278    
1279        inline static void setNoteParamScopeBy_FinalUnit(float& param, const bool bFinal, const StdUnit_t unit) {
1280            /* NOOP */
1281        }
1282    
1283        template<class T>
1284        inline static void setNoteParamValue(T& param, vmfloat value) {
1285            param.Value = value;
1286        }
1287    
1288        inline static void setNoteParamValue(float& param, vmfloat value) {
1289            param = value;
1290        }
1291    
1292      // Arbitrarily chosen constant value symbolizing "no limit".      // Arbitrarily chosen constant value symbolizing "no limit".
1293      #define NO_LIMIT 1315916909      #define NO_LIMIT 1315916909
1294    
1295      template<float NoteBase::_Override::*T_noteParam, vmint T_synthParam,      template<class T_NoteParamType, T_NoteParamType NoteBase::_Override::*T_noteParam,
1296               bool T_isNormalizedParam, vmint T_maxValue, vmint T_minValue>               vmint T_synthParam,
1297      VMFnResult* VMChangeSynthParamFunction::execTemplate(VMFnArgs* args, const char* functionName) {               vmint T_minValueNorm, vmint T_maxValueNorm, bool T_normalizeNorm,
1298          vmint value = args->arg(1)->asInt()->evalInt();               vmint T_minValueUnit, vmint T_maxValueUnit,
1299          if (T_maxValue != NO_LIMIT && value > T_maxValue) {               MetricPrefix_t T_unitPrefix0, MetricPrefix_t ... T_unitPrefixN>
1300              wrnMsg(String(functionName) + "(): argument 2 may not be larger than " + ToString(T_maxValue));      VMFnResult* VMChangeSynthParamFunction::execTemplate(VMFnArgs* args, const char* functionName)
1301              value = T_maxValue;      {
1302          } else if (T_minValue != NO_LIMIT && value < T_minValue) {          const StdUnit_t unit = args->arg(1)->asInt()->unitType();
1303              if (T_minValue == 0)          const bool isFinal   = args->arg(1)->asInt()->isFinal();
1304                  wrnMsg(String(functionName) + "(): argument 2 may not be negative");          vmint value =
1305              else              (unit & m_unit) ?
1306                  wrnMsg(String(functionName) + "(): argument 2 may not be smaller than " + ToString(T_minValue));                  args->arg(1)->asInt()->evalInt(T_unitPrefix0, T_unitPrefixN ...) :
1307              value = T_minValue;                  args->arg(1)->asInt()->evalInt(VM_NO_PREFIX);
1308          }  
1309          const float fValue = (T_isNormalizedParam) ?          if (unit && !isFinal && m_unit != VM_BEL && m_unit) {
1310              float(value) / float(T_maxValue) : // convert to 0.0 .. 1.0 value range              wrnMsg(String(functionName) + "(): you must pass argument 2 as 'final' value when using a unit");
1311              float(value) / 1000000.f; // assuming microseconds here, convert to seconds              return successResult();
1312            }
1313    
1314            // check if passed value is in allowed range
1315            if (unit && m_unit) {
1316                if (T_maxValueUnit != NO_LIMIT && value > T_maxValueUnit) {
1317                    wrnMsg(String(functionName) + "(): argument 2 may not be larger than " + ToString(T_maxValueUnit));
1318                    value = T_maxValueUnit;
1319                } else if (T_minValueUnit != NO_LIMIT && value < T_minValueUnit) {
1320                    if (T_minValueUnit == 0)
1321                        wrnMsg(String(functionName) + "(): argument 2 may not be negative");
1322                    else
1323                        wrnMsg(String(functionName) + "(): argument 2 may not be smaller than " + ToString(T_minValueUnit));
1324                    value = T_minValueUnit;
1325                }
1326            } else { // value was passed to this function without a unit ...
1327                if (T_maxValueNorm != NO_LIMIT && value > T_maxValueNorm) {
1328                    wrnMsg(String(functionName) + "(): argument 2 may not be larger than " + ToString(T_maxValueNorm));
1329                    value = T_maxValueNorm;
1330                } else if (T_minValueNorm != NO_LIMIT && value < T_minValueNorm) {
1331                    if (T_minValueNorm == 0)
1332                        wrnMsg(String(functionName) + "(): argument 2 may not be negative");
1333                    else
1334                        wrnMsg(String(functionName) + "(): argument 2 may not be smaller than " + ToString(T_minValueNorm));
1335                    value = T_minValueNorm;
1336                }
1337            }
1338    
1339            // convert passed argument value to engine internal expected value range (i.e. 0.0 .. 1.0)
1340            const float fValue =
1341                (unit && m_unit) ?
1342                    (unit == VM_BEL) ?
1343                        RTMath::DecibelToLinRatio(float(value) * float(T_unitPrefix0) /*i.e. mdB -> dB*/) :
1344                        float(value) * VMUnit::unitFactor(T_unitPrefix0, T_unitPrefixN ...) /*i.e. us -> s*/ :
1345                    (T_normalizeNorm) ?
1346                        float(value) / ((T_maxValueNorm != NO_LIMIT) ? float(T_maxValueNorm) : 1000000.f/* fallback: value range used for most */) :
1347                        float(value) /* as is */;
1348    
1349          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
1350              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
# Line 1132  namespace LinuxSampler { Line 1367  namespace LinuxSampler {
1367              // note was triggered then immediately apply the synth parameter              // note was triggered then immediately apply the synth parameter
1368              // change to Note object              // change to Note object
1369              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1370                  pNote->Override.*T_noteParam = fValue;                  setNoteParamValue(pNote->Override.*T_noteParam, fValue);
1371                    setNoteParamScopeBy_FinalUnit(
1372                        (pNote->Override.*T_noteParam),
1373                        isFinal, unit
1374                    );
1375              } else { // otherwise schedule this synth parameter change ...              } else { // otherwise schedule this synth parameter change ...
1376                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1377                  e.Init(); // clear IDs                  e.Init(); // clear IDs
# Line 1140  namespace LinuxSampler { Line 1379  namespace LinuxSampler {
1379                  e.Param.NoteSynthParam.NoteID   = id.noteID();                  e.Param.NoteSynthParam.NoteID   = id.noteID();
1380                  e.Param.NoteSynthParam.Type     = (Event::synth_param_t) T_synthParam;                  e.Param.NoteSynthParam.Type     = (Event::synth_param_t) T_synthParam;
1381                  e.Param.NoteSynthParam.Delta    = fValue;                  e.Param.NoteSynthParam.Delta    = fValue;
1382                  e.Param.NoteSynthParam.Relative = false;                  e.Param.NoteSynthParam.Scope = Event::scopeBy_FinalRelativeUnit(
1383                        isFinal, false, unit
1384                    );
1385                  pEngineChannel->ScheduleEventMicroSec(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
1386              }              }
1387          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
# Line 1157  namespace LinuxSampler { Line 1397  namespace LinuxSampler {
1397                  // note was triggered then immediately apply the synth parameter                  // note was triggered then immediately apply the synth parameter
1398                  // change to Note object                  // change to Note object
1399                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1400                      pNote->Override.*T_noteParam = fValue;                      setNoteParamValue(pNote->Override.*T_noteParam, fValue);
1401                        setNoteParamScopeBy_FinalUnit(
1402                            (pNote->Override.*T_noteParam),
1403                            isFinal, unit
1404                        );
1405                  } else { // otherwise schedule this synth parameter change ...                  } else { // otherwise schedule this synth parameter change ...
1406                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1407                      e.Init(); // clear IDs                      e.Init(); // clear IDs
# Line 1165  namespace LinuxSampler { Line 1409  namespace LinuxSampler {
1409                      e.Param.NoteSynthParam.NoteID   = id.noteID();                      e.Param.NoteSynthParam.NoteID   = id.noteID();
1410                      e.Param.NoteSynthParam.Type     = (Event::synth_param_t) T_synthParam;                      e.Param.NoteSynthParam.Type     = (Event::synth_param_t) T_synthParam;
1411                      e.Param.NoteSynthParam.Delta    = fValue;                      e.Param.NoteSynthParam.Delta    = fValue;
1412                      e.Param.NoteSynthParam.Relative = false;                      e.Param.NoteSynthParam.Scope = Event::scopeBy_FinalRelativeUnit(
1413                            isFinal, false, unit
1414                        );
1415                      pEngineChannel->ScheduleEventMicroSec(&e, 0);                      pEngineChannel->ScheduleEventMicroSec(&e, 0);
1416                  }                  }
1417              }              }
# Line 1179  namespace LinuxSampler { Line 1424  namespace LinuxSampler {
1424    
1425      VMFnResult* InstrumentScriptVMFunction_change_sustain::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_sustain::exec(VMFnArgs* args) {
1426          return VMChangeSynthParamFunction::execTemplate<          return VMChangeSynthParamFunction::execTemplate<
1427                        decltype(NoteBase::_Override::Sustain),
1428                      &NoteBase::_Override::Sustain,                      &NoteBase::_Override::Sustain,
1429                      Event::synth_param_sustain,                      Event::synth_param_sustain,
1430                      false, NO_LIMIT, 0>( args, "change_sustain" );                      /* if value passed without unit */
1431                        0, NO_LIMIT, true,
1432                        /* if value passed WITH 'Bel' unit */
1433                        NO_LIMIT, NO_LIMIT, VM_MILLI, VM_DECI>( args, "change_sustain" );
1434      }      }
1435    
1436      // change_cutoff_attack() function      // change_cutoff_attack() function
1437    
1438      VMFnResult* InstrumentScriptVMFunction_change_cutoff_attack::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_cutoff_attack::exec(VMFnArgs* args) {
1439          return VMChangeSynthParamFunction::execTemplate<          return VMChangeSynthParamFunction::execTemplate<
1440                        decltype(NoteBase::_Override::CutoffAttack),
1441                      &NoteBase::_Override::CutoffAttack,                      &NoteBase::_Override::CutoffAttack,
1442                      Event::synth_param_cutoff_attack,                      Event::synth_param_cutoff_attack,
1443                      false, NO_LIMIT, 0>( args, "change_cutoff_attack" );                      /* if value passed without unit */
1444                        0, NO_LIMIT, true,
1445                        /* if value passed with 'seconds' unit */
1446                        0, NO_LIMIT, VM_MICRO>( args, "change_cutoff_attack" );
1447      }      }
1448    
1449      // change_cutoff_decay() function      // change_cutoff_decay() function
1450    
1451      VMFnResult* InstrumentScriptVMFunction_change_cutoff_decay::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_cutoff_decay::exec(VMFnArgs* args) {
1452          return VMChangeSynthParamFunction::execTemplate<          return VMChangeSynthParamFunction::execTemplate<
1453                        decltype(NoteBase::_Override::CutoffDecay),
1454                      &NoteBase::_Override::CutoffDecay,                      &NoteBase::_Override::CutoffDecay,
1455                      Event::synth_param_cutoff_decay,                      Event::synth_param_cutoff_decay,
1456                      false, NO_LIMIT, 0>( args, "change_cutoff_decay" );                      /* if value passed without unit */
1457                        0, NO_LIMIT, true,
1458                        /* if value passed with 'seconds' unit */
1459                        0, NO_LIMIT, VM_MICRO>( args, "change_cutoff_decay" );
1460      }      }
1461    
1462      // change_cutoff_sustain() function      // change_cutoff_sustain() function
1463    
1464      VMFnResult* InstrumentScriptVMFunction_change_cutoff_sustain::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_cutoff_sustain::exec(VMFnArgs* args) {
1465          return VMChangeSynthParamFunction::execTemplate<          return VMChangeSynthParamFunction::execTemplate<
1466                        decltype(NoteBase::_Override::CutoffSustain),
1467                      &NoteBase::_Override::CutoffSustain,                      &NoteBase::_Override::CutoffSustain,
1468                      Event::synth_param_cutoff_sustain,                      Event::synth_param_cutoff_sustain,
1469                      false, NO_LIMIT, 0>( args, "change_cutoff_sustain" );                      /* if value passed without unit */
1470                        0, NO_LIMIT, true,
1471                        /* if value passed WITH 'Bel' unit */
1472                        NO_LIMIT, NO_LIMIT, VM_MILLI, VM_DECI>( args, "change_cutoff_sustain" );
1473      }      }
1474    
1475      // change_cutoff_release() function      // change_cutoff_release() function
1476    
1477      VMFnResult* InstrumentScriptVMFunction_change_cutoff_release::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_cutoff_release::exec(VMFnArgs* args) {
1478          return VMChangeSynthParamFunction::execTemplate<          return VMChangeSynthParamFunction::execTemplate<
1479                        decltype(NoteBase::_Override::CutoffRelease),
1480                      &NoteBase::_Override::CutoffRelease,                      &NoteBase::_Override::CutoffRelease,
1481                      Event::synth_param_cutoff_release,                      Event::synth_param_cutoff_release,
1482                      false, NO_LIMIT, 0>( args, "change_cutoff_release" );                      /* if value passed without unit */
1483                        0, NO_LIMIT, true,
1484                        /* if value passed with 'seconds' unit */
1485                        0, NO_LIMIT, VM_MICRO>( args, "change_cutoff_release" );
1486      }      }
1487    
1488      // change_amp_lfo_depth() function      // change_amp_lfo_depth() function
1489    
1490      VMFnResult* InstrumentScriptVMFunction_change_amp_lfo_depth::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_amp_lfo_depth::exec(VMFnArgs* args) {
1491          return VMChangeSynthParamFunction::execTemplate<          return VMChangeSynthParamFunction::execTemplate<
1492                        decltype(NoteBase::_Override::AmpLFODepth),
1493                      &NoteBase::_Override::AmpLFODepth,                      &NoteBase::_Override::AmpLFODepth,
1494                      Event::synth_param_amp_lfo_depth,                      Event::synth_param_amp_lfo_depth,
1495                      true, 1000000, 0>( args, "change_amp_lfo_depth" );                      /* if value passed without unit */
1496                        0, 1000000, true,
1497                        /* not used (since this function does not accept unit) */
1498                        NO_LIMIT, NO_LIMIT, VM_NO_PREFIX>( args, "change_amp_lfo_depth" );
1499      }      }
1500    
1501      // change_amp_lfo_freq() function      // change_amp_lfo_freq() function
1502    
1503      VMFnResult* InstrumentScriptVMFunction_change_amp_lfo_freq::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_amp_lfo_freq::exec(VMFnArgs* args) {
1504          return VMChangeSynthParamFunction::execTemplate<          return VMChangeSynthParamFunction::execTemplate<
1505                        decltype(NoteBase::_Override::AmpLFOFreq),
1506                      &NoteBase::_Override::AmpLFOFreq,                      &NoteBase::_Override::AmpLFOFreq,
1507                      Event::synth_param_amp_lfo_freq,                      Event::synth_param_amp_lfo_freq,
1508                      true, 1000000, 0>( args, "change_amp_lfo_freq" );                      /* if value passed without unit */
1509                        0, 1000000, true,
1510                        /* if value passed with 'Hz' unit */
1511                        0, 30000, VM_NO_PREFIX>( args, "change_amp_lfo_freq" );
1512      }      }
1513    
1514      // change_cutoff_lfo_depth() function      // change_cutoff_lfo_depth() function
1515    
1516      VMFnResult* InstrumentScriptVMFunction_change_cutoff_lfo_depth::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_cutoff_lfo_depth::exec(VMFnArgs* args) {
1517          return VMChangeSynthParamFunction::execTemplate<          return VMChangeSynthParamFunction::execTemplate<
1518                        decltype(NoteBase::_Override::CutoffLFODepth),
1519                      &NoteBase::_Override::CutoffLFODepth,                      &NoteBase::_Override::CutoffLFODepth,
1520                      Event::synth_param_cutoff_lfo_depth,                      Event::synth_param_cutoff_lfo_depth,
1521                      true, 1000000, 0>( args, "change_cutoff_lfo_depth" );                      /* if value passed without unit */
1522                        0, 1000000, true,
1523                        /* not used (since this function does not accept unit) */
1524                        NO_LIMIT, NO_LIMIT, VM_NO_PREFIX>( args, "change_cutoff_lfo_depth" );
1525      }      }
1526    
1527      // change_cutoff_lfo_freq() function      // change_cutoff_lfo_freq() function
1528    
1529      VMFnResult* InstrumentScriptVMFunction_change_cutoff_lfo_freq::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_cutoff_lfo_freq::exec(VMFnArgs* args) {
1530          return VMChangeSynthParamFunction::execTemplate<          return VMChangeSynthParamFunction::execTemplate<
1531                        decltype(NoteBase::_Override::CutoffLFOFreq),
1532                      &NoteBase::_Override::CutoffLFOFreq,                      &NoteBase::_Override::CutoffLFOFreq,
1533                      Event::synth_param_cutoff_lfo_freq,                      Event::synth_param_cutoff_lfo_freq,
1534                      true, 1000000, 0>( args, "change_cutoff_lfo_freq" );                      /* if value passed without unit */
1535                        0, 1000000, true,
1536                        /* if value passed with 'Hz' unit */
1537                        0, 30000, VM_NO_PREFIX>( args, "change_cutoff_lfo_freq" );
1538      }      }
1539    
1540      // change_pitch_lfo_depth() function      // change_pitch_lfo_depth() function
1541    
1542      VMFnResult* InstrumentScriptVMFunction_change_pitch_lfo_depth::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_pitch_lfo_depth::exec(VMFnArgs* args) {
1543          return VMChangeSynthParamFunction::execTemplate<          return VMChangeSynthParamFunction::execTemplate<
1544                        decltype(NoteBase::_Override::PitchLFODepth),
1545                      &NoteBase::_Override::PitchLFODepth,                      &NoteBase::_Override::PitchLFODepth,
1546                      Event::synth_param_pitch_lfo_depth,                      Event::synth_param_pitch_lfo_depth,
1547                      true, 1000000, 0>( args, "change_pitch_lfo_depth" );                      /* if value passed without unit */
1548                        0, 1000000, true,
1549                        /* not used (since this function does not accept unit) */
1550                        NO_LIMIT, NO_LIMIT, VM_NO_PREFIX>( args, "change_pitch_lfo_depth" );
1551      }      }
1552    
1553      // change_pitch_lfo_freq() function      // change_pitch_lfo_freq() function
1554    
1555      VMFnResult* InstrumentScriptVMFunction_change_pitch_lfo_freq::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_pitch_lfo_freq::exec(VMFnArgs* args) {
1556          return VMChangeSynthParamFunction::execTemplate<          return VMChangeSynthParamFunction::execTemplate<
1557                        decltype(NoteBase::_Override::PitchLFOFreq),
1558                      &NoteBase::_Override::PitchLFOFreq,                      &NoteBase::_Override::PitchLFOFreq,
1559                      Event::synth_param_pitch_lfo_freq,                      Event::synth_param_pitch_lfo_freq,
1560                      true, 1000000, 0>( args, "change_pitch_lfo_freq" );                      /* if value passed without unit */
1561                        0, 1000000, true,
1562                        /* if value passed with 'Hz' unit */
1563                        0, 30000, VM_NO_PREFIX>( args, "change_pitch_lfo_freq" );
1564      }      }
1565    
1566      // change_vol_time() function      // change_vol_time() function
1567    
1568      VMFnResult* InstrumentScriptVMFunction_change_vol_time::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_vol_time::exec(VMFnArgs* args) {
1569          return VMChangeSynthParamFunction::execTemplate<          return VMChangeSynthParamFunction::execTemplate<
1570                        decltype(NoteBase::_Override::VolumeTime),
1571                      &NoteBase::_Override::VolumeTime,                      &NoteBase::_Override::VolumeTime,
1572                      Event::synth_param_volume_time,                      Event::synth_param_volume_time,
1573                      false, NO_LIMIT, 0>( args, "change_vol_time" );                      /* if value passed without unit (implying 'us' unit) */
1574                        0, NO_LIMIT, true,
1575                        /* if value passed with 'seconds' unit */
1576                        0, NO_LIMIT, VM_MICRO>( args, "change_vol_time" );
1577      }      }
1578    
1579      // change_tune_time() function      // change_tune_time() function
1580    
1581      VMFnResult* InstrumentScriptVMFunction_change_tune_time::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_tune_time::exec(VMFnArgs* args) {
1582          return VMChangeSynthParamFunction::execTemplate<          return VMChangeSynthParamFunction::execTemplate<
1583                        decltype(NoteBase::_Override::PitchTime),
1584                      &NoteBase::_Override::PitchTime,                      &NoteBase::_Override::PitchTime,
1585                      Event::synth_param_pitch_time,                      Event::synth_param_pitch_time,
1586                      false, NO_LIMIT, 0>( args, "change_tune_time" );                      /* if value passed without unit (implying 'us' unit) */
1587                        0, NO_LIMIT, true,
1588                        /* if value passed with 'seconds' unit */
1589                        0, NO_LIMIT, VM_MICRO>( args, "change_tune_time" );
1590      }      }
1591    
1592      // change_pan_time() function      // change_pan_time() function
1593    
1594      VMFnResult* InstrumentScriptVMFunction_change_pan_time::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_pan_time::exec(VMFnArgs* args) {
1595          return VMChangeSynthParamFunction::execTemplate<          return VMChangeSynthParamFunction::execTemplate<
1596          &NoteBase::_Override::PanTime,                      decltype(NoteBase::_Override::PanTime),
1597          Event::synth_param_pan_time,                      &NoteBase::_Override::PanTime,
1598          false, NO_LIMIT, 0>( args, "change_pan_time" );                      Event::synth_param_pan_time,
1599                        /* if value passed without unit (implying 'us' unit) */
1600                        0, NO_LIMIT, true,
1601                        /* if value passed with 'seconds' unit */
1602                        0, NO_LIMIT, VM_MICRO>( args, "change_pan_time" );
1603      }      }
1604    
1605      // template for change_*_curve() functions      // template for change_*_curve() functions
# Line 1351  namespace LinuxSampler { Line 1652  namespace LinuxSampler {
1652                  e.Param.NoteSynthParam.NoteID   = id.noteID();                  e.Param.NoteSynthParam.NoteID   = id.noteID();
1653                  e.Param.NoteSynthParam.Type     = (Event::synth_param_t) T_synthParam;                  e.Param.NoteSynthParam.Type     = (Event::synth_param_t) T_synthParam;
1654                  e.Param.NoteSynthParam.Delta    = value;                  e.Param.NoteSynthParam.Delta    = value;
1655                  e.Param.NoteSynthParam.Relative = false;                  e.Param.NoteSynthParam.Scope = Event::ValueScope::RELATIVE; // actually ignored
1656    
1657                  pEngineChannel->ScheduleEventMicroSec(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
1658              }              }
# Line 1376  namespace LinuxSampler { Line 1677  namespace LinuxSampler {
1677                      e.Param.NoteSynthParam.NoteID   = id.noteID();                      e.Param.NoteSynthParam.NoteID   = id.noteID();
1678                      e.Param.NoteSynthParam.Type     = (Event::synth_param_t) T_synthParam;                      e.Param.NoteSynthParam.Type     = (Event::synth_param_t) T_synthParam;
1679                      e.Param.NoteSynthParam.Delta    = value;                      e.Param.NoteSynthParam.Delta    = value;
1680                      e.Param.NoteSynthParam.Relative = false;                      e.Param.NoteSynthParam.Scope = Event::ValueScope::RELATIVE; // actually ignored
1681    
1682                      pEngineChannel->ScheduleEventMicroSec(&e, 0);                      pEngineChannel->ScheduleEventMicroSec(&e, 0);
1683                  }                  }
# Line 1424  namespace LinuxSampler { Line 1725  namespace LinuxSampler {
1725              return type == INT_EXPR;              return type == INT_EXPR;
1726      }      }
1727    
1728        bool InstrumentScriptVMFunction_fade_in::acceptsArgUnitType(vmint iArg, StdUnit_t type) const {
1729            if (iArg == 1)
1730                return type == VM_NO_UNIT || type == VM_SECOND;
1731            else
1732                return type == VM_NO_UNIT;
1733        }
1734    
1735        bool InstrumentScriptVMFunction_fade_in::acceptsArgUnitPrefix(vmint iArg) const {
1736            return iArg == 1;
1737        }
1738    
1739      VMFnResult* InstrumentScriptVMFunction_fade_in::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_fade_in::exec(VMFnArgs* args) {
1740          vmint duration = args->arg(1)->asInt()->evalInt();          vmint duration = args->arg(1)->asInt()->evalInt(VM_MICRO);
1741          if (duration < 0) {          if (duration < 0) {
1742              wrnMsg("fade_in(): argument 2 may not be negative");              wrnMsg("fade_in(): argument 2 may not be negative");
1743              duration = 0;              duration = 0;
# Line 1453  namespace LinuxSampler { Line 1765  namespace LinuxSampler {
1765              // then immediately apply a start volume of zero to Note object,              // then immediately apply a start volume of zero to Note object,
1766              // as well as the fade in duration              // as well as the fade in duration
1767              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1768                  pNote->Override.Volume = 0.f;                  pNote->Override.Volume.Value = 0.f;
1769                  pNote->Override.VolumeTime = fDuration;                  pNote->Override.VolumeTime = fDuration;
1770              } else { // otherwise schedule a "volume time" change with the requested fade in duration ...              } else { // otherwise schedule a "volume time" change with the requested fade in duration ...
1771                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
# Line 1462  namespace LinuxSampler { Line 1774  namespace LinuxSampler {
1774                  e.Param.NoteSynthParam.NoteID   = id.noteID();                  e.Param.NoteSynthParam.NoteID   = id.noteID();
1775                  e.Param.NoteSynthParam.Type     = Event::synth_param_volume_time;                  e.Param.NoteSynthParam.Type     = Event::synth_param_volume_time;
1776                  e.Param.NoteSynthParam.Delta    = fDuration;                  e.Param.NoteSynthParam.Delta    = fDuration;
1777                  e.Param.NoteSynthParam.Relative = false;                  e.Param.NoteSynthParam.Scope = Event::ValueScope::RELATIVE; // actually ignored
1778    
1779                  pEngineChannel->ScheduleEventMicroSec(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
1780              }              }
# Line 1475  namespace LinuxSampler { Line 1787  namespace LinuxSampler {
1787                  e.Param.NoteSynthParam.NoteID   = id.noteID();                  e.Param.NoteSynthParam.NoteID   = id.noteID();
1788                  e.Param.NoteSynthParam.Type     = Event::synth_param_volume;                  e.Param.NoteSynthParam.Type     = Event::synth_param_volume;
1789                  e.Param.NoteSynthParam.Delta    = 1.f;                  e.Param.NoteSynthParam.Delta    = 1.f;
1790                  e.Param.NoteSynthParam.Relative = false;                  e.Param.NoteSynthParam.Scope = Event::ValueScope::RELATIVE; // actually ignored
1791    
1792                  // scheduling with 0 delay would also work here, but +1 is more                  // scheduling with 0 delay would also work here, but +1 is more
1793                  // safe regarding potential future implementation changes of the                  // safe regarding potential future implementation changes of the
# Line 1495  namespace LinuxSampler { Line 1807  namespace LinuxSampler {
1807                  // then immediately apply a start volume of zero to Note object,                  // then immediately apply a start volume of zero to Note object,
1808                  // as well as the fade in duration                  // as well as the fade in duration
1809                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1810                      pNote->Override.Volume = 0.f;                      pNote->Override.Volume.Value = 0.f;
1811                      pNote->Override.VolumeTime = fDuration;                      pNote->Override.VolumeTime = fDuration;
1812                  } else { // otherwise schedule a "volume time" change with the requested fade in duration ...                  } else { // otherwise schedule a "volume time" change with the requested fade in duration ...
1813                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
# Line 1504  namespace LinuxSampler { Line 1816  namespace LinuxSampler {
1816                      e.Param.NoteSynthParam.NoteID   = id.noteID();                      e.Param.NoteSynthParam.NoteID   = id.noteID();
1817                      e.Param.NoteSynthParam.Type     = Event::synth_param_volume_time;                      e.Param.NoteSynthParam.Type     = Event::synth_param_volume_time;
1818                      e.Param.NoteSynthParam.Delta    = fDuration;                      e.Param.NoteSynthParam.Delta    = fDuration;
1819                      e.Param.NoteSynthParam.Relative = false;                      e.Param.NoteSynthParam.Scope = Event::ValueScope::RELATIVE; // actually ignored
1820    
1821                      pEngineChannel->ScheduleEventMicroSec(&e, 0);                      pEngineChannel->ScheduleEventMicroSec(&e, 0);
1822                  }                  }
# Line 1517  namespace LinuxSampler { Line 1829  namespace LinuxSampler {
1829                      e.Param.NoteSynthParam.NoteID   = id.noteID();                      e.Param.NoteSynthParam.NoteID   = id.noteID();
1830                      e.Param.NoteSynthParam.Type     = Event::synth_param_volume;                      e.Param.NoteSynthParam.Type     = Event::synth_param_volume;
1831                      e.Param.NoteSynthParam.Delta    = 1.f;                      e.Param.NoteSynthParam.Delta    = 1.f;
1832                      e.Param.NoteSynthParam.Relative = false;                      e.Param.NoteSynthParam.Scope = Event::ValueScope::RELATIVE; // actually ignored
1833    
1834                      // scheduling with 0 delay would also work here, but +1 is more                      // scheduling with 0 delay would also work here, but +1 is more
1835                      // safe regarding potential future implementation changes of the                      // safe regarding potential future implementation changes of the
# Line 1544  namespace LinuxSampler { Line 1856  namespace LinuxSampler {
1856              return type == INT_EXPR;              return type == INT_EXPR;
1857      }      }
1858    
1859        bool InstrumentScriptVMFunction_fade_out::acceptsArgUnitType(vmint iArg, StdUnit_t type) const {
1860            if (iArg == 1)
1861                return type == VM_NO_UNIT || type == VM_SECOND;
1862            else
1863                return type == VM_NO_UNIT;
1864        }
1865    
1866        bool InstrumentScriptVMFunction_fade_out::acceptsArgUnitPrefix(vmint iArg) const {
1867            return iArg == 1;
1868        }
1869    
1870      VMFnResult* InstrumentScriptVMFunction_fade_out::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_fade_out::exec(VMFnArgs* args) {
1871          vmint duration = args->arg(1)->asInt()->evalInt();          vmint duration = args->arg(1)->asInt()->evalInt(VM_MICRO);
1872          if (duration < 0) {          if (duration < 0) {
1873              wrnMsg("fade_out(): argument 2 may not be negative");              wrnMsg("fade_out(): argument 2 may not be negative");
1874              duration = 0;              duration = 0;
# Line 1582  namespace LinuxSampler { Line 1905  namespace LinuxSampler {
1905                  e.Param.NoteSynthParam.NoteID   = id.noteID();                  e.Param.NoteSynthParam.NoteID   = id.noteID();
1906                  e.Param.NoteSynthParam.Type     = Event::synth_param_volume_time;                  e.Param.NoteSynthParam.Type     = Event::synth_param_volume_time;
1907                  e.Param.NoteSynthParam.Delta    = fDuration;                  e.Param.NoteSynthParam.Delta    = fDuration;
1908                  e.Param.NoteSynthParam.Relative = false;                  e.Param.NoteSynthParam.Scope = Event::ValueScope::RELATIVE; // actually ignored
1909    
1910                  pEngineChannel->ScheduleEventMicroSec(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
1911              }              }
# Line 1595  namespace LinuxSampler { Line 1918  namespace LinuxSampler {
1918                  e.Param.NoteSynthParam.NoteID   = id.noteID();                  e.Param.NoteSynthParam.NoteID   = id.noteID();
1919                  e.Param.NoteSynthParam.Type     = Event::synth_param_volume;                  e.Param.NoteSynthParam.Type     = Event::synth_param_volume;
1920                  e.Param.NoteSynthParam.Delta    = 0.f;                  e.Param.NoteSynthParam.Delta    = 0.f;
1921                  e.Param.NoteSynthParam.Relative = false;                  e.Param.NoteSynthParam.Scope = Event::ValueScope::RELATIVE; // actually ignored
1922    
1923                  // scheduling with 0 delay would also work here, but +1 is more                  // scheduling with 0 delay would also work here, but +1 is more
1924                  // safe regarding potential future implementation changes of the                  // safe regarding potential future implementation changes of the
# Line 1634  namespace LinuxSampler { Line 1957  namespace LinuxSampler {
1957                      e.Param.NoteSynthParam.NoteID   = id.noteID();                      e.Param.NoteSynthParam.NoteID   = id.noteID();
1958                      e.Param.NoteSynthParam.Type     = Event::synth_param_volume_time;                      e.Param.NoteSynthParam.Type     = Event::synth_param_volume_time;
1959                      e.Param.NoteSynthParam.Delta    = fDuration;                      e.Param.NoteSynthParam.Delta    = fDuration;
1960                      e.Param.NoteSynthParam.Relative = false;                      e.Param.NoteSynthParam.Scope = Event::ValueScope::RELATIVE; // actually ignored
1961    
1962                      pEngineChannel->ScheduleEventMicroSec(&e, 0);                      pEngineChannel->ScheduleEventMicroSec(&e, 0);
1963                  }                  }
# Line 1647  namespace LinuxSampler { Line 1970  namespace LinuxSampler {
1970                      e.Param.NoteSynthParam.NoteID   = id.noteID();                      e.Param.NoteSynthParam.NoteID   = id.noteID();
1971                      e.Param.NoteSynthParam.Type     = Event::synth_param_volume;                      e.Param.NoteSynthParam.Type     = Event::synth_param_volume;
1972                      e.Param.NoteSynthParam.Delta    = 0.f;                      e.Param.NoteSynthParam.Delta    = 0.f;
1973                      e.Param.NoteSynthParam.Relative = false;                      e.Param.NoteSynthParam.Scope = Event::ValueScope::RELATIVE; // actually ignored
1974    
1975                      // scheduling with 0 delay would also work here, but +1 is more                      // scheduling with 0 delay would also work here, but +1 is more
1976                      // safe regarding potential future implementation changes of the                      // safe regarding potential future implementation changes of the
# Line 1707  namespace LinuxSampler { Line 2030  namespace LinuxSampler {
2030                  return successResult(pNote->cause.Param.Note.Velocity);                  return successResult(pNote->cause.Param.Note.Velocity);
2031              case EVENT_PAR_VOLUME:              case EVENT_PAR_VOLUME:
2032                  return successResult(                  return successResult(
2033                      RTMath::LinRatioToDecibel(pNote->Override.Volume) * 1000.f                      RTMath::LinRatioToDecibel(pNote->Override.Volume.Value) * 1000.f
2034                  );                  );
2035              case EVENT_PAR_TUNE:              case EVENT_PAR_TUNE:
2036                  return successResult(                  return successResult(
2037                       RTMath::FreqRatioToCents(pNote->Override.Pitch) * 1000.f                       RTMath::FreqRatioToCents(pNote->Override.Pitch.Value) * 1000.f
2038                  );                  );
2039              case EVENT_PAR_0:              case EVENT_PAR_0:
2040                  return successResult(pNote->userPar[0]);                  return successResult(pNote->userPar[0]);
# Line 1890  namespace LinuxSampler { Line 2213  namespace LinuxSampler {
2213      {      {
2214      }      }
2215    
2216        bool InstrumentScriptVMFunction_change_play_pos::acceptsArgUnitType(vmint iArg, StdUnit_t type) const {
2217            if (iArg == 1)
2218                return type == VM_NO_UNIT || type == VM_SECOND;
2219            else
2220                return type == VM_NO_UNIT;
2221        }
2222    
2223        bool InstrumentScriptVMFunction_change_play_pos::acceptsArgUnitPrefix(vmint iArg) const {
2224            return iArg == 1;
2225        }
2226    
2227      VMFnResult* InstrumentScriptVMFunction_change_play_pos::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_play_pos::exec(VMFnArgs* args) {
2228          const ScriptID id = args->arg(0)->asInt()->evalInt();          const ScriptID id = args->arg(0)->asInt()->evalInt(VM_MICRO);
2229          if (!id) {          if (!id) {
2230              wrnMsg("change_play_pos(): note ID for argument 1 may not be zero");              wrnMsg("change_play_pos(): note ID for argument 1 may not be zero");
2231              return successResult();              return successResult();

Legend:
Removed from v.3557  
changed lines
  Added in v.3561

  ViewVC Help
Powered by ViewVC