|
|
1.1.1.4 root 1: /*
1.1 root 2: * UAE - The Un*x Amiga Emulator
1.1.1.4 root 3: *
1.1 root 4: * Support for Linux/USS sound
1.1.1.4 root 5: *
1.1 root 6: * Copyright 1997 Bernd Schmidt
7: */
8:
9: #include "sysconfig.h"
10: #include "sysdeps.h"
11:
12: #include "options.h"
13: #include "memory.h"
14: #include "events.h"
15: #include "custom.h"
16: #include "gensound.h"
17: #include "sounddep/sound.h"
18: #include "threaddep/thread.h"
19: #include "SDL_audio.h"
20:
21: int sound_fd;
22: static int have_sound = 0;
23: static unsigned long formats;
24:
1.1.1.5 ! root 25: uae_u16 sndbuffer[2][44100];
! 26: uae_u16 *sndbufpt, *sndbuf_base;
! 27: int which_buffer;
1.1 root 28: int sndbufsize;
29: static SDL_AudioSpec spec;
30:
31: static smp_comm_pipe to_sound_pipe;
32: static uae_sem_t data_available_sem, callback_done_sem, sound_init_sem;
33:
1.1.1.5 ! root 34: static int dont_block;
! 35:
1.1 root 36: static int in_callback, closing_sound;
37:
38: static void sound_callback (void *userdata, Uint8 *stream, int len)
39: {
40: if (closing_sound)
41: return;
42: in_callback = 1;
43: /* Wait for data to finish. */
44: uae_sem_wait (&data_available_sem);
45: if (! closing_sound) {
46: memcpy (stream, sndbuffer, sndbufsize);
1.1.1.5 ! root 47:
1.1 root 48: /* Notify writer that we're done. */
1.1.1.5 ! root 49: if (!dont_block)
! 50: uae_sem_post (&callback_done_sem);
! 51: else
! 52: blocking_on_sound = 0;
1.1 root 53: }
54: in_callback = 0;
55: }
56:
57: void finish_sound_buffer (void)
58: {
1.1.1.5 ! root 59: dont_block = currprefs.m68k_speed == -1;
! 60:
! 61: if (dont_block)
! 62: blocking_on_sound = 1;
1.1 root 63: uae_sem_post (&data_available_sem);
1.1.1.5 ! root 64: if (!dont_block)
! 65: uae_sem_wait (&callback_done_sem);
! 66: sndbufpt = sndbuffer[which_buffer ^= 1];
1.1 root 67: }
68:
69: /* Try to determine whether sound is available. This is only for GUI purposes. */
70: int setup_sound (void)
71: {
72: int size = currprefs.sound_maxbsiz;
73:
74: spec.freq = currprefs.sound_freq;
75: spec.format = AUDIO_S16;
1.1.1.3 root 76: spec.channels = currprefs.sound_stereo ? 2 : 1;
1.1 root 77: size >>= spec.channels - 1;
78: size >>= 1;
79: while (size & (size - 1))
80: size &= size - 1;
81: if (size < 512)
82: size = 512;
83: spec.samples = size;
84: spec.callback = sound_callback;
85: spec.userdata = 0;
86:
87: if (SDL_OpenAudio (&spec, NULL) < 0) {
88: write_log (stderr, "Couldn't open audio: %s\n", SDL_GetError());
89: return 0;
90: }
91: sound_available = 1;
92: SDL_CloseAudio ();
93: return 1;
94: }
95:
96: static int open_sound (void)
97: {
98: int size = currprefs.sound_maxbsiz;
99:
100: spec.freq = currprefs.sound_freq;
1.1.1.5 ! root 101: spec.format = AUDIO_S16;
1.1.1.3 root 102: spec.channels = currprefs.sound_stereo ? 2 : 1;
1.1 root 103: /* Always interpret buffer size as number of samples, not as actual
104: buffer size. Of course, since 8192 is the default, we'll have to
105: scale that to a sane value (assuming that otherwise 16 bits and
106: stereo would have been enabled and we'd have done the shift by
107: two anyway). */
1.1.1.5 ! root 108: size >>= spec.channels;
! 109:
1.1 root 110: while (size & (size - 1))
111: size &= size - 1;
112: if (size < 512)
113: size = 512;
114: spec.samples = size;
115: spec.callback = sound_callback;
116: spec.userdata = 0;
117:
118: if (SDL_OpenAudio (&spec, NULL) < 0) {
119: write_log (stderr, "Couldn't open audio: %s\n", SDL_GetError());
120: return 0;
121: }
122: have_sound = 1;
123:
1.1.1.5 ! root 124: obtainedfreq = spec.freq;
1.1 root 125:
126: if (spec.format == AUDIO_S16) {
127: init_sound_table16 ();
1.1.1.3 root 128: sample_handler = currprefs.sound_stereo ? sample16s_handler : sample16_handler;
1.1 root 129: } else {
130: init_sound_table8 ();
1.1.1.3 root 131: sample_handler = currprefs.sound_stereo ? sample8s_handler : sample8_handler;
1.1 root 132: }
133: sound_available = 1;
1.1.1.5 ! root 134: write_log ("SDL sound driver found and configured at %d Hz, buffer is %d samples\n",
! 135: spec.freq, spec.samples);
! 136: sndbufpt = sndbuf_base = sndbuffer[which_buffer = 0];
! 137: sndbufsize = size * 2 * spec.channels;
1.1 root 138: return 1;
139: }
140:
141: static void *sound_thread (void *dummy)
142: {
143: for (;;) {
144: int cmd = read_comm_pipe_int_blocking (&to_sound_pipe);
145: int n;
146:
147: switch (cmd) {
148: case 0:
149: open_sound ();
150: uae_sem_post (&sound_init_sem);
151: break;
152: case 1:
153: uae_sem_post (&sound_init_sem);
154: return 0;
155: }
156: }
157: }
158:
159: /* We need a thread for this, since communication between finish_sound_buffer
160: and the callback works through semaphores. In theory, this is unnecessary,
161: since SDL uses a sound thread internally, and the callback runs in its
162: context. But we don't want to depend on SDL's internals too much. */
163: static void init_sound_thread (void)
164: {
165: uae_thread_id tid;
166:
167: init_comm_pipe (&to_sound_pipe, 20, 1);
168: uae_sem_init (&data_available_sem, 0, 0);
169: uae_sem_init (&callback_done_sem, 0, 0);
170: uae_sem_init (&sound_init_sem, 0, 0);
171: uae_start_thread (sound_thread, NULL, &tid);
172: }
173:
174: void close_sound (void)
175: {
176: if (! have_sound)
177: return;
178:
179: SDL_PauseAudio (1);
180: if (in_callback) {
181: closing_sound = 1;
182: uae_sem_post (&data_available_sem);
183: }
184: write_comm_pipe_int (&to_sound_pipe, 1, 1);
185: uae_sem_wait (&sound_init_sem);
186: SDL_CloseAudio ();
187: uae_sem_destroy (&data_available_sem);
188: uae_sem_destroy (&sound_init_sem);
189: uae_sem_destroy (&callback_done_sem);
190: have_sound = 0;
191: }
192:
193: int init_sound (void)
194: {
195: in_callback = 0;
196: closing_sound = 0;
197:
198: init_sound_thread ();
199: write_comm_pipe_int (&to_sound_pipe, 0, 1);
200: uae_sem_wait (&sound_init_sem);
201: SDL_PauseAudio (0);
202:
203: return have_sound;
204: }
205:
206: void pause_sound (void)
207: {
208: SDL_PauseAudio (1);
209: }
210:
211: void resume_sound (void)
212: {
213: SDL_PauseAudio (0);
214: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.