audio.c (4934B)
1 #include <stdint.h>
2 #include <stdbool.h>
3 #include <stddef.h>
4 #include "audio.h"
5
6 #define TA_AUDIO_MASK (TA_AUDIO_BUFFER_SIZE - 1)
7 #define TA_AUDIO_MIX_CHUNK 256
8
9 typedef char ta_audio_size_is_power_of_two[(TA_AUDIO_BUFFER_SIZE & TA_AUDIO_MASK) == 0 ? 1 : -1];
10
11 typedef struct {
12 int8_t data[TA_AUDIO_BUFFER_SIZE];
13 uint32_t read;
14 uint32_t write;
15 ta_audio_source source;
16 void *user;
17 uint8_t volume;
18 uint8_t pan;
19 bool locked;
20 } ta_audio_buffer;
21
22 static ta_audio_buffer buffers[TA_AUDIO_BUFFERS];
23 static int32_t mix_left[TA_AUDIO_MIX_CHUNK];
24 static int32_t mix_right[TA_AUDIO_MIX_CHUNK];
25
26 static bool buffer_valid(int buffer) {
27 return buffer >= 0 && buffer < TA_AUDIO_BUFFERS && buffers[buffer].locked;
28 }
29
30 int ta_audio_lock(ta_audio_source source, void *user) {
31 for (int i = 0; i < TA_AUDIO_BUFFERS; i++) {
32 if (!buffers[i].locked) {
33 buffers[i].read = 0;
34 buffers[i].write = 0;
35 buffers[i].source = source;
36 buffers[i].user = user;
37 buffers[i].volume = TA_AUDIO_VOLUME_MAX;
38 buffers[i].pan = TA_AUDIO_PAN_CENTER;
39 buffers[i].locked = true;
40
41 return i;
42 }
43 }
44
45 return -1;
46 }
47
48 void ta_audio_unlock(int buffer) {
49 if (!buffer_valid(buffer)) {
50 return;
51 }
52
53 buffers[buffer].locked = false;
54 buffers[buffer].source = NULL;
55 buffers[buffer].user = NULL;
56 buffers[buffer].read = 0;
57 buffers[buffer].write = 0;
58 }
59
60 bool ta_audio_is_locked(int buffer) {
61 return buffer_valid(buffer);
62 }
63
64 void ta_audio_set_volume(int buffer, uint8_t volume) {
65 if (buffer_valid(buffer)) {
66 buffers[buffer].volume = volume;
67 }
68 }
69
70 void ta_audio_set_pan(int buffer, uint8_t pan) {
71 if (buffer_valid(buffer)) {
72 buffers[buffer].pan = pan;
73 }
74 }
75
76 uint8_t ta_audio_get_volume(int buffer) {
77 return buffer_valid(buffer) ? buffers[buffer].volume : 0;
78 }
79
80 uint8_t ta_audio_get_pan(int buffer) {
81 return buffer_valid(buffer) ? buffers[buffer].pan : TA_AUDIO_PAN_CENTER;
82 }
83
84 uint32_t ta_audio_available(int buffer) {
85 if (!buffer_valid(buffer)) {
86 return 0;
87 }
88
89 return buffers[buffer].write - buffers[buffer].read;
90 }
91
92 uint32_t ta_audio_free(int buffer) {
93 if (!buffer_valid(buffer)) {
94 return 0;
95 }
96
97 return TA_AUDIO_BUFFER_SIZE - (buffers[buffer].write - buffers[buffer].read);
98 }
99
100 uint32_t ta_audio_write(int buffer, const int8_t *samples, uint32_t count) {
101 uint32_t room = ta_audio_free(buffer);
102
103 if (samples == NULL || room == 0) {
104 return 0;
105 }
106
107 if (count > room) {
108 count = room;
109 }
110
111 ta_audio_buffer *target = &buffers[buffer];
112
113 for (uint32_t i = 0; i < count; i++) {
114 target->data[(target->write + i) & TA_AUDIO_MASK] = samples[i];
115 }
116
117 target->write += count;
118
119 return count;
120 }
121
122 uint32_t ta_audio_read(int buffer, int8_t *samples, uint32_t count) {
123 uint32_t ready = ta_audio_available(buffer);
124
125 if (samples == NULL || ready == 0) {
126 return 0;
127 }
128
129 if (count > ready) {
130 count = ready;
131 }
132
133 ta_audio_buffer *source = &buffers[buffer];
134
135 for (uint32_t i = 0; i < count; i++) {
136 samples[i] = source->data[(source->read + i) & TA_AUDIO_MASK];
137 }
138
139 source->read += count;
140
141 return count;
142 }
143
144 void ta_audio_clear(int buffer) {
145 if (buffer_valid(buffer)) {
146 buffers[buffer].read = buffers[buffer].write;
147 }
148 }
149
150 void ta_audio_update(void) {
151 for (int i = 0; i < TA_AUDIO_BUFFERS; i++) {
152 if (!buffers[i].locked || buffers[i].source == NULL) {
153 continue;
154 }
155
156 bool already_called = false;
157
158 for (int j = 0; j < i; j++) {
159 if (buffers[j].locked && buffers[j].source == buffers[i].source && buffers[j].user == buffers[i].user) {
160 already_called = true;
161 break;
162 }
163 }
164
165 if (!already_called) {
166 buffers[i].source(buffers[i].user);
167 }
168 }
169 }
170
171 static int16_t clamp16(int32_t value) {
172 if (value > 32767) {
173 return 32767;
174 }
175
176 if (value < -32768) {
177 return -32768;
178 }
179
180 return (int16_t)value;
181 }
182
183 uint32_t ta_audio_mix(int16_t *out, uint32_t frames) {
184 if (out == NULL) {
185 return 0;
186 }
187
188 uint32_t done = 0;
189
190 while (done < frames) {
191 uint32_t chunk = frames - done;
192
193 if (chunk > TA_AUDIO_MIX_CHUNK) {
194 chunk = TA_AUDIO_MIX_CHUNK;
195 }
196
197 for (uint32_t i = 0; i < chunk; i++) {
198 mix_left[i] = 0;
199 mix_right[i] = 0;
200 }
201
202 for (int b = 0; b < TA_AUDIO_BUFFERS; b++) {
203 if (!buffers[b].locked || buffers[b].volume == 0) {
204 continue;
205 }
206
207 ta_audio_buffer *source = &buffers[b];
208 uint32_t ready = source->write - source->read;
209
210 if (ready > chunk) {
211 ready = chunk;
212 }
213
214 int32_t gain_right = source->pan;
215 int32_t gain_left = 255 - gain_right;
216 int32_t left_scale = (int32_t)source->volume * gain_left;
217 int32_t right_scale = (int32_t)source->volume * gain_right;
218
219 for (uint32_t i = 0; i < ready; i++) {
220 int32_t sample = source->data[(source->read + i) & TA_AUDIO_MASK];
221
222 mix_left[i] += (sample * left_scale) >> 8;
223 mix_right[i] += (sample * right_scale) >> 8;
224 }
225
226 source->read += ready;
227 }
228
229 for (uint32_t i = 0; i < chunk; i++) {
230 out[(done + i) * 2] = clamp16(mix_left[i]);
231 out[(done + i) * 2 + 1] = clamp16(mix_right[i]);
232 }
233
234 done += chunk;
235 }
236
237 return done;
238 }