[feature]: ADSR (#15)

closes #14

Reviewed-on: #15
This commit is contained in:
2023-09-06 11:29:46 +03:00
parent 64fa6396bc
commit c50a8335d7
20 changed files with 444 additions and 140 deletions

37
inc/ADSR.h Normal file
View File

@@ -0,0 +1,37 @@
#pragma once
#include "Effect.h"
#include "Ramp.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 { Off, Attack, Decay, Sustain, Release };
class ADSR : public Effect {
private:
ADSRParameters m_parameters;
ADSRState m_state;
Ramp* m_ramp;
void process_sample(float* sample);
bool is_attack_elapsed();
bool is_decay_elapsed();
bool is_release_elapsed();
void recheck_state();
public:
ADSR(/* args */);
ADSR(ADSRParameters param);
~ADSR();
void OnSetNote() override;
void OnUnsetNote() override;
// void RetriggerState() override;
void Process(std::vector<float>& samples) override;
void Reset();
void SetParameters(float attack, float decay, float sustain, float release);
};

View File

@@ -6,23 +6,21 @@
#include <vector>
struct Adder {
static std::vector<float>&
SumOscillators(const std::vector<Oscillator*>& oscillators,
float duration) {
size_t sample_count = (size_t)(duration * SAMPLE_RATE);
static void SumOscillators(const std::vector<Oscillator*>& oscillators,
std::vector<float>& signal) {
size_t sample_count =
STREAM_BUFFER_SIZE; //(size_t)(1.f/FPS * SAMPLE_RATE);
std::vector<float>* output = new std::vector<float>();
output->reserve(sample_count);
// std::vector<float>* output = new std::vector<float>();
// output->reserve(sample_count);
for (size_t i = 0; i < sample_count; i++) {
float sample = 0.0f;
for (Oscillator* osc : oscillators) {
sample += osc->GenerateSample(duration);
sample += osc->GenerateSample(1.f);
}
output->push_back(sample);
signal[i] = sample;
}
return (*output);
}
};

View File

@@ -1,7 +1,6 @@
#pragma once
#include "Note.h"
#include "Renderer.h"
#include "RingBuffer.h"
#include "Synth.h"
#include "SynthGuiState.h"
#include "raylib.h"
@@ -10,18 +9,15 @@ class Application {
private:
Synth m_synth;
SynthGuiState m_synth_gui_state;
RingBuffer<float>* m_ring_buffer;
AudioStream m_synth_stream;
int m_sound_played_count;
float* m_temp_buffer;
Note* m_current_note;
Renderer m_renderer;
std::size_t detect_note_pressed(Note* note);
bool detect_note_pressed(Note* note);
void init_synth();
void init_audio();
void update_on_note_input();
void play_buffered_audio();
void fill_audio_buffer();
public:
Application(/* args */);

13
inc/Effect.h Normal file
View File

@@ -0,0 +1,13 @@
#pragma once
#include <vector>
class Effect {
private:
/* data */
public:
Effect(/* args */){};
~Effect(){};
virtual void OnSetNote(){};
virtual void OnUnsetNote(){};
// virtual void RetriggerState(){};
virtual void Process(std::vector<float>& samples){};
};

16
inc/Ramp.h Normal file
View File

@@ -0,0 +1,16 @@
#pragma once
class Ramp {
private:
float m_level;
float m_sample_rate;
float m_increment;
int m_counter;
public:
Ramp(float starting_level, float sample_rate);
~Ramp();
void RampTo(float value, float time);
float Process();
bool IsCompleted();
};

View File

@@ -1,4 +1,5 @@
#pragma once
#include "ADSR.h"
#include "Synth.h"
#include "SynthGuiState.h"
#include "raylib.h"
@@ -8,8 +9,8 @@ class Renderer {
private:
void draw_main_panel(const Rectangle& panel_bounds);
void draw_add_oscillator_button(Synth& synth, SynthGuiState& synth_gui,
Rectangle panel_bounds);
void draw_oscillators_panels(
Rectangle panel_bounds);
float draw_oscillators_panels(
const std::vector<Oscillator*>& oscillators,
const std::vector<OscillatorGuiState*>& gui_oscillators,
const Rectangle& panel_bounds);
@@ -18,6 +19,8 @@ class Renderer {
const std::vector<OscillatorGuiState*>& guiOscillators);
void draw_ui(Synth& synth, SynthGuiState& synth_gui);
void draw_signal(Synth& synth, SynthGuiState& synth_gui);
void draw_adsr_panel(ADSR* adsr, ADSRGuiState& gui_adsr,
const Rectangle& panel_bounds, float panel_y_offset);
public:
Renderer(/* args */);

View File

@@ -1,12 +1,13 @@
#pragma once
#define SAMPLE_RATE 48000.f
#define SAMPLE_RATE 44100.f
#define BPM 120.f
#define BEAT_DURATION 60.f/BPM
#define BEAT_DURATION 60.f / BPM
#define PITCH_STANDARD 440.f
#define VOLUME 0.5f
#define ATTACK_MS 100.f
#define STREAM_BUFFER_SIZE 4096
#define STREAM_BUFFER_SIZE 1024
#define FPS 60
#define SYNTH_PI 3.1415926535f
#define SYNTH_VOLUME 0.5f

View File

@@ -1,6 +1,8 @@
#pragma once
#include "ADSR.h"
#include "Adder.h"
#include "Effect.h"
#include "Note.h"
#include "Oscillator.h"
#include "Settings.h"
@@ -8,18 +10,28 @@
class Synth {
private:
bool is_note_triggered;
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 zero_signal();
void get_note();
void trigger_note_on_effects();
void untrigger_note_on_effects();
void apply_effects();
public:
Synth(/* args */);
~Synth();
void ProduceNoteSound(Note input);
void TriggerNote(Note input);
void ProduceSound();
void StopSound();
void AddOscillator();
void AddEffect(Effect* fx);
const std::vector<float>& GetOutSignal() { return m_out_signal; }
const std::vector<Oscillator*>& GetOscillators() { return m_oscillators; }
const bool& GetIsNoteTriggered() { return is_note_triggered; }
ADSR* GetADSR() { return (ADSR*)m_effects[0]; }
};

View File

@@ -11,6 +11,14 @@ struct OscillatorGuiState {
Rectangle shape_dropdown_rect;
};
struct ADSRGuiState {
float attack;
float decay;
float sustain;
float release;
};
struct SynthGuiState {
std::vector<OscillatorGuiState*> oscillators;
ADSRGuiState adsr;
};