/[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 3188 by schoenebeck, Fri May 19 14:23:12 2017 UTC revision 3303 by schoenebeck, Mon Jul 10 17:45:30 2017 UTC
# Line 23  namespace LinuxSampler { Line 23  namespace LinuxSampler {
23      VMFnResult* InstrumentScriptVMFunction_play_note::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_play_note::exec(VMFnArgs* args) {
24          int note = args->arg(0)->asInt()->evalInt();          int note = args->arg(0)->asInt()->evalInt();
25          int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;          int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;
         int sampleoffset = (args->argsCount() >= 3) ? args->arg(2)->asInt()->evalInt() : 0;  
26          int duration = (args->argsCount() >= 4) ? args->arg(3)->asInt()->evalInt() : 0; //TODO: -1 might be a better default value instead of 0          int duration = (args->argsCount() >= 4) ? args->arg(3)->asInt()->evalInt() : 0; //TODO: -1 might be a better default value instead of 0
27    
28          if (note < 0 || note > 127) {          if (note < 0 || note > 127) {
# Line 36  namespace LinuxSampler { Line 35  namespace LinuxSampler {
35              return errorResult(0);              return errorResult(0);
36          }          }
37    
38          if (sampleoffset < 0) {          if (duration < -2) {
39              errMsg("play_note(): argument 3 may not be a negative sample offset");              errMsg("play_note(): argument 4 must be a duration value of at least -2 or higher");
             return errorResult(0);  
         } else if (sampleoffset != 0) {  
             wrnMsg("play_note(): argument 3 does not support a sample offset other than 0 yet");  
         }  
   
         if (duration < -1) {  
             errMsg("play_note(): argument 4 must be a duration value of at least -1 or higher");  
40              return errorResult(0);              return errorResult(0);
41          }          }
42    
# Line 63  namespace LinuxSampler { Line 55  namespace LinuxSampler {
55                  return errorResult(0);                  return errorResult(0);
56              }              }
57              e.Param.Note.ParentNoteID = m_vm->m_event->cause.Param.Note.ID;              e.Param.Note.ParentNoteID = m_vm->m_event->cause.Param.Note.ID;
58                // check if that requested parent note is actually still alive
59                NoteBase* pParentNote =
60                    pEngineChannel->pEngine->NoteByID( e.Param.Note.ParentNoteID );
61                // if parent note is already gone then this new note is not required anymore
62                if (!pParentNote)
63                    return successResult(0);
64          }          }
65    
66          const note_id_t id = pEngineChannel->ScheduleNoteMicroSec(&e, 0);          const note_id_t id = pEngineChannel->ScheduleNoteMicroSec(&e, 0);
67    
68            // if a sample offset is supplied, assign the offset as override
69            // to the previously created Note object
70            if (args->argsCount() >= 3) {
71                int sampleoffset = args->arg(2)->asInt()->evalInt();
72                if (sampleoffset >= 0) {
73                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID(id);
74                    if (pNote) {
75                        pNote->Override.SampleOffset = sampleoffset;
76                    }
77                } else if (sampleoffset < -1) {
78                    errMsg("play_note(): sample offset of argument 3 may not be less than -1");
79                }
80            }
81    
82          // if a duration is supplied (and play-note event was scheduled          // if a duration is supplied (and play-note event was scheduled
83          // successfully above), then schedule a subsequent stop-note event          // successfully above), then schedule a subsequent stop-note event
84          if (id && duration > 0) {          if (id && duration > 0) {
# Line 136  namespace LinuxSampler { Line 148  namespace LinuxSampler {
148          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
149                  static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);                  static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
150    
151          if (args->arg(0)->exprType() == INT_EXPR) {          if (args->argsCount() == 0 || args->arg(0)->exprType() == INT_EXPR) {
152              const ScriptID id = args->arg(0)->asInt()->evalInt();              const ScriptID id = (args->argsCount() >= 1) ? args->arg(0)->asInt()->evalInt() : m_vm->m_event->id;
153              if (!id) {              if (!id && args->argsCount() >= 1) {
154                  wrnMsg("ignore_event(): event ID argument may not be zero");                  wrnMsg("ignore_event(): event ID argument may not be zero");
155                  // 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
156                  return successResult();                  return successResult();
# Line 385  namespace LinuxSampler { Line 397  namespace LinuxSampler {
397              if (!pNote) return successResult();              if (!pNote) return successResult();
398    
399              // if change_vol() was called immediately after note was triggered              // if change_vol() was called immediately after note was triggered
400              // then immediately apply the volume to note object              // then immediately apply the volume to note object, but only if
401              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              // change_vol_time() has not been called before
402                if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime &&
403                    pNote->Override.VolumeTime <= DEFAULT_NOTE_VOLUME_TIME_S)
404                {
405                  if (relative)                  if (relative)
406                      pNote->Override.Volume *= fVolumeLin;                      pNote->Override.Volume *= fVolumeLin;
407                  else                  else
# Line 412  namespace LinuxSampler { Line 427  namespace LinuxSampler {
427                  if (!pNote) continue;                  if (!pNote) continue;
428    
429                  // if change_vol() was called immediately after note was triggered                  // if change_vol() was called immediately after note was triggered
430                  // then immediately apply the volume to Note object                  // then immediately apply the volume to Note object, but only if
431                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  // change_vol_time() has not been called before
432                    if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime &&
433                        pNote->Override.VolumeTime <= DEFAULT_NOTE_VOLUME_TIME_S)
434                    {
435                      if (relative)                      if (relative)
436                          pNote->Override.Volume *= fVolumeLin;                          pNote->Override.Volume *= fVolumeLin;
437                      else                      else
# Line 472  namespace LinuxSampler { Line 490  namespace LinuxSampler {
490              if (!pNote) return successResult();              if (!pNote) return successResult();
491    
492              // if change_tune() was called immediately after note was triggered              // if change_tune() was called immediately after note was triggered
493              // then immediately apply the tuning to Note object              // then immediately apply the tuning to Note object, but only if
494              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              // change_tune_time() has not been called before
495                if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime &&
496                    pNote->Override.PitchTime <= DEFAULT_NOTE_PITCH_TIME_S)
497                {
498                  if (relative)                  if (relative)
499                      pNote->Override.Pitch *= fFreqRatio;                      pNote->Override.Pitch *= fFreqRatio;
500                  else                  else
# Line 499  namespace LinuxSampler { Line 520  namespace LinuxSampler {
520                  if (!pNote) continue;                  if (!pNote) continue;
521    
522                  // if change_tune() was called immediately after note was triggered                  // if change_tune() was called immediately after note was triggered
523                  // then immediately apply the tuning to Note object                  // then immediately apply the tuning to Note object, but only if
524                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  // change_tune_time() has not been called before
525                    if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime &&
526                        pNote->Override.PitchTime <= DEFAULT_NOTE_PITCH_TIME_S)
527                    {
528                      if (relative)                      if (relative)
529                          pNote->Override.Pitch *= fFreqRatio;                          pNote->Override.Pitch *= fFreqRatio;
530                      else                      else
# Line 568  namespace LinuxSampler { Line 592  namespace LinuxSampler {
592    
593              // if change_pan() was called immediately after note was triggered              // if change_pan() was called immediately after note was triggered
594              // then immediately apply the panning to Note object              // then immediately apply the panning to Note object
595              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
596                  if (relative) {                  if (relative) {
597                      pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);                      pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);
598                  } else {                  } else {
# Line 597  namespace LinuxSampler { Line 621  namespace LinuxSampler {
621    
622                  // if change_pan() was called immediately after note was triggered                  // if change_pan() was called immediately after note was triggered
623                  // then immediately apply the panning to Note object                  // then immediately apply the panning to Note object
624                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
625                      if (relative) {                      if (relative) {
626                          pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);                          pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);
627                      } else {                      } else {
# Line 668  namespace LinuxSampler { Line 692  namespace LinuxSampler {
692    
693              // if change_cutoff() was called immediately after note was triggered              // if change_cutoff() was called immediately after note was triggered
694              // then immediately apply cutoff to Note object              // then immediately apply cutoff to Note object
695              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
696                  pNote->Override.Cutoff = fCutoff;                  pNote->Override.Cutoff = fCutoff;
697              } else { // otherwise schedule cutoff change ...              } else { // otherwise schedule cutoff change ...
698                  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 716  namespace LinuxSampler {
716    
717                  // if change_cutoff() was called immediately after note was triggered                  // if change_cutoff() was called immediately after note was triggered
718                  // then immediately apply cutoff to Note object                  // then immediately apply cutoff to Note object
719                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
720                      pNote->Override.Cutoff = fCutoff;                      pNote->Override.Cutoff = fCutoff;
721                  } else { // otherwise schedule cutoff change ...                  } else { // otherwise schedule cutoff change ...
722                      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 755  namespace LinuxSampler { Line 779  namespace LinuxSampler {
779    
780              // if change_reso() was called immediately after note was triggered              // if change_reso() was called immediately after note was triggered
781              // then immediately apply resonance to Note object              // then immediately apply resonance to Note object
782              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
783                  pNote->Override.Resonance = fResonance;                  pNote->Override.Resonance = fResonance;
784              } else { // otherwise schedule resonance change ...              } else { // otherwise schedule resonance change ...
785                  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 803  namespace LinuxSampler {
803    
804                  // if change_reso() was called immediately after note was triggered                  // if change_reso() was called immediately after note was triggered
805                  // then immediately apply resonance to Note object                  // then immediately apply resonance to Note object
806                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
807                      pNote->Override.Resonance = fResonance;                      pNote->Override.Resonance = fResonance;
808                  } else { // otherwise schedule resonance change ...                  } else { // otherwise schedule resonance change ...
809                      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 814  namespace LinuxSampler { Line 838  namespace LinuxSampler {
838    
839      VMFnResult* InstrumentScriptVMFunction_change_attack::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_attack::exec(VMFnArgs* args) {
840          int attack = args->arg(1)->asInt()->evalInt();          int attack = args->arg(1)->asInt()->evalInt();
841          if (attack > VM_EG_PAR_MAX_VALUE) {          // note: intentionally not checking against a max. value here!
842              wrnMsg("change_attack(): argument 2 may not be larger than 1000000");          // (to allow i.e. passing 2000000 for doubling the attack time)
843              attack = VM_EG_PAR_MAX_VALUE;          if (attack < 0) {
         } else if (attack < 0) {  
844              wrnMsg("change_attack(): argument 2 may not be negative");              wrnMsg("change_attack(): argument 2 may not be negative");
845              attack = 0;              attack = 0;
846          }          }
# Line 842  namespace LinuxSampler { Line 865  namespace LinuxSampler {
865    
866              // if change_attack() was called immediately after note was triggered              // if change_attack() was called immediately after note was triggered
867              // then immediately apply attack to Note object              // then immediately apply attack to Note object
868              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
869                  pNote->Override.Attack = fAttack;                  pNote->Override.Attack = fAttack;
870              } else { // otherwise schedule attack change ...              } else { // otherwise schedule attack change ...
871                  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 889  namespace LinuxSampler {
889    
890                  // if change_attack() was called immediately after note was triggered                  // if change_attack() was called immediately after note was triggered
891                  // then immediately apply attack to Note object                  // then immediately apply attack to Note object
892                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
893                      pNote->Override.Attack = fAttack;                      pNote->Override.Attack = fAttack;
894                  } else { // otherwise schedule attack change ...                  } else { // otherwise schedule attack change ...
895                      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 901  namespace LinuxSampler { Line 924  namespace LinuxSampler {
924    
925      VMFnResult* InstrumentScriptVMFunction_change_decay::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_decay::exec(VMFnArgs* args) {
926          int decay = args->arg(1)->asInt()->evalInt();          int decay = args->arg(1)->asInt()->evalInt();
927          if (decay > VM_EG_PAR_MAX_VALUE) {          // note: intentionally not checking against a max. value here!
928              wrnMsg("change_decay(): argument 2 may not be larger than 1000000");          // (to allow i.e. passing 2000000 for doubling the decay time)
929              decay = VM_EG_PAR_MAX_VALUE;          if (decay < 0) {
         } else if (decay < 0) {  
930              wrnMsg("change_decay(): argument 2 may not be negative");              wrnMsg("change_decay(): argument 2 may not be negative");
931              decay = 0;              decay = 0;
932          }          }
# Line 929  namespace LinuxSampler { Line 951  namespace LinuxSampler {
951    
952              // if change_decay() was called immediately after note was triggered              // if change_decay() was called immediately after note was triggered
953              // then immediately apply decay to Note object              // then immediately apply decay to Note object
954              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
955                  pNote->Override.Decay = fDecay;                  pNote->Override.Decay = fDecay;
956              } else { // otherwise schedule decay change ...              } else { // otherwise schedule decay change ...
957                  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 975  namespace LinuxSampler {
975    
976                  // if change_decay() was called immediately after note was triggered                  // if change_decay() was called immediately after note was triggered
977                  // then immediately apply decay to Note object                  // then immediately apply decay to Note object
978                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
979                      pNote->Override.Decay = fDecay;                      pNote->Override.Decay = fDecay;
980                  } else { // otherwise schedule decay change ...                  } else { // otherwise schedule decay change ...
981                      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 988  namespace LinuxSampler { Line 1010  namespace LinuxSampler {
1010    
1011      VMFnResult* InstrumentScriptVMFunction_change_release::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_release::exec(VMFnArgs* args) {
1012          int release = args->arg(1)->asInt()->evalInt();          int release = args->arg(1)->asInt()->evalInt();
1013          if (release > VM_EG_PAR_MAX_VALUE) {          // note: intentionally not checking against a max. value here!
1014              wrnMsg("change_release(): argument 2 may not be larger than 1000000");          // (to allow i.e. passing 2000000 for doubling the release time)
1015              release = VM_EG_PAR_MAX_VALUE;          if (release < 0) {
         } else if (release < 0) {  
1016              wrnMsg("change_release(): argument 2 may not be negative");              wrnMsg("change_release(): argument 2 may not be negative");
1017              release = 0;              release = 0;
1018          }          }
# Line 1016  namespace LinuxSampler { Line 1037  namespace LinuxSampler {
1037    
1038              // if change_release() was called immediately after note was triggered              // if change_release() was called immediately after note was triggered
1039              // then immediately apply relase to Note object              // then immediately apply relase to Note object
1040              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1041                  pNote->Override.Release = fRelease;                  pNote->Override.Release = fRelease;
1042              } else { // otherwise schedule release change ...              } else { // otherwise schedule release change ...
1043                  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 1061  namespace LinuxSampler {
1061    
1062                  // if change_release() was called immediately after note was triggered                  // if change_release() was called immediately after note was triggered
1063                  // then immediately apply relase to Note object                  // then immediately apply relase to Note object
1064                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1065                      pNote->Override.Release = fRelease;                      pNote->Override.Release = fRelease;
1066                  } else { // otherwise schedule release change ...                  } else { // otherwise schedule release change ...
1067                      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 1080  namespace LinuxSampler {
1080          return successResult();          return successResult();
1081      }      }
1082    
1083        // template for change_*() functions
1084    
1085      bool VMChangeSynthParamFunction::acceptsArgType(int iArg, ExprType_t type) const {      bool VMChangeSynthParamFunction::acceptsArgType(int iArg, ExprType_t type) const {
1086          if (iArg == 0)          if (iArg == 0)
1087              return type == INT_EXPR || type == INT_ARR_EXPR;              return type == INT_EXPR || type == INT_ARR_EXPR;
# Line 1066  namespace LinuxSampler { Line 1089  namespace LinuxSampler {
1089              return type == INT_EXPR;              return type == INT_EXPR;
1090      }      }
1091    
1092        // Arbitrarily chosen constant value symbolizing "no limit".
1093        #define NO_LIMIT 1315916909
1094    
1095      template<float NoteBase::_Override::*T_noteParam, int T_synthParam,      template<float NoteBase::_Override::*T_noteParam, int T_synthParam,
1096               bool T_isNormalizedParam, int T_maxValue, int T_minValue>               bool T_isNormalizedParam, int T_maxValue, int T_minValue>
1097      VMFnResult* VMChangeSynthParamFunction::execTemplate(VMFnArgs* args, const char* functionName) {      VMFnResult* VMChangeSynthParamFunction::execTemplate(VMFnArgs* args, const char* functionName) {
1098          int value = args->arg(1)->asInt()->evalInt();          int value = args->arg(1)->asInt()->evalInt();
1099          if (value > T_maxValue) {          if (T_maxValue != NO_LIMIT && value > T_maxValue) {
1100              wrnMsg(String(functionName) + "(): argument 2 may not be larger than " + ToString(T_maxValue));              wrnMsg(String(functionName) + "(): argument 2 may not be larger than " + ToString(T_maxValue));
1101              value = T_maxValue;              value = T_maxValue;
1102          } else if (value < T_minValue) {          } else if (T_minValue != NO_LIMIT && value < T_minValue) {
1103              if (T_minValue == 0)              if (T_minValue == 0)
1104                  wrnMsg(String(functionName) + "(): argument 2 may not be negative");                  wrnMsg(String(functionName) + "(): argument 2 may not be negative");
1105              else              else
# Line 1104  namespace LinuxSampler { Line 1130  namespace LinuxSampler {
1130              // if this change_*() script function was called immediately after              // if this change_*() script function was called immediately after
1131              // note was triggered then immediately apply the synth parameter              // note was triggered then immediately apply the synth parameter
1132              // change to Note object              // change to Note object
1133              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1134                  pNote->Override.*T_noteParam = fValue;                  pNote->Override.*T_noteParam = fValue;
1135              } else { // otherwise schedule this synth parameter change ...              } else { // otherwise schedule this synth parameter change ...
1136                  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 1129  namespace LinuxSampler { Line 1155  namespace LinuxSampler {
1155                  // if this change_*() script function was called immediately after                  // if this change_*() script function was called immediately after
1156                  // note was triggered then immediately apply the synth parameter                  // note was triggered then immediately apply the synth parameter
1157                  // change to Note object                  // change to Note object
1158                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1159                      pNote->Override.*T_noteParam = fValue;                      pNote->Override.*T_noteParam = fValue;
1160                  } else { // otherwise schedule this synth parameter change ...                  } else { // otherwise schedule this synth parameter change ...
1161                      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 1153  namespace LinuxSampler { Line 1179  namespace LinuxSampler {
1179      VMFnResult* InstrumentScriptVMFunction_change_amp_lfo_depth::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_amp_lfo_depth::exec(VMFnArgs* args) {
1180          return VMChangeSynthParamFunction::execTemplate<          return VMChangeSynthParamFunction::execTemplate<
1181                      &NoteBase::_Override::AmpLFODepth,                      &NoteBase::_Override::AmpLFODepth,
1182                      Event::synth_param_amp_lfo_depth, true>( args, "change_amp_lfo_depth" );                      Event::synth_param_amp_lfo_depth,
1183                        true, 1000000, 0>( args, "change_amp_lfo_depth" );
1184      }      }
1185    
1186      // change_amp_lfo_freq() function      // change_amp_lfo_freq() function
# Line 1161  namespace LinuxSampler { Line 1188  namespace LinuxSampler {
1188      VMFnResult* InstrumentScriptVMFunction_change_amp_lfo_freq::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_amp_lfo_freq::exec(VMFnArgs* args) {
1189          return VMChangeSynthParamFunction::execTemplate<          return VMChangeSynthParamFunction::execTemplate<
1190                      &NoteBase::_Override::AmpLFOFreq,                      &NoteBase::_Override::AmpLFOFreq,
1191                      Event::synth_param_amp_lfo_freq, true>( args, "change_amp_lfo_freq" );                      Event::synth_param_amp_lfo_freq,
1192                        true, 1000000, 0>( args, "change_amp_lfo_freq" );
1193      }      }
1194    
1195      // change_pitch_lfo_depth() function      // change_pitch_lfo_depth() function
# Line 1169  namespace LinuxSampler { Line 1197  namespace LinuxSampler {
1197      VMFnResult* InstrumentScriptVMFunction_change_pitch_lfo_depth::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_pitch_lfo_depth::exec(VMFnArgs* args) {
1198          return VMChangeSynthParamFunction::execTemplate<          return VMChangeSynthParamFunction::execTemplate<
1199                      &NoteBase::_Override::PitchLFODepth,                      &NoteBase::_Override::PitchLFODepth,
1200                      Event::synth_param_pitch_lfo_depth, true>( args, "change_pitch_lfo_depth" );                      Event::synth_param_pitch_lfo_depth,
1201                        true, 1000000, 0>( args, "change_pitch_lfo_depth" );
1202      }      }
1203    
1204      // change_pitch_lfo_freq() function      // change_pitch_lfo_freq() function
# Line 1177  namespace LinuxSampler { Line 1206  namespace LinuxSampler {
1206      VMFnResult* InstrumentScriptVMFunction_change_pitch_lfo_freq::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_pitch_lfo_freq::exec(VMFnArgs* args) {
1207          return VMChangeSynthParamFunction::execTemplate<          return VMChangeSynthParamFunction::execTemplate<
1208                      &NoteBase::_Override::PitchLFOFreq,                      &NoteBase::_Override::PitchLFOFreq,
1209                      Event::synth_param_pitch_lfo_freq, true>( args, "change_pitch_lfo_freq" );                      Event::synth_param_pitch_lfo_freq,
1210                        true, 1000000, 0>( args, "change_pitch_lfo_freq" );
1211      }      }
1212    
1213      // change_vol_time() function      // change_vol_time() function
# Line 1185  namespace LinuxSampler { Line 1215  namespace LinuxSampler {
1215      VMFnResult* InstrumentScriptVMFunction_change_vol_time::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_vol_time::exec(VMFnArgs* args) {
1216          return VMChangeSynthParamFunction::execTemplate<          return VMChangeSynthParamFunction::execTemplate<
1217                      &NoteBase::_Override::VolumeTime,                      &NoteBase::_Override::VolumeTime,
1218                      Event::synth_param_volume_time, false>( args, "change_vol_time" );                      Event::synth_param_volume_time,
1219                        false, NO_LIMIT, 0>( args, "change_vol_time" );
1220      }      }
1221    
1222      // change_tune_time() function      // change_tune_time() function
# Line 1193  namespace LinuxSampler { Line 1224  namespace LinuxSampler {
1224      VMFnResult* InstrumentScriptVMFunction_change_tune_time::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_tune_time::exec(VMFnArgs* args) {
1225          return VMChangeSynthParamFunction::execTemplate<          return VMChangeSynthParamFunction::execTemplate<
1226                      &NoteBase::_Override::PitchTime,                      &NoteBase::_Override::PitchTime,
1227                      Event::synth_param_pitch_time, false>( args, "change_tune_time" );                      Event::synth_param_pitch_time,
1228                        false, NO_LIMIT, 0>( args, "change_tune_time" );
1229        }
1230    
1231        // template for change_*_curve() functions
1232    
1233        bool VMChangeFadeCurveFunction::acceptsArgType(int iArg, ExprType_t type) const {
1234            if (iArg == 0)
1235                return type == INT_EXPR || type == INT_ARR_EXPR;
1236            else
1237                return type == INT_EXPR;
1238        }
1239    
1240        template<fade_curve_t NoteBase::_Override::*T_noteParam, int T_synthParam>
1241        VMFnResult* VMChangeFadeCurveFunction::execTemplate(VMFnArgs* args, const char* functionName) {
1242            int value = args->arg(1)->asInt()->evalInt();
1243            switch (value) {
1244                case FADE_CURVE_LINEAR:
1245                case FADE_CURVE_EASE_IN_EASE_OUT:
1246                    break;
1247                default:
1248                    wrnMsg(String(functionName) + "(): invalid curve type passed as argument 2");
1249                    return successResult();
1250            }
1251    
1252            AbstractEngineChannel* pEngineChannel =
1253                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1254    
1255            if (args->arg(0)->exprType() == INT_EXPR) {
1256                const ScriptID id = args->arg(0)->asInt()->evalInt();
1257                if (!id) {
1258                    wrnMsg(String(functionName) + "(): note ID for argument 1 may not be zero");
1259                    return successResult();
1260                }
1261                if (!id.isNoteID()) {
1262                    wrnMsg(String(functionName) + "(): argument 1 is not a note ID");
1263                    return successResult();
1264                }
1265    
1266                NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1267                if (!pNote) return successResult();
1268    
1269                // if this change_*_curve() script function was called immediately after
1270                // note was triggered then immediately apply the synth parameter
1271                // change to Note object
1272                if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1273                    pNote->Override.*T_noteParam = (fade_curve_t) value;
1274                } else { // otherwise schedule this synth parameter change ...
1275                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1276                    e.Init(); // clear IDs
1277                    e.Type = Event::type_note_synth_param;
1278                    e.Param.NoteSynthParam.NoteID   = id.noteID();
1279                    e.Param.NoteSynthParam.Type     = (Event::synth_param_t) T_synthParam;
1280                    e.Param.NoteSynthParam.Delta    = value;
1281                    e.Param.NoteSynthParam.Relative = false;
1282    
1283                    pEngineChannel->ScheduleEventMicroSec(&e, 0);
1284                }
1285            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
1286                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
1287                for (int i = 0; i < ids->arraySize(); ++i) {
1288                    const ScriptID id = ids->evalIntElement(i);
1289                    if (!id || !id.isNoteID()) continue;
1290    
1291                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1292                    if (!pNote) continue;
1293    
1294                    // if this change_*_curve() script function was called immediately after
1295                    // note was triggered then immediately apply the synth parameter
1296                    // change to Note object
1297                    if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1298                        pNote->Override.*T_noteParam = (fade_curve_t) value;
1299                    } else { // otherwise schedule this synth parameter change ...
1300                        Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1301                        e.Init(); // clear IDs
1302                        e.Type = Event::type_note_synth_param;
1303                        e.Param.NoteSynthParam.NoteID   = id.noteID();
1304                        e.Param.NoteSynthParam.Type     = (Event::synth_param_t) T_synthParam;
1305                        e.Param.NoteSynthParam.Delta    = value;
1306                        e.Param.NoteSynthParam.Relative = false;
1307    
1308                        pEngineChannel->ScheduleEventMicroSec(&e, 0);
1309                    }
1310                }
1311            }
1312    
1313            return successResult();
1314        }
1315    
1316        // change_vol_curve() function
1317    
1318        VMFnResult* InstrumentScriptVMFunction_change_vol_curve::exec(VMFnArgs* args) {
1319            return VMChangeFadeCurveFunction::execTemplate<
1320                        &NoteBase::_Override::VolumeCurve,
1321                        Event::synth_param_volume_curve>( args, "change_vol_curve" );
1322        }
1323    
1324        // change_tune_curve() function
1325    
1326        VMFnResult* InstrumentScriptVMFunction_change_tune_curve::exec(VMFnArgs* args) {
1327            return VMChangeFadeCurveFunction::execTemplate<
1328                        &NoteBase::_Override::PitchCurve,
1329                        Event::synth_param_pitch_curve>( args, "change_tune_curve" );
1330      }      }
1331    
1332      // fade_in() function      // fade_in() function
# Line 1238  namespace LinuxSampler { Line 1371  namespace LinuxSampler {
1371              // if fade_in() was called immediately after note was triggered              // if fade_in() was called immediately after note was triggered
1372              // then immediately apply a start volume of zero to Note object,              // then immediately apply a start volume of zero to Note object,
1373              // as well as the fade in duration              // as well as the fade in duration
1374              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1375                  pNote->Override.Volume = 0.f;                  pNote->Override.Volume = 0.f;
1376                  pNote->Override.VolumeTime = fDuration;                  pNote->Override.VolumeTime = fDuration;
1377              } 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 ...
# Line 1280  namespace LinuxSampler { Line 1413  namespace LinuxSampler {
1413                  // if fade_in() was called immediately after note was triggered                  // if fade_in() was called immediately after note was triggered
1414                  // then immediately apply a start volume of zero to Note object,                  // then immediately apply a start volume of zero to Note object,
1415                  // as well as the fade in duration                  // as well as the fade in duration
1416                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1417                      pNote->Override.Volume = 0.f;                      pNote->Override.Volume = 0.f;
1418                      pNote->Override.VolumeTime = fDuration;                      pNote->Override.VolumeTime = fDuration;
1419                  } 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 ...
# Line 1359  namespace LinuxSampler { Line 1492  namespace LinuxSampler {
1492    
1493              // if fade_out() was called immediately after note was triggered              // if fade_out() was called immediately after note was triggered
1494              // then immediately apply fade out duration to Note object              // then immediately apply fade out duration to Note object
1495              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1496                  pNote->Override.VolumeTime = fDuration;                  pNote->Override.VolumeTime = fDuration;
1497              } else { // otherwise schedule a "volume time" change with the requested fade out duration ...              } else { // otherwise schedule a "volume time" change with the requested fade out duration ...
1498                  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 1411  namespace LinuxSampler { Line 1544  namespace LinuxSampler {
1544    
1545                  // if fade_out() was called immediately after note was triggered                  // if fade_out() was called immediately after note was triggered
1546                  // then immediately apply fade out duration to Note object                  // then immediately apply fade out duration to Note object
1547                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1548                      pNote->Override.VolumeTime = fDuration;                      pNote->Override.VolumeTime = fDuration;
1549                  } else { // otherwise schedule a "volume time" change with the requested fade out duration ...                  } else { // otherwise schedule a "volume time" change with the requested fade out duration ...
1550                      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 1458  namespace LinuxSampler { Line 1591  namespace LinuxSampler {
1591          return successResult();          return successResult();
1592      }      }
1593    
1594        // get_event_par() function
1595    
1596        InstrumentScriptVMFunction_get_event_par::InstrumentScriptVMFunction_get_event_par(InstrumentScriptVM* parent)
1597            : m_vm(parent)
1598        {
1599        }
1600    
1601        VMFnResult* InstrumentScriptVMFunction_get_event_par::exec(VMFnArgs* args) {
1602            AbstractEngineChannel* pEngineChannel =
1603                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1604    
1605            const ScriptID id = args->arg(0)->asInt()->evalInt();
1606            if (!id) {
1607                wrnMsg("get_event_par(): note ID for argument 1 may not be zero");
1608                return successResult(0);
1609            }
1610            if (!id.isNoteID()) {
1611                wrnMsg("get_event_par(): argument 1 is not a note ID");
1612                return successResult(0);
1613            }
1614    
1615            NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1616            if (!pNote) {
1617                wrnMsg("get_event_par(): no note alive with that note ID of argument 1");
1618                return successResult(0);
1619            }
1620    
1621            const int parameter = args->arg(1)->asInt()->evalInt();
1622            switch (parameter) {
1623                case EVENT_PAR_NOTE:
1624                    return successResult(pNote->cause.Param.Note.Key);
1625                case EVENT_PAR_VELOCITY:
1626                    return successResult(pNote->cause.Param.Note.Velocity);
1627                case EVENT_PAR_VOLUME:
1628                    return successResult(
1629                        RTMath::LinRatioToDecibel(pNote->Override.Volume) * 1000.f
1630                    );
1631                case EVENT_PAR_TUNE:
1632                    return successResult(
1633                         RTMath::FreqRatioToCents(pNote->Override.Pitch) * 1000.f
1634                    );
1635                case EVENT_PAR_0:
1636                    return successResult(pNote->userPar[0]);
1637                case EVENT_PAR_1:
1638                    return successResult(pNote->userPar[1]);
1639                case EVENT_PAR_2:
1640                    return successResult(pNote->userPar[2]);
1641                case EVENT_PAR_3:
1642                    return successResult(pNote->userPar[3]);
1643            }
1644    
1645            wrnMsg("get_event_par(): argument 2 is an invalid event parameter");
1646            return successResult(0);
1647        }
1648    
1649        // set_event_par() function
1650    
1651        InstrumentScriptVMFunction_set_event_par::InstrumentScriptVMFunction_set_event_par(InstrumentScriptVM* parent)
1652            : m_vm(parent)
1653        {
1654        }
1655    
1656        VMFnResult* InstrumentScriptVMFunction_set_event_par::exec(VMFnArgs* args) {
1657            AbstractEngineChannel* pEngineChannel =
1658                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1659    
1660            const ScriptID id = args->arg(0)->asInt()->evalInt();
1661            if (!id) {
1662                wrnMsg("set_event_par(): note ID for argument 1 may not be zero");
1663                return successResult();
1664            }
1665            if (!id.isNoteID()) {
1666                wrnMsg("set_event_par(): argument 1 is not a note ID");
1667                return successResult();
1668            }
1669    
1670            NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1671            if (!pNote) return successResult();
1672    
1673            const int parameter = args->arg(1)->asInt()->evalInt();
1674            const int value     = args->arg(2)->asInt()->evalInt();
1675    
1676            switch (parameter) {
1677                case EVENT_PAR_NOTE:
1678                    if (value < 0 || value > 127) {
1679                        wrnMsg("set_event_par(): note number of argument 3 is out of range");
1680                        return successResult();
1681                    }
1682                    if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1683                        pNote->cause.Param.Note.Key = value;
1684                        m_vm->m_event->cause.Param.Note.Key = value;
1685                    } else {
1686                        wrnMsg("set_event_par(): note number can only be changed when note is new");
1687                    }
1688                    return successResult();
1689                case EVENT_PAR_VELOCITY:
1690                    if (value < 0 || value > 127) {
1691                        wrnMsg("set_event_par(): velocity of argument 3 is out of range");
1692                        return successResult();
1693                    }
1694                    if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1695                        pNote->cause.Param.Note.Velocity = value;
1696                        m_vm->m_event->cause.Param.Note.Velocity = value;
1697                    } else {
1698                        wrnMsg("set_event_par(): velocity can only be changed when note is new");
1699                    }
1700                    return successResult();
1701                case EVENT_PAR_VOLUME:
1702                    wrnMsg("set_event_par(): changing volume by this function is currently not supported, use change_vol() instead");
1703                    return successResult();
1704                case EVENT_PAR_TUNE:
1705                    wrnMsg("set_event_par(): changing tune by this function is currently not supported, use change_tune() instead");
1706                    return successResult();
1707                case EVENT_PAR_0:
1708                    pNote->userPar[0] = value;
1709                    return successResult();
1710                case EVENT_PAR_1:
1711                    pNote->userPar[1] = value;
1712                    return successResult();
1713                case EVENT_PAR_2:
1714                    pNote->userPar[2] = value;
1715                    return successResult();
1716                case EVENT_PAR_3:
1717                    pNote->userPar[3] = value;
1718                    return successResult();
1719            }
1720    
1721            wrnMsg("set_event_par(): argument 2 is an invalid event parameter");
1722            return successResult();
1723        }
1724    
1725        // change_note() function
1726    
1727        InstrumentScriptVMFunction_change_note::InstrumentScriptVMFunction_change_note(InstrumentScriptVM* parent)
1728        : m_vm(parent)
1729        {
1730        }
1731    
1732        VMFnResult* InstrumentScriptVMFunction_change_note::exec(VMFnArgs* args) {
1733            AbstractEngineChannel* pEngineChannel =
1734                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1735    
1736            const ScriptID id = args->arg(0)->asInt()->evalInt();
1737            if (!id) {
1738                wrnMsg("change_note(): note ID for argument 1 may not be zero");
1739                return successResult();
1740            }
1741            if (!id.isNoteID()) {
1742                wrnMsg("change_note(): argument 1 is not a note ID");
1743                return successResult();
1744            }
1745    
1746            NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1747            if (!pNote) return successResult();
1748    
1749            const int value = args->arg(1)->asInt()->evalInt();
1750            if (value < 0 || value > 127) {
1751                wrnMsg("change_note(): note number of argument 2 is out of range");
1752                return successResult();
1753            }
1754    
1755            if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1756                pNote->cause.Param.Note.Key = value;
1757                m_vm->m_event->cause.Param.Note.Key = value;
1758            } else {
1759                wrnMsg("change_note(): note number can only be changed when note is new");
1760            }
1761    
1762            return successResult();
1763        }
1764    
1765        // change_velo() function
1766    
1767        InstrumentScriptVMFunction_change_velo::InstrumentScriptVMFunction_change_velo(InstrumentScriptVM* parent)
1768        : m_vm(parent)
1769        {
1770        }
1771    
1772        VMFnResult* InstrumentScriptVMFunction_change_velo::exec(VMFnArgs* args) {
1773            AbstractEngineChannel* pEngineChannel =
1774                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1775    
1776            const ScriptID id = args->arg(0)->asInt()->evalInt();
1777            if (!id) {
1778                wrnMsg("change_velo(): note ID for argument 1 may not be zero");
1779                return successResult();
1780            }
1781            if (!id.isNoteID()) {
1782                wrnMsg("change_velo(): argument 1 is not a note ID");
1783                return successResult();
1784            }
1785    
1786            NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1787            if (!pNote) return successResult();
1788    
1789            const int value = args->arg(1)->asInt()->evalInt();
1790            if (value < 0 || value > 127) {
1791                wrnMsg("change_velo(): velocity of argument 2 is out of range");
1792                return successResult();
1793            }
1794    
1795            if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1796                pNote->cause.Param.Note.Velocity = value;
1797                m_vm->m_event->cause.Param.Note.Velocity = value;
1798            } else {
1799                wrnMsg("change_velo(): velocity can only be changed when note is new");
1800            }
1801    
1802            return successResult();
1803        }
1804    
1805        // change_play_pos() function
1806    
1807        InstrumentScriptVMFunction_change_play_pos::InstrumentScriptVMFunction_change_play_pos(InstrumentScriptVM* parent)
1808        : m_vm(parent)
1809        {
1810        }
1811    
1812        VMFnResult* InstrumentScriptVMFunction_change_play_pos::exec(VMFnArgs* args) {
1813            const ScriptID id = args->arg(0)->asInt()->evalInt();
1814            if (!id) {
1815                wrnMsg("change_play_pos(): note ID for argument 1 may not be zero");
1816                return successResult();
1817            }
1818            if (!id.isNoteID()) {
1819                wrnMsg("change_play_pos(): argument 1 is not a note ID");
1820                return successResult();
1821            }
1822    
1823            const int pos = args->arg(1)->asInt()->evalInt();
1824            if (pos < 0) {
1825                wrnMsg("change_play_pos(): playback position of argument 2 may not be negative");
1826                return successResult();
1827            }
1828    
1829            AbstractEngineChannel* pEngineChannel =
1830                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1831    
1832            NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1833            if (!pNote) return successResult();
1834    
1835            pNote->Override.SampleOffset = pos;
1836    
1837            return successResult();
1838        }
1839    
1840      // event_status() function      // event_status() function
1841    
1842      InstrumentScriptVMFunction_event_status::InstrumentScriptVMFunction_event_status(InstrumentScriptVM* parent)      InstrumentScriptVMFunction_event_status::InstrumentScriptVMFunction_event_status(InstrumentScriptVM* parent)
# Line 1483  namespace LinuxSampler { Line 1862  namespace LinuxSampler {
1862          return successResult(pNote ? EVENT_STATUS_NOTE_QUEUE : EVENT_STATUS_INACTIVE);          return successResult(pNote ? EVENT_STATUS_NOTE_QUEUE : EVENT_STATUS_INACTIVE);
1863      }      }
1864    
1865        // callback_status() function
1866    
1867        InstrumentScriptVMFunction_callback_status::InstrumentScriptVMFunction_callback_status(InstrumentScriptVM* parent)
1868            : m_vm(parent)
1869        {
1870        }
1871    
1872        VMFnResult* InstrumentScriptVMFunction_callback_status::exec(VMFnArgs* args) {
1873            const script_callback_id_t id = args->arg(0)->asInt()->evalInt();
1874            if (!id) {
1875                wrnMsg("callback_status(): callback ID for argument 1 may not be zero");
1876                return successResult();
1877            }
1878    
1879            AbstractEngineChannel* pEngineChannel =
1880                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1881    
1882            RTList<ScriptEvent>::Iterator itCallback = pEngineChannel->ScriptCallbackByID(id);
1883            if (!itCallback)
1884                return successResult(CALLBACK_STATUS_TERMINATED);
1885    
1886            return successResult(
1887                (m_vm->m_event->execCtx == itCallback->execCtx) ?
1888                    CALLBACK_STATUS_RUNNING : CALLBACK_STATUS_QUEUE
1889            );
1890        }
1891    
1892      // wait() function (overrides core wait() implementation)      // wait() function (overrides core wait() implementation)
1893    
1894      InstrumentScriptVMFunction_wait::InstrumentScriptVMFunction_wait(InstrumentScriptVM* parent)      InstrumentScriptVMFunction_wait::InstrumentScriptVMFunction_wait(InstrumentScriptVM* parent)
# Line 1523  namespace LinuxSampler { Line 1929  namespace LinuxSampler {
1929              (args->argsCount() >= 2) ? (args->arg(1)->asInt()->evalInt() == 1) : false;              (args->argsCount() >= 2) ? (args->arg(1)->asInt()->evalInt() == 1) : false;
1930    
1931          pEngineChannel->ScheduleResumeOfScriptCallback(          pEngineChannel->ScheduleResumeOfScriptCallback(
1932              itCallback, m_vm->m_event->cause.SchedTime(), disableWaitForever              itCallback, m_vm->m_event->scheduleTime, disableWaitForever
1933          );          );
1934    
1935          return successResult();          return successResult();
1936      }      }
1937    
1938        // abort() function
1939    
1940        InstrumentScriptVMFunction_abort::InstrumentScriptVMFunction_abort(InstrumentScriptVM* parent)
1941            : m_vm(parent)
1942        {
1943        }
1944    
1945        VMFnResult* InstrumentScriptVMFunction_abort::exec(VMFnArgs* args) {
1946            const script_callback_id_t id = args->arg(0)->asInt()->evalInt();
1947            if (!id) {
1948                wrnMsg("abort(): callback ID for argument 1 may not be zero");
1949                return successResult();
1950            }
1951    
1952            AbstractEngineChannel* pEngineChannel =
1953                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1954    
1955            RTList<ScriptEvent>::Iterator itCallback = pEngineChannel->ScriptCallbackByID(id);
1956            if (!itCallback) return successResult(); // ignore if callback is i.e. not alive anymore
1957    
1958            itCallback->execCtx->signalAbort();
1959    
1960            return successResult();
1961        }
1962    
1963        // fork() function
1964    
1965        InstrumentScriptVMFunction_fork::InstrumentScriptVMFunction_fork(InstrumentScriptVM* parent)
1966            : m_vm(parent)
1967        {
1968        }
1969    
1970        VMFnResult* InstrumentScriptVMFunction_fork::exec(VMFnArgs* args) {
1971            // check if this is actually the parent going to fork, or rather one of
1972            // the children which is already forked
1973            if (m_vm->m_event->forkIndex != 0) { // this is the entry point for a child ...
1974                int forkResult = m_vm->m_event->forkIndex;
1975                // reset so that this child may i.e. also call fork() later on
1976                m_vm->m_event->forkIndex = 0;
1977                return successResult(forkResult);
1978            }
1979    
1980            // if we are here, then this is the parent, so we must fork this parent
1981    
1982            const int n =
1983                (args->argsCount() >= 1) ? args->arg(0)->asInt()->evalInt() : 1;
1984            const bool bAutoAbort =
1985                (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : true;
1986    
1987            if (m_vm->m_event->countChildHandlers() + n > MAX_FORK_PER_SCRIPT_HANDLER) {
1988                wrnMsg("fork(): requested amount would exceed allowed limit per event handler");
1989                return successResult(-1);
1990            }
1991    
1992            AbstractEngineChannel* pEngineChannel =
1993                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1994    
1995            if (!pEngineChannel->hasFreeScriptCallbacks(n)) {
1996                wrnMsg("fork(): global limit of event handlers exceeded");
1997                return successResult(-1);
1998            }
1999    
2000            for (int iChild = 0; iChild < n; ++iChild) {
2001                RTList<ScriptEvent>::Iterator itChild =
2002                    pEngineChannel->forkScriptCallback(m_vm->m_event, bAutoAbort);
2003                if (!itChild) { // should never happen, otherwise its a bug ...
2004                    errMsg("fork(): internal error while allocating child");
2005                    return errorResult(-1); // terminate script
2006                }
2007                // since both parent, as well all child script execution instances
2008                // all land in this exect() method, the following is (more or less)
2009                // the only feature that lets us distinguish the parent and
2010                // respective children from each other in this exect() method
2011                itChild->forkIndex = iChild + 1;
2012            }
2013    
2014            return successResult(0);
2015        }
2016    
2017  } // namespace LinuxSampler  } // namespace LinuxSampler

Legend:
Removed from v.3188  
changed lines
  Added in v.3303

  ViewVC Help
Powered by ViewVC