[feature]: ADSR #15
16
inc/Adder.h
16
inc/Adder.h
@@ -6,23 +6,21 @@
|
||||
#include <vector>
|
||||
|
||||
struct Adder {
|
||||
static std::vector<float>&
|
||||
static void
|
||||
SumOscillators(const std::vector<Oscillator*>& oscillators,
|
||||
float duration) {
|
||||
size_t sample_count = (size_t)(1.f/FPS * SAMPLE_RATE);
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ class Application {
|
||||
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();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#define SAMPLE_RATE 48000.f
|
||||
#define SAMPLE_RATE 44100.f
|
||||
#define BPM 120.f
|
||||
#define BEAT_DURATION 60.f/BPM
|
||||
#define PITCH_STANDARD 440.f
|
||||
|
||||
@@ -15,13 +15,14 @@ class Synth {
|
||||
// OscillatorUI* ui_oscillators;
|
||||
// Note m_current_note;
|
||||
std::vector<float> m_out_signal;
|
||||
std::vector<float>& get_note(int semitone, float beats);
|
||||
void get_note(int semitone, float beats);
|
||||
void apply_effects();
|
||||
|
||||
public:
|
||||
Synth(/* args */);
|
||||
~Synth();
|
||||
void ProduceNoteSound(Note input);
|
||||
void StopNoteSound();
|
||||
void AddOscillator();
|
||||
void AddEffect(Effect* fx);
|
||||
const std::vector<float>& GetOutSignal() { return m_out_signal; }
|
||||
|
||||
@@ -55,72 +55,82 @@ void Application::init_synth() {
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t Application::detect_note_pressed(Note* note) {
|
||||
bool Application::detect_note_pressed(Note* note) {
|
||||
std::size_t is_pressed = 0;
|
||||
note->length = 8;
|
||||
if (IsKeyPressed(KEY_A)) {
|
||||
if (IsKeyDown(KEY_A)) {
|
||||
note->name.assign("A4");
|
||||
is_pressed = 1;
|
||||
}
|
||||
if (IsKeyPressed(KEY_B)) {
|
||||
if (IsKeyDown(KEY_B)) {
|
||||
note->name.assign("B4");
|
||||
is_pressed = 1;
|
||||
}
|
||||
if (IsKeyPressed(KEY_C)) {
|
||||
note->name.assign("C4");
|
||||
if (IsKeyDown(KEY_C)) {
|
||||
note->name.assign("C5");
|
||||
is_pressed = 1;
|
||||
}
|
||||
if (IsKeyPressed(KEY_D)) {
|
||||
note->name.assign("D4");
|
||||
if (IsKeyDown(KEY_D)) {
|
||||
note->name.assign("D5");
|
||||
is_pressed = 1;
|
||||
}
|
||||
if (IsKeyPressed(KEY_E)) {
|
||||
note->name.assign("E4");
|
||||
if (IsKeyDown(KEY_E)) {
|
||||
note->name.assign("E5");
|
||||
is_pressed = 1;
|
||||
}
|
||||
if (IsKeyPressed(KEY_F)) {
|
||||
note->name.assign("F4");
|
||||
if (IsKeyDown(KEY_F)) {
|
||||
note->name.assign("F5");
|
||||
is_pressed = 1;
|
||||
}
|
||||
if (IsKeyPressed(KEY_G)) {
|
||||
note->name.assign("G4");
|
||||
if (IsKeyDown(KEY_G)) {
|
||||
note->name.assign("G5");
|
||||
is_pressed = 1;
|
||||
}
|
||||
return is_pressed;
|
||||
return is_pressed == 1;
|
||||
}
|
||||
|
||||
// Update On Input
|
||||
void Application::update_on_note_input() {
|
||||
detect_note_pressed(m_current_note);
|
||||
// if (detect_note_pressed(m_current_note)) {
|
||||
if (detect_note_pressed(m_current_note)) {
|
||||
// if (detect_note_pressed(m_current_note)) {
|
||||
m_synth.ProduceNoteSound((*m_current_note));
|
||||
//m_sound_played_count = 0;
|
||||
write_log("Note played: %s\n", m_current_note->name.c_str());
|
||||
//}
|
||||
//}
|
||||
}
|
||||
else {
|
||||
m_synth.StopNoteSound();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Play ring-buffered audio
|
||||
void Application::play_buffered_audio() {
|
||||
std::size_t size_to_read = m_ring_buffer->GetSize();
|
||||
size_t sample_count = (size_t)(1.f/FPS * SAMPLE_RATE);
|
||||
//std::size_t size_to_read = m_ring_buffer->GetSize();
|
||||
size_t sample_count = STREAM_BUFFER_SIZE;//(size_t)(1.f/FPS * SAMPLE_RATE);
|
||||
if (IsAudioStreamProcessed(m_synth_stream)) {
|
||||
write_log("Samples to play:%zu \n", size_to_read);
|
||||
//write_log("Samples to play:%zu \n", size_to_read);
|
||||
// todo: try to start reading directly from ring buffer, avoiding
|
||||
// temp_buffer
|
||||
//todo: can be optimized to only move pointers, without the usage of temp buffer
|
||||
|
||||
//m_synth.ProduceNoteSound((*m_current_note));
|
||||
// can try the SetAudioStreamCallback
|
||||
UpdateAudioStream(m_synth_stream, m_temp_buffer, sample_count);
|
||||
const float audio_frame_start_time = GetTime();
|
||||
update_on_note_input();
|
||||
UpdateAudioStream(m_synth_stream, m_synth.GetOutSignal().data(), sample_count);
|
||||
// can overwrite the ring buffer to avoid that
|
||||
const float audio_freme_duration = GetTime() - audio_frame_start_time;
|
||||
write_log("Frame time: %.3f%% \n", 100.0f / ((1.0f / audio_freme_duration) / ((float)SAMPLE_RATE/STREAM_BUFFER_SIZE)));
|
||||
|
||||
|
||||
// if (m_synth.GetOutSignal().size() == m_sound_played_count) {
|
||||
// m_ring_buffer->Reset();
|
||||
// }
|
||||
}
|
||||
m_ring_buffer->Read(m_temp_buffer, sample_count);
|
||||
m_ring_buffer->Reset();
|
||||
if (m_ring_buffer->IsFull() || m_ring_buffer->IsEmpty()) {
|
||||
}
|
||||
//m_ring_buffer->Read(m_temp_buffer, sample_count);
|
||||
//m_ring_buffer->Reset();
|
||||
//if (m_ring_buffer->IsFull() || m_ring_buffer->IsEmpty()) {
|
||||
//}
|
||||
}
|
||||
|
||||
// Fill ring buffer from current sound
|
||||
@@ -154,9 +164,9 @@ void Application::Run() {
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
fill_audio_buffer();
|
||||
//fill_audio_buffer();
|
||||
//update_on_note_input();
|
||||
play_buffered_audio();
|
||||
update_on_note_input();
|
||||
|
||||
m_renderer.Draw(m_synth, m_synth_gui_state);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
Synth::Synth(/* args */) {
|
||||
AddOscillator();
|
||||
AddEffect(new ADSR());
|
||||
for (size_t i = 0; i < STREAM_BUFFER_SIZE; i++) {
|
||||
float sample = 0.0f;
|
||||
m_out_signal.push_back(sample);
|
||||
}
|
||||
}
|
||||
|
||||
Synth::~Synth() {
|
||||
@@ -15,9 +19,13 @@ Synth::~Synth() {
|
||||
m_out_signal.clear();
|
||||
}
|
||||
|
||||
std::vector<float>& Synth::get_note(int semitone, float beats) {
|
||||
void Synth::get_note(int semitone, float beats) {
|
||||
for (size_t i = 0; i < STREAM_BUFFER_SIZE; i++) {
|
||||
float sample = 0.0f;
|
||||
m_out_signal[i] = sample;
|
||||
}
|
||||
|
||||
float hz = KeyBoard::GetHzBySemitone(semitone);
|
||||
float duration = beats * BEAT_DURATION;
|
||||
|
||||
// will change after oscillator starts to be more autonomous
|
||||
for (Oscillator* osc : m_oscillators) {
|
||||
@@ -25,7 +33,7 @@ std::vector<float>& Synth::get_note(int semitone, float beats) {
|
||||
}
|
||||
|
||||
// todo: add other pipeline steps (e.g ADSR, Filters, FX);
|
||||
return m_adder.SumOscillators(m_oscillators, duration);
|
||||
Adder::SumOscillators(m_oscillators, m_out_signal);
|
||||
}
|
||||
|
||||
void Synth::apply_effects() {
|
||||
@@ -39,10 +47,17 @@ void Synth::apply_effects() {
|
||||
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);
|
||||
get_note(semitone_shift, length);
|
||||
apply_effects();
|
||||
}
|
||||
|
||||
void Synth::StopNoteSound() {
|
||||
for (size_t i = 0; i < STREAM_BUFFER_SIZE; i++) {
|
||||
float sample = 0.0f;
|
||||
m_out_signal[i] = sample;
|
||||
}
|
||||
}
|
||||
|
||||
void Synth::AddOscillator() {
|
||||
m_oscillators.push_back(
|
||||
new Oscillator(OscillatorType::Sine, 440.f, VOLUME));
|
||||
|
||||
Reference in New Issue
Block a user