diff --git a/synth/tx_envelope.h b/synth/tx_envelope.h index 76e20dd..782a802 100644 --- a/synth/tx_envelope.h +++ b/synth/tx_envelope.h @@ -41,7 +41,6 @@ public: template float process_sample(bool gate, bool trigger, t_sample _attack_mod, t_sample _decay_mod) { - size_t attack_mid_x1 = ms_to_samples(attack1_rate + (float)_attack_mod); size_t attack_mid_x2 = ms_to_samples(attack2_rate + (float)_attack_mod); size_t hold_samp = ms_to_samples(hold_rate); diff --git a/synth/tx_parameter_mapping.h b/synth/tx_parameter_mapping.h new file mode 100644 index 0000000..ba88cf3 --- /dev/null +++ b/synth/tx_parameter_mapping.h @@ -0,0 +1,89 @@ +#include +namespace trnr { + enum tx_parameter { + BIT_RESOLUTION = 0, + FEEDBACKOSC_PHASE_RESOLUTION, + FEEDBACK, + ALGORITHM, + + PITCH_ENVELOPE_AMOUNT, + PITCH_ENVELOPE_SKIP_SUSTAIN, + PITCH_ENVELOPE_ATTACK1_RATE, + PITCH_ENVELOPE_ATTACK1_LEVEL, + PITCH_ENVELOPE_ATTACK2_RATE, + PITCH_ENVELOPE_HOLD_RATE, + PITCH_ENVELOPE_DECAY1_RATE, + PITCH_ENVELOPE_DECAY1_LEVEL, + PITCH_ENVELOPE_DECAY2_RATE, + PITCH_ENVELOPE_SUSTAIN_LEVEL, + PITCH_ENVELOPE_RELEASE1_RATE, + PITCH_ENVELOPE_RELEASE1_LEVEL, + PITCH_ENVELOPE_RELEASE2_RATE, + + OP1_RATIO, + OP1_AMPLITUDE, + OP1_PHASE_RESOLUTION, + OP1_ENVELOPE_SKIP_SUSTAIN, + OP1_ENVELOPE_ATTACK1_RATE, + OP1_ENVELOPE_ATTACK1_LEVEL, + OP1_ENVELOPE_ATTACK2_RATE, + OP1_ENVELOPE_HOLD_RATE, + OP1_ENVELOPE_DECAY1_RATE, + OP1_ENVELOPE_DECAY1_LEVEL, + OP1_ENVELOPE_DECAY2_RATE, + OP1_ENVELOPE_SUSTAIN_LEVEL, + OP1_ENVELOPE_RELEASE1_RATE, + OP1_ENVELOPE_RELEASE1_LEVEL, + OP1_ENVELOPE_RELEASE2_RATE, + + OP2_RATIO, + OP2_AMPLITUDE, + OP2_PHASE_RESOLUTION, + OP2_ENVELOPE_SKIP_SUSTAIN, + OP2_ENVELOPE_ATTACK1_RATE, + OP2_ENVELOPE_ATTACK1_LEVEL, + OP2_ENVELOPE_ATTACK2_RATE, + OP2_ENVELOPE_HOLD_RATE, + OP2_ENVELOPE_DECAY1_RATE, + OP2_ENVELOPE_DECAY1_LEVEL, + OP2_ENVELOPE_DECAY2_RATE, + OP2_ENVELOPE_SUSTAIN_LEVEL, + OP2_ENVELOPE_RELEASE1_RATE, + OP2_ENVELOPE_RELEASE1_LEVEL, + OP2_ENVELOPE_RELEASE2_RATE, + + OP3_RATIO, + OP3_AMPLITUDE, + OP3_PHASE_RESOLUTION, + OP3_ENVELOPE_SKIP_SUSTAIN, + OP3_ENVELOPE_ATTACK1_RATE, + OP3_ENVELOPE_ATTACK1_LEVEL, + OP3_ENVELOPE_ATTACK2_RATE, + OP3_ENVELOPE_HOLD_RATE, + OP3_ENVELOPE_DECAY1_RATE, + OP3_ENVELOPE_DECAY1_LEVEL, + OP3_ENVELOPE_DECAY2_RATE, + OP3_ENVELOPE_SUSTAIN_LEVEL, + OP3_ENVELOPE_RELEASE1_RATE, + OP3_ENVELOPE_RELEASE1_LEVEL, + OP3_ENVELOPE_RELEASE2_RATE, + }; + + struct tx_parameter_mapping { + float range_min; + float range_max; + float exponent; + tx_parameter parameter; + + tx_parameter_mapping(float _range_min, float _range_max, float _exponent, tx_parameter _parameter) + : range_min(_range_min), range_max(_range_max), exponent(_exponent), parameter(_parameter) + {} + + float apply(float _input) const + { + if (range_min == range_max && exponent == 1.f) return _input; + + return powf(_input, exponent) * (range_max - range_min) + range_min; + } + }; +} \ No newline at end of file diff --git a/synth/tx_voice.h b/synth/tx_voice.h index c063bd3..4b1915c 100644 --- a/synth/tx_voice.h +++ b/synth/tx_voice.h @@ -4,6 +4,7 @@ #include "tx_envelope.h" #include "tx_operator.h" #include "tx_sineosc.h" +#include "tx_parameter_mapping.h" namespace trnr { @@ -104,6 +105,14 @@ public: feedback_osc.phase_reset = phase_reset; } + void update_parameters(float _value, const std::vector& _mappings) + { + for (const tx_parameter_mapping& mapping : _mappings) { + float normalized = mapping.apply(_value); + map_parameter(mapping, normalized); + } + } + private: double samplerate; const float MOD_INDEX_COEFF = 4.f; @@ -184,5 +193,197 @@ private: return value; } + + void map_parameter(const tx_parameter_mapping& _mapping, const float _value) + { + switch (_mapping.parameter) { + case tx_parameter::BIT_RESOLUTION: + bit_resolution = _value; + break; + case tx_parameter::FEEDBACKOSC_PHASE_RESOLUTION: + feedback_osc.set_phase_resolution(_value); + break; + case tx_parameter::FEEDBACK: + feedback_amt = _value; + break; + case tx_parameter::ALGORITHM: + algorithm = _value; + break; + case tx_parameter::PITCH_ENVELOPE_AMOUNT: + pitch_env_amt = _value; + break; + case tx_parameter::PITCH_ENVELOPE_SKIP_SUSTAIN: + pitch_env.skip_sustain = _value; + break; + case tx_parameter::PITCH_ENVELOPE_ATTACK1_RATE: + pitch_env.attack1_rate = _value; + break; + case tx_parameter::PITCH_ENVELOPE_ATTACK1_LEVEL: + pitch_env.attack1_level = _value; + break; + case tx_parameter::PITCH_ENVELOPE_ATTACK2_RATE: + pitch_env.attack2_rate = _value; + break; + case tx_parameter::PITCH_ENVELOPE_HOLD_RATE: + pitch_env.hold_rate = _value; + break; + case tx_parameter::PITCH_ENVELOPE_DECAY1_RATE: + pitch_env.decay1_rate = _value; + break; + case tx_parameter::PITCH_ENVELOPE_DECAY1_LEVEL: + pitch_env.decay1_level = _value; + break; + case tx_parameter::PITCH_ENVELOPE_DECAY2_RATE: + pitch_env.decay2_rate = _value; + break; + case tx_parameter::PITCH_ENVELOPE_SUSTAIN_LEVEL: + pitch_env.sustain_level = _value; + break; + case tx_parameter::PITCH_ENVELOPE_RELEASE1_RATE: + pitch_env.release1_rate = _value; + break; + case tx_parameter::PITCH_ENVELOPE_RELEASE1_LEVEL: + pitch_env.release1_level = _value; + break; + case tx_parameter::PITCH_ENVELOPE_RELEASE2_RATE: + pitch_env.release2_rate = _value; + break; + case tx_parameter::OP1_RATIO: + op1.ratio = _value; + break; + case tx_parameter::OP1_AMPLITUDE: + op1.amplitude = _value; + break; + case tx_parameter::OP1_PHASE_RESOLUTION: + op1.oscillator.set_phase_resolution(_value); + break; + case tx_parameter::OP1_ENVELOPE_SKIP_SUSTAIN: + op1.envelope.skip_sustain = _value; + break; + case tx_parameter::OP1_ENVELOPE_ATTACK1_RATE: + op1.envelope.attack1_rate = _value; + break; + case tx_parameter::OP1_ENVELOPE_ATTACK1_LEVEL: + op1.envelope.attack1_level = _value; + break; + case tx_parameter::OP1_ENVELOPE_ATTACK2_RATE: + op1.envelope.attack2_rate = _value; + break; + case tx_parameter::OP1_ENVELOPE_HOLD_RATE: + op1.envelope.hold_rate = _value; + break; + case tx_parameter::OP1_ENVELOPE_DECAY1_RATE: + op1.envelope.decay1_rate = _value; + break; + case tx_parameter::OP1_ENVELOPE_DECAY1_LEVEL: + op1.envelope.decay1_level = _value; + break; + case tx_parameter::OP1_ENVELOPE_DECAY2_RATE: + op1.envelope.decay2_rate = _value; + break; + case tx_parameter::OP1_ENVELOPE_SUSTAIN_LEVEL: + op1.envelope.sustain_level = _value; + break; + case tx_parameter::OP1_ENVELOPE_RELEASE1_RATE: + op1.envelope.release1_rate = _value; + break; + case tx_parameter::OP1_ENVELOPE_RELEASE1_LEVEL: + op1.envelope.release1_level = _value; + break; + case tx_parameter::OP1_ENVELOPE_RELEASE2_RATE: + op1.envelope.release2_rate = _value; + break; + case tx_parameter::OP2_RATIO: + op2.ratio = _value; + break; + case tx_parameter::OP2_AMPLITUDE: + op2.amplitude = _value; + break; + case tx_parameter::OP2_PHASE_RESOLUTION: + op2.oscillator.set_phase_resolution(_value); + break; + case tx_parameter::OP2_ENVELOPE_SKIP_SUSTAIN: + op2.envelope.skip_sustain = _value; + break; + case tx_parameter::OP2_ENVELOPE_ATTACK1_RATE: + op2.envelope.attack1_rate = _value; + break; + case tx_parameter::OP2_ENVELOPE_ATTACK1_LEVEL: + op2.envelope.attack1_level = _value; + break; + case tx_parameter::OP2_ENVELOPE_ATTACK2_RATE: + op2.envelope.attack2_rate = _value; + break; + case tx_parameter::OP2_ENVELOPE_HOLD_RATE: + op2.envelope.hold_rate = _value; + break; + case tx_parameter::OP2_ENVELOPE_DECAY1_RATE: + op2.envelope.decay1_rate = _value; + break; + case tx_parameter::OP2_ENVELOPE_DECAY1_LEVEL: + op2.envelope.decay1_level = _value; + break; + case tx_parameter::OP2_ENVELOPE_DECAY2_RATE: + op2.envelope.decay2_rate = _value; + break; + case tx_parameter::OP2_ENVELOPE_SUSTAIN_LEVEL: + op2.envelope.sustain_level = _value; + break; + case tx_parameter::OP2_ENVELOPE_RELEASE1_RATE: + op2.envelope.release1_rate = _value; + break; + case tx_parameter::OP2_ENVELOPE_RELEASE1_LEVEL: + op2.envelope.release1_level = _value; + break; + case tx_parameter::OP2_ENVELOPE_RELEASE2_RATE: + op2.envelope.release2_rate = _value; + break; + case tx_parameter::OP3_RATIO: + op3.ratio = _value; + break; + case tx_parameter::OP3_AMPLITUDE: + op3.amplitude = _value; + break; + case tx_parameter::OP3_PHASE_RESOLUTION: + op3.oscillator.set_phase_resolution(_value); + break; + case tx_parameter::OP3_ENVELOPE_SKIP_SUSTAIN: + op3.envelope.skip_sustain = _value; + break; + case tx_parameter::OP3_ENVELOPE_ATTACK1_RATE: + op3.envelope.attack1_rate = _value; + break; + case tx_parameter::OP3_ENVELOPE_ATTACK1_LEVEL: + op3.envelope.attack1_level = _value; + break; + case tx_parameter::OP3_ENVELOPE_ATTACK2_RATE: + op3.envelope.attack2_rate = _value; + break; + case tx_parameter::OP3_ENVELOPE_HOLD_RATE: + op3.envelope.hold_rate = _value; + break; + case tx_parameter::OP3_ENVELOPE_DECAY1_RATE: + op3.envelope.decay1_rate = _value; + break; + case tx_parameter::OP3_ENVELOPE_DECAY1_LEVEL: + op3.envelope.decay1_level = _value; + break; + case tx_parameter::OP3_ENVELOPE_DECAY2_RATE: + op3.envelope.decay2_rate = _value; + break; + case tx_parameter::OP3_ENVELOPE_SUSTAIN_LEVEL: + op3.envelope.sustain_level = _value; + break; + case tx_parameter::OP3_ENVELOPE_RELEASE1_RATE: + op3.envelope.release1_rate = _value; + break; + case tx_parameter::OP3_ENVELOPE_RELEASE1_LEVEL: + op3.envelope.release1_level = _value; + break; + case tx_parameter::OP3_ENVELOPE_RELEASE2_RATE: + op3.envelope.release2_rate = _value; + break; + } + } }; } // namespace trnr \ No newline at end of file