comparison src/audio/SDL_audio.c @ 2716:f8f68f47285a

Final merge of Google Summer of Code 2008 work... Audio Ideas - Resampling and Pitch Shifting by Aaron Wishnick, mentored by Ryan C. Gordon
author Sam Lantinga <slouken@libsdl.org>
date Mon, 25 Aug 2008 15:08:59 +0000
parents aedfcdeb69b6
children 2768bd7281e0
comparison
equal deleted inserted replaced
2715:336b604ec15b 2716:f8f68f47285a
254 FILL_STUB(UnlockDevice); 254 FILL_STUB(UnlockDevice);
255 FILL_STUB(Deinitialize); 255 FILL_STUB(Deinitialize);
256 #undef FILL_STUB 256 #undef FILL_STUB
257 } 257 }
258 258
259 /* Streaming functions (for when the input and output buffer sizes are different) */
260 /* Write [length] bytes from buf into the streamer */
261 void
262 SDL_StreamWrite(SDL_AudioStreamer * stream, Uint8 * buf, int length)
263 {
264 int i;
265
266 for (i = 0; i < length; ++i) {
267 stream->buffer[stream->write_pos] = buf[i];
268 ++stream->write_pos;
269 }
270 }
271
272 /* Read [length] bytes out of the streamer into buf */
273 void
274 SDL_StreamRead(SDL_AudioStreamer * stream, Uint8 * buf, int length)
275 {
276 int i;
277
278 for (i = 0; i < length; ++i) {
279 buf[i] = stream->buffer[stream->read_pos];
280 ++stream->read_pos;
281 }
282 }
283
284 int
285 SDL_StreamLength(SDL_AudioStreamer * stream)
286 {
287 return (stream->write_pos - stream->read_pos) % stream->max_len;
288 }
289
290 /* Initialize the stream by allocating the buffer and setting the read/write heads to the beginning */
291 int
292 SDL_StreamInit(SDL_AudioStreamer * stream, int max_len, Uint8 silence)
293 {
294 int i;
295
296 /* First try to allocate the buffer */
297 stream->buffer = (Uint8 *) malloc(max_len);
298 if (stream->buffer == NULL) {
299 return -1;
300 }
301
302 stream->max_len = max_len;
303 stream->read_pos = 0;
304 stream->write_pos = 0;
305
306 /* Zero out the buffer */
307 for (i = 0; i < max_len; ++i) {
308 stream->buffer[i] = silence;
309 }
310 }
311
312 /* Deinitialize the stream simply by freeing the buffer */
313 void
314 SDL_StreamDeinit(SDL_AudioStreamer * stream)
315 {
316 if (stream->buffer != NULL) {
317 free(stream->buffer);
318 }
319 }
320
259 321
260 /* The general mixing thread function */ 322 /* The general mixing thread function */
261 int SDLCALL 323 int SDLCALL
262 SDL_RunAudio(void *devicep) 324 SDL_RunAudio(void *devicep)
263 { 325 {
265 Uint8 *stream; 327 Uint8 *stream;
266 int stream_len; 328 int stream_len;
267 void *udata; 329 void *udata;
268 void (SDLCALL * fill) (void *userdata, Uint8 * stream, int len); 330 void (SDLCALL * fill) (void *userdata, Uint8 * stream, int len);
269 int silence; 331 int silence;
332 int stream_max_len;
333
334 /* For streaming when the buffer sizes don't match up */
335 Uint8 *istream;
336 int istream_len;
270 337
271 /* Perform any thread setup */ 338 /* Perform any thread setup */
272 device->threadid = SDL_ThreadID(); 339 device->threadid = SDL_ThreadID();
273 current_audio.impl.ThreadInit(device); 340 current_audio.impl.ThreadInit(device);
274 341
275 /* Set up the mixing function */ 342 /* Set up the mixing function */
276 fill = device->spec.callback; 343 fill = device->spec.callback;
277 udata = device->spec.userdata; 344 udata = device->spec.userdata;
345
346 /* By default do not stream */
347 device->use_streamer = 0;
278 348
279 if (device->convert.needed) { 349 if (device->convert.needed) {
280 if (device->convert.src_format == AUDIO_U8) { 350 if (device->convert.src_format == AUDIO_U8) {
281 silence = 0x80; 351 silence = 0x80;
282 } else { 352 } else {
283 silence = 0; 353 silence = 0;
284 } 354 }
285 stream_len = device->convert.len; 355
356 /* If the result of the conversion alters the length, i.e. resampling is being used, use the streamer */
357 if (device->convert.len_mult != 1 || device->convert.len_div != 1) {
358 /* The streamer's maximum length should be twice whichever is larger: spec.size or len_cvt */
359 stream_max_len = 2 * device->spec.size;
360 if (device->convert.len_mult > device->convert.len_div) {
361 stream_max_len *= device->convert.len_mult;
362 stream_max_len /= device->convert.len_div;
363 }
364 if (SDL_StreamInit(&device->streamer, stream_max_len, silence) <
365 0)
366 return -1;
367 device->use_streamer = 1;
368
369 /* istream_len should be the length of what we grab from the callback and feed to conversion,
370 so that we get close to spec_size. I.e. we want device.spec_size = istream_len * u / d
371 */
372 istream_len =
373 device->spec.size * device->convert.len_div /
374 device->convert.len_mult;
375 }
376
377 /* stream_len = device->convert.len; */
378 stream_len = device->spec.size;
286 } else { 379 } else {
287 silence = device->spec.silence; 380 silence = device->spec.silence;
288 stream_len = device->spec.size; 381 stream_len = device->spec.size;
289 } 382 }
290 383
291 /* Loop, filling the audio buffers */ 384 /* Determine if the streamer is necessary here */
292 while (device->enabled) { 385 if (device->use_streamer == 1) {
293 386 /* This code is almost the same as the old code. The difference is, instead of reding
294 /* Fill the current buffer with sound */ 387 directly from the callback into "stream", then converting and sending the audio off,
295 if (device->convert.needed) { 388 we go: callback -> "istream" -> (conversion) -> streamer -> stream -> device.
296 if (device->convert.buf) { 389 However, reading and writing with streamer are done separately:
297 stream = device->convert.buf; 390 - We only call the callback and write to the streamer when the streamer does not
391 contain enough samples to output to the device.
392 - We only read from the streamer and tell the device to play when the streamer
393 does have enough samples to output.
394 This allows us to perform resampling in the conversion step, where the output of the
395 resampling process can be any number. We will have to see what a good size for the
396 stream's maximum length is, but I suspect 2*max(len_cvt, stream_len) is a good figure.
397 */
398 while (device->enabled) {
399 /* Only read in audio if the streamer doesn't have enough already (if it does not have enough samples to output) */
400 if (SDL_StreamLength(&device->streamer) < stream_len) {
401 /* Set up istream */
402 if (device->convert.needed) {
403 if (device->convert.buf) {
404 istream = device->convert.buf;
405 } else {
406 continue;
407 }
408 } else {
409 istream = current_audio.impl.GetDeviceBuf(device);
410 if (istream == NULL) {
411 istream = device->fake_stream;
412 }
413 }
414
415 /* Read from the callback into the _input_ stream */
416 if (!device->paused) {
417 SDL_mutexP(device->mixer_lock);
418 (*fill) (udata, istream, istream_len);
419 SDL_mutexV(device->mixer_lock);
420 }
421
422 /* Convert the audio if necessary and write to the streamer */
423 if (device->convert.needed) {
424 SDL_ConvertAudio(&device->convert);
425 if (istream == NULL) {
426 istream = device->fake_stream;
427 }
428 /*SDL_memcpy(istream, device->convert.buf, device->convert.len_cvt); */
429 SDL_StreamWrite(&device->streamer, device->convert.buf,
430 device->convert.len_cvt);
431 } else {
432 SDL_StreamWrite(&device->streamer, istream, istream_len);
433 }
434 }
435
436 /* Only output audio if the streamer has enough to output */
437 if (SDL_StreamLength(&device->streamer) >= stream_len) {
438 /* Set up the output stream */
439 if (device->convert.needed) {
440 if (device->convert.buf) {
441 stream = device->convert.buf;
442 } else {
443 continue;
444 }
445 } else {
446 stream = current_audio.impl.GetDeviceBuf(device);
447 if (stream == NULL) {
448 stream = device->fake_stream;
449 }
450 }
451
452 /* Now read from the streamer */
453 SDL_StreamRead(&device->streamer, stream, stream_len);
454
455 /* Ready current buffer for play and change current buffer */
456 if (stream != device->fake_stream) {
457 current_audio.impl.PlayDevice(device);
458 }
459
460 /* Wait for an audio buffer to become available */
461 if (stream == device->fake_stream) {
462 SDL_Delay((device->spec.samples * 1000) /
463 device->spec.freq);
464 } else {
465 current_audio.impl.WaitDevice(device);
466 }
467 }
468
469 }
470 } else {
471 /* Otherwise, do not use the streamer. This is the old code. */
472
473 /* Loop, filling the audio buffers */
474 while (device->enabled) {
475
476 /* Fill the current buffer with sound */
477 if (device->convert.needed) {
478 if (device->convert.buf) {
479 stream = device->convert.buf;
480 } else {
481 continue;
482 }
298 } else { 483 } else {
299 continue; 484 stream = current_audio.impl.GetDeviceBuf(device);
300 } 485 if (stream == NULL) {
301 } else { 486 stream = device->fake_stream;
302 stream = current_audio.impl.GetDeviceBuf(device); 487 }
303 if (stream == NULL) { 488 }
304 stream = device->fake_stream; 489
305 } 490 if (!device->paused) {
306 } 491 SDL_mutexP(device->mixer_lock);
307 492 (*fill) (udata, stream, stream_len);
308 if (!device->paused) { 493 SDL_mutexV(device->mixer_lock);
309 SDL_mutexP(device->mixer_lock); 494 }
310 (*fill) (udata, stream, stream_len); 495
311 SDL_mutexV(device->mixer_lock); 496 /* Convert the audio if necessary */
312 } 497 if (device->convert.needed) {
313 498 SDL_ConvertAudio(&device->convert);
314 /* Convert the audio if necessary */ 499 stream = current_audio.impl.GetDeviceBuf(device);
315 if (device->convert.needed) { 500 if (stream == NULL) {
316 SDL_ConvertAudio(&device->convert); 501 stream = device->fake_stream;
317 stream = current_audio.impl.GetDeviceBuf(device); 502 }
318 if (stream == NULL) { 503 SDL_memcpy(stream, device->convert.buf,
319 stream = device->fake_stream; 504 device->convert.len_cvt);
320 } 505 }
321 SDL_memcpy(stream, device->convert.buf, device->convert.len_cvt); 506
322 } 507 /* Ready current buffer for play and change current buffer */
323 508 if (stream != device->fake_stream) {
324 /* Ready current buffer for play and change current buffer */ 509 current_audio.impl.PlayDevice(device);
325 if (stream != device->fake_stream) { 510 }
326 current_audio.impl.PlayDevice(device); 511
327 } 512 /* Wait for an audio buffer to become available */
328 513 if (stream == device->fake_stream) {
329 /* Wait for an audio buffer to become available */ 514 SDL_Delay((device->spec.samples * 1000) / device->spec.freq);
330 if (stream == device->fake_stream) { 515 } else {
331 SDL_Delay((device->spec.samples * 1000) / device->spec.freq); 516 current_audio.impl.WaitDevice(device);
332 } else { 517 }
333 current_audio.impl.WaitDevice(device);
334 } 518 }
335 } 519 }
336 520
337 /* Wait for the audio to drain.. */ 521 /* Wait for the audio to drain.. */
338 current_audio.impl.WaitDone(device); 522 current_audio.impl.WaitDone(device);
523
524 /* If necessary, deinit the streamer */
525 if (device->use_streamer == 1)
526 SDL_StreamDeinit(&device->streamer);
339 527
340 return (0); 528 return (0);
341 } 529 }
342 530
343 531