Compare two input channels


#1

Hi! I guess that newbie questions are nerve consuming, but i couldn’t find solution in tutorials or documentation. I must warn you that i’m newbie in c++ too, so it could be annoying… sorry…:).
I’m trying to compare two input signals in frequency domain and i made code based on SimpleFFTExample. For input i use two channels (for compare).But… there is many examples with getNextAudioBlock function, and there are always two “for loops”, first one that iterrate channels, and other, nested, that itterate samples. My question is, if i wait for one input channel that fills 480 samples (default) in buffer, and then second to fill next 480 samples in buffer, and so on… there is a lot of delay, so what’s approach in this situation, where i need to fill two buffers sample by sample…


#2

Well, your question is a bit cryptic, you should try rewriting and maybe attach some code to it :slight_smile:
But I’ll try to answer from what I got…

The AudioBuffer offers you methods for copying from another buffer directly, without iterating over samples. Also, the AudioBuffer supports multiple channels, you don’t need multiple buffers for that.

By comparing 2 channels you mean cross-correlation?
If so, you definitely don’t need 2 buffers for that :slight_smile:

As I said, it is a bit hard for me to get what you’re trying to do and which problens you’re facing.
Try explaining better and put some code too :slight_smile:


#3

Hi, thanks for quick response,… and yes, i would like to do cross-correlation, and also want to calculate phase difference… My starting point was SimpleFFTExample…, so i just wrap one for loop with “channel loop” like:

	for (int channel = 0; channel < bufferToFill.buffer->getNumChannels(); ++channel)
	{
		float* const buffer = bufferToFill.buffer->getWritePointer(channel, bufferToFill.startSample);		
		for (int i = 0; i < bufferToFill.numSamples; ++i)			
				mainView.pushNextSampleIntoFifo(buffer[i], channel);							
	}

but guess that i started with wrong example, and should do more reading and try more examples on AudioBuffer class (like https://juce.com/doc/tutorial_looping_audio_sample_buffer ??)


#4

I just looked up a cross correlation from a currently paused project:

float MyAudioProcessor::getCorellation (AudioSampleBuffer& buffer,
                                        const int channelA, const float meanA,
                                        const int channelB, const float meanB)
{
    const int numSamples = buffer.getNumSamples();
    const float* ptrA = buffer.getReadPointer (channelA);
    const float* ptrB = buffer.getReadPointer (channelB);
    float sum (0);
    float sumA (0);
    float sumB (0);
    float varA, varB;
    for (int i=0; i < numSamples; ++i) {
        varA = *(++ptrA) - meanA;
        varB = *(++ptrB) - meanB;
        sum += varA * varB;
        sumA += varA * varA;
        sumB += varB * varB;
    }
    return sum / sqrtf (sumA * sumB);
}

Very brutal but working code… I think I will optimise that in the coming days… But it gives you a starting point…

Note: I compute meanA and meanB outside, because I average over bigger blocks, in case you have small block sizes, when the mean value becomes unsteady
Note 2: in case you wonder: mean is synonym to RMS, so you can use AudioBuffer::getRMSLevel()


#5

There you go, @daniel saves the day again!!! hahahahaha


#6

Thanks!
G.


#7

I’m just curious @daniel. Do you keep an auxiliary FIFO or circular buffer to calculate the RMS?


#8

I use the getRMSLevel() per block, and stuff it in a little template, that keeps the average. I don’t know if it makes much sense, but I wanted to avoid summing all elements each time, so this is some kind of FIFO :wink:

template <typename FloatType, size_t num>
class AveragedValue {
public:
    AveragedValue ()
    : samplesPtr (0)
    {
        reset();
    }

    void reset (const FloatType initial=0.0)
    {
        samplesPtr = 0;
        for (int i=0; i < num; ++i) {
            samples [i] = initial;
        }
        sum = num * initial;
    }

    FloatType averaged (FloatType value)
    {
        sum -= samples [samplesPtr];
        samples [samplesPtr++] = value;
        samplesPtr %= num;
        sum += value;
        return sum / static_cast<FloatType> (num);
    }

    FloatType averaged ()
    {
        return sum / static_cast<FloatType> (num);
    }


private:
    FloatType samples[num];
    FloatType sum;
    int       samplesPtr;
};

#9

I’m used to calling this a ring buffer… but I’m not sure about the orthodox terminology hehehehe

Anyways, nice code! Thanks for sharing!


#10

No you’re absolutely right… my bad, was only half present, my mind was somewhere else :-/


#11

hahahaha… no worries… after a few beers FIFO and ring buffers all look the same