comparison render_audio.c @ 1931:374a5ae694e8 mame_interp

Merge from default
author Michael Pavone <pavone@retrodev.com>
date Sat, 18 Apr 2020 11:42:53 -0700
parents e4671a39d155
children cfd53c94fffb
comparison
equal deleted inserted replaced
1843:13abdc98379e 1931:374a5ae694e8
1 #include <limits.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <math.h>
5 #include "render_audio.h"
6 #include "util.h"
7 #include "config.h"
8 #include "blastem.h"
9
10 static uint8_t output_channels;
11 static uint32_t buffer_samples, sample_rate;
12
13 static audio_source *audio_sources[8];
14 static audio_source *inactive_audio_sources[8];
15 static uint8_t num_audio_sources;
16 static uint8_t num_inactive_audio_sources;
17
18 static float overall_gain_mult, *mix_buf;
19 static int sample_size;
20
21 typedef void (*conv_func)(float *samples, void *vstream, int sample_count);
22
23 static void convert_null(float *samples, void *vstream, int sample_count)
24 {
25 memset(vstream, 0, sample_count * sample_size);
26 }
27
28 static void convert_s16(float *samples, void *vstream, int sample_count)
29 {
30 int16_t *stream = vstream;
31 for (int16_t *end = stream + sample_count; stream < end; stream++, samples++)
32 {
33 float sample = *samples;
34 int16_t out_sample;
35 if (sample >= 1.0f) {
36 out_sample = 0x7FFF;
37 } else if (sample <= -1.0f) {
38 out_sample = -0x8000;
39 } else {
40 out_sample = sample * 0x7FFF;
41 }
42 *stream = out_sample;
43 }
44 }
45
46 static void clamp_f32(float *samples, void *vstream, int sample_count)
47 {
48 for (; sample_count > 0; sample_count--, samples++)
49 {
50 float sample = *samples;
51 if (sample > 1.0f) {
52 sample = 1.0f;
53 } else if (sample < -1.0f) {
54 sample = -1.0f;
55 }
56 *samples = sample;
57 }
58 }
59
60 static int32_t mix_f32(audio_source *audio, float *stream, int samples)
61 {
62 float *end = stream + samples;
63 int16_t *src = audio->front;
64 uint32_t i = audio->read_start;
65 uint32_t i_end = audio->read_end;
66 float *cur = stream;
67 float gain_mult = audio->gain_mult * overall_gain_mult;
68 size_t first_add = output_channels > 1 ? 1 : 0, second_add = output_channels > 1 ? output_channels - 1 : 1;
69 if (audio->num_channels == 1) {
70 while (cur < end && i != i_end)
71 {
72 *cur += gain_mult * ((float)src[i]) / 0x7FFF;
73 cur += first_add;
74 *cur += gain_mult * ((float)src[i++]) / 0x7FFF;
75 cur += second_add;
76 i &= audio->mask;
77 }
78 } else {
79 while(cur < end && i != i_end)
80 {
81 *cur += gain_mult * ((float)src[i++]) / 0x7FFF;
82 cur += first_add;
83 *cur += gain_mult * ((float)src[i++]) / 0x7FFF;
84 cur += second_add;
85 i &= audio->mask;
86 }
87 }
88 if (!render_is_audio_sync()) {
89 audio->read_start = i;
90 }
91 if (cur != end) {
92 debug_message("Underflow of %d samples, read_start: %d, read_end: %d, mask: %X\n", (int)(end-cur)/2, audio->read_start, audio->read_end, audio->mask);
93 return (cur-end)/2;
94 } else {
95 return ((i_end - i) & audio->mask) / audio->num_channels;
96 }
97 }
98
99 static conv_func convert;
100
101
102 int mix_and_convert(unsigned char *byte_stream, int len, int *min_remaining_out)
103 {
104 int samples = len / sample_size;
105 float *mix_dest = mix_buf ? mix_buf : (float *)byte_stream;
106 memset(mix_dest, 0, samples * sizeof(float));
107 int min_buffered = INT_MAX;
108 int min_remaining_buffer = INT_MAX;
109 for (uint8_t i = 0; i < num_audio_sources; i++)
110 {
111 int buffered = mix_f32(audio_sources[i], mix_dest, samples);
112 int remaining = (audio_sources[i]->mask + 1) / audio_sources[i]->num_channels - buffered;
113 min_buffered = buffered < min_buffered ? buffered : min_buffered;
114 min_remaining_buffer = remaining < min_remaining_buffer ? remaining : min_remaining_buffer;
115 audio_sources[i]->front_populated = 0;
116 render_buffer_consumed(audio_sources[i]);
117 }
118 convert(mix_dest, byte_stream, samples);
119 if (min_remaining_out) {
120 *min_remaining_out = min_remaining_buffer;
121 }
122 return min_buffered;
123 }
124
125 uint8_t all_sources_ready(void)
126 {
127 uint8_t num_populated = 0;
128 num_populated = 0;
129 for (uint8_t i = 0; i < num_audio_sources; i++)
130 {
131 if (audio_sources[i]->front_populated) {
132 num_populated++;
133 }
134 }
135 return num_populated == num_audio_sources;
136 }
137
138 #define BUFFER_INC_RES 0x40000000UL
139
140 void render_audio_adjust_clock(audio_source *src, uint64_t master_clock, uint64_t sample_divider)
141 {
142 src->buffer_inc = ((BUFFER_INC_RES * (uint64_t)sample_rate) / master_clock) * sample_divider;
143 }
144
145 void render_audio_adjust_speed(float adjust_ratio)
146 {
147 for (uint8_t i = 0; i < num_audio_sources; i++)
148 {
149 audio_sources[i]->buffer_inc = ((double)audio_sources[i]->buffer_inc) + ((double)audio_sources[i]->buffer_inc) * adjust_ratio + 0.5;
150 }
151 }
152
153 audio_source *render_audio_source(uint64_t master_clock, uint64_t sample_divider, uint8_t channels)
154 {
155 audio_source *ret = NULL;
156 uint32_t alloc_size = render_is_audio_sync() ? channels * buffer_samples : nearest_pow2(render_min_buffered() * 4 * channels);
157 render_lock_audio();
158 if (num_audio_sources < 8) {
159 ret = calloc(1, sizeof(audio_source));
160 ret->back = malloc(alloc_size * sizeof(int16_t));
161 ret->front = render_is_audio_sync() ? malloc(alloc_size * sizeof(int16_t)) : ret->back;
162 ret->front_populated = 0;
163 ret->opaque = render_new_audio_opaque();
164 ret->num_channels = channels;
165 audio_sources[num_audio_sources++] = ret;
166 }
167 render_unlock_audio();
168 if (!ret) {
169 fatal_error("Too many audio sources!");
170 } else {
171 render_audio_adjust_clock(ret, master_clock, sample_divider);
172 double lowpass_cutoff = get_lowpass_cutoff(config);
173 double rc = (1.0 / lowpass_cutoff) / (2.0 * M_PI);
174 ret->dt = 1.0 / ((double)master_clock / (double)(sample_divider));
175 double alpha = ret->dt / (ret->dt + rc);
176 ret->lowpass_alpha = (int32_t)(((double)0x10000) * alpha);
177 ret->buffer_pos = 0;
178 ret->buffer_fraction = 0;
179 ret->last_left = ret->last_right = 0;
180 ret->read_start = 0;
181 ret->read_end = render_is_audio_sync() ? buffer_samples * channels : 0;
182 ret->mask = render_is_audio_sync() ? 0xFFFFFFFF : alloc_size-1;
183 ret->gain_mult = 1.0f;
184 }
185 render_audio_created(ret);
186
187 return ret;
188 }
189
190
191 static float db_to_mult(float gain)
192 {
193 return powf(10.0f, gain/20.0f);
194 }
195
196 void render_audio_source_gaindb(audio_source *src, float gain)
197 {
198 src->gain_mult = db_to_mult(gain);
199 }
200
201 void render_pause_source(audio_source *src)
202 {
203 uint8_t found = 0, remaining_sources;
204 render_lock_audio();
205 for (uint8_t i = 0; i < num_audio_sources; i++)
206 {
207 if (audio_sources[i] == src) {
208 audio_sources[i] = audio_sources[--num_audio_sources];
209 found = 1;
210 remaining_sources = num_audio_sources;
211 break;
212 }
213 }
214
215 render_unlock_audio();
216 if (found) {
217 render_source_paused(src, remaining_sources);
218 }
219 inactive_audio_sources[num_inactive_audio_sources++] = src;
220 }
221
222 void render_resume_source(audio_source *src)
223 {
224 render_lock_audio();
225 if (num_audio_sources < 8) {
226 audio_sources[num_audio_sources++] = src;
227 }
228 render_unlock_audio();
229 for (uint8_t i = 0; i < num_inactive_audio_sources; i++)
230 {
231 if (inactive_audio_sources[i] == src) {
232 inactive_audio_sources[i] = inactive_audio_sources[--num_inactive_audio_sources];
233 }
234 }
235 render_source_resumed(src);
236 }
237
238 void render_free_source(audio_source *src)
239 {
240 uint8_t found = 0;
241 for (uint8_t i = 0; i < num_inactive_audio_sources; i++)
242 {
243 if (inactive_audio_sources[i] == src) {
244 inactive_audio_sources[i] = inactive_audio_sources[--num_inactive_audio_sources];
245 found = 1;
246 break;
247 }
248 }
249 if (!found) {
250 render_pause_source(src);
251 num_inactive_audio_sources--;
252 }
253
254 free(src->front);
255 if (render_is_audio_sync()) {
256 free(src->back);
257 render_free_audio_opaque(src->opaque);
258 }
259 free(src);
260 }
261
262 static int16_t lowpass_sample(audio_source *src, int16_t last, int16_t current)
263 {
264 int32_t tmp = current * src->lowpass_alpha + last * (0x10000 - src->lowpass_alpha);
265 current = tmp >> 16;
266 return current;
267 }
268
269 static void interp_sample(audio_source *src, int16_t last, int16_t current)
270 {
271 int64_t tmp = last * ((src->buffer_fraction << 16) / src->buffer_inc);
272 tmp += current * (0x10000 - ((src->buffer_fraction << 16) / src->buffer_inc));
273 src->back[src->buffer_pos++] = tmp >> 16;
274 }
275
276 static uint32_t sync_samples;
277 void render_put_mono_sample(audio_source *src, int16_t value)
278 {
279 value = lowpass_sample(src, src->last_left, value);
280 src->buffer_fraction += src->buffer_inc;
281 uint32_t base = render_is_audio_sync() ? 0 : src->read_end;
282 while (src->buffer_fraction > BUFFER_INC_RES)
283 {
284 src->buffer_fraction -= BUFFER_INC_RES;
285 interp_sample(src, src->last_left, value);
286
287 if (((src->buffer_pos - base) & src->mask) >= sync_samples) {
288 render_do_audio_ready(src);
289 }
290 src->buffer_pos &= src->mask;
291 }
292 src->last_left = value;
293 }
294
295 void render_put_stereo_sample(audio_source *src, int16_t left, int16_t right)
296 {
297 left = lowpass_sample(src, src->last_left, left);
298 right = lowpass_sample(src, src->last_right, right);
299 src->buffer_fraction += src->buffer_inc;
300 uint32_t base = render_is_audio_sync() ? 0 : src->read_end;
301 while (src->buffer_fraction > BUFFER_INC_RES)
302 {
303 src->buffer_fraction -= BUFFER_INC_RES;
304
305 interp_sample(src, src->last_left, left);
306 interp_sample(src, src->last_right, right);
307
308 if (((src->buffer_pos - base) & src->mask)/2 >= sync_samples) {
309 render_do_audio_ready(src);
310 }
311 src->buffer_pos &= src->mask;
312 }
313 src->last_left = left;
314 src->last_right = right;
315 }
316
317 static void update_source(audio_source *src, double rc, uint8_t sync_changed)
318 {
319 double alpha = src->dt / (src->dt + rc);
320 int32_t lowpass_alpha = (int32_t)(((double)0x10000) * alpha);
321 src->lowpass_alpha = lowpass_alpha;
322 if (sync_changed) {
323 uint32_t alloc_size = render_is_audio_sync() ? src->num_channels * buffer_samples : nearest_pow2(render_min_buffered() * 4 * src->num_channels);
324 src->back = realloc(src->back, alloc_size * sizeof(int16_t));
325 if (render_is_audio_sync()) {
326 src->front = malloc(alloc_size * sizeof(int16_t));
327 } else {
328 free(src->front);
329 src->front = src->back;
330 }
331 src->mask = render_is_audio_sync() ? 0xFFFFFFFF : alloc_size-1;
332 src->read_start = 0;
333 src->read_end = render_is_audio_sync() ? buffer_samples * src->num_channels : 0;
334 src->buffer_pos = 0;
335 }
336 }
337
338 uint8_t old_audio_sync;
339 void render_audio_initialized(render_audio_format format, uint32_t rate, uint8_t channels, uint32_t buffer_size, int sample_size_in)
340 {
341 sample_rate = rate;
342 output_channels = channels;
343 buffer_samples = buffer_size;
344 sample_size = sample_size_in;
345 if (mix_buf) {
346 free(mix_buf);
347 mix_buf = NULL;
348 }
349 switch(format)
350 {
351 case RENDER_AUDIO_S16:
352 convert = convert_s16;
353 mix_buf = calloc(output_channels * buffer_samples, sizeof(float));
354 break;
355 case RENDER_AUDIO_FLOAT:
356 convert = clamp_f32;
357 break;
358 case RENDER_AUDIO_UNKNOWN:
359 convert = convert_null;
360 mix_buf = calloc(output_channels * buffer_samples, sizeof(float));
361 break;
362 }
363 uint32_t syncs = render_audio_syncs_per_sec();
364 if (syncs) {
365 sync_samples = rate / syncs;
366 } else {
367 sync_samples = buffer_samples;
368 }
369 char * gain_str = tern_find_path(config, "audio\0gain\0", TVAL_PTR).ptrval;
370 overall_gain_mult = db_to_mult(gain_str ? atof(gain_str) : 0.0f);
371 uint8_t sync_changed = old_audio_sync != render_is_audio_sync();
372 old_audio_sync = render_is_audio_sync();
373 double lowpass_cutoff = get_lowpass_cutoff(config);
374 double rc = (1.0 / lowpass_cutoff) / (2.0 * M_PI);
375 render_lock_audio();
376 for (uint8_t i = 0; i < num_audio_sources; i++)
377 {
378 update_source(audio_sources[i], rc, sync_changed);
379 }
380 render_unlock_audio();
381 for (uint8_t i = 0; i < num_inactive_audio_sources; i++)
382 {
383 update_source(inactive_audio_sources[i], rc, sync_changed);
384 }
385 }