[feature]: ADSR #15
@@ -26,6 +26,7 @@ release_samples = int(release_time * sample_rate)
|
||||
|
||||
# Attack phase
|
||||
envelope[:attack_samples] = np.linspace(0, 1, num=attack_samples)
|
||||
# 1/n * count;
|
||||
|
||||
# Decay phase
|
||||
decay_slope = (1 - sustain_level) / decay_samples
|
||||
|
||||
31
inc/ADSR.h
Normal file
31
inc/ADSR.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include "Effect.h"
|
||||
#include <cstddef>
|
||||
|
||||
struct ADSRParameters {
|
||||
float attack_time; // Attack time in seconds
|
||||
float decay_time; // Decay time in seconds
|
||||
float sustain_level; // Sustain level (0 to 1)
|
||||
float release_time;
|
||||
};
|
||||
|
||||
enum ADSRState { Attack, Decay, Sustain, Release };
|
||||
|
||||
class ADSR : public Effect {
|
||||
private:
|
||||
ADSRParameters m_parameters;
|
||||
ADSRState m_state;
|
||||
std::size_t m_counter;
|
||||
void set_state(std::size_t attack_samples, std::size_t decay_samples,
|
||||
std::size_t release_samples);
|
||||
void process_sample(float* sample, std::size_t attack_samples,
|
||||
std::size_t decay_samples, std::size_t release_samples);
|
||||
|
||||
public:
|
||||
ADSR(/* args */);
|
||||
ADSR(ADSRParameters param);
|
||||
~ADSR();
|
||||
void RetriggerState() override;
|
||||
void Process(std::vector<float>& samples) override;
|
||||
void Reset();
|
||||
};
|
||||
11
inc/Effect.h
Normal file
11
inc/Effect.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
class Effect {
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
Effect(/* args */){};
|
||||
~Effect(){};
|
||||
virtual void RetriggerState(){};
|
||||
virtual void Process(std::vector<float>& samples){};
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Adder.h"
|
||||
#include "Effect.h"
|
||||
#include "Note.h"
|
||||
#include "Oscillator.h"
|
||||
#include "Settings.h"
|
||||
@@ -10,16 +11,19 @@ class Synth {
|
||||
private:
|
||||
std::vector<Oscillator*> m_oscillators;
|
||||
Adder m_adder;
|
||||
std::vector<Effect*> m_effects;
|
||||
// OscillatorUI* ui_oscillators;
|
||||
// Note m_current_note;
|
||||
std::vector<float> m_out_signal;
|
||||
std::vector<float>& get_note(int semitone, float beats);
|
||||
void apply_effects();
|
||||
|
||||
public:
|
||||
Synth(/* args */);
|
||||
~Synth();
|
||||
void ProduceNoteSound(Note input);
|
||||
void AddOscillator();
|
||||
void AddEffect(Effect* fx);
|
||||
const std::vector<float>& GetOutSignal() { return m_out_signal; }
|
||||
const std::vector<Oscillator*>& GetOscillators() { return m_oscillators; }
|
||||
};
|
||||
63
src/ADSR.cpp
Normal file
63
src/ADSR.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#include "ADSR.h"
|
||||
#include "Settings.h"
|
||||
#include "Logger.h"
|
||||
|
||||
ADSR::ADSR(/* args */) {
|
||||
m_parameters.attack_time = 0.025f;
|
||||
m_parameters.decay_time = 0.3f;
|
||||
m_parameters.sustain_level = 0.6f;
|
||||
m_parameters.release_time = 1.0f;
|
||||
m_counter = 0;
|
||||
}
|
||||
|
||||
ADSR::ADSR(ADSRParameters param) {
|
||||
m_parameters = param;
|
||||
m_counter = 0;
|
||||
}
|
||||
|
||||
ADSR::~ADSR() {}
|
||||
|
||||
void ADSR::set_state(std::size_t attack_samples, std::size_t decay_samples,
|
||||
std::size_t release_samples) {
|
||||
if (m_counter < attack_samples) {
|
||||
m_state = Attack;
|
||||
} else if (m_counter >= attack_samples &&
|
||||
m_counter < attack_samples + decay_samples) {
|
||||
m_state = Decay;
|
||||
} else if (m_counter >= attack_samples + decay_samples) {
|
||||
m_state = Sustain;
|
||||
}
|
||||
}
|
||||
|
||||
void ADSR::process_sample(float* sample, std::size_t attack_samples,
|
||||
std::size_t decay_samples,
|
||||
std::size_t release_samples) {
|
||||
|
||||
set_state(attack_samples, decay_samples, release_samples);
|
||||
if (m_state == Attack) {
|
||||
(*sample) = (float)(1.f / attack_samples) * m_counter;
|
||||
} else if (m_state == Decay) {
|
||||
}
|
||||
m_counter++;
|
||||
// todo: release state on note off (in reset function?)
|
||||
}
|
||||
|
||||
void ADSR::RetriggerState() {
|
||||
m_counter = 0;
|
||||
m_state = Attack;
|
||||
}
|
||||
|
||||
void ADSR::Process(std::vector<float>& samples) {
|
||||
const std::size_t attack_samples =
|
||||
(std::size_t)(m_parameters.attack_time * SAMPLE_RATE);
|
||||
const std::size_t decay_samples =
|
||||
(std::size_t)(m_parameters.decay_time * SAMPLE_RATE);
|
||||
const std::size_t release_samples =
|
||||
(std::size_t)(m_parameters.release_time * SAMPLE_RATE);
|
||||
write_log("Attack samples: %zu \n", attack_samples);
|
||||
for (std::size_t i = 0; i < samples.size(); i++) {
|
||||
process_sample(&samples[i], attack_samples, decay_samples,
|
||||
release_samples);
|
||||
}
|
||||
write_log("Processed samples: %zu \n", m_counter);
|
||||
}
|
||||
@@ -1,11 +1,19 @@
|
||||
#include "Synth.h"
|
||||
#include "ADSR.h"
|
||||
#include "KeyBoard.h"
|
||||
#include "OscillatorType.h"
|
||||
#include "Settings.h"
|
||||
|
||||
Synth::Synth(/* args */) { AddOscillator(); }
|
||||
Synth::Synth(/* args */) {
|
||||
AddOscillator();
|
||||
AddEffect(new ADSR());
|
||||
}
|
||||
|
||||
Synth::~Synth() {}
|
||||
Synth::~Synth() {
|
||||
m_oscillators.clear();
|
||||
m_effects.clear();
|
||||
m_out_signal.clear();
|
||||
}
|
||||
|
||||
std::vector<float>& Synth::get_note(int semitone, float beats) {
|
||||
float hz = KeyBoard::GetHzBySemitone(semitone);
|
||||
@@ -20,13 +28,24 @@ std::vector<float>& Synth::get_note(int semitone, float beats) {
|
||||
return m_adder.SumOscillators(m_oscillators, duration);
|
||||
}
|
||||
|
||||
void Synth::apply_effects() {
|
||||
for (Effect* effect : m_effects) {
|
||||
// maybe not here
|
||||
effect->RetriggerState();
|
||||
effect->Process(m_out_signal);
|
||||
}
|
||||
}
|
||||
|
||||
void Synth::ProduceNoteSound(Note input) {
|
||||
float length = 1.f / input.length;
|
||||
int semitone_shift = KeyBoard::GetSemitoneShift(input.name);
|
||||
m_out_signal = get_note(semitone_shift, length);
|
||||
apply_effects();
|
||||
}
|
||||
|
||||
void Synth::AddOscillator() {
|
||||
m_oscillators.push_back(
|
||||
new Oscillator(OscillatorType::Sine, 440.f, VOLUME));
|
||||
}
|
||||
|
||||
void Synth::AddEffect(Effect* fx) { m_effects.push_back(fx); }
|
||||
|
||||
Reference in New Issue
Block a user