From 7eb6a1755de14ad192f9643b254bf2212ef1cb08 Mon Sep 17 00:00:00 2001 From: e1lama Date: Sun, 18 Jun 2023 14:46:20 +0300 Subject: [PATCH] fix: refactor code structure into files (#8) closes #7 Co-authored-by: HiveBeats Reviewed-on: https://gitea.e1lama.ru/e1lama/SeeSynth/pulls/8 --- .vscode/tasks.json | 4 + build.sh | 2 +- export.c | 74 ++++++++ export.h | 9 + main.c | 463 +-------------------------------------------- oscillator.c | 153 +++++++++++++++ oscillator.h | 33 ++++ ring_buffer.c | 99 ++++++++++ ring_buffer.h | 22 +++ settings.h | 18 ++ utils.c | 30 +++ utils.h | 22 +++ 12 files changed, 473 insertions(+), 456 deletions(-) create mode 100644 export.c create mode 100644 export.h create mode 100644 oscillator.c create mode 100644 oscillator.h create mode 100644 ring_buffer.c create mode 100644 ring_buffer.h create mode 100644 settings.h create mode 100644 utils.c create mode 100644 utils.h diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 1f577ce..f40e7f1 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -9,7 +9,11 @@ "-fansi-escape-codes", "-g", "${file}", + "${fileDirname}/utils.c", + "${fileDirname}/ring_buffer.c", + "${fileDirname}/oscillator.c", "${fileDirname}/parser.c", + "${fileDirname}/export.c", "-lm", "-lraylib", "-o", diff --git a/build.sh b/build.sh index 996cdba..a9c9dfe 100644 --- a/build.sh +++ b/build.sh @@ -1,3 +1,3 @@ #!/bin/bash CC="${CXX:-cc}" -$CC -Wall -std=c11 ./main.c ./parser.c -lm -lraylib -o ./bin/main +$CC -Wall -std=c11 ./main.c ./utils.c ./ring_buffer.c ./oscillator.c ./parser.c ./export.c -lm -lraylib -o ./bin/main diff --git a/export.c b/export.c new file mode 100644 index 0000000..8a231de --- /dev/null +++ b/export.c @@ -0,0 +1,74 @@ +#include "export.h" + +#include "stdio.h" +#include "string.h" +#include "settings.h" + +uint16_t toInt16Sample(float sample) { + return (uint16_t)(sample * 32767.f); +} + +static void write_file(char* filename, void* data, int size) { + FILE* fp = fopen(filename, "wb"); // open file for writing in binary mode + if (fp == NULL) { + fprintf(stderr, "Cannot open file: %s\n", filename); + exit(1); + } + + fwrite(data, size, 1, fp); // write data to file + + fclose(fp); // close file +} + +void pack(uint16_t* d, size_t length) { + size_t dataLength = length * 2; + + int bytesPerSample = 2; + int byteRate = SAMPLE_RATE * bytesPerSample; + + size_t fileSize = 36 + dataLength; + + uint8_t* buffer = (uint8_t*)malloc(fileSize); + + int i = 0; + + // RIFF header + memcpy(buffer + i, "RIFF", 4); + i += 4; + memcpy(buffer + i, &fileSize, 4); + i += 4; + memcpy(buffer + i, "WAVE", 4); + i += 4; + + // fmt subchunk + memcpy(buffer + i, "fmt ", 4); + i += 4; + int fmtSize = 16; + memcpy(buffer + i, &fmtSize, 4); + i += 4; + uint16_t audioFormat = 1; + memcpy(buffer + i, &audioFormat, 2); + i += 2; + uint16_t numChannels = 1; + memcpy(buffer + i, &numChannels, 2); + i += 2; + int sampleRate = (int)SAMPLE_RATE; + memcpy(buffer + i, &sampleRate, 4); + i += 4; + memcpy(buffer + i, &byteRate, 4); + i += 4; + memcpy(buffer + i, &bytesPerSample, 2); + i += 2; + int bitsPerSample = bytesPerSample * 8; + memcpy(buffer + i, &bitsPerSample, 2); + i += 2; + + // data subchunk + memcpy(buffer + i, "data", 4); + i += 4; + memcpy(buffer + i, &dataLength, 4); + i += 4; + memcpy(buffer + i, d, dataLength); + + write_file("output.wav", buffer, fileSize); +} \ No newline at end of file diff --git a/export.h b/export.h new file mode 100644 index 0000000..0cb1aaa --- /dev/null +++ b/export.h @@ -0,0 +1,9 @@ +#ifndef EXPORT_H +#define EXPORT_H + +#include "stdlib.h" + +uint16_t toInt16Sample(float sample); +void pack(uint16_t* d, size_t length); + +#endif \ No newline at end of file diff --git a/main.c b/main.c index 4ee4c43..4adc5fb 100644 --- a/main.c +++ b/main.c @@ -2,350 +2,16 @@ #include "stdio.h" #include "string.h" #include "math.h" + #include "parser.h" +#include "utils.h" +#include "ring_buffer.h" +#include "settings.h" +#include "oscillator.h" +#include "export.h" #include "raylib.h" -#define SAMPLE_RATE 48000.f -#define BPM 120.f -#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 SYNTH_PI 3.1415926535f -#define SYNTH_VOLUME 0.5f - -#define WINDOW_WIDTH 640 -#define WINDOW_HEIGHT 480 - -#define write_log(format,args...) do { \ - printf(format, ## args); \ - } while(0) - -//------------------------------------------------------------------------------------ -// Ring Buffer -//------------------------------------------------------------------------------------ - -typedef struct RingBuffer { - float* items; - size_t head; - size_t tail; - int is_full; - int is_empty; - size_t size; -} RingBuffer; - -RingBuffer ring_buffer_init(size_t buffer_size) { - RingBuffer buffer = { - .items = calloc(buffer_size, sizeof(float)), - .head = 0, - .tail = 0, - .is_full = 0, - .is_empty = 1, - .size = buffer_size - }; - - return buffer; -} - -void ring_buffer_reset(RingBuffer* me) { - me->head = 0; - me->tail = 0; - me->is_full = 0; -} - -// + -static void advance_pointer(RingBuffer* me) { - if(me->is_full) { - me->tail++; - if (me->tail == me->size) { - me->tail = 0; - } - } - me->head++; - if (me->head == me->size) { - me->head = 0; - } - size_t is_full = me->head == me->tail ? 1 : 0; - me->is_full = is_full; -} - -// - -static void retreat_pointer(RingBuffer* me) { - me->is_full = 0; - me->tail++; - if (me->tail == me->size) { - me->tail = 0; - } -} - -void ring_buffer_write(RingBuffer* buffer, float* data, size_t count) { - if (buffer->is_full || buffer->head + count > buffer->size) { - write_log("[WARN] Trying to overfill the ring buffer: \n\tIsFull:%d\n\tHead:%zu\n\tCount:%zu\n\t", - buffer->is_full, - buffer->head, - count); - return; - } - buffer->is_empty = 0; - - for (size_t i = 0; i < count; i++) { - buffer->items[buffer->head] = data[i]; - advance_pointer(buffer); - } - //me->is_empty = is_full && (me->head == me->tail); -} - -int ring_buffer_read(RingBuffer* buffer, float* output, size_t count) { - if (buffer->is_empty) { - write_log("[WARN] Trying to read empty buffer"); - return 0; - } - - for (size_t i = 0; i < count; i++) { - output[i] = buffer->items[buffer->tail]; - retreat_pointer(buffer); - } - buffer->is_empty = !buffer->is_full && (buffer->head == buffer->tail); - return 1; -} - -size_t ring_buffer_size(RingBuffer* buffer) { - size_t size = buffer->size; - if(!buffer->is_full) { - if(buffer->head >= buffer->tail) { - size = (buffer->head - buffer->tail); - } - else { - size = (buffer->size + buffer->head - buffer->tail); - } - } - - return size; -} - -void ring_buffer_print(RingBuffer* me) { - write_log("[INFO] The ring buffer: \n\tIsFull:%d\n\tIsEmpty:%d\n\tHead:%zu\n\tTail:%zu\n\t", - me->is_full, - me->is_empty, - me->head, - me->tail); -} - - -//------------------------------------------------------------------------------------ -// General SynthSound -//------------------------------------------------------------------------------------ - -typedef struct SynthSound { - float* samples; - size_t sample_count; -} SynthSound; - -// frees the original sounds -SynthSound concat_sounds(SynthSound* sounds, size_t count) { - size_t total_count = 0; - for (size_t i = 0; i < count; i++) { - total_count += sounds[i].sample_count; - } - // array to hold the result - float* total = malloc(total_count * sizeof(float)); - - size_t current_count = 0; - for (size_t i = 0; i < count; i++) { - memcpy(total + current_count, - sounds[i].samples, - sounds[i].sample_count * sizeof(float)); - current_count += sounds[i].sample_count; - - free(sounds[i].samples); - } - - SynthSound result = { - .samples = total, - .sample_count = total_count - }; - - return result; -} - -//------------------------------------------------------------------------------------ -// Oscillator -//------------------------------------------------------------------------------------ - -typedef enum { - Sine, - Triangle, - Saw, - Square -} OscillatorType; - -typedef struct OscillatorParameter { - OscillatorType osc; - float freq; -} OscillatorParameter; - -typedef struct OscillatorParameterList { - OscillatorParameter* array; - size_t count; -} OscillatorParameterList; - -typedef struct OscillatorGenerationParameter { - OscillatorParameterList oscillators; - float sample; -} OscillatorGenerationParameter; - -static SynthSound get_init_samples(float duration) { - size_t sample_count = (size_t)(duration * SAMPLE_RATE); - float* samples = malloc(sizeof(float) * sample_count); - - for (double i = 0.0; i < duration * SAMPLE_RATE; i++) { - samples[(int)i] = i; - } - - SynthSound res = { - .samples = samples, - .sample_count = sample_count - }; - - return res; -} - -static float pos(float hz, float x) { - return fmodf(hz * x / SAMPLE_RATE, 1); -} - -float sineosc(float hz, float x) { - return sinf(x * (2.f * SYNTH_PI * hz / SAMPLE_RATE)); -} - -static float sign(float v) { - return (v > 0.0) ? 1.f : -1.f; -} - -float squareosc(float hz, float x) { - return sign(sineosc(hz, x)); -} - -float triangleosc(float hz, float x) { - return 1.f - fabsf(pos(hz, x) - 0.5f) * 4.f; -} - -float sawosc(float hz, float x) { - return pos(hz, x) * 2.f - 1.f; -} - -float multiosc(OscillatorGenerationParameter param) { - float osc_sample = 0.f; - for (size_t i = 0; i < param.oscillators.count; i++) { - OscillatorParameter osc = param.oscillators.array[i]; - switch (osc.osc) { - case Sine: - osc_sample += sineosc(osc.freq, param.sample); - break; - case Triangle: - osc_sample += triangleosc(osc.freq, param.sample); - break; - case Square: - osc_sample += squareosc(osc.freq, param.sample); - break; - case Saw: - osc_sample += sawosc(osc.freq, param.sample); - break; - } - } - - return osc_sample; -} - -static SynthSound freq(float duration, OscillatorParameterList osc) { - SynthSound samples = get_init_samples(duration); - // SynthSound attack = get_attack_samples(); - - float* output = malloc(sizeof(float) * samples.sample_count); - for (int i = 0; i < samples.sample_count; i++) { - float sample = samples.samples[i]; - OscillatorGenerationParameter param = { - .oscillators = osc, - .sample = sample - }; - output[i] = multiosc(param) * VOLUME; - } - - // create attack and release - /* - let adsrLength = Seq.length output - let attackArray = attack |> Seq.take adsrLength - let release = Seq.rev attackArray - */ - /* - todo: I will change the ADSR approach to an explicit ADSR module(with it's own state) - size_t adsr_length = samples.sample_count; - float *attackArray = NULL, *releaseArray = NULL; - - if (adsr_length > 0) { - //todo: calloc - attackArray = malloc(sizeof(float) * adsr_length); - size_t attack_length = attack.sample_count < adsr_length - ? attack.sample_count - : adsr_length; - - memcpy(attackArray, attack.samples, attack_length); - //todo: calloc - releaseArray = malloc(sizeof(float) * adsr_length); - memcpy(releaseArray, attackArray, attack_length); - reverse_array(releaseArray, 0, adsr_length); - } - */ - - // if (samples.sample_count > 1024) { - // samples.sample_count = 1024; - // } - // //todo: move to somewhere - // for (size_t i = 0; i < 1024; i++) { - // synth_sound.samples[i] = 0.0f; - // } - - // for (size_t i = 0; i < samples.sample_count; i++) { - // synth_sound.samples[i] = output[i]; - // } - // synth_sound.sample_count = samples.sample_count; - - - // return zipped array - SynthSound res = { - .samples = output, - .sample_count = samples.sample_count - }; - - return res; -} - -/* -static SynthSound get_attack_samples() { - float attack_time = 0.001 * ATTACK_MS; - size_t sample_count = (size_t)(attack_time * SAMPLE_RATE); - float* attack = malloc(sizeof(float) * sample_count); - float samples_to_rise = SAMPLE_RATE * attack_time; - float rising_delta = 1.0 / samples_to_rise; - float i = 0.0; - - for (int j = 0; j < sample_count; j++) { - i += rising_delta; - attack[j] = fmin(i, 1.0); - } - - SynthSound res = { - .samples = attack, - .sample_count = sample_count - }; - - return res; -} -*/ - //------------------------------------------------------------------------------------ // Synth //------------------------------------------------------------------------------------ @@ -435,80 +101,7 @@ SynthSound get_note_sound(Note input) { int semitone_shift = get_semitone_shift(input.name); return note(semitone_shift, length); } - - -//------------------------------------------------------------------------------------ -// Wav File -//------------------------------------------------------------------------------------ - -static uint16_t toInt16Sample(float sample) { - return (uint16_t)(sample * 32767.f); -} - -static void write_file(char* filename, void* data, int size) { - FILE* fp = fopen(filename, "wb"); // open file for writing in binary mode - if (fp == NULL) { - fprintf(stderr, "Cannot open file: %s\n", filename); - exit(1); - } - - fwrite(data, size, 1, fp); // write data to file - - fclose(fp); // close file -} - -void pack(uint16_t* d, size_t length) { - size_t dataLength = length * 2; - - int bytesPerSample = 2; - int byteRate = SAMPLE_RATE * bytesPerSample; - - size_t fileSize = 36 + dataLength; - - uint8_t* buffer = (uint8_t*)malloc(fileSize); - - int i = 0; - - // RIFF header - memcpy(buffer + i, "RIFF", 4); - i += 4; - memcpy(buffer + i, &fileSize, 4); - i += 4; - memcpy(buffer + i, "WAVE", 4); - i += 4; - - // fmt subchunk - memcpy(buffer + i, "fmt ", 4); - i += 4; - int fmtSize = 16; - memcpy(buffer + i, &fmtSize, 4); - i += 4; - uint16_t audioFormat = 1; - memcpy(buffer + i, &audioFormat, 2); - i += 2; - uint16_t numChannels = 1; - memcpy(buffer + i, &numChannels, 2); - i += 2; - int sampleRate = (int)SAMPLE_RATE; - memcpy(buffer + i, &sampleRate, 4); - i += 4; - memcpy(buffer + i, &byteRate, 4); - i += 4; - memcpy(buffer + i, &bytesPerSample, 2); - i += 2; - int bitsPerSample = bytesPerSample * 8; - memcpy(buffer + i, &bitsPerSample, 2); - i += 2; - - // data subchunk - memcpy(buffer + i, "data", 4); - i += 4; - memcpy(buffer + i, &dataLength, 4); - i += 4; - memcpy(buffer + i, d, dataLength); - - write_file("output.wav", buffer, fileSize); -} +//------------------------------------------------------- size_t detect_note_pressed(Note* note) { size_t is_pressed = 0; @@ -544,42 +137,6 @@ size_t detect_note_pressed(Note* note) { return is_pressed; } -//------------------------------------------------------------------------------------ -// UI -//------------------------------------------------------------------------------------ -/* -int get_zero_crossing(SynthSound* sound) { - int zero_crossing_index = 0; - for (size_t i = 1; i < sound->sample_count; i++) - { - if (sound->samples[i] >= 0.0f && sound->samples[i-1] < 0.0f) // zero-crossing - { - zero_crossing_index = i; - break; - } - } - return zero_crossing_index; -} - -Vector2* GetVisualSignal(SynthSound* sound, int zero_crossing_index) -{ - const int signal_amp = 300; - - Vector2* signal_points = malloc(sizeof(Vector2) * STREAM_BUFFER_SIZE); - - const float screen_vertical_midpoint = (WINDOW_HEIGHT/2); - for (size_t point_idx = 0; point_idx < sound->sample_count; point_idx++) - { - const int signal_idx = (point_idx + zero_crossing_index) % STREAM_BUFFER_SIZE; - signal_points[point_idx].x = (float)point_idx + WINDOW_WIDTH; - signal_points[point_idx].y = screen_vertical_midpoint + (int)(sound->samples[signal_idx] * 300); - } - - return signal_points; -} - -*/ - //------------------------------------------------------------------------------------ // Main //------------------------------------------------------------------------------------ @@ -604,7 +161,7 @@ int main(int argc, char **argv) { InitAudioDevice(); SetMasterVolume(SYNTH_VOLUME); SetAudioStreamBufferSizeDefault(STREAM_BUFFER_SIZE); - AudioStream synth_stream = LoadAudioStream(SAMPLE_RATE, sizeof(float) * 8, 1);//float*8 + AudioStream synth_stream = LoadAudioStream(SAMPLE_RATE, sizeof(float) * 8, 1); SetAudioStreamVolume(synth_stream, 0.5f); PlayAudioStream(synth_stream); @@ -670,10 +227,6 @@ int main(int argc, char **argv) { BeginDrawing(); ClearBackground(RAYWHITE); - // int zero_crossing = get_zero_crossing(&sound); - // Vector2* visual_signal = GetVisualSignal(&sound, zero_crossing); - // DrawLineStrip(visual_signal, STREAM_BUFFER_SIZE - zero_crossing, RED); - DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY); DrawFPS(0,0); diff --git a/oscillator.c b/oscillator.c new file mode 100644 index 0000000..693a867 --- /dev/null +++ b/oscillator.c @@ -0,0 +1,153 @@ +#include "oscillator.h" +#include "settings.h" +#include "math.h" +#include "stdlib.h" + +static SynthSound get_init_samples(float duration) { + size_t sample_count = (size_t)(duration * SAMPLE_RATE); + float* samples = malloc(sizeof(float) * sample_count); + + for (double i = 0.0; i < duration * SAMPLE_RATE; i++) { + samples[(int)i] = i; + } + + SynthSound res = { + .samples = samples, + .sample_count = sample_count + }; + + return res; +} + +static float pos(float hz, float x) { + return fmodf(hz * x / SAMPLE_RATE, 1); +} + +static float sineosc(float hz, float x) { + return sinf(x * (2.f * SYNTH_PI * hz / SAMPLE_RATE)); +} + +static float sign(float v) { + return (v > 0.0) ? 1.f : -1.f; +} + +static float squareosc(float hz, float x) { + return sign(sineosc(hz, x)); +} + +static float triangleosc(float hz, float x) { + return 1.f - fabsf(pos(hz, x) - 0.5f) * 4.f; +} + +static float sawosc(float hz, float x) { + return pos(hz, x) * 2.f - 1.f; +} + +float multiosc(OscillatorGenerationParameter param) { + float osc_sample = 0.f; + for (size_t i = 0; i < param.oscillators.count; i++) { + OscillatorParameter osc = param.oscillators.array[i]; + switch (osc.osc) { + case Sine: + osc_sample += sineosc(osc.freq, param.sample); + break; + case Triangle: + osc_sample += triangleosc(osc.freq, param.sample); + break; + case Square: + osc_sample += squareosc(osc.freq, param.sample); + break; + case Saw: + osc_sample += sawosc(osc.freq, param.sample); + break; + } + } + + return osc_sample; +} + +SynthSound freq(float duration, OscillatorParameterList osc) { + SynthSound samples = get_init_samples(duration); + // SynthSound attack = get_attack_samples(); + + float* output = malloc(sizeof(float) * samples.sample_count); + for (int i = 0; i < samples.sample_count; i++) { + float sample = samples.samples[i]; + OscillatorGenerationParameter param = { + .oscillators = osc, + .sample = sample + }; + output[i] = multiosc(param) * VOLUME; + } + + // create attack and release + /* + let adsrLength = Seq.length output + let attackArray = attack |> Seq.take adsrLength + let release = Seq.rev attackArray + */ + /* + todo: I will change the ADSR approach to an explicit ADSR module(with it's own state) + size_t adsr_length = samples.sample_count; + float *attackArray = NULL, *releaseArray = NULL; + + if (adsr_length > 0) { + //todo: calloc + attackArray = malloc(sizeof(float) * adsr_length); + size_t attack_length = attack.sample_count < adsr_length + ? attack.sample_count + : adsr_length; + + memcpy(attackArray, attack.samples, attack_length); + //todo: calloc + releaseArray = malloc(sizeof(float) * adsr_length); + memcpy(releaseArray, attackArray, attack_length); + reverse_array(releaseArray, 0, adsr_length); + } + */ + + // if (samples.sample_count > 1024) { + // samples.sample_count = 1024; + // } + // //todo: move to somewhere + // for (size_t i = 0; i < 1024; i++) { + // synth_sound.samples[i] = 0.0f; + // } + + // for (size_t i = 0; i < samples.sample_count; i++) { + // synth_sound.samples[i] = output[i]; + // } + // synth_sound.sample_count = samples.sample_count; + + + // return zipped array + SynthSound res = { + .samples = output, + .sample_count = samples.sample_count + }; + + return res; +} + +/* +static SynthSound get_attack_samples() { + float attack_time = 0.001 * ATTACK_MS; + size_t sample_count = (size_t)(attack_time * SAMPLE_RATE); + float* attack = malloc(sizeof(float) * sample_count); + float samples_to_rise = SAMPLE_RATE * attack_time; + float rising_delta = 1.0 / samples_to_rise; + float i = 0.0; + + for (int j = 0; j < sample_count; j++) { + i += rising_delta; + attack[j] = fmin(i, 1.0); + } + + SynthSound res = { + .samples = attack, + .sample_count = sample_count + }; + + return res; +} +*/ \ No newline at end of file diff --git a/oscillator.h b/oscillator.h new file mode 100644 index 0000000..536cc0d --- /dev/null +++ b/oscillator.h @@ -0,0 +1,33 @@ +#ifndef OSCILLATOR_H +#define OSCILLATOR_H + +#include "utils.h" + +typedef enum { + Sine, + Triangle, + Saw, + Square +} OscillatorType; + +typedef struct OscillatorParameter { + OscillatorType osc; + float freq; +} OscillatorParameter; + +typedef struct OscillatorParameterList { + OscillatorParameter* array; + size_t count; +} OscillatorParameterList; + +typedef struct OscillatorGenerationParameter { + OscillatorParameterList oscillators; + float sample; +} OscillatorGenerationParameter; + +float multiosc(OscillatorGenerationParameter param); +SynthSound freq(float duration, OscillatorParameterList osc); + + + +#endif \ No newline at end of file diff --git a/ring_buffer.c b/ring_buffer.c new file mode 100644 index 0000000..3d46364 --- /dev/null +++ b/ring_buffer.c @@ -0,0 +1,99 @@ +#include "ring_buffer.h" +#include "utils.h" + +RingBuffer ring_buffer_init(size_t buffer_size) { + RingBuffer buffer = { + .items = calloc(buffer_size, sizeof(float)), + .head = 0, + .tail = 0, + .is_full = 0, + .is_empty = 1, + .size = buffer_size + }; + + return buffer; +} + +void ring_buffer_reset(RingBuffer* me) { + me->head = 0; + me->tail = 0; + me->is_full = 0; +} + +// + +static void advance_pointer(RingBuffer* me) { + if(me->is_full) { + me->tail++; + if (me->tail == me->size) { + me->tail = 0; + } + } + me->head++; + if (me->head == me->size) { + me->head = 0; + } + size_t is_full = me->head == me->tail ? 1 : 0; + me->is_full = is_full; +} + +// - +static void retreat_pointer(RingBuffer* me) { + me->is_full = 0; + me->tail++; + if (me->tail == me->size) { + me->tail = 0; + } +} + +void ring_buffer_write(RingBuffer* buffer, float* data, size_t count) { + if (buffer->is_full || buffer->head + count > buffer->size) { + write_log("[WARN] Trying to overfill the ring buffer: \n\tIsFull:%d\n\tHead:%zu\n\tCount:%zu\n\t", + buffer->is_full, + buffer->head, + count); + return; + } + buffer->is_empty = 0; + + for (size_t i = 0; i < count; i++) { + buffer->items[buffer->head] = data[i]; + advance_pointer(buffer); + } + //me->is_empty = is_full && (me->head == me->tail); +} + +int ring_buffer_read(RingBuffer* buffer, float* output, size_t count) { + if (buffer->is_empty) { + write_log("[WARN] Trying to read empty buffer"); + return 0; + } + + for (size_t i = 0; i < count; i++) { + output[i] = buffer->items[buffer->tail]; + retreat_pointer(buffer); + } + buffer->is_empty = !buffer->is_full && (buffer->head == buffer->tail); + return 1; +} + +size_t ring_buffer_size(RingBuffer* buffer) { + size_t size = buffer->size; + if(!buffer->is_full) { + if(buffer->head >= buffer->tail) { + size = (buffer->head - buffer->tail); + } + else { + size = (buffer->size + buffer->head - buffer->tail); + } + } + + return size; +} + +void ring_buffer_print(RingBuffer* me) { + write_log("[INFO] The ring buffer: \n\tIsFull:%d\n\tIsEmpty:%d\n\tHead:%zu\n\tTail:%zu\n\t", + me->is_full, + me->is_empty, + me->head, + me->tail); +} diff --git a/ring_buffer.h b/ring_buffer.h new file mode 100644 index 0000000..b840759 --- /dev/null +++ b/ring_buffer.h @@ -0,0 +1,22 @@ +#ifndef RING_BUFFER_H +#define RING_BUFFER_H + +#include "stdlib.h" + +typedef struct RingBuffer { + float* items; + size_t head; + size_t tail; + int is_full; + int is_empty; + size_t size; +} RingBuffer; + +RingBuffer ring_buffer_init(size_t buffer_size); +void ring_buffer_reset(RingBuffer* me); +void ring_buffer_write(RingBuffer* buffer, float* data, size_t count); +int ring_buffer_read(RingBuffer* buffer, float* output, size_t count); +size_t ring_buffer_size(RingBuffer* buffer); +void ring_buffer_print(RingBuffer* me); + +#endif diff --git a/settings.h b/settings.h new file mode 100644 index 0000000..e4f600a --- /dev/null +++ b/settings.h @@ -0,0 +1,18 @@ +#ifndef SETTINGS_H +#define SETTINGS_H + +#define SAMPLE_RATE 48000.f +#define BPM 120.f +#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 SYNTH_PI 3.1415926535f +#define SYNTH_VOLUME 0.5f + +#define WINDOW_WIDTH 640 +#define WINDOW_HEIGHT 480 + +#endif \ No newline at end of file diff --git a/utils.c b/utils.c new file mode 100644 index 0000000..694def5 --- /dev/null +++ b/utils.c @@ -0,0 +1,30 @@ +#include "utils.h" +#include "stdlib.h" +#include "string.h" + +// frees the original sounds +SynthSound concat_sounds(SynthSound* sounds, size_t count) { + size_t total_count = 0; + for (size_t i = 0; i < count; i++) { + total_count += sounds[i].sample_count; + } + // array to hold the result + float* total = malloc(total_count * sizeof(float)); + + size_t current_count = 0; + for (size_t i = 0; i < count; i++) { + memcpy(total + current_count, + sounds[i].samples, + sounds[i].sample_count * sizeof(float)); + current_count += sounds[i].sample_count; + + free(sounds[i].samples); + } + + SynthSound result = { + .samples = total, + .sample_count = total_count + }; + + return result; +} \ No newline at end of file diff --git a/utils.h b/utils.h new file mode 100644 index 0000000..287b8bc --- /dev/null +++ b/utils.h @@ -0,0 +1,22 @@ +#ifndef UTILS_H +#define UTILS_H + +#include "stdio.h" + +#define write_log(format,args...) do { \ + printf(format, ## args); \ + } while(0) + +//------------------------------------------------------------------------------------ +// General SynthSound +//------------------------------------------------------------------------------------ + +typedef struct SynthSound { + float* samples; + size_t sample_count; +} SynthSound; + +// frees the original sounds +SynthSound concat_sounds(SynthSound* sounds, size_t count); + +#endif \ No newline at end of file