Compare commits
1 Commits
54996469d1
...
feature/wa
| Author | SHA1 | Date | |
|---|---|---|---|
| 5d86018d06 |
@@ -55,10 +55,11 @@ add_library(sonobulus_core STATIC
|
|||||||
src/synth/NoteQueue.cpp
|
src/synth/NoteQueue.cpp
|
||||||
src/synth/Scope.cpp
|
src/synth/Scope.cpp
|
||||||
src/synth/Synth.cpp
|
src/synth/Synth.cpp
|
||||||
src/synth/Voice.cpp
|
#src/synth/Voice.cpp
|
||||||
src/synth/Filter.cpp
|
src/synth/Filter.cpp
|
||||||
src/synth/WavetableLoader.cpp
|
src/synth/WavetableLoader.cpp
|
||||||
src/synth/Envelope.cpp
|
src/synth/Envelope.cpp
|
||||||
|
src/synth/InstrumentFactory.cpp
|
||||||
src/synth/instruments/Instrument.cpp
|
src/synth/instruments/Instrument.cpp
|
||||||
src/synth/instruments/PianoString.cpp
|
src/synth/instruments/PianoString.cpp
|
||||||
src/synth/instruments/WavetableOscillator.cpp
|
src/synth/instruments/WavetableOscillator.cpp
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ Logger = (
|
|||||||
"Info",
|
"Info",
|
||||||
"Warning",
|
"Warning",
|
||||||
"Error"
|
"Error"
|
||||||
);
|
); # TODO: console flags vs file flags
|
||||||
|
|
||||||
ShowTime = false;
|
ShowTime = false;
|
||||||
ShowSourceTrace = false;
|
ShowSourceTrace = false;
|
||||||
@@ -35,6 +35,7 @@ AudioEngine = (
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
# TODO: I don't like this being in the main config, maybe import it in (mainly the notes and keycodes)
|
||||||
KeyboardController = (
|
KeyboardController = (
|
||||||
{
|
{
|
||||||
Id = "Main";
|
Id = "Main";
|
||||||
|
|||||||
@@ -50,4 +50,3 @@ int main(int argc, char* argv[]) {
|
|||||||
// execute app
|
// execute app
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
38
src/synth/InstrumentFactory.cpp
Normal file
38
src/synth/InstrumentFactory.cpp
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
|
||||||
|
#include "InstrumentFactory.hpp"
|
||||||
|
|
||||||
|
#include "Instruments/PianoString.hpp"
|
||||||
|
#include "Instruments/WavetableOscillator.hpp"
|
||||||
|
|
||||||
|
InstrumentFactory::InstrumentFactory(ConfigService* config, LoggerService* logger) :
|
||||||
|
config_(config), logger_(logger) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Instrument* InstrumentFactory::createInstrument(InstrumentType type, float sampleRate, AudioParams* params) {
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case InstrumentType::Default:
|
||||||
|
return new Instrument(config_, logger_, sampleRate, params);
|
||||||
|
case InstrumentType::PianoString:
|
||||||
|
return new PianoString(config_, logger_, sampleRate, params);
|
||||||
|
case InstrumentType::WavetableOscillator:
|
||||||
|
return new WavetableOscillator(config_, logger_, wavetableLoader_, sampleRate, params);
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t InstrumentFactory::createInstruments(std::vector<Instrument*>* instruments, size_t voiceCount, float sampleRate, AudioParams* params) {
|
||||||
|
|
||||||
|
// parse the config file
|
||||||
|
// if there's wavetables then we need a wavetable loader
|
||||||
|
// initialize wavetableLoader_ here
|
||||||
|
|
||||||
|
for(size_t i = 0; i < params->maxVoices; i++) {
|
||||||
|
instruments->push_back(createInstrument(InstrumentType::PianoString, static_cast<float>(params->sampleRate), params));
|
||||||
|
}
|
||||||
|
|
||||||
|
return params->maxVoices;
|
||||||
|
|
||||||
|
}
|
||||||
35
src/synth/InstrumentFactory.hpp
Normal file
35
src/synth/InstrumentFactory.hpp
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "config/ConfigService.hpp"
|
||||||
|
#include "config/AudioConfig.hpp"
|
||||||
|
#include "LoggerService.hpp"
|
||||||
|
#include "Instruments/Instrument.hpp"
|
||||||
|
#include "WavetableLoader.hpp"
|
||||||
|
|
||||||
|
class InstrumentFactory {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
InstrumentFactory(ConfigService* config, LoggerService* logger);
|
||||||
|
~InstrumentFactory() = default;
|
||||||
|
|
||||||
|
int32_t createInstruments(std::vector<Instrument*>* instruments, size_t voiceCount, float sampleRate, AudioParams* params);
|
||||||
|
|
||||||
|
enum class InstrumentType {
|
||||||
|
Default,
|
||||||
|
PianoString,
|
||||||
|
WavetableOscillator
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Instrument* createInstrument(InstrumentType type, float sampleRate, AudioParams* params);
|
||||||
|
|
||||||
|
ConfigService* config_;
|
||||||
|
LoggerService* logger_;
|
||||||
|
|
||||||
|
// optional creators
|
||||||
|
WavetableLoader* wavetableLoader_ = nullptr;
|
||||||
|
|
||||||
|
};
|
||||||
@@ -3,8 +3,16 @@
|
|||||||
|
|
||||||
#include "string"
|
#include "string"
|
||||||
|
|
||||||
Instrument::Instrument(ConfigService* config, LoggerService* logger, float sampleRate) :
|
Instrument::Instrument(ConfigService* config, LoggerService* logger, float sampleRate, AudioParams* params) :
|
||||||
config_(config), logger_(logger), sampleRate_(sampleRate) {
|
config_(config), logger_(logger), sampleRate_(sampleRate), params_(params) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Instrument::startNote(uint8_t midiNote, float velocity) {
|
||||||
|
|
||||||
|
note_ = midiNote;
|
||||||
|
|
||||||
|
noteOn(noteToFrequency(midiNote), velocity);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "config/ConfigService.hpp"
|
#include "config/ConfigService.hpp"
|
||||||
#include "LoggerService.hpp"
|
#include "LoggerService.hpp"
|
||||||
|
#include "config/AudioConfig.hpp"
|
||||||
|
|
||||||
// an instrument is our state space model. it calculates discrete samples as a function of time, the current states, and the inputs
|
// an instrument is our state space model. it calculates discrete samples as a function of time, the current states, and the inputs
|
||||||
// an instrument is owned by a voice
|
// an instrument is owned by a voice
|
||||||
@@ -11,9 +12,10 @@ class Instrument {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
Instrument() = default;
|
Instrument() = default;
|
||||||
Instrument(ConfigService* config, LoggerService* logger, float sampleRate);
|
Instrument(ConfigService* config, LoggerService* logger, float sampleRate, AudioParams* params);
|
||||||
~Instrument() = default;
|
~Instrument() = default;
|
||||||
|
|
||||||
|
void startNote(uint8_t midiNote, float velocity);
|
||||||
virtual void noteOn(float frequency, float velocity);
|
virtual void noteOn(float frequency, float velocity);
|
||||||
virtual void noteOff();
|
virtual void noteOff();
|
||||||
|
|
||||||
@@ -21,13 +23,23 @@ public:
|
|||||||
|
|
||||||
virtual float process(bool& scopeTrigger);
|
virtual float process(bool& scopeTrigger);
|
||||||
|
|
||||||
protected:
|
uint8_t note() { return note_; }
|
||||||
|
float frequency() { return noteToFrequency(note_); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
inline float noteToFrequency(uint8_t note) {
|
||||||
|
return params_->pitchStandard * pow(params_->octaveConstant, static_cast<float>(note - params_->midiHome) / params_->notesPerOctave);
|
||||||
|
}
|
||||||
|
|
||||||
float sampleRate_ = 1.0f;
|
float sampleRate_ = 1.0f;
|
||||||
bool active_ = false;
|
bool active_ = false;
|
||||||
|
|
||||||
ConfigService* config_;
|
ConfigService* config_;
|
||||||
LoggerService* logger_;
|
LoggerService* logger_;
|
||||||
|
AudioParams* params_;
|
||||||
|
|
||||||
|
uint8_t note_;
|
||||||
|
|
||||||
static constexpr float pi = 3.14159265358979323846f;
|
static constexpr float pi = 3.14159265358979323846f;
|
||||||
float phase_ = 0.0f;
|
float phase_ = 0.0f;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
#include "PianoString.hpp"
|
#include "PianoString.hpp"
|
||||||
|
|
||||||
PianoString::PianoString(ConfigService* config, LoggerService* logger, float sampleRate) : Instrument(config, logger, sampleRate) {
|
PianoString::PianoString(ConfigService* config, LoggerService* logger, float sampleRate, AudioParams* params) : Instrument(config, logger, sampleRate, params) {
|
||||||
|
|
||||||
stringY_current_.resize(segmentCount_ + 1);
|
stringY_current_.resize(segmentCount_ + 1);
|
||||||
stringY_previous_.resize(segmentCount_ + 1);
|
stringY_previous_.resize(segmentCount_ + 1);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class PianoString : public Instrument {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
PianoString() = default;
|
PianoString() = default;
|
||||||
PianoString(ConfigService* config, LoggerService* logger, float sampleRate);
|
PianoString(ConfigService* config, LoggerService* logger, float sampleRate, AudioParams* params);
|
||||||
~PianoString() = default;
|
~PianoString() = default;
|
||||||
|
|
||||||
void noteOn(float frequency, float velocity) override;
|
void noteOn(float frequency, float velocity) override;
|
||||||
|
|||||||
@@ -2,12 +2,17 @@
|
|||||||
#include "WavetableOscillator.hpp"
|
#include "WavetableOscillator.hpp"
|
||||||
|
|
||||||
|
|
||||||
WavetableOscillator::WavetableOscillator(ConfigService* config, LoggerService* logger, float sampleRate) {
|
WavetableOscillator::WavetableOscillator(ConfigService* config, LoggerService* logger, WavetableLoader* wavetabler, float sampleRate, AudioParams* params)
|
||||||
|
: Instrument(config, logger, sampleRate, params), wavetableLoader_(wavetabler) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WavetableOscillator::noteOn(float frequency, float velocity) {
|
void WavetableOscillator::noteOn(float frequency, float velocity) {
|
||||||
envelope_.noteOn(); // hmm we can scale this by velocity
|
envelope_.noteOn(); // hmm we can scale this by velocity
|
||||||
|
|
||||||
|
frequency_ = frequency;
|
||||||
|
phaseIncrement_ = 2.0f * kPi_ * frequency_ / sampleRate_;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WavetableOscillator::noteOff() {
|
void WavetableOscillator::noteOff() {
|
||||||
@@ -19,12 +24,18 @@ bool WavetableOscillator::isActive() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float WavetableOscillator::process(bool& scopeTrigger) {
|
float WavetableOscillator::process(bool& scopeTrigger) {
|
||||||
// return wavetable_.process() * envelope_.process();
|
|
||||||
// more like
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WavetableOscillator::loadWavetable(std::string filename) {
|
if(wavetableLoader_ == nullptr) {
|
||||||
return false;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float sampleOut = wavetableLoader_->sample(wavetableId_, phase_);
|
||||||
|
|
||||||
|
phase_ += phaseIncrement_;
|
||||||
|
if(phase_ > 2.0f * kPi_) {
|
||||||
|
phase_ -= 2.0f * kPi_;
|
||||||
|
scopeTrigger = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sampleOut;
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,13 +5,14 @@
|
|||||||
|
|
||||||
#include "synth/instruments/Instrument.hpp"
|
#include "synth/instruments/Instrument.hpp"
|
||||||
#include "synth/Envelope.hpp"
|
#include "synth/Envelope.hpp"
|
||||||
|
#include "synth/WavetableLoader.hpp"
|
||||||
|
|
||||||
class WavetableOscillator : public Instrument {
|
class WavetableOscillator : public Instrument {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
WavetableOscillator() = default;
|
WavetableOscillator() = default;
|
||||||
WavetableOscillator(ConfigService* config, LoggerService* logger, float sampleRate);
|
WavetableOscillator(ConfigService* config, LoggerService* logger, WavetableLoader* wavetabler, float sampleRate, AudioParams* params);
|
||||||
~WavetableOscillator() = default;
|
~WavetableOscillator() = default;
|
||||||
|
|
||||||
void noteOn(float frequency, float velocity) override;
|
void noteOn(float frequency, float velocity) override;
|
||||||
@@ -21,12 +22,19 @@ public:
|
|||||||
|
|
||||||
float process(bool& scopeTrigger) override;
|
float process(bool& scopeTrigger) override;
|
||||||
|
|
||||||
|
bool setWavetableId(size_t id) { wavetableId_ = id; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool loadWavetable(std::string filename); // TODO: load from conf file instead
|
WavetableLoader* wavetableLoader_;
|
||||||
|
size_t wavetableId_ = 0;
|
||||||
std::vector<float> wavetable_;
|
|
||||||
|
|
||||||
Envelope envelope_;
|
Envelope envelope_;
|
||||||
|
|
||||||
|
// float phase_ = 0.0f; inherited from parent class
|
||||||
|
float frequency_ = 0.0f;
|
||||||
|
float phaseIncrement = 0.0f;
|
||||||
|
|
||||||
|
static constexpr float kPi_ = 3.14159265358979323846;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#include "Synth.hpp"
|
#include "Synth.hpp"
|
||||||
|
|
||||||
Synth::Synth(ConfigService* config, LoggerService* logger, ScopeBuffer* scope, NoteQueue* queue) :
|
Synth::Synth(ConfigService* config, LoggerService* logger, ScopeBuffer* scope, NoteQueue* queue) :
|
||||||
config_(config), logger_(logger), scope_(scope), noteQueue_(queue) {
|
config_(config), logger_(logger), scope_(scope), noteQueue_(queue), instrumentFactory_(config_, logger_) {
|
||||||
|
|
||||||
// load audio settings from config service
|
// load audio settings from config service
|
||||||
if(!(config->getConfig<AudioParams, AudioConfig>("AudioEngine", "Main", &engineConfiguration_))) {
|
if(!(config->getConfig<AudioParams, AudioConfig>("AudioEngine", "Main", &engineConfiguration_))) {
|
||||||
@@ -12,7 +12,14 @@ Synth::Synth(ConfigService* config, LoggerService* logger, ScopeBuffer* scope, N
|
|||||||
// note: this is the audio engine's configuration so we can grab sample rate
|
// note: this is the audio engine's configuration so we can grab sample rate
|
||||||
// it includes some synth params as well, so when synth gets its own config node they all need to be moved
|
// it includes some synth params as well, so when synth gets its own config node they all need to be moved
|
||||||
|
|
||||||
voices_.assign(engineConfiguration_.maxVoices, Voice(config_, logger_, static_cast<float>(engineConfiguration_.sampleRate), &engineConfiguration_));
|
int32_t instrumentsCreated = instrumentFactory_.createInstruments(&instruments_, engineConfiguration_.maxVoices, static_cast<float>(engineConfiguration_.sampleRate), &engineConfiguration_);
|
||||||
|
if(instrumentsCreated == 0) {
|
||||||
|
logger_->log("Audio", LogFlag::Error, "Failed to create any voices from factory.");
|
||||||
|
} else if(instrumentsCreated > engineConfiguration_.maxVoices) {
|
||||||
|
logger_->log("Audio", LogFlag::Warning, "Created too many voices, possible truncation or overflow.");
|
||||||
|
} else {
|
||||||
|
logger_->log("Audio", LogFlag::Info, "Created voices from factory.");
|
||||||
|
}
|
||||||
|
|
||||||
filter_.setSampleRate(engineConfiguration_.sampleRate);
|
filter_.setSampleRate(engineConfiguration_.sampleRate);
|
||||||
filter_.setParams(Filter::Type::BiquadLowpass, 4000.0f, 0.707f);
|
filter_.setParams(Filter::Type::BiquadLowpass, 4000.0f, 0.707f);
|
||||||
@@ -22,16 +29,16 @@ Synth::Synth(ConfigService* config, LoggerService* logger, ScopeBuffer* scope, N
|
|||||||
void Synth::handleNoteEvent(const NoteEvent& event) {
|
void Synth::handleNoteEvent(const NoteEvent& event) {
|
||||||
|
|
||||||
// stop all voices that are currently playing this note
|
// stop all voices that are currently playing this note
|
||||||
for(Voice& v : voices_) {
|
for(Instrument* i : instruments_) {
|
||||||
if(v.isActive() && v.note() == event.note) {
|
if(i->isActive() && i->note() == event.note) {
|
||||||
v.noteOff();
|
i->noteOff();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// call note-on for an idle voice for the note-event
|
// call note-on for an idle voice for the note-event
|
||||||
if(event.type == NoteEventType::NoteOn) {
|
if(event.type == NoteEventType::NoteOn) {
|
||||||
Voice* v = findFreeVoice();
|
Instrument* i = findFreeVoice();
|
||||||
if(v != nullptr) v->noteOn(event.note, event.velocity);
|
if(i != nullptr) i->startNote(event.note, event.velocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -46,9 +53,9 @@ void Synth::process(float* out, size_t nFrames) {
|
|||||||
// find lowest frequency voice for scope triggering
|
// find lowest frequency voice for scope triggering
|
||||||
size_t lowestVoice = 0;
|
size_t lowestVoice = 0;
|
||||||
float lowestFreq = FLT_MAX;
|
float lowestFreq = FLT_MAX;
|
||||||
for(size_t i = 0; i < voices_.size(); i++) {
|
for(size_t i = 0; i < instruments_.size(); i++) {
|
||||||
if(!voices_[i].isActive()) continue;
|
if(!instruments_[i]->isActive()) continue;
|
||||||
float currentFreq = voices_[i].frequency();
|
float currentFreq = instruments_[i]->frequency();
|
||||||
if(currentFreq < lowestFreq) {
|
if(currentFreq < lowestFreq) {
|
||||||
lowestVoice = i;
|
lowestVoice = i;
|
||||||
lowestFreq = currentFreq;
|
lowestFreq = currentFreq;
|
||||||
@@ -66,10 +73,10 @@ void Synth::process(float* out, size_t nFrames) {
|
|||||||
|
|
||||||
// process all active voices and mix their produced samples
|
// process all active voices and mix their produced samples
|
||||||
float mix = 0.0f;
|
float mix = 0.0f;
|
||||||
for(size_t j = 0; j < voices_.size(); j++) {
|
for(size_t j = 0; j < instruments_.size(); j++) {
|
||||||
bool temp = false;
|
bool temp = false;
|
||||||
if(!voices_[j].isActive()) continue;
|
if(!instruments_[j]->isActive()) continue;
|
||||||
mix += voices_[j].process(temp);
|
mix += instruments_[j]->process(temp);
|
||||||
if(j == lowestVoice) triggered = temp;
|
if(j == lowestVoice) triggered = temp;
|
||||||
}
|
}
|
||||||
mix = tanh(mix); // prevent clipping
|
mix = tanh(mix); // prevent clipping
|
||||||
@@ -89,21 +96,21 @@ void Synth::process(float* out, size_t nFrames) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Voice* Synth::findFreeVoice() {
|
Instrument* Synth::findFreeVoice() {
|
||||||
|
|
||||||
for(Voice& v : voices_) {
|
for(Instrument* i : instruments_) {
|
||||||
if(!v.isActive()) {
|
if(!i->isActive()) {
|
||||||
return &v;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Voice* Synth::findVoiceByNote(uint8_t note) {
|
Instrument* Synth::findVoiceByNote(uint8_t note) {
|
||||||
|
|
||||||
for(Voice& v : voices_) {
|
for(Instrument* i : instruments_) {
|
||||||
if(v.isActive() && v.note() == note) {
|
if(i->isActive() && i->note() == note) {
|
||||||
return &v;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|||||||
@@ -5,9 +5,10 @@
|
|||||||
#include "config/AudioConfig.hpp"
|
#include "config/AudioConfig.hpp"
|
||||||
#include "LoggerService.hpp"
|
#include "LoggerService.hpp"
|
||||||
#include "NoteQueue.hpp"
|
#include "NoteQueue.hpp"
|
||||||
#include "Voice.hpp"
|
|
||||||
#include "Scope.hpp"
|
#include "Scope.hpp"
|
||||||
#include "Filter.hpp"
|
#include "Filter.hpp"
|
||||||
|
#include "Instruments/Instrument.hpp"
|
||||||
|
#include "InstrumentFactory.hpp"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -23,20 +24,21 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Voice* findFreeVoice();
|
Instrument* findFreeVoice();
|
||||||
Voice* findVoiceByNote(uint8_t note);
|
Instrument* findVoiceByNote(uint8_t note);
|
||||||
|
|
||||||
std::vector<uint8_t> sustainedNotes_;
|
std::vector<uint8_t> sustainedNotes_;
|
||||||
Filter filter_;
|
Filter filter_;
|
||||||
|
|
||||||
// voices
|
// voices
|
||||||
size_t maxVoices;
|
size_t maxVoices;
|
||||||
std::vector<Voice> voices_;
|
std::vector<Instrument*> instruments_;
|
||||||
|
|
||||||
ConfigService* config_;
|
ConfigService* config_;
|
||||||
AudioParams engineConfiguration_;
|
AudioParams engineConfiguration_;
|
||||||
LoggerService* logger_;
|
LoggerService* logger_;
|
||||||
ScopeBuffer* scope_;;
|
ScopeBuffer* scope_;
|
||||||
NoteQueue* noteQueue_;
|
NoteQueue* noteQueue_;
|
||||||
|
InstrumentFactory instrumentFactory_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
|
|
||||||
#include "Voice.hpp"
|
|
||||||
|
|
||||||
Voice::Voice(ConfigService* config, LoggerService* logger, float sampleRate, AudioParams* params) :
|
|
||||||
config_(config), logger_(logger), sampleRate_(sampleRate), params_(params) {
|
|
||||||
|
|
||||||
// TODO: instrument factory << WHAT DO YOU MEAN JUST TODO A WHOLE FACTORY
|
|
||||||
instrument_ = PianoString(config_, logger_, sampleRate_);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Voice::noteOn(uint8_t midiNote, float velocity) {
|
|
||||||
|
|
||||||
note_ = midiNote;
|
|
||||||
instrument_.noteOn(noteToFrequency(midiNote), velocity);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Voice::noteOff() {
|
|
||||||
|
|
||||||
instrument_.noteOff();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Voice::isActive() {
|
|
||||||
|
|
||||||
return instrument_.isActive();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
float Voice::process(bool& scopeTrigger) {
|
|
||||||
|
|
||||||
return instrument_.process(scopeTrigger);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "instruments/Instrument.hpp"
|
|
||||||
#include "instruments/PianoString.hpp"
|
|
||||||
#include "config/AudioConfig.hpp"
|
|
||||||
|
|
||||||
// a voice is a tone generator that the synth uses for polyphony
|
|
||||||
// the synth mixes multiple voices together into a polyphonic audio. calculations for samples are handled in the instrument
|
|
||||||
class Voice {
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Voice() = default;
|
|
||||||
Voice(ConfigService* config, LoggerService* logger, float sampleRate, AudioParams* params);
|
|
||||||
~Voice() = default;
|
|
||||||
|
|
||||||
void noteOn(uint8_t midiNote, float velocity);
|
|
||||||
void noteOff();
|
|
||||||
bool isActive();
|
|
||||||
|
|
||||||
float process(bool& scopeTrigger);
|
|
||||||
uint8_t note() { return note_; }
|
|
||||||
float frequency() { return noteToFrequency(note_); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
inline float noteToFrequency(uint8_t note) {
|
|
||||||
return params_->pitchStandard * pow(params_->octaveConstant, static_cast<float>(note - params_->midiHome) / params_->notesPerOctave);
|
|
||||||
}
|
|
||||||
|
|
||||||
float sampleRate_ = 1.0f;
|
|
||||||
uint8_t note_ = 0;
|
|
||||||
float velocity_ = 1.0f;
|
|
||||||
bool active_ = false;
|
|
||||||
|
|
||||||
ConfigService* config_;
|
|
||||||
AudioParams* params_;
|
|
||||||
LoggerService* logger_;
|
|
||||||
PianoString instrument_;
|
|
||||||
|
|
||||||
};
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
// placeholder to handle loading wavetables from files
|
// placeholder to handle loading wavetables from files
|
||||||
// so that wavetables can be shared to each voice/instrument
|
// so that wavetables can be shared to each voice/instrument
|
||||||
// only need to need to load once for x number of voices
|
// only need to need to load once for x number of voices
|
||||||
|
|||||||
Reference in New Issue
Block a user