3

I have some problem with received sound (UDP WiFi) and I want clear it as much as I can. So at start I want cut off sounds above some frequency. Clearly I got raw data from socket, then I copy it to output buffer. I'm sure that exact cut off should be done right there.

Could You suggest me?

My current callback code

static OSStatus outputCallback(void *udata,
                               AudioUnitRenderActionFlags *flags,
                               const AudioTimeStamp *ts,
                               UInt32 busnum,
                               UInt32 nframes,
                               AudioBufferList *buflist) {

    NXAudioDevice *dev = (__bridge NXAudioDevice *) udata;
    AudioBuffer *buf = buflist->mBuffers;
    // Here I get new audioBufferData
    NSData *data = [dev getAudioData];
    if (!data) {
        buf->mDataByteSize = 0;
        return -1;
    } else {
        [data getBytes:buf->mData length:buf->mDataByteSize];
    }

    return noErr;
}

UPDATE

I found something like this for render callback, atm I want add something similar for outputCallback.

OSStatus RenderFFTCallback (void                    *inRefCon,
                            AudioUnitRenderActionFlags  *ioActionFlags,
                            const AudioTimeStamp            *inTimeStamp,
                            UInt32                      inBusNumber,
                            UInt32                      inNumberFrames,
                            AudioBufferList             *ioData)
{
    RIOInterface* THIS = (RIOInterface *)inRefCon;
    COMPLEX_SPLIT A = THIS->A;
    void *dataBuffer = THIS->dataBuffer;
    float *outputBuffer = THIS->outputBuffer;
    FFTSetup fftSetup = THIS->fftSetup;

    uint32_t log2n = THIS->log2n;
    uint32_t n = THIS->n;
    uint32_t nOver2 = THIS->nOver2;
    uint32_t stride = 1;
    int bufferCapacity = THIS->bufferCapacity;
    SInt16 index = THIS->index;

    AudioUnit rioUnit = THIS->ioUnit;
    OSStatus renderErr;
    UInt32 bus1 = 1;

    renderErr = AudioUnitRender(rioUnit, ioActionFlags,
                                inTimeStamp, bus1, inNumberFrames, THIS->bufferList);
    if (renderErr < 0) {
        return renderErr;
    }

    // Fill the buffer with our sampled data. If we fill our buffer, run the
    // fft.
    int read = bufferCapacity - index;
    if (read > inNumberFrames) {
        memcpy((SInt16 *)dataBuffer + index, THIS->bufferList->mBuffers[0].mData, inNumberFrames*sizeof(SInt16));
        THIS->index += inNumberFrames;
    } else {
        // If we enter this conditional, our buffer will be filled and we should
        // perform the FFT.
        memcpy((SInt16 *)dataBuffer + index, THIS->bufferList->mBuffers[0].mData, read*sizeof(SInt16));

        // Reset the index.
        THIS->index = 0;

        /*************** FFT ***************/
        // We want to deal with only floating point values here.
        ConvertInt16ToFloat(THIS, dataBuffer, outputBuffer, bufferCapacity);

        /**
         Look at the real signal as an interleaved complex vector by casting it.
         Then call the transformation function vDSP_ctoz to get a split complex
         vector, which for a real signal, divides into an even-odd configuration.
         */
        vDSP_ctoz((COMPLEX*)outputBuffer, 2, &A, 1, nOver2);

        // Carry out a Forward FFT transform.
        vDSP_fft_zrip(fftSetup, &A, stride, log2n, FFT_FORWARD);

        // The output signal is now in a split real form. Use the vDSP_ztoc to get
        // a split real vector.
        vDSP_ztoc(&A, 1, (COMPLEX *)outputBuffer, 2, nOver2);

        // Determine the dominant frequency by taking the magnitude squared and
        // saving the bin which it resides in.
        float dominantFrequency = 0;
        int bin = -1;
        for (int i=0; i<n; i+=2) {
            float curFreq = MagnitudeSquared(outputBuffer[i], outputBuffer[i+1]);
            if (curFreq > dominantFrequency) {
                dominantFrequency = curFreq;
                bin = (i+1)/2;
            }
        }
        memset(outputBuffer, 0, n*sizeof(SInt16));

        // Update the UI with our newly acquired frequency value.
        [THIS->listener frequencyChangedWithValue:bin*(THIS->sampleRate/bufferCapacity)];
        printf("Dominant frequency: %f   bin: %d \n", bin*(THIS->sampleRate/bufferCapacity), bin);


    }

    return noErr;
}
Błażej
  • 3,617
  • 7
  • 35
  • 62

2 Answers2

1

That is not as easy as it may seem. One approach would be to use a FFT to move the data into the frequency domain, remove the high frequencies and then move back to the time domain with a reverse FFT. There are FFT functions available in iOS. See Using Fourier Transforms vDSP Programming Guide.

One starting point is Apple's sample code aurioTouch2.

In answer to a comment: A byte does not have a frequency, just an amplitude (loudness). Basically there are amplitude samples at a periodic rate such as 44100Hz. A naive approach to lowpass audio would be to remove every other sample but that does not work, it just aliases the higher frequencies into lower frequencies.

zaph
  • 111,848
  • 21
  • 189
  • 228
1

You can use AudioUnit to do this:

@constant       kAudioUnitSubType_LowPassFilter         
                A filter that passes frequencies below a specified cut-off frequency

@constant       kAudioUnitSubType_HighPassFilter        
                A filter that passes frequencies above a specified cut-off frequency

@constant       kAudioUnitSubType_BandPassFilter        
                A filter that passes frequencies between a low and high cut-off frequency.
  • So this will affect on renderCallback and outputCallback? – Błażej Feb 17 '14 at 12:04
  • Because I use something like that `AudioUnitSetParameter(ioUnit,kAudioUnitSubType_LowPassFilter,kAudioUnitScope_Global,0,150,0);` and check with updated renderCallback (in question) and I got frequency above 150. – Błażej Feb 17 '14 at 12:12
  • @Dudi , you cannot use `kAudioUnitSubType_LowPassFilter` as parameter for ioUnit in case `kAudioUnitSubType_LowPassFilter` is kind of AudioUnit. You need to make AUGraph with IO-AU and LowPassFilter-AU or init LowPassFilter-AU standalone and call `AudioUnitRender` manually. – Aliaksandr Andrashuk Feb 17 '14 at 18:05
  • @Aliksandr Andrashuk Do you have could you pass some example code how to use it? I use google but there isn't much of it. – Błażej Feb 18 '14 at 10:24
  • 1
    I found similar question http://stackoverflow.com/questions/11117375/how-do-i-apply-effect-to-mic-inputios-core-audio-audio-graph but conclusion in comment `RemoteIO->Converter->Effect->Converer->RemoteIO` is not telling me much :( – Błażej Feb 18 '14 at 12:56