summaryrefslogtreecommitdiff
path: root/uisimulator/sdl/sound.c
diff options
context:
space:
mode:
Diffstat (limited to 'uisimulator/sdl/sound.c')
-rw-r--r--uisimulator/sdl/sound.c250
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
38static bool pcm_playing;
39static bool pcm_paused;
40static int cvt_status = -1; 33static int cvt_status = -1;
41static unsigned long pcm_frequency = SAMPR_44; 34static unsigned long pcm_frequency = SAMPR_44;
42static unsigned long pcm_curr_frequency = SAMPR_44;
43 35
44static Uint8* pcm_data; 36static Uint8* pcm_data;
45static size_t pcm_data_size; 37static 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
58void pcm_play_lock(void)
59{
60 SDL_LockAudio();
61}
62
63void pcm_play_unlock(void)
64{
65 SDL_UnlockAudio();
66}
67
66static void pcm_apply_settings_nolock(void) 68static 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
78void pcm_apply_settings(void) 80void 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
85static void sdl_dma_start_nolock(const void *addr, size_t size) 87void 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
99static void sdl_dma_stop_nolock(void) 97void 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
108static void (*callback_for_more)(unsigned char**, size_t*) = NULL; 102void pcm_play_dma_pause(bool pause)
109void 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
128size_t pcm_get_bytes_waiting(void) 110size_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
133void pcm_mute(bool mute)
134{
135 (void) mute;
136}
137
138void pcm_play_stop(void)
139{
140 SDL_LockAudio();
141 if (pcm_playing) {
142 sdl_dma_stop_nolock();
143 }
144 SDL_UnlockAudio();
145}
146
147void 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
191bool pcm_is_paused(void)
192{
193 return pcm_paused;
194}
195
196bool pcm_is_playing(void)
197{
198 return pcm_playing;
199}
200
201void pcm_set_frequency(unsigned int frequency) 115void 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
237void 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
289extern int sim_volume; /* in firmware/sound.c */ 139extern int sim_volume; /* in firmware/sound.c */
290void write_to_soundcard(struct pcm_udata *udata) { 140void 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
260const 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
410void pcm_init_recording(void) 268void pcm_rec_lock(void)
411{ 269{
412} 270}
413 271
414void pcm_close_recording(void) 272void pcm_rec_unlock(void)
415{ 273{
416} 274}
417 275
418void pcm_record_data(void (*more_ready)(void* start, size_t size), 276void pcm_rec_dma_init(void)
419 void *start, size_t size) 277{
278}
279
280void pcm_rec_dma_close(void)
420{ 281{
421 (void)more_ready;
422 (void)start;
423 (void)size;
424} 282}
425 283
426void pcm_stop_recording(void) 284void pcm_rec_dma_start(void *start, size_t size)
285{
286}
287
288void 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
436void pcm_calculate_rec_peaks(int *left, int *right) 298unsigned 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
444unsigned long pcm_rec_status(void) 303const 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
451int pcm_init(void) 311void 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
503void pcm_postinit(void) 359void pcm_postinit(void)