Added mutex and proper audio playback

Author Mitja Felicijan <mitja.felicijan@gmail.com> 2024-10-09 17:59:41 +0200
Committer Mitja Felicijan <mitja.felicijan@gmail.com> 2024-10-09 17:59:41 +0200
Commit bfc79cef2cb743fedba3e93fd005d25b0a4923dc (patch)
-rw-r--r-- Makefile 2
-rw-r--r-- main.c 7
-rw-r--r-- midi.c 16
-rw-r--r-- midi.h 4
-rw-r--r-- mutex.c 19
-rw-r--r-- mutex.h 24
-rw-r--r-- soundfonts/general-808.sf2 bin 0 B -> 70.0 KB
-rw-r--r-- synth.c 31
-rw-r--r-- synth.h 4
9 files changed, 96 insertions, 11 deletions
diff --git a/Makefile b/Makefile
1
CC      := cc
1
CC      := cc
2
CFLAGS  := -Wall -Wextra -Wshadow -Wunused -Wswitch-enum -Wpedantic -ggdb
2
CFLAGS  := -Wall -Wextra -Wshadow -Wunused -Wswitch-enum -Wpedantic -ggdb
3
LDFLAGS := -lm -ldl -lpthread -lasound
3
LDFLAGS := -lm -ldl -lpthread -lasound
4
FILES   := main.c midi.c synth.c minisdl_audio.c
4
FILES   := main.c midi.c synth.c mutex.c minisdl_audio.c
5
PROG    := ttdaw
5
PROG    := ttdaw
6
  
6
  
7
$(PROG): main.c
7
$(PROG): main.c
...
diff --git a/main.c b/main.c
...
7
#include "version.h"
7
#include "version.h"
8
#include "midi.h"
8
#include "midi.h"
9
#include "synth.h"
9
#include "synth.h"
  
10
#include "mutex.h"
10
  
11
  
11
void help(const char *argv0) {
12
void help(const char *argv0) {
12
	printf("Usage: %s [options]\n"
13
	printf("Usage: %s [options]\n"
...
70
	fprintf(stdout, "> Device port:   %s\n", port_name);
71
	fprintf(stdout, "> Device port:   %s\n", port_name);
71
	fprintf(stdout, "> Soundfont:     %s\n", soundfont_file);
72
	fprintf(stdout, "> Soundfont:     %s\n", soundfont_file);
72
  
73
  
  
74
	// Create mutex.
  
75
	initialize_mutex();	
  
76
  
73
	// Create synth thread.
77
	// Create synth thread.
74
	pthread_t synth_thread;
78
	pthread_t synth_thread;
75
	SynthArgs synth_args = { soundfont_file };
79
	SynthArgs synth_args = { soundfont_file };
...
90
  
94
  
91
	pthread_join(midi_thread, NULL);
95
	pthread_join(midi_thread, NULL);
92
	pthread_join(synth_thread, NULL);
96
	pthread_join(synth_thread, NULL);
  
97
  
  
98
	// Destroy mutex.
  
99
	destroy_mutex();
93
  
100
  
94
	fprintf(stdout, "Exiting...\n");
101
	fprintf(stdout, "Exiting...\n");
95
	return 0;
102
	return 0;
...
diff --git a/midi.c b/midi.c
...
5
#include <alsa/asoundlib.h>
5
#include <alsa/asoundlib.h>
6
  
6
  
7
#include "midi.h"
7
#include "midi.h"
  
8
#include "mutex.h"
8
  
9
  
9
static snd_seq_t *seq_handle;
10
static snd_seq_t *seq_handle;
10
static snd_seq_addr_t *ports;
11
static snd_seq_addr_t *ports;
...
81
				}
82
				}
82
  
83
  
83
				if (ev) {
84
				if (ev) {
  
85
					pthread_mutex_lock(&mutex);
84
					switch (ev->type) {
86
					switch (ev->type) {
85
						case SND_SEQ_EVENT_NOTEON:
87
						case SND_SEQ_EVENT_NOTEON:
  
88
							shared_data.note = ev->data.note.note;
  
89
							shared_data.state = 1;
  
90
							shared_data.velocity = ev->data.note.velocity;
86
							printf("%3d:%-3dNote on  %2d, note %d, velocity: %3d\n",
91
							printf("%3d:%-3dNote on  %2d, note %d, velocity: %3d\n",
87
									ev->source.client, ev->source.port,
92
									ev->source.client, ev->source.port,
88
									ev->data.note.channel,
93
									ev->data.note.channel,
...
91
							break;
96
							break;
92
  
97
  
93
						case SND_SEQ_EVENT_NOTEOFF:
98
						case SND_SEQ_EVENT_NOTEOFF:
  
99
							shared_data.note = ev->data.note.note;
  
100
							shared_data.state = 0;
  
101
							shared_data.velocity = 0;
94
							printf("%3d:%-3dNote off\t%2d, note %d\n",
102
							printf("%3d:%-3dNote off\t%2d, note %d\n",
95
									ev->source.client, ev->source.port,
103
									ev->source.client, ev->source.port,
96
									ev->data.note.channel,
104
									ev->data.note.channel,
97
									ev->data.note.note);
105
									ev->data.note.note);
98
							break;
106
							break;
  
107
						default:
  
108
							break;
  
109
					}
99
  
110
  
  
111
					shared_data.action = 1;
  
112
					shared_data.preset = 3;
100
  
113
  
101
					}
114
					pthread_cond_signal(&cond_synth);
  
115
					pthread_mutex_unlock(&mutex);
102
				}
116
				}
103
			}
117
			}
104
  
118
  
...
diff --git a/midi.h b/midi.h
1
#include <alsa/asoundlib.h>
  
2
  
  
3
#ifndef MIDI_H_
1
#ifndef MIDI_H_
4
#define MIDI_H_
2
#define MIDI_H_
  
3
  
  
4
#include <alsa/asoundlib.h>
5
  
5
  
6
#define CLIENT_NAME "ttdaw"
6
#define CLIENT_NAME "ttdaw"
7
#define MAX_MIDI_PORTS 1
7
#define MAX_MIDI_PORTS 1
...
diff --git a/mutex.c b/mutex.c
  
1
#include <pthread.h>
  
2
#include "mutex.h"
  
3
  
  
4
SharedData shared_data;
  
5
  
  
6
pthread_mutex_t mutex;
  
7
pthread_cond_t cond_midi;
  
8
pthread_cond_t cond_synth;
  
9
  
  
10
void initialize_mutex() {
  
11
	pthread_mutex_init(&mutex, NULL);
  
12
	pthread_cond_init(&cond_synth, NULL);
  
13
}
  
14
  
  
15
void destroy_mutex() {
  
16
	pthread_mutex_destroy(&mutex);
  
17
	pthread_cond_destroy(&cond_synth);
  
18
}
  
19
  
diff --git a/mutex.h b/mutex.h
  
1
#ifndef MUTEX_H
  
2
#define MUTEX_H
  
3
  
  
4
#include <pthread.h>
  
5
  
  
6
typedef struct {
  
7
	int note;
  
8
	int state;
  
9
	int velocity;
  
10
	int preset;
  
11
	int action;
  
12
} SharedData;
  
13
  
  
14
extern SharedData shared_data;
  
15
  
  
16
extern pthread_mutex_t mutex;
  
17
extern pthread_cond_t cond_midi;
  
18
extern pthread_cond_t cond_synth;
  
19
  
  
20
void initialize_mutex();
  
21
void destroy_mutex();
  
22
  
  
23
#endif // MUTEX_H
  
24
  
diff --git a/soundfonts/general-808.sf2 b/soundfonts/general-808.sf2
diff --git a/synth.c b/synth.c
...
2
#include <unistd.h>
2
#include <unistd.h>
3
  
3
  
4
#include "synth.h"
4
#include "synth.h"
  
5
#include "mutex.h"
5
#include "minisdl_audio.h"
6
#include "minisdl_audio.h"
6
  
7
  
7
#define TSF_IMPLEMENTATION
8
#define TSF_IMPLEMENTATION
...
12
  
13
  
13
// Render the audio samples in float format.
14
// Render the audio samples in float format.
14
static void AudioCallback(void* data, Uint8 *stream, int len) {
15
static void AudioCallback(void* data, Uint8 *stream, int len) {
15
	int SampleCount = (len / (2 * sizeof(float))); // 2 output channels.
16
	int SampleCount = (len / (AUDIO_CHANNELS * sizeof(float))); // 2 output channels.
16
	SDL_LockMutex(g_Mutex); // Get exclusive lock.
17
	SDL_LockMutex(g_Mutex); // Get exclusive lock.
17
	tsf_render_float(g_TinySoundFont, (float*)stream, SampleCount, 0);
18
	tsf_render_float(g_TinySoundFont, (float*)stream, SampleCount, 0);
18
	SDL_UnlockMutex(g_Mutex);
19
	SDL_UnlockMutex(g_Mutex);
...
22
	SynthArgs* args = (SynthArgs*)arg;
23
	SynthArgs* args = (SynthArgs*)arg;
23
  
24
  
24
	SDL_AudioSpec OutputAudioSpec;
25
	SDL_AudioSpec OutputAudioSpec;
25
	OutputAudioSpec.freq = 44100;
26
	OutputAudioSpec.freq = AUDIO_FREQ;
26
	OutputAudioSpec.format = AUDIO_F32;
27
	OutputAudioSpec.format = AUDIO_F32;
27
	OutputAudioSpec.channels = 2;
28
	OutputAudioSpec.channels = AUDIO_CHANNELS;
28
	OutputAudioSpec.samples = 4096;
29
	OutputAudioSpec.samples = AUDIO_SAMPLES;
29
	OutputAudioSpec.callback = AudioCallback;
30
	OutputAudioSpec.callback = AudioCallback;
30
  
31
  
31
	// Initialize the audio system.
32
	// Initialize the audio system.
...
56
	SDL_PauseAudio(0);
57
	SDL_PauseAudio(0);
57
  
58
  
58
	while (1) {
59
	while (1) {
59
		sleep(1);
60
		pthread_mutex_lock(&mutex);
  
61
		while (shared_data.action == 0) {
  
62
			pthread_cond_wait(&cond_synth, &mutex);
  
63
		}
60
  
64
  
61
		SDL_LockMutex(g_Mutex);
65
		SDL_LockMutex(g_Mutex);
62
		tsf_note_off(g_TinySoundFont, 1, 50);
66
  
63
		tsf_note_on(g_TinySoundFont, 1, 50, 1.0f);
67
		if (shared_data.state == 0) {
  
68
			tsf_note_off(g_TinySoundFont, shared_data.preset, shared_data.note);
  
69
		} else {
  
70
			float normalized_velocity = (float)shared_data.velocity / 127.0f;
  
71
			tsf_note_on(g_TinySoundFont, shared_data.preset, shared_data.note, normalized_velocity);
  
72
		}
  
73
  
64
		SDL_UnlockMutex(g_Mutex);
74
		SDL_UnlockMutex(g_Mutex);
  
75
  
  
76
		printf("Consumed: note=%d, state=%d velocity:%d\n", shared_data.note, shared_data.state, shared_data.velocity);
  
77
  
  
78
		// Reset state to indicate data has been consumed.
  
79
		shared_data.action = 0; 
  
80
  
  
81
		pthread_mutex_unlock(&mutex);
65
	}
82
	}
66
}
83
}
67
  
84
  
diff --git a/synth.h b/synth.h
1
#ifndef SYNTH_H_
1
#ifndef SYNTH_H_
2
#define SYNTH_H_
2
#define SYNTH_H_
3
  
3
  
  
4
#define AUDIO_FREQ 44100
  
5
#define AUDIO_SAMPLES 64
  
6
#define AUDIO_CHANNELS 2
  
7
  
4
typedef struct {
8
typedef struct {
5
	char *soundfont_file;
9
	char *soundfont_file;
6
} SynthArgs;
10
} SynthArgs;
...