1#include <stdio.h>
2#include <unistd.h>
3
4#include "synth.h"
5#include "mutex.h"
6#include "minisdl_audio.h"
7#include "termbox2.h"
8
9#define TSF_IMPLEMENTATION
10#include "tsf.h"
11
12static tsf* g_TinySoundFont;
13static SDL_mutex* g_Mutex;
14
15// Render the audio samples in float format.
16static void AudioCallback(void* data, Uint8 *stream, int len) {
17 int SampleCount = (len / (AUDIO_CHANNELS * sizeof(float))); // 2 output channels.
18 SDL_LockMutex(g_Mutex); // Get exclusive lock.
19 tsf_render_float(g_TinySoundFont, (float*)stream, SampleCount, 0);
20 SDL_UnlockMutex(g_Mutex);
21}
22
23void *synth(void *arg) {
24 SynthArgs* args = (SynthArgs*)arg;
25
26 SDL_AudioSpec OutputAudioSpec;
27 OutputAudioSpec.freq = AUDIO_FREQ;
28 OutputAudioSpec.format = AUDIO_F32;
29 OutputAudioSpec.channels = AUDIO_CHANNELS;
30 OutputAudioSpec.samples = AUDIO_SAMPLES;
31 OutputAudioSpec.callback = AudioCallback;
32
33 // Initialize the audio system.
34 if (SDL_AudioInit(TSF_NULL) < 0) {
35 fprintf(stderr, "Could not initialize audio hardware or driver\n");
36 exit(1);
37 }
38
39 // Load the SoundFont from a file.
40 g_TinySoundFont = tsf_load_filename(args->soundfont_file);
41 if (!g_TinySoundFont) {
42 fprintf(stderr, "Could not load SoundFont\n");
43 exit(1);
44 }
45
46 // Set the SoundFont rendering output mode.
47 tsf_set_output(g_TinySoundFont, TSF_STEREO_INTERLEAVED, OutputAudioSpec.freq, 0);
48
49 // Create the mutex.
50 g_Mutex = SDL_CreateMutex();
51
52 // Request the desired audio output format.
53 if (SDL_OpenAudio(&OutputAudioSpec, TSF_NULL) < 0) {
54 fprintf(stderr, "Could not open the audio hardware or the desired audio output format\n");
55 exit(1);
56 }
57
58 SDL_PauseAudio(0);
59
60 while (1) {
61 pthread_mutex_lock(&mutex);
62 while (shared_data.action == 0) {
63 pthread_cond_wait(&cond_synth, &mutex);
64 }
65
66 SDL_LockMutex(g_Mutex);
67
68 if (shared_data.state == 0) {
69 tsf_note_off(g_TinySoundFont, args->soundfont_preset, shared_data.note);
70 } else {
71 float normalized_velocity = (float)shared_data.velocity / 127.0f;
72 tsf_note_on(g_TinySoundFont, args->soundfont_preset, shared_data.note, normalized_velocity);
73 }
74
75 SDL_UnlockMutex(g_Mutex);
76
77 /* printf("Consumed: note=%d, state=%d velocity:%d\n", shared_data.note, shared_data.state, shared_data.velocity); */
78
79 // Reset state to indicate data has been consumed.
80 shared_data.action = 0;
81
82 pthread_mutex_unlock(&mutex);
83 }
84}
85