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 }