ResamplingAudioSource Silence


#1

Hey all.

I have a distortion plugin that I’m working on for which I’d like to oversample (the distortion process is introducing aliasing). As a first step, I wanted to stick a ResamplingAudioSource at the end of my AudioSource signal chain and set the resamplingRatio to 1.0 just to verify that I could get my signal flowing through the ResamplingAudioSource…

So I did that, but no matter what I try, I just get silence coming out of the ResamplingAudioSource. I’ve tried narrowing down the problem but I can’t even seem to find a small case that works, however, as long as I take the ResamplingAudioSource out of the chain (no matter where I tried to put it) I get signal flowing as expected.

I’m not sure how to explain this any better than to provide a diff of my working tree:

diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp
index fcb4b20..2a3a8c3 100644
--- a/Source/PluginProcessor.cpp
+++ b/Source/PluginProcessor.cpp
@@ -32,8 +32,10 @@ MxzeroAudioProcessor::MxzeroAudioProcessor()
     waveshaper = new WaveshaperAudioSource(identitySource, false);
     smoothingFilter = new PoleZeroFilterAudioSource(waveshaper, false);
-    dcBlocker = new PoleZeroFilterAudioSource(smoothingFilter, false);
+    downsampler = new ResamplingAudioSource(smoothingFilter, false);
+    dcBlocker = new PoleZeroFilterAudioSource(downsampler, false);
 
+    downsampler->setResamplingRatio(1.0);
     dcBlocker->setBlockZero();
 
     // Set up the rotary parameters
@@ -137,6 +139,7 @@ void MxzeroAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock
     waveshaper->prepareToPlay(samplesPerBlock, sampleRate);
     smoothingFilter->prepareToPlay(samplesPerBlock, sampleRate);
     dcBlocker->prepareToPlay(samplesPerBlock, sampleRate);
+    downsampler->prepareToPlay(samplesPerBlock, sampleRate);
 }
 
 void MxzeroAudioProcessor::releaseResources()
@@ -147,6 +150,7 @@ void MxzeroAudioProcessor::releaseResources()
     smoothingFilter->releaseResources();
     dcBlocker->releaseResources();
+    downsampler->releaseResources();
 }
 
 #ifndef JucePlugin_PreferredChannelConfigurations

And then in my processBlock method I ask the dcBlocker to getNextAudioBlock. The change seems really simple I have no idea why I’m getting silence; has anybody experienced trouble like this here?

Any input here would be greatly appreciated. Thank you!

EDIT: If it’s helpful to see the header file changes, I’d be happy to add that here too. All I’ve done is add a private member variable ScopedPointer<ResamplingAudioSource> downsampler.


#2

I think I found my issue, but it begs another question.

The way I’ve wired up my AudioSource chain ultimately ends up with a little module I’m calling an IdentitySource.

AudioProcessor::processBlock -> dcBlocker->getNextAudioBlock -> waveshaper->getNextAudioBlock -> ... -> identitySource->getNextAudioBlock.

The IdentitySource is an AudioSource whose sole responsibility is to pass back the buffer that was passed to it, or rather, just perform a no-op on the input buffer. This was my attempt at beginning the AudioSource chain with “use what’s already in the buffer,” as the buffer that ends up going to the identity source is the same buffer that came into AudioProcessor::processBlock, therefore the relevant input data is already in the buffer.

That has served me fine so far, but now I believe what’s happening is that I’m asking the ResamplingAudioSource to fill a buffer of size N (containing input information), and the ResamplingAudioSource implementation then asks its input to fill a new (empty) buffer of size M so that it can resample M samples to fill an N-sample buffer. Which means that eventually my identity source is receiving the empty buffer prepared by the ResamplingAudioSource, and just turning it around and sending it back. So the input data never makes it through the ResamplingAudioSource the way I had intended.

I can get around that by saving a copy of the input data received in processBlock into a temporary buffer and then feeding those temporary buffer contents back out in the identitySource’s getNextAudioBlock method. But that leads me to the following question: if my AudioProcessor is given a buffer of 512 samples, already containing input information, and I try to resample it with a ResamplingAudioSource at a resamplingRatio of 1.0, the ResamplingAudioSource asks its input for 515 samples. Where should I get those 3 extra samples from? Obviously I can’t just make up input data. Does that make sense? I can’t tell if I just rambled here.

Thanks.

EDIT: I verified my hunch there by copying the input buffer and replaying it from identitySource, and I realized that my second question was rather dumb. If the block size is 512 samples and my intention is to oversample, then I’ll need fewer than 512 samples to produce a higher-sample-rate block which my remaining AudioSource nodes can consume, and then downsample on the other end to fit back into the 512 block size that the AudioProcessor was expecting. :expressionless: Sorry for the rambling… Feel free to ignore this whole thing then (or delete it, mods). Cheers.