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