ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/PDL-Audio/sndlib/sndlib.txt
Revision: 1.1
Committed: Tue Dec 28 01:05:17 2004 UTC (19 years, 4 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

# Content
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)))))