Mercurial > hg > xemacs-beta
annotate src/sgiplay.c @ 5518:3cc7470ea71c
gnuclient: if TMPDIR was set and connect failed, try again with /tmp
2011-06-03 Aidan Kehoe <kehoea@parhasard.net>
* gnuslib.c (connect_to_unix_server):
Retry with /tmp as a directory in which to search for Unix sockets
if an attempt to connect with some other directory failed (which
may be because gnuclient and gnuserv don't share an environment
value for TMPDIR, or because gnuserv was compiled with USE_TMPDIR
turned off).
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Fri, 03 Jun 2011 18:40:57 +0100 |
parents | 308d34e9f07d |
children | 56144c8593a8 |
rev | line source |
---|---|
428 | 1 /* Play sound using the SGI audio library |
2 written by Simon Leinen <simon@lia.di.epfl.ch> | |
3 Copyright (C) 1992 Free Software Foundation, Inc. | |
4 | |
5 This file is part of XEmacs. | |
6 | |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
2367
diff
changeset
|
7 XEmacs is free software: you can redistribute it and/or modify it |
428 | 8 under the terms of the GNU General Public License as published by the |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
2367
diff
changeset
|
9 Free Software Foundation, either version 3 of the License, or (at your |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
2367
diff
changeset
|
10 option) any later version. |
428 | 11 |
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 for more details. | |
16 | |
17 You should have received a copy of the GNU General Public License | |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
2367
diff
changeset
|
18 along with XEmacs. If not, see <http://www.gnu.org/licenses/>. */ |
428 | 19 |
20 /* Synched up with: Not in FSF. */ | |
21 | |
563 | 22 /* This file Mule-ized by Ben Wing, 5-15-01. */ |
23 | |
428 | 24 #include <config.h> |
25 #include "lisp.h" | |
26 | |
563 | 27 #include "sound.h" |
28 | |
29 #include "sysfile.h" | |
30 #include "sysproc.h" /* netinet/in.h for ntohl() etc. */ | |
428 | 31 |
609 | 32 #include <audio.h> |
33 | |
428 | 34 /* Configuration options */ |
35 | |
36 /* ability to parse Sun/NeXT (.au or .snd) audio file headers. The | |
37 .snd format supports all sampling rates and sample widths that are | |
38 commonly used, as well as stereo. It is also easy to parse. */ | |
39 #ifndef HAVE_SND_FILES | |
40 #define HAVE_SND_FILES 1 | |
41 #endif | |
42 | |
43 /* support for eight-but mu-law encoding. This is a useful compaction | |
44 technique, and most sounds from the Sun universe are in this | |
45 format. */ | |
46 #ifndef HAVE_MULAW_8 | |
47 #define HAVE_MULAW_8 1 | |
48 #endif | |
49 | |
50 /* if your machine is very slow, you have to use a table lookup to | |
51 convert mulaw samples to linear. This makes Emacs bigger so try to | |
52 avoid it. */ | |
53 #ifndef USE_MULAW_DECODE_TABLE | |
54 #define USE_MULAW_DECODE_TABLE 0 | |
55 #endif | |
56 | |
57 /* support for linear encoding -- useful if you want better quality. | |
58 This enables 8, 16 and 24 bit wide samples. */ | |
59 #ifndef HAVE_LINEAR | |
60 #define HAVE_LINEAR 1 | |
61 #endif | |
62 | |
63 /* support for 32 bit wide samples. If you notice the difference | |
64 between 32 and 24 bit samples, you must have very good ears. Since | |
65 the SGI audio library only supports 24 bit samples, each sample has | |
66 to be shifted right by 8 bits anyway. So you should probably just | |
67 convert all your 32 bit audio files to 24 bit. */ | |
68 #ifndef HAVE_LINEAR_32 | |
69 #define HAVE_LINEAR_32 0 | |
70 #endif | |
71 | |
72 /* support for stereo sound. Imagine the cool applications of this: | |
73 finally you don't just hear a beep -- you also know immediately | |
74 *where* something went wrong! Unfortunately the programming | |
75 interface only takes a single volume argument so far. */ | |
76 #ifndef HAVE_STEREO | |
77 #define HAVE_STEREO 1 | |
78 #endif | |
79 | |
80 /* the play routine can be interrupted between chunks, so we choose a | |
81 small chunksize to keep the system responsive (2000 samples | |
82 correspond to a quarter of a second for .au files. If you | |
83 HAVE_STEREO, the chunksize should probably be even. */ | |
84 #define CHUNKSIZE 8000 | |
85 | |
86 /* the format assumed for header-less audio data. The following | |
87 assumes ".au" format (8000 samples/sec mono 8-bit mulaw). */ | |
88 #define DEFAULT_SAMPLING_RATE 8000 | |
89 #define DEFAULT_CHANNEL_COUNT 1 | |
90 #define DEFAULT_FORMAT AFmulaw8 | |
91 | |
92 /* Data structures */ | |
93 | |
94 /* an AudioContext describes everything we want to know about how a | |
95 particular sound snippet should be played. It is split into three | |
96 parts (device, port and buffer) for implementation reasons. The | |
97 device part corresponds to the state of the output device and must | |
98 be reverted after playing the samples. The port part corresponds | |
99 to an ALport; we want to allocate a minimal number of these since | |
100 there are only four of them system-wide, but on the other hand we | |
101 can't use the same port for mono and stereo. The buffer part | |
102 corresponds to the sound data itself. */ | |
103 | |
104 typedef struct _AudioContextRec * AudioContext; | |
105 | |
106 typedef struct | |
107 { | |
108 long device; | |
109 int left_speaker_gain; | |
110 int right_speaker_gain; | |
111 long output_rate; | |
112 } | |
113 AudioDeviceRec, * AudioDevice; | |
114 | |
115 /* supported sound data formats */ | |
116 | |
117 typedef enum | |
118 { | |
119 AFunknown, | |
120 #if HAVE_MULAW_8 | |
121 AFmulaw8, | |
122 #endif | |
123 #if HAVE_LINEAR | |
124 AFlinear8, | |
125 AFlinear16, | |
126 AFlinear24, | |
127 #if HAVE_LINEAR_32 | |
128 AFlinear32, | |
129 #endif | |
130 #endif | |
131 AFillegal | |
132 } | |
133 AudioFormat; | |
134 | |
135 typedef struct | |
136 { | |
137 ALport port; | |
138 AudioFormat format; | |
139 unsigned nchan; | |
140 unsigned queue_size; | |
141 } | |
142 AudioPortRec, * AudioPort; | |
143 | |
144 typedef struct | |
145 { | |
146 void * data; | |
147 unsigned long size; | |
148 void (* write_chunk_function) (void *, void *, AudioContext); | |
149 } | |
150 AudioBufferRec, * AudioBuffer; | |
151 | |
152 typedef struct _AudioContextRec | |
153 { | |
154 AudioDeviceRec device; | |
155 AudioPortRec port; | |
156 AudioBufferRec buffer; | |
157 } | |
158 AudioContextRec; | |
159 | |
160 #define ac_device device.device | |
161 #define ac_left_speaker_gain device.left_speaker_gain | |
162 #define ac_right_speaker_gain device.right_speaker_gain | |
163 #define ac_output_rate device.output_rate | |
164 #define ac_port port.port | |
165 #define ac_format port.format | |
166 #define ac_nchan port.nchan | |
167 #define ac_queue_size port.queue_size | |
168 #define ac_data buffer.data | |
169 #define ac_size buffer.size | |
170 #define ac_write_chunk_function buffer.write_chunk_function | |
171 | |
172 /* Forward declarations */ | |
173 | |
174 static Lisp_Object close_sound_file (Lisp_Object); | |
2367 | 175 static AudioContext audio_initialize (Binbyte *, int, int); |
176 static int play_internal (Binbyte *, int, AudioContext); | |
428 | 177 static void drain_audio_port (AudioContext); |
178 static void write_mulaw_8_chunk (void *, void *, AudioContext); | |
179 static void write_linear_chunk (void *, void *, AudioContext); | |
180 static void write_linear_32_chunk (void *, void *, AudioContext); | |
181 static Lisp_Object restore_audio_port (Lisp_Object); | |
182 static AudioContext initialize_audio_port (AudioContext); | |
183 static int open_audio_port (AudioContext, AudioContext); | |
184 static void adjust_audio_volume (AudioDevice); | |
185 static void get_current_volumes (AudioDevice); | |
186 static int set_channels (ALconfig, unsigned); | |
187 static int set_output_format (ALconfig, AudioFormat); | |
188 static int parse_snd_header (void*, long, AudioContext); | |
189 | |
190 /* are we looking at an NeXT/Sun audio header? */ | |
191 #define LOOKING_AT_SND_HEADER_P(address) \ | |
192 (!strncmp(".snd", (char *)(address), 4)) | |
193 | |
194 static Lisp_Object | |
195 close_sound_file (Lisp_Object closure) | |
196 { | |
197 close (XINT (closure)); | |
198 return Qnil; | |
199 } | |
200 | |
201 void | |
563 | 202 play_sound_file (Extbyte *sound_file, int volume) |
428 | 203 { |
204 int count = specpdl_depth (); | |
205 int input_fd; | |
2367 | 206 Binbyte buffer[CHUNKSIZE]; |
428 | 207 int bytes_read; |
208 AudioContext ac = (AudioContext) 0; | |
209 | |
210 input_fd = open (sound_file, O_RDONLY); | |
211 if (input_fd == -1) | |
212 /* no error message -- this can't happen | |
213 because Fplay_sound_file has checked the | |
214 file for us. */ | |
215 return; | |
216 | |
217 record_unwind_protect (close_sound_file, make_int (input_fd)); | |
218 | |
219 while ((bytes_read = read (input_fd, buffer, CHUNKSIZE)) > 0) | |
220 { | |
221 if (ac == (AudioContext) 0) | |
222 { | |
223 ac = audio_initialize (buffer, bytes_read, volume); | |
224 if (ac == 0) | |
225 return; | |
226 } | |
227 else | |
228 { | |
229 ac->ac_data = buffer; | |
230 ac->ac_size = bytes_read; | |
231 } | |
232 play_internal (buffer, bytes_read, ac); | |
233 } | |
234 drain_audio_port (ac); | |
771 | 235 unbind_to (count); |
428 | 236 } |
237 | |
238 static long | |
239 saved_device_state[] = { | |
240 AL_OUTPUT_RATE, 0, | |
241 AL_LEFT_SPEAKER_GAIN, 0, | |
242 AL_RIGHT_SPEAKER_GAIN, 0, | |
243 }; | |
244 | |
245 static Lisp_Object | |
246 restore_audio_port (Lisp_Object closure) | |
247 { | |
248 Lisp_Object * contents = XVECTOR_DATA (closure); | |
249 saved_device_state[1] = XINT (contents[0]); | |
250 saved_device_state[3] = XINT (contents[1]); | |
251 saved_device_state[5] = XINT (contents[2]); | |
252 ALsetparams (AL_DEFAULT_DEVICE, saved_device_state, 6); | |
253 return Qnil; | |
254 } | |
255 | |
609 | 256 int |
2367 | 257 play_sound_data (Binbyte *data, int length, int volume) |
428 | 258 { |
259 int count = specpdl_depth (); | |
260 AudioContext ac; | |
609 | 261 int result; |
428 | 262 |
263 ac = audio_initialize (data, length, volume); | |
264 if (ac == (AudioContext) 0) | |
609 | 265 return 0; |
266 result = play_internal (data, length, ac); | |
428 | 267 drain_audio_port (ac); |
771 | 268 unbind_to (count); |
609 | 269 return result; |
428 | 270 } |
271 | |
272 static AudioContext | |
2367 | 273 audio_initialize (Binbyte *data, int length, int volume) |
428 | 274 { |
275 Lisp_Object audio_port_state[3]; | |
276 static AudioContextRec desc; | |
277 AudioContext ac; | |
278 | |
279 desc.ac_right_speaker_gain | |
280 = desc.ac_left_speaker_gain | |
281 = volume * 256 / 100; | |
282 desc.ac_device = AL_DEFAULT_DEVICE; | |
283 | |
284 #if HAVE_SND_FILES | |
285 if (LOOKING_AT_SND_HEADER_P (data)) | |
286 { | |
287 if (parse_snd_header (data, length, & desc)==-1) | |
563 | 288 report_sound_error ("decoding .snd header", Qunbound); |
428 | 289 } |
290 else | |
291 #endif | |
292 { | |
293 desc.ac_data = data; | |
294 desc.ac_size = length; | |
295 desc.ac_output_rate = DEFAULT_SAMPLING_RATE; | |
296 desc.ac_nchan = DEFAULT_CHANNEL_COUNT; | |
297 desc.ac_format = DEFAULT_FORMAT; | |
298 desc.ac_write_chunk_function = write_mulaw_8_chunk; | |
299 } | |
300 | |
301 /* Make sure that the audio port is reset to | |
302 its initial characteristics after exit */ | |
303 ALgetparams (desc.ac_device, saved_device_state, | |
304 sizeof (saved_device_state) / sizeof (long)); | |
305 audio_port_state[0] = make_int (saved_device_state[1]); | |
306 audio_port_state[1] = make_int (saved_device_state[3]); | |
307 audio_port_state[2] = make_int (saved_device_state[5]); | |
308 record_unwind_protect (restore_audio_port, | |
309 Fvector (3, &audio_port_state[0])); | |
310 | |
311 ac = initialize_audio_port (& desc); | |
312 desc = * ac; | |
313 return ac; | |
314 } | |
315 | |
609 | 316 static int |
2367 | 317 play_internal (Binbyte *data, int UNUSED (length), AudioContext ac) |
428 | 318 { |
2367 | 319 Binbyte * limit; |
428 | 320 if (ac == (AudioContext) 0) |
609 | 321 return 0; |
428 | 322 |
2367 | 323 data = (Binbyte *) ac->ac_data; |
428 | 324 limit = data + ac->ac_size; |
325 while (data < limit) | |
326 { | |
2367 | 327 Binbyte * chunklimit = data + CHUNKSIZE; |
428 | 328 |
329 if (chunklimit > limit) | |
330 chunklimit = limit; | |
331 | |
332 QUIT; | |
333 | |
334 (* ac->ac_write_chunk_function) (data, chunklimit, ac); | |
335 data = chunklimit; | |
336 } | |
609 | 337 |
338 return 1; | |
428 | 339 } |
340 | |
341 static void | |
342 drain_audio_port (AudioContext ac) | |
343 { | |
344 while (ALgetfilled (ac->ac_port) > 0) | |
345 sginap(1); | |
346 } | |
347 | |
348 /* Methods to write a "chunk" from a buffer containing audio data to | |
349 an audio port. This may involve some conversion if the output | |
350 device doesn't directly support the format the audio data is in. */ | |
351 | |
352 #if HAVE_MULAW_8 | |
353 | |
354 #if USE_MULAW_DECODE_TABLE | |
355 #include "libst.h" | |
356 #else /* not USE_MULAW_DECODE_TABLE */ | |
357 static int | |
358 st_ulaw_to_linear (int u) | |
359 { | |
442 | 360 static const short table[] = {0,132,396,924,1980,4092,8316,16764}; |
428 | 361 int u1 = ~u; |
362 short exponent = (u1 >> 4) & 0x07; | |
363 int mantissa = u1 & 0x0f; | |
364 int unsigned_result = table[exponent]+(mantissa << (exponent+3)); | |
365 return u1 & 0x80 ? -unsigned_result : unsigned_result; | |
366 } | |
367 #endif /* not USE_MULAW_DECODE_TABLE */ | |
368 | |
369 static void | |
370 write_mulaw_8_chunk (void *buffer, void *chunklimit, AudioContext ac) | |
371 { | |
2367 | 372 Binbyte * data = (Binbyte *) buffer; |
373 Binbyte * limit = (Binbyte *) chunklimit; | |
428 | 374 short * obuf, * bufp; |
375 long n_samples = limit - data; | |
376 | |
377 obuf = alloca_array (short, n_samples); | |
378 bufp = &obuf[0]; | |
379 | |
380 while (data < limit) | |
381 *bufp++ = st_ulaw_to_linear (*data++); | |
382 ALwritesamps (ac->ac_port, obuf, n_samples); | |
383 } | |
384 #endif /* HAVE_MULAW_8 */ | |
385 | |
386 #if HAVE_LINEAR | |
387 static void | |
388 write_linear_chunk (void *data, void *limit, AudioContext ac) | |
389 { | |
390 unsigned n_samples; | |
391 | |
392 switch (ac->ac_format) | |
393 { | |
394 case AFlinear16: n_samples = (short *) limit - (short *) data; break; | |
2367 | 395 case AFlinear8: n_samples = (CBinbyte *) limit - (CBinbyte *) data; break; |
428 | 396 default: n_samples = (long *) limit - (long *) data; break; |
397 } | |
398 ALwritesamps (ac->ac_port, data, (long) n_samples); | |
399 } | |
400 | |
401 #if HAVE_LINEAR_32 | |
402 static void | |
403 write_linear_32_chunk (void *buffer, void *chunklimit, AudioContext ac) | |
404 { | |
405 long * data = (long *) buffer; | |
406 long * limit = (long *) chunklimit; | |
407 long * obuf, * bufp; | |
408 long n_samples = limit-data; | |
409 | |
410 obuf = alloca_array (long, n_samples); | |
411 bufp = &obuf[0]; | |
412 | |
413 while (data < limit) | |
414 *bufp++ = *data++ >> 8; | |
415 ALwritesamps (ac->ac_port, obuf, n_samples); | |
416 } | |
417 #endif /* HAVE_LINEAR_32 */ | |
418 #endif /* HAVE_LINEAR */ | |
419 | |
420 static AudioContext | |
421 initialize_audio_port (AudioContext desc) | |
422 { | |
423 /* we can't use the same port for mono and stereo */ | |
424 static AudioContextRec mono_port_state | |
425 = { { 0, 0, 0, 0 }, | |
426 { (ALport) 0, AFunknown, 1, 0 }, | |
427 { (void *) 0, (unsigned long) 0 } }; | |
428 #if HAVE_STEREO | |
429 static AudioContextRec stereo_port_state | |
430 = { { 0, 0, 0, 0 }, | |
431 { (ALport) 0, AFunknown, 2, 0 }, | |
432 { (void *) 0, (unsigned long) 0 } }; | |
433 static AudioContext return_ac; | |
434 | |
435 switch (desc->ac_nchan) | |
436 { | |
437 case 1: return_ac = & mono_port_state; break; | |
438 case 2: return_ac = & stereo_port_state; break; | |
439 default: return (AudioContext) 0; | |
440 } | |
441 #else /* not HAVE_STEREO */ | |
442 static AudioContext return_ac = & mono_port_state; | |
443 #endif /* not HAVE_STEREO */ | |
444 | |
445 return_ac->device = desc->device; | |
446 return_ac->buffer = desc->buffer; | |
447 return_ac->ac_format = desc->ac_format; | |
448 return_ac->ac_queue_size = desc->ac_queue_size; | |
449 | |
450 if (return_ac->ac_port==(ALport) 0) | |
451 { | |
452 if ((open_audio_port (return_ac, desc))==-1) | |
453 { | |
563 | 454 report_sound_error ("Open audio port", Qunbound); |
428 | 455 return (AudioContext) 0; |
456 } | |
457 } | |
458 else | |
459 { | |
460 ALconfig config = ALgetconfig (return_ac->ac_port); | |
461 int changed = 0; | |
462 long params[2]; | |
463 | |
464 params[0] = AL_OUTPUT_RATE; | |
465 ALgetparams (return_ac->ac_device, params, 2); | |
466 return_ac->ac_output_rate = params[1]; | |
467 | |
468 if (return_ac->ac_output_rate != desc->ac_output_rate) | |
469 { | |
470 return_ac->ac_output_rate = params[1] = desc->ac_output_rate; | |
471 ALsetparams (return_ac->ac_device, params, 2); | |
472 } | |
473 if ((changed = set_output_format (config, return_ac->ac_format))==-1) | |
474 return (AudioContext) 0; | |
475 return_ac->ac_format = desc->ac_format; | |
476 if (changed) | |
477 ALsetconfig (return_ac->ac_port, config); | |
478 } | |
479 return_ac->ac_write_chunk_function = desc->ac_write_chunk_function; | |
480 get_current_volumes (& return_ac->device); | |
481 if (return_ac->ac_left_speaker_gain != desc->ac_left_speaker_gain | |
482 || return_ac->ac_right_speaker_gain != desc->ac_right_speaker_gain) | |
483 adjust_audio_volume (& desc->device); | |
484 return return_ac; | |
485 } | |
486 | |
487 static int | |
488 open_audio_port (AudioContext return_ac, AudioContext desc) | |
489 { | |
490 ALconfig config = ALnewconfig(); | |
491 long params[2]; | |
492 | |
493 adjust_audio_volume (& desc->device); | |
494 return_ac->ac_left_speaker_gain = desc->ac_left_speaker_gain; | |
495 return_ac->ac_right_speaker_gain = desc->ac_right_speaker_gain; | |
496 params[0] = AL_OUTPUT_RATE; | |
497 params[1] = desc->ac_output_rate; | |
498 ALsetparams (desc->ac_device, params, 2); | |
499 return_ac->ac_output_rate = desc->ac_output_rate; | |
500 if (set_channels (config, desc->ac_nchan)==-1) | |
501 return -1; | |
502 return_ac->ac_nchan = desc->ac_nchan; | |
503 if (set_output_format (config, desc->ac_format)==-1) | |
504 return -1; | |
505 return_ac->ac_format = desc->ac_format; | |
506 ALsetqueuesize (config, (long) CHUNKSIZE); | |
507 return_ac->ac_port = ALopenport("XEmacs audio output", "w", config); | |
508 ALfreeconfig (config); | |
509 if (return_ac->ac_port==0) | |
510 { | |
563 | 511 report_sound_error ("Opening audio output port", Qunbound); |
428 | 512 return -1; |
513 } | |
514 return 0; | |
515 } | |
516 | |
517 static int | |
518 set_channels (ALconfig config, unsigned int nchan) | |
519 { | |
520 switch (nchan) | |
521 { | |
522 case 1: ALsetchannels (config, AL_MONO); break; | |
523 #if HAVE_STEREO | |
524 case 2: ALsetchannels (config, AL_STEREO); break; | |
525 #endif /* HAVE_STEREO */ | |
526 default: | |
563 | 527 report_sound_error ("Unsupported channel count", |
528 make_int (nchan)); | |
428 | 529 return -1; |
530 } | |
531 return 0; | |
532 } | |
533 | |
534 static int | |
535 set_output_format (ALconfig config, AudioFormat format) | |
536 { | |
537 long samplesize; | |
538 long old_samplesize; | |
539 | |
540 switch (format) | |
541 { | |
542 #if HAVE_MULAW_8 | |
543 case AFmulaw8: | |
544 #endif | |
545 #if HAVE_LINEAR | |
546 case AFlinear16: | |
547 #endif | |
548 #if HAVE_MULAW_8 || HAVE_LINEAR | |
549 samplesize = AL_SAMPLE_16; | |
550 break; | |
551 #endif | |
552 #if HAVE_LINEAR | |
553 case AFlinear8: | |
554 samplesize = AL_SAMPLE_8; | |
555 break; | |
556 case AFlinear24: | |
557 #if HAVE_LINEAR_32 | |
558 case AFlinear32: | |
559 samplesize = AL_SAMPLE_24; | |
560 break; | |
561 #endif | |
562 #endif | |
563 default: | |
563 | 564 report_sound_error ("Unsupported audio format", make_int (format)); |
428 | 565 return -1; |
566 } | |
567 old_samplesize = ALgetwidth (config); | |
568 if (old_samplesize==samplesize) | |
569 return 0; | |
570 ALsetwidth (config, samplesize); | |
571 return 1; | |
572 } | |
573 | |
574 static void | |
575 adjust_audio_volume (AudioDevice device) | |
576 { | |
577 long params[4]; | |
578 params[0] = AL_LEFT_SPEAKER_GAIN; | |
579 params[1] = device->left_speaker_gain; | |
580 params[2] = AL_RIGHT_SPEAKER_GAIN; | |
581 params[3] = device->right_speaker_gain; | |
582 ALsetparams (device->device, params, 4); | |
583 } | |
584 | |
585 static void | |
586 get_current_volumes (AudioDevice device) | |
587 { | |
588 long params[4]; | |
589 params[0] = AL_LEFT_SPEAKER_GAIN; | |
590 params[2] = AL_RIGHT_SPEAKER_GAIN; | |
591 ALgetparams (device->device, params, 4); | |
592 device->left_speaker_gain = params[1]; | |
593 device->right_speaker_gain = params[3]; | |
594 } | |
595 | |
596 #if HAVE_SND_FILES | |
597 | |
598 /* Parsing .snd (NeXT/Sun) headers */ | |
599 | |
600 typedef struct | |
601 { | |
602 int magic; | |
603 int dataLocation; | |
604 int dataSize; | |
605 int dataFormat; | |
606 int samplingRate; | |
607 int channelCount; | |
2367 | 608 CBinbyte info[4]; |
428 | 609 } |
610 SNDSoundStruct; | |
611 #define SOUND_TO_HOST_INT(x) ntohl(x) | |
612 | |
613 typedef enum | |
614 { | |
615 SND_FORMAT_FORMAT_UNSPECIFIED, | |
616 SND_FORMAT_MULAW_8, | |
617 SND_FORMAT_LINEAR_8, | |
618 SND_FORMAT_LINEAR_16, | |
619 SND_FORMAT_LINEAR_24, | |
620 SND_FORMAT_LINEAR_32, | |
621 SND_FORMAT_FLOAT, | |
622 SND_FORMAT_DOUBLE, | |
623 SND_FORMAT_INDIRECT, | |
624 SND_FORMAT_NESTED, | |
625 SND_FORMAT_DSP_CODE, | |
626 SND_FORMAT_DSP_DATA_8, | |
627 SND_FORMAT_DSP_DATA_16, | |
628 SND_FORMAT_DSP_DATA_24, | |
629 SND_FORMAT_DSP_DATA_32, | |
630 SND_FORMAT_DSP_unknown_15, | |
631 SND_FORMAT_DISPLAY, | |
632 SND_FORMAT_MULAW_SQUELCH, | |
633 SND_FORMAT_EMPHASIZED, | |
634 SND_FORMAT_COMPRESSED, | |
635 SND_FORMAT_COMPRESSED_EMPHASIZED, | |
636 SND_FORMAT_DSP_COMMANDS, | |
637 SND_FORMAT_DSP_COMMANDS_SAMPLES | |
638 } | |
639 SNDFormatCode; | |
640 | |
641 static int | |
642 parse_snd_header (void *header, long length, AudioContext desc) | |
643 { | |
644 #define hp ((SNDSoundStruct *) (header)) | |
645 long limit; | |
646 | |
647 #if HAVE_LINEAR | |
648 desc->ac_write_chunk_function = write_linear_chunk; | |
649 #endif | |
650 switch ((SNDFormatCode) SOUND_TO_HOST_INT (hp->dataFormat)) | |
651 { | |
652 #if HAVE_MULAW_8 | |
653 case SND_FORMAT_MULAW_8: | |
654 desc->ac_format = AFmulaw8; | |
655 desc->ac_write_chunk_function = write_mulaw_8_chunk; | |
656 break; | |
657 #endif | |
658 #if HAVE_LINEAR | |
659 case SND_FORMAT_LINEAR_8: | |
660 desc->ac_format = AFlinear8; | |
661 break; | |
662 case SND_FORMAT_LINEAR_16: | |
663 desc->ac_format = AFlinear16; | |
664 break; | |
665 case SND_FORMAT_LINEAR_24: | |
666 desc->ac_format = AFlinear24; | |
667 break; | |
668 #endif | |
669 #if HAVE_LINEAR_32 | |
670 case SND_FORMAT_LINEAR_32: | |
671 desc->ac_format = AFlinear32; | |
672 desc->ac_write_chunk_function = write_linear_32_chunk; | |
673 break; | |
674 #endif | |
675 default: | |
676 desc->ac_format = AFunknown; | |
677 } | |
678 desc->ac_output_rate = SOUND_TO_HOST_INT (hp->samplingRate); | |
679 desc->ac_nchan = SOUND_TO_HOST_INT (hp->channelCount); | |
2367 | 680 desc->ac_data = (CBinbyte *) header + SOUND_TO_HOST_INT (hp->dataLocation); |
681 limit = (CBinbyte *) header + length - (CBinbyte *) desc->ac_data; | |
428 | 682 desc->ac_size = SOUND_TO_HOST_INT (hp->dataSize); |
683 if (desc->ac_size > limit) desc->ac_size = limit; | |
684 return 0; | |
685 #undef hp | |
686 } | |
687 #endif /* HAVE_SND_FILES */ | |
688 |