AudioTransportSource and clicks


#1

I'm using the AudioTransportSource and I'm finding it clicks when I seek since the buffers in the ResamplingAudioSource don't get cleared on seek. I'm guessing this isn't usually a big deal since seeking clicks anyway.

What I'm trying to do is fillup background buffers using the AudioTransportSource. I have a huge set of AudioSampleBuffers that my audio engine thread reads from. I have a background thread that looks at the current playhead position, loop points, etc and tries to intelegently guess what audio is likely to be needed soon and load it into the buffers. The background thread uses an AudioTransportSource to load the appropriate chunks of each file.

For example if the order of operations is:

setNextReadPosition: position 0 seconds
getNextAudioBlock: duration 2 seconds
setNextReadPosition: position 4 seconds
getNextAudioBlock: duation 2 seconds
setNextReadPosition: position 2 seconds
getNextAudioBlock: duration 2 seconds

Then I've read 3 audio blocks from the file out of order, but if I put the resulting audio blocks in order, there will be clicks, as the start of each audio block will have 1 or 2 samples of audio from then end of the previously audio block.

I think each time there is a seek, the resample buffers should get flushed. 


#2

I don't think that flushing the resamplers would help with that - they use an IIR filter, so they're always going to take a couple of samples to get rolling and start producing repeatable data. Flushing them with zeros would be no better than not flushing them at all - you'd need to roll back a few samples before the time that you need and then play forwards discarding samples for it to be able to jump around click-free.

But.. that's really not what the TransportSource is designed to do - it's intended for user-level seek operation, not to provide random access to its input stream. Perhaps you're using the wrong tool for the job?


#3

I probably am, but it doesn't look like juce has the right tool and I was trying to avoid writing something myself. 

When the project loads, I should probably create temporary versions of all my source files at the correct sample rate, and then random access will be a lot easier.

I don't flush the resamplers buffers with zeros, I just empty them. While it's not perfect, I think it's better than what it does now, which is return wrong data.

My changes are:

void ResamplingAudioSource::clearBuffers()
{
 const SpinLock::ScopedLockType sl (ratioLock);

 buffer.clear();
 sampsInBuffer = 0;
 bufferPos = 0;
 subSampleOffset = 0.0;

 filterStates.calloc ((size_t) numChannels);
 srcBuffers.calloc ((size_t) numChannels);
 destBuffers.calloc ((size_t) numChannels);
 createLowPass (ratio);
 resetFilters();
}

and


void AudioTransportSource::setNextReadPosition (int64 newPosition)
{
    if (positionableSource != nullptr)
    {
        if (sampleRate > 0 && sourceSampleRate > 0)
            newPosition = (int64) (newPosition * sourceSampleRate / sampleRate);
        positionableSource->setNextReadPosition (newPosition);
        
        if (resamplerSource)
            resamplerSource->clearBuffers();
        
        inputStreamEOF = false;
    }
}

#4

Ok, I've changed that now.

But.. I really don't think it's a wise choice to use it in this way. For example in the future a nice feature that could be added to the transport source would be to make it fade in/out when it skips position. That'd screw up what you're doing with it, because it really isn't designed to give a guarantee that the samples will be a direct mirrot of the input material at that sample position.