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;
}
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.
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.
来源:https://stackoverflow.com/questions/21755629/ios-audio-unit-cut-sound-above-some-frequency