alWriteBuffers(3dm) alWriteBuffers(3dm) NAME alWriteBuffers - write flexibly interleaved or non-interleaved audio data to an audio port SYNOPSIS #include <dmedia/audio.h> int alWriteBuffers(const ALport port, void **bufs, int *strides, const int framecount) PARAMETER port is the audio output port to which you want to write samples. This is the returned value of an alOpenPort(3dm) call. bufs is an array of pointers to sample buffers, each element of which corresponds to a single channel of audio output. strides is an array of integers, one corresponding to each output channel. Each element indicates the number of interleaved channels in the buffer directed at that channel. framecount is the number of sample frames that you want to write to the audio port. DESCRIPTION alWriteBuffers transfers data to an audio port from a set of buffers, or from different locations in a single buffer. alWriteBuffers allows the application to specify how the data is interleaved. bufs is an array of pointers to sample buffers. Each element of bufs corresponds to one output channel. If the element is 0, that channel will be zeroed on output. This allows an application to only direct audio at the channels of interest. The sample buffers can be arbitrarily interleaved; the strides parameter indicates the number of channels in each source sample buffer. For example, if strides[n] is 1, then bufs[n] is mono; if strides[n] is 2, then bufs[n] is interleaved stereo, and alWriteFrames will read every other sample from that buffer. The elements of strides can have any value. If strides is 0, all the sample buffers are considered mono, and alWriteBuffers does non-interleaved output. There must be exactly as many elements in bufs and strides as the number of channels specified for the port with alSetChannels(3dm). alWriteBuffers blocks until framecount sample frames have been written to the port. If you do not wish to block, make sure that framecount is less than the return value of alGetFillable(3dm). The expected format of each sample depends upon the configuration of the audio port. Each sample can be an 8-, 16-, or 32-bit integer, or a single- or double-precision floating-point value or subcode data; see alSetSampFmt(3dm) and alSetWidth(3dm) for a description of how these formats work. By default, the sample format is 16-bit integer (short). Note that since an audio port contains an internal queue, samples written to the port will not immediately come out the associated audio device or devices. For precise synchronization of audio and other media, use alGetFrameTime(3dm) and alGetFrameNumber(3dm) to determine when samples will actually be output. In order to achieve the best possible performance, alWriteBuffers does not attempt to verify that port, bufs, or strides are valid. You should make certain these values are valid before passing them as arguments to alWriteBuffers. EXAMPLES The following code fragment opens an 8-channel audio output port and writes 8 separate mono buffers to it. Then it mutes channels 3 and 5 and writes the same data. ALport p; short buf[8][1000]; void *bufs[8]; int i,j; ALconfig c; c = alNewConfig(); if (!c) { printf("config create failed:%s\n", alGetErrorString(oserror())); exit(-1); } alSetChannels(c, 8); /* open a port with our configuration */ p = alOpenPort("alWriteBuffers example","w",c); if (!p) { printf("port open failed:%s\n", alGetErrorString(oserror())); exit(-1); } /* * Fill our buffer. This isn't real audio data here; it's DC on each * channel. In a real application, we'd want more meaningful data in * each of the buffers. */ for (i = 0; i < 8; i++) { /* fill channel i */ for (j = 0; j < 1000; j++) { buf[i][j] = i * 2000; } bufs[i] = buf[i]; } alWriteBuffers(p, bufs, 0, 1000); /* write 1000 8-channel frames */ /* * Now mute channels 3 and 5 */ bufs[2] = 0; /* channel 3 */ bufs[4] = 0; /* channel 5 */ alWriteBuffers(p, bufs, 0, 1000); /* write 1000 8-channel frames */ } The following example writes a single 16-channel buffer to 2 8-channel devices. This is somewhat simplified, since it does not actually synchronize the audio between the devices. For examples of how to do that, see the example "scrub" in /usr/share/src/dmedia/audio. #include <audio.h> #define NPORTS 2 #define NCHANS_PER_PORT 8 #define BUF_NCHANS (NPORTS*NCHANS_PER_PORT) main() { ALport p[NPORTS]; float buf[1000 * BUF_NCHANS]; void *bufs[NPORTS][NCHANS_PER_PORT]; int strides[NCHANS_PER_PORT]; ALconfig c; int i, j, k = 0; /* * Set up an array of device resource ID's. To do multi-device * I/O meaningfully, we'd want these to be different resource ID's. * This here will open 2 ports to the same resource ID, and the * audio system will mix the 2 ports. */ int device[NPORTS]={AL_DEFAULT_OUTPUT, AL_DEFAULT_OUTPUT}; for (i = 0; i < 16000; i++) { buf[i] = (i & 15) * 1000.0; } c = alNewConfig(); if (!c) { printf("config create failed:%s\n", alGetErrorString(oserror())); exit(-1); } alSetChannels(c, NCHANS_PER_PORT); alSetFloatMax(c, 32767); alSetSampFmt(c, AL_SAMPFMT_FLOAT); /* * Let's assume that in this case we know our floating-point data * to be in range. We turn limiting off for (potentially) increased * performance. */ alSetLimiting(c, 0); /* * Set up bufs & strides to make different NCHANS-channel "windows" * into our buffer. */ k = 0; for (j=0; j < NPORTS; j++) { for (i=0; i < NCHANS_PER_PORT; i++) { bufs[j][i] = &buf[k++]; } } for (i=0; i < NCHANS_PER_PORT; i++) { strides[i] = BUF_NCHANS; /* 16, by default */ } /* * Open up NPORTS audio ports. Note that we aren't doing * anything special to synchronize the ports here; they won't * in general be sync'ed. */ for (i = 0; i < NPORTS; i++) { alSetDevice(c, device[i]); p[i] = alOpenPort("alWriteBuffers example","w",c); if (!p[i]) { printf("port open failed:%s\n", alGetErrorString(oserror())); exit(-1); } } /* * Write 1000 frames of data to all the audio ports */ while (1) for (i =0; i < NPORTS; i++) { alWriteBuffers(p[i], bufs[i], strides, 1000); } } DIAGNOSTICS alWriteBuffers always returns 0. NOTES On output, the data from all ports on the system writing to a particular output device will be mixed together, except in the case of subcode data. Because subcode data is treated as inherently logical information, no amount mathematics can be applied to perform operations such as mixing. This function was introduced via patch to IRIX 6.3 and 6.4, and is present by default in later OS releases. You should ensure that the target system will have the functionality before calling this function; otherwise, your program will crash when you attempt to make the function call. To determine if the feature is present, check the value of AL_VERSION on the system resource. The parameter must be present and its value must be at least 6. pv.param = AL_VERSION; alGetParams(AL_SYSTEM,&pv,1); if (pv.sizeOut < 0 || pv.value.i < 6) { /* feature not present */ } SEE ALSO alOpenPort(3dm), alGetFillable(3dm), alGetFilled(3dm), alSetChannels(3dm), alSetWidth(3dm), alReadFrames(3dm), alZeroFrames(3dm), alSetConfig(3dm), alSetQueueSize(3dm), alSetSampFmt(3dm), alSetFloatMax(3dm) Page 5