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