|
diff --git a/main.c b/main.c
|
| ... |
| 6 |
|
6 |
|
| 7 |
#include "version.h" |
7 |
#include "version.h" |
| 8 |
#include "midi.h" |
8 |
#include "midi.h" |
|
|
9 |
#include "synth.h" |
| 9 |
|
10 |
|
| 10 |
void help(const char *argv0) { |
11 |
void help(const char *argv0) { |
| 11 |
printf("Usage: %s [options]\n" |
12 |
printf("Usage: %s [options]\n" |
| ... |
| 69 |
fprintf(stdout, "> Device port: %s\n", port_name); |
70 |
fprintf(stdout, "> Device port: %s\n", port_name); |
| 70 |
fprintf(stdout, "> Soundfont: %s\n", soundfont_file); |
71 |
fprintf(stdout, "> Soundfont: %s\n", soundfont_file); |
| 71 |
|
72 |
|
| 72 |
// Create and start MIDI thread. |
73 |
// Create synth thread. |
|
|
74 |
pthread_t synth_thread; |
|
|
75 |
SynthArgs synth_args = { soundfont_file }; |
|
|
76 |
|
|
|
77 |
if (pthread_create(&synth_thread, NULL, synth, (void*)&synth_args) != 0) { |
|
|
78 |
fprintf(stderr, "Error creating synth thread\n"); |
|
|
79 |
return 1; |
|
|
80 |
} |
|
|
81 |
|
|
|
82 |
// Create MIDI thread. |
| 73 |
pthread_t midi_thread; |
83 |
pthread_t midi_thread; |
| 74 |
MidiArgs midi_args = { port_name }; |
84 |
MidiArgs midi_args = { port_name }; |
| 75 |
|
85 |
|
| ... |
| 79 |
} |
89 |
} |
| 80 |
|
90 |
|
| 81 |
pthread_join(midi_thread, NULL); |
91 |
pthread_join(midi_thread, NULL); |
|
|
92 |
pthread_join(synth_thread, NULL); |
| 82 |
|
93 |
|
| 83 |
fprintf(stdout, "Exiting...\n"); |
94 |
fprintf(stdout, "Exiting...\n"); |
| 84 |
return 0; |
95 |
return 0; |
| ... |
|
diff --git a/synth.c b/synth.c
|
|
|
1 |
#include <stdio.h> |
|
|
2 |
#include <unistd.h> |
|
|
3 |
|
|
|
4 |
#include "synth.h" |
|
|
5 |
#include "minisdl_audio.h" |
|
|
6 |
|
|
|
7 |
#define TSF_IMPLEMENTATION |
|
|
8 |
#include "tsf.h" |
|
|
9 |
|
|
|
10 |
static tsf* g_TinySoundFont; |
|
|
11 |
static SDL_mutex* g_Mutex; |
|
|
12 |
|
|
|
13 |
// Render the audio samples in float format. |
|
|
14 |
static void AudioCallback(void* data, Uint8 *stream, int len) { |
|
|
15 |
int SampleCount = (len / (2 * sizeof(float))); // 2 output channels. |
|
|
16 |
SDL_LockMutex(g_Mutex); // Get exclusive lock. |
|
|
17 |
tsf_render_float(g_TinySoundFont, (float*)stream, SampleCount, 0); |
|
|
18 |
SDL_UnlockMutex(g_Mutex); |
|
|
19 |
} |
|
|
20 |
|
|
|
21 |
void *synth(void *arg) { |
|
|
22 |
SynthArgs* args = (SynthArgs*)arg; |
|
|
23 |
|
|
|
24 |
SDL_AudioSpec OutputAudioSpec; |
|
|
25 |
OutputAudioSpec.freq = 44100; |
|
|
26 |
OutputAudioSpec.format = AUDIO_F32; |
|
|
27 |
OutputAudioSpec.channels = 2; |
|
|
28 |
OutputAudioSpec.samples = 4096; |
|
|
29 |
OutputAudioSpec.callback = AudioCallback; |
|
|
30 |
|
|
|
31 |
// Initialize the audio system. |
|
|
32 |
if (SDL_AudioInit(TSF_NULL) < 0) { |
|
|
33 |
fprintf(stderr, "Could not initialize audio hardware or driver\n"); |
|
|
34 |
exit(1); |
|
|
35 |
} |
|
|
36 |
|
|
|
37 |
// Load the SoundFont from a file. |
|
|
38 |
g_TinySoundFont = tsf_load_filename(args->soundfont_file); |
|
|
39 |
if (!g_TinySoundFont) { |
|
|
40 |
fprintf(stderr, "Could not load SoundFont\n"); |
|
|
41 |
exit(1); |
|
|
42 |
} |
|
|
43 |
|
|
|
44 |
// Set the SoundFont rendering output mode. |
|
|
45 |
tsf_set_output(g_TinySoundFont, TSF_STEREO_INTERLEAVED, OutputAudioSpec.freq, 0); |
|
|
46 |
|
|
|
47 |
// Create the mutex. |
|
|
48 |
g_Mutex = SDL_CreateMutex(); |
|
|
49 |
|
|
|
50 |
// Request the desired audio output format. |
|
|
51 |
if (SDL_OpenAudio(&OutputAudioSpec, TSF_NULL) < 0) { |
|
|
52 |
fprintf(stderr, "Could not open the audio hardware or the desired audio output format\n"); |
|
|
53 |
exit(1); |
|
|
54 |
} |
|
|
55 |
|
|
|
56 |
SDL_PauseAudio(0); |
|
|
57 |
|
|
|
58 |
while (1) { |
|
|
59 |
sleep(1); |
|
|
60 |
|
|
|
61 |
SDL_LockMutex(g_Mutex); |
|
|
62 |
tsf_note_off(g_TinySoundFont, 1, 50); |
|
|
63 |
tsf_note_on(g_TinySoundFont, 1, 50, 1.0f); |
|
|
64 |
SDL_UnlockMutex(g_Mutex); |
|
|
65 |
} |
|
|
66 |
} |
|
|
67 |
|