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