Mercurial > hg > xemacs-beta
annotate src/sgiplay.c @ 5803:b79e1e02bf01
Preserve extent information in the command builder code.
src/ChangeLog addition:
2014-07-14 Aidan Kehoe <kehoea@parhasard.net>
* event-stream.c:
* event-stream.c (mark_command_builder):
* event-stream.c (finalize_command_builder): Removed.
* event-stream.c (allocate_command_builder):
* event-stream.c (free_command_builder): Removed. Use
free_normal_lisp_object() instead.
* event-stream.c (echo_key_event):
* event-stream.c (regenerate_echo_keys_from_this_command_keys):
Detach all extents here.
* event-stream.c (maybe_echo_keys):
* event-stream.c (reset_key_echo):
* event-stream.c (execute_help_form):
* event-stream.c (Fnext_event):
* event-stream.c (command_builder_find_leaf_no_jit_binding):
* event-stream.c (command_builder_find_leaf):
* event-stream.c (lookup_command_event):
* events.h (struct command_builder):
Move the command builder's echo_buf to being a Lisp string rather
than a malloced Ibyte array. This allows passing through extent
information, which was previously dropped. It also simplifies the
allocation and release code for the command builder.
Rename echo_buf_index to echo_buf_fill_pointer, better reflecting
its function.
Don't rely on zero-termination (something not particularly
compatible with Lisp-level code) when showing a substring of
echo_buf that differs from that designated by
echo_buf_fill_pointer, keep a separate counter instead and use
that.
* minibuf.c:
* minibuf.c (echo_area_append):
Use the new START and END keyword arguments to #'append-message,
rather than consing a new string for basically every #'next-event
prompt displayed.
test/ChangeLog addition:
2014-07-14 Aidan Kehoe <kehoea@parhasard.net>
* automated/extent-tests.el:
Check that extent information is passed through to the echo area
correctly with #'next-event's PROMPT argument.
lisp/ChangeLog addition:
2014-07-14 Aidan Kehoe <kehoea@parhasard.net>
* simple.el (raw-append-message):
Use #'write-sequence in this, take its START and END keyword
arguments, so our callers don't have to cons as much.
* simple.el (append-message):
Pass through START and END here.
| author | Aidan Kehoe <kehoea@parhasard.net> |
|---|---|
| date | Mon, 14 Jul 2014 13:42:42 +0100 |
| parents | 56144c8593a8 |
| children |
| 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 { | |
|
5581
56144c8593a8
Mechanically change INT to FIXNUM in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5402
diff
changeset
|
197 close (XFIXNUM (closure)); |
| 428 | 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 | |
|
5581
56144c8593a8
Mechanically change INT to FIXNUM in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5402
diff
changeset
|
217 record_unwind_protect (close_sound_file, make_fixnum (input_fd)); |
| 428 | 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); | |
|
5581
56144c8593a8
Mechanically change INT to FIXNUM in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5402
diff
changeset
|
249 saved_device_state[1] = XFIXNUM (contents[0]); |
|
56144c8593a8
Mechanically change INT to FIXNUM in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5402
diff
changeset
|
250 saved_device_state[3] = XFIXNUM (contents[1]); |
|
56144c8593a8
Mechanically change INT to FIXNUM in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5402
diff
changeset
|
251 saved_device_state[5] = XFIXNUM (contents[2]); |
| 428 | 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)); | |
|
5581
56144c8593a8
Mechanically change INT to FIXNUM in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5402
diff
changeset
|
305 audio_port_state[0] = make_fixnum (saved_device_state[1]); |
|
56144c8593a8
Mechanically change INT to FIXNUM in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5402
diff
changeset
|
306 audio_port_state[1] = make_fixnum (saved_device_state[3]); |
|
56144c8593a8
Mechanically change INT to FIXNUM in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5402
diff
changeset
|
307 audio_port_state[2] = make_fixnum (saved_device_state[5]); |
| 428 | 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", |
|
5581
56144c8593a8
Mechanically change INT to FIXNUM in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5402
diff
changeset
|
528 make_fixnum (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: | |
|
5581
56144c8593a8
Mechanically change INT to FIXNUM in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5402
diff
changeset
|
564 report_sound_error ("Unsupported audio format", make_fixnum (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 |
