/[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 3212 by schoenebeck, Thu May 25 13:17:47 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 386  namespace LinuxSampler { Line 386  namespace LinuxSampler {
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
389              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
390                  if (relative)                  if (relative)
391                      pNote->Override.Volume *= fVolumeLin;                      pNote->Override.Volume *= fVolumeLin;
392                  else                  else
# Line 413  namespace LinuxSampler { Line 413  namespace LinuxSampler {
413    
414                  // if change_vol() was called immediately after note was triggered                  // if change_vol() was called immediately after note was triggered
415                  // then immediately apply the volume to Note object                  // then immediately apply the volume to Note object
416                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
417                      if (relative)                      if (relative)
418                          pNote->Override.Volume *= fVolumeLin;                          pNote->Override.Volume *= fVolumeLin;
419                      else                      else
# Line 446  namespace LinuxSampler { Line 446  namespace LinuxSampler {
446          if (iArg == 0)          if (iArg == 0)
447              return type == INT_EXPR || type == INT_ARR_EXPR;              return type == INT_EXPR || type == INT_ARR_EXPR;
448          else          else
449              return INT_EXPR;              return type == INT_EXPR;
450      }      }
451    
452      VMFnResult* InstrumentScriptVMFunction_change_tune::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_tune::exec(VMFnArgs* args) {
# Line 473  namespace LinuxSampler { Line 473  namespace LinuxSampler {
473    
474              // if change_tune() was called immediately after note was triggered              // if change_tune() was called immediately after note was triggered
475              // then immediately apply the tuning to Note object              // then immediately apply the tuning to Note object
476              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
477                  if (relative)                  if (relative)
478                      pNote->Override.Pitch *= fFreqRatio;                      pNote->Override.Pitch *= fFreqRatio;
479                  else                  else
# Line 500  namespace LinuxSampler { Line 500  namespace LinuxSampler {
500    
501                  // if change_tune() was called immediately after note was triggered                  // if change_tune() was called immediately after note was triggered
502                  // then immediately apply the tuning to Note object                  // then immediately apply the tuning to Note object
503                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
504                      if (relative)                      if (relative)
505                          pNote->Override.Pitch *= fFreqRatio;                          pNote->Override.Pitch *= fFreqRatio;
506                      else                      else
# Line 533  namespace LinuxSampler { Line 533  namespace LinuxSampler {
533          if (iArg == 0)          if (iArg == 0)
534              return type == INT_EXPR || type == INT_ARR_EXPR;              return type == INT_EXPR || type == INT_ARR_EXPR;
535          else          else
536              return INT_EXPR;              return type == INT_EXPR;
537      }      }
538    
539      VMFnResult* InstrumentScriptVMFunction_change_pan::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_pan::exec(VMFnArgs* args) {
# Line 568  namespace LinuxSampler { Line 568  namespace LinuxSampler {
568    
569              // if change_pan() was called immediately after note was triggered              // if change_pan() was called immediately after note was triggered
570              // then immediately apply the panning to Note object              // then immediately apply the panning to Note object
571              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
572                  if (relative) {                  if (relative) {
573                      pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);                      pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);
574                  } else {                  } else {
# Line 597  namespace LinuxSampler { Line 597  namespace LinuxSampler {
597    
598                  // if change_pan() was called immediately after note was triggered                  // if change_pan() was called immediately after note was triggered
599                  // then immediately apply the panning to Note object                  // then immediately apply the panning to Note object
600                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
601                      if (relative) {                      if (relative) {
602                          pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);                          pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);
603                      } else {                      } else {
# Line 635  namespace LinuxSampler { Line 635  namespace LinuxSampler {
635          if (iArg == 0)          if (iArg == 0)
636              return type == INT_EXPR || type == INT_ARR_EXPR;              return type == INT_EXPR || type == INT_ARR_EXPR;
637          else          else
638              return INT_EXPR;              return type == INT_EXPR;
639      }      }
640    
641      VMFnResult* InstrumentScriptVMFunction_change_cutoff::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_cutoff::exec(VMFnArgs* args) {
# Line 668  namespace LinuxSampler { Line 668  namespace LinuxSampler {
668    
669              // if change_cutoff() was called immediately after note was triggered              // if change_cutoff() was called immediately after note was triggered
670              // then immediately apply cutoff to Note object              // then immediately apply cutoff to Note object
671              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
672                  pNote->Override.Cutoff = fCutoff;                  pNote->Override.Cutoff = fCutoff;
673              } else { // otherwise schedule cutoff change ...              } else { // otherwise schedule cutoff change ...
674                  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 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 722  namespace LinuxSampler { Line 722  namespace LinuxSampler {
722          if (iArg == 0)          if (iArg == 0)
723              return type == INT_EXPR || type == INT_ARR_EXPR;              return type == INT_EXPR || type == INT_ARR_EXPR;
724          else          else
725              return INT_EXPR;              return type == INT_EXPR;
726      }      }
727    
728      VMFnResult* InstrumentScriptVMFunction_change_reso::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_reso::exec(VMFnArgs* args) {
# Line 755  namespace LinuxSampler { Line 755  namespace LinuxSampler {
755    
756              // if change_reso() was called immediately after note was triggered              // if change_reso() was called immediately after note was triggered
757              // then immediately apply resonance to Note object              // then immediately apply resonance to Note object
758              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
759                  pNote->Override.Resonance = fResonance;                  pNote->Override.Resonance = fResonance;
760              } else { // otherwise schedule resonance change ...              } else { // otherwise schedule resonance change ...
761                  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 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 809  namespace LinuxSampler { Line 809  namespace LinuxSampler {
809          if (iArg == 0)          if (iArg == 0)
810              return type == INT_EXPR || type == INT_ARR_EXPR;              return type == INT_EXPR || type == INT_ARR_EXPR;
811          else          else
812              return INT_EXPR;              return type == INT_EXPR;
813      }      }
814    
815      VMFnResult* InstrumentScriptVMFunction_change_attack::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_attack::exec(VMFnArgs* args) {
# Line 842  namespace LinuxSampler { Line 842  namespace LinuxSampler {
842    
843              // if change_attack() was called immediately after note was triggered              // if change_attack() was called immediately after note was triggered
844              // then immediately apply attack to Note object              // then immediately apply attack to Note object
845              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
846                  pNote->Override.Attack = fAttack;                  pNote->Override.Attack = fAttack;
847              } else { // otherwise schedule attack change ...              } else { // otherwise schedule attack change ...
848                  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 866  namespace LinuxSampler {
866    
867                  // if change_attack() was called immediately after note was triggered                  // if change_attack() was called immediately after note was triggered
868                  // then immediately apply attack to Note object                  // then immediately apply attack to Note object
869                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
870                      pNote->Override.Attack = fAttack;                      pNote->Override.Attack = fAttack;
871                  } else { // otherwise schedule attack change ...                  } else { // otherwise schedule attack change ...
872                      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 896  namespace LinuxSampler {
896          if (iArg == 0)          if (iArg == 0)
897              return type == INT_EXPR || type == INT_ARR_EXPR;              return type == INT_EXPR || type == INT_ARR_EXPR;
898          else          else
899              return INT_EXPR;              return type == INT_EXPR;
900      }      }
901    
902      VMFnResult* InstrumentScriptVMFunction_change_decay::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_decay::exec(VMFnArgs* args) {
# Line 929  namespace LinuxSampler { Line 929  namespace LinuxSampler {
929    
930              // if change_decay() was called immediately after note was triggered              // if change_decay() was called immediately after note was triggered
931              // then immediately apply decay to Note object              // then immediately apply decay to Note object
932              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
933                  pNote->Override.Decay = fDecay;                  pNote->Override.Decay = fDecay;
934              } else { // otherwise schedule decay change ...              } else { // otherwise schedule decay change ...
935                  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 953  namespace LinuxSampler {
953    
954                  // if change_decay() was called immediately after note was triggered                  // if change_decay() was called immediately after note was triggered
955                  // then immediately apply decay to Note object                  // then immediately apply decay to Note object
956                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
957                      pNote->Override.Decay = fDecay;                      pNote->Override.Decay = fDecay;
958                  } else { // otherwise schedule decay change ...                  } else { // otherwise schedule decay change ...
959                      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 983  namespace LinuxSampler {
983          if (iArg == 0)          if (iArg == 0)
984              return type == INT_EXPR || type == INT_ARR_EXPR;              return type == INT_EXPR || type == INT_ARR_EXPR;
985          else          else
986              return INT_EXPR;              return type == INT_EXPR;
987      }      }
988    
989      VMFnResult* InstrumentScriptVMFunction_change_release::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_release::exec(VMFnArgs* args) {
# Line 1016  namespace LinuxSampler { Line 1016  namespace LinuxSampler {
1016    
1017              // if change_release() was called immediately after note was triggered              // if change_release() was called immediately after note was triggered
1018              // then immediately apply relase to Note object              // then immediately apply relase to Note object
1019              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {              if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1020                  pNote->Override.Release = fRelease;                  pNote->Override.Release = fRelease;
1021              } else { // otherwise schedule release change ...              } else { // otherwise schedule release change ...
1022                  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 1040  namespace LinuxSampler {
1040    
1041                  // if change_release() was called immediately after note was triggered                  // if change_release() was called immediately after note was triggered
1042                  // then immediately apply relase to Note object                  // then immediately apply relase to Note object
1043                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {                  if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1044                      pNote->Override.Release = fRelease;                      pNote->Override.Release = fRelease;
1045                  } else { // otherwise schedule release change ...                  } else { // otherwise schedule release change ...
1046                      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 1059  namespace LinuxSampler {
1059          return successResult();          return successResult();
1060      }      }
1061    
1062        bool VMChangeSynthParamFunction::acceptsArgType(int iArg, ExprType_t type) const {
1063            if (iArg == 0)
1064                return type == INT_EXPR || type == INT_ARR_EXPR;
1065            else
1066                return type == INT_EXPR;
1067        }
1068    
1069        // Arbitrarily chosen constant value symbolizing "no limit".
1070        #define NO_LIMIT 1315916909
1071    
1072        template<float NoteBase::_Override::*T_noteParam, int T_synthParam,
1073                 bool T_isNormalizedParam, int T_maxValue, int T_minValue>
1074        VMFnResult* VMChangeSynthParamFunction::execTemplate(VMFnArgs* args, const char* functionName) {
1075            int value = args->arg(1)->asInt()->evalInt();
1076            if (T_maxValue != NO_LIMIT && value > T_maxValue) {
1077                wrnMsg(String(functionName) + "(): argument 2 may not be larger than " + ToString(T_maxValue));
1078                value = T_maxValue;
1079            } else if (T_minValue != NO_LIMIT && value < T_minValue) {
1080                if (T_minValue == 0)
1081                    wrnMsg(String(functionName) + "(): argument 2 may not be negative");
1082                else
1083                    wrnMsg(String(functionName) + "(): argument 2 may not be smaller than " + ToString(T_minValue));
1084                value = T_minValue;
1085            }
1086            const float fValue = (T_isNormalizedParam) ?
1087                float(value) / float(T_maxValue) : // convert to 0.0 .. 1.0 value range
1088                float(value) / 1000000.f; // assuming microseconds here, convert to seconds
1089    
1090            AbstractEngineChannel* pEngineChannel =
1091                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1092    
1093            if (args->arg(0)->exprType() == INT_EXPR) {
1094                const ScriptID id = args->arg(0)->asInt()->evalInt();
1095                if (!id) {
1096                    wrnMsg(String(functionName) + "(): note ID for argument 1 may not be zero");
1097                    return successResult();
1098                }
1099                if (!id.isNoteID()) {
1100                    wrnMsg(String(functionName) + "(): argument 1 is not a note ID");
1101                    return successResult();
1102                }
1103    
1104                NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1105                if (!pNote) return successResult();
1106    
1107                // if this change_*() script function was called immediately after
1108                // note was triggered then immediately apply the synth parameter
1109                // change to Note object
1110                if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1111                    pNote->Override.*T_noteParam = fValue;
1112                } else { // otherwise schedule this synth parameter change ...
1113                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1114                    e.Init(); // clear IDs
1115                    e.Type = Event::type_note_synth_param;
1116                    e.Param.NoteSynthParam.NoteID   = id.noteID();
1117                    e.Param.NoteSynthParam.Type     = (Event::synth_param_t) T_synthParam;
1118                    e.Param.NoteSynthParam.Delta    = fValue;
1119                    e.Param.NoteSynthParam.Relative = false;
1120    
1121                    pEngineChannel->ScheduleEventMicroSec(&e, 0);
1122                }
1123            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
1124                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
1125                for (int i = 0; i < ids->arraySize(); ++i) {
1126                    const ScriptID id = ids->evalIntElement(i);
1127                    if (!id || !id.isNoteID()) continue;
1128    
1129                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1130                    if (!pNote) continue;
1131    
1132                    // if this change_*() script function was called immediately after
1133                    // note was triggered then immediately apply the synth parameter
1134                    // change to Note object
1135                    if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1136                        pNote->Override.*T_noteParam = fValue;
1137                    } else { // otherwise schedule this synth parameter change ...
1138                        Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1139                        e.Init(); // clear IDs
1140                        e.Type = Event::type_note_synth_param;
1141                        e.Param.NoteSynthParam.NoteID   = id.noteID();
1142                        e.Param.NoteSynthParam.Type     = (Event::synth_param_t) T_synthParam;
1143                        e.Param.NoteSynthParam.Delta    = fValue;
1144                        e.Param.NoteSynthParam.Relative = false;
1145    
1146                        pEngineChannel->ScheduleEventMicroSec(&e, 0);
1147                    }
1148                }
1149            }
1150    
1151            return successResult();
1152        }
1153    
1154        // change_amp_lfo_depth() function
1155    
1156        VMFnResult* InstrumentScriptVMFunction_change_amp_lfo_depth::exec(VMFnArgs* args) {
1157            return VMChangeSynthParamFunction::execTemplate<
1158                        &NoteBase::_Override::AmpLFODepth,
1159                        Event::synth_param_amp_lfo_depth,
1160                        true, 1000000, 0>( args, "change_amp_lfo_depth" );
1161        }
1162    
1163        // change_amp_lfo_freq() function
1164    
1165        VMFnResult* InstrumentScriptVMFunction_change_amp_lfo_freq::exec(VMFnArgs* args) {
1166            return VMChangeSynthParamFunction::execTemplate<
1167                        &NoteBase::_Override::AmpLFOFreq,
1168                        Event::synth_param_amp_lfo_freq,
1169                        true, 1000000, 0>( args, "change_amp_lfo_freq" );
1170        }
1171    
1172        // change_pitch_lfo_depth() function
1173    
1174        VMFnResult* InstrumentScriptVMFunction_change_pitch_lfo_depth::exec(VMFnArgs* args) {
1175            return VMChangeSynthParamFunction::execTemplate<
1176                        &NoteBase::_Override::PitchLFODepth,
1177                        Event::synth_param_pitch_lfo_depth,
1178                        true, 1000000, 0>( args, "change_pitch_lfo_depth" );
1179        }
1180    
1181        // change_pitch_lfo_freq() function
1182    
1183        VMFnResult* InstrumentScriptVMFunction_change_pitch_lfo_freq::exec(VMFnArgs* args) {
1184            return VMChangeSynthParamFunction::execTemplate<
1185                        &NoteBase::_Override::PitchLFOFreq,
1186                        Event::synth_param_pitch_lfo_freq,
1187                        true, 1000000, 0>( args, "change_pitch_lfo_freq" );
1188        }
1189    
1190        // change_vol_time() function
1191    
1192        VMFnResult* InstrumentScriptVMFunction_change_vol_time::exec(VMFnArgs* args) {
1193            return VMChangeSynthParamFunction::execTemplate<
1194                        &NoteBase::_Override::VolumeTime,
1195                        Event::synth_param_volume_time,
1196                        false, NO_LIMIT, 0>( args, "change_vol_time" );
1197        }
1198    
1199        // change_tune_time() function
1200    
1201        VMFnResult* InstrumentScriptVMFunction_change_tune_time::exec(VMFnArgs* args) {
1202            return VMChangeSynthParamFunction::execTemplate<
1203                        &NoteBase::_Override::PitchTime,
1204                        Event::synth_param_pitch_time,
1205                        false, NO_LIMIT, 0>( args, "change_tune_time" );
1206        }
1207    
1208        // fade_in() function
1209    
1210        InstrumentScriptVMFunction_fade_in::InstrumentScriptVMFunction_fade_in(InstrumentScriptVM* parent)
1211            : m_vm(parent)
1212        {
1213        }
1214    
1215        bool InstrumentScriptVMFunction_fade_in::acceptsArgType(int iArg, ExprType_t type) const {
1216            if (iArg == 0)
1217                return type == INT_EXPR || type == INT_ARR_EXPR;
1218            else
1219                return type == INT_EXPR;
1220        }
1221    
1222        VMFnResult* InstrumentScriptVMFunction_fade_in::exec(VMFnArgs* args) {
1223            int duration = args->arg(1)->asInt()->evalInt();
1224            if (duration < 0) {
1225                wrnMsg("fade_in(): argument 2 may not be negative");
1226                duration = 0;
1227            }
1228            const float fDuration = float(duration) / 1000000.f; // convert microseconds to seconds
1229    
1230            AbstractEngineChannel* pEngineChannel =
1231                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1232    
1233            if (args->arg(0)->exprType() == INT_EXPR) {
1234                const ScriptID id = args->arg(0)->asInt()->evalInt();
1235                if (!id) {
1236                    wrnMsg("fade_in(): note ID for argument 1 may not be zero");
1237                    return successResult();
1238                }
1239                if (!id.isNoteID()) {
1240                    wrnMsg("fade_in(): argument 1 is not a note ID");
1241                    return successResult();
1242                }
1243    
1244                NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1245                if (!pNote) return successResult();
1246    
1247                // if fade_in() was called immediately after note was triggered
1248                // then immediately apply a start volume of zero to Note object,
1249                // as well as the fade in duration
1250                if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1251                    pNote->Override.Volume = 0.f;
1252                    pNote->Override.VolumeTime = fDuration;
1253                } else { // otherwise schedule a "volume time" change with the requested fade in duration ...
1254                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1255                    e.Init(); // clear IDs
1256                    e.Type = Event::type_note_synth_param;
1257                    e.Param.NoteSynthParam.NoteID   = id.noteID();
1258                    e.Param.NoteSynthParam.Type     = Event::synth_param_volume_time;
1259                    e.Param.NoteSynthParam.Delta    = fDuration;
1260                    e.Param.NoteSynthParam.Relative = false;
1261    
1262                    pEngineChannel->ScheduleEventMicroSec(&e, 0);
1263                }
1264                // and finally schedule a "volume" change, simply one time slice
1265                // ahead, with the final fade in volume (1.0)
1266                {
1267                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1268                    e.Init(); // clear IDs
1269                    e.Type = Event::type_note_synth_param;
1270                    e.Param.NoteSynthParam.NoteID   = id.noteID();
1271                    e.Param.NoteSynthParam.Type     = Event::synth_param_volume;
1272                    e.Param.NoteSynthParam.Delta    = 1.f;
1273                    e.Param.NoteSynthParam.Relative = false;
1274    
1275                    // scheduling with 0 delay would also work here, but +1 is more
1276                    // safe regarding potential future implementation changes of the
1277                    // scheduler (see API comments of RTAVLTree::insert())
1278                    pEngineChannel->ScheduleEventMicroSec(&e, 1);
1279                }
1280            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
1281                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
1282                for (int i = 0; i < ids->arraySize(); ++i) {
1283                    const ScriptID id = ids->evalIntElement(i);
1284                    if (!id || !id.isNoteID()) continue;
1285    
1286                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1287                    if (!pNote) continue;
1288    
1289                    // if fade_in() was called immediately after note was triggered
1290                    // then immediately apply a start volume of zero to Note object,
1291                    // as well as the fade in duration
1292                    if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1293                        pNote->Override.Volume = 0.f;
1294                        pNote->Override.VolumeTime = fDuration;
1295                    } else { // otherwise schedule a "volume time" change with the requested fade in duration ...
1296                        Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1297                        e.Init(); // clear IDs
1298                        e.Type = Event::type_note_synth_param;
1299                        e.Param.NoteSynthParam.NoteID   = id.noteID();
1300                        e.Param.NoteSynthParam.Type     = Event::synth_param_volume_time;
1301                        e.Param.NoteSynthParam.Delta    = fDuration;
1302                        e.Param.NoteSynthParam.Relative = false;
1303    
1304                        pEngineChannel->ScheduleEventMicroSec(&e, 0);
1305                    }
1306                    // and finally schedule a "volume" change, simply one time slice
1307                    // ahead, with the final fade in volume (1.0)
1308                    {
1309                        Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1310                        e.Init(); // clear IDs
1311                        e.Type = Event::type_note_synth_param;
1312                        e.Param.NoteSynthParam.NoteID   = id.noteID();
1313                        e.Param.NoteSynthParam.Type     = Event::synth_param_volume;
1314                        e.Param.NoteSynthParam.Delta    = 1.f;
1315                        e.Param.NoteSynthParam.Relative = false;
1316    
1317                        // scheduling with 0 delay would also work here, but +1 is more
1318                        // safe regarding potential future implementation changes of the
1319                        // scheduler (see API comments of RTAVLTree::insert())
1320                        pEngineChannel->ScheduleEventMicroSec(&e, 1);
1321                    }
1322                }
1323            }
1324    
1325            return successResult();
1326        }
1327    
1328        // fade_out() function
1329    
1330        InstrumentScriptVMFunction_fade_out::InstrumentScriptVMFunction_fade_out(InstrumentScriptVM* parent)
1331            : m_vm(parent)
1332        {
1333        }
1334    
1335        bool InstrumentScriptVMFunction_fade_out::acceptsArgType(int iArg, ExprType_t type) const {
1336            if (iArg == 0)
1337                return type == INT_EXPR || type == INT_ARR_EXPR;
1338            else
1339                return type == INT_EXPR;
1340        }
1341    
1342        VMFnResult* InstrumentScriptVMFunction_fade_out::exec(VMFnArgs* args) {
1343            int duration = args->arg(1)->asInt()->evalInt();
1344            if (duration < 0) {
1345                wrnMsg("fade_out(): argument 2 may not be negative");
1346                duration = 0;
1347            }
1348            const float fDuration = float(duration) / 1000000.f; // convert microseconds to seconds
1349    
1350            bool stop = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : true;
1351    
1352            AbstractEngineChannel* pEngineChannel =
1353                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1354    
1355            if (args->arg(0)->exprType() == INT_EXPR) {
1356                const ScriptID id = args->arg(0)->asInt()->evalInt();
1357                if (!id) {
1358                    wrnMsg("fade_out(): note ID for argument 1 may not be zero");
1359                    return successResult();
1360                }
1361                if (!id.isNoteID()) {
1362                    wrnMsg("fade_out(): argument 1 is not a note ID");
1363                    return successResult();
1364                }
1365    
1366                NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1367                if (!pNote) return successResult();
1368    
1369                // if fade_out() was called immediately after note was triggered
1370                // then immediately apply fade out duration to Note object
1371                if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1372                    pNote->Override.VolumeTime = fDuration;
1373                } else { // otherwise schedule a "volume time" change with the requested fade out duration ...
1374                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1375                    e.Init(); // clear IDs
1376                    e.Type = Event::type_note_synth_param;
1377                    e.Param.NoteSynthParam.NoteID   = id.noteID();
1378                    e.Param.NoteSynthParam.Type     = Event::synth_param_volume_time;
1379                    e.Param.NoteSynthParam.Delta    = fDuration;
1380                    e.Param.NoteSynthParam.Relative = false;
1381    
1382                    pEngineChannel->ScheduleEventMicroSec(&e, 0);
1383                }
1384                // now schedule a "volume" change, simply one time slice ahead, with
1385                // the final fade out volume (0.0)
1386                {
1387                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1388                    e.Init(); // clear IDs
1389                    e.Type = Event::type_note_synth_param;
1390                    e.Param.NoteSynthParam.NoteID   = id.noteID();
1391                    e.Param.NoteSynthParam.Type     = Event::synth_param_volume;
1392                    e.Param.NoteSynthParam.Delta    = 0.f;
1393                    e.Param.NoteSynthParam.Relative = false;
1394    
1395                    // scheduling with 0 delay would also work here, but +1 is more
1396                    // safe regarding potential future implementation changes of the
1397                    // scheduler (see API comments of RTAVLTree::insert())
1398                    pEngineChannel->ScheduleEventMicroSec(&e, 1);
1399                }
1400                // and finally if stopping the note was requested after the fade out
1401                // completed, then schedule to kill the voice after the requested
1402                // duration
1403                if (stop) {
1404                    Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1405                    e.Init(); // clear IDs
1406                    e.Type = Event::type_kill_note;
1407                    e.Param.Note.ID = id.noteID();
1408                    e.Param.Note.Key = pNote->hostKey;
1409    
1410                    pEngineChannel->ScheduleEventMicroSec(&e, duration + 1);
1411                }
1412            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
1413                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
1414                for (int i = 0; i < ids->arraySize(); ++i) {
1415                    const ScriptID id = ids->evalIntElement(i);
1416                    if (!id || !id.isNoteID()) continue;
1417    
1418                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1419                    if (!pNote) continue;
1420    
1421                    // if fade_out() was called immediately after note was triggered
1422                    // then immediately apply fade out duration to Note object
1423                    if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) {
1424                        pNote->Override.VolumeTime = fDuration;
1425                    } else { // otherwise schedule a "volume time" change with the requested fade out duration ...
1426                        Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1427                        e.Init(); // clear IDs
1428                        e.Type = Event::type_note_synth_param;
1429                        e.Param.NoteSynthParam.NoteID   = id.noteID();
1430                        e.Param.NoteSynthParam.Type     = Event::synth_param_volume_time;
1431                        e.Param.NoteSynthParam.Delta    = fDuration;
1432                        e.Param.NoteSynthParam.Relative = false;
1433    
1434                        pEngineChannel->ScheduleEventMicroSec(&e, 0);
1435                    }
1436                    // now schedule a "volume" change, simply one time slice ahead, with
1437                    // the final fade out volume (0.0)
1438                    {
1439                        Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1440                        e.Init(); // clear IDs
1441                        e.Type = Event::type_note_synth_param;
1442                        e.Param.NoteSynthParam.NoteID   = id.noteID();
1443                        e.Param.NoteSynthParam.Type     = Event::synth_param_volume;
1444                        e.Param.NoteSynthParam.Delta    = 0.f;
1445                        e.Param.NoteSynthParam.Relative = false;
1446    
1447                        // scheduling with 0 delay would also work here, but +1 is more
1448                        // safe regarding potential future implementation changes of the
1449                        // scheduler (see API comments of RTAVLTree::insert())
1450                        pEngineChannel->ScheduleEventMicroSec(&e, 1);
1451                    }
1452                    // and finally if stopping the note was requested after the fade out
1453                    // completed, then schedule to kill the voice after the requested
1454                    // duration
1455                    if (stop) {
1456                        Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1457                        e.Init(); // clear IDs
1458                        e.Type = Event::type_kill_note;
1459                        e.Param.Note.ID = id.noteID();
1460                        e.Param.Note.Key = pNote->hostKey;
1461                        
1462                        pEngineChannel->ScheduleEventMicroSec(&e, duration + 1);
1463                    }
1464                }
1465            }
1466    
1467            return successResult();
1468        }
1469    
1470        // get_event_par() function
1471    
1472        InstrumentScriptVMFunction_get_event_par::InstrumentScriptVMFunction_get_event_par(InstrumentScriptVM* parent)
1473            : m_vm(parent)
1474        {
1475        }
1476    
1477        VMFnResult* InstrumentScriptVMFunction_get_event_par::exec(VMFnArgs* args) {
1478            AbstractEngineChannel* pEngineChannel =
1479                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1480    
1481            const ScriptID id = args->arg(0)->asInt()->evalInt();
1482            if (!id) {
1483                wrnMsg("get_event_par(): note ID for argument 1 may not be zero");
1484                return successResult(0);
1485            }
1486            if (!id.isNoteID()) {
1487                wrnMsg("get_event_par(): argument 1 is not a note ID");
1488                return successResult(0);
1489            }
1490    
1491            NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1492            if (!pNote) {
1493                wrnMsg("get_event_par(): no note alive with that note ID of argument 1");
1494                return successResult(0);
1495            }
1496    
1497            const int parameter = args->arg(1)->asInt()->evalInt();
1498            switch (parameter) {
1499                case EVENT_PAR_NOTE:
1500                    return successResult(pNote->cause.Param.Note.Key);
1501                case EVENT_PAR_VELOCITY:
1502                    return successResult(pNote->cause.Param.Note.Velocity);
1503                case EVENT_PAR_VOLUME:
1504                    return successResult(
1505                        RTMath::LinRatioToDecibel(pNote->Override.Volume) * 1000.f
1506                    );
1507                case EVENT_PAR_TUNE:
1508                    return successResult(
1509                         RTMath::FreqRatioToCents(pNote->Override.Pitch) * 1000.f
1510                    );
1511                case EVENT_PAR_0:
1512                    return successResult(pNote->userPar[0]);
1513                case EVENT_PAR_1:
1514                    return successResult(pNote->userPar[1]);
1515                case EVENT_PAR_2:
1516                    return successResult(pNote->userPar[2]);
1517                case EVENT_PAR_3:
1518                    return successResult(pNote->userPar[3]);
1519            }
1520    
1521            wrnMsg("get_event_par(): argument 2 is an invalid event parameter");
1522            return successResult(0);
1523        }
1524    
1525        // set_event_par() function
1526    
1527        InstrumentScriptVMFunction_set_event_par::InstrumentScriptVMFunction_set_event_par(InstrumentScriptVM* parent)
1528            : m_vm(parent)
1529        {
1530        }
1531    
1532        VMFnResult* InstrumentScriptVMFunction_set_event_par::exec(VMFnArgs* args) {
1533            AbstractEngineChannel* pEngineChannel =
1534                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1535    
1536            const ScriptID id = args->arg(0)->asInt()->evalInt();
1537            if (!id) {
1538                wrnMsg("set_event_par(): note ID for argument 1 may not be zero");
1539                return successResult();
1540            }
1541            if (!id.isNoteID()) {
1542                wrnMsg("set_event_par(): argument 1 is not a note ID");
1543                return successResult();
1544            }
1545    
1546            NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1547            if (!pNote) return successResult();
1548    
1549            const int parameter = args->arg(1)->asInt()->evalInt();
1550            const int value     = args->arg(2)->asInt()->evalInt();
1551    
1552            switch (parameter) {
1553                case EVENT_PAR_NOTE:
1554                    if (value < 0 || value > 127) {
1555                        wrnMsg("set_event_par(): note number of argument 3 is out of range");
1556                        return successResult();
1557                    }
1558                    if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime)
1559                        pNote->cause.Param.Note.Key = value;
1560                    else
1561                        wrnMsg("set_event_par(): note number can only be changed when note is new");
1562                    return successResult();
1563                case EVENT_PAR_VELOCITY:
1564                    if (value < 0 || value > 127) {
1565                        wrnMsg("set_event_par(): velocity of argument 3 is out of range");
1566                        return successResult();
1567                    }
1568                    if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime)
1569                        pNote->cause.Param.Note.Velocity = value;
1570                    else
1571                        wrnMsg("set_event_par(): velocity can only be changed when note is new");
1572                    return successResult();
1573                case EVENT_PAR_VOLUME:
1574                    wrnMsg("set_event_par(): changing volume by this function is currently not supported, use change_vol() instead");
1575                    return successResult();
1576                case EVENT_PAR_TUNE:
1577                    wrnMsg("set_event_par(): changing tune by this function is currently not supported, use change_tune() instead");
1578                    return successResult();
1579                case EVENT_PAR_0:
1580                    pNote->userPar[0] = value;
1581                    return successResult();
1582                case EVENT_PAR_1:
1583                    pNote->userPar[1] = value;
1584                    return successResult();
1585                case EVENT_PAR_2:
1586                    pNote->userPar[2] = value;
1587                    return successResult();
1588                case EVENT_PAR_3:
1589                    pNote->userPar[3] = value;
1590                    return successResult();
1591            }
1592    
1593            wrnMsg("set_event_par(): argument 2 is an invalid event parameter");
1594            return successResult();
1595        }
1596    
1597      // event_status() function      // event_status() function
1598    
1599      InstrumentScriptVMFunction_event_status::InstrumentScriptVMFunction_event_status(InstrumentScriptVM* parent)      InstrumentScriptVMFunction_event_status::InstrumentScriptVMFunction_event_status(InstrumentScriptVM* parent)
# Line 1124  namespace LinuxSampler { Line 1659  namespace LinuxSampler {
1659              (args->argsCount() >= 2) ? (args->arg(1)->asInt()->evalInt() == 1) : false;              (args->argsCount() >= 2) ? (args->arg(1)->asInt()->evalInt() == 1) : false;
1660    
1661          pEngineChannel->ScheduleResumeOfScriptCallback(          pEngineChannel->ScheduleResumeOfScriptCallback(
1662              itCallback, m_vm->m_event->cause.SchedTime(), disableWaitForever              itCallback, m_vm->m_event->scheduleTime, disableWaitForever
1663          );          );
1664    
1665          return successResult();          return successResult();

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

  ViewVC Help
Powered by ViewVC