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