home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / lucid / lemacs-19.6 / src / sgiplay.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-28  |  18.8 KB  |  732 lines

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