From bc213362f07353c5fdda6288f98f90db897633ad Mon Sep 17 00:00:00 2001 From: Christopher Herb Date: Mon, 10 Jul 2023 17:04:16 +0200 Subject: [PATCH] added support for pitch wheel modulation --- synth/midi_event.h | 46 +++++++++++++++++++++++++++++++++++++++++ synth/midi_synth.h | 10 ++++----- synth/note_event.h | 25 ---------------------- synth/tx_voice.h | 5 +++-- synth/voice_allocator.h | 23 +++++++++++++-------- util/audio_math.h | 2 +- 6 files changed, 69 insertions(+), 42 deletions(-) create mode 100644 synth/midi_event.h delete mode 100644 synth/note_event.h diff --git a/synth/midi_event.h b/synth/midi_event.h new file mode 100644 index 0000000..cd17e30 --- /dev/null +++ b/synth/midi_event.h @@ -0,0 +1,46 @@ +#pragma once + +namespace trnr { + +enum midi_event_type { + note_on = 0, + note_off, + pitch_wheel, + mod_wheel +}; + +class midi_event { +public: + midi_event_type type; + int offset = 0; + int midi_note = 0; + float velocity = 1.f; + double data = 0; + + void make_note_on(int _midi_note, float _velocity, int _offset = 0) + { + type = midi_event_type::note_on; + midi_note = _midi_note; + velocity = _velocity; + offset = _offset; + } + + void make_note_off(int _midi_note, float _velocity, int _offset = 0) + { + type = midi_event_type::note_off; + midi_note = _midi_note; + velocity = _velocity; + offset = _offset; + } + + void make_pitch_weel(double _pitch, int _offset = 0) { + type = midi_event_type::pitch_wheel; + data = _pitch; + } + + void make_mod_weel(double _mod, int _offset = 0) { + type = midi_event_type::pitch_wheel; + data = _mod; + } +}; +} diff --git a/synth/midi_synth.h b/synth/midi_synth.h index 6be2fd4..04a8a04 100644 --- a/synth/midi_synth.h +++ b/synth/midi_synth.h @@ -1,7 +1,7 @@ #pragma once #include #include -#include "note_event.h" +#include "midi_event.h" #include "voice_allocator.h" namespace trnr { @@ -35,7 +35,7 @@ public: block_size = samples_remaining; while (!m_event_queue.empty()) { - note_event event = m_event_queue.front(); + midi_event event = m_event_queue.front(); // we assume the messages are in chronological order. If we find one later than the current block we are done. if (event.offset > start_index + block_size) @@ -66,9 +66,9 @@ public: } } - void add_event(note_event event) + void add_event(midi_event event) { - if (event.type == note_event_type::note_on) + if (event.type == midi_event_type::note_on) m_voices_active = true; m_event_queue.push_back(event); @@ -82,7 +82,7 @@ public: } private: - std::vector m_event_queue; + std::vector m_event_queue; int m_block_size; bool m_voices_active; }; diff --git a/synth/note_event.h b/synth/note_event.h deleted file mode 100644 index 2b90918..0000000 --- a/synth/note_event.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -namespace trnr { - -enum note_event_type { - note_on = 0, - note_off -}; - -class note_event { -public: - note_event_type type; - int midi_note; - float velocity; - int offset; - - note_event(note_event_type type, int _midi_note, float _velocity, int _offset) - : type { type } - , midi_note { _midi_note } - , velocity { _velocity } - , offset { _offset } - { - } -}; -} diff --git a/synth/tx_voice.h b/synth/tx_voice.h index 17850d5..4ca2b17 100644 --- a/synth/tx_voice.h +++ b/synth/tx_voice.h @@ -20,7 +20,8 @@ public: bool trigger = false; int midi_note = 0; float velocity = 1.f; - float pitch_mod = 0.f; + float pitch_mod = 0.f; // modulates pitch in semi-tones + float pitch_mod2 = 0.f; // modulates pitch in frequency int algorithm; float pitch_env_amt; @@ -45,7 +46,7 @@ public: float process_sample() { float pitch_env_signal = pitch_env.process_sample(gate, trigger) * pitch_env_amt; - float pitched_freq = midi_to_frequency(midi_note) + pitch_env_signal + pitch_mod; + float pitched_freq = midi_to_frequency(midi_note + pitch_mod) + pitch_env_signal + pitch_mod2; float output = 0.f; diff --git a/synth/voice_allocator.h b/synth/voice_allocator.h index f47edbb..eb18322 100644 --- a/synth/voice_allocator.h +++ b/synth/voice_allocator.h @@ -1,6 +1,6 @@ #pragma once +#include "midi_event.h" #include -#include "note_event.h" namespace trnr { @@ -8,7 +8,7 @@ template class voice_allocator { public: std::vector voices; - + voice_allocator() : voices(8, t_voice()) { @@ -19,7 +19,7 @@ public: voices.resize(voice_count, voices.at(0)); } - void note_on(const note_event& event) + void note_on(const midi_event& event) { t_voice* voice = get_free_voice(event.midi_note); @@ -32,7 +32,7 @@ public: } } - void note_off(const note_event& event) + void note_off(const midi_event& event) { for (auto it = voices.begin(); it != voices.end(); it++) { if ((*it).midi_note == event.midi_note) { @@ -63,7 +63,7 @@ public: } } - void add_event(note_event event) + void add_event(midi_event event) { input_queue.push_back(event); } @@ -88,7 +88,7 @@ public: } private: - std::vector input_queue; + std::vector input_queue; t_voice* get_free_voice(float frequency) { @@ -126,16 +126,21 @@ private: auto iterator = input_queue.begin(); while (iterator != input_queue.end()) { - note_event& event = *iterator; + midi_event& event = *iterator; if (event.offset == _start_index) { switch (event.type) { - case note_event_type::note_on: + case midi_event_type::note_on: note_on(event); break; - case note_event_type::note_off: + case midi_event_type::note_off: note_off(event); break; + case midi_event_type::pitch_wheel: + access([&event](t_voice& voice) { voice.pitch_mod = event.data; }); + break; + default: + break; } iterator = input_queue.erase(iterator); diff --git a/util/audio_math.h b/util/audio_math.h index fcfb0f2..7e3cf21 100644 --- a/util/audio_math.h +++ b/util/audio_math.h @@ -9,7 +9,7 @@ namespace trnr { return pow(10, db/20); } - static inline float midi_to_frequency(int midi_note) { + static inline float midi_to_frequency(float midi_note) { return 440.0 * powf(2.0, ((float)midi_note - 69.0) / 12.0); } } \ No newline at end of file