ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/PDL-Audio/sndlib/sndlib.txt
Revision: 1.1
Committed: Tue Dec 28 01:05:17 2004 UTC (21 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-1_1, rel-1_2, HEAD
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 SndLib
2    
3     Bill Schottstaedt (bil@ccrma.stanford.edu)
4    
5     Contents
6    
7     Introduction
8     Headers
9     Data
10     Hardware
11     Music V
12     Examples
13     SndInfo
14     SndPlay
15     SndRecord
16     AudInfo
17     SndSine
18     clmosc
19     Other Examples
20     How to Make Sndlib and the examples
21     Current Status
22     Lower Levels
23     Sndlib and Guile
24    
25     Introduction
26    
27     The sound library is a collection of sound file and audio hardware handlers
28     written in C and running currently on SGI (either audio library), NeXT, Sun,
29     Be, OSS or ALSA (Linux and others), Mac, HPUX, MkLinux/LinuxPPC, and Windoze
30     systems. It provides relatively straightforward access to many sound file
31     headers and data types, and most of the features of the audio hardware.
32    
33     The following files make up sndlib:
34    
35     * io.c (read and write sound file data)
36     * headers.c (read and write sound file headers)
37     * audio.c (read and write sound hardware ports)
38     * sound.c (provide slightly higher level access to the preceding files)
39     * sndlib.h (header for the preceding files)
40     * sndlib2scm.c and sndlib-strings.h (tie preceding into Guile)
41     * clm.c and clm.h (Music V implementation)
42     * clm2scm.c, vct.c and vct.h (tie clm.c into Guile)
43     * old-sndlib.h (old names)
44    
45     In version 6.0, I changed most of the exported names to use the prefix "mus"
46     or "SNDLIB" (to be more in line with the Gnu standard); see old-sndlib.h for
47     backwards compatibility.
48    
49     To build sndlib (sndlib.so if possible, and sndlib.a):
50    
51     ./configure
52     make
53    
54     To install it, 'make install' -- I've tested this process in Linux, SGI,
55     Sun, and NeXT. It could conceivably work elsewhere. For more details see How
56     to Make Sndlib below.
57    
58     Headers
59    
60     Sound files have built-in descriptors known as headers. The following
61     functions return the information in the header. In each case the argument to
62     the function is the full file name of the sound file.
63    
64     int sound_samples (char *arg) /* samples of sound according to header (can be incorrect) */
65     int sound_frames (char *arg) /* samples per channel */
66     float sound_duration (char *arg)
67     int sound_datum_size (char *arg) /* bytes per sample */
68     int sound_data_location (char *arg) /* location of first sample (bytes) */
69     int sound_chans (char *arg) /* number of channels (samples are interleaved) */
70     int sound_srate (char *arg) /* sampling rate */
71     int sound_header_type (char *arg) /* header type (aiff etc) */
72     int sound_data_format (char *arg) /* data format (alaw etc) */
73     int sound_original_format (char *arg) /* unmodified data format specifier */
74     char *sound_comment (char *arg) /* comment if any */
75     int sound_comment_start (char *arg) /* comment start (bytes) if any */
76     int sound_comment_end (char *arg) /* comment end (bytes) */
77     int sound_length (char *arg) /* true file length (for error checks) */
78     int sound_fact_samples (char *arg) /* compression scheme data */
79     int sound_distributed (char *arg) /* is header scattered around in sound file */
80     int sound_write_date (char *arg) /* bare (uninterpreted) file write date */
81     int sound_type_specifier (char *arg) /* original header type identifier */
82     int sound_align (char *arg) /* more compression data */
83     int sound_bits_per_sample(char *arg) /* bits per sample */
84     int sound_bytes_per_sample(int format) /* bytes per sample */
85     int sound_max_amp(char *arg, int *vals)/* return list of max-amp sample pairs */
86     int sound_aiff_p(char *arg) /* is it an old-style AIFF file (not AIFC) */
87     void initialize_sndlib(void) /* initialize everything */
88     int sound_aiff_p(char *arg) /* if sound's header actually an old-style AIFF (not AIFC) header */
89    
90     The following can be used to provide user-understandable descriptions of the
91     header type and the data format:
92    
93     char *sound_type_name(int type) /* "AIFF" etc */
94     char *sound_format_name(int format) /* "16-bit big endian linear" etc */
95    
96     In all cases if an error occurs, -1 is returned; for information about the
97     error use:
98    
99     int audio_error(void) /* returns error code indicated by preceding audio call */
100     char *audio_error_name(int err) /* gives string decription of error code */
101    
102     Header data is cached internally, so the actual header is read only if it
103     hasn't already been read, or the write date has changed. Loop points are
104     also available, if there's interest. To go below the "sound" level, see
105     headers.c -- once a header has been read, all the components that have been
106     found can be read via functions such as mus_header_srate.
107    
108     Data
109    
110     The following functions provide access to sound file data:
111    
112     int open_sound_input (char *arg)
113     int open_sound_output (char *arg, int srate, int chans, int data_format, int header_type, char *comment)
114     int reopen_sound_output (char *arg, int type, int format, int data_loc)
115     int close_sound_input (int fd)
116     int close_sound_output (int fd, int bytes_of_data)
117     int read_sound (int fd, int beg, int end, int chans, int **bufs)
118     int write_sound (int fd, int beg, int end, int chans, int **bufs)
119     int seek_sound (int fd, long offset, int origin)
120     int seek_sound_frame (int fd, int frame)
121     int mus_float_sound(char *charbuf, int samps, int charbuf_format, float *buffer)
122    
123     open_sound_input opens arg for reading. Most standard uncompressed formats
124     are readable. This function returns the associated file number, or -1 upon
125     failure.
126    
127     close_sound_input closes an open sound file. Its argument is the integer
128     returned by open_sound_input.
129    
130     open_sound_output opens arg, setting its sampling rate to be srate, number
131     of channels to chans, data format to data_format (see sndlib.h for these
132     types: SNDLIB_16_LINEAR, for example, means 16-bit 2's complement big endian
133     fractions), header type to header_type (AIFF for example; the available
134     writable header types are AIFF_sound_file, RIFF_sound_file ('wave'),
135     NeXT_sound_file, and IRCAM_sound_file), and comment (if any) to comment. The
136     header is not considered complete without an indication of the data size,
137     but since this is rarely known in advance, it is supplied when the sound
138     file is closed. This function returns the associated file number.
139    
140     close_sound_output first updates the file's header to reflect the final data
141     size bytes_of_data, then closes the file. The argument fd is the integer
142     returned by open_sound_output.
143    
144     read_sound reads data from the file indicated by fd, placing data in the
145     array obufs as 32-bit integers in the host's byte order. chans determines
146     how many arrays of ints are in obufs, which is filled by read_sound from its
147     index beg to end with zero padding if necessary. See the sndplay example
148     below if this is not obvious.
149    
150     write_sound writes data to the file indicated by fd, starting for each of
151     chans channels in obufs at beg and ending at end.
152    
153     seek_sound moves the read or write position for the file indicated by fd to
154     offset given the origin indication (both treated as in lseek). The new
155     actual position attained is returned. In both cases (the returned value and
156     offset), the output datum size is considered to be 2, no matter what it
157     really is. That is, use byte positions as if you were always reading and
158     writing 16-bit data, and seek_sound will compensate if its actually 32-bit
159     floats or whatever. Since this is impossible to understand, there's also
160     seek_sound_frame which moves to the indicated frame.
161    
162     mus_float_sound takes a buffer full of sound data in some format
163     (charbuf_format and returns the data as a buffer full of (unscaled) floats.
164    
165     Hardware
166    
167     The following functions provide access to audio harware. If an error occurs,
168     they return -1, and the audio_error functions can be used to find out what
169     went wrong.
170    
171     int initialize_audio(void)
172     void save_audio_state(void)
173     void restore_audio_state(void)
174     void describe_audio_state(void)
175     char *report_audio_state(void)
176     int open_audio_output(int dev, int srate, int chans, int format, int size)
177     int open_audio_input(int dev, int srate, int chans, int format, int size)
178     int write_audio(int line, char *buf, int bytes)
179     int close_audio(int line)
180     int read_audio(int line, char *buf, int bytes)
181     int read_audio_state(int dev, int field, int chan, float *val)
182     int write_audio_state(int dev, int field, int chan, float *val)
183     int audio_systems(void)
184     char *audio_system_name(int system)
185     void setup_dsps(int cards, int *dsps, int *mixers) /* OSS only */
186    
187     initialize_audio takes care of any necessary intialization.
188    
189     save_audio_state saves the current audio hardware state.
190    
191     restore_audio_state restores the audio hardware to the last saved state.
192    
193     describe_audio_state prints to stdout a description of the current state of
194     the audio hardware. report_audio_state returns the same description as a
195     string.
196    
197     audio_systems returns the number of separate and complete audio systems
198     (soundcards essentially) that are available. audio_system_name returns some
199     user-recognizable name for the given card.
200    
201     open_audio_input opens an audio port to read sound data (i.e. a microphone,
202     line in, etc). The input device is dev (see sndlib.h for details; when in
203     doubt, use SNDLIB_DEFAULT_DEVICE). The input sampling rate is srate or as
204     close as we can get to it. The number of input channels (if available) is
205     chans. The input data format is format (when in doubt, use the macro
206     SNDLIB_COMPATIBLE_FORMAT). And the input buffer size (if settable at all) is
207     size (bytes). This function returns an integer to distinguish its port from
208     others that might be in use. In this and other related functions, the device
209     has an optional second portion that refers to the soundcard or system for
210     that device. SNDLIB_AUDIO_SYSTEM(n) refers to the nth such card, so
211     (SNDLIB_DAC_DEVICE | SNDLIB_AUDIO_SYSTEM(1)) is the 2nd card's dac (the
212     default is system 0, the first card).
213    
214     open_audio_output opens an audio port to write date (i.e. speakers, line
215     out, etc). The output device is dev (see sndlib.h). Its sampling rate is
216     srate, number of channels chans, data format format, and buffer size size.
217     This function returns the associated line number of the output port.
218    
219     close_audio closes the port (input or output) associated with line.
220    
221     read_audio reads sound data from line. The incoming bytes bytes of data are
222     placed in buf. If no error was returned from open_audio_input, the data is
223     in the format requested by that function with channels interleaved.
224    
225     write_audio writes bytes bytes of data in buf to the output port associated
226     with line. This data is assumed to be in the format requested by
227     open_audio_output with channels interleaved.
228    
229     read_audio_state and write_audio_state are complicated. They get and set the
230     audio hardware state. The audio hardware is treated as a set of "systems"
231     (sound cards) each of which has a set of "devices" (dacs, adcs, etc), with
232     various "fields" that can be read or set (gain, channels active, etc). For
233     example, a microphone is called the SNDLIB_MICROPHONE_DEVICE, and its
234     hardware gain setting (if any) is called the SNDLIB_AMP_FIELD. All gains are
235     considered to be linear between 0.0 and 1.0, so to set the microphone's
236     first channel amplitude to .5 (that is, the gain of the signal before it
237     reaches the analog-to-digital converter),
238    
239     float vals[1];
240     vals[0]=0.5;
241     write_audio_state(SNDLIB_MICROPHONE_DEVICE,SNDLIB_AMP_FIELD,0,vals);
242    
243     Similarly
244    
245     read_audio_state(SNDLIB_MICROPHONE_DEVICE,SNDLIB_AMP_FIELD,0,vals);
246     amp=vals[0];
247    
248     returns the current gain in the float array vals. read_audio_state can also
249     return a description of the currently available audio hardware.
250    
251     If a requested operation is not implemented, -1 is returned, and
252     SNDLIB_AUDIO_ERROR is set to SNDLIB_CANT_READ or SNDLIB_CANT_WRITE. If an
253     error occurs during the requested operation, -1 is returned, and
254     SNDLIB_AUDIO_ERROR is set to SNDLIB_READ_ERROR or SNDLIB_WRITE_ERROR. If
255     some operation cannot be performed on the current hardware, -1 is returned
256     and SNDLIB_AUDIO_ERROR tries to indicate what portion of the requested
257     operation is impossible (SNDLIB_SRATE_NOT_AVAILABLE,
258     SNDLIB_FORMAT_NOT_AVAILABLE, and so on).
259    
260     Systems
261    
262     Each separate sound card is called a system, accessible via the device
263     argument through the macro SNDLIB_AUDIO_SYSTEM(n). The count starts at 0
264     which is the default. The function audio_systems returns how many such cards
265     are available. (Currently it returns more than one only on Linux systems
266     with multiple sound cards).
267    
268     Devices
269    
270     Each audio system has a set of available devices. To find out what is
271     available on a given system
272    
273     #define LIST_MAX_SIZE 32;
274     float device_list[LIST_MAX_SIZE];
275     read_audio_state(SNDLIB_AUDIO_SYSTEM(0),SNDLIB_DEVICE_FIELD,LIST_MAX_SIZE,device_list);
276    
277     The list of available devices is returned in the device_list array, with the
278     number of the devices as device_list[0]. The set of device identifiers is in
279     sndlib.h (SNDLIB_LINE_IN_DEVICE for example). Two special devices are
280     SNDLIB_MIXER_DEVICE and SNDLIB_DAC_FILTER_DEVICE. The latter refers to the
281     low-pass filter often associated with a DAC. The former refers to a set of
282     analog gain and tone controls often associated with a sound card. The
283     individual gains are accessed through the various fields (described below).
284    
285     Fields
286    
287     The field argument in read-audio-state and write-audio-state selects one
288     aspect of the given card's devices' controls. The simplest operations
289     involve SNDLIB_AMP_FIELD and SNDLIB_SRATE_FIELD. The latter gets or sets the
290     sampling rate of the device, and the former gets or sets the amplitude
291     (between 0.0 and 1.0) of the specified channel of the device. The value to
292     be set or returned is in the 0th element of the vals array. An example of
293     reading the current microphone gain is given above. The meaning of the field
294     argument can depend on which device it is applied to, so there is some
295     complexity here. The channel argument usually selects which channel we are
296     interested in, but in some cases it instead tells read-audio-state how big a
297     returned list can get. A brief description of the fields:
298    
299     SNDLIB_AMP_FIELD gain or volume control (0.0 to 1.0)
300     SNDLIB_SRATE_FIELD sampling rate
301     SNDLIB_CHANNEL_FIELD active channels
302    
303     SNDLIB_BASS_FIELD, SNDLIB_TREBLE_FIELD mixer's tone control
304     SNDLIB_LINE_FIELD mixer's line-in gain control
305     SNDLIB_MIC_FIELD mixer's microphone gain control
306     similarly for SNDLIB_IMIX_FIELD, SNDLIB_IGAIN_FIELD,
307     SNDLIB_RECLEV_FIELD, SNDLIB_PCM_FIELD, SNDLIB_PCM2_FIELD,
308     SNDLIB_OGAIN_FIELD, SNDLIB_LINE1_FIELD,
309     SNDLIB_LINE2_FIELD, SNDLIB_LINE3_FIELD, SNDLIB_SYNTH_FIELD
310    
311     SNDLIB_FORMAT_FIELD return list of usable sound formats (e.g. SNDLIB_16_LINEAR)
312     SNDLIB_DEVICE_FIELD return list of available devices (e.g. SNDLIB_MICROPHONE_DEVICE)
313    
314     MusicV
315    
316     clm.c and friends implement all the generators found in CLM, a common lisp
317     music V implementation, and clm2scm.c ties these into Guile (Scheme). The
318     primary clm documentation (which describes both the Scheme and Common Lisp
319     implementations) is clm.html found in clm-2.tar.gz alongside sndlib at
320     ccrma-ftp. The simplest way to try these out is to load them into Snd; see
321     extsnd.html and examp.scm in snd-3.tar.gz for more details. The C
322     implementation is essentially the same as the two Lisp versions, but (as
323     might be expected), works at a lower level, expecting the caller to handle
324     garbage collection and so forth. The following briefly describes the C calls
325     (see clm.h).
326    
327     clm.c implements a bunch of generators and sound IO handlers. Each generator
328     has three associated functions, make-gen, gen, and gen_p; the first creates
329     the generator (if needed), the second gets the next sample from the
330     generator, and the last examines some pointer to determine if it is that
331     kind of generator. In addition, there are a variety of "generic" functions
332     that generators respond to: mus_free, for example, frees a generator, and
333     mus_frequency returns its current frequency, if relevant. All generators are
334     pointers to mus_any structs. Finally, CLM has two special data types: frame
335     and mixer. A frame is an array that represents a multi-channel sample (that
336     is, in a stereo file, at time 0.0, there are two samples, one for each
337     channel). A mixer is a array of arrays that represents a set of input and
338     output scalers, as if it were the current state of a mixing console's volume
339     controls. A frame (a multi-channel input) can be "mixed" into a new frame (a
340     multi-channel output) by passing it through a "mixer" (a matrix, the
341     operation being a matrix multiply).
342    
343     * oscil -- generate a sine wave.
344     o mus_any *mus_make_oscil (float freq, float phase)
345     o float mus_oscil (mus_any *o, float fm, float pm)
346     o int mus_oscil_p (mus_any *ptr)
347    
348     mus_any *osc;
349     init_mus_module();
350     osc = mus_make_oscil(440.0,0.0);
351     if (oscil_p(osc)) fprintf(stderr,"%.3f, %.3f ",.1 * mus_oscil(osc,0.0,0.0),mus_frequency(osc));
352     mus_free(osc);
353    
354     The other generators are:
355    
356     * sum_of_cosines -- generate a pulse train made up of cosines
357     * delay -- a delay line with optional interpolation
358     * tap -- read delay line
359     * comb -- comb filter
360     * notch -- notch filter
361     * all_pass -- all pass filter
362     * table_lookup -- interpolating table lookup
363     * sawtooth_wave, triangle_wave, pulse_train, square_wave
364     * rand -- white noise (a step function)
365     * rand-interp -- interpolating noise
366     * asymmetric_fm -- a variety of FM
367     * one_zero, two_zero, one_pole, two_pole -- basic filters
368     * formant -- create a formant region (two poles, two zeros)
369     * sine_summation -- another way to create sine waves
370     * filter, fir_filter, iir_filter -- direct form filters of any order
371     * wave_train -- sequence of possibly overlapping waves
372     * buffer -- a way to handle block processing in the generator world
373     * env -- envelopes
374     * waveshape -- waveshaping
375     * readin, file2sample, file2frame, in_any -- file sample input
376     * locsig, sample2file, frame2file, out_any -- file sample output
377     * src -- sampling rate conversion
378     * granulate -- granular synthesis
379     * convolve -- convolution
380    
381     Some useful functions provided by clm.c are:
382    
383     * float mus_radians2hz(float rads) -- convert radians/sample to
384     cycles/sec.
385     * float mus_hz2radians(float hz) -- and the reverse.
386     * float mus_degrees2radians(float deg) -- convert degrees to radians.
387     * float mus_radians2degrees(float rads) -- and the reverse.
388     * float mus_srate(void) -- current sampling rate
389     * float mus_set_srate(float rate) -- set current sampling rate
390     * float mus_ring_modulate(float sig1, float sig2) -- multiply sig1 by
391     sig2
392     * float mus_amplitude_modulate(float s1, float s2, float s3) -- AM
393     * float mus_contrast_enhancement(float sig, float index)
394     * float mus_dot_product(float *data1, float *data2, int size)
395     * void mus_clear_array(float *arr, int size)
396     * float mus_array_interp(float *wave, float phase, int size)
397     * float mus_polynomial(float *coeffs, float x, int ncoeffs);
398     * void mus_multiply_arrays(float *data, float *window, int len);
399     * void mus_rectangular2polar(float *rl, float *im, int size);
400     * void mus_spectrum(float *rdat, float *idat, float *window, int n, int
401     type)
402     * void mus_fft(float *rl, float *im, int n, int isign, int ipow)
403     * float *mus_make_fft_window(int size, int type, float beta)
404     * void mus_convolution(float* rl1, float* rl2, int n, int ipow)
405     * float *mus_partials2wave(float *partial_data, int partials, float
406     *table, int table_size, int normalize)
407     * float *mus_phasepartials2wave(float *partial_data, int partials, float
408     *table, int table_size, int normalize)
409    
410     and various others -- see clm.h.
411    
412     The more useful generic functions are:
413    
414     * int mus_free(mus_any *ptr)
415     * char *mus_describe(mus_any *gen)
416     * float mus_phase(mus_any *gen)
417     * float mus_set_phase(mus_any *gen, float val)
418     * float mus_set_frequency(mus_any *gen, float val)
419     * float mus_frequency(mus_any *gen)
420     * int mus_length(mus_any *gen)
421     * int mus_set_length(mus_any *gen, int len)
422     * float *mus_data(mus_any *gen)
423     * float *mus_set_data(mus_any *gen, float *data)
424     * char *mus_name(mus_any *ptr)
425     * int mus_type(mus_any *ptr)
426     * float mus_scaler(mus_any *gen)
427     * float mus_set_scaler(mus_any *gen, float val)
428    
429     Before using any of these functions, call init_mus_module. Errors are
430     reported through mus_error which can be redirected or muffled. See clm2scm.c
431     for an example.
432    
433     ------------------------------------------------------------------------
434    
435     Examples
436    
437     In the following examples I've omitted the usual garrulous C-header gab and
438     other inessential stuff. The full program code is available as noted below.
439    
440     SndInfo
441    
442     This program prints out a description of a sound file (sndinfo.c).
443    
444     int main(int argc, char *argv[])
445     {
446     int fd,chans,srate,samples;
447     float length;
448     time_t date;
449     char *comment;
450     char timestr[64];
451     initialize_sndlib();
452     fd = mus_open_read(argv[1]); /* see if it exists */
453     if (fd != -1)
454     {
455     close(fd);
456     date = sound_write_date(argv[1]);
457     srate = sound_srate(argv[1]);
458     chans = sound_chans(argv[1]);
459     samples = sound_samples(argv[1]);
460     comment = sound_comment(argv[1]);
461     length = (float)samples / (float)(chans * srate);
462     strftime(timestr,64,"%a %d-%b-%y %H:%M %Z",localtime(&date));
463     fprintf(stdout,"%s:\n srate: %d\n chans: %d\n length: %f\n",
464     argv[1],srate,chans,length);
465     fprintf(stdout," type: %s\n format: %s\n written: %s\n comment: %s\n",
466     sound_type_name(sound_header_type(argv[1])),
467     sound_format_name(sound_data_format(argv[1])),
468     timestr,comment);
469     }
470     else
471     fprintf(stderr,"%s: %s\n",argv[1],strerror(errno));
472     return(0);
473     }
474    
475     SndPlay
476    
477     This code plays a sound file (sndplay.c):
478    
479     int main(int argc, char *argv[])
480     {
481     int fd,afd,i,j,n,k,chans,srate,frames,outbytes;
482     int **bufs;
483     short *obuf;
484     initialize_sndlib();
485     fd = open_sound_input(argv[1]);
486     if (fd != -1)
487     {
488     chans = sound_chans(argv[1]);
489     srate = sound_srate(argv[1]);
490     frames = sound_frames(argv[1]);
491     outbytes = BUFFER_SIZE * chans * 2;
492     bufs = (int **)calloc(chans,sizeof(int *));
493     for (i=0;i<chans;i++) bufs[i] = (int *)calloc(BUFFER_SIZE,sizeof(int));
494     obuf = (short *)calloc(BUFFER_SIZE * chans,sizeof(short));
495     afd = open_audio_output(SNDLIB_DEFAULT_DEVICE,srate,chans,SNDLIB_COMPATIBLE_FORMAT,outbytes);
496     if (afd != -1)
497     {
498     for (i=0;i<frames;i+=BUFFER_SIZE)
499     {
500     read_sound(fd,0,BUFFER_SIZE-1,chans,bufs);
501     for (k=0,j=0;k<BUFFER_SIZE;k++,j+=chans)
502     for (n=0;n<chans;n++) obuf[j+n] = bufs[n][k];
503     write_audio(afd,(char *)obuf,outbytes);
504     }
505     close_audio(afd);
506     }
507     close_sound_input(fd);
508     for (i=0;i<chans;i++) free(bufs[i]);
509     free(bufs);
510     free(obuf);
511     }
512     else
513     fprintf(stderr,"%s: %s ",argv[1],audio_error_name(audio_error()));
514     return(0);
515     }
516    
517     SndRecord
518    
519     This code records a couple seconds of sound from a microphone. Input formats
520     and sampling rates are dependent on available hardware, so in a "real"
521     program, you'd use read_audio_state to find out what was available, then
522     float-sound to turn that data into a stream of floats. You'd also provide,
523     no doubt, some whizzy user interface to turn the thing off. (sndrecord.c)
524    
525     int main(int argc, char *argv[])
526     {
527     int fd,afd,i,err;
528     short *ibuf;
529     #if MACOS
530     argc = ccommand(&argv);
531     #endif
532     afd = -1;
533     initialize_sndlib();
534     fd = open_sound_output(argv[1],22050,1,SNDLIB_16_LINEAR,NeXT_sound_file,"created by sndrecord");
535     if (fd != -1)
536     {
537     ibuf = (short *)calloc(BUFFER_SIZE,sizeof(short));
538     afd = open_audio_input(SNDLIB_MICROPHONE_DEVICE,22050,1,SNDLIB_16_LINEAR,BUFFER_SIZE);
539     if (afd != -1)
540     {
541     for (i=0;i<10;i++) /* grab 10 buffers of input */
542     {
543     err = read_audio(afd,(char *)ibuf,BUFFER_SIZE*2);
544     if (err != SNDLIB_NO_ERROR) {fprintf(stderr,audio_error_name(audio_error())); break;}
545     write(fd,ibuf,BUFFER_SIZE*2);
546     }
547     close_audio(afd);
548     }
549     else
550     fprintf(stderr,audio_error_name(audio_error()));
551     close_sound_output(fd,BUFFER_SIZE*10*2);
552     free(ibuf);
553     }
554     else
555     fprintf(stderr,"%s: %s ",argv[1],strerror(errno));
556     return(0);
557     }
558    
559     AudInfo
560    
561     This program describes the current audio harware state (audinfo.c):
562    
563     int main(int argc, char *argv[])
564     {
565     initialize_sndlib();
566     describe_audio_state();
567     return(0);
568     }
569    
570     SndSine
571    
572     This program writes a one channel NeXT/Sun sound file containing a sine wave
573     at 440 Hz.
574    
575     int main(int argc, char *argv[])
576     {
577     int fd,i,k,frames;
578     float phase,incr;
579     int *obuf[1];
580     initialize_sndlib();
581     fd = open_sound_output(argv[1],22050,1,SNDLIB_16_LINEAR,NeXT_sound_file,"created by sndsine");
582     if (fd != -1)
583     {
584     frames = 22050;
585     phase = 0.0;
586     incr = 2*PI*440.0/22050.0;
587     obuf[0] = (int *)calloc(BUFFER_SIZE,sizeof(int));
588     k=0;
589     for (i=0;i<frames;i++)
590     {
591     obuf[0][k] = (int)(3276.8 * sin(phase)); /* amp = .1 */
592     phase += incr;
593     k++;
594     if (k == BUFFER_SIZE)
595     {
596     write_sound(fd,0,BUFFER_SIZE-1,1,obuf);
597     k=0;
598     }
599     }
600     if (k>0) write_sound(fd,0,k-1,1,obuf);
601     close_sound_output(fd,22050*mus_format2bytes(SNDLIB_16_LINEAR));
602     free(obuf[0]);
603     }
604     return(0);
605     }
606    
607     clmosc
608    
609     This is program uses the clm.c oscillator and output functions to write the
610     same sine wave as we wrote in SndSine. (Compile clm.c with -DHAVE_SNDLIB=1).
611    
612     int main(int argc, char *argv[])
613     {
614     int i;
615     mus_any *osc,*op;
616     initialize_sndlib();
617     init_mus_module();
618     osc = mus_make_oscil(440.0,0.0);
619     op = mus_make_file_output("test.snd",22050,1,SNDLIB_16_LINEAR,NeXT_sound_file,"created by clmosc");
620     if (op) for (i=0;i<22050;i++) mus_sample2file(op,i,0,.1 * mus_oscil(osc,0.0,0.0));
621     mus_free(osc);
622     if (op) mus_free(op);
623     return(0);
624     }
625    
626     Here is the fm-violin and a sample with-sound call:
627    
628     static int feq(float x, int i) {return(fabs(x-i)<.00001);}
629    
630     void fm_violin(float start, float dur, float frequency, float amplitude, float fm_index, mus_any *op)
631     {
632     float pervibfrq = 5.0,
633     ranvibfrq = 16.0,
634     pervibamp = .0025,
635     ranvibamp = .005,
636     noise_amount = 0.0,
637     noise_frq = 1000.0,
638     gliss_amp = 0.0,
639     fm1_rat = 1.0,
640     fm2_rat = 3.0,
641     fm3_rat = 4.0,
642     reverb_amount = 0.0,
643     degree = 0.0,
644     distance = 1.0;
645     float fm_env[] = {0.0, 1.0, 25.0, 0.4, 75.0, 0.6, 100.0, 0.0};
646     float amp_env[] = {0.0, 0.0, 25.0, 1.0, 75.0, 1.0, 100.0, 0.0};
647     float frq_env[] = {0.0, -1.0, 15.0, 1.0, 25.0, 0.0, 100.0, 0.0};
648     int beg = 0,end,easy_case = 0,npartials,i;
649     float *coeffs,*partials;
650     float frq_scl,maxdev,logfrq,sqrtfrq,index1,index2,index3,norm,vib = 0.0,modulation = 0.0,fuzz = 0.0,indfuzz = 1.0,ampfuzz = 1.0;
651     mus_any *carrier,*fmosc1,*fmosc2,*fmosc3,*ampf,*indf1,*indf2,*indf3,*fmnoi = NULL,*pervib,*ranvib,*frqf = NULL,*loc;
652     beg = start * mus_srate();
653     end = beg + dur * mus_srate();
654     frq_scl = mus_hz2radians(frequency);
655     maxdev = frq_scl * fm_index;
656     if ((noise_amount == 0.0) && (feq(fm1_rat,floor(fm1_rat))) && (feq(fm2_rat,floor(fm2_rat))) && (feq(fm3_rat,floor(fm3_rat)))) easy_case = 1;
657     logfrq = log(frequency);
658     sqrtfrq = sqrt(frequency);
659     index1 = maxdev * 5.0 / logfrq; if (index1 > M_PI) index1 = M_PI;
660     index2 = maxdev * 3.0 * (8.5 - logfrq) / (3.0 + frequency * .001); if (index2 > M_PI) index2 = M_PI;
661     index3 = maxdev * 4.0 / sqrtfrq; if (index3 > M_PI) index3 = M_PI;
662     if (easy_case)
663     {
664     npartials = floor(fm1_rat);
665     if ((floor(fm2_rat)) > npartials) npartials = floor(fm2_rat);
666     if ((floor(fm3_rat)) > npartials) npartials = floor(fm3_rat);
667     npartials++;
668     partials = (float *)CALLOC(npartials,sizeof(float));
669     partials[(int)(fm1_rat)] = index1;
670     partials[(int)(fm2_rat)] = index2;
671     partials[(int)(fm3_rat)] = index3;
672     coeffs = mus_partials2polynomial(npartials,partials,1);
673     norm = 1.0;
674     }
675     else norm = index1;
676     carrier = mus_make_oscil(frequency,0.0);
677     if (easy_case == 0)
678     {
679     fmosc1 = mus_make_oscil(frequency * fm1_rat,0.0);
680     fmosc2 = mus_make_oscil(frequency * fm2_rat,0.0);
681     fmosc3 = mus_make_oscil(frequency * fm3_rat,0.0);
682     }
683     else fmosc1 = mus_make_oscil(frequency,0.0);
684     ampf = mus_make_env(amp_env,4,amplitude,0.0,1.0,dur,0,0,NULL);
685     indf1 = mus_make_env(fm_env,4,norm,0.0,1.0,dur,0,0,NULL);
686     if (gliss_amp != 0.0) frqf = mus_make_env(frq_env,4,gliss_amp * frq_scl,0.0,1.0,dur,0,0,NULL);
687     if (easy_case == 0)
688     {
689     indf2 = mus_make_env(fm_env,4,index2,0.0,1.0,dur,0,0,NULL);
690     indf3 = mus_make_env(fm_env,4,index3,0.0,1.0,dur,0,0,NULL);
691     }
692     pervib = mus_make_triangle_wave(pervibfrq,frq_scl * pervibamp,0.0);
693     ranvib = mus_make_rand_interp(ranvibfrq,frq_scl * ranvibamp);
694     if (noise_amount != 0.0) fmnoi = mus_make_rand(noise_frq,noise_amount * M_PI);
695     loc = mus_make_locsig(degree,distance,reverb_amount,1,(mus_output *)op,NULL);
696     for (i=beg;i<end;i++)
697     {
698     if (noise_amount != 0.0) fuzz = mus_rand(fmnoi,0.0);
699     if (frqf) vib = mus_env(frqf); else vib = 0.0;
700     vib += mus_triangle_wave(pervib,0.0) + mus_rand_interp(ranvib,0.0);
701     if (easy_case)
702     modulation = mus_env(indf1) * mus_polynomial(coeffs,mus_oscil(fmosc1,vib,0.0),npartials);
703     else
704     modulation = mus_env(indf1) * mus_oscil(fmosc1,(fuzz + fm1_rat * vib),0.0) +
705     mus_env(indf2) * mus_oscil(fmosc2,(fuzz + fm2_rat * vib),0.0) +
706     mus_env(indf3) * mus_oscil(fmosc3,(fuzz + fm3_rat * vib),0.0);
707     mus_locsig(loc,i,mus_env(ampf) * mus_oscil(carrier,vib + indfuzz * modulation,0.0));
708     }
709     mus_free(pervib);
710     mus_free(ranvib);
711     mus_free(carrier);
712     mus_free(fmosc1);
713     mus_free(ampf);
714     mus_free(indf1);
715     if (fmnoi) mus_free(fmnoi);
716     if (frqf) mus_free(frqf);
717     if (easy_case == 0)
718     {
719     mus_free(indf2);
720     mus_free(indf3);
721     mus_free(fmosc2);
722     mus_free(fmosc3);
723     }
724     else
725     FREE(partials);
726     mus_free(loc);
727     }
728    
729     int main(int argc, char *argv[])
730     {
731     mus_any *osc = NULL,*op = NULL;
732     initialize_sndlib();
733     init_mus_module();
734     op = mus_make_file_output("test.snd",22050,1,SNDLIB_16_LINEAR,NeXT_sound_file,"created by clmosc");
735     if (op)
736     {
737     fm_violin(0.0,20.0,440.0,.3,1.0,op);
738     mus_free(op);
739     }
740     return(0);
741     }
742    
743     The CLM version is v.ins, the Scheme version can be found in examp.scm. This
744     code can be run:
745    
746     cc v.c -o vc -O3 -lm io.o headers.o audio.o sound.o clm.o -DLINUX
747    
748     where clm.o was compiled with -DHAVE_SNDLIB.
749    
750     ------------------------------------------------------------------------
751    
752     Other Examples
753    
754     The primary impetus for the sound library was the development of Snd and
755     CLM, both of which are freely available.
756    
757     ------------------------------------------------------------------------
758    
759     How to Make Sndlib and the examples
760    
761     The Sndlib files can be used as separate modules or made into a library. The
762     following sequence, for example, builds the sndplay program from scratch on
763     an SGI:
764    
765     cc -c io.c -O -DSGI
766     cc -c headers.c -O -DSGI
767     cc -c audio.c -O -DSGI
768     cc -c sound.c -O -DSGI
769     cc sndplay.c -o sndplay -O -DSGI audio.o io.o headers.o sound.o -laudio -lm
770    
771     To make a library out of the sndlib files, first compile them as above,
772     then:
773    
774     ld -r audio.o io.o headers.o sound.o -o sndlib.a
775     cc sndplay.c -o sndplay -O -DSGI sndlib.a -laudio -lm
776    
777     The full sequence in Linux:
778    
779     cc -c io.c -O -DLINUX
780     cc -c audio.c -O -DLINUX
781     cc -c headers.c -O -DLINUX
782     cc -c sound.c -O -DLINUX
783     cc sndplay.c -o sndplay -O -DLINUX audio.o io.o headers.o sound.o -lm
784    
785     ld -r audio.o io.o headers.o sound.o -o sndlib.a
786     cc sndplay.c -o sndplay -O -DLINUX sndlib.a -lm
787    
788     And on a NeXT:
789    
790     cc -c io.c -O -DNEXT
791     cc -c audio.c -O -DNEXT
792     cc -c headers.c -O -DNEXT
793     cc -c sound.c -O -DNEXT
794     cc sndplay.c -o sndplay -O -DNEXT audio.o io.o headers.o sound.o
795    
796     ld -r audio.o io.o headers.o sound.o -o sndlib.a
797     cc sndplay.c -o sndplay -O -DNEXT sndlib.a
798    
799     Some similar sequence should work on a Sun (-DSOLARIS) or in HP-UX (-DHPUX).
800     On a Mac, you need to make a project in CodeWarrior or whatever that
801     includes all the basic sndlib .c and .h files (io.c, audio.c headers.c,
802     sound.c, sndlib.h) as source files. Add the main program you're interested
803     in (say sndplay.c), and "Make" the project. When the project is "Run", a
804     dialog pops up asking for the arguments to the program (in this case the
805     name of the file to be played, as a quoted string). In Windoze, you can use
806     the C IDE (a project builder as in the Mac case), or run the compiler from a
807     DOS shell. In the latter case, (in Watcom C) cl io.c -c -DWINDOZE to create
808     the object files (io.obj and so on), then
809    
810     cl sndplay sndplay.obj -DWINDOZE audio.obj io.obj headers.obj sound.obj
811    
812     or in MS C
813    
814     cl -c io.c -DWINDOZE
815     (and so on)
816     cl sndplay.c -DWINDOZE sndplay.obj audio.obj io.obj headers.obj sound.obj winmm.lib
817    
818     or in gcc (available via the cygwin project)
819    
820     gcc -c io.c -DWINDOZE -O2
821    
822     You can run the program from the DOS shell (sndplay oboe.snd or
823     ./sndplay.exe oboe.snd). On a Be, you can either build a project or use a
824     makefile. The C compiler's name is mwcc. The tricky part here is that you
825     have to find and include explicitly the Be audio library, libmedia.so --
826     look first in beos/system/lib. Or
827    
828     make sndplay
829    
830     To make sndlib into a shared library,
831    
832     ld -shared io.o headers.o audio.o sound.o -o sndlib.so
833    
834     (in Linux), or (to include the CLM module),
835    
836     ld -shared io.o headers.o audio.o sound.o clm.o -o sndlib.so
837    
838     ------------------------------------------------------------------------
839    
840     Current Status
841    
842     System SndSine SndInfo Audinfo SndPlay SndRecord CLM
843     NeXT 68k ok ok ok ok ok ok
844     NeXT Intel ok ok ok interruptionsruns (*) untried
845     SGI old and new
846     AL ok ok ok ok ok ok
847     OSS (Linux et
848     al) ok ok ok ok ok ok
849     Be ok ok ok ok ok untried
850     Mac ok ok ok ok ok ok
851    
852     Windoze ok ok ok ok not ok
853     written
854     Sun ok ok ok ok runs (*) ok
855     HPUX untested untested untested untested untested untried
856    
857     MkLinux/LinuxPPCok ok ok ok untested ok
858     (**)
859     ALSA untested untested untested untested untested untested
860    
861     (*) I can't find a microphone.
862     (**) Last I looked, recording was still not supported in this OS.
863    
864     headers supported read/write
865     NeXT/Sun/DEC/AFsp
866     AIFF/AIFC
867     RIFF (Microsoft wave)
868     IRCAM (old style)
869     NIST-sphere
870     no header
871     headers supported read-only
872     8SVX (IFF), IRCAM Vax float, EBICSF, INRS, ESPS,
873     SPPACK, ADC (OGI), AVR, VOC,
874     Sound Tools, Turtle Beach SMP, SoundFont 2.0,
875     Sound Designer I and II, PSION, MAUD, Kurzweil 2000,
876     Tandy DeskMate, Gravis Ultrasound, ASF,
877     Comdisco SPW, Goldwave sample, omf, quicktime
878     Sonic Foundry, SBStudio II, Delusion digital,
879     Digiplayer ST3, Farandole Composer WaveSample,
880     Ultratracker WaveSample, Sample Dump exchange,
881     Yamaha SY85, SY99, and TX16, Covox v8, SPL, AVI,
882    
883     Incomplete: OMF, AVI, ASF, QuickTime, SoundFont 2.0.
884     Not handled: Esignal, ILS, HTK, DVSM, SoundEdit.
885     Handled by Snd: Mus10, IEEE text, HCOM, various compression schemes.
886    
887     Lower Levels
888    
889     If you'd like to go below the "sound" interface described above, the
890     following functions are exported from sndlib. You need to remember to call
891     sndlib_initialize (or the underlying initializers) before using these
892     functions (this is normally done for you by the various "sound_" functions).
893    
894     int mus_read_header (char *name)
895     int mus_write_header (char *name, int type, int in_srate, int in_chans, int loc, int size, int format, char *comment, int len)
896     int mus_update_header (char *name, int type, int size, int srate, int format, int chans, int loc)
897     int mus_header_writable(int type, int format)
898    
899     These read and write a sound file's header. The loc parameter is normally 0
900     (the data location depends on many things -- you'd normally write the
901     header, then use mus_header_data_location to get the resultant data
902     location). len is the length (bytes) of comment. mus_update_header is
903     normally used only to set the file size after the sound has been written.
904     mus_header_writable returns 1 if the given combination of header type and
905     data format can be handled by sndlib. If you already have the file
906     descriptor (as returned by open), the corresponding lower level calls are:
907    
908     int mus_read_header_with_fd (int fd)
909     int mus_write_header_with_fd (int fd, int type, int in_srate, int in_chans, int loc, int size, int format, char *comment, int len)
910     int mus_update_header_with_fd (int fd, int type, int siz)
911    
912     Once mus_read_header has been called, the data in it can be accessed
913     through:
914    
915     int mus_header_samples (void) samples
916     int mus_header_frames (void) frames (samples / chans)
917     int mus_header_data_location (void) location of data (bytes)
918     int mus_header_chans (void) channels
919     int mus_header_srate (void) srate
920     int mus_header_type (void) header type (i.e. aiff, wave, etc) (see sndlib.h)
921     int mus_header_format (void) data format (see sndlib.h)
922     int mus_header_distributed (void) true if header info is scattered around in the file
923     int mus_header_comment_start (void) comment start location (if any) (bytes)
924     int mus_header_comment_end (void) comment end location
925     int mus_header_aux_comment_start (int n) if multiple comments, nth start location
926     int mus_header_aux_comment_end (int n) if multiple comments, nth end location
927     int mus_header_type_specifier (void) original (header-specific) type ID
928     int mus_header_bits_per_sample (void) sample width in bits
929     int mus_true_file_length (void) true (lseek) file length
930     int mus_header_format2bytes (void) sample width in bytes
931     int mus_header_aiff_p(void) is header actually old-style AIFF, not AIFC
932     char *mus_header_type2string (int type) sound_type_name
933     char *mus_header_data_format2string (int format) sound_format_name
934    
935     Various less useful header fields are accessible: see headers.c or sndlib.h
936     for details. The next functions handle various IO calls:
937    
938     int mus_open_read (char *arg) open file read-only
939     int mus_probe_file (char *arg) return 1 if file exists
940     int mus_open_write (char *arg) open file read-write, creating it if necessary, else truncating
941     int mus_create (char *arg) create file
942     int mus_reopen_write (char *arg) open file read-write without changing anything
943     int mus_close (int fd) close file
944     long mus_seek (int tfd, long offset, int origin)
945     int mus_seek_frame (int tfd, int frame) go to a specific frame in file
946     int mus_read (int fd, int beg, int end, int chans, int **bufs)
947     int mus_read_chans (int fd, int beg, int end, int chans, int **bufs, int *cm)
948     int mus_read_any (int tfd, int beg, int chans, int nints, int **bufs, int *cm)
949     int mus_write_zeros (int tfd, int num)
950     int mus_write (int tfd, int beg, int end, int chans, int **bufs)
951     int mus_float_sound (char *charbuf, int samps, int charbuf_format, float *buffer)
952     int mus_unshort_sound (short *in_buf, int samps, int new_format, char *out_buf)
953     int sound_max_amp (char *ifile, int *vals)
954    
955     If you're trying to deal with various data types yourself, the following
956     functions may be useful; they perform various byte-order-aware type
957     conversions:
958    
959     void mus_set_big_endian_int (unsigned char *j, int x)
960     int mus_big_endian_int (unsigned char *inp)
961     void mus_set_little_endian_int (unsigned char *j, int x)
962     int mus_little_endian_int (unsigned char *inp)
963     int mus_uninterpreted_int (unsigned char *inp)
964     void mus_set_big_endian_float (unsigned char *j, float x)
965     float mus_big_endian_float (unsigned char *inp)
966     void mus_set_little_endian_float (unsigned char *j, float x)
967     float mus_little_endian_float (unsigned char *inp)
968     void mus_set_big_endian_short (unsigned char *j, short x)
969     short mus_big_endian_short (unsigned char *inp)
970     void mus_set_little_endian_short (unsigned char *j, short x)
971     short mus_little_endian_short (unsigned char *inp)
972     void mus_set_big_endian_unsigned_short (unsigned char *j, unsigned short x)
973     unsigned short mus_big_endian_unsigned_short (unsigned char *inp)
974     void mus_set_little_endian_unsigned_short (unsigned char *j, unsigned short x)
975     unsigned short mus_little_endian_unsigned_short (unsigned char *inp)
976     double mus_little_endian_double (unsigned char *inp)
977     double mus_big_endian_double (unsigned char *inp)
978     void mus_set_big_endian_double (unsigned char *j, double x)
979     void mus_set_little_endian_double (unsigned char *j, double x)
980     unsigned int mus_big_endian_unsigned_int (unsigned char *inp)
981     unsigned int mus_little_endian_unsigned_int (unsigned char *inp)
982    
983     Finally, a couple functions are provided to read and write sound files to
984     and from arrays:
985    
986     int mus_file2array (char *filename, int chan, int start, int samples, int *array)
987     int mus_array2file (char *filename, int *ddata, int len, int srate, int channels)
988    
989     Sndlib and Guile
990    
991     Much of sndlib is accessible at run time in any program that has Guile; the
992     modules sndlib2scm and clm2scm tie most of the library into Scheme making it
993     possible to call the library functions from Guile. The documentation is
994     scattered around, unfortunately: the clm side is in clm.html and extsnd.html
995     with many examples in Snd's examp.scm. Most of these are obvious
996     translations of the constants and functions described above into Scheme.
997    
998     snd-16-linear snd-16-linear-little-endian snd-24-linear snd-24-linear-little-endian
999     snd-32-float snd-32-float-little-endian snd-32-linear snd-32-linear-little-endian
1000     snd-64-double snd-64-double-little-endian snd-8-alaw snd-8-linear
1001     snd-8-mulaw snd-8-unsigned snd-16-unsigned snd-16-unsigned-little-endian
1002    
1003     next-sound-file nist-sound-file aiff-sound-file ircam-sound-file raw-sound-file riff-sound-file
1004    
1005     sndlib-default-device sndlib-read-write-device sndlib-line-out-device
1006     sndlib-line-in-device sndlib-microphone-device sndlib-speakers-device
1007     sndlib-dac-out-device sndlib-adat-in-device sndlib-aes-in-device
1008     sndlib-digital-in-device sndlib-digital-out-device sndlib-adat-out-device
1009     sndlib-aes-out-device sndlib-dac-filter-device sndlib-mixer-device
1010     sndlib-line1-device sndlib-line2-device sndlib-line3-device
1011     sndlib-aux-input-device sndlib-cd-in-device sndlib-aux-output-device
1012     sndlib-spdif-in-device sndlib-spdif-out-device
1013    
1014     sndlib-amp-field sndlib-srate-field sndlib-channel-field
1015     sndlib-format-field sndlib-device-field sndlib-imix-field
1016     sndlib-igain-field sndlib-reclev-field sndlib-pcm-field
1017     sndlib-pcm2-field sndlib-ogain-field sndlib-line-field
1018     sndlib-mic-field sndlib-line1-field sndlib-line2-field
1019     sndlib-line3-field sndlib-synth-field sndlib-bass-field
1020     sndlib-treble-field sndlib-cd-field
1021    
1022     sound-samples (filename) samples of sound according to header (can be incorrect)
1023     sound-frames (filename) frames of sound according to header (can be incorrect)
1024     sound-duration (filename) duration of sound in seconds
1025     sound-datum-size (filename) bytes per sample
1026     sound-data-location (filename) location of first sample (bytes)
1027     sound-chans (filename) number of channels (samples are interleaved)
1028     sound-srate (filename) sampling rate
1029     sound-header-type (filename) header type (e.g. aiff-sound-file)
1030     sound-data-format(filename) data format (e.g. 16-linear)
1031     sound-length (filename) true file length (bytes)
1032     sound-type-specifier (filename) original header type identifier
1033     sound-max-amp(filename) returns a vector of max amps and locations thereof
1034    
1035     sound-type-name (type) e.g. "AIFF"
1036     sound-format-name (format) e.g. "16-bit big endian linear"
1037     sound-comment (filename) header comment, if any
1038     sound-bytes-per-sample (format) bytes per sample
1039    
1040     audio-error () returns error code indicated by preceding audio call
1041     audio-error-name(err) string decription of error code
1042     describe-audio () describe audio hardware state
1043     report-audio-state() return audio hardware state as a string
1044     set-oss-buffers (num size) in Linux (OSS) sets the number and size of the OSS "fragments"
1045     audio-outputs(speaker, headphones, line-out) On the Sun, cause output to go to the chosen devices
1046    
1047     open-sound-input (filename) open filename (a sound file) returning an integer ("fd" below)
1048     open-sound-output (filename srate chans data-format header-type comment)
1049     create a new sound file with the indicated attributes, return "fd"
1050     reopen-sound-output (filename chans data-format header-type data-location)
1051     reopen (without disturbing) filename, ready to be written
1052     close-sound-input (fd) close sound file
1053     close-sound-output (fd bytes) close sound file and update its length indication, if any
1054     read-sound (fd beg end chans sdata) read data from sound file fd from frame beg to end
1055     sdata is a sound-data object that should be able to accomodate the read
1056     write-sound (fd beg end chans sdata) write data to sound file fd
1057     seek-sound (fd offset origin) complicated -- see seek_sound above
1058     seek-sound-frame (fd frame) move to frame in sound file fd
1059    
1060     open-audio-output (device srate chans format bufsize)
1061     open audio port device ready for output with the indicated attributes
1062     open-audio-input (device srate chans format bufsize)
1063     open audio port device ready for input with the indicated attributes
1064     write-audio (line sdata frames) write frames of data from sound-data object sdata to port line
1065     read-audio (line sdata frames) read frames of data into sound-data object sdata from port line
1066     close-audio (line) close audio port line
1067     read-audio-state (device field channel vals)
1068     read current state of device's field -- see read_audio_state above.
1069     write-audio-state (device field channel vals)
1070     write new state for device's field -- see write_audio_state above.
1071     audio-systems () returns how many separate "systems" (soundcards) it can find
1072     save-audio-state () write current audio state to .mixer or whatever
1073     restore-audio-state () read previously stored audio state
1074    
1075     make-sound-data (chans, frames) return a sound-data object with chans arrays, each of length frames
1076     sound-data-ref (obj chan frame) return (as a float) the sample in channel chan at location frame
1077     sound-data-set! (obj chan frame val) set obj's sample at frame in chan to (the float) val
1078     sound-data? (obj) #t if obj is of type sound-data
1079     sound-data-length (obj) length of each channel of data in obj
1080     sound-data-chans (obj) number of channels of data in obj
1081     sound-data->vct (sdobj chan vobj) place sound-data channel data in vct
1082     vct->sound-data (vobj sdobj chan) place vct data in sound-data
1083    
1084     ;;; this function prints header information
1085     (define info
1086     (lambda (file)
1087     (string-append
1088     file
1089     ": chans: " (number->string (sound-chans file))
1090     ", srate: " (number->string (sound-srate file))
1091     ", " (sound-type-name (sound-header-type file))
1092     ", " (sound-format-name (sound-data-format file))
1093     ", len: " (number->string
1094     (/ (sound-samples file)
1095     (* (sound-chans file) (sound-srate file)))))))
1096    
1097     ;;; this function reads the first 32 samples of a file, returning the 30th in channel 0
1098     (define read-sample-30
1099     (lambda (file)
1100     (let* ((fd (open-sound-input file))
1101     (chans (sound-chans file))
1102     (data (make-sound-data chans 32)))
1103     (read-sound fd 0 31 chans data)
1104     ;; we could use sound-data->vct here to return all the samples
1105     (let ((val (sound-data-ref data 0 29)))
1106     (close-sound-input fd)
1107     val))))
1108    
1109     ;;; here we get the microphone volume, then set it to .5
1110     (define vals (make-vector 32))
1111     (read-audio-state sndlib-microphone-device sndlib-amp-field 0 vals)
1112     (vector-ref vals 0)
1113     (vector-set! vals 0 .5)
1114     (write-audio-state sndlib-microphone-device sndlib-amp-field 0 vals)
1115    
1116     ;;; this function plays a sound (we're assuming that we can play 16-bit linear little-endian data)
1117     (define play-sound
1118     (lambda (file)
1119     (let* ((sound-fd (open-sound-input file))
1120     (chans (sound-chans file))
1121     (frames (sound-frames file))
1122     (bufsize 256)
1123     (data (make-sound-data chans bufsize))
1124     (bytes (* bufsize chans 2)))
1125     (read-sound sound-fd 0 (1- bufsize) chans data)
1126     (let ((audio-fd (open-audio-output sndlib-default-device (sound-srate file) chans snd-16-linear-little-endian bytes)))
1127     (do ((i 0 (+ i bufsize)))
1128     ((>= i frames))
1129     (write-audio audio-fd data bufsize)
1130     (read-sound sound-fd 0 (1- bufsize) chans data))
1131     (close-sound-input sound-fd)
1132     (close-audio audio-fd)))))