diff options
Diffstat (limited to 'uisimulator/sdl')
-rw-r--r-- | uisimulator/sdl/sound.c | 250 |
1 files changed, 53 insertions, 197 deletions
diff --git a/uisimulator/sdl/sound.c b/uisimulator/sdl/sound.c index 6016676f70..3636939f06 100644 --- a/uisimulator/sdl/sound.c +++ b/uisimulator/sdl/sound.c | |||
@@ -26,20 +26,12 @@ | |||
26 | #include "kernel.h" | 26 | #include "kernel.h" |
27 | #include "sound.h" | 27 | #include "sound.h" |
28 | 28 | ||
29 | #ifdef HAVE_RECORDING | 29 | #include "pcm.h" |
30 | #ifndef REC_SAMPR_CAPS | ||
31 | #define REC_SAMPR_CAPS SAMPR_CAP_44 | ||
32 | #endif | ||
33 | #endif | ||
34 | |||
35 | #include "pcm_sampr.h" | 30 | #include "pcm_sampr.h" |
36 | #include "SDL.h" | 31 | #include "SDL.h" |
37 | 32 | ||
38 | static bool pcm_playing; | ||
39 | static bool pcm_paused; | ||
40 | static int cvt_status = -1; | 33 | static int cvt_status = -1; |
41 | static unsigned long pcm_frequency = SAMPR_44; | 34 | static unsigned long pcm_frequency = SAMPR_44; |
42 | static unsigned long pcm_curr_frequency = SAMPR_44; | ||
43 | 35 | ||
44 | static Uint8* pcm_data; | 36 | static Uint8* pcm_data; |
45 | static size_t pcm_data_size; | 37 | static size_t pcm_data_size; |
@@ -63,66 +55,56 @@ extern bool debug_audio; | |||
63 | #define MIN(a, b) (((a) < (b)) ? (a) : (b)) | 55 | #define MIN(a, b) (((a) < (b)) ? (a) : (b)) |
64 | #endif | 56 | #endif |
65 | 57 | ||
58 | void pcm_play_lock(void) | ||
59 | { | ||
60 | SDL_LockAudio(); | ||
61 | } | ||
62 | |||
63 | void pcm_play_unlock(void) | ||
64 | { | ||
65 | SDL_UnlockAudio(); | ||
66 | } | ||
67 | |||
66 | static void pcm_apply_settings_nolock(void) | 68 | static void pcm_apply_settings_nolock(void) |
67 | { | 69 | { |
68 | cvt_status = SDL_BuildAudioCVT(&cvt, AUDIO_S16SYS, 2, pcm_frequency, | 70 | cvt_status = SDL_BuildAudioCVT(&cvt, AUDIO_S16SYS, 2, pcm_frequency, |
69 | obtained.format, obtained.channels, obtained.freq); | 71 | obtained.format, obtained.channels, obtained.freq); |
70 | 72 | ||
71 | pcm_curr_frequency = pcm_frequency; | 73 | pcm_curr_sampr = pcm_frequency; |
72 | 74 | ||
73 | if (cvt_status < 0) { | 75 | if (cvt_status < 0) { |
74 | cvt.len_ratio = (double)obtained.freq / (double)pcm_curr_frequency; | 76 | cvt.len_ratio = (double)obtained.freq / (double)pcm_curr_sampr; |
75 | } | 77 | } |
76 | } | 78 | } |
77 | 79 | ||
78 | void pcm_apply_settings(void) | 80 | void pcm_apply_settings(void) |
79 | { | 81 | { |
80 | SDL_LockAudio(); | 82 | pcm_play_lock(); |
81 | pcm_apply_settings_nolock(); | 83 | pcm_apply_settings_nolock(); |
82 | SDL_UnlockAudio(); | 84 | pcm_play_unlock(); |
83 | } | 85 | } |
84 | 86 | ||
85 | static void sdl_dma_start_nolock(const void *addr, size_t size) | 87 | void pcm_play_dma_start(const void *addr, size_t size) |
86 | { | 88 | { |
87 | pcm_playing = false; | ||
88 | |||
89 | pcm_apply_settings_nolock(); | 89 | pcm_apply_settings_nolock(); |
90 | 90 | ||
91 | pcm_data = (Uint8 *) addr; | 91 | pcm_data = (Uint8 *) addr; |
92 | pcm_data_size = size; | 92 | pcm_data_size = size; |
93 | 93 | ||
94 | pcm_playing = true; | ||
95 | |||
96 | SDL_PauseAudio(0); | 94 | SDL_PauseAudio(0); |
97 | } | 95 | } |
98 | 96 | ||
99 | static void sdl_dma_stop_nolock(void) | 97 | void pcm_play_dma_stop(void) |
100 | { | 98 | { |
101 | pcm_playing = false; | ||
102 | |||
103 | SDL_PauseAudio(1); | 99 | SDL_PauseAudio(1); |
104 | |||
105 | pcm_paused = false; | ||
106 | } | 100 | } |
107 | 101 | ||
108 | static void (*callback_for_more)(unsigned char**, size_t*) = NULL; | 102 | void pcm_play_dma_pause(bool pause) |
109 | void pcm_play_data(void (*get_more)(unsigned char** start, size_t* size), | ||
110 | unsigned char* start, size_t size) | ||
111 | { | 103 | { |
112 | SDL_LockAudio(); | 104 | if (pause) |
113 | 105 | SDL_PauseAudio(1); | |
114 | callback_for_more = get_more; | 106 | else |
115 | 107 | SDL_PauseAudio(0); | |
116 | if (!(start && size)) { | ||
117 | if (get_more) | ||
118 | get_more(&start, &size); | ||
119 | } | ||
120 | |||
121 | if (start && size) { | ||
122 | sdl_dma_start_nolock(start, size); | ||
123 | } | ||
124 | |||
125 | SDL_UnlockAudio(); | ||
126 | } | 108 | } |
127 | 109 | ||
128 | size_t pcm_get_bytes_waiting(void) | 110 | size_t pcm_get_bytes_waiting(void) |
@@ -130,74 +112,6 @@ size_t pcm_get_bytes_waiting(void) | |||
130 | return pcm_data_size; | 112 | return pcm_data_size; |
131 | } | 113 | } |
132 | 114 | ||
133 | void pcm_mute(bool mute) | ||
134 | { | ||
135 | (void) mute; | ||
136 | } | ||
137 | |||
138 | void pcm_play_stop(void) | ||
139 | { | ||
140 | SDL_LockAudio(); | ||
141 | if (pcm_playing) { | ||
142 | sdl_dma_stop_nolock(); | ||
143 | } | ||
144 | SDL_UnlockAudio(); | ||
145 | } | ||
146 | |||
147 | void pcm_play_pause(bool play) | ||
148 | { | ||
149 | size_t next_size; | ||
150 | Uint8 *next_start; | ||
151 | |||
152 | SDL_LockAudio(); | ||
153 | |||
154 | if (!pcm_playing) { | ||
155 | SDL_UnlockAudio(); | ||
156 | return; | ||
157 | } | ||
158 | |||
159 | if(pcm_paused && play) { | ||
160 | if (pcm_get_bytes_waiting()) { | ||
161 | printf("unpause\n"); | ||
162 | pcm_apply_settings_nolock(); | ||
163 | SDL_PauseAudio(0); | ||
164 | } else { | ||
165 | printf("unpause, no data waiting\n"); | ||
166 | |||
167 | void (*get_more)(unsigned char**, size_t*) = callback_for_more; | ||
168 | |||
169 | if (get_more) { | ||
170 | get_more(&next_start, &next_size); | ||
171 | } | ||
172 | |||
173 | if (next_start && next_size) { | ||
174 | sdl_dma_start_nolock(next_start, next_size); | ||
175 | } else { | ||
176 | sdl_dma_stop_nolock(); | ||
177 | printf("unpause attempted, no data\n"); | ||
178 | } | ||
179 | } | ||
180 | } else if(!pcm_paused && !play) { | ||
181 | printf("pause\n"); | ||
182 | |||
183 | SDL_PauseAudio(1); | ||
184 | } | ||
185 | |||
186 | pcm_paused = !play; | ||
187 | |||
188 | SDL_UnlockAudio(); | ||
189 | } | ||
190 | |||
191 | bool pcm_is_paused(void) | ||
192 | { | ||
193 | return pcm_paused; | ||
194 | } | ||
195 | |||
196 | bool pcm_is_playing(void) | ||
197 | { | ||
198 | return pcm_playing; | ||
199 | } | ||
200 | |||
201 | void pcm_set_frequency(unsigned int frequency) | 115 | void pcm_set_frequency(unsigned int frequency) |
202 | { | 116 | { |
203 | switch (frequency) | 117 | switch (frequency) |
@@ -222,70 +136,6 @@ void pcm_set_frequency(unsigned int frequency) | |||
222 | pcm_frequency = frequency; | 136 | pcm_frequency = frequency; |
223 | } | 137 | } |
224 | 138 | ||
225 | /* | ||
226 | * This function goes directly into the DMA buffer to calculate the left and | ||
227 | * right peak values. To avoid missing peaks it tries to look forward two full | ||
228 | * peek periods (2/HZ sec, 100% overlap), although it's always possible that | ||
229 | * the entire period will not be visible. To reduce CPU load it only looks at | ||
230 | * every third sample, and this can be reduced even further if needed (even | ||
231 | * every tenth sample would still be pretty accurate). | ||
232 | */ | ||
233 | |||
234 | #define PEAK_SAMPLES (44100*2/HZ) /* 44100 samples * 2 / 100 Hz tick */ | ||
235 | #define PEAK_STRIDE 3 /* every 3rd sample is plenty... */ | ||
236 | |||
237 | void pcm_calculate_peaks(int *left, int *right) | ||
238 | { | ||
239 | long samples = (long) pcm_data_size / 4; | ||
240 | short *addr = (short *) pcm_data; | ||
241 | |||
242 | if (samples > PEAK_SAMPLES) | ||
243 | samples = PEAK_SAMPLES; | ||
244 | |||
245 | samples /= PEAK_STRIDE; | ||
246 | |||
247 | if (left && right) { | ||
248 | int left_peak = 0, right_peak = 0, value; | ||
249 | |||
250 | while (samples--) { | ||
251 | if ((value = addr [0]) > left_peak) | ||
252 | left_peak = value; | ||
253 | else if (-value > left_peak) | ||
254 | left_peak = -value; | ||
255 | |||
256 | if ((value = addr [PEAK_STRIDE | 1]) > right_peak) | ||
257 | right_peak = value; | ||
258 | else if (-value > right_peak) | ||
259 | right_peak = -value; | ||
260 | |||
261 | addr += PEAK_STRIDE * 2; | ||
262 | } | ||
263 | |||
264 | *left = left_peak; | ||
265 | *right = right_peak; | ||
266 | } | ||
267 | else if (left || right) { | ||
268 | int peak_value = 0, value; | ||
269 | |||
270 | if (right) | ||
271 | addr += (PEAK_STRIDE | 1); | ||
272 | |||
273 | while (samples--) { | ||
274 | if ((value = addr [0]) > peak_value) | ||
275 | peak_value = value; | ||
276 | else if (-value > peak_value) | ||
277 | peak_value = -value; | ||
278 | |||
279 | addr += PEAK_STRIDE * 2; | ||
280 | } | ||
281 | |||
282 | if (left) | ||
283 | *left = peak_value; | ||
284 | else | ||
285 | *right = peak_value; | ||
286 | } | ||
287 | } | ||
288 | |||
289 | extern int sim_volume; /* in firmware/sound.c */ | 139 | extern int sim_volume; /* in firmware/sound.c */ |
290 | void write_to_soundcard(struct pcm_udata *udata) { | 140 | void write_to_soundcard(struct pcm_udata *udata) { |
291 | if (cvt.needed) { | 141 | if (cvt.needed) { |
@@ -380,8 +230,8 @@ void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len) | |||
380 | if ((ssize_t)pcm_data_size <= 0) { | 230 | if ((ssize_t)pcm_data_size <= 0) { |
381 | pcm_data_size = 0; | 231 | pcm_data_size = 0; |
382 | 232 | ||
383 | if (callback_for_more) | 233 | if (pcm_callback_for_more) |
384 | callback_for_more(&pcm_data, &pcm_data_size); | 234 | pcm_callback_for_more(&pcm_data, &pcm_data_size); |
385 | } | 235 | } |
386 | 236 | ||
387 | if (pcm_data_size > 0) { | 237 | if (pcm_data_size > 0) { |
@@ -400,30 +250,42 @@ void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len) | |||
400 | len -= udata->num_out; | 250 | len -= udata->num_out; |
401 | } else { | 251 | } else { |
402 | DEBUGF("sdl_audio_callback: No Data.\n"); | 252 | DEBUGF("sdl_audio_callback: No Data.\n"); |
403 | sdl_dma_stop_nolock(); | 253 | pcm_play_dma_stop(); |
254 | pcm_play_dma_stopped_callback(); | ||
404 | break; | 255 | break; |
405 | } | 256 | } |
406 | } | 257 | } |
407 | } | 258 | } |
408 | 259 | ||
260 | const void * pcm_play_dma_get_peak_buffer(int *count) | ||
261 | { | ||
262 | uintptr_t addr = (uintptr_t)pcm_data; | ||
263 | *count = pcm_data_size / 4; | ||
264 | return (void *)((addr + 2) & ~3); | ||
265 | } | ||
266 | |||
409 | #ifdef HAVE_RECORDING | 267 | #ifdef HAVE_RECORDING |
410 | void pcm_init_recording(void) | 268 | void pcm_rec_lock(void) |
411 | { | 269 | { |
412 | } | 270 | } |
413 | 271 | ||
414 | void pcm_close_recording(void) | 272 | void pcm_rec_unlock(void) |
415 | { | 273 | { |
416 | } | 274 | } |
417 | 275 | ||
418 | void pcm_record_data(void (*more_ready)(void* start, size_t size), | 276 | void pcm_rec_dma_init(void) |
419 | void *start, size_t size) | 277 | { |
278 | } | ||
279 | |||
280 | void pcm_rec_dma_close(void) | ||
420 | { | 281 | { |
421 | (void)more_ready; | ||
422 | (void)start; | ||
423 | (void)size; | ||
424 | } | 282 | } |
425 | 283 | ||
426 | void pcm_stop_recording(void) | 284 | void pcm_rec_dma_start(void *start, size_t size) |
285 | { | ||
286 | } | ||
287 | |||
288 | void pcm_rec_dma_stop(void) | ||
427 | { | 289 | { |
428 | } | 290 | } |
429 | 291 | ||
@@ -433,22 +295,20 @@ void pcm_record_more(void *start, size_t size) | |||
433 | (void)size; | 295 | (void)size; |
434 | } | 296 | } |
435 | 297 | ||
436 | void pcm_calculate_rec_peaks(int *left, int *right) | 298 | unsigned long pcm_rec_status(void) |
437 | { | 299 | { |
438 | if (left) | 300 | return 0; |
439 | *left = 0; | ||
440 | if (right) | ||
441 | *right = 0; | ||
442 | } | 301 | } |
443 | 302 | ||
444 | unsigned long pcm_rec_status(void) | 303 | const void * pcm_rec_dma_get_peak_buffer(int *count) |
445 | { | 304 | { |
446 | return 0; | 305 | *count = 0; |
306 | return NULL; | ||
447 | } | 307 | } |
448 | 308 | ||
449 | #endif /* HAVE_RECORDING */ | 309 | #endif /* HAVE_RECORDING */ |
450 | 310 | ||
451 | int pcm_init(void) | 311 | void pcm_play_dma_init(void) |
452 | { | 312 | { |
453 | SDL_AudioSpec wanted_spec; | 313 | SDL_AudioSpec wanted_spec; |
454 | udata.debug = NULL; | 314 | udata.debug = NULL; |
@@ -470,7 +330,7 @@ int pcm_init(void) | |||
470 | /* Open the audio device and start playing sound! */ | 330 | /* Open the audio device and start playing sound! */ |
471 | if(SDL_OpenAudio(&wanted_spec, &obtained) < 0) { | 331 | if(SDL_OpenAudio(&wanted_spec, &obtained) < 0) { |
472 | fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError()); | 332 | fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError()); |
473 | return -1; | 333 | return; |
474 | } | 334 | } |
475 | 335 | ||
476 | switch (obtained.format) | 336 | switch (obtained.format) |
@@ -488,16 +348,12 @@ int pcm_init(void) | |||
488 | default: | 348 | default: |
489 | fprintf(stderr, "Unknown sample format obtained: %u\n", | 349 | fprintf(stderr, "Unknown sample format obtained: %u\n", |
490 | (unsigned)obtained.format); | 350 | (unsigned)obtained.format); |
491 | return -1; | 351 | return; |
492 | } | 352 | } |
493 | 353 | ||
494 | pcm_sample_bytes = obtained.channels * pcm_channel_bytes; | 354 | pcm_sample_bytes = obtained.channels * pcm_channel_bytes; |
495 | 355 | ||
496 | pcm_apply_settings_nolock(); | 356 | pcm_apply_settings_nolock(); |
497 | |||
498 | sdl_dma_stop_nolock(); | ||
499 | |||
500 | return 0; | ||
501 | } | 357 | } |
502 | 358 | ||
503 | void pcm_postinit(void) | 359 | void pcm_postinit(void) |