1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
#ifndef SOUNDS_H_
#define SOUNDS_H_
#include <alsa/asoundlib.h>
#include <limits.h>
#include <math.h>
#include <pthread.h>
#include <stdbool.h>
#define check(ret) \
do { \
int res = (ret); \
if (res < 0) { \
fprintf(stderr, "%s:%d ERROR: %s (%d)\n", __FILE__, __LINE__, \
snd_strerror(res), res); \
exit(1); \
} \
} while (0)
#define MESSAGE_QUEUE_SIZE 128
#define SAMPLE_RATE 48000
#define PERIOD_SIZE 480
typedef enum {
PARAM_OSC,
PARAM_VOLUME,
} param_type;
typedef enum {
OSC_SINE,
OSC_SAW,
OSC_SQUARE,
OSC_TRIANGLE,
} oscilator_type;
typedef enum {
MSG_NOTE_ON,
MSG_NOTE_OFF,
MSG_ALL_NOTES_OFF,
MSG_PARAM_CHANGE,
MSG_STOP,
} synth_message_type;
typedef struct {
synth_message_type type;
union {
// NOTE_ON / NOTE_OFF
struct {
size_t note_id;
} note;
// SET_PARAM;
struct {
param_type param_type;
float value;
} param_change;
};
} synth_message;
typedef struct {
synth_message buffer[MESSAGE_QUEUE_SIZE];
size_t head;
size_t tail;
pthread_mutex_t lock;
} message_queue;
typedef struct {
snd_pcm_t *pcm;
message_queue *queue;
} sound_thread_meta;
typedef enum {
ENV_OFF,
ENV_ATTACK,
ENV_DECAY,
ENV_SUSTAIN,
ENV_RELEASE,
} envelope_state;
typedef struct {
envelope_state state;
int counter;
int attack_time;
int decay_time;
float sustain_level;
int release_time;
float increases[3];
} envelope;
typedef struct {
bool active;
float freq;
float phase;
float phase_inc;
envelope envelope;
} synth_voice;
typedef struct {
synth_voice *buffer;
size_t size;
} synth_voices;
typedef struct {
oscilator_type oscilator_type;
float master_volume;
} synth_params;
typedef float (*oscilator_func)(float phase);
int mqueue_get(message_queue *q, synth_message *msg);
int mqueue_push(message_queue *q, synth_message msg);
#define mqueue_init(q) \
do { \
(q)->head = (q)->tail = 0; \
pthread_mutex_init(&(q)->lock, NULL); \
} while (0)
/* #define mqueue_get(q, msg, ok) \ */
/* do { \ */
/* pthread_mutex_lock(&(q)->lock); \ */
/* if ((q)->tail == (q)->head) { \ */
/* pthread_mutex_unlock(&(q)->lock); \ */
/* *(ok) = false;\ */
/* break; \ */
/* } \ */
/* \ */
/* *(msg) = (q)->buffer[(q)->tail]; \ */
/* (q)->tail = ((q)->tail + 1) % MESSAGE_QUEUE_SIZE; \ */
/* \ */
/* pthread_mutex_unlock(&(q)->lock); \ */
/* *(ok) = true; \ */
/* } while (0) */
#define mqueue_empty(q) (q)->head == (q)->tail
void *sound_thread_start(void *ptr);
int set_hw_params(snd_pcm_t *pcm);
#endif // SOUNDS_H_
|