What would be the right way to read the samples from host’s audio callback IO buffer into a Csound object, process them and write them back, but with different sizes of ksmps and host’s IO buffer?
I.e. if a host’s audio callback has an i.e. 512 frame samples and Csound object has 256 ksmps.
The most logical way would be to simply make two iterations of usual steps:
read ksmps number of values from host’s input buffer and write them into Csound Spin buffer
make PerformKsmps()
read result values from Csound Spout buffer and write them to the host’s output buffer
However, that doesn’t work as expected, for some reason I get corrupted audio.
On the other hand, if ksmps size matches host’s IO buffer then everything works perfectly (of course in this case it involves only one iteration through the above steps).
Hi @Lovre The steps you outline should work fine. Here is what I typically do with the JUCE process routine. Note that Csound buffer, and the host buffer uses independent sample positions. This ensures everything works fine even if the host has a different buffer size to Csound’s ksmps.
float** ioBuffer = buffer.getArrayOfWritePointers();
const int channelNum = buffer.getNumChannels();
for (int i = 0; i < numSamples; i++, ++csndIndex)
{
if (csndIndex >= csdKsmps)
{
csound->PerformKsmps();
csndIndex = 0;
}
pos = csndIndex * channelNum;
for (int channel = 0; channel < getTotalNumOutputChannels(); channel++)
{
ioBuffer[channel][i] = CSspout[csndPosition] / cs_scale;
pos++;
}
}
Hi @rory! Yes, the steps I described above work fine, I made a rooky pointer mistake
Nevertheless, I took your code because it is more elegant than mine and I modified it a bit for my use case:
void getNextAudioBlock (const juce::AudioSourceChannelInfo& bufferToFill){
MYFLT* CSspout = _csound->GetSpout();
MYFLT* CSspin = _csound->GetSpin();
int numSamples = bufferToFill.numSamples;
int numChannels = bufferToFill.buffer->getNumChannels();
const float** ioBuffer_rd = bufferToFill.buffer->getArrayOfReadPointers();
float** ioBuffer_wr = bufferToFill.buffer->getArrayOfWritePointers();
int csndPosition = 0;
for (int sample = 0; sample < numSamples; sample++)
{
csndPosition = _csndIndex * numChannels;
// Step 1) write new sample frame into CSOUND Spin
for (int channel = 0; channel < numChannels; channel++)
CSspin[csndPosition + channel] = ioBuffer_rd[channel][sample] * cs_scale;
// Step 2) if csdKsmps frame samples are written in CSOUND Spin -> PerformKsmps
if (_csndIndex >= csdKsmps - 1)
{
_csound->PerformKsmps();
_csndIndex = 0;
}
else _csndIndex++;
csndPosition = _csndIndex * numChannels;
// Step 3) read result frames from CSOUND Spout
for (int channel = 0; channel < numChannels; channel++)
ioBuffer_wr[channel][sample] = CSspout[csndPosition+channel] / cs_scale;
}
}