voice interface and type checks
This commit is contained in:
25
synth/ivoice.h
Normal file
25
synth/ivoice.h
Normal file
@@ -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 <class derived>
|
||||
struct is_convertible {
|
||||
template <class T>
|
||||
static char test(T*);
|
||||
|
||||
template <class T>
|
||||
static double test(...);
|
||||
|
||||
static const bool value = sizeof(test<ivoice>(static_cast<derived*>(0))) == 1;
|
||||
};
|
||||
}
|
||||
@@ -1,18 +1,22 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#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 <typename t_voice>
|
||||
class midi_synth : public voice_allocator<t_voice> {
|
||||
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<t_voice>::value ? 1 : -1];
|
||||
}
|
||||
|
||||
void set_samplerate_blocksize(double _samplerate, int _block_size)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "midi_event.h"
|
||||
#include "ivoice.h"
|
||||
#include <vector>
|
||||
|
||||
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<t_voice>::value ? 1 : -1];
|
||||
}
|
||||
|
||||
void set_voice_count(const int& voice_count)
|
||||
|
||||
Reference in New Issue
Block a user