103 lines
2.4 KiB
C++
103 lines
2.4 KiB
C++
|
|
#include "Synth.hpp"
|
|
|
|
Synth::Synth(ConfigService* config, LoggerService* logger, ScopeBuffer* scope, NoteQueue* queue) :
|
|
config_(config), logger_(logger), scope_(scope), noteQueue_(queue) {
|
|
|
|
voices_.fill(Voice(config_, logger_));
|
|
|
|
filter_.setSampleRate(44100.0f);
|
|
filter_.setParams(Filter::Type::BiquadLowpass, 4000.0f, 0.707f);
|
|
|
|
}
|
|
|
|
void Synth::handleNoteEvent(const NoteEvent& event) {
|
|
|
|
// Voice* v = findVoiceByNote(event.note);
|
|
// if(v != nullptr) v->noteOff();
|
|
|
|
// stop all voices that are currently playing this note
|
|
for(Voice& v : voices_) {
|
|
if(v.isActive() && v.note() == event.note) {
|
|
v.noteOff();
|
|
}
|
|
}
|
|
|
|
if(event.type == NoteEventType::NoteOn) {
|
|
|
|
Voice* v = findFreeVoice();
|
|
if(v != nullptr) v->noteOn(event.note, event.velocity);
|
|
}
|
|
|
|
}
|
|
|
|
void Synth::process(float* out, size_t nFrames) {
|
|
|
|
NoteEvent noteEvent;
|
|
while(noteQueue_->pop(noteEvent)) {
|
|
handleNoteEvent(noteEvent);
|
|
}
|
|
|
|
size_t lowestVoice = 0;
|
|
float lowestFreq = 100000.0f;
|
|
for(size_t i = 0; i < voices_.size(); i++) {
|
|
if(!voices_[i].isActive()) continue;
|
|
float currentFreq = voices_[i].frequency();
|
|
if(currentFreq < lowestFreq) {
|
|
lowestVoice = i;
|
|
lowestFreq = currentFreq;
|
|
}
|
|
}
|
|
|
|
scope_->spinlock(true);
|
|
|
|
float sampleOut = 0.0f;
|
|
bool triggered = false;
|
|
bool once = false;
|
|
for(size_t i = 0; i < nFrames; i++) {
|
|
|
|
float mix = 0.0f;
|
|
for(size_t j = 0; j < voices_.size(); j++) {
|
|
bool temp = false;
|
|
if(!voices_[j].isActive()) continue;
|
|
mix += voices_[j].process(temp);
|
|
if(j == lowestVoice) triggered = temp;
|
|
}
|
|
mix = tanh(mix); // prevent clipping
|
|
|
|
sampleOut = filter_.biquadProcess(mix);
|
|
out[2*i] = sampleOut;
|
|
out[2*i+1] = sampleOut;
|
|
|
|
if(scope_) scope_->push(sampleOut);
|
|
if(triggered && !once) {
|
|
scope_->setTrigger(i);
|
|
once = true;
|
|
}
|
|
}
|
|
|
|
scope_->spinlock(false);
|
|
|
|
|
|
}
|
|
|
|
Voice* Synth::findFreeVoice() {
|
|
|
|
for(Voice& v : voices_) {
|
|
if(!v.isActive()) {
|
|
return &v;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Voice* Synth::findVoiceByNote(uint8_t note) {
|
|
|
|
for(Voice& v : voices_) {
|
|
if(v.isActive() && v.note() == note) {
|
|
return &v;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|