Как воспроизвести и прочитать аудиофайл .caf PCM

У меня есть приложение, которое выбирает песню из библиотеки iPod, а затем копирует эту песню в каталог приложения в виде файла «.caf». Теперь мне нужно воспроизвести и в то же время прочитать этот файл в Apples FFT из среды Accelerate, чтобы я мог визуализировать данные как спектрограмму. Вот код для БПФ:

void FFTAccelerate::doFFTReal(float samples[], float amp[], int numSamples)
{
int i;
vDSP_Length log2n = log2f(numSamples);

//Convert float array of reals samples to COMPLEX_SPLIT array A
vDSP_ctoz((COMPLEX*)samples,2,&A,1,numSamples/2);

//Perform FFT using fftSetup and A
//Results are returned in A
vDSP_fft_zrip(fftSetup, &A, 1, log2n, FFT_FORWARD);

//Convert COMPLEX_SPLIT A result to float array to be returned
amp[0] = A.realp[0]/(numSamples*2);
for(i=1;i<numSamples;i++)
    amp[i]=sqrt(A.realp[i]*A.realp[i]+A.imagp[i]*A.imagp[i])/numSamples;
}

//Constructor
FFTAccelerate::FFTAccelerate (int numSamples)
{
vDSP_Length log2n = log2f(numSamples);
fftSetup = vDSP_create_fftsetup(log2n, FFT_RADIX2);
int nOver2 = numSamples/2;
A.realp = (float *) malloc(nOver2*sizeof(float));
A.imagp = (float *) malloc(nOver2*sizeof(float));
}

Мой вопрос заключается в том, как прокрутить аудиофайл '.caf', чтобы передать БПФ и одновременно воспроизвести песню? Мне нужен только один канал. Я предполагаю, что мне нужно получить 1024 сэмпла песни, обработать их в FTT, а затем перейти дальше по файлу и получить еще 1024 сэмпла. Но я не понимаю, как читать аудиофайл, чтобы сделать это. Файл имеет частоту дискретизации 44100,0 Гц, в линейном формате PCM, 16 бит, и я думаю, что он также чередуется, если это поможет...


person Snick    schedule 02.12.2013    source источник


Ответы (1)


Попробуйте API ExtendedAudioFile (требуется AudioToolbox.framework).

#include <AudioToolbox/ExtendedAudioFile.h>

NSURL   *urlToCAF = ...;

ExtAudioFileRef caf;
OSStatus    status;

status = ExtAudioFileOpenURL((__bridge CFURLRef)urlToCAF, &caf);
if(noErr == status) {
    // request float format
    const UInt32 NumFrames = 1024;
    const int ChannelsPerFrame = 1;  // Mono, 2 for Stereo

    // request float format
    AudioStreamBasicDescription clientFormat;
    clientFormat.mChannelsPerFrame = ChannelsPerFrame;
    clientFormat.mSampleRate = 44100;

    clientFormat.mFormatID = kAudioFormatLinearPCM;
    clientFormat.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsNonInterleaved; // float
    int cmpSize = sizeof(float);
    int frameSize = cmpSize*ChannelsPerFrame;
    clientFormat.mBitsPerChannel = cmpSize*8;
    clientFormat.mBytesPerPacket = frameSize;
    clientFormat.mFramesPerPacket = 1;
    clientFormat.mBytesPerFrame = frameSize;

    status = ExtAudioFileSetProperty(caf, kExtAudioFileProperty_ClientDataFormat, sizeof(clientFormat), &clientFormat);
     if(noErr != status) { /* handle it */ }

    while(1) {
        float   buf[ChannelsPerFrame*NumFrames];
        AudioBuffer ab = { ChannelsPerFrame, sizeof(buf), buf };
        AudioBufferList abl;
        abl.mNumberBuffers = 1;
        abl.mBuffers[0] = ab;

        UInt32  ioNumFrames = NumFrames;
        status = ExtAudioFileRead(caf, &ioNumFrames, &abl);

        if(noErr == status) {
            // process ioNumFrames here in buf
            if(0 == ioNumFrames) {
                // EOF!
                break;
            } else if(ioNumFrames < NumFrames) {
                // TODO: pad buf with zeroes out to NumFrames 
            } else {
                 float amp[NumFrames]; // scratch space
                 doFFTReal(buf, amp, NumFrames);
            }
        }
    }

    // later
    status = ExtAudioFileDispose(caf);
    if(noErr != status) { /* hmm */ }
}
person Rhythmic Fistman    schedule 02.12.2013
comment
Спасибо... выглядит многообещающе! Как мне зациклиться и получить следующие 1024 кадра? Как бы я также воспроизвел звук одновременно? - person Snick; 03.12.2013
comment
добавлена ​​петля. только что понял, что вам нужны образцы с плавающей запятой. нужно это исправить. для одновременного воспроизведения звука вам, вероятно, следует задать другой вопрос. есть много способов сделать это. - person Rhythmic Fistman; 03.12.2013
comment
Я запутался, что такое ioNumFrames? Разве мне не нужен массив образцов с плавающей запятой? Является ли «аб» тем, что хранит эту информацию?? - person Snick; 03.12.2013
comment
добавлено преобразование с плавающей запятой - person Rhythmic Fistman; 03.12.2013
comment
ioNumFrames — это количество кадров, которые вы на самом деле получили, может быть короче, чем вы запрашивали из-за EOF. ab содержит указатели на ваши буферы. теперь он обрабатывает поплавки - person Rhythmic Fistman; 03.12.2013
comment
Как я использовал «ab» для доступа к этим поплавкам? К чему подключать: fftAccel->doFFTReal(samples[], Frequency[], numSamples); - person Snick; 03.12.2013
comment
Ненавижу просить о дополнительной помощи, но почему некоторые амплитуды, возвращаемые БПФ, такие большие? Я ожидал, что бины FFT AMP останутся ниже 1.0, но некоторые возвращают INF... - person Snick; 03.12.2013
comment
Возможно, образцы, считанные из аудиофайла, не нормализованы. Возможно, вам понадобится это вручную. - person Rhythmic Fistman; 03.12.2013
comment
Я забыл упомянуть, что файл caf находится в стерео, но я хочу обработать только 1 канал, чтобы упростить задачу. Это не то, что отбрасывает БПФ? Кроме того, что толкает буфер к следующему набору образцов? ExtAudioFileRead проталкивает буфер вниз по файлу? - person Snick; 03.12.2013
comment
Я думаю, что ExtAudioFile должен быть преобразован в моно для вас. Да, ExtAudioFileRead продвигается по файлу. - person Rhythmic Fistman; 03.12.2013