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