Mercurial > sdl-ios-xcode
comparison src/audio/arts/SDL_artsaudio.c @ 1895:c121d94672cb
SDL 1.2 is moving to a branch, and SDL 1.3 is becoming the head.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Mon, 10 Jul 2006 21:04:37 +0000 |
parents | d910939febfa |
children | 3b4ce57c6215 |
comparison
equal
deleted
inserted
replaced
1894:c69cee13dd76 | 1895:c121d94672cb |
---|---|
39 | 39 |
40 /* The tag name used by artsc audio */ | 40 /* The tag name used by artsc audio */ |
41 #define ARTS_DRIVER_NAME "arts" | 41 #define ARTS_DRIVER_NAME "arts" |
42 | 42 |
43 /* Audio driver functions */ | 43 /* Audio driver functions */ |
44 static int ARTS_OpenAudio(_THIS, SDL_AudioSpec *spec); | 44 static int ARTS_OpenAudio(_THIS, SDL_AudioSpec * spec); |
45 static void ARTS_WaitAudio(_THIS); | 45 static void ARTS_WaitAudio(_THIS); |
46 static void ARTS_PlayAudio(_THIS); | 46 static void ARTS_PlayAudio(_THIS); |
47 static Uint8 *ARTS_GetAudioBuf(_THIS); | 47 static Uint8 *ARTS_GetAudioBuf(_THIS); |
48 static void ARTS_CloseAudio(_THIS); | 48 static void ARTS_CloseAudio(_THIS); |
49 | 49 |
51 | 51 |
52 static const char *arts_library = SDL_AUDIO_DRIVER_ARTS_DYNAMIC; | 52 static const char *arts_library = SDL_AUDIO_DRIVER_ARTS_DYNAMIC; |
53 static void *arts_handle = NULL; | 53 static void *arts_handle = NULL; |
54 static int arts_loaded = 0; | 54 static int arts_loaded = 0; |
55 | 55 |
56 static int (*SDL_NAME(arts_init))(void); | 56 static int (*SDL_NAME(arts_init)) (void); |
57 static void (*SDL_NAME(arts_free))(void); | 57 static void (*SDL_NAME(arts_free)) (void); |
58 static arts_stream_t (*SDL_NAME(arts_play_stream))(int rate, int bits, int channels, const char *name); | 58 static arts_stream_t(*SDL_NAME(arts_play_stream)) (int rate, int bits, |
59 static int (*SDL_NAME(arts_stream_set))(arts_stream_t s, arts_parameter_t param, int value); | 59 int channels, |
60 static int (*SDL_NAME(arts_stream_get))(arts_stream_t s, arts_parameter_t param); | 60 const char *name); |
61 static int (*SDL_NAME(arts_write))(arts_stream_t s, const void *buffer, int count); | 61 static int (*SDL_NAME(arts_stream_set)) (arts_stream_t s, |
62 static void (*SDL_NAME(arts_close_stream))(arts_stream_t s); | 62 arts_parameter_t param, int value); |
63 | 63 static int (*SDL_NAME(arts_stream_get)) (arts_stream_t s, |
64 static struct { | 64 arts_parameter_t param); |
65 const char *name; | 65 static int (*SDL_NAME(arts_write)) (arts_stream_t s, const void *buffer, |
66 void **func; | 66 int count); |
67 static void (*SDL_NAME(arts_close_stream)) (arts_stream_t s); | |
68 | |
69 static struct | |
70 { | |
71 const char *name; | |
72 void **func; | |
67 } arts_functions[] = { | 73 } arts_functions[] = { |
68 { "arts_init", (void **)&SDL_NAME(arts_init) }, | 74 { |
69 { "arts_free", (void **)&SDL_NAME(arts_free) }, | 75 "arts_init", (void **) &SDL_NAME(arts_init)}, { |
70 { "arts_play_stream", (void **)&SDL_NAME(arts_play_stream) }, | 76 "arts_free", (void **) &SDL_NAME(arts_free)}, { |
71 { "arts_stream_set", (void **)&SDL_NAME(arts_stream_set) }, | 77 "arts_play_stream", (void **) &SDL_NAME(arts_play_stream)}, { |
72 { "arts_stream_get", (void **)&SDL_NAME(arts_stream_get) }, | 78 "arts_stream_set", (void **) &SDL_NAME(arts_stream_set)}, { |
73 { "arts_write", (void **)&SDL_NAME(arts_write) }, | 79 "arts_stream_get", (void **) &SDL_NAME(arts_stream_get)}, { |
74 { "arts_close_stream", (void **)&SDL_NAME(arts_close_stream) }, | 80 "arts_write", (void **) &SDL_NAME(arts_write)}, { |
81 "arts_close_stream", (void **) &SDL_NAME(arts_close_stream)},}; | |
82 | |
83 static void | |
84 UnloadARTSLibrary() | |
85 { | |
86 if (arts_loaded) { | |
87 SDL_UnloadObject(arts_handle); | |
88 arts_handle = NULL; | |
89 arts_loaded = 0; | |
90 } | |
91 } | |
92 | |
93 static int | |
94 LoadARTSLibrary(void) | |
95 { | |
96 int i, retval = -1; | |
97 | |
98 arts_handle = SDL_LoadObject(arts_library); | |
99 if (arts_handle) { | |
100 arts_loaded = 1; | |
101 retval = 0; | |
102 for (i = 0; i < SDL_arraysize(arts_functions); ++i) { | |
103 *arts_functions[i].func = | |
104 SDL_LoadFunction(arts_handle, arts_functions[i].name); | |
105 if (!*arts_functions[i].func) { | |
106 retval = -1; | |
107 UnloadARTSLibrary(); | |
108 break; | |
109 } | |
110 } | |
111 } | |
112 return retval; | |
113 } | |
114 | |
115 #else | |
116 | |
117 static void | |
118 UnloadARTSLibrary() | |
119 { | |
120 return; | |
121 } | |
122 | |
123 static int | |
124 LoadARTSLibrary(void) | |
125 { | |
126 return 0; | |
127 } | |
128 | |
129 #endif /* SDL_AUDIO_DRIVER_ARTS_DYNAMIC */ | |
130 | |
131 /* Audio driver bootstrap functions */ | |
132 | |
133 static int | |
134 Audio_Available(void) | |
135 { | |
136 int available = 0; | |
137 | |
138 if (LoadARTSLibrary() < 0) { | |
139 return available; | |
140 } | |
141 if (SDL_NAME(arts_init) () == 0) { | |
142 #define ARTS_CRASH_HACK /* Play a stream so aRts doesn't crash */ | |
143 #ifdef ARTS_CRASH_HACK | |
144 arts_stream_t stream2; | |
145 stream2 = SDL_NAME(arts_play_stream) (44100, 16, 2, "SDL"); | |
146 SDL_NAME(arts_write) (stream2, "", 0); | |
147 SDL_NAME(arts_close_stream) (stream2); | |
148 #endif | |
149 available = 1; | |
150 SDL_NAME(arts_free) (); | |
151 } | |
152 UnloadARTSLibrary(); | |
153 | |
154 return available; | |
155 } | |
156 | |
157 static void | |
158 Audio_DeleteDevice(SDL_AudioDevice * device) | |
159 { | |
160 SDL_free(device->hidden); | |
161 SDL_free(device); | |
162 UnloadARTSLibrary(); | |
163 } | |
164 | |
165 static SDL_AudioDevice * | |
166 Audio_CreateDevice(int devindex) | |
167 { | |
168 SDL_AudioDevice *this; | |
169 | |
170 /* Initialize all variables that we clean on shutdown */ | |
171 LoadARTSLibrary(); | |
172 this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice)); | |
173 if (this) { | |
174 SDL_memset(this, 0, (sizeof *this)); | |
175 this->hidden = (struct SDL_PrivateAudioData *) | |
176 SDL_malloc((sizeof *this->hidden)); | |
177 } | |
178 if ((this == NULL) || (this->hidden == NULL)) { | |
179 SDL_OutOfMemory(); | |
180 if (this) { | |
181 SDL_free(this); | |
182 } | |
183 return (0); | |
184 } | |
185 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); | |
186 stream = 0; | |
187 | |
188 /* Set the function pointers */ | |
189 this->OpenAudio = ARTS_OpenAudio; | |
190 this->WaitAudio = ARTS_WaitAudio; | |
191 this->PlayAudio = ARTS_PlayAudio; | |
192 this->GetAudioBuf = ARTS_GetAudioBuf; | |
193 this->CloseAudio = ARTS_CloseAudio; | |
194 | |
195 this->free = Audio_DeleteDevice; | |
196 | |
197 return this; | |
198 } | |
199 | |
200 AudioBootStrap ARTS_bootstrap = { | |
201 ARTS_DRIVER_NAME, "Analog Realtime Synthesizer", | |
202 Audio_Available, Audio_CreateDevice | |
75 }; | 203 }; |
76 | 204 |
77 static void UnloadARTSLibrary() | 205 /* This function waits until it is possible to write a full sound buffer */ |
78 { | 206 static void |
79 if ( arts_loaded ) { | 207 ARTS_WaitAudio(_THIS) |
80 SDL_UnloadObject(arts_handle); | 208 { |
81 arts_handle = NULL; | 209 Sint32 ticks; |
82 arts_loaded = 0; | 210 |
83 } | 211 /* Check to see if the thread-parent process is still alive */ |
84 } | 212 { |
85 | 213 static int cnt = 0; |
86 static int LoadARTSLibrary(void) | 214 /* Note that this only works with thread implementations |
87 { | 215 that use a different process id for each thread. |
88 int i, retval = -1; | 216 */ |
89 | 217 if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */ |
90 arts_handle = SDL_LoadObject(arts_library); | 218 if (kill(parent, 0) < 0) { |
91 if ( arts_handle ) { | 219 this->enabled = 0; |
92 arts_loaded = 1; | 220 } |
93 retval = 0; | 221 } |
94 for ( i=0; i<SDL_arraysize(arts_functions); ++i ) { | 222 } |
95 *arts_functions[i].func = SDL_LoadFunction(arts_handle, arts_functions[i].name); | 223 |
96 if ( !*arts_functions[i].func ) { | 224 /* Use timer for general audio synchronization */ |
97 retval = -1; | 225 ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS; |
98 UnloadARTSLibrary(); | 226 if (ticks > 0) { |
99 break; | 227 SDL_Delay(ticks); |
100 } | 228 } |
101 } | 229 } |
102 } | 230 |
103 return retval; | 231 static void |
104 } | 232 ARTS_PlayAudio(_THIS) |
105 | 233 { |
234 int written; | |
235 | |
236 /* Write the audio data */ | |
237 written = SDL_NAME(arts_write) (stream, mixbuf, mixlen); | |
238 | |
239 /* If timer synchronization is enabled, set the next write frame */ | |
240 if (frame_ticks) { | |
241 next_frame += frame_ticks; | |
242 } | |
243 | |
244 /* If we couldn't write, assume fatal error for now */ | |
245 if (written < 0) { | |
246 this->enabled = 0; | |
247 } | |
248 #ifdef DEBUG_AUDIO | |
249 fprintf(stderr, "Wrote %d bytes of audio data\n", written); | |
250 #endif | |
251 } | |
252 | |
253 static Uint8 * | |
254 ARTS_GetAudioBuf(_THIS) | |
255 { | |
256 return (mixbuf); | |
257 } | |
258 | |
259 static void | |
260 ARTS_CloseAudio(_THIS) | |
261 { | |
262 if (mixbuf != NULL) { | |
263 SDL_FreeAudioMem(mixbuf); | |
264 mixbuf = NULL; | |
265 } | |
266 if (stream) { | |
267 SDL_NAME(arts_close_stream) (stream); | |
268 stream = 0; | |
269 } | |
270 SDL_NAME(arts_free) (); | |
271 } | |
272 | |
273 static int | |
274 ARTS_OpenAudio(_THIS, SDL_AudioSpec * spec) | |
275 { | |
276 int bits, frag_spec; | |
277 Uint16 test_format, format; | |
278 | |
279 /* Reset the timer synchronization flag */ | |
280 frame_ticks = 0.0; | |
281 | |
282 mixbuf = NULL; | |
283 | |
284 /* Try for a closest match on audio format */ | |
285 format = 0; | |
286 bits = 0; | |
287 for (test_format = SDL_FirstAudioFormat(spec->format); | |
288 !format && test_format;) { | |
289 #ifdef DEBUG_AUDIO | |
290 fprintf(stderr, "Trying format 0x%4.4x\n", test_format); | |
291 #endif | |
292 switch (test_format) { | |
293 case AUDIO_U8: | |
294 bits = 8; | |
295 format = 1; | |
296 break; | |
297 case AUDIO_S16LSB: | |
298 bits = 16; | |
299 format = 1; | |
300 break; | |
301 default: | |
302 format = 0; | |
303 break; | |
304 } | |
305 if (!format) { | |
306 test_format = SDL_NextAudioFormat(); | |
307 } | |
308 } | |
309 if (format == 0) { | |
310 SDL_SetError("Couldn't find any hardware audio formats"); | |
311 return (-1); | |
312 } | |
313 spec->format = test_format; | |
314 | |
315 if (SDL_NAME(arts_init) () != 0) { | |
316 SDL_SetError("Unable to initialize ARTS"); | |
317 return (-1); | |
318 } | |
319 stream = | |
320 SDL_NAME(arts_play_stream) (spec->freq, bits, spec->channels, "SDL"); | |
321 | |
322 /* Calculate the final parameters for this audio specification */ | |
323 SDL_CalculateAudioSpec(spec); | |
324 | |
325 /* Determine the power of two of the fragment size */ | |
326 for (frag_spec = 0; (0x01 << frag_spec) < spec->size; ++frag_spec); | |
327 if ((0x01 << frag_spec) != spec->size) { | |
328 SDL_SetError("Fragment size must be a power of two"); | |
329 return (-1); | |
330 } | |
331 frag_spec |= 0x00020000; /* two fragments, for low latency */ | |
332 | |
333 #ifdef ARTS_P_PACKET_SETTINGS | |
334 SDL_NAME(arts_stream_set) (stream, ARTS_P_PACKET_SETTINGS, frag_spec); | |
106 #else | 335 #else |
107 | 336 SDL_NAME(arts_stream_set) (stream, ARTS_P_PACKET_SIZE, |
108 static void UnloadARTSLibrary() | 337 frag_spec & 0xffff); |
109 { | 338 SDL_NAME(arts_stream_set) (stream, ARTS_P_PACKET_COUNT, frag_spec >> 16); |
110 return; | 339 #endif |
111 } | 340 spec->size = SDL_NAME(arts_stream_get) (stream, ARTS_P_PACKET_SIZE); |
112 | 341 |
113 static int LoadARTSLibrary(void) | 342 /* Allocate mixing buffer */ |
114 { | 343 mixlen = spec->size; |
115 return 0; | 344 mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen); |
116 } | 345 if (mixbuf == NULL) { |
117 | 346 return (-1); |
118 #endif /* SDL_AUDIO_DRIVER_ARTS_DYNAMIC */ | 347 } |
119 | 348 SDL_memset(mixbuf, spec->silence, spec->size); |
120 /* Audio driver bootstrap functions */ | 349 |
121 | 350 /* Get the parent process id (we're the parent of the audio thread) */ |
122 static int Audio_Available(void) | 351 parent = getpid(); |
123 { | 352 |
124 int available = 0; | 353 /* We're ready to rock and roll. :-) */ |
125 | 354 return (0); |
126 if ( LoadARTSLibrary() < 0 ) { | 355 } |
127 return available; | 356 |
128 } | 357 /* vi: set ts=4 sw=4 expandtab: */ |
129 if ( SDL_NAME(arts_init)() == 0 ) { | |
130 #define ARTS_CRASH_HACK /* Play a stream so aRts doesn't crash */ | |
131 #ifdef ARTS_CRASH_HACK | |
132 arts_stream_t stream2; | |
133 stream2=SDL_NAME(arts_play_stream)(44100, 16, 2, "SDL"); | |
134 SDL_NAME(arts_write)(stream2, "", 0); | |
135 SDL_NAME(arts_close_stream)(stream2); | |
136 #endif | |
137 available = 1; | |
138 SDL_NAME(arts_free)(); | |
139 } | |
140 UnloadARTSLibrary(); | |
141 | |
142 return available; | |
143 } | |
144 | |
145 static void Audio_DeleteDevice(SDL_AudioDevice *device) | |
146 { | |
147 SDL_free(device->hidden); | |
148 SDL_free(device); | |
149 UnloadARTSLibrary(); | |
150 } | |
151 | |
152 static SDL_AudioDevice *Audio_CreateDevice(int devindex) | |
153 { | |
154 SDL_AudioDevice *this; | |
155 | |
156 /* Initialize all variables that we clean on shutdown */ | |
157 LoadARTSLibrary(); | |
158 this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice)); | |
159 if ( this ) { | |
160 SDL_memset(this, 0, (sizeof *this)); | |
161 this->hidden = (struct SDL_PrivateAudioData *) | |
162 SDL_malloc((sizeof *this->hidden)); | |
163 } | |
164 if ( (this == NULL) || (this->hidden == NULL) ) { | |
165 SDL_OutOfMemory(); | |
166 if ( this ) { | |
167 SDL_free(this); | |
168 } | |
169 return(0); | |
170 } | |
171 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); | |
172 stream = 0; | |
173 | |
174 /* Set the function pointers */ | |
175 this->OpenAudio = ARTS_OpenAudio; | |
176 this->WaitAudio = ARTS_WaitAudio; | |
177 this->PlayAudio = ARTS_PlayAudio; | |
178 this->GetAudioBuf = ARTS_GetAudioBuf; | |
179 this->CloseAudio = ARTS_CloseAudio; | |
180 | |
181 this->free = Audio_DeleteDevice; | |
182 | |
183 return this; | |
184 } | |
185 | |
186 AudioBootStrap ARTS_bootstrap = { | |
187 ARTS_DRIVER_NAME, "Analog Realtime Synthesizer", | |
188 Audio_Available, Audio_CreateDevice | |
189 }; | |
190 | |
191 /* This function waits until it is possible to write a full sound buffer */ | |
192 static void ARTS_WaitAudio(_THIS) | |
193 { | |
194 Sint32 ticks; | |
195 | |
196 /* Check to see if the thread-parent process is still alive */ | |
197 { static int cnt = 0; | |
198 /* Note that this only works with thread implementations | |
199 that use a different process id for each thread. | |
200 */ | |
201 if (parent && (((++cnt)%10) == 0)) { /* Check every 10 loops */ | |
202 if ( kill(parent, 0) < 0 ) { | |
203 this->enabled = 0; | |
204 } | |
205 } | |
206 } | |
207 | |
208 /* Use timer for general audio synchronization */ | |
209 ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS; | |
210 if ( ticks > 0 ) { | |
211 SDL_Delay(ticks); | |
212 } | |
213 } | |
214 | |
215 static void ARTS_PlayAudio(_THIS) | |
216 { | |
217 int written; | |
218 | |
219 /* Write the audio data */ | |
220 written = SDL_NAME(arts_write)(stream, mixbuf, mixlen); | |
221 | |
222 /* If timer synchronization is enabled, set the next write frame */ | |
223 if ( frame_ticks ) { | |
224 next_frame += frame_ticks; | |
225 } | |
226 | |
227 /* If we couldn't write, assume fatal error for now */ | |
228 if ( written < 0 ) { | |
229 this->enabled = 0; | |
230 } | |
231 #ifdef DEBUG_AUDIO | |
232 fprintf(stderr, "Wrote %d bytes of audio data\n", written); | |
233 #endif | |
234 } | |
235 | |
236 static Uint8 *ARTS_GetAudioBuf(_THIS) | |
237 { | |
238 return(mixbuf); | |
239 } | |
240 | |
241 static void ARTS_CloseAudio(_THIS) | |
242 { | |
243 if ( mixbuf != NULL ) { | |
244 SDL_FreeAudioMem(mixbuf); | |
245 mixbuf = NULL; | |
246 } | |
247 if ( stream ) { | |
248 SDL_NAME(arts_close_stream)(stream); | |
249 stream = 0; | |
250 } | |
251 SDL_NAME(arts_free)(); | |
252 } | |
253 | |
254 static int ARTS_OpenAudio(_THIS, SDL_AudioSpec *spec) | |
255 { | |
256 int bits, frag_spec; | |
257 Uint16 test_format, format; | |
258 | |
259 /* Reset the timer synchronization flag */ | |
260 frame_ticks = 0.0; | |
261 | |
262 mixbuf = NULL; | |
263 | |
264 /* Try for a closest match on audio format */ | |
265 format = 0; | |
266 bits = 0; | |
267 for ( test_format = SDL_FirstAudioFormat(spec->format); | |
268 ! format && test_format; ) { | |
269 #ifdef DEBUG_AUDIO | |
270 fprintf(stderr, "Trying format 0x%4.4x\n", test_format); | |
271 #endif | |
272 switch ( test_format ) { | |
273 case AUDIO_U8: | |
274 bits = 8; | |
275 format = 1; | |
276 break; | |
277 case AUDIO_S16LSB: | |
278 bits = 16; | |
279 format = 1; | |
280 break; | |
281 default: | |
282 format = 0; | |
283 break; | |
284 } | |
285 if ( ! format ) { | |
286 test_format = SDL_NextAudioFormat(); | |
287 } | |
288 } | |
289 if ( format == 0 ) { | |
290 SDL_SetError("Couldn't find any hardware audio formats"); | |
291 return(-1); | |
292 } | |
293 spec->format = test_format; | |
294 | |
295 if ( SDL_NAME(arts_init)() != 0 ) { | |
296 SDL_SetError("Unable to initialize ARTS"); | |
297 return(-1); | |
298 } | |
299 stream = SDL_NAME(arts_play_stream)(spec->freq, bits, spec->channels, "SDL"); | |
300 | |
301 /* Calculate the final parameters for this audio specification */ | |
302 SDL_CalculateAudioSpec(spec); | |
303 | |
304 /* Determine the power of two of the fragment size */ | |
305 for ( frag_spec = 0; (0x01<<frag_spec) < spec->size; ++frag_spec ); | |
306 if ( (0x01<<frag_spec) != spec->size ) { | |
307 SDL_SetError("Fragment size must be a power of two"); | |
308 return(-1); | |
309 } | |
310 frag_spec |= 0x00020000; /* two fragments, for low latency */ | |
311 | |
312 #ifdef ARTS_P_PACKET_SETTINGS | |
313 SDL_NAME(arts_stream_set)(stream, ARTS_P_PACKET_SETTINGS, frag_spec); | |
314 #else | |
315 SDL_NAME(arts_stream_set)(stream, ARTS_P_PACKET_SIZE, frag_spec&0xffff); | |
316 SDL_NAME(arts_stream_set)(stream, ARTS_P_PACKET_COUNT, frag_spec>>16); | |
317 #endif | |
318 spec->size = SDL_NAME(arts_stream_get)(stream, ARTS_P_PACKET_SIZE); | |
319 | |
320 /* Allocate mixing buffer */ | |
321 mixlen = spec->size; | |
322 mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen); | |
323 if ( mixbuf == NULL ) { | |
324 return(-1); | |
325 } | |
326 SDL_memset(mixbuf, spec->silence, spec->size); | |
327 | |
328 /* Get the parent process id (we're the parent of the audio thread) */ | |
329 parent = getpid(); | |
330 | |
331 /* We're ready to rock and roll. :-) */ | |
332 return(0); | |
333 } |