--- linuxsampler/trunk/src/engines/common/InstrumentScriptVMFunctions.cpp 2017/05/19 14:23:12 3188 +++ linuxsampler/trunk/src/engines/common/InstrumentScriptVMFunctions.cpp 2017/05/25 16:32:17 3218 @@ -136,9 +136,9 @@ AbstractEngineChannel* pEngineChannel = static_cast(m_vm->m_event->cause.pEngineChannel); - if (args->arg(0)->exprType() == INT_EXPR) { - const ScriptID id = args->arg(0)->asInt()->evalInt(); - if (!id) { + if (args->argsCount() == 0 || args->arg(0)->exprType() == INT_EXPR) { + const ScriptID id = (args->argsCount() >= 1) ? args->arg(0)->asInt()->evalInt() : m_vm->m_event->id; + if (!id && args->argsCount() >= 1) { wrnMsg("ignore_event(): event ID argument may not be zero"); // not errorResult(), because that would abort the script, not intentional in this case return successResult(); @@ -385,8 +385,11 @@ if (!pNote) return successResult(); // if change_vol() was called immediately after note was triggered - // then immediately apply the volume to note object - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + // then immediately apply the volume to note object, but only if + // change_vol_time() has not been called before + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime && + pNote->Override.VolumeTime <= DEFAULT_NOTE_VOLUME_TIME_S) + { if (relative) pNote->Override.Volume *= fVolumeLin; else @@ -412,8 +415,11 @@ if (!pNote) continue; // if change_vol() was called immediately after note was triggered - // then immediately apply the volume to Note object - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + // then immediately apply the volume to Note object, but only if + // change_vol_time() has not been called before + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime && + pNote->Override.VolumeTime <= DEFAULT_NOTE_VOLUME_TIME_S) + { if (relative) pNote->Override.Volume *= fVolumeLin; else @@ -472,8 +478,11 @@ if (!pNote) return successResult(); // if change_tune() was called immediately after note was triggered - // then immediately apply the tuning to Note object - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + // then immediately apply the tuning to Note object, but only if + // change_tune_time() has not been called before + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime && + pNote->Override.PitchTime <= DEFAULT_NOTE_PITCH_TIME_S) + { if (relative) pNote->Override.Pitch *= fFreqRatio; else @@ -499,8 +508,11 @@ if (!pNote) continue; // if change_tune() was called immediately after note was triggered - // then immediately apply the tuning to Note object - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + // then immediately apply the tuning to Note object, but only if + // change_tune_time() has not been called before + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime && + pNote->Override.PitchTime <= DEFAULT_NOTE_PITCH_TIME_S) + { if (relative) pNote->Override.Pitch *= fFreqRatio; else @@ -568,7 +580,7 @@ // if change_pan() was called immediately after note was triggered // then immediately apply the panning to Note object - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { if (relative) { pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources); } else { @@ -597,7 +609,7 @@ // if change_pan() was called immediately after note was triggered // then immediately apply the panning to Note object - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { if (relative) { pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources); } else { @@ -668,7 +680,7 @@ // if change_cutoff() was called immediately after note was triggered // then immediately apply cutoff to Note object - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { pNote->Override.Cutoff = fCutoff; } else { // otherwise schedule cutoff change ... Event e = m_vm->m_event->cause; // copy to get fragment time for "now" @@ -692,7 +704,7 @@ // if change_cutoff() was called immediately after note was triggered // then immediately apply cutoff to Note object - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { pNote->Override.Cutoff = fCutoff; } else { // otherwise schedule cutoff change ... Event e = m_vm->m_event->cause; // copy to get fragment time for "now" @@ -755,7 +767,7 @@ // if change_reso() was called immediately after note was triggered // then immediately apply resonance to Note object - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { pNote->Override.Resonance = fResonance; } else { // otherwise schedule resonance change ... Event e = m_vm->m_event->cause; // copy to get fragment time for "now" @@ -779,7 +791,7 @@ // if change_reso() was called immediately after note was triggered // then immediately apply resonance to Note object - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { pNote->Override.Resonance = fResonance; } else { // otherwise schedule resonance change ... Event e = m_vm->m_event->cause; // copy to get fragment time for "now" @@ -842,7 +854,7 @@ // if change_attack() was called immediately after note was triggered // then immediately apply attack to Note object - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { pNote->Override.Attack = fAttack; } else { // otherwise schedule attack change ... Event e = m_vm->m_event->cause; // copy to get fragment time for "now" @@ -866,7 +878,7 @@ // if change_attack() was called immediately after note was triggered // then immediately apply attack to Note object - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { pNote->Override.Attack = fAttack; } else { // otherwise schedule attack change ... Event e = m_vm->m_event->cause; // copy to get fragment time for "now" @@ -929,7 +941,7 @@ // if change_decay() was called immediately after note was triggered // then immediately apply decay to Note object - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { pNote->Override.Decay = fDecay; } else { // otherwise schedule decay change ... Event e = m_vm->m_event->cause; // copy to get fragment time for "now" @@ -953,7 +965,7 @@ // if change_decay() was called immediately after note was triggered // then immediately apply decay to Note object - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { pNote->Override.Decay = fDecay; } else { // otherwise schedule decay change ... Event e = m_vm->m_event->cause; // copy to get fragment time for "now" @@ -1016,7 +1028,7 @@ // if change_release() was called immediately after note was triggered // then immediately apply relase to Note object - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { pNote->Override.Release = fRelease; } else { // otherwise schedule release change ... Event e = m_vm->m_event->cause; // copy to get fragment time for "now" @@ -1040,7 +1052,7 @@ // if change_release() was called immediately after note was triggered // then immediately apply relase to Note object - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { pNote->Override.Release = fRelease; } else { // otherwise schedule release change ... Event e = m_vm->m_event->cause; // copy to get fragment time for "now" @@ -1066,14 +1078,17 @@ return type == INT_EXPR; } + // Arbitrarily chosen constant value symbolizing "no limit". + #define NO_LIMIT 1315916909 + template VMFnResult* VMChangeSynthParamFunction::execTemplate(VMFnArgs* args, const char* functionName) { int value = args->arg(1)->asInt()->evalInt(); - if (value > T_maxValue) { + if (T_maxValue != NO_LIMIT && value > T_maxValue) { wrnMsg(String(functionName) + "(): argument 2 may not be larger than " + ToString(T_maxValue)); value = T_maxValue; - } else if (value < T_minValue) { + } else if (T_minValue != NO_LIMIT && value < T_minValue) { if (T_minValue == 0) wrnMsg(String(functionName) + "(): argument 2 may not be negative"); else @@ -1104,7 +1119,7 @@ // if this change_*() script function was called immediately after // note was triggered then immediately apply the synth parameter // change to Note object - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { pNote->Override.*T_noteParam = fValue; } else { // otherwise schedule this synth parameter change ... Event e = m_vm->m_event->cause; // copy to get fragment time for "now" @@ -1129,7 +1144,7 @@ // if this change_*() script function was called immediately after // note was triggered then immediately apply the synth parameter // change to Note object - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { pNote->Override.*T_noteParam = fValue; } else { // otherwise schedule this synth parameter change ... Event e = m_vm->m_event->cause; // copy to get fragment time for "now" @@ -1153,7 +1168,8 @@ VMFnResult* InstrumentScriptVMFunction_change_amp_lfo_depth::exec(VMFnArgs* args) { return VMChangeSynthParamFunction::execTemplate< &NoteBase::_Override::AmpLFODepth, - Event::synth_param_amp_lfo_depth, true>( args, "change_amp_lfo_depth" ); + Event::synth_param_amp_lfo_depth, + true, 1000000, 0>( args, "change_amp_lfo_depth" ); } // change_amp_lfo_freq() function @@ -1161,7 +1177,8 @@ VMFnResult* InstrumentScriptVMFunction_change_amp_lfo_freq::exec(VMFnArgs* args) { return VMChangeSynthParamFunction::execTemplate< &NoteBase::_Override::AmpLFOFreq, - Event::synth_param_amp_lfo_freq, true>( args, "change_amp_lfo_freq" ); + Event::synth_param_amp_lfo_freq, + true, 1000000, 0>( args, "change_amp_lfo_freq" ); } // change_pitch_lfo_depth() function @@ -1169,7 +1186,8 @@ VMFnResult* InstrumentScriptVMFunction_change_pitch_lfo_depth::exec(VMFnArgs* args) { return VMChangeSynthParamFunction::execTemplate< &NoteBase::_Override::PitchLFODepth, - Event::synth_param_pitch_lfo_depth, true>( args, "change_pitch_lfo_depth" ); + Event::synth_param_pitch_lfo_depth, + true, 1000000, 0>( args, "change_pitch_lfo_depth" ); } // change_pitch_lfo_freq() function @@ -1177,7 +1195,8 @@ VMFnResult* InstrumentScriptVMFunction_change_pitch_lfo_freq::exec(VMFnArgs* args) { return VMChangeSynthParamFunction::execTemplate< &NoteBase::_Override::PitchLFOFreq, - Event::synth_param_pitch_lfo_freq, true>( args, "change_pitch_lfo_freq" ); + Event::synth_param_pitch_lfo_freq, + true, 1000000, 0>( args, "change_pitch_lfo_freq" ); } // change_vol_time() function @@ -1185,7 +1204,8 @@ VMFnResult* InstrumentScriptVMFunction_change_vol_time::exec(VMFnArgs* args) { return VMChangeSynthParamFunction::execTemplate< &NoteBase::_Override::VolumeTime, - Event::synth_param_volume_time, false>( args, "change_vol_time" ); + Event::synth_param_volume_time, + false, NO_LIMIT, 0>( args, "change_vol_time" ); } // change_tune_time() function @@ -1193,7 +1213,8 @@ VMFnResult* InstrumentScriptVMFunction_change_tune_time::exec(VMFnArgs* args) { return VMChangeSynthParamFunction::execTemplate< &NoteBase::_Override::PitchTime, - Event::synth_param_pitch_time, false>( args, "change_tune_time" ); + Event::synth_param_pitch_time, + false, NO_LIMIT, 0>( args, "change_tune_time" ); } // fade_in() function @@ -1238,7 +1259,7 @@ // if fade_in() was called immediately after note was triggered // then immediately apply a start volume of zero to Note object, // as well as the fade in duration - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { pNote->Override.Volume = 0.f; pNote->Override.VolumeTime = fDuration; } else { // otherwise schedule a "volume time" change with the requested fade in duration ... @@ -1280,7 +1301,7 @@ // if fade_in() was called immediately after note was triggered // then immediately apply a start volume of zero to Note object, // as well as the fade in duration - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { pNote->Override.Volume = 0.f; pNote->Override.VolumeTime = fDuration; } else { // otherwise schedule a "volume time" change with the requested fade in duration ... @@ -1359,7 +1380,7 @@ // if fade_out() was called immediately after note was triggered // then immediately apply fade out duration to Note object - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { pNote->Override.VolumeTime = fDuration; } else { // otherwise schedule a "volume time" change with the requested fade out duration ... Event e = m_vm->m_event->cause; // copy to get fragment time for "now" @@ -1411,7 +1432,7 @@ // if fade_out() was called immediately after note was triggered // then immediately apply fade out duration to Note object - if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) { + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { pNote->Override.VolumeTime = fDuration; } else { // otherwise schedule a "volume time" change with the requested fade out duration ... Event e = m_vm->m_event->cause; // copy to get fragment time for "now" @@ -1458,6 +1479,217 @@ return successResult(); } + // get_event_par() function + + InstrumentScriptVMFunction_get_event_par::InstrumentScriptVMFunction_get_event_par(InstrumentScriptVM* parent) + : m_vm(parent) + { + } + + VMFnResult* InstrumentScriptVMFunction_get_event_par::exec(VMFnArgs* args) { + AbstractEngineChannel* pEngineChannel = + static_cast(m_vm->m_event->cause.pEngineChannel); + + const ScriptID id = args->arg(0)->asInt()->evalInt(); + if (!id) { + wrnMsg("get_event_par(): note ID for argument 1 may not be zero"); + return successResult(0); + } + if (!id.isNoteID()) { + wrnMsg("get_event_par(): argument 1 is not a note ID"); + return successResult(0); + } + + NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() ); + if (!pNote) { + wrnMsg("get_event_par(): no note alive with that note ID of argument 1"); + return successResult(0); + } + + const int parameter = args->arg(1)->asInt()->evalInt(); + switch (parameter) { + case EVENT_PAR_NOTE: + return successResult(pNote->cause.Param.Note.Key); + case EVENT_PAR_VELOCITY: + return successResult(pNote->cause.Param.Note.Velocity); + case EVENT_PAR_VOLUME: + return successResult( + RTMath::LinRatioToDecibel(pNote->Override.Volume) * 1000.f + ); + case EVENT_PAR_TUNE: + return successResult( + RTMath::FreqRatioToCents(pNote->Override.Pitch) * 1000.f + ); + case EVENT_PAR_0: + return successResult(pNote->userPar[0]); + case EVENT_PAR_1: + return successResult(pNote->userPar[1]); + case EVENT_PAR_2: + return successResult(pNote->userPar[2]); + case EVENT_PAR_3: + return successResult(pNote->userPar[3]); + } + + wrnMsg("get_event_par(): argument 2 is an invalid event parameter"); + return successResult(0); + } + + // set_event_par() function + + InstrumentScriptVMFunction_set_event_par::InstrumentScriptVMFunction_set_event_par(InstrumentScriptVM* parent) + : m_vm(parent) + { + } + + VMFnResult* InstrumentScriptVMFunction_set_event_par::exec(VMFnArgs* args) { + AbstractEngineChannel* pEngineChannel = + static_cast(m_vm->m_event->cause.pEngineChannel); + + const ScriptID id = args->arg(0)->asInt()->evalInt(); + if (!id) { + wrnMsg("set_event_par(): note ID for argument 1 may not be zero"); + return successResult(); + } + if (!id.isNoteID()) { + wrnMsg("set_event_par(): argument 1 is not a note ID"); + return successResult(); + } + + NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() ); + if (!pNote) return successResult(); + + const int parameter = args->arg(1)->asInt()->evalInt(); + const int value = args->arg(2)->asInt()->evalInt(); + + switch (parameter) { + case EVENT_PAR_NOTE: + if (value < 0 || value > 127) { + wrnMsg("set_event_par(): note number of argument 3 is out of range"); + return successResult(); + } + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { + pNote->cause.Param.Note.Key = value; + m_vm->m_event->cause.Param.Note.Key = value; + } else { + wrnMsg("set_event_par(): note number can only be changed when note is new"); + } + return successResult(); + case EVENT_PAR_VELOCITY: + if (value < 0 || value > 127) { + wrnMsg("set_event_par(): velocity of argument 3 is out of range"); + return successResult(); + } + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { + pNote->cause.Param.Note.Velocity = value; + m_vm->m_event->cause.Param.Note.Velocity = value; + } else { + wrnMsg("set_event_par(): velocity can only be changed when note is new"); + } + return successResult(); + case EVENT_PAR_VOLUME: + wrnMsg("set_event_par(): changing volume by this function is currently not supported, use change_vol() instead"); + return successResult(); + case EVENT_PAR_TUNE: + wrnMsg("set_event_par(): changing tune by this function is currently not supported, use change_tune() instead"); + return successResult(); + case EVENT_PAR_0: + pNote->userPar[0] = value; + return successResult(); + case EVENT_PAR_1: + pNote->userPar[1] = value; + return successResult(); + case EVENT_PAR_2: + pNote->userPar[2] = value; + return successResult(); + case EVENT_PAR_3: + pNote->userPar[3] = value; + return successResult(); + } + + wrnMsg("set_event_par(): argument 2 is an invalid event parameter"); + return successResult(); + } + + // change_note() function + + InstrumentScriptVMFunction_change_note::InstrumentScriptVMFunction_change_note(InstrumentScriptVM* parent) + : m_vm(parent) + { + } + + VMFnResult* InstrumentScriptVMFunction_change_note::exec(VMFnArgs* args) { + AbstractEngineChannel* pEngineChannel = + static_cast(m_vm->m_event->cause.pEngineChannel); + + const ScriptID id = args->arg(0)->asInt()->evalInt(); + if (!id) { + wrnMsg("change_note(): note ID for argument 1 may not be zero"); + return successResult(); + } + if (!id.isNoteID()) { + wrnMsg("change_note(): argument 1 is not a note ID"); + return successResult(); + } + + NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() ); + if (!pNote) return successResult(); + + const int value = args->arg(1)->asInt()->evalInt(); + if (value < 0 || value > 127) { + wrnMsg("change_note(): note number of argument 2 is out of range"); + return successResult(); + } + + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { + pNote->cause.Param.Note.Key = value; + m_vm->m_event->cause.Param.Note.Key = value; + } else { + wrnMsg("change_note(): note number can only be changed when note is new"); + } + + return successResult(); + } + + // change_velo() function + + InstrumentScriptVMFunction_change_velo::InstrumentScriptVMFunction_change_velo(InstrumentScriptVM* parent) + : m_vm(parent) + { + } + + VMFnResult* InstrumentScriptVMFunction_change_velo::exec(VMFnArgs* args) { + AbstractEngineChannel* pEngineChannel = + static_cast(m_vm->m_event->cause.pEngineChannel); + + const ScriptID id = args->arg(0)->asInt()->evalInt(); + if (!id) { + wrnMsg("change_velo(): note ID for argument 1 may not be zero"); + return successResult(); + } + if (!id.isNoteID()) { + wrnMsg("change_velo(): argument 1 is not a note ID"); + return successResult(); + } + + NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() ); + if (!pNote) return successResult(); + + const int value = args->arg(1)->asInt()->evalInt(); + if (value < 0 || value > 127) { + wrnMsg("change_velo(): velocity of argument 2 is out of range"); + return successResult(); + } + + if (m_vm->m_event->scheduleTime == pNote->triggerSchedTime) { + pNote->cause.Param.Note.Velocity = value; + m_vm->m_event->cause.Param.Note.Velocity = value; + } else { + wrnMsg("change_velo(): velocity can only be changed when note is new"); + } + + return successResult(); + } + // event_status() function InstrumentScriptVMFunction_event_status::InstrumentScriptVMFunction_event_status(InstrumentScriptVM* parent) @@ -1523,7 +1755,7 @@ (args->argsCount() >= 2) ? (args->arg(1)->asInt()->evalInt() == 1) : false; pEngineChannel->ScheduleResumeOfScriptCallback( - itCallback, m_vm->m_event->cause.SchedTime(), disableWaitForever + itCallback, m_vm->m_event->scheduleTime, disableWaitForever ); return successResult();