diff src/audio/SDL_audio.c @ 2666:e12ccc6c9576 gsoc2008_audio_resampling

Implemented streamer code in SDL_RunAudio() but have not tested it.
author Aaron Wishnick <schnarf@gmail.com>
date Wed, 13 Aug 2008 02:50:10 +0000
parents f39a056aec8b
children 4174e511655f
line wrap: on
line diff
--- a/src/audio/SDL_audio.c	Tue Aug 12 01:03:05 2008 +0000
+++ b/src/audio/SDL_audio.c	Wed Aug 13 02:50:10 2008 +0000
@@ -319,6 +319,10 @@
     void *udata;
     void (SDLCALL * fill) (void *userdata, Uint8 * stream, int len);
     int silence;
+	
+	/* For streaming when the buffer sizes don't match up */
+	Uint8 *istream;
+	int istream_len;
 
     /* Perform any thread setup */
     device->threadid = SDL_ThreadID();
@@ -341,52 +345,125 @@
     }
 	
 	/* Determine if the streamer is necessary here */
-
-    /* Loop, filling the audio buffers */
-    while (device->enabled) {
-
-        /* Fill the current buffer with sound */
-        if (device->convert.needed) {
-            if (device->convert.buf) {
-                stream = device->convert.buf;
-            } else {
-                continue;
-            }
-        } else {
-            stream = current_audio.impl.GetDeviceBuf(device);
-            if (stream == NULL) {
-                stream = device->fake_stream;
-            }
-        }
+	if(device->use_streamer) {
+		/* This code is almost the same as the old code. The difference is, instead of reding
+		   directly from the callback into "stream", then converting and sending the audio off,
+		   we go: callback -> "istream" -> (conversion) -> streamer -> stream -> device.
+		   However, reading and writing with streamer are done separately:
+		      - We only call the callback and write to the streamer when the streamer does not
+			    contain enough samples to output to the device.
+			  - We only read from the streamer and tell the device to play when the streamer
+			    does have enough samples to output.
+		   This allows us to perform resampling in the conversion step, where the output of the
+		   resampling process can be any number. We will have to see what a good size for the
+		   stream's maximum length is, but I suspect 2*max(len_cvt, stream_len) is a good figure.
+		*/
+		while (device->enabled) {
+			/* Only read in audio if the streamer doesn't have enough already (if it does not have enough samples to output) */
+			if(SDL_StreamLength(&device->streamer) < stream_len) {
+				/* Read from the callback into the _input_ stream */
+				if (!device->paused) {
+					SDL_mutexP(device->mixer_lock);
+					(*fill) (udata, istream, istream_len);
+					SDL_mutexV(device->mixer_lock);
+				}
+			
+				 /* Convert the audio if necessary and write to the streamer */
+				if (device->convert.needed) {
+					SDL_ConvertAudio(&device->convert);
+					istream = current_audio.impl.GetDeviceBuf(device);
+					if (istream == NULL) {
+						istream = device->fake_stream;
+					}
+					SDL_memcpy(istream, device->convert.buf, device->convert.len_cvt);
+					SDL_StreamWrite(&device->streamer, istream, device->convert.len_cvt);
+				} else {
+					SDL_StreamWrite(&device->streamer, istream, istream_len);
+				}
+			}
+		
+			/* Only output audio if the streamer has enough to output */
+			if(SDL_StreamLength(&device->streamer) >= stream_len) {
+				/* Set up the output stream */
+				if (device->convert.needed) {
+					if (device->convert.buf) {
+						stream = device->convert.buf;
+					} else {
+						continue;
+					}
+				} else {
+					stream = current_audio.impl.GetDeviceBuf(device);
+					if (stream == NULL) {
+						stream = device->fake_stream;
+					}
+				}
+				
+				/* Now read from the streamer */
+				SDL_StreamRead(&device->streamer, stream, stream_len);
+				
+				 /* Ready current buffer for play and change current buffer */
+				if (stream != device->fake_stream) {
+					current_audio.impl.PlayDevice(device);
+				}
 
-        if (!device->paused) {
-            SDL_mutexP(device->mixer_lock);
-            (*fill) (udata, stream, stream_len);
-            SDL_mutexV(device->mixer_lock);
-        }
+				/* Wait for an audio buffer to become available */
+				if (stream == device->fake_stream) {
+					SDL_Delay((device->spec.samples * 1000) / device->spec.freq);
+				} else {
+					current_audio.impl.WaitDevice(device);
+				}
+			}		
+			
+		}
+	} else {
+	/* Otherwise, do not use the streamer. This is the old code. */
+    
+		/* Loop, filling the audio buffers */
+		while (device->enabled) {
+
+			/* Fill the current buffer with sound */
+			if (device->convert.needed) {
+				if (device->convert.buf) {
+					stream = device->convert.buf;
+				} else {
+					continue;
+				}
+			} else {
+				stream = current_audio.impl.GetDeviceBuf(device);
+				if (stream == NULL) {
+					stream = device->fake_stream;
+				}
+			}
 
-        /* Convert the audio if necessary */
-        if (device->convert.needed) {
-            SDL_ConvertAudio(&device->convert);
-            stream = current_audio.impl.GetDeviceBuf(device);
-            if (stream == NULL) {
-                stream = device->fake_stream;
-            }
-            SDL_memcpy(stream, device->convert.buf, device->convert.len_cvt);
-        }
+			if (!device->paused) {
+				SDL_mutexP(device->mixer_lock);
+				(*fill) (udata, stream, stream_len);
+				SDL_mutexV(device->mixer_lock);
+			}
 
-        /* Ready current buffer for play and change current buffer */
-        if (stream != device->fake_stream) {
-            current_audio.impl.PlayDevice(device);
-        }
+			/* Convert the audio if necessary */
+			if (device->convert.needed) {
+				SDL_ConvertAudio(&device->convert);
+				stream = current_audio.impl.GetDeviceBuf(device);
+				if (stream == NULL) {
+					stream = device->fake_stream;
+				}
+				SDL_memcpy(stream, device->convert.buf, device->convert.len_cvt);
+			}
 
-        /* Wait for an audio buffer to become available */
-        if (stream == device->fake_stream) {
-            SDL_Delay((device->spec.samples * 1000) / device->spec.freq);
-        } else {
-            current_audio.impl.WaitDevice(device);
-        }
-    }
+			/* Ready current buffer for play and change current buffer */
+			if (stream != device->fake_stream) {
+				current_audio.impl.PlayDevice(device);
+			}
+
+			/* Wait for an audio buffer to become available */
+			if (stream == device->fake_stream) {
+				SDL_Delay((device->spec.samples * 1000) / device->spec.freq);
+			} else {
+				current_audio.impl.WaitDevice(device);
+			}
+		}
+	}
 
     /* Wait for the audio to drain.. */
     current_audio.impl.WaitDone(device);