ios - 从频域到时域

标签 ios audio avfoundation audiounit

基于我的 previous questionpitch detector在 GitHub 上。我设法检测到我的样本的主要频率是多少。但正如 Zaph 所说,切断整个样本是愚蠢的。我的问题是,如果我已经将样本从时域转换为频域,那么如何返回并将频率转换为时域?

我的接近时间->频率

ConvertInt16ToFloat(THIS, dataBuffer, outputBufferFrequency, bufferCapacity);

maxFrames = 32;
log2n = log2f(maxFrames);
n = 1 << log2n;
assert(n == maxFrames);
nOver2 = maxFrames/2;
bufferCapacity = maxFrames;
COMPLEX_SPLIT A;
A.realp = (float *)malloc(nOver2 * sizeof(float));
A.imagp = (float *)malloc(nOver2 * sizeof(float));
fftSetup = vDSP_create_fftsetup(log2n, FFT_RADIX2);

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;
    }
}

更新

//First faild approach to convert frequency->ti
vDSP_ctoz((COMPLEX*)outputBufferFrequency, 2, &A, 1, nOver2);

vDSP_fft_zrip(fftSetup, &A, stride, log2n, FFT_INVERSE);

vDSP_ztoc(&A, 1, (COMPLEX *)outputBufferFrequency, 2, nOver2);

ConvertFloatToInt16(THIS, outputBufferFrequency, outputBufferTime, bufferCapacity);    

// checking is preTimeToFrequency buffer is same as postTimeToFrequency buffer
// and is not, atm.
for (int i=0; i<bufferCapacity; i++) {
    printf("%i != %i",((SInt16*)dataBuffer)[i], ((SInt16*)outputBufferTime)[i]);
    if (((SInt16*)dataBuffer)[i] != ((SInt16*)outputBufferTime)[i]){
        printf("dupa\n");
    }
}

void ConvertInt16ToFloat(RIOInterface* THIS, void *buf, float *outputBuf, size_t capacity) {
    AudioConverterRef converter;
    OSStatus err;

    size_t bytesPerSample = sizeof(float);
    AudioStreamBasicDescription outFormat = {0};
    outFormat.mFormatID = kAudioFormatLinearPCM;
    outFormat.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked;
    outFormat.mBitsPerChannel = 8 * bytesPerSample;
    outFormat.mFramesPerPacket = 1;
    outFormat.mChannelsPerFrame = 1;
    outFormat.mBytesPerPacket = bytesPerSample * outFormat.mFramesPerPacket;
    outFormat.mBytesPerFrame = bytesPerSample * outFormat.mChannelsPerFrame;
    outFormat.mSampleRate = THIS->sampleRate;

    const AudioStreamBasicDescription inFormat = THIS->streamFormat;

    UInt32 inSize = capacity*sizeof(SInt16);
    UInt32 outSize = capacity*sizeof(float);
    err = AudioConverterNew(&inFormat, &outFormat, &converter);
    err = AudioConverterConvertBuffer(converter, inSize, buf, &outSize, outputBuf);
}

void ConvertFloatToInt16(RIOInterface* dev, float *buf, void *outputBuf, size_t capacity) {
    AudioConverterRef converter;
    OSStatus err;

    size_t bytesPerSample = sizeof(short);
    AudioStreamBasicDescription outFormat = {0};
    outFormat.mFormatID = kAudioFormatLinearPCM;
    outFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
    outFormat.mBitsPerChannel = 8 * bytesPerSample;
    outFormat.mFramesPerPacket = 1;
    outFormat.mChannelsPerFrame = 1;
    outFormat.mBytesPerPacket = bytesPerSample * outFormat.mFramesPerPacket;
    outFormat.mBytesPerFrame = bytesPerSample * outFormat.mChannelsPerFrame;
    outFormat.mSampleRate = dev->sampleRate;

    const AudioStreamBasicDescription inFormat = dev->streamFormat;

    UInt32 inSize = capacity*sizeof(float);
    UInt32 outSize = capacity*sizeof(SInt16);
    err = AudioConverterNew(&inFormat, &outFormat, &converter);
    err = AudioConverterConvertBuffer(converter, inSize, buf, &outSize, outputBuf);
}

更新 2

阅读后的第二种方法this示例代码

vDSP_fft_zrip(fftSetup, &A, stride, log2n, FFT_INVERSE);

vDSP_ztoc(&A, 1, (COMPLEX *)outputBufferFrequency, 2, nOver2);

float scale = 0.5/maxFrames;
vDSP_vsmul(outputBufferFrequency, 1, &scale, outputBufferFrequency, 1, maxFrames);

ConvertFloatToInt16(THIS, outputBufferFrequency, outputBufferTime, bufferCapacity);

已解决

终于!我读完this anwser ,阅读一些我设法找出问题的示例代码。

我的工作代码。

Variable streamFormat is initialize somewhere eles and I put that initialization ConvertFloatToInt16 just for better view of what I use.

ConvertInt16ToFloat(THIS, dataBuffer, outputBufferFrequency, bufferCapacity);
//TIME -> FREQUENCU
vDSP_ctoz((COMPLEX*)outputBufferFrequency, 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 *)outputBufferFrequency, 2, nOver2);


//FREQUENCY -> TIME
//Back to time domain
vDSP_ctoz((COMPLEX*)outputBufferFrequency, 2, &A, 1, nOver2);

vDSP_fft_zrip(fftSetup, &A, stride, log2n, FFT_INVERSE);

float scale = (float) 1.0 / (2 * maxFrames);;

vDSP_vsmul(A.realp, 1, &scale, A.realp, 1, nOver2);
vDSP_vsmul(A.imagp, 1, &scale, A.imagp, 1, nOver2);

vDSP_ztoc(&A, 1, (COMPLEX *)outputBufferFrequency, 2, nOver2);

ConvertFloatToInt16(THIS, outputBufferFrequency, outputBufferTime, bufferCapacity);


void ConvertInt16ToFloat(RIOInterface* THIS, void *buf, float *outputBuf, size_t capacity) {
    AudioConverterRef converter;
    OSStatus err;

    size_t bytesPerSample = sizeof(float);
    AudioStreamBasicDescription outFormat = {0};
    outFormat.mFormatID = kAudioFormatLinearPCM;
    outFormat.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked;
    outFormat.mBitsPerChannel = 8 * bytesPerSample;
    outFormat.mFramesPerPacket = 1;
    outFormat.mChannelsPerFrame = 1;
    outFormat.mBytesPerPacket = bytesPerSample * outFormat.mFramesPerPacket;
    outFormat.mBytesPerFrame = bytesPerSample * outFormat.mChannelsPerFrame;
    outFormat.mSampleRate = THIS->sampleRate;

    THIS->streamFloatFormat = outFormat;
    const AudioStreamBasicDescription inFormat = THIS->streamFormat;

    UInt32 inSize = capacity*sizeof(SInt16);
    UInt32 outSize = capacity*sizeof(float);
    err = AudioConverterNew(&inFormat, &outFormat, &converter);
    err = AudioConverterConvertBuffer(converter, inSize, buf, &outSize, outputBuf);
}

void ConvertFloatToInt16(RIOInterface* THIS, float *buf, void *outputBuf, size_t capacity) {
    AudioConverterRef converter;
    OSStatus err;

    AudioStreamBasicDescription asbd = {0};
    size_t bytesPerSample;
    bytesPerSample = sizeof(SInt16);
    asbd.mFormatID = kAudioFormatLinearPCM;
    asbd.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
    asbd.mBitsPerChannel = 8 * bytesPerSample;
    asbd.mFramesPerPacket = 1;
    asbd.mChannelsPerFrame = 1;
    asbd.mBytesPerPacket = bytesPerSample * asbd.mFramesPerPacket;
    asbd.mBytesPerFrame = bytesPerSample * asbd.mChannelsPerFrame;
    asbd.mSampleRate = sampleRate;

    THIS->streamFormat = asbd;

    const AudioStreamBasicDescription outFormat = THIS->streamFormat;
    const AudioStreamBasicDescription inFormat = THIS->streamFloatFormat;

    UInt32 inSize = capacity*sizeof(float);
    UInt32 outSize = capacity*sizeof(SInt16);
    err = AudioConverterNew(&inFormat, &outFormat, &converter);
    err = AudioConverterConvertBuffer(converter, inSize, buf, &outSize, outputBuf);
}

最佳答案

逆傅里叶变换会将您的离散信号从频域转换回时域。

您可以像这样执行逆傅立叶变换 -

vDSP_fft_zrip(fftSetup, &A, stride, log2n, FFT_INVERSE);

然后必须相应地缩放它。缩放因子位于 图 2-6 在 vDSP Programming Guide 中找到的比例因子摘要由苹果

可以在这里找到一个很好的例子 Forward and Inverse FFT using Accelerate .

此外,在阅读您的更新后,如果您尝试在频域中对信号进行音调偏移,然后将其转换回时域,则涉及的内容要多得多。我可以建议阅读这篇关于 Pitch shifting using the Fourier transform 的文章吗?来自 DSP Dimension。

关于ios - 从频域到时域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21905798/

相关文章:

audio - 从传输流中提取音频并保留长度

c# - 在 wp8.1 rt 中播放来自应用程序的通知音

ios - CALayer - 将子层放在 Storyboard UIButtons 下方?

iphone - 如何在多部 iPhone 上使用相同的 sqlite 数据

ios - UITableView 的错误值 :rowHeight at iOS8

swift - 从 Swift 中的 unSafeMutablePointer Int16 获取音频数据的值(value)

swift - 我如何同步 AVCaptureDevice setFocusModeLockedWithLensPosition 调用

ios - UINavigationBar 右键太高

ios - 从 FIREBASE 嵌套的子节点中捕获信息到一个数组中,并将其传递给下一个 ViewController XCODE

swift - iOS - Swift - 录制时的一些音频达到最大允许长度