From cf2cfcd8a96921dbe812647045dff71ab63989cd Mon Sep 17 00:00:00 2001 From: Mitja Felicijan Date: Wed, 9 Oct 2024 03:12:15 +0200 Subject: Added synth thread that plays a simple note --- Makefile | 4 ++-- main.c | 13 ++++++++++++- synth.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ synth.h | 11 +++++++++++ 4 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 synth.c create mode 100644 synth.h diff --git a/Makefile b/Makefile index 98a41d3..8681948 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CC := cc -CFLAGS := -Wall -Wextra -Wshadow -Wunused -Wswitch-enum -Wpedantic -Wundef +CFLAGS := -Wall -Wextra -Wshadow -Wunused -Wswitch-enum -Wpedantic -ggdb LDFLAGS := -lm -ldl -lpthread -lasound -FILES := main.c midi.c minisdl_audio.c +FILES := main.c midi.c synth.c minisdl_audio.c PROG := ttdaw $(PROG): main.c diff --git a/main.c b/main.c index 3a45592..5a1916e 100644 --- a/main.c +++ b/main.c @@ -6,6 +6,7 @@ #include "version.h" #include "midi.h" +#include "synth.h" void help(const char *argv0) { printf("Usage: %s [options]\n" @@ -69,7 +70,16 @@ int main(int argc, char *argv[]) { fprintf(stdout, "> Device port: %s\n", port_name); fprintf(stdout, "> Soundfont: %s\n", soundfont_file); - // Create and start MIDI thread. + // Create synth thread. + pthread_t synth_thread; + SynthArgs synth_args = { soundfont_file }; + + if (pthread_create(&synth_thread, NULL, synth, (void*)&synth_args) != 0) { + fprintf(stderr, "Error creating synth thread\n"); + return 1; + } + + // Create MIDI thread. pthread_t midi_thread; MidiArgs midi_args = { port_name }; @@ -79,6 +89,7 @@ int main(int argc, char *argv[]) { } pthread_join(midi_thread, NULL); + pthread_join(synth_thread, NULL); fprintf(stdout, "Exiting...\n"); return 0; diff --git a/synth.c b/synth.c new file mode 100644 index 0000000..d391056 --- /dev/null +++ b/synth.c @@ -0,0 +1,67 @@ +#include +#include + +#include "synth.h" +#include "minisdl_audio.h" + +#define TSF_IMPLEMENTATION +#include "tsf.h" + +static tsf* g_TinySoundFont; +static SDL_mutex* g_Mutex; + +// Render the audio samples in float format. +static void AudioCallback(void* data, Uint8 *stream, int len) { + int SampleCount = (len / (2 * sizeof(float))); // 2 output channels. + SDL_LockMutex(g_Mutex); // Get exclusive lock. + tsf_render_float(g_TinySoundFont, (float*)stream, SampleCount, 0); + SDL_UnlockMutex(g_Mutex); +} + +void *synth(void *arg) { + SynthArgs* args = (SynthArgs*)arg; + + SDL_AudioSpec OutputAudioSpec; + OutputAudioSpec.freq = 44100; + OutputAudioSpec.format = AUDIO_F32; + OutputAudioSpec.channels = 2; + OutputAudioSpec.samples = 4096; + OutputAudioSpec.callback = AudioCallback; + + // Initialize the audio system. + if (SDL_AudioInit(TSF_NULL) < 0) { + fprintf(stderr, "Could not initialize audio hardware or driver\n"); + exit(1); + } + + // Load the SoundFont from a file. + g_TinySoundFont = tsf_load_filename(args->soundfont_file); + if (!g_TinySoundFont) { + fprintf(stderr, "Could not load SoundFont\n"); + exit(1); + } + + // Set the SoundFont rendering output mode. + tsf_set_output(g_TinySoundFont, TSF_STEREO_INTERLEAVED, OutputAudioSpec.freq, 0); + + // Create the mutex. + g_Mutex = SDL_CreateMutex(); + + // Request the desired audio output format. + if (SDL_OpenAudio(&OutputAudioSpec, TSF_NULL) < 0) { + fprintf(stderr, "Could not open the audio hardware or the desired audio output format\n"); + exit(1); + } + + SDL_PauseAudio(0); + + while (1) { + sleep(1); + + SDL_LockMutex(g_Mutex); + tsf_note_off(g_TinySoundFont, 1, 50); + tsf_note_on(g_TinySoundFont, 1, 50, 1.0f); + SDL_UnlockMutex(g_Mutex); + } +} + diff --git a/synth.h b/synth.h new file mode 100644 index 0000000..1976745 --- /dev/null +++ b/synth.h @@ -0,0 +1,11 @@ +#ifndef SYNTH_H_ +#define SYNTH_H_ + +typedef struct { + char *soundfont_file; +} SynthArgs; + +void *synth(void *arg); + +#endif // SYNTH_H_ + -- cgit v1.2.3