Documentation Index
Fetch the complete documentation index at: https://mintlify.com/csound/csound/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Csound uses two primary audio buffers:
- spin - Audio input buffer (software input)
- spout - Audio output buffer (software output)
These buffers allow external software to write audio into Csound before calling csoundPerformKsmps() and read audio from Csound afterward.
Buffer structure
Each buffer contains audio data for one control period (ksmps frames). The buffers are interleaved for multi-channel audio:
Mono: [sample0, sample1, sample2, ..., sample(ksmps-1)]
Stereo: [L0, R0, L1, R1, L2, R2, ..., L(ksmps-1), R(ksmps-1)]
Total buffer size = ksmps * nchnls * sizeof(MYFLT)
csoundGetSpin
MYFLT *csoundGetSpin(CSOUND *csound);
Returns the address of the Csound audio input working buffer (spin). Write audio data to this buffer before calling csoundPerformKsmps().
Pointer to the input audio buffer
uint32_t ksmps = csoundGetKsmps(csound);
MYFLT *spin = csoundGetSpin(csound);
csoundStart(csound);
while (!csoundPerformKsmps(csound)) {
// Write input audio samples
for (uint32_t i = 0; i < ksmps; i++) {
spin[i] = getNextInputSample();
}
// Process audio
csoundPerformKsmps(csound);
}
uint32_t ksmps = csoundGetKsmps(csound);
uint32_t nchnls_i = csoundGetChannels(csound, 1); // Input channels
MYFLT *spin = csoundGetSpin(csound);
csoundStart(csound);
while (!csoundPerformKsmps(csound)) {
// Write interleaved stereo input
for (uint32_t i = 0; i < ksmps; i++) {
spin[i * nchnls_i + 0] = getLeftInputSample();
spin[i * nchnls_i + 1] = getRightInputSample();
}
csoundPerformKsmps(csound);
}
Example: Audio callback integration
typedef struct {
CSOUND *csound;
MYFLT *spin;
const MYFLT *spout;
uint32_t ksmps;
uint32_t in_channels;
uint32_t out_channels;
} AudioContext;
void audio_callback(float *input, float *output,
unsigned int frames, void *user_data) {
AudioContext *ctx = (AudioContext*)user_data;
// Copy input to spin buffer
for (unsigned int i = 0; i < frames * ctx->in_channels; i++) {
ctx->spin[i] = (MYFLT)input[i];
}
// Process audio
csoundPerformKsmps(ctx->csound);
// Copy spout buffer to output
for (unsigned int i = 0; i < frames * ctx->out_channels; i++) {
output[i] = (float)ctx->spout[i];
}
}
csoundGetSpout
const MYFLT *csoundGetSpout(CSOUND *csound);
Returns the address of the Csound audio output working buffer (spout). Read audio data from this buffer after calling csoundPerformKsmps().
Pointer to the output audio buffer (read-only)
Example: Reading mono output
uint32_t ksmps = csoundGetKsmps(csound);
const MYFLT *spout = csoundGetSpout(csound);
csoundStart(csound);
while (!csoundPerformKsmps(csound)) {
csoundPerformKsmps(csound);
// Read output audio samples
for (uint32_t i = 0; i < ksmps; i++) {
writeOutputSample(spout[i]);
}
}
Example: Reading stereo output
uint32_t ksmps = csoundGetKsmps(csound);
uint32_t nchnls = csoundGetChannels(csound, 0); // Output channels
const MYFLT *spout = csoundGetSpout(csound);
csoundStart(csound);
while (!csoundPerformKsmps(csound)) {
csoundPerformKsmps(csound);
// Read interleaved stereo output
for (uint32_t i = 0; i < ksmps; i++) {
MYFLT left = spout[i * nchnls + 0];
MYFLT right = spout[i * nchnls + 1];
writeStereoPair(left, right);
}
}
Example: Recording to file
#include <sndfile.h>
typedef struct {
SF_INFO sfinfo;
SNDFILE *sndfile;
} RecordContext;
RecordContext* start_recording(CSOUND *csound, const char *filename) {
RecordContext *ctx = malloc(sizeof(RecordContext));
ctx->sfinfo.samplerate = (int)csoundGetSr(csound);
ctx->sfinfo.channels = csoundGetChannels(csound, 0);
ctx->sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
ctx->sndfile = sf_open(filename, SFM_WRITE, &ctx->sfinfo);
return ctx;
}
void record_loop(CSOUND *csound, RecordContext *rec) {
const MYFLT *spout = csoundGetSpout(csound);
uint32_t ksmps = csoundGetKsmps(csound);
uint32_t nchnls = csoundGetChannels(csound, 0);
uint32_t frame_size = ksmps * nchnls;
csoundStart(csound);
while (!csoundPerformKsmps(csound)) {
// Write audio frames to file
sf_writef_float(rec->sndfile, (const float*)spout, ksmps);
}
sf_close(rec->sndfile);
}
Example: Amplitude monitoring
MYFLT get_peak_amplitude(CSOUND *csound) {
const MYFLT *spout = csoundGetSpout(csound);
uint32_t ksmps = csoundGetKsmps(csound);
uint32_t nchnls = csoundGetChannels(csound, 0);
MYFLT peak = 0.0;
for (uint32_t i = 0; i < ksmps * nchnls; i++) {
MYFLT abs_sample = fabs(spout[i]);
if (abs_sample > peak) {
peak = abs_sample;
}
}
return peak;
}
// Usage
csoundStart(csound);
while (!csoundPerformKsmps(csound)) {
csoundPerformKsmps(csound);
MYFLT peak = get_peak_amplitude(csound);
MYFLT dbfs = csoundGet0dBFS(csound);
MYFLT db = 20.0 * log10(peak / dbfs);
printf("Peak: %.2f dB\n", db);
}
Important notes
The spin and spout pointers remain valid for the lifetime of the Csound instance but may be reallocated if csoundReset() is called.
Buffer access is not thread-safe. Ensure synchronization if accessing buffers from multiple threads.
Buffer timing
The correct order of operations is:
- Write to
spin buffer (input)
- Call
csoundPerformKsmps()
- Read from
spout buffer (output)
- Repeat
Zero initialization
The spin buffer should be filled with data before each call to csoundPerformKsmps(). If no input is needed, fill with zeros:
uint32_t ksmps = csoundGetKsmps(csound);
uint32_t nchnls_i = csoundGetChannels(csound, 1);
MYFLT *spin = csoundGetSpin(csound);
memset(spin, 0, ksmps * nchnls_i * sizeof(MYFLT));