First shot at new audio data types (int32 and float32).
Notable changes:
- Converters between types are autogenerated. Instead of making multiple
passes over the data with seperate filters for endianess, size, signedness,
etc, converting between data types is always one specialized filter. This
simplifies SDL_BuildAudioCVT(), which otherwise had a million edge cases
with the new types, and makes the actually conversions more CPU cache
friendly. Left a stub for adding specific optimized versions of these
routines (SSE/MMX/Altivec, assembler, etc)
- Autogenerated converters are built by SDL/src/audio/sdlgenaudiocvt.pl. This
does not need to be run unless tweaking the code, and thus doesn't need
integration into the build system.
- Went through all the drivers and tried to weed out all the "Uint16"
references that are better specified with the new SDL_AudioFormat typedef.
- Cleaned out a bunch of hardcoded bitwise magic numbers and replaced them
with new SDL_AUDIO_* macros.
- Added initial float32 and int32 support code. Theoretically, existing
drivers will push these through converters to get the data they want to
feed to the hardware.
Still TODO:
- Optimize and debug new converters.
- Update the CoreAudio backend to accept float32 data directly.
- Other backends, too?
- SDL_LoadWAV() needs to be updated to support int32 and float32 .wav files
(both of which exist and can be generated by 'sox' for testing purposes).
- Update the mixer to handle new datatypes.
- Optionally update SDL_sound and SDL_mixer, etc.
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2006 Sam Lantinga
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 This driver was written by:
26 #include "SDL_config.h"
28 /* Allow access to a raw mixing buffer */
33 #include "SDL_timer.h"
34 #include "SDL_audio.h"
35 #include "../SDL_audiomem.h"
36 #include "../SDL_audio_c.h"
37 #include "../SDL_audiodev_c.h"
38 #include "SDL_nasaudio.h"
40 /* The tag name used by artsc audio */
41 #define NAS_DRIVER_NAME "nas"
43 static struct SDL_PrivateAudioData *this2 = NULL;
45 /* Audio driver functions */
46 static int NAS_OpenAudio(_THIS, SDL_AudioSpec * spec);
47 static void NAS_WaitAudio(_THIS);
48 static void NAS_PlayAudio(_THIS);
49 static Uint8 *NAS_GetAudioBuf(_THIS);
50 static void NAS_CloseAudio(_THIS);
52 /* Audio driver bootstrap functions */
57 AuServer *aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
66 Audio_DeleteDevice(SDL_AudioDevice * device)
68 SDL_free(device->hidden);
72 static SDL_AudioDevice *
73 Audio_CreateDevice(int devindex)
75 SDL_AudioDevice *this;
77 /* Initialize all variables that we clean on shutdown */
78 this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
80 SDL_memset(this, 0, (sizeof *this));
81 this->hidden = (struct SDL_PrivateAudioData *)
82 SDL_malloc((sizeof *this->hidden));
84 if ((this == NULL) || (this->hidden == NULL)) {
91 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
93 /* Set the function pointers */
94 this->OpenAudio = NAS_OpenAudio;
95 this->WaitAudio = NAS_WaitAudio;
96 this->PlayAudio = NAS_PlayAudio;
97 this->GetAudioBuf = NAS_GetAudioBuf;
98 this->CloseAudio = NAS_CloseAudio;
100 this->free = Audio_DeleteDevice;
105 AudioBootStrap NAS_bootstrap = {
106 NAS_DRIVER_NAME, "Network Audio System",
107 Audio_Available, Audio_CreateDevice
110 /* This function waits until it is possible to write a full sound buffer */
114 while (this->hidden->buf_free < this->hidden->mixlen) {
116 AuNextEvent(this->hidden->aud, AuTrue, &ev);
117 AuDispatchEvent(this->hidden->aud, &ev);
124 while (this->hidden->mixlen > this->hidden->buf_free) { /* We think the buffer is full? Yikes! Ask the server for events,
125 in the hope that some of them is LowWater events telling us more
126 of the buffer is free now than what we think. */
128 AuNextEvent(this->hidden->aud, AuTrue, &ev);
129 AuDispatchEvent(this->hidden->aud, &ev);
131 this->hidden->buf_free -= this->hidden->mixlen;
133 /* Write the audio data */
134 AuWriteElement(this->hidden->aud, this->hidden->flow, 0,
135 this->hidden->mixlen, this->hidden->mixbuf, AuFalse, NULL);
137 this->hidden->written += this->hidden->mixlen;
140 fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen);
145 NAS_GetAudioBuf(_THIS)
147 return (this->hidden->mixbuf);
151 NAS_CloseAudio(_THIS)
153 if (this->hidden->mixbuf != NULL) {
154 SDL_FreeAudioMem(this->hidden->mixbuf);
155 this->hidden->mixbuf = NULL;
157 if (this->hidden->aud) {
158 AuCloseServer(this->hidden->aud);
159 this->hidden->aud = 0;
164 sdlformat_to_auformat(unsigned int fmt)
168 return AuFormatLinearUnsigned8;
170 return AuFormatLinearSigned8;
172 return AuFormatLinearUnsigned16LSB;
174 return AuFormatLinearUnsigned16MSB;
176 return AuFormatLinearSigned16LSB;
178 return AuFormatLinearSigned16MSB;
184 event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd)
187 case AuEventTypeElementNotify:
189 AuElementNotifyEvent *event = (AuElementNotifyEvent *) ev;
191 switch (event->kind) {
192 case AuElementNotifyKindLowWater:
193 if (this2->buf_free >= 0) {
194 this2->really += event->num_bytes;
195 gettimeofday(&this2->last_tv, 0);
196 this2->buf_free += event->num_bytes;
198 this2->buf_free = event->num_bytes;
201 case AuElementNotifyKindState:
202 switch (event->cur_state) {
204 if (event->reason != AuReasonUser) {
205 if (this2->buf_free >= 0) {
206 this2->really += event->num_bytes;
207 gettimeofday(&this2->last_tv, 0);
208 this2->buf_free += event->num_bytes;
210 this2->buf_free = event->num_bytes;
222 find_device(_THIS, int nch)
225 for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) {
226 if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) ==
227 AuComponentKindPhysicalOutput) &&
228 AuDeviceNumTracks(AuServerDevice(this->hidden->aud, i)) == nch) {
229 return AuDeviceIdentifier(AuServerDevice(this->hidden->aud, i));
236 NAS_OpenAudio(_THIS, SDL_AudioSpec * spec)
240 SDL_AudioFormat test_format, format;
242 this->hidden->mixbuf = NULL;
244 /* Try for a closest match on audio format */
246 for (test_format = SDL_FirstAudioFormat(spec->format);
247 !format && test_format;) {
248 format = sdlformat_to_auformat(test_format);
250 if (format == AuNone) {
251 test_format = SDL_NextAudioFormat();
255 SDL_SetError("Couldn't find any hardware audio formats");
258 spec->format = test_format;
260 this->hidden->aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
261 if (this->hidden->aud == 0) {
262 SDL_SetError("Couldn't open connection to NAS server");
266 this->hidden->dev = find_device(this, spec->channels);
267 if ((this->hidden->dev == AuNone)
268 || (!(this->hidden->flow = AuCreateFlow(this->hidden->aud, NULL)))) {
269 AuCloseServer(this->hidden->aud);
270 this->hidden->aud = 0;
271 SDL_SetError("Couldn't find a fitting playback device on NAS server");
275 buffer_size = spec->freq;
276 if (buffer_size < 4096)
279 if (buffer_size > 32768)
280 buffer_size = 32768; /* So that the buffer won't get unmanageably big. */
282 /* Calculate the final parameters for this audio specification */
283 SDL_CalculateAudioSpec(spec);
285 this2 = this->hidden;
287 AuMakeElementImportClient(elms, spec->freq, format, spec->channels,
288 AuTrue, buffer_size, buffer_size / 4, 0, NULL);
289 AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, spec->freq,
290 AuUnlimitedSamples, 0, NULL);
291 AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms,
293 AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0,
294 this->hidden->flow, event_handler,
297 AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
299 /* Allocate mixing buffer */
300 this->hidden->mixlen = spec->size;
301 this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
302 if (this->hidden->mixbuf == NULL) {
305 SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
307 /* Get the parent process id (we're the parent of the audio thread) */
308 this->hidden->parent = getpid();
310 /* We're ready to rock and roll. :-) */
314 /* vi: set ts=4 sw=4 expandtab: */