/[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 2962 by schoenebeck, Sun Jul 17 17:54:04 2016 UTC revision 3246 by schoenebeck, Sun May 28 22:22:56 2017 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (c) 2014-2016 Christian Schoenebeck   * Copyright (c) 2014-2017 Christian Schoenebeck
3   *   *
4   * http://www.linuxsampler.org   * http://www.linuxsampler.org
5   *   *
# Line 136  namespace LinuxSampler { Line 136  namespace LinuxSampler {
136          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
137                  static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);                  static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
138    
139          if (args->arg(0)->exprType() == INT_EXPR) {          if (args->argsCount() == 0 || args->arg(0)->exprType() == INT_EXPR) {
140              const ScriptID id = args->arg(0)->asInt()->evalInt();              const ScriptID id = (args->argsCount() >= 1) ? args->arg(0)->asInt()->evalInt() : m_vm->m_event->id;
141              if (!id) {              if (!id && args->argsCount() >= 1) {
142                  wrnMsg("ignore_event(): event ID argument may not be zero");                  wrnMsg("ignore_event(): event ID argument may not be zero");
143                  // not errorResult(), because that would abort the script, not intentional in this case                  // not errorResult(), because that would abort the script, not intentional in this case
144                  return successResult();                  return successResult();
# Line 359  namespace LinuxSampler { Line 359  namespace LinuxSampler {
359          if (iArg == 0)          if (iArg == 0)
360              return type == INT_EXPR || type == INT_ARR_EXPR;              return type == INT_EXPR || type == INT_ARR_EXPR;
361          else          else
362              return INT_EXPR;              return type == INT_EXPR;
363      }      }
364    
365      VMFnResult* InstrumentScriptVMFunction_change_vol::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_vol::exec(VMFnArgs* args) {
# Line 385  namespace LinuxSampler { Line 385  namespace LinuxSampler {
385              if (!pNote) return successResult();              if (!pNote) return successResult();
386    
387              // if change_vol() was called immediately after note was triggered              // if change_vol() was called immediately after note was triggered
388              // then immediately apply the volume to note object              // then immediately apply the volume to note object, but only if
389              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              // change_vol_time() has not been called before
390                if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime &&
391                    pNote->Override.VolumeTime <= DEFAULT_NOTE_VOLUME_TIME_S)
392                {
393                  if (relative)                  if (relative)
394                      pNote->Override.Volume *= fVolumeLin;                      pNote->Override.Volume *= fVolumeLin;
395                  else                  else
# Line 412  namespace LinuxSampler { Line 415  namespace LinuxSampler {
415                  if (!pNote) continue;                  if (!pNote) continue;
416    
417                  // if change_vol() was called immediately after note was triggered                  // if change_vol() was called immediately after note was triggered
418                  // then immediately apply the volume to Note object                  // then immediately apply the volume to Note object, but only if
419                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  // change_vol_time() has not been called before
420                    if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime &&
421                        pNote->Override.VolumeTime <= DEFAULT_NOTE_VOLUME_TIME_S)
422                    {
423                      if (relative)                      if (relative)
424                          pNote->Override.Volume *= fVolumeLin;                          pNote->Override.Volume *= fVolumeLin;
425                      else                      else
# Line 446  namespace LinuxSampler { Line 452  namespace LinuxSampler {
452          if (iArg == 0)          if (iArg == 0)
453              return type == INT_EXPR || type == INT_ARR_EXPR;              return type == INT_EXPR || type == INT_ARR_EXPR;
454          else          else
455              return INT_EXPR;              return type == INT_EXPR;
456      }      }
457    
458      VMFnResult* InstrumentScriptVMFunction_change_tune::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_tune::exec(VMFnArgs* args) {
# Line 472  namespace LinuxSampler { Line 478  namespace LinuxSampler {
478              if (!pNote) return successResult();              if (!pNote) return successResult();
479    
480              // if change_tune() was called immediately after note was triggered              // if change_tune() was called immediately after note was triggered
481              // then immediately apply the tuning to Note object              // then immediately apply the tuning to Note object, but only if
482              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              // change_tune_time() has not been called before
483                if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime &&
484                    pNote->Override.PitchTime <= DEFAULT_NOTE_PITCH_TIME_S)
485                {
486                  if (relative)                  if (relative)
487                      pNote->Override.Pitch *= fFreqRatio;                      pNote->Override.Pitch *= fFreqRatio;
488                  else                  else
# Line 499  namespace LinuxSampler { Line 508  namespace LinuxSampler {
508                  if (!pNote) continue;                  if (!pNote) continue;
509    
510                  // if change_tune() was called immediately after note was triggered                  // if change_tune() was called immediately after note was triggered
511                  // then immediately apply the tuning to Note object                  // then immediately apply the tuning to Note object, but only if
512                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  // change_tune_time() has not been called before
513                    if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime &&
514                        pNote->Override.PitchTime <= DEFAULT_NOTE_PITCH_TIME_S)
515                    {
516                      if (relative)                      if (relative)
517                          pNote->Override.Pitch *= fFreqRatio;                          pNote->Override.Pitch *= fFreqRatio;
518                      else                      else
# Line 533  namespace LinuxSampler { Line 545  namespace LinuxSampler {
545          if (iArg == 0)          if (iArg == 0)
546              return type == INT_EXPR || type == INT_ARR_EXPR;              return type == INT_EXPR || type == INT_ARR_EXPR;
547          else          else
548              return INT_EXPR;              return type == INT_EXPR;
549      }      }
550    
551      VMFnResult* InstrumentScriptVMFunction_change_pan::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_pan::exec(VMFnArgs* args) {
# Line 568  namespace LinuxSampler { Line 580  namespace LinuxSampler {
580    
581              // if change_pan() was called immediately after note was triggered              // if change_pan() was called immediately after note was triggered
582              // then immediately apply the panning to Note object              // then immediately apply the panning to Note object
583              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
584                  if (relative) {                  if (relative) {
585                      pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);                      pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);
586                  } else {                  } else {
# Line 597  namespace LinuxSampler { Line 609  namespace LinuxSampler {
609    
610                  // if change_pan() was called immediately after note was triggered                  // if change_pan() was called immediately after note was triggered
611                  // then immediately apply the panning to Note object                  // then immediately apply the panning to Note object
612                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
613                      if (relative) {                      if (relative) {
614                          pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);                          pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);
615                      } else {                      } else {
# Line 635  namespace LinuxSampler { Line 647  namespace LinuxSampler {
647          if (iArg == 0)          if (iArg == 0)
648              return type == INT_EXPR || type == INT_ARR_EXPR;              return type == INT_EXPR || type == INT_ARR_EXPR;
649          else          else
650              return INT_EXPR;              return type == INT_EXPR;
651      }      }
652    
653      VMFnResult* InstrumentScriptVMFunction_change_cutoff::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_cutoff::exec(VMFnArgs* args) {
# Line 668  namespace LinuxSampler { Line 680  namespace LinuxSampler {
680    
681              // if change_cutoff() was called immediately after note was triggered              // if change_cutoff() was called immediately after note was triggered
682              // then immediately apply cutoff to Note object              // then immediately apply cutoff to Note object
683              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
684                  pNote->Override.Cutoff = fCutoff;                  pNote->Override.Cutoff = fCutoff;
685              } else { // otherwise schedule cutoff change ...              } else { // otherwise schedule cutoff change ...
686                  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 692  namespace LinuxSampler { Line 704  namespace LinuxSampler {
704    
705                  // if change_cutoff() was called immediately after note was triggered                  // if change_cutoff() was called immediately after note was triggered
706                  // then immediately apply cutoff to Note object                  // then immediately apply cutoff to Note object
707                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
708                      pNote->Override.Cutoff = fCutoff;                      pNote->Override.Cutoff = fCutoff;
709                  } else { // otherwise schedule cutoff change ...                  } else { // otherwise schedule cutoff change ...
710                      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 722  namespace LinuxSampler { Line 734  namespace LinuxSampler {
734          if (iArg == 0)          if (iArg == 0)
735              return type == INT_EXPR || type == INT_ARR_EXPR;              return type == INT_EXPR || type == INT_ARR_EXPR;
736          else          else
737              return INT_EXPR;              return type == INT_EXPR;
738      }      }
739    
740      VMFnResult* InstrumentScriptVMFunction_change_reso::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_reso::exec(VMFnArgs* args) {
# Line 755  namespace LinuxSampler { Line 767  namespace LinuxSampler {
767    
768              // if change_reso() was called immediately after note was triggered              // if change_reso() was called immediately after note was triggered
769              // then immediately apply resonance to Note object              // then immediately apply resonance to Note object
770              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
771                  pNote->Override.Resonance = fResonance;                  pNote->Override.Resonance = fResonance;
772              } else { // otherwise schedule resonance change ...              } else { // otherwise schedule resonance change ...
773                  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 779  namespace LinuxSampler { Line 791  namespace LinuxSampler {
791    
792                  // if change_reso() was called immediately after note was triggered                  // if change_reso() was called immediately after note was triggered
793                  // then immediately apply resonance to Note object                  // then immediately apply resonance to Note object
794                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
795                      pNote->Override.Resonance = fResonance;                      pNote->Override.Resonance = fResonance;
796                  } else { // otherwise schedule resonance change ...                  } else { // otherwise schedule resonance change ...
797                      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 809  namespace LinuxSampler { Line 821  namespace LinuxSampler {
821          if (iArg == 0)          if (iArg == 0)
822              return type == INT_EXPR || type == INT_ARR_EXPR;              return type == INT_EXPR || type == INT_ARR_EXPR;
823          else          else
824              return INT_EXPR;              return type == INT_EXPR;
825      }      }
826    
827      VMFnResult* InstrumentScriptVMFunction_change_attack::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_attack::exec(VMFnArgs* args) {
# Line 842  namespace LinuxSampler { Line 854  namespace LinuxSampler {
854    
855              // if change_attack() was called immediately after note was triggered              // if change_attack() was called immediately after note was triggered
856              // then immediately apply attack to Note object              // then immediately apply attack to Note object
857              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
858                  pNote->Override.Attack = fAttack;                  pNote->Override.Attack = fAttack;
859              } else { // otherwise schedule attack change ...              } else { // otherwise schedule attack change ...
860                  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 866  namespace LinuxSampler { Line 878  namespace LinuxSampler {
878    
879                  // if change_attack() was called immediately after note was triggered                  // if change_attack() was called immediately after note was triggered
880                  // then immediately apply attack to Note object                  // then immediately apply attack to Note object
881                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
882                      pNote->Override.Attack = fAttack;                      pNote->Override.Attack = fAttack;
883                  } else { // otherwise schedule attack change ...                  } else { // otherwise schedule attack change ...
884                      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 896  namespace LinuxSampler { Line 908  namespace LinuxSampler {
908          if (iArg == 0)          if (iArg == 0)
909              return type == INT_EXPR || type == INT_ARR_EXPR;              return type == INT_EXPR || type == INT_ARR_EXPR;
910          else          else
911              return INT_EXPR;              return type == INT_EXPR;
912      }      }
913    
914      VMFnResult* InstrumentScriptVMFunction_change_decay::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_decay::exec(VMFnArgs* args) {
# Line 929  namespace LinuxSampler { Line 941  namespace LinuxSampler {
941    
942              // if change_decay() was called immediately after note was triggered              // if change_decay() was called immediately after note was triggered
943              // then immediately apply decay to Note object              // then immediately apply decay to Note object
944              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
945                  pNote->Override.Decay = fDecay;                  pNote->Override.Decay = fDecay;
946              } else { // otherwise schedule decay change ...              } else { // otherwise schedule decay change ...
947                  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 953  namespace LinuxSampler { Line 965  namespace LinuxSampler {
965    
966                  // if change_decay() was called immediately after note was triggered                  // if change_decay() was called immediately after note was triggered
967                  // then immediately apply decay to Note object                  // then immediately apply decay to Note object
968                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
969                      pNote->Override.Decay = fDecay;                      pNote->Override.Decay = fDecay;
970                  } else { // otherwise schedule decay change ...                  } else { // otherwise schedule decay change ...
971                      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 983  namespace LinuxSampler { Line 995  namespace LinuxSampler {
995          if (iArg == 0)          if (iArg == 0)
996              return type == INT_EXPR || type == INT_ARR_EXPR;              return type == INT_EXPR || type == INT_ARR_EXPR;
997          else          else
998              return INT_EXPR;              return type == INT_EXPR;
999      }      }
1000    
1001      VMFnResult* InstrumentScriptVMFunction_change_release::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_release::exec(VMFnArgs* args) {
# Line 1016  namespace LinuxSampler { Line 1028  namespace LinuxSampler {
1028    
1029              // if change_release() was called immediately after note was triggered              // if change_release() was called immediately after note was triggered
1030              // then immediately apply relase to Note object              // then immediately apply relase to Note object
1031              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1032                  pNote->Override.Release = fRelease;                  pNote->Override.Release = fRelease;
1033              } else { // otherwise schedule release change ...              } else { // otherwise schedule release change ...
1034                  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 1040  namespace LinuxSampler { Line 1052  namespace LinuxSampler {
1052    
1053                  // if change_release() was called immediately after note was triggered                  // if change_release() was called immediately after note was triggered
1054                  // then immediately apply relase to Note object                  // then immediately apply relase to Note object
1055                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1056                      pNote->Override.Release = fRelease;                      pNote->Override.Release = fRelease;
1057                  } else { // otherwise schedule release change ...                  } else { // otherwise schedule release change ...
1058                      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 1059  namespace LinuxSampler { Line 1071  namespace LinuxSampler {
1071          return successResult();          return successResult();
1072      }      }
1073    
1074        // template for change_*() functions
1075    
1076        bool VMChangeSynthParamFunction::acceptsArgType(int iArg, ExprType_t type) const {
1077            if (iArg == 0)
1078                return type == INT_EXPR || type == INT_ARR_EXPR;
1079            else
1080                return type == INT_EXPR;
1081        }
1082    
1083        // Arbitrarily chosen constant value symbolizing "no limit".
1084        #define NO_LIMIT 1315916909
1085    
1086        template<float NoteBase::_Override::*T_noteParam, int T_synthParam,
1087                 bool T_isNormalizedParam, int T_maxValue, int T_minValue>
1088        VMFnResult* VMChangeSynthParamFunction::execTemplate(VMFnArgs* args, const char* functionName) {
1089            int value = args->arg(1)->asInt()->evalInt();
1090            if (T_maxValue != NO_LIMIT && value > T_maxValue) {
1091                wrnMsg(String(functionName) + "(): argument 2 may not be larger than " + ToString(T_maxValue));
1092                value = T_maxValue;
1093            } else if (T_minValue != NO_LIMIT && value < T_minValue) {
1094                if (T_minValue == 0)
1095                    wrnMsg(String(functionName) + "(): argument 2 may not be negative");
1096                else
1097                    wrnMsg(String(functionName) + "(): argument 2 may not be smaller than " + ToString(T_minValue));
1098                value = T_minValue;
1099            }
1100            const float fValue = (T_isNormalizedParam) ?
1101                float(value) / float(T_maxValue) : // convert to 0.0 .. 1.0 value range
1102                float(value) / 1000000.f; // assuming microseconds here, convert to seconds
1103    
1104            AbstractEngineChannel* pEngineChannel =
1105                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1106    
1107            if (args->arg(0)->exprType() == INT_EXPR) {
1108                const ScriptID id = args->arg(0)->asInt()->evalInt();
1109                if (!id) {
1110                    wrnMsg(String(functionName) + "(): note ID for argument 1 may not be zero");
1111                    return successResult();
1112                }
1113                if (!id.isNoteID()) {
1114                    wrnMsg(String(functionName) + "(): argument 1 is not a note ID");
1115                    return successResult();
1116                }
1117    
1118                NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1119                if (!pNote) return successResult();
1120    
1121                // if this change_*() script function was called immediately after
1122                // note was triggered then immediately apply the synth parameter
1123                // change to Note object
1124                if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1125                    pNote->Override.*T_noteParam = fValue;
1126                } else { // otherwise schedule this synth parameter change ...
1127                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1128                    e.Init(); // clear IDs
1129                    e.Type = Event::type_note_synth_param;
1130                    e.Param.NoteSynthParam.NoteID   = id.noteID();
1131                    e.Param.NoteSynthParam.Type     = (Event::synth_param_t) T_synthParam;
1132                    e.Param.NoteSynthParam.Delta    = fValue;
1133                    e.Param.NoteSynthParam.Relative = false;
1134    
1135                    pEngineChannel->ScheduleEventMicroSec(&e, 0);
1136                }
1137            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
1138                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
1139                for (int i = 0; i < ids->arraySize(); ++i) {
1140                    const ScriptID id = ids->evalIntElement(i);
1141                    if (!id || !id.isNoteID()) continue;
1142    
1143                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1144                    if (!pNote) continue;
1145    
1146                    // if this change_*() script function was called immediately after
1147                    // note was triggered then immediately apply the synth parameter
1148                    // change to Note object
1149                    if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1150                        pNote->Override.*T_noteParam = fValue;
1151                    } else { // otherwise schedule this synth parameter change ...
1152                        Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1153                        e.Init(); // clear IDs
1154                        e.Type = Event::type_note_synth_param;
1155                        e.Param.NoteSynthParam.NoteID   = id.noteID();
1156                        e.Param.NoteSynthParam.Type     = (Event::synth_param_t) T_synthParam;
1157                        e.Param.NoteSynthParam.Delta    = fValue;
1158                        e.Param.NoteSynthParam.Relative = false;
1159    
1160                        pEngineChannel->ScheduleEventMicroSec(&e, 0);
1161                    }
1162                }
1163            }
1164    
1165            return successResult();
1166        }
1167    
1168        // change_amp_lfo_depth() function
1169    
1170        VMFnResult* InstrumentScriptVMFunction_change_amp_lfo_depth::exec(VMFnArgs* args) {
1171            return VMChangeSynthParamFunction::execTemplate<
1172                        &NoteBase::_Override::AmpLFODepth,
1173                        Event::synth_param_amp_lfo_depth,
1174                        true, 1000000, 0>( args, "change_amp_lfo_depth" );
1175        }
1176    
1177        // change_amp_lfo_freq() function
1178    
1179        VMFnResult* InstrumentScriptVMFunction_change_amp_lfo_freq::exec(VMFnArgs* args) {
1180            return VMChangeSynthParamFunction::execTemplate<
1181                        &NoteBase::_Override::AmpLFOFreq,
1182                        Event::synth_param_amp_lfo_freq,
1183                        true, 1000000, 0>( args, "change_amp_lfo_freq" );
1184        }
1185    
1186        // change_pitch_lfo_depth() function
1187    
1188        VMFnResult* InstrumentScriptVMFunction_change_pitch_lfo_depth::exec(VMFnArgs* args) {
1189            return VMChangeSynthParamFunction::execTemplate<
1190                        &NoteBase::_Override::PitchLFODepth,
1191                        Event::synth_param_pitch_lfo_depth,
1192                        true, 1000000, 0>( args, "change_pitch_lfo_depth" );
1193        }
1194    
1195        // change_pitch_lfo_freq() function
1196    
1197        VMFnResult* InstrumentScriptVMFunction_change_pitch_lfo_freq::exec(VMFnArgs* args) {
1198            return VMChangeSynthParamFunction::execTemplate<
1199                        &NoteBase::_Override::PitchLFOFreq,
1200                        Event::synth_param_pitch_lfo_freq,
1201                        true, 1000000, 0>( args, "change_pitch_lfo_freq" );
1202        }
1203    
1204        // change_vol_time() function
1205    
1206        VMFnResult* InstrumentScriptVMFunction_change_vol_time::exec(VMFnArgs* args) {
1207            return VMChangeSynthParamFunction::execTemplate<
1208                        &NoteBase::_Override::VolumeTime,
1209                        Event::synth_param_volume_time,
1210                        false, NO_LIMIT, 0>( args, "change_vol_time" );
1211        }
1212    
1213        // change_tune_time() function
1214    
1215        VMFnResult* InstrumentScriptVMFunction_change_tune_time::exec(VMFnArgs* args) {
1216            return VMChangeSynthParamFunction::execTemplate<
1217                        &NoteBase::_Override::PitchTime,
1218                        Event::synth_param_pitch_time,
1219                        false, NO_LIMIT, 0>( args, "change_tune_time" );
1220        }
1221    
1222        // template for change_*_curve() functions
1223    
1224        bool VMChangeFadeCurveFunction::acceptsArgType(int iArg, ExprType_t type) const {
1225            if (iArg == 0)
1226                return type == INT_EXPR || type == INT_ARR_EXPR;
1227            else
1228                return type == INT_EXPR;
1229        }
1230    
1231        template<fade_curve_t NoteBase::_Override::*T_noteParam, int T_synthParam>
1232        VMFnResult* VMChangeFadeCurveFunction::execTemplate(VMFnArgs* args, const char* functionName) {
1233            int value = args->arg(1)->asInt()->evalInt();
1234            switch (value) {
1235                case FADE_CURVE_LINEAR:
1236                case FADE_CURVE_EASE_IN_EASE_OUT:
1237                    break;
1238                default:
1239                    wrnMsg(String(functionName) + "(): invalid curve type passed as argument 2");
1240                    return successResult();
1241            }
1242    
1243            AbstractEngineChannel* pEngineChannel =
1244                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1245    
1246            if (args->arg(0)->exprType() == INT_EXPR) {
1247                const ScriptID id = args->arg(0)->asInt()->evalInt();
1248                if (!id) {
1249                    wrnMsg(String(functionName) + "(): note ID for argument 1 may not be zero");
1250                    return successResult();
1251                }
1252                if (!id.isNoteID()) {
1253                    wrnMsg(String(functionName) + "(): argument 1 is not a note ID");
1254                    return successResult();
1255                }
1256    
1257                NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1258                if (!pNote) return successResult();
1259    
1260                // if this change_*_curve() script function was called immediately after
1261                // note was triggered then immediately apply the synth parameter
1262                // change to Note object
1263                if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1264                    pNote->Override.*T_noteParam = (fade_curve_t) value;
1265                } else { // otherwise schedule this synth parameter change ...
1266                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1267                    e.Init(); // clear IDs
1268                    e.Type = Event::type_note_synth_param;
1269                    e.Param.NoteSynthParam.NoteID   = id.noteID();
1270                    e.Param.NoteSynthParam.Type     = (Event::synth_param_t) T_synthParam;
1271                    e.Param.NoteSynthParam.Delta    = value;
1272                    e.Param.NoteSynthParam.Relative = false;
1273    
1274                    pEngineChannel->ScheduleEventMicroSec(&e, 0);
1275                }
1276            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
1277                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
1278                for (int i = 0; i < ids->arraySize(); ++i) {
1279                    const ScriptID id = ids->evalIntElement(i);
1280                    if (!id || !id.isNoteID()) continue;
1281    
1282                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1283                    if (!pNote) continue;
1284    
1285                    // if this change_*_curve() script function was called immediately after
1286                    // note was triggered then immediately apply the synth parameter
1287                    // change to Note object
1288                    if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1289                        pNote->Override.*T_noteParam = (fade_curve_t) value;
1290                    } else { // otherwise schedule this synth parameter change ...
1291                        Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1292                        e.Init(); // clear IDs
1293                        e.Type = Event::type_note_synth_param;
1294                        e.Param.NoteSynthParam.NoteID   = id.noteID();
1295                        e.Param.NoteSynthParam.Type     = (Event::synth_param_t) T_synthParam;
1296                        e.Param.NoteSynthParam.Delta    = value;
1297                        e.Param.NoteSynthParam.Relative = false;
1298    
1299                        pEngineChannel->ScheduleEventMicroSec(&e, 0);
1300                    }
1301                }
1302            }
1303    
1304            return successResult();
1305        }
1306    
1307        // change_vol_curve() function
1308    
1309        VMFnResult* InstrumentScriptVMFunction_change_vol_curve::exec(VMFnArgs* args) {
1310            return VMChangeFadeCurveFunction::execTemplate<
1311                        &NoteBase::_Override::VolumeCurve,
1312                        Event::synth_param_volume_curve>( args, "change_vol_curve" );
1313        }
1314    
1315        // change_tune_curve() function
1316    
1317        VMFnResult* InstrumentScriptVMFunction_change_tune_curve::exec(VMFnArgs* args) {
1318            return VMChangeFadeCurveFunction::execTemplate<
1319                        &NoteBase::_Override::PitchCurve,
1320                        Event::synth_param_pitch_curve>( args, "change_tune_curve" );
1321        }
1322    
1323        // fade_in() function
1324    
1325        InstrumentScriptVMFunction_fade_in::InstrumentScriptVMFunction_fade_in(InstrumentScriptVM* parent)
1326            : m_vm(parent)
1327        {
1328        }
1329    
1330        bool InstrumentScriptVMFunction_fade_in::acceptsArgType(int iArg, ExprType_t type) const {
1331            if (iArg == 0)
1332                return type == INT_EXPR || type == INT_ARR_EXPR;
1333            else
1334                return type == INT_EXPR;
1335        }
1336    
1337        VMFnResult* InstrumentScriptVMFunction_fade_in::exec(VMFnArgs* args) {
1338            int duration = args->arg(1)->asInt()->evalInt();
1339            if (duration < 0) {
1340                wrnMsg("fade_in(): argument 2 may not be negative");
1341                duration = 0;
1342            }
1343            const float fDuration = float(duration) / 1000000.f; // convert microseconds to seconds
1344    
1345            AbstractEngineChannel* pEngineChannel =
1346                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1347    
1348            if (args->arg(0)->exprType() == INT_EXPR) {
1349                const ScriptID id = args->arg(0)->asInt()->evalInt();
1350                if (!id) {
1351                    wrnMsg("fade_in(): note ID for argument 1 may not be zero");
1352                    return successResult();
1353                }
1354                if (!id.isNoteID()) {
1355                    wrnMsg("fade_in(): argument 1 is not a note ID");
1356                    return successResult();
1357                }
1358    
1359                NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1360                if (!pNote) return successResult();
1361    
1362                // if fade_in() was called immediately after note was triggered
1363                // then immediately apply a start volume of zero to Note object,
1364                // as well as the fade in duration
1365                if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1366                    pNote->Override.Volume = 0.f;
1367                    pNote->Override.VolumeTime = fDuration;
1368                } else { // otherwise schedule a "volume time" change with the requested fade in duration ...
1369                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1370                    e.Init(); // clear IDs
1371                    e.Type = Event::type_note_synth_param;
1372                    e.Param.NoteSynthParam.NoteID   = id.noteID();
1373                    e.Param.NoteSynthParam.Type     = Event::synth_param_volume_time;
1374                    e.Param.NoteSynthParam.Delta    = fDuration;
1375                    e.Param.NoteSynthParam.Relative = false;
1376    
1377                    pEngineChannel->ScheduleEventMicroSec(&e, 0);
1378                }
1379                // and finally schedule a "volume" change, simply one time slice
1380                // ahead, with the final fade in volume (1.0)
1381                {
1382                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1383                    e.Init(); // clear IDs
1384                    e.Type = Event::type_note_synth_param;
1385                    e.Param.NoteSynthParam.NoteID   = id.noteID();
1386                    e.Param.NoteSynthParam.Type     = Event::synth_param_volume;
1387                    e.Param.NoteSynthParam.Delta    = 1.f;
1388                    e.Param.NoteSynthParam.Relative = false;
1389    
1390                    // scheduling with 0 delay would also work here, but +1 is more
1391                    // safe regarding potential future implementation changes of the
1392                    // scheduler (see API comments of RTAVLTree::insert())
1393                    pEngineChannel->ScheduleEventMicroSec(&e, 1);
1394                }
1395            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
1396                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
1397                for (int i = 0; i < ids->arraySize(); ++i) {
1398                    const ScriptID id = ids->evalIntElement(i);
1399                    if (!id || !id.isNoteID()) continue;
1400    
1401                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1402                    if (!pNote) continue;
1403    
1404                    // if fade_in() was called immediately after note was triggered
1405                    // then immediately apply a start volume of zero to Note object,
1406                    // as well as the fade in duration
1407                    if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1408                        pNote->Override.Volume = 0.f;
1409                        pNote->Override.VolumeTime = fDuration;
1410                    } else { // otherwise schedule a "volume time" change with the requested fade in duration ...
1411                        Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1412                        e.Init(); // clear IDs
1413                        e.Type = Event::type_note_synth_param;
1414                        e.Param.NoteSynthParam.NoteID   = id.noteID();
1415                        e.Param.NoteSynthParam.Type     = Event::synth_param_volume_time;
1416                        e.Param.NoteSynthParam.Delta    = fDuration;
1417                        e.Param.NoteSynthParam.Relative = false;
1418    
1419                        pEngineChannel->ScheduleEventMicroSec(&e, 0);
1420                    }
1421                    // and finally schedule a "volume" change, simply one time slice
1422                    // ahead, with the final fade in volume (1.0)
1423                    {
1424                        Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1425                        e.Init(); // clear IDs
1426                        e.Type = Event::type_note_synth_param;
1427                        e.Param.NoteSynthParam.NoteID   = id.noteID();
1428                        e.Param.NoteSynthParam.Type     = Event::synth_param_volume;
1429                        e.Param.NoteSynthParam.Delta    = 1.f;
1430                        e.Param.NoteSynthParam.Relative = false;
1431    
1432                        // scheduling with 0 delay would also work here, but +1 is more
1433                        // safe regarding potential future implementation changes of the
1434                        // scheduler (see API comments of RTAVLTree::insert())
1435                        pEngineChannel->ScheduleEventMicroSec(&e, 1);
1436                    }
1437                }
1438            }
1439    
1440            return successResult();
1441        }
1442    
1443        // fade_out() function
1444    
1445        InstrumentScriptVMFunction_fade_out::InstrumentScriptVMFunction_fade_out(InstrumentScriptVM* parent)
1446            : m_vm(parent)
1447        {
1448        }
1449    
1450        bool InstrumentScriptVMFunction_fade_out::acceptsArgType(int iArg, ExprType_t type) const {
1451            if (iArg == 0)
1452                return type == INT_EXPR || type == INT_ARR_EXPR;
1453            else
1454                return type == INT_EXPR;
1455        }
1456    
1457        VMFnResult* InstrumentScriptVMFunction_fade_out::exec(VMFnArgs* args) {
1458            int duration = args->arg(1)->asInt()->evalInt();
1459            if (duration < 0) {
1460                wrnMsg("fade_out(): argument 2 may not be negative");
1461                duration = 0;
1462            }
1463            const float fDuration = float(duration) / 1000000.f; // convert microseconds to seconds
1464    
1465            bool stop = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : true;
1466    
1467            AbstractEngineChannel* pEngineChannel =
1468                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1469    
1470            if (args->arg(0)->exprType() == INT_EXPR) {
1471                const ScriptID id = args->arg(0)->asInt()->evalInt();
1472                if (!id) {
1473                    wrnMsg("fade_out(): note ID for argument 1 may not be zero");
1474                    return successResult();
1475                }
1476                if (!id.isNoteID()) {
1477                    wrnMsg("fade_out(): argument 1 is not a note ID");
1478                    return successResult();
1479                }
1480    
1481                NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1482                if (!pNote) return successResult();
1483    
1484                // if fade_out() was called immediately after note was triggered
1485                // then immediately apply fade out duration to Note object
1486                if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1487                    pNote->Override.VolumeTime = fDuration;
1488                } else { // otherwise schedule a "volume time" change with the requested fade out duration ...
1489                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1490                    e.Init(); // clear IDs
1491                    e.Type = Event::type_note_synth_param;
1492                    e.Param.NoteSynthParam.NoteID   = id.noteID();
1493                    e.Param.NoteSynthParam.Type     = Event::synth_param_volume_time;
1494                    e.Param.NoteSynthParam.Delta    = fDuration;
1495                    e.Param.NoteSynthParam.Relative = false;
1496    
1497                    pEngineChannel->ScheduleEventMicroSec(&e, 0);
1498                }
1499                // now schedule a "volume" change, simply one time slice ahead, with
1500                // the final fade out volume (0.0)
1501                {
1502                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1503                    e.Init(); // clear IDs
1504                    e.Type = Event::type_note_synth_param;
1505                    e.Param.NoteSynthParam.NoteID   = id.noteID();
1506                    e.Param.NoteSynthParam.Type     = Event::synth_param_volume;
1507                    e.Param.NoteSynthParam.Delta    = 0.f;
1508                    e.Param.NoteSynthParam.Relative = false;
1509    
1510                    // scheduling with 0 delay would also work here, but +1 is more
1511                    // safe regarding potential future implementation changes of the
1512                    // scheduler (see API comments of RTAVLTree::insert())
1513                    pEngineChannel->ScheduleEventMicroSec(&e, 1);
1514                }
1515                // and finally if stopping the note was requested after the fade out
1516                // completed, then schedule to kill the voice after the requested
1517                // duration
1518                if (stop) {
1519                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1520                    e.Init(); // clear IDs
1521                    e.Type = Event::type_kill_note;
1522                    e.Param.Note.ID = id.noteID();
1523                    e.Param.Note.Key = pNote->hostKey;
1524    
1525                    pEngineChannel->ScheduleEventMicroSec(&e, duration + 1);
1526                }
1527            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
1528                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
1529                for (int i = 0; i < ids->arraySize(); ++i) {
1530                    const ScriptID id = ids->evalIntElement(i);
1531                    if (!id || !id.isNoteID()) continue;
1532    
1533                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1534                    if (!pNote) continue;
1535    
1536                    // if fade_out() was called immediately after note was triggered
1537                    // then immediately apply fade out duration to Note object
1538                    if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1539                        pNote->Override.VolumeTime = fDuration;
1540                    } else { // otherwise schedule a "volume time" change with the requested fade out duration ...
1541                        Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1542                        e.Init(); // clear IDs
1543                        e.Type = Event::type_note_synth_param;
1544                        e.Param.NoteSynthParam.NoteID   = id.noteID();
1545                        e.Param.NoteSynthParam.Type     = Event::synth_param_volume_time;
1546                        e.Param.NoteSynthParam.Delta    = fDuration;
1547                        e.Param.NoteSynthParam.Relative = false;
1548    
1549                        pEngineChannel->ScheduleEventMicroSec(&e, 0);
1550                    }
1551                    // now schedule a "volume" change, simply one time slice ahead, with
1552                    // the final fade out volume (0.0)
1553                    {
1554                        Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1555                        e.Init(); // clear IDs
1556                        e.Type = Event::type_note_synth_param;
1557                        e.Param.NoteSynthParam.NoteID   = id.noteID();
1558                        e.Param.NoteSynthParam.Type     = Event::synth_param_volume;
1559                        e.Param.NoteSynthParam.Delta    = 0.f;
1560                        e.Param.NoteSynthParam.Relative = false;
1561    
1562                        // scheduling with 0 delay would also work here, but +1 is more
1563                        // safe regarding potential future implementation changes of the
1564                        // scheduler (see API comments of RTAVLTree::insert())
1565                        pEngineChannel->ScheduleEventMicroSec(&e, 1);
1566                    }
1567                    // and finally if stopping the note was requested after the fade out
1568                    // completed, then schedule to kill the voice after the requested
1569                    // duration
1570                    if (stop) {
1571                        Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1572                        e.Init(); // clear IDs
1573                        e.Type = Event::type_kill_note;
1574                        e.Param.Note.ID = id.noteID();
1575                        e.Param.Note.Key = pNote->hostKey;
1576                        
1577                        pEngineChannel->ScheduleEventMicroSec(&e, duration + 1);
1578                    }
1579                }
1580            }
1581    
1582            return successResult();
1583        }
1584    
1585        // get_event_par() function
1586    
1587        InstrumentScriptVMFunction_get_event_par::InstrumentScriptVMFunction_get_event_par(InstrumentScriptVM* parent)
1588            : m_vm(parent)
1589        {
1590        }
1591    
1592        VMFnResult* InstrumentScriptVMFunction_get_event_par::exec(VMFnArgs* args) {
1593            AbstractEngineChannel* pEngineChannel =
1594                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1595    
1596            const ScriptID id = args->arg(0)->asInt()->evalInt();
1597            if (!id) {
1598                wrnMsg("get_event_par(): note ID for argument 1 may not be zero");
1599                return successResult(0);
1600            }
1601            if (!id.isNoteID()) {
1602                wrnMsg("get_event_par(): argument 1 is not a note ID");
1603                return successResult(0);
1604            }
1605    
1606            NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1607            if (!pNote) {
1608                wrnMsg("get_event_par(): no note alive with that note ID of argument 1");
1609                return successResult(0);
1610            }
1611    
1612            const int parameter = args->arg(1)->asInt()->evalInt();
1613            switch (parameter) {
1614                case EVENT_PAR_NOTE:
1615                    return successResult(pNote->cause.Param.Note.Key);
1616                case EVENT_PAR_VELOCITY:
1617                    return successResult(pNote->cause.Param.Note.Velocity);
1618                case EVENT_PAR_VOLUME:
1619                    return successResult(
1620                        RTMath::LinRatioToDecibel(pNote->Override.Volume) * 1000.f
1621                    );
1622                case EVENT_PAR_TUNE:
1623                    return successResult(
1624                         RTMath::FreqRatioToCents(pNote->Override.Pitch) * 1000.f
1625                    );
1626                case EVENT_PAR_0:
1627                    return successResult(pNote->userPar[0]);
1628                case EVENT_PAR_1:
1629                    return successResult(pNote->userPar[1]);
1630                case EVENT_PAR_2:
1631                    return successResult(pNote->userPar[2]);
1632                case EVENT_PAR_3:
1633                    return successResult(pNote->userPar[3]);
1634            }
1635    
1636            wrnMsg("get_event_par(): argument 2 is an invalid event parameter");
1637            return successResult(0);
1638        }
1639    
1640        // set_event_par() function
1641    
1642        InstrumentScriptVMFunction_set_event_par::InstrumentScriptVMFunction_set_event_par(InstrumentScriptVM* parent)
1643            : m_vm(parent)
1644        {
1645        }
1646    
1647        VMFnResult* InstrumentScriptVMFunction_set_event_par::exec(VMFnArgs* args) {
1648            AbstractEngineChannel* pEngineChannel =
1649                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1650    
1651            const ScriptID id = args->arg(0)->asInt()->evalInt();
1652            if (!id) {
1653                wrnMsg("set_event_par(): note ID for argument 1 may not be zero");
1654                return successResult();
1655            }
1656            if (!id.isNoteID()) {
1657                wrnMsg("set_event_par(): argument 1 is not a note ID");
1658                return successResult();
1659            }
1660    
1661            NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1662            if (!pNote) return successResult();
1663    
1664            const int parameter = args->arg(1)->asInt()->evalInt();
1665            const int value     = args->arg(2)->asInt()->evalInt();
1666    
1667            switch (parameter) {
1668                case EVENT_PAR_NOTE:
1669                    if (value < 0 || value > 127) {
1670                        wrnMsg("set_event_par(): note number of argument 3 is out of range");
1671                        return successResult();
1672                    }
1673                    if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1674                        pNote->cause.Param.Note.Key = value;
1675                        m_vm->m_event->cause.Param.Note.Key = value;
1676                    } else {
1677                        wrnMsg("set_event_par(): note number can only be changed when note is new");
1678                    }
1679                    return successResult();
1680                case EVENT_PAR_VELOCITY:
1681                    if (value < 0 || value > 127) {
1682                        wrnMsg("set_event_par(): velocity of argument 3 is out of range");
1683                        return successResult();
1684                    }
1685                    if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1686                        pNote->cause.Param.Note.Velocity = value;
1687                        m_vm->m_event->cause.Param.Note.Velocity = value;
1688                    } else {
1689                        wrnMsg("set_event_par(): velocity can only be changed when note is new");
1690                    }
1691                    return successResult();
1692                case EVENT_PAR_VOLUME:
1693                    wrnMsg("set_event_par(): changing volume by this function is currently not supported, use change_vol() instead");
1694                    return successResult();
1695                case EVENT_PAR_TUNE:
1696                    wrnMsg("set_event_par(): changing tune by this function is currently not supported, use change_tune() instead");
1697                    return successResult();
1698                case EVENT_PAR_0:
1699                    pNote->userPar[0] = value;
1700                    return successResult();
1701                case EVENT_PAR_1:
1702                    pNote->userPar[1] = value;
1703                    return successResult();
1704                case EVENT_PAR_2:
1705                    pNote->userPar[2] = value;
1706                    return successResult();
1707                case EVENT_PAR_3:
1708                    pNote->userPar[3] = value;
1709                    return successResult();
1710            }
1711    
1712            wrnMsg("set_event_par(): argument 2 is an invalid event parameter");
1713            return successResult();
1714        }
1715    
1716        // change_note() function
1717    
1718        InstrumentScriptVMFunction_change_note::InstrumentScriptVMFunction_change_note(InstrumentScriptVM* parent)
1719        : m_vm(parent)
1720        {
1721        }
1722    
1723        VMFnResult* InstrumentScriptVMFunction_change_note::exec(VMFnArgs* args) {
1724            AbstractEngineChannel* pEngineChannel =
1725                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1726    
1727            const ScriptID id = args->arg(0)->asInt()->evalInt();
1728            if (!id) {
1729                wrnMsg("change_note(): note ID for argument 1 may not be zero");
1730                return successResult();
1731            }
1732            if (!id.isNoteID()) {
1733                wrnMsg("change_note(): argument 1 is not a note ID");
1734                return successResult();
1735            }
1736    
1737            NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1738            if (!pNote) return successResult();
1739    
1740            const int value = args->arg(1)->asInt()->evalInt();
1741            if (value < 0 || value > 127) {
1742                wrnMsg("change_note(): note number of argument 2 is out of range");
1743                return successResult();
1744            }
1745    
1746            if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1747                pNote->cause.Param.Note.Key = value;
1748                m_vm->m_event->cause.Param.Note.Key = value;
1749            } else {
1750                wrnMsg("change_note(): note number can only be changed when note is new");
1751            }
1752    
1753            return successResult();
1754        }
1755    
1756        // change_velo() function
1757    
1758        InstrumentScriptVMFunction_change_velo::InstrumentScriptVMFunction_change_velo(InstrumentScriptVM* parent)
1759        : m_vm(parent)
1760        {
1761        }
1762    
1763        VMFnResult* InstrumentScriptVMFunction_change_velo::exec(VMFnArgs* args) {
1764            AbstractEngineChannel* pEngineChannel =
1765                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1766    
1767            const ScriptID id = args->arg(0)->asInt()->evalInt();
1768            if (!id) {
1769                wrnMsg("change_velo(): note ID for argument 1 may not be zero");
1770                return successResult();
1771            }
1772            if (!id.isNoteID()) {
1773                wrnMsg("change_velo(): argument 1 is not a note ID");
1774                return successResult();
1775            }
1776    
1777            NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1778            if (!pNote) return successResult();
1779    
1780            const int value = args->arg(1)->asInt()->evalInt();
1781            if (value < 0 || value > 127) {
1782                wrnMsg("change_velo(): velocity of argument 2 is out of range");
1783                return successResult();
1784            }
1785    
1786            if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1787                pNote->cause.Param.Note.Velocity = value;
1788                m_vm->m_event->cause.Param.Note.Velocity = value;
1789            } else {
1790                wrnMsg("change_velo(): velocity can only be changed when note is new");
1791            }
1792    
1793            return successResult();
1794        }
1795    
1796      // event_status() function      // event_status() function
1797    
1798      InstrumentScriptVMFunction_event_status::InstrumentScriptVMFunction_event_status(InstrumentScriptVM* parent)      InstrumentScriptVMFunction_event_status::InstrumentScriptVMFunction_event_status(InstrumentScriptVM* parent)
# Line 1124  namespace LinuxSampler { Line 1858  namespace LinuxSampler {
1858              (args->argsCount() >= 2) ? (args->arg(1)->asInt()->evalInt() == 1) : false;              (args->argsCount() >= 2) ? (args->arg(1)->asInt()->evalInt() == 1) : false;
1859    
1860          pEngineChannel->ScheduleResumeOfScriptCallback(          pEngineChannel->ScheduleResumeOfScriptCallback(
1861              itCallback, m_vm->m_event->cause.SchedTime(), disableWaitForever              itCallback, m_vm->m_event->scheduleTime, disableWaitForever
1862          );          );
1863    
1864          return successResult();          return successResult();

Legend:
Removed from v.2962  
changed lines
  Added in v.3246

  ViewVC Help
Powered by ViewVC