1 /*
2 * sound.c - General code for the sound interface.
3 *
4 * Written by
5 * Teemu Rantanen <tvr@cs.hut.fi>
6 * Marco van den Heuvel <blackystardust68@yahoo.com>
7 *
8 * Resource and cmdline code by
9 * Ettore Perazzoli <ettore@comm2000.it>
10 *
11 * This file is part of VICE, the Versatile Commodore Emulator.
12 * See README for copyright notice.
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 * 02111-1307 USA.
28 *
29 */
30
31 #include "vice.h"
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <time.h>
37 #include <assert.h>
38
39 #ifdef HAVE_STRINGS_H
40 #include <strings.h>
41 #endif
42
43 #include "archdep.h"
44 #include "clkguard.h"
45 #include "cmdline.h"
46 #include "debug.h"
47 #include "fixpoint.h"
48 #include "lib.h"
49 #include "log.h"
50 #include "machine.h"
51 #include "maincpu.h"
52 #include "monitor.h"
53 #include "resources.h"
54 #include "sound.h"
55 #include "types.h"
56 #include "tick.h"
57 #include "uiapi.h"
58 #include "util.h"
59 #include "vsync.h"
60 #include "math.h"
61 #include "ui.h"
62
63
64 static log_t sound_log = LOG_ERR;
65
66 /* ------------------------------------------------------------------------- */
67
68 #ifndef TRUE
69 #define TRUE 1
70 #endif
71
72 #ifndef FALSE
73 #define FALSE 0
74 #endif
75
76 /* ------------------------------------------------------------------------- */
77
78 typedef struct sound_register_devices_s {
79 char *name;
80 int (*init)(void);
81 int is_playback_device;
82 } sound_register_devices_t;
83
84 /* This table is used to specify the order of inits of the playback and recording devices */
85 static sound_register_devices_t sound_register_devices[] = {
86
87 /* the "native" platform specific drivers should come first, sorted by
88 priority (most wanted first) */
89
90 #ifdef USE_PULSE
91 { "pulse", sound_init_pulse_device, SOUND_PLAYBACK_DEVICE },
92 #endif
93 #ifdef USE_ARTS
94 { "arts", sound_init_arts_device, SOUND_PLAYBACK_DEVICE },
95 #endif
96 #ifdef USE_ALSA
97 { "alsa", sound_init_alsa_device, SOUND_PLAYBACK_DEVICE },
98 #endif
99 #ifdef USE_COREAUDIO
100 { "coreaudio", sound_init_coreaudio_device, SOUND_PLAYBACK_DEVICE },
101 #endif
102
103 /* Don't use the NetBSD/SUN sound driver for OpenBSD */
104 #if defined(HAVE_SYS_AUDIOIO_H) && !defined(__OpenBSD__)
105 #if defined(__NetBSD__)
106 { "netbsd", sound_init_sun_device, SOUND_PLAYBACK_DEVICE },
107 #else
108 /* Really? */
109 { "sun", sound_init_sun_device, SOUND_PLAYBACK_DEVICE },
110 #endif /* __NetBSD__*/
111 #endif /* HAVE_SYS_AUDIOIO_H */
112
113 #ifdef WIN32_COMPILE
114 #ifdef USE_DXSOUND
115 { "dx", sound_init_dx_device, SOUND_PLAYBACK_DEVICE },
116 #endif
117 #if !defined(__XBOX__)
118 { "wmm", sound_init_wmm_device, SOUND_PLAYBACK_DEVICE },
119 #endif
120 #endif
121
122 #if defined(__OS2__) && !defined(USE_SDLUI)
123 { "dart", sound_init_dart_device, SOUND_PLAYBACK_DEVICE },
124 #endif
125
126 #ifdef BEOS_COMPILE
127 { "beos", sound_init_beos_device, SOUND_PLAYBACK_DEVICE },
128 { "bsp", sound_init_bsp_device, SOUND_PLAYBACK_DEVICE },
129 #endif
130
131 #if defined(AMIGA_SUPPORT) && defined(HAVE_DEVICES_AHI_H)
132 { "ahi", sound_init_ahi_device, SOUND_PLAYBACK_DEVICE },
133 #endif
134
135 /* SDL driver last, after all platform specific ones */
136 #ifdef USE_SDL_AUDIO
137 { "sdl", sound_init_sdl_device, SOUND_PLAYBACK_DEVICE },
138 #endif
139
140 /* the dummy device acts as a "guard" against the drivers that create files,
141 since the list will be searched top-down, and the dummy driver always
142 works, no files will be created accidently */
143 { "dummy", sound_init_dummy_device, SOUND_PLAYBACK_DEVICE },
144
145 { "fs", sound_init_fs_device, SOUND_RECORD_DEVICE },
146 { "dump", sound_init_dump_device, SOUND_RECORD_DEVICE },
147 { "wav", sound_init_wav_device, SOUND_RECORD_DEVICE },
148 { "voc", sound_init_voc_device, SOUND_RECORD_DEVICE },
149 { "iff", sound_init_iff_device, SOUND_RECORD_DEVICE },
150 { "aiff", sound_init_aiff_device, SOUND_RECORD_DEVICE },
151
152 #ifdef USE_LAMEMP3
153 { "mp3", sound_init_mp3_device, SOUND_RECORD_DEVICE },
154 #endif
155
156 #ifdef USE_FLAC
157 { "flac", sound_init_flac_device, SOUND_RECORD_DEVICE },
158 #endif
159
160 #ifdef USE_VORBIS
161 { "ogg", sound_init_vorbis_device, SOUND_RECORD_DEVICE },
162 #endif
163
164 { "soundmovie", sound_init_movie_device, SOUND_RECORD_DEVICE },
165 { NULL, NULL, 0 }
166 };
167
168 /* ------------------------------------------------------------------------- */
169
170 static uint16_t offset = 0;
171
172 static sound_chip_t *sound_calls[SOUND_CHIPS_MAX];
173
sound_chip_register(sound_chip_t * chip)174 uint16_t sound_chip_register(sound_chip_t *chip)
175 {
176 assert(chip != NULL);
177
178 sound_calls[offset >> 5] = chip;
179 offset += 0x20;
180
181 assert((offset >> 5) < SOUND_CHIPS_MAX);
182
183 return offset - 0x20;
184 }
185
186 /* ------------------------------------------------------------------------- */
187
sound_machine_open(int chipno)188 static sound_t *sound_machine_open(int chipno)
189 {
190 sound_t *retval = NULL;
191 int i;
192
193 for (i = 0; i < (offset >> 5); i++) {
194 if (sound_calls[i]->open) {
195 retval = sound_calls[i]->open(chipno);
196 }
197 }
198 return retval;
199 }
200
sound_machine_init(sound_t * psid,int speed,int cycles_per_sec)201 static int sound_machine_init(sound_t *psid, int speed, int cycles_per_sec)
202 {
203 int retval = 1;
204 int i;
205
206 for (i = 0; i < (offset >> 5); i++) {
207 if (sound_calls[i]->init) {
208 retval &= sound_calls[i]->init(psid, speed, cycles_per_sec);
209 }
210 }
211 return retval;
212 }
213
sound_machine_close(sound_t * psid)214 static void sound_machine_close(sound_t *psid)
215 {
216 int i;
217
218 for (i = 0; i < (offset >> 5); i++) {
219 if (sound_calls[i]->close) {
220 sound_calls[i]->close(psid);
221 }
222 }
223 }
224
225 /*
226 There is some inconsistency about when the buffer should be overwritten and
227 when mixed. Usually it's overwritten by SID and other cycle based engines,
228 and mixed by non-cycle based engines. On pet unfortunately it is always
229 mixed (unless SID is enabled) resulting in looping and distorted sound. As
230 a quick bandaid the memset was added below. This should be really cleaned
231 up someday.
232 */
sound_machine_calculate_samples(sound_t ** psid,int16_t * pbuf,int nr,int soc,int scc,int * delta_t)233 static int sound_machine_calculate_samples(sound_t **psid, int16_t *pbuf, int nr, int soc, int scc, int *delta_t)
234 {
235 int i;
236 int temp;
237 int initial_delta_t = *delta_t;
238 int delta_t_for_other_chips;
239
240 if (sound_calls[0]->cycle_based() || (!sound_calls[0]->cycle_based() && sound_calls[0]->chip_enabled)) {
241 temp = sound_calls[0]->calculate_samples(psid, pbuf, nr, soc, scc, delta_t);
242 } else {
243 memset(pbuf, 0, nr * sizeof(int16_t) * soc); /* FIXME: see above */
244 temp = nr;
245 }
246
247 for (i = 1; i < (offset >> 5); i++) {
248 if (sound_calls[i]->chip_enabled) {
249 delta_t_for_other_chips = initial_delta_t;
250 sound_calls[i]->calculate_samples(psid, pbuf, temp, soc, scc, &delta_t_for_other_chips);
251 }
252 }
253 return temp;
254 }
255
sound_machine_store(sound_t * psid,uint16_t addr,uint8_t val)256 static void sound_machine_store(sound_t *psid, uint16_t addr, uint8_t val)
257 {
258 if (sound_calls[addr >> 5]->store) {
259 sound_calls[addr >> 5]->store(psid, (uint16_t)(addr & 0x1f), val);
260 }
261 }
262
sound_machine_read(sound_t * psid,uint16_t addr)263 static uint8_t sound_machine_read(sound_t *psid, uint16_t addr)
264 {
265 if (sound_calls[addr >> 5]->read) {
266 return sound_calls[addr >> 5]->read(psid, (uint16_t)(addr & 0x1f));
267 }
268 return 0;
269 }
270
sound_machine_reset(sound_t * psid,CLOCK cpu_clk)271 static void sound_machine_reset(sound_t *psid, CLOCK cpu_clk)
272 {
273 int i;
274
275 for (i = 0; i < (offset >> 5); i++) {
276 if (sound_calls[i]->reset) {
277 sound_calls[i]->reset(psid, cpu_clk);
278 }
279 }
280 }
281
sound_machine_cycle_based(void)282 static int sound_machine_cycle_based(void)
283 {
284 int i;
285 int retval = 0;
286
287 for (i = 0; i < (offset >> 5); i++) {
288 retval |= sound_calls[i]->cycle_based();
289 }
290 return retval;
291 }
292
sound_machine_channels(void)293 static int sound_machine_channels(void)
294 {
295 int i;
296 int retval = 0;
297 int temp;
298
299 for (i = 0; i < (offset >> 5); i++) {
300 temp = sound_calls[i]->channels();
301 if (temp > retval) {
302 retval = temp;
303 }
304 }
305 return retval;
306 }
307
308 /* ------------------------------------------------------------------------- */
309
310 /* Resource handling -- Added by Ettore 98-04-26. */
311
312 /* FIXME: We need sanity checks! And do we really need all of these
313 `sound_close()' calls? */
314
315 static int playback_enabled; /* app_resources.sound */
316 static int sample_rate; /* app_resources.soundSampleRate */
317 static char *device_name = NULL; /* app_resources.soundDeviceName */
318 static char *device_arg = NULL; /* app_resources.soundDeviceArg */
319 static char *recorddevice_name = NULL; /* app_resources.soundDeviceName */
320 static char *recorddevice_arg = NULL; /* app_resources.soundDeviceArg */
321 static int buffer_size; /* app_resources.soundBufferSize */
322 static int suspend_time; /* app_resources.soundSuspendTime */
323 static int volume;
324 static int amp;
325 static int fragment_size;
326 static int output_option;
327
328 /* divisors for fragment size calculation */
329 static int fragment_divisor[] = {
330 32, /* 100ms / 32 = 0.625ms */
331 16, /* 100ms / 16 = 1.25ms */
332 8, /* 100ms / 8 = 2.5ms */
333 4, /* 100ms / 4 = 5ms */
334 2, /* 100ms / 2 = 10 ms */
335 1 /* 100ms / 1 = 20 ms, actually unused (since it is not practical) */
336 };
337
338 static char *playback_devices_cmdline = NULL;
339 static char *record_devices_cmdline = NULL;
340
341 /* I need this to serialize close_sound and enablesound/sound_open in
342 the OS/2 Multithreaded environment */
343 static int sdev_open = FALSE;
344
345 /* I need this to serialize close_sound and enablesound/sound_open in
346 the OS/2 Multithreaded environment */
347 int sound_state_changed;
348 int sid_state_changed;
349
350 /* Sample based or cycle based sound engine. */
351 static int cycle_based = 0;
352
353 /* If a current playback device is used to control emulator timing */
354 static int sound_is_timing_source = FALSE;
355
set_output_option(int val,void * param)356 static int set_output_option(int val, void *param)
357 {
358 switch (val) {
359 case SOUND_OUTPUT_SYSTEM:
360 case SOUND_OUTPUT_MONO:
361 case SOUND_OUTPUT_STEREO:
362 break;
363 default:
364 return -1;
365 }
366
367 if (output_option != val) {
368 output_option = val;
369 sound_state_changed = TRUE;
370 }
371 return 0;
372 }
373
set_playback_enabled(int value,void * param)374 static int set_playback_enabled(int value, void *param)
375 {
376 int val = value ? 1 : 0;
377
378 if (val) {
379 vsync_disable_timer();
380 }
381
382 playback_enabled = val;
383 sound_machine_enable(playback_enabled);
384 return 0;
385 }
386
set_sample_rate(int val,void * param)387 static int set_sample_rate(int val, void *param)
388 {
389 if (val <= 0) {
390 return -1;
391 }
392
393 sample_rate = val;
394 sound_state_changed = TRUE;
395 return 0;
396 }
397
set_device_name(const char * val,void * param)398 static int set_device_name(const char *val, void *param)
399 {
400 if (!val || val[0] == '\0') {
401 /* Use the default sound device */
402 if (archdep_is_haiku() == 0) {
403 util_string_set(&device_name, "bsp");
404 } else {
405 util_string_set(&device_name, sound_register_devices[0].name);
406 }
407 } else {
408 util_string_set(&device_name, val);
409 }
410 sound_state_changed = TRUE;
411 return 0;
412 }
413
set_device_arg(const char * val,void * param)414 static int set_device_arg(const char *val, void *param)
415 {
416 util_string_set(&device_arg, val);
417 sound_state_changed = TRUE;
418 return 0;
419 }
420
set_recorddevice_name(const char * val,void * param)421 static int set_recorddevice_name(const char *val, void *param)
422 {
423 util_string_set(&recorddevice_name, val);
424 sound_state_changed = TRUE;
425 return 0;
426 }
427
set_recorddevice_arg(const char * val,void * param)428 static int set_recorddevice_arg(const char *val, void *param)
429 {
430 util_string_set(&recorddevice_arg, val);
431 sound_state_changed = TRUE;
432 return 0;
433 }
434
set_buffer_size(int val,void * param)435 static int set_buffer_size(int val, void *param)
436 {
437 if (val > 0) {
438 buffer_size = val;
439 } else {
440 if (machine_class == VICE_MACHINE_VSID) {
441 buffer_size = SOUND_SAMPLE_MAX_BUFFER_SIZE;
442 } else {
443 buffer_size = SOUND_SAMPLE_BUFFER_SIZE;
444 }
445 }
446
447 sound_state_changed = TRUE;
448 return 0;
449 }
450
set_fragment_size(int val,void * param)451 static int set_fragment_size(int val, void *param)
452 {
453 if (val < SOUND_FRAGMENT_VERY_SMALL) {
454 val = SOUND_FRAGMENT_VERY_SMALL;
455 } else if (val > SOUND_FRAGMENT_VERY_LARGE) {
456 val = SOUND_FRAGMENT_VERY_LARGE;
457 }
458 fragment_size = val;
459 sound_state_changed = TRUE;
460 return 0;
461 }
462
set_suspend_time(int val,void * param)463 static int set_suspend_time(int val, void *param)
464 {
465 suspend_time = val;
466
467 if (suspend_time < 0) {
468 suspend_time = 0;
469 }
470
471 sound_state_changed = TRUE;
472 return 0;
473 }
474
set_volume(int val,void * param)475 static int set_volume(int val, void *param)
476 {
477 volume = val;
478
479 if (volume < 0) {
480 volume = 0;
481 }
482
483 if (volume > 100) {
484 volume = 100;
485 }
486
487 amp = (int)((exp((double)volume / 100.0 * log(2.0)) - 1.0) * 4096.0);
488
489 ui_display_volume(volume);
490
491 return 0;
492 }
493
494 static const resource_string_t resources_string[] = {
495 { "SoundDeviceName", "", RES_EVENT_NO, NULL,
496 &device_name, set_device_name, NULL },
497 { "SoundDeviceArg", "", RES_EVENT_NO, NULL,
498 &device_arg, set_device_arg, NULL },
499 { "SoundRecordDeviceName", "", RES_EVENT_STRICT, (resource_value_t)"",
500 &recorddevice_name, set_recorddevice_name, NULL },
501 { "SoundRecordDeviceArg", "", RES_EVENT_NO, NULL,
502 &recorddevice_arg, set_recorddevice_arg, NULL },
503 RESOURCE_STRING_LIST_END
504 };
505
506 static const resource_int_t resources_int[] = {
507 { "Sound", 1, RES_EVENT_SAME, NULL,
508 (void *)&playback_enabled, set_playback_enabled, NULL },
509 { "SoundSampleRate", SOUND_SAMPLE_RATE, RES_EVENT_NO, NULL,
510 (void *)&sample_rate, set_sample_rate, NULL },
511 { "SoundBufferSize", SOUND_SAMPLE_BUFFER_SIZE, RES_EVENT_NO, NULL,
512 (void *)&buffer_size, set_buffer_size, NULL },
513 { "SoundFragmentSize", SOUND_FRAGMENT_MEDIUM, RES_EVENT_NO, NULL,
514 (void *)&fragment_size, set_fragment_size, NULL },
515 { "SoundSuspendTime", 0, RES_EVENT_NO, NULL,
516 (void *)&suspend_time, set_suspend_time, NULL },
517 { "SoundVolume", 100, RES_EVENT_NO, NULL,
518 (void *)&volume, set_volume, NULL },
519 { "SoundOutput", ARCHDEP_SOUND_OUTPUT_MODE, RES_EVENT_NO, NULL,
520 (void *)&output_option, set_output_option, NULL },
521 RESOURCE_INT_LIST_END
522 };
523
sound_resources_init(void)524 int sound_resources_init(void)
525 {
526 if (resources_register_string(resources_string) < 0) {
527 return -1;
528 }
529
530 return resources_register_int(resources_int);
531 }
532
sound_resources_shutdown(void)533 void sound_resources_shutdown(void)
534 {
535 lib_free(device_name);
536 lib_free(device_arg);
537 lib_free(recorddevice_name);
538 lib_free(recorddevice_arg);
539 lib_free(playback_devices_cmdline);
540 lib_free(record_devices_cmdline);
541 }
542
543 /* ------------------------------------------------------------------------- */
544
545 static const cmdline_option_t cmdline_options[] =
546 {
547 { "-sound", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
548 NULL, NULL, "Sound", (resource_value_t)1,
549 NULL, "Enable sound playback" },
550 { "+sound", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
551 NULL, NULL, "Sound", (resource_value_t)0,
552 NULL, "Disable sound playback" },
553 { "-soundrate", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
554 NULL, NULL, "SoundSampleRate", NULL,
555 "<value>", "Set sound sample rate to <value> Hz" },
556 { "-soundbufsize", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
557 NULL, NULL, "SoundBufferSize", NULL,
558 "<value>", "Set sound buffer size to <value> msec" },
559 { "-soundfragsize", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
560 NULL, NULL, "SoundFragmentSize", NULL,
561 "<value>", "Set sound fragment size (0: very small, 1: small, 2: medium, 3: large, 4: very large)" },
562 { "-soundoutput", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
563 NULL, NULL, "SoundOutput", NULL,
564 "<output mode>", "Sound output mode: (0: system decides mono/stereo, 1: always mono, 2: always stereo)" },
565 { "-soundsuspend", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
566 NULL, NULL, "SoundSuspendTime", NULL,
567 "<Seconds>", "Specify the pause interval when audio underflows (clicks) happen. 0 means no pause is done." },
568 { "-soundvolume", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
569 NULL, NULL, "SoundVolume", NULL,
570 "<Volume>", "Specify the sound volume (0..100)" },
571 CMDLINE_LIST_END
572 };
573
574 static cmdline_option_t devs_cmdline_options[] =
575 {
576 { "-sounddev", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
577 NULL, NULL, "SoundDeviceName", NULL,
578 "<Name>", NULL },
579 { "-soundarg", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
580 NULL, NULL, "SoundDeviceArg", NULL,
581 "<args>", "Specify initialization parameters for sound driver" },
582 { "-soundrecdev", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
583 NULL, NULL, "SoundRecordDeviceName", NULL,
584 "<Name>", NULL },
585 { "-soundrecarg", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
586 NULL, NULL, "SoundRecordDeviceArg", NULL,
587 "<args>", "Specify initialization parameters for recording sound driver" },
588 CMDLINE_LIST_END
589 };
590
sound_cmdline_options_init(void)591 int sound_cmdline_options_init(void)
592 {
593 int i;
594 int started_playback = 0;
595 int started_record = 0;
596 char *temp = NULL;
597
598 if (cmdline_register_options(cmdline_options) < 0) {
599 return -1;
600 }
601
602 playback_devices_cmdline = lib_strdup("Specify sound driver. (");
603 record_devices_cmdline = lib_strdup("Specify recording sound driver. (");
604
605 for (i = 0; sound_register_devices[i].name; i++) {
606 if (sound_register_devices[i].is_playback_device) {
607 if (started_playback) {
608 temp = util_concat(playback_devices_cmdline, "/", sound_register_devices[i].name, NULL);
609 } else {
610 temp = util_concat(playback_devices_cmdline, sound_register_devices[i].name, NULL);
611 started_playback = 1;
612 }
613 lib_free(playback_devices_cmdline);
614 playback_devices_cmdline = temp;
615 } else {
616 if (started_record) {
617 temp = util_concat(record_devices_cmdline, "/", sound_register_devices[i].name, NULL);
618 } else {
619 temp = util_concat(record_devices_cmdline, sound_register_devices[i].name, NULL);
620 started_record = 1;
621 }
622 lib_free(record_devices_cmdline);
623 record_devices_cmdline = temp;
624 }
625 }
626 temp = util_concat(playback_devices_cmdline, ")", NULL);
627 lib_free(playback_devices_cmdline);
628 playback_devices_cmdline = temp;
629
630 temp = util_concat(record_devices_cmdline, ")", NULL);
631 lib_free(record_devices_cmdline);
632 record_devices_cmdline = temp;
633
634 devs_cmdline_options[0].description = playback_devices_cmdline;
635 devs_cmdline_options[2].description = record_devices_cmdline;
636
637 return cmdline_register_options(devs_cmdline_options);
638 }
639
640 /* ------------------------------------------------------------------------- */
641
642 /* timing constants */
643 static unsigned int cycles_per_sec;
644 static unsigned int cycles_per_rfsh;
645 static double rfsh_per_sec;
646
647 /* Speed in percent, tracks relative_speed from vsync.c */
648 static double speed_percent;
649
650 /* Flag: Is warp mode enabled? */
651 static int warp_mode_enabled;
652
653 typedef struct {
654 /* Number of sound output channels */
655 int sound_output_channels;
656
657 /* Number of sound chip channels (for multiple SIDs) */
658 int sound_chip_channels;
659
660 /* sid itself */
661 sound_t *psid[SOUND_SIDS_MAX];
662
663 /* number of clocks between each sample. used value */
664 soundclk_t clkstep;
665
666 /* number of clocks between each sample. original value */
667 soundclk_t origclkstep;
668
669 /* factor between those two clksteps */
670 soundclk_t clkfactor;
671
672 /* time of last sample generated */
673 soundclk_t fclk;
674
675 /* time of last write to sid. used for pdev->dump() */
676 CLOCK wclk;
677
678 /* time of last call to sound_run_sound() */
679 CLOCK lastclk;
680
681 /* sample buffer */
682 int16_t *buffer;
683
684 /* sample buffer pointer */
685 int bufptr;
686
687 /* pointer to playback device structure in use */
688 sound_device_t *playdev;
689
690 /* pointer to playback device structure in use */
691 sound_device_t *recdev;
692
693 /* number of samples in a fragment */
694 int fragsize;
695
696 /* number of fragments in kernel buffer */
697 int fragnr;
698
699 /* number of samples in kernel buffer */
700 int bufsize;
701
702 /* is the device suspended? */
703 int issuspended;
704 int16_t lastsample[SOUND_CHANNELS_MAX];
705 } snddata_t;
706
707 static snddata_t snddata;
708
709 /* device registration code */
710 #define MAX_SOUND_DEVICES 24
711
712 static sound_device_t *sound_devices[MAX_SOUND_DEVICES];
713
714 static int sound_device_count = 0;
715
sound_register_device(sound_device_t * pdevice)716 int sound_register_device(sound_device_t *pdevice)
717 {
718 if (sound_device_count < MAX_SOUND_DEVICES) {
719 sound_devices[sound_device_count] = pdevice;
720 sound_device_count++;
721 } else {
722 log_error(sound_log, "available sound devices exceed VICEs storage");
723 }
724
725 return 0;
726 }
727
sound_device_num(void)728 unsigned int sound_device_num(void)
729 {
730 return sound_device_count;
731 }
732
sound_device_name(unsigned int num)733 const char *sound_device_name(unsigned int num)
734 {
735 return sound_devices[num]->name;
736 }
737
738
739 /* code to disable sid for a given number of seconds if needed */
740 static time_t disabletime;
741
enablesound(void)742 static void enablesound(void)
743 {
744 time_t diff;
745 if (!disabletime) {
746 return;
747 }
748 diff = time(0) - disabletime;
749 if (diff < 0 || diff >= (time_t)suspend_time) {
750 disabletime = 0;
751 }
752 }
753
754 /* close sid device and show error dialog */
sound_error(const char * msg)755 static int sound_error(const char *msg)
756 {
757 sound_close();
758
759 if (console_mode || video_disabled_mode) {
760 log_message(sound_log, "%s", msg);
761 } else {
762 char *txt = lib_msprintf("Sound: %s", msg);
763 ui_error(txt);
764 lib_free(txt);
765 }
766
767 playback_enabled = 0;
768
769 return 1;
770 }
771
772 static int16_t *temp_buffer = NULL;
773 static int temp_buffer_size = 0;
774
realloc_buffer(int size)775 static int16_t *realloc_buffer(int size)
776 {
777 if (temp_buffer_size < size) {
778 temp_buffer = lib_realloc(temp_buffer, size);
779 if (temp_buffer) {
780 temp_buffer_size = size;
781 memset(temp_buffer, 0, size);
782 } else {
783 temp_buffer_size = 0;
784 }
785 }
786 return temp_buffer;
787 }
788
789 /* Fill buffer with last sample.
790 rise < 0 : attenuation
791 rise == 0 : constant value
792 rise > 0 : gain
793 */
fill_buffer(int size,int rise)794 static void fill_buffer(int size, int rise)
795 {
796 int c, i;
797 int16_t *p;
798 double factor;
799
800 p = realloc_buffer(size * sizeof(int16_t) * snddata.sound_output_channels);
801 if (!p) {
802 return;
803 }
804
805 for (c = 0; c < snddata.sound_output_channels; c++) {
806 for (i = 0; i < size; i++) {
807 if (rise < 0) {
808 factor = (double)(size - i) / size;
809 } else {
810 if (rise > 0) {
811 factor = (double)i / size;
812 } else {
813 factor = 1.0;
814 }
815 }
816
817 p[i * snddata.sound_output_channels + c] = (int16_t)(snddata.lastsample[c] * factor);
818 }
819 }
820
821 i = snddata.playdev->write(p, size * snddata.sound_output_channels);
822 if (i) {
823 sound_error("write to sound device failed.");
824 }
825 }
826
827
828 /* open SID engine */
sid_open(void)829 static int sid_open(void)
830 {
831 int c;
832
833 for (c = 0; c < snddata.sound_chip_channels; c++) {
834 if (!(snddata.psid[c] = sound_machine_open(c))) {
835 return sound_error("Cannot open SID engine");
836 }
837 }
838
839 return 0;
840 }
841
842 /* initialize SID engine */
sid_init(void)843 static int sid_init(void)
844 {
845 double speed_factor;
846 int c, speed;
847
848 /* Special handling for cycle based as opposed to sample based sound
849 engines. reSID is cycle based. */
850 cycle_based = sound_machine_cycle_based();
851
852 /* "No limit" doesn't make sense for cycle based sound engines,
853 which have a fixed sampling rate. */
854 speed_factor = speed_percent ? speed_percent : 100;
855 speed = sample_rate * 100 / speed_factor;
856
857 for (c = 0; c < snddata.sound_chip_channels; c++) {
858 if (!sound_machine_init(snddata.psid[c], speed, cycles_per_sec)) {
859 return sound_error("Cannot initialize SID engine");
860 }
861 }
862
863 snddata.clkstep = SOUNDCLK_CONSTANT(cycles_per_sec) / sample_rate;
864
865 snddata.origclkstep = snddata.clkstep;
866 snddata.clkfactor = SOUNDCLK_CONSTANT(1.0);
867 snddata.fclk = SOUNDCLK_CONSTANT(maincpu_clk);
868 snddata.wclk = maincpu_clk;
869 snddata.lastclk = maincpu_clk;
870
871 return 0;
872 }
873
874 /* close SID engine */
sid_close(void)875 static void sid_close(void)
876 {
877 int c;
878 for (c = 0; c < snddata.sound_chip_channels; c++) {
879 if (snddata.psid[c]) {
880 sound_machine_close(snddata.psid[c]);
881 snddata.psid[c] = NULL;
882 }
883 }
884 }
885
sound_get_psid(unsigned int channel)886 sound_t *sound_get_psid(unsigned int channel)
887 {
888 return snddata.psid[channel];
889 }
890
891 /* open sound device */
sound_open(void)892 int sound_open(void)
893 {
894 int c, i, j;
895 int channels_cap;
896 int channels;
897 sound_device_t *pdev, *rdev;
898 char *playname, *recname;
899 char *playparam, *recparam;
900 char *err;
901 int speed;
902 int fragsize;
903 int fragnr;
904 double bufsize;
905
906 if (suspend_time > 0 && disabletime) {
907 return 1;
908 }
909
910 if (snddata.playdev) {
911 /*
912 * This can happen when loading a snapshot with multiple sids. Whilst fixing that is a good idea,
913 * this should be safe and simpler.
914 */
915 log_warning(sound_log, "ignoring sound_open when snddata.playdev is not NULL.");
916 return 0;
917 }
918
919 /* Opening the sound device and initializing the sound engine
920 might take some time. */
921 vsync_suspend_speed_eval();
922
923 /* Second SID. */
924 snddata.sound_chip_channels = sound_machine_channels();
925
926 playname = device_name;
927 if (playname && playname[0] == '\0') {
928 playname = NULL;
929 }
930
931 playparam = device_arg;
932 if (playparam && playparam[0] == '\0') {
933 playparam = NULL;
934 }
935
936 recname = recorddevice_name;
937 if (recname && recname[0] == '\0') {
938 recname = NULL;
939 }
940
941 recparam = recorddevice_arg;
942 if (recparam && recparam[0] == '\0') {
943 recparam = NULL;
944 }
945
946 /* Calculate buffer size in seconds. */
947 bufsize = ((buffer_size < 1 || buffer_size > 1000)
948 ? SOUND_SAMPLE_BUFFER_SIZE : buffer_size) / 1000.0;
949 speed = (sample_rate < 8000 || sample_rate > 96000)
950 ? SOUND_SAMPLE_RATE : sample_rate;
951
952 switch (output_option) {
953 case SOUND_OUTPUT_SYSTEM:
954 default:
955 channels = (snddata.sound_chip_channels >= 2) ? 2 : 1;
956 break;
957 case SOUND_OUTPUT_MONO:
958 channels = 1;
959 break;
960 case SOUND_OUTPUT_STEREO:
961 channels = 2;
962 break;
963 }
964
965 /* find pdev */
966 for (i = 0; (pdev = sound_devices[i]); i++) {
967 if (!playname || (pdev->name && !strcasecmp(playname, pdev->name))) {
968 break;
969 }
970 }
971
972 /* Calculate reasonable fragments. Target is 2 fragments per frame,
973 * which gives a reasonable number of fillable audio chunks to avoid
974 * ugly situation where a full frame refresh needs to occur before more
975 * audio is generated. It also improves the estimate of optimal frame
976 * length for vsync, which is closely tied to audio and uses the fragment
977 * information to calculate it. */
978 /* note: in practise it is actually better to use fragments that are as
979 * small as possible, as that will allow the whole system to catch up
980 * faster and compensate errors better. */
981 fragsize = speed / ((rfsh_per_sec < 1.0) ? 1 : ((int)rfsh_per_sec))
982 / fragment_divisor[fragment_size];
983 if (pdev) {
984 if (channels <= pdev->max_channels) {
985 fragsize *= channels;
986 }
987 }
988
989 for (i = 1; 1 << i < fragsize; i++) {
990 }
991 fragsize = 1 << i;
992 fragnr = (int)((speed * bufsize + fragsize - 1) / fragsize);
993
994 if (pdev) {
995
996 snddata.playdev = pdev;
997 snddata.fragsize = fragsize;
998 snddata.fragnr = fragnr;
999 snddata.bufsize = fragsize * fragnr;
1000 snddata.bufptr = 0;
1001
1002 if (pdev->init) {
1003 channels_cap = channels;
1004 if (pdev->init(playparam, &speed, &fragsize, &fragnr, &channels_cap)) {
1005 err = lib_msprintf("initialization failed for device `%s'.", pdev->name);
1006 sound_error(err);
1007 lib_free(err);
1008 return 1;
1009 }
1010 if (channels_cap != channels) {
1011 if (output_option != SOUND_OUTPUT_MONO) {
1012 log_warning(sound_log, "sound device lacks stereo capability, switching to mono output");
1013 }
1014 snddata.sound_output_channels = 1;
1015 } else {
1016 snddata.sound_output_channels = channels;
1017 }
1018 }
1019 snddata.buffer = lib_malloc(snddata.bufsize * snddata.sound_output_channels * sizeof(int16_t));
1020 snddata.issuspended = 0;
1021
1022 for (c = 0; c < snddata.sound_output_channels; c++) {
1023 snddata.lastsample[c] = 0;
1024 }
1025
1026 log_message(sound_log,
1027 "Opened device `%s', speed %dHz, fragment size %.2fms, buffer size %.2fms%s",
1028 pdev->name,
1029 speed,
1030 (1000.0 * fragsize / speed),
1031 (1000.0 * snddata.bufsize / speed),
1032 snddata.sound_output_channels > 1 ? ", stereo" : "");
1033 sample_rate = speed;
1034
1035 if (sid_open() != 0 || sid_init() != 0) {
1036 return 1;
1037 }
1038
1039 sound_is_timing_source = pdev->is_timing_source ? TRUE : FALSE;
1040 sid_state_changed = FALSE;
1041
1042 /* Fill up the sound hardware buffer. */
1043 if (pdev->bufferspace) {
1044 /* Fill to bufsize - fragsize. */
1045 j = pdev->bufferspace() - snddata.fragsize;
1046 if (j > 0) {
1047 /* Whole fragments. */
1048 j -= j % snddata.fragsize;
1049
1050 fill_buffer(j, 0);
1051 }
1052 }
1053 } else {
1054 err = lib_msprintf("device '%s' not found or not supported.", playname);
1055 sound_error(err);
1056 lib_free(err);
1057 return 1;
1058 }
1059
1060 /* now the playback sound device is open */
1061 sdev_open = TRUE;
1062 sound_state_changed = FALSE;
1063
1064 for (i = 0; (rdev = sound_devices[i]); i++) {
1065 if (recname && rdev->name && !strcasecmp(recname, rdev->name)) {
1066 break;
1067 }
1068 }
1069
1070 if (recname && rdev == NULL) {
1071 ui_error("Recording device %s doesn't exist!", recname);
1072 }
1073
1074 if (rdev) {
1075 if (rdev == pdev) {
1076 ui_error("Recording device must be different from playback device");
1077 resources_set_string("SoundRecordDeviceName", "");
1078 return 0;
1079 }
1080
1081 if (rdev->bufferspace != NULL) {
1082 ui_error("Warning! Recording device %s seems to be a realtime device!");
1083 }
1084
1085 if (rdev->init) {
1086 channels_cap = snddata.sound_output_channels;
1087 if (rdev->init(recparam, &speed, &fragsize, &fragnr, &channels_cap)) {
1088 ui_error("initialization failed for device `%s'.", rdev->name);
1089 resources_set_string("SoundRecordDeviceName", "");
1090 return 0;
1091 }
1092
1093 if (sample_rate != speed
1094 || snddata.fragsize != fragsize
1095 || snddata.fragnr != fragnr
1096 || snddata.sound_output_channels != channels_cap) {
1097 ui_error("The recording device doesn't support current sound parameters");
1098 rdev->close();
1099 resources_set_string("SoundRecordDeviceName", "");
1100 } else {
1101 snddata.recdev = rdev;
1102 log_message(sound_log, "Opened recording device device `%s'", rdev->name);
1103 }
1104 }
1105 }
1106 return 0;
1107 }
1108
1109 /* close sid */
sound_close(void)1110 void sound_close(void)
1111 {
1112 if (snddata.playdev) {
1113 log_message(sound_log, "Closing device `%s'", snddata.playdev->name);
1114 if (snddata.playdev->close) {
1115 snddata.playdev->close();
1116 }
1117 snddata.playdev = NULL;
1118 }
1119
1120 if (snddata.recdev) {
1121 log_message(sound_log, "Closing recording device `%s'", snddata.recdev->name);
1122 if (snddata.recdev->close) {
1123 snddata.recdev->close();
1124 }
1125 snddata.recdev = NULL;
1126 }
1127
1128 sid_close();
1129
1130 sdev_open = FALSE;
1131 sound_state_changed = FALSE;
1132 sound_is_timing_source = FALSE;
1133
1134 lib_free(snddata.buffer);
1135 snddata.buffer = NULL;
1136 snddata.bufsize = 0;
1137
1138 if (temp_buffer) {
1139 lib_free(temp_buffer);
1140 temp_buffer = NULL;
1141 temp_buffer_size = 0;
1142 }
1143
1144 /* Closing the sound device might take some time, and displaying
1145 UI dialogs certainly does. */
1146 vsync_suspend_speed_eval();
1147 }
1148
1149 /* run sid */
sound_run_sound(void)1150 static int sound_run_sound(void)
1151 {
1152 #if 0
1153 static int overflow_warning_count = 0;
1154 #endif
1155
1156 int nr = 0;
1157 int i;
1158 int delta_t = 0;
1159 int16_t *bufferptr;
1160
1161 /* XXX: implement the exact ... */
1162 if (!playback_enabled || (suspend_time > 0 && disabletime)) {
1163 return 1;
1164 }
1165
1166 if (!snddata.playdev) {
1167 i = sound_open();
1168 if (i) {
1169 return i;
1170 }
1171 }
1172
1173 /* Handling of cycle based sound engines. */
1174 if (cycle_based) {
1175 delta_t = maincpu_clk - snddata.lastclk;
1176 bufferptr = snddata.buffer + snddata.bufptr * snddata.sound_output_channels;
1177 nr = sound_machine_calculate_samples(snddata.psid,
1178 bufferptr,
1179 snddata.bufsize - snddata.bufptr,
1180 snddata.sound_output_channels,
1181 snddata.sound_chip_channels,
1182 &delta_t);
1183 if (delta_t) {
1184 sound_error("Sound buffer overflow (cycle based)");
1185 return -1;
1186 #if 0
1187 if (overflow_warning_count < 25) {
1188 log_warning(sound_log, "%s", "Sound buffer overflow (cycle based)");
1189 overflow_warning_count++;
1190 } else {
1191 if (overflow_warning_count == 25) {
1192 log_warning(sound_log, "Buffer overflow warning repeated 25 times, will now be ignored");
1193 overflow_warning_count++;
1194 }
1195 }
1196 #endif
1197 }
1198 } else {
1199 /* Handling of sample based sound engines. */
1200 nr = (int)((SOUNDCLK_CONSTANT(maincpu_clk) - snddata.fclk)
1201 / snddata.clkstep);
1202 if (!nr) {
1203 return 0;
1204 }
1205 if (nr > snddata.bufsize - snddata.bufptr) {
1206 nr = snddata.bufsize - snddata.bufptr;
1207 }
1208 bufferptr = snddata.buffer + snddata.bufptr * snddata.sound_output_channels;
1209 sound_machine_calculate_samples(snddata.psid,
1210 bufferptr,
1211 nr,
1212 snddata.sound_output_channels,
1213 snddata.sound_chip_channels,
1214 &delta_t);
1215 snddata.fclk += nr * snddata.clkstep;
1216 }
1217
1218 if (amp < 4096) {
1219 if (amp) {
1220 for (i = 0; i < (nr * snddata.sound_output_channels); i++) {
1221 bufferptr[i] = bufferptr[i] * amp / 4096;
1222 }
1223 } else {
1224 memset(bufferptr, 0, nr * snddata.sound_output_channels * sizeof(int16_t));
1225 }
1226 }
1227
1228 snddata.bufptr += nr;
1229 snddata.lastclk = maincpu_clk;
1230
1231 return 0;
1232 }
1233
1234 /* reset sid */
sound_reset(void)1235 void sound_reset(void)
1236 {
1237 int c;
1238
1239 snddata.fclk = SOUNDCLK_CONSTANT(maincpu_clk);
1240 snddata.wclk = maincpu_clk;
1241 snddata.lastclk = maincpu_clk;
1242 snddata.bufptr = 0; /* ugly hack! */
1243 for (c = 0; c < snddata.sound_chip_channels; c++) {
1244 if (snddata.psid[c]) {
1245 sound_machine_reset(snddata.psid[c], maincpu_clk);
1246 }
1247 }
1248 }
1249
prevent_clk_overflow_callback(CLOCK sub,void * data)1250 static void prevent_clk_overflow_callback(CLOCK sub, void *data)
1251 {
1252 int c;
1253
1254 snddata.lastclk -= sub;
1255 snddata.fclk -= SOUNDCLK_CONSTANT(sub);
1256 snddata.wclk -= sub;
1257 for (c = 0; c < snddata.sound_chip_channels; c++) {
1258 if (snddata.psid[c]) {
1259 sound_machine_prevent_clk_overflow(snddata.psid[c], sub);
1260 }
1261 }
1262 }
1263
1264 /* flush all generated samples from buffer to sounddevice. */
sound_flush()1265 bool sound_flush()
1266 {
1267 const unsigned long max_block_ms = 5000; /* If sound write blocks this long, assume it's broken */
1268 const unsigned long block_warn_ms = 500; /* If sound write blocks at least this long before succeeding, log a warning */
1269
1270 static unsigned long last_restart_tick = 0;
1271
1272 int c, i, nr, space;
1273 char *state;
1274 bool slept = false;
1275 unsigned long first_block_tick = 0;
1276 unsigned long total_block_ms;
1277
1278 if (!playback_enabled) {
1279 if (sdev_open) {
1280 sound_close();
1281 }
1282 goto done;
1283 }
1284
1285 if (sound_state_changed) {
1286 if (sdev_open) {
1287 sound_close();
1288 }
1289 sound_state_changed = FALSE;
1290 }
1291
1292 if (suspend_time > 0) {
1293 enablesound();
1294 }
1295 if (sound_run_sound()) {
1296 goto done;
1297 }
1298
1299 if (sid_state_changed) {
1300 if (sid_init() != 0) {
1301 goto done;
1302 }
1303 sid_state_changed = FALSE;
1304 }
1305
1306 if (warp_mode_enabled && snddata.recdev == NULL) {
1307 snddata.bufptr = 0;
1308 goto done;
1309 }
1310 sound_resume();
1311
1312 if (snddata.playdev->flush) {
1313 state = sound_machine_dump_state(snddata.psid[0]);
1314 i = snddata.playdev->flush(state);
1315 lib_free(state);
1316 if (i) {
1317 sound_error("cannot flush.");
1318 goto done;
1319 }
1320 }
1321
1322 /* Calculate the number of samples to flush - whole fragments. */
1323 nr = snddata.bufptr - snddata.bufptr % snddata.fragsize;
1324 if (!nr) {
1325 goto done;
1326 }
1327
1328 /*
1329 * At this point we have to block until we have written at least one fragment.
1330 *
1331 * The 'push against the audio device' sync method depends on this.
1332 */
1333
1334 while (!warp_mode_enabled) {
1335
1336 if (snddata.playdev->bufferspace) {
1337 space = snddata.playdev->bufferspace();
1338 } else {
1339 /*
1340 * Blocking driver like simple pulse - write everything we have.
1341 * I'm not sure if this is the right thing to do, perhaps we should
1342 * only be writin a single fragment at time?
1343 */
1344 space = nr;
1345 }
1346
1347 space -= space % snddata.fragsize;
1348
1349 if (space) {
1350 if (nr > space) {
1351 /* Write as much as we can */
1352 nr = space;
1353 }
1354
1355 /* Flush buffer, all channels are already mixed into it. */
1356 if (snddata.playdev->write(snddata.buffer, nr * snddata.sound_output_channels)) {
1357 sound_error("write to sound device failed.");
1358 goto done;
1359 }
1360
1361 if (snddata.recdev) {
1362 if (snddata.recdev->write(snddata.buffer, nr * snddata.sound_output_channels)) {
1363 sound_error("write to sound device failed.");
1364 goto done;
1365 }
1366 }
1367
1368 if (first_block_tick) {
1369 total_block_ms = tick_delta(first_block_tick) / (tick_per_second() / 1000);
1370 if (total_block_ms >= block_warn_ms) {
1371 log_warning(sound_log, "Sound device write was blocked for %lums", total_block_ms);
1372 }
1373
1374 /* not blocked anymore */
1375 first_block_tick = 0;
1376 }
1377 break;
1378 }
1379
1380 /* Haven't written yet, try again after a minimal sleep */
1381
1382 if (!first_block_tick) {
1383 first_block_tick = tick_now();
1384 } else {
1385 total_block_ms = tick_delta(first_block_tick) / (tick_per_second() / 1000);
1386
1387 if (total_block_ms >= max_block_ms) {
1388
1389 /*
1390 * Sound device may have stalled and might benefit from a restart.
1391 * But only try if we haven't tried a restart recently.
1392 */
1393
1394 log_message(sound_log, "Writing to sound device still blocked after %lums", total_block_ms);
1395
1396 if (tick_delta(last_restart_tick) / (tick_per_second() / 1000) >= 2 * max_block_ms) {
1397 log_message(sound_log, "Attempting restart");
1398 sound_close();
1399 last_restart_tick = tick_now();
1400 first_block_tick = 0;
1401 goto done;
1402 }
1403
1404 log_message(sound_log, "Last restart is too recent, disabling sound.");
1405 sound_error("Sound device stalled");
1406 goto done;
1407 }
1408
1409 /* More to write, try again after a minimal sleep */
1410 tick_sleep(tick_per_second() / 1000);
1411 slept = true;
1412 }
1413 }
1414
1415 snddata.bufptr -= nr;
1416
1417 /*
1418 * Move any incomplete fragments back to the start of the sample buffer
1419 */
1420
1421 for (c = 0; c < snddata.sound_output_channels; c++) {
1422 snddata.lastsample[c] = snddata.buffer[(nr - 1) * snddata.sound_output_channels + c];
1423 for (i = 0; i < snddata.bufptr; i++) {
1424 snddata.buffer[i * snddata.sound_output_channels + c] =
1425 snddata.buffer[(i + nr) * snddata.sound_output_channels + c];
1426 }
1427 }
1428
1429 done:
1430
1431 if (!slept) {
1432 mainlock_yield_once();
1433 }
1434
1435 /*
1436 * If the sound device is not a timing source, then we need
1437 * the host to sleep to sync time with the emulator.
1438 */
1439
1440 return !sound_is_timing_source;
1441 }
1442
1443 /* suspend sid (eg. before pause) */
sound_suspend(void)1444 void sound_suspend(void)
1445 {
1446 if (!snddata.playdev) {
1447 return;
1448 }
1449
1450 if (snddata.playdev->write && !snddata.issuspended
1451 && snddata.playdev->need_attenuation) {
1452 /* fill buffer, but avoid overwriting */
1453 if (!snddata.playdev->bufferspace
1454 || snddata.playdev->bufferspace() >= snddata.fragsize) {
1455 fill_buffer(snddata.fragsize, -1);
1456 } else {
1457 log_warning(sound_log, "Buffer full during suspend");
1458 }
1459 /* fill_buffer() can call sound_close() */
1460 if (!snddata.playdev) {
1461 return;
1462 }
1463 }
1464
1465 if (snddata.playdev->suspend && !snddata.issuspended) {
1466 if (snddata.playdev->suspend()) {
1467 return;
1468 }
1469 }
1470 snddata.issuspended = 1;
1471 }
1472
1473 /* resume sid */
sound_resume(void)1474 void sound_resume(void)
1475 {
1476 if (!snddata.playdev) {
1477 return;
1478 }
1479
1480 if (snddata.issuspended) {
1481 if (snddata.playdev->resume) {
1482 snddata.issuspended = snddata.playdev->resume();
1483 } else {
1484 snddata.issuspended = 0;
1485 }
1486
1487 if (snddata.playdev->write && !snddata.issuspended
1488 && snddata.playdev->need_attenuation) {
1489 fill_buffer(snddata.fragsize, 1);
1490 }
1491 }
1492 }
1493
1494 /* set PAL/NTSC clock speed */
sound_set_machine_parameter(long clock_rate,long ticks_per_frame)1495 void sound_set_machine_parameter(long clock_rate, long ticks_per_frame)
1496 {
1497 sid_state_changed = TRUE;
1498
1499 cycles_per_sec = (unsigned int)clock_rate;
1500 cycles_per_rfsh = (unsigned int)ticks_per_frame;
1501 rfsh_per_sec = (1.0 / ((double)cycles_per_rfsh / (double)cycles_per_sec));
1502 }
1503
1504 /* initialize sid at program start -time */
sound_init(unsigned int clock_rate,unsigned int ticks_per_frame)1505 void sound_init(unsigned int clock_rate, unsigned int ticks_per_frame)
1506 {
1507 char *devlist, *tmplist;
1508 int i;
1509
1510 sound_log = log_open("Sound");
1511
1512 sound_state_changed = FALSE;
1513 sid_state_changed = FALSE;
1514
1515 cycles_per_sec = clock_rate;
1516 cycles_per_rfsh = ticks_per_frame;
1517 rfsh_per_sec = (1.0 / ((double)cycles_per_rfsh / (double)cycles_per_sec));
1518
1519 clk_guard_add_callback(maincpu_clk_guard, prevent_clk_overflow_callback,
1520 NULL);
1521
1522 devlist = lib_strdup("");
1523
1524 for (i = 0; sound_register_devices[i].name; i++) {
1525 sound_register_devices[i].init();
1526 tmplist = lib_msprintf("%s %s", devlist, sound_register_devices[i].name);
1527 lib_free(devlist);
1528 devlist = tmplist;
1529 }
1530
1531 log_message(sound_log, "Available sound devices:%s", devlist);
1532
1533 lib_free(devlist);
1534
1535 archdep_sound_enable_default_device_tracking();
1536 }
1537
sound_sample_position(void)1538 long sound_sample_position(void)
1539 {
1540 return (snddata.clkstep == 0)
1541 ? 0 : (long)((SOUNDCLK_CONSTANT(maincpu_clk) - snddata.fclk)
1542 / snddata.clkstep);
1543 }
1544
sound_dump(int chipno)1545 int sound_dump(int chipno)
1546 {
1547 if (chipno >= snddata.sound_chip_channels) {
1548 return -1;
1549 }
1550 mon_out("%s\n", sound_machine_dump_state(snddata.psid[chipno]));
1551 return 0;
1552 }
1553
sound_read(uint16_t addr,int chipno)1554 int sound_read(uint16_t addr, int chipno)
1555 {
1556 if (sound_run_sound()) {
1557 return -1;
1558 }
1559
1560 if (chipno >= snddata.sound_chip_channels) {
1561 return -1;
1562 }
1563
1564 return sound_machine_read(snddata.psid[chipno], addr);
1565 }
1566
sound_store(uint16_t addr,uint8_t val,int chipno)1567 void sound_store(uint16_t addr, uint8_t val, int chipno)
1568 {
1569 int i;
1570
1571 if (sound_run_sound()) {
1572 return;
1573 }
1574
1575 if (chipno >= snddata.sound_chip_channels) {
1576 return;
1577 }
1578
1579 sound_machine_store(snddata.psid[chipno], addr, val);
1580
1581 if (!snddata.playdev->dump) {
1582 return;
1583 }
1584
1585 i = snddata.playdev->dump(addr, val, maincpu_clk - snddata.wclk);
1586
1587 snddata.wclk = maincpu_clk;
1588
1589 if (i) {
1590 sound_error("store to sounddevice failed.");
1591 }
1592 }
1593
1594
sound_set_relative_speed(int value)1595 void sound_set_relative_speed(int value)
1596 {
1597 double natural_fps;
1598 double new_percent;
1599
1600 if (value < 0) {
1601 natural_fps = (double)machine_get_cycles_per_second() / machine_get_cycles_per_frame();
1602 new_percent = 100.0 * (double)(0 - value) / natural_fps;
1603 } else {
1604 new_percent = value;
1605 }
1606
1607 /* printf("sound new percent: %f\n", new_percent); */
1608
1609 if (new_percent != speed_percent) {
1610 sid_state_changed = TRUE;
1611 speed_percent = new_percent;
1612 }
1613 }
1614
sound_set_warp_mode(int value)1615 void sound_set_warp_mode(int value)
1616 {
1617 warp_mode_enabled = value;
1618
1619 if (value) {
1620 sound_suspend();
1621 } else {
1622 sound_resume();
1623 }
1624 }
1625
sound_snapshot_prepare(void)1626 void sound_snapshot_prepare(void)
1627 {
1628 /* Update lastclk. */
1629 sound_run_sound();
1630 }
1631
sound_snapshot_finish(void)1632 void sound_snapshot_finish(void)
1633 {
1634 snddata.lastclk = maincpu_clk;
1635 }
1636
sound_dac_init(sound_dac_t * dac,int speed)1637 void sound_dac_init(sound_dac_t *dac, int speed)
1638 {
1639 /* 20 dB/Decade high pass filter, cutoff at 5 Hz. For DC offset filtering. */
1640 dac->alpha = (float)(0.0318309886 / (0.0318309886 + 1.0 / (float)speed));
1641 dac->value = 0;
1642 dac->output = 0.0;
1643 }
1644
1645 /* FIXME: this should use bandlimited step synthesis. Sadly, VICE does not
1646 * have an easy-to-use infrastructure for blep generation. We should write
1647 * this code. */
sound_dac_calculate_samples(sound_dac_t * dac,int16_t * pbuf,int value,int nr,int soc,int cs)1648 int sound_dac_calculate_samples(sound_dac_t *dac, int16_t *pbuf, int value, int nr, int soc, int cs)
1649 {
1650 int i, sample;
1651 int off = 0;
1652 /* A simple high pass digital filter is employed here to get rid of the DC offset,
1653 which would cause distortion when mixed with other signal. This filter is formed
1654 on the actual hardware by the combination of output decoupling capacitor and load
1655 resistance.
1656 */
1657 if (nr) {
1658 dac->output = dac->alpha * (dac->output + (float)(value - dac->value));
1659 dac->value = value;
1660 sample = (int)dac->output;
1661 if (!sample) {
1662 return nr;
1663 }
1664 if (cs & 1) {
1665 pbuf[off] = sound_audio_mix(pbuf[off], sample);
1666 }
1667 if (cs & 2) {
1668 pbuf[off + 1] = sound_audio_mix(pbuf[off + 1], sample);
1669 }
1670 off += soc;
1671 }
1672
1673 for (i = 1; i < nr; i++) {
1674 dac->output *= dac->alpha;
1675 sample = (int)dac->output;
1676 if (cs & 1) {
1677 pbuf[off] = sound_audio_mix(pbuf[off], sample);
1678 }
1679 if (cs & 2) {
1680 pbuf[off + 1] = sound_audio_mix(pbuf[off + 1], sample);
1681 }
1682 off += soc;
1683 }
1684 return nr;
1685 }
1686
1687 /* recording related functions, equivalent to screenshot_... */
sound_stop_recording(void)1688 void sound_stop_recording(void)
1689 {
1690 resources_set_string("SoundRecordDeviceName", "");
1691 }
1692
sound_is_recording(void)1693 int sound_is_recording(void)
1694 {
1695 return (strlen(recorddevice_name) > 0);
1696 }
1697