1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #if 1 // def FSE_DRIVERS
6
7 #ifdef WITH_OPENAL
8
9 #define FSE_INTERNAL_API
10 #include <fs/emu/audio.h>
11 #include <fs/emu/benchmark.h>
12 #include <fs/emu.h>
13 #include <stdio.h>
14 #include <fs/base.h>
15 #include <fs/glib.h>
16 #include <fs/thread.h>
17
18 #ifdef HAVE_AL_AL_H
19 #include <AL/al.h>
20 #elif defined(HAVE_OPENAL_AL_H)
21 #include <OpenAL/al.h>
22 #endif
23 #ifdef HAVE_AL_ALC_H
24 #include <AL/alc.h>
25 #elif defined(HAVE_OPENAL_ALC_H)
26 #include <OpenAL/alc.h>
27 #endif
28
29 #include "../emu/libfsemu.h"
30 #include "../emu/audio.h"
31
32 // the actual frequency negotiated with the audio driver
33 static double g_audio_out_frequency = 0.0;
34
35 static int g_sys_buffer_bytes = 0;
36
37 double g_default_audio_pitch = 1.0;
38 int g_default_fill_target = 0;
39
fs_emu_audio_set_default_pitch(double pitch)40 void fs_emu_audio_set_default_pitch(double pitch)
41 {
42 g_default_audio_pitch = pitch;
43 }
44
45 int g_fs_emu_audio_stream_playing[MAX_STREAMS] = {};
46
47 #define FRAME_TIME_LIST_COUNT 256
48 #define AUDIO_AVG_FILL_QUEUE_COUNT 256
49 #define AUDIO_FILL_QUEUE_COUNT 256
50 #define AUDIO_FILL_QUEUE2_COUNT 128
51 #define AUDIO_IN_FRAME_QUEUE_SIZE 128
52 #define AUDIO_OUT_FRAME_QUEUE_SIZE 1024
53
54 #define FILL_STAT_BUFFER_LENGTH 512
55 #define FILL_STAT_BUFFER_ITEMS 256
56
57 #define FILL_STAT_BUFFER_ITEMS_AVG 64
58 #define FILL_STAT_BUFFER_ITEMS_MIN 64
59 #define FILL_STAT_BUFFER_ITEMS_ERR 64
60
61 #define MEMORY_BARRIER __asm__ __volatile__ ("" ::: "memory")
62
63 typedef struct audio_stream {
64 ALuint source;
65 ALuint *buffers;
66 int num_buffers;
67 int buffer_size;
68 int frequency;
69 GQueue *queue;
70 fs_mutex *mutex;
71 int buffers_queued;
72 int min_buffers;
73 int fill_target;
74
75 int fill_stat_buffer[FILL_STAT_BUFFER_LENGTH];
76
77 int err_stat_buffer[FILL_STAT_BUFFER_LENGTH];
78 int err_stat_buffer_sum;
79
80 int avg_fill_stat_buffer[FILL_STAT_BUFFER_LENGTH];
81 int min_fill_stat_buffer[FILL_STAT_BUFFER_LENGTH];
82 int avg_min_fill_stat_buffer[FILL_STAT_BUFFER_LENGTH];
83
84 int fill_stat_buffer_avg_sum;
85 int fill_stat_buffer_avg;
86 int fill_stat_buffer_min;
87 int fill_stat_buffer_avg_min_sum;
88 int fill_stat_buffer_avg_min;
89 volatile int fill_stat_buffer_pos;
90
91 //double pid_integral;
92 double pid_last_error;
93 double pid_last_last_error;
94 int pid_last_time;
95 int pid_last_last_time;
96 double pitch;
97
98 double source_volume_current;
99
100 } audio_stream;
101
102 static audio_stream *g_streams[MAX_STREAMS] = {};
103
104 #define MAX_BUFFERS 48
105
106 static ALCdevice *g_device = NULL;
107 static ALCcontext *g_context = NULL;
108
check_al_error(const char * label)109 static int check_al_error(const char *label)
110 {
111 int error;
112 if ((error = alGetError()) != AL_NO_ERROR) {
113 fs_log("openal error %d (%s)\n", error, label);
114 }
115 return error;
116 }
117
118 #define KP (1.0 * 0.00000025)
119 #define KI (1.0 * 0.000000001)
120 #define KD (1.0 * 0.0)
121
pid_controller_step(int stream,int time_ms)122 static void pid_controller_step(int stream, int time_ms)
123 {
124 audio_stream *s = g_streams[stream];
125 if (s->fill_target == 0) {
126 return;
127 }
128 if (s->pid_last_last_time == 0) {
129 s->pid_last_time = time_ms;
130 s->pid_last_last_time = time_ms;
131 }
132 int dt = time_ms - s->pid_last_last_time;
133 int error = s->fill_target - s->fill_stat_buffer_avg;
134
135 //static double last_error = 0.0;
136 //if (s->pid_last_error == 0.0) {
137 // s->pid_last_error = error;
138 //}
139 //s->pid_integral = s->pid_integral + (error * dt);
140 //s->pid_integral = s->err_stat_buffer_sum;
141
142 double derivative;
143 if (dt > 0) {
144 derivative = (s->pid_last_last_error - error) / dt;
145 } else {
146 derivative = 0;
147 }
148 double output = KP * error + KI * s->err_stat_buffer_sum + KD * derivative;
149
150 s->pid_last_last_error = s->pid_last_error;
151 s->pid_last_last_time = s->pid_last_time;
152 s->pid_last_error = error;
153 s->pid_last_time = time_ms;
154
155 s->pitch = g_default_audio_pitch - output;
156 s->pitch = MAX(0.5, MIN(2.0, s->pitch));
157 #if 0
158 static int count = 0;
159 if (++count % 25 == 0) {
160 printf("pitch: %0.3f (output %0.6f err %d err sum %d)\n",
161 s->pitch, output, error, s->err_stat_buffer_sum);
162 }
163 #endif
164 alSourcef(s->source, AL_PITCH, (ALfloat) s->pitch);
165 check_al_error("alSourcef (AL_PITCH)");
166 }
167
unqueue_old_buffers(int stream)168 static void unqueue_old_buffers(int stream)
169 {
170 audio_stream *s = g_streams[stream];
171 ALint old_buffers = 0;
172 fs_mutex_lock(s->mutex);
173 // locking here because unqueue_old_buffers can be run called from
174 // both the video thread and the emulation thread (consider changing this,
175 // perhaps even have a separate thread for periodically unqueuing).
176 alGetSourcei(s->source, AL_BUFFERS_PROCESSED, &old_buffers);
177 check_al_error("alGetSourcei (AL_BUFFERS_PROCESSED)");
178
179 if (old_buffers > 0) {
180 ALuint buffers[MAX_BUFFERS];
181 old_buffers = MIN(old_buffers, MAX_BUFFERS);
182 alSourceUnqueueBuffers(s->source, old_buffers, buffers);
183 if (check_al_error("alSourceUnqueueBuffers") != AL_NO_ERROR) {
184 fs_log("while trying to unqueue %d buffers\n");
185 }
186 for (int i = 0; i < old_buffers; i++) {
187 g_queue_push_tail(s->queue, FS_UINT_TO_POINTER(buffers[i]));
188 }
189 s->buffers_queued -= old_buffers;
190 }
191 fs_mutex_unlock(s->mutex);
192 }
193
set_paused(int stream,bool paused)194 static void set_paused(int stream, bool paused)
195 {
196 if (paused) {
197 fs_log("[AUDIO] fs_emu_audio_resume_stream %d\n", stream);
198 audio_stream *s = g_streams[stream];
199 alSourcePause(s->source);
200 g_fs_emu_audio_stream_playing[stream] = 0;
201 check_al_error("alSourcePlay");
202 } else {
203 fs_log("[AUDIO] fs_emu_audio_resume_stream %d\n", stream);
204 audio_stream *s = g_streams[stream];
205 alSourcePlay(s->source);
206 g_fs_emu_audio_stream_playing[stream] = 1;
207 check_al_error("alSourcePlay");
208 }
209 }
210
check_buffer(int stream,int buffer)211 static int check_buffer(int stream, int buffer)
212 {
213 unqueue_old_buffers(stream);
214 audio_stream *s = g_streams[stream];
215 // not extremely efficient
216 fs_mutex_lock(s->mutex);
217 GList *link = g_queue_peek_head_link(s->queue);
218 while (link) {
219 if ((unsigned int) buffer == FS_POINTER_TO_UINT(link->data)) {
220 fs_mutex_unlock(s->mutex);
221 return 1;
222 }
223 link = link->next;
224 }
225 fs_mutex_unlock(s->mutex);
226 return 0;
227 }
228
queue_buffer(int stream,int16_t * data,int size)229 static int queue_buffer(int stream, int16_t* data, int size)
230 {
231 if (g_fs_emu_benchmark_mode) {
232 /* No audio output while benchmarking. */
233 return 0;
234 }
235 if (g_fs_emu_benchmarking) {
236 /* No audio output while benchmarking. */
237 return 0;
238 }
239 //fs_log("fs_emu_queue_audio_buffer stream %d size %d\n", stream, size);
240 audio_stream *s = g_streams[stream];
241
242 ALuint buffer = 0;
243 fs_mutex_lock(s->mutex);
244 //while (1) {
245 buffer = FS_POINTER_TO_UINT(g_queue_pop_head(s->queue));
246 if (!buffer) {
247 fs_log("[AUDIO] no audio buffer available - dropping data\n");
248 fs_mutex_unlock(s->mutex);
249 return 0;
250 }
251 s->buffers_queued += 1;
252 // create a local copy while we have the lock
253 //int buffers_queued = s->buffers_queued;
254 fs_mutex_unlock(s->mutex);
255
256 #if 0
257 /* For debugging purposes, clear one of the stereo channels. */
258 int16_t *d = data;
259 for (int i = 0; i < size / 4; i++) {
260 d++;
261 *d = 0;
262 d++;
263 }
264 #endif
265
266 alBufferData(buffer, AL_FORMAT_STEREO16, data, size, s->frequency);
267 check_al_error("alBufferData");
268 alSourceQueueBuffers(s->source, 1, &buffer);
269 check_al_error("alSourceQueueBuffers");
270
271 ALint state;
272 alGetSourcei(s->source, AL_SOURCE_STATE, &state);
273 check_al_error("alGetSourcei (AL_SOURCE_STATE)");
274 if (state != AL_PLAYING) {
275 g_fs_emu_audio_buffer_underrun_time = fs_get_monotonic_time();
276 g_fs_emu_audio_buffer_underruns += 1;
277 // we have had a buffer underrun - we now wait until we have queued
278 // some buffers
279 //if (buffers_queued < s->min_buffers) {
280 // // want more buffers
281 //}
282 //else {
283 fs_log("[AUDIO] Buffer underrun in stream %d\n", stream);
284 alSourcePlay(s->source);
285 g_fs_emu_audio_stream_playing[stream] = 1;
286 check_al_error("alSourcePlay");
287 //}
288 }
289
290 double want_volume = fse_audio.want_volume[stream] * 0.9;
291 if (want_volume != s->source_volume_current) {
292 s->source_volume_current = want_volume;
293 alSourcef(s->source, AL_GAIN, want_volume);
294 }
295
296 unqueue_old_buffers(stream);
297 return buffer;
298 }
299
fs_emu_audio_get_measured_avg_buffer_fill(int stream)300 double fs_emu_audio_get_measured_avg_buffer_fill(int stream)
301 {
302 audio_stream *s = g_streams[stream];
303 return s->fill_stat_buffer_avg;
304 }
305
306 #if 0
307 void fs_emu_enable_audio_stream(int stream)
308 {
309 fs_log("enabling audio stream %d\n", stream);
310 }
311
312 #endif
313
314 #if 0
315 void fs_emu_disable_audio_stream(int stream)
316 {
317 fs_log("disabling audio stream %d\n", stream);
318 }
319
320 #endif
321
322 #if 0
323 void fs_emu_set_audio_buffer_frequency(int stream, int frequency)
324 {
325
326 }
327
328 #endif
329
output_frequency(void)330 static int output_frequency(void)
331 {
332 return g_audio_out_frequency;
333 }
334
335 #if 0
336 int fs_emu_get_audio_buffer_size()
337 {
338 return g_sys_buffer_bytes;
339 }
340
341 #endif
342
343 #if 0
344 void fs_emu_audio_sample(int stream, int16_t left, int16_t right)
345 {
346
347 }
348
349 #endif
350
stream_buffer_time_us(audio_stream * s)351 static double stream_buffer_time_us(audio_stream *s)
352 {
353 int bytes = s->buffers_queued * s->buffer_size;
354 int channels = 2;
355 int sample_bytes = 2;
356 return (int) (1000000.0 * bytes / (s->frequency * channels * sample_bytes));
357 }
358
update_stats(int stream,int time_ms)359 static void update_stats(int stream, int time_ms)
360 {
361 if (!g_fs_emu_audio_stream_playing[stream]) {
362 return;
363 }
364 audio_stream *s = g_streams[stream];
365 int available = stream_buffer_time_us(s);
366 //int error = available - s->fill_target;
367 int error = s->fill_target - s->fill_stat_buffer_avg;
368
369 int head_pos = s->fill_stat_buffer_pos;
370 int avg_tail_pos = head_pos - (FILL_STAT_BUFFER_ITEMS_AVG - 1);
371 int min_tail_pos = head_pos - (FILL_STAT_BUFFER_ITEMS_MIN - 1);
372 head_pos = (head_pos + 1) % FILL_STAT_BUFFER_LENGTH;
373 avg_tail_pos = (avg_tail_pos + FILL_STAT_BUFFER_LENGTH) %
374 FILL_STAT_BUFFER_LENGTH;
375 min_tail_pos = (min_tail_pos + FILL_STAT_BUFFER_LENGTH) %
376 FILL_STAT_BUFFER_LENGTH;
377
378 s->fill_stat_buffer[head_pos] = available;
379
380 s->err_stat_buffer[head_pos] = error;
381 int err_tail_pos = head_pos - (FILL_STAT_BUFFER_ITEMS_ERR - 1);
382 err_tail_pos = (err_tail_pos + FILL_STAT_BUFFER_LENGTH) %
383 FILL_STAT_BUFFER_LENGTH;
384 s->err_stat_buffer_sum = s->err_stat_buffer_sum -
385 s->err_stat_buffer[err_tail_pos] + error;
386
387 s->fill_stat_buffer_avg_sum = s->fill_stat_buffer_avg_sum - \
388 s->fill_stat_buffer[avg_tail_pos] +
389 available;
390 s->fill_stat_buffer_avg = s->fill_stat_buffer_avg_sum /
391 FILL_STAT_BUFFER_ITEMS_AVG;
392 #if 0
393 printf("%d %d %d\n", available, s->fill_stat_buffer_avg,
394 s->fill_target);
395 #endif
396
397 if (s->fill_stat_buffer[min_tail_pos] <= s->fill_stat_buffer_min) {
398 if (s->fill_stat_buffer[min_tail_pos] < s->fill_stat_buffer_min) {
399 fs_log("\n\nERROR WITH g_fill_stat_buffer_min, "
400 "g_fill_stat_buffer[min_tail_pos] = %d, "
401 "g_fill_stat_buffer_min = %d\n\n",
402 s->fill_stat_buffer[min_tail_pos],
403 s->fill_stat_buffer_min);
404 }
405 // must re-calculate min value
406 int pos = head_pos;
407 int min = 1000000000;
408 for (int i = 0; i < FILL_STAT_BUFFER_ITEMS_MIN; i++) {
409 int val = s->fill_stat_buffer[pos];
410 if (val < min) {
411 min = val;
412 }
413 pos = pos - 1;
414 pos = (pos + FILL_STAT_BUFFER_LENGTH) % FILL_STAT_BUFFER_LENGTH;
415 }
416 s->fill_stat_buffer_min = min;
417 }
418
419 s->fill_stat_buffer_avg_min_sum = s->fill_stat_buffer_avg_min_sum - \
420 s->min_fill_stat_buffer[avg_tail_pos] +
421 s->fill_stat_buffer_min;
422 s->fill_stat_buffer_avg_min = s->fill_stat_buffer_avg_min_sum /
423 FILL_STAT_BUFFER_ITEMS_AVG;
424
425 s->avg_fill_stat_buffer[head_pos] = s->fill_stat_buffer_avg;
426 s->min_fill_stat_buffer[head_pos] = s->fill_stat_buffer_min;
427 s->avg_min_fill_stat_buffer[head_pos] = s->fill_stat_buffer_avg_min;
428
429 MEMORY_BARRIER;
430 //g_fill_stat_buffer_pos = (g_fill_stat_buffer_pos + 1) % FILL_STAT_BUFFER_LENGTH;
431 s->fill_stat_buffer_pos = head_pos;
432 }
433
fs_emu_audio_video_sync(int time_ms)434 void fs_emu_audio_video_sync(int time_ms)
435 {
436 for (int i = 0; i < MAX_STREAMS; i++) {
437 if (g_streams[i]) {
438 unqueue_old_buffers(i);
439 update_stats(i, time_ms);
440 pid_controller_step(i, time_ms);
441 }
442 }
443 }
444
log_openal_info(void)445 static void log_openal_info(void)
446 {
447 fs_log("[OPENAL] Information:\n");
448 if (alGetString(AL_VERSION)) {
449 fs_log("[OPENAL] Version \"%s\"\n", alGetString(AL_VERSION));
450 }
451 if (alGetString(AL_RENDERER)) {
452 fs_log("[OPENAL] Renderer \"%s\"\n", alGetString(AL_RENDERER));
453 }
454 if (alGetString(AL_VENDOR)) {
455 fs_log("[OPENAL] Vendor \"%s\"\n", alGetString(AL_VENDOR));
456 }
457 if (alGetString(AL_EXTENSIONS)) {
458 fs_log("[OPENAL] Extensions \"%s\"\n", alGetString(AL_EXTENSIONS));
459 }
460 }
461
log_openal_devices(void)462 static void log_openal_devices(void)
463 {
464 fs_log("[OPENAL] Devices:\n");
465 if (alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT") == AL_TRUE) {
466 const char *s = (const char *) alcGetString(NULL,
467 ALC_DEVICE_SPECIFIER);
468 while (*s) {
469 fs_log("- %s\n", s);
470 while (*s++) {
471 // loop until s points to next string
472 }
473 }
474 } else {
475 fs_log(" - no support for device enumeration\n");
476 }
477 fs_log("[OPENAL] Default device: %s\n",
478 alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER));
479 }
480
fs_emu_init_audio_stream(int stream,fse_audio_stream_options * options)481 static void fs_emu_init_audio_stream(int stream,
482 fse_audio_stream_options *options)
483 {
484 audio_stream *s = g_malloc0(sizeof(audio_stream));
485 s->buffer_size = options->buffer_size;
486 s->frequency = options->frequency;
487 s->num_buffers = MAX_BUFFERS;
488 s->min_buffers = options->min_buffers;
489 fs_log("[AUDIO] Stream %d, frequency: %d, buffers: %d buffer "
490 "size: %d bytes\n", stream, s->frequency, s->num_buffers,
491 s->buffer_size);
492 s->mutex = fs_mutex_create();
493 s->queue = g_queue_new();
494 s->source_volume_current = 1.0;
495 s->buffers_queued = 0;
496 s->pid_last_error = 0;
497 s->pid_last_last_error = 0;
498 s->pid_last_time = 0;
499 s->pid_last_last_time = 0;
500
501 alGenSources(1, &s->source);
502 //alSourcei (s->source, AL_SOURCE_RELATIVE, AL_TRUE);
503 //alSource3f(s->source, AL_POSITION, 0.0, 0.0, -1.0);
504 //alSourcef (s->source, AL_ROLLOFF_FACTOR, 0.0);
505 // AL_DIRECT_CHANNELS_SOFT
506 alSourcei(s->source, 0x1033, AL_TRUE);
507
508 check_al_error("alGenSources");
509 for (int i = 0; i < s->num_buffers; i++) {
510 ALuint buffer;
511 alGenBuffers(1, &buffer);
512 check_al_error("alGenBuffers");
513 g_queue_push_tail(s->queue, FS_UINT_TO_POINTER(buffer));
514 }
515
516 if (stream == 0) {
517 s->fill_target = g_default_fill_target;
518 } else {
519 s->fill_target = 0;
520 }
521
522 g_streams[stream] = s;
523 }
524
configure(fse_audio_stream_options ** options)525 static void configure(fse_audio_stream_options **options)
526 {
527 int k = 0;
528 for (fse_audio_stream_options **o = options; *o; o++) {
529 fs_emu_init_audio_stream(k++, *o);
530 }
531 }
532
register_functions(void)533 static void register_functions(void)
534 {
535 fse_audio.configure = configure;
536 fse_audio.queue_buffer = queue_buffer;
537 fse_audio.check_buffer = check_buffer;
538 fse_audio.set_paused = set_paused;
539 fse_audio.frequency = output_frequency;
540 }
541
fse_init_openal_audio(void)542 void fse_init_openal_audio(void)
543 {
544 fs_log("[AUDIO] Initialize OpenAL audio driver\n");
545 register_functions();
546
547 // select the "preferred device"
548 g_device = alcOpenDevice(NULL);
549 if (g_device) {
550 fs_log("[OPENAL] Opened device: %s\n",
551 alcGetString(g_device, ALC_DEVICE_SPECIFIER));
552 } else {
553 fs_log("[OPENAL] NULL from alcOpenDevice\n");
554 ALenum error_code = alGetError();
555 fs_log("[OPENAL] Error code %d\n", error_code);
556 if (alGetString(error_code)) {
557 fs_log("[OPENAL] %s\n", alGetString(error_code));
558 }
559 fs_emu_warning("OPENAL: Could not open audio device");
560 }
561 if (!g_device) {
562 return;
563 }
564 log_openal_info();
565 log_openal_devices();
566
567 int frequencies[] = { 48000, 44100, 0 };
568 if (fs_config_get_int("audio_frequency") != FS_CONFIG_NONE) {
569 frequencies[0] = fs_config_get_int("audio_frequency");
570 }
571
572 for (int i = 0; frequencies[i]; i++) {
573 int frequency = frequencies[i];
574 fs_log("OPENAL: trying frequency %d\n", frequency);
575 ALCint attributes[] = {
576 ALC_MONO_SOURCES, 0,
577 ALC_STEREO_SOURCES, 2,
578 ALC_FREQUENCY, frequency,
579 0
580 };
581 #if 0
582 if (frequency == 0) {
583 // this will zero out ALC_FREQUENCY, so this index will be
584 // interpreted as end-of-attributes and OpenAL will choose
585 // frequency itself.
586 attributes[4] = 0;
587 }
588 #endif
589
590 g_context = alcCreateContext(g_device, attributes);
591 if (g_context) {
592 g_audio_out_frequency = frequency;
593 break;
594 }
595 }
596
597 #if 0
598 // FIXME: enable later
599 ALCint attributes[3] = { ALC_FREQUENCY, 48000, 0 };
600
601 fs_log("OPENAL: trying 48000\n");
602 g_context = alcCreateContext(g_device, attributes);
603 if (g_context) {
604 g_audio_out_frequency = 48000;
605 } else {
606 //check_al_error("alcCreateContext");
607 fs_log("OPENAL: trying without frequency specified\n");
608 }
609 #endif
610 #if 0
611 ALCint attributes[] = { ALC_MONO_SOURCES, 0,
612 ALC_STEREO_SOURCES, 2, 0 };
613
614 if (!g_context) {
615 g_context = alcCreateContext(g_device, attributes);
616 g_audio_out_frequency = 44100;
617 }
618 #endif
619 if (g_context) {
620 fs_log("OPENAL: created context\n");
621 alcMakeContextCurrent(g_context);
622 check_al_error("alcMakeContextCurrent");
623 fs_log("OPENAL: made context current\n");
624 } else {
625 fs_emu_warning("OpenAL: no context created\n");
626 //check_al_error("alcCreateContext");
627 }
628
629 int stereo_sources;
630 alcGetIntegerv(g_device, ALC_STEREO_SOURCES, 1, &stereo_sources);
631 fs_log("openal: number of stereo sources is %d\n", stereo_sources);
632
633 // FIXME: configure elsewhere
634 int abt = fs_config_get_int_clamped("audio_buffer_target_size",
635 1, 100);
636 if (abt == FS_CONFIG_NONE) {
637 if (fs_config_get_int("audio_buffer_target_bytes") != FS_CONFIG_NONE) {
638 fs_emu_warning("Use audio_buffer_target_size instead\n");
639 }
640 abt = 40;
641 #if 0
642 if (abt == FS_CONFIG_NONE) {
643 abt = 40;
644 } else {
645 abt = (int) (abt / 1000.0 * (options->frequency * 2 * 2));
646 }
647 #endif
648 }
649 fs_log("[AUDIO] Buffer target size (ms) = %d\n", abt);
650 //abt = (int) (abt / 1000.0 * (options->frequency * 2 * 2));
651 // fs_log("AUDIO: Buffer target size (bytes) = %d\n", abt);
652 /* Specifying fill target in microseconds */
653 g_default_fill_target = abt * 1000;
654 }
655
openal_audio_shutdown()656 static void openal_audio_shutdown()
657 {
658 for (int i = 0; i < MAX_STREAMS; i++) {
659 if (g_streams[i]) {
660 fs_log("OPENAL: Stopping stream %d\n", i);
661 alSourceStop(g_streams[i]->source);
662 }
663 }
664 alcMakeContextCurrent(NULL);
665 if (g_context) {
666 fs_log("OPENAL: alcDestroyContext\n");
667 alcDestroyContext(g_context);
668 g_context = NULL;
669 }
670 if (g_device) {
671 fs_log("OPENAL: alcCloseDevice\n");
672 alcCloseDevice(g_device);
673 g_device = NULL;
674 }
675 }
676
fs_emu_audio_shutdown()677 void fs_emu_audio_shutdown()
678 {
679 fs_log("[OPENAL] fs_emu_audio_shutdown\n");
680 openal_audio_shutdown();
681 }
682
683 #if 0
684 void fs_emu_init_audio_stream_options(fse_audio_stream_options *options)
685 {
686 options->frequency = 44100;
687 options->channels = 2;
688 options->sample_size = 16;
689 //options->buffer_size = 1024;
690 options->buffer_size = 512;
691 //options->min_buffers = 10;
692 options->min_buffers = 1;
693 }
694 #endif
695
696 //#define AUDIO_DEBUG_SCALE 0.012
697 #define AUDIO_DEBUG_SCALE 0.003
698
fs_emu_audio_render_debug_info(uint32_t * texture)699 void fs_emu_audio_render_debug_info(uint32_t *texture)
700 {
701 int x;
702 int y1;
703 uint32_t color;
704 uint32_t *line;
705
706 if (g_audio_out_frequency == 0.0) {
707 /* no audio */
708 return;
709 }
710
711 audio_stream *s = g_streams[0];
712 int head_pos = s->fill_stat_buffer_pos;
713
714 int pos = head_pos;
715
716 x = 255;
717 y1 = 0;
718 for (int i = 0; i < FILL_STAT_BUFFER_ITEMS; i++) {
719 int val = s->fill_stat_buffer[pos];
720 int underrun = val < g_sys_buffer_bytes;
721 int y2 = y1 + val * AUDIO_DEBUG_SCALE;
722 y2 = MIN(y2, 255);
723 if (underrun) {
724 color = 0x80000080;
725 } else {
726 color = 0x60602020;
727 }
728 for (int y = y1; y < y2; y++) {
729 *(texture + ((y * 256) + x)) = color;
730 }
731 if (--x < 128) {
732 break;
733 }
734 pos = pos - 1;
735 pos = (pos + FILL_STAT_BUFFER_LENGTH) % FILL_STAT_BUFFER_LENGTH;
736 }
737
738 pos = head_pos;
739 color = 0xb0b0b0b0;
740 x = 255;
741 for (int i = 0; i < FILL_STAT_BUFFER_ITEMS; i++) {
742 int val = s->avg_fill_stat_buffer[pos];
743 int y = val * AUDIO_DEBUG_SCALE;
744 if (--x < 128) {
745 break;
746 }
747 y = MIN(y, 255);
748 *(texture + ((y * 256) + x)) = color;
749 pos = pos - 1;
750 pos = (pos + FILL_STAT_BUFFER_LENGTH) % FILL_STAT_BUFFER_LENGTH;
751
752 }
753
754 pos = head_pos;
755 color = 0xb000b0b0;
756 x = 255;
757 for (int i = 0; i < FILL_STAT_BUFFER_ITEMS; i++) {
758 int val = s->avg_min_fill_stat_buffer[pos];
759 int y = val * AUDIO_DEBUG_SCALE;
760 if (--x < 128) {
761 break;
762 }
763 y = MIN(y, 255);
764 *(texture + ((y * 256) + x)) = color;
765 pos = pos - 1;
766 pos = (pos + FILL_STAT_BUFFER_LENGTH) % FILL_STAT_BUFFER_LENGTH;
767
768 }
769
770 // target buffer line
771 color = 0xb000b000;
772 line = texture + (int) (s->fill_target * AUDIO_DEBUG_SCALE) * 256 +
773 128;
774 for (int x = 128; x < 256; x++) {
775 *(line++) = color;
776 }
777 }
778
779 #endif /* WITH_OPENAL */
780
781 #endif /* FSE_DRIVERS */
782