diff --git a/synth/ivoice.h b/synth/ivoice.h new file mode 100644 index 0000000..d4709f2 --- /dev/null +++ b/synth/ivoice.h @@ -0,0 +1,25 @@ +#pragma once + +namespace trnr { +struct ivoice { + virtual ~ivoice() = default; + virtual float process_sample() = 0; + virtual bool is_busy() = 0; + virtual void set_samplerate(double samplerate) = 0; + virtual void note_on(int _note, float _velocity) = 0; + virtual void note_off() = 0; + virtual void modulate_pitch(float _pitch) = 0; +}; + +// check if a template derives from ivoice +template +struct is_convertible { + template + static char test(T*); + + template + static double test(...); + + static const bool value = sizeof(test(static_cast(0))) == 1; +}; +} \ No newline at end of file diff --git a/synth/midi_synth.h b/synth/midi_synth.h index 04a8a04..6524df2 100644 --- a/synth/midi_synth.h +++ b/synth/midi_synth.h @@ -1,18 +1,22 @@ #pragma once #include #include +#include "ivoice.h" #include "midi_event.h" #include "voice_allocator.h" namespace trnr { // a generic midi synth base class with sample accurate event handling. +// the templated type t_voice must derive from ivoice template class midi_synth : public voice_allocator { public: midi_synth(int _n_voices) : m_voices_active { false } { + // checks whether template derives from ivoice + typedef t_voice assert_at_compile_time[is_convertible::value ? 1 : -1]; } void set_samplerate_blocksize(double _samplerate, int _block_size) diff --git a/synth/tx_voice.h b/synth/tx_voice.h index 19c20cd..b2f8b00 100644 --- a/synth/tx_voice.h +++ b/synth/tx_voice.h @@ -2,11 +2,12 @@ #include "tx_sineosc.h" #include "tx_envelope.h" #include "tx_operator.h" +#include "ivoice.h" #include "../util/audio_math.h" namespace trnr { -class tx_voice { +class tx_voice : public ivoice { public: tx_voice() : algorithm { 0 } @@ -32,23 +33,23 @@ public: tx_operator op2; tx_operator op3; - void note_on(int _note, float _velocity) { + void note_on(int _note, float _velocity) override { this->gate = true; this->trigger = true; midi_note = _note; velocity = _velocity; } - void note_off() { + void note_off() override { this->gate = false; } // modulates the pitch in semitones - void modulate_pitch(float pitch) { - this->pitch_mod = pitch; + void modulate_pitch(float _pitch) override { + this->pitch_mod = _pitch; } - float process_sample() { + float process_sample() override { float pitch_env_signal = pitch_env.process_sample(gate, trigger) * pitch_env_amt; float pitched_freq = midi_to_frequency(midi_note + pitch_mod + additional_pitch_mod) + pitch_env_signal; @@ -79,9 +80,9 @@ public: return redux(output, bit_resolution); } - bool is_busy() { return gate || op1.envelope.is_busy() || op2.envelope.is_busy() || op3.envelope.is_busy(); } + bool is_busy() override { return gate || op1.envelope.is_busy() || op2.envelope.is_busy() || op3.envelope.is_busy(); } - void set_samplerate(double samplerate) { + void set_samplerate(double samplerate) override { pitch_env.set_samplerate(samplerate); feedback_osc.set_samplerate(samplerate); op1.set_samplerate(samplerate); diff --git a/synth/voice_allocator.h b/synth/voice_allocator.h index cb3132a..aea76a2 100644 --- a/synth/voice_allocator.h +++ b/synth/voice_allocator.h @@ -1,5 +1,6 @@ #pragma once #include "midi_event.h" +#include "ivoice.h" #include namespace trnr { @@ -12,6 +13,8 @@ public: voice_allocator() : voices(8, t_voice()) { + // checks whether template derives from ivoice + typedef t_voice assert_at_compile_time[is_convertible::value ? 1 : -1]; } void set_voice_count(const int& voice_count)