Datenformat von der Aufnahme mit dem Audio Queue Framework

Ich schreibe eine iPhone-App, die die Stimme des Benutzers aufzeichnen und die Audiodaten für Änderungen wie Tempo und Tonhöhe in eine Bibliothek einspeisen soll. Ich habe mit dem SpeakHere-Beispielcode von Apple angefangen:

http: //developer.apple.com/library/ios/#samplecode/SpeakHere/Introduction/Intro.htm

Dieses Projekt bildet die Grundlage für die Aufzeichnung und Wiedergabe der Stimme des Benutzers. Es funktioniert gut

Nun tauche ich in den Code ein und muss herausfinden, wie ich die Audiodaten in die SoundTouch-Bibliothek einspeisen kann http: //www.surina.net/soundtouch), um die Tonhöhe zu ändern. Ich habe mich mit dem Audio Queue-Framework vertraut gemacht, als ich den Code durchgesehen habe, und habe den Ort gefunden, an dem ich die Audiodaten von der Aufnahme empfange.

Im Wesentlichen rufen SieAudioQueueNewInput, um eine neue Eingabewarteschlange zu erstellen. Sie übergeben eine Rückruffunktion, die jedes Mal aufgerufen wird, wenn ein Teil der Audiodaten verfügbar ist. Innerhalb dieses Rückrufs muss ich die Datenblöcke an SoundTouch übergeben.

Ich habe alles eingerichtet, aber das Rauschen, das ich von der SoundTouch-Bibliothek wiedergebe, ist sehr statisch (es ähnelt kaum dem Original). Wenn ich es nicht durch SoundTouch leite und das Original-Audio wiedergebe, funktioniert es einwandfrei.

rundsätzlich fehlt mir etwas darüber, was die tatsächlichen Daten darstellen, die ich erhalte. Ich ging davon aus, dass ich einen Stream von @ bekomshorts sind Samples, 1 Sample für jeden Kanal. So erwartet SoundTouch es, also muss es irgendwie nicht stimmen.

Hier ist der Code, mit dem die Audio-Warteschlange eingerichtet wird, damit Sie sehen können, wie sie konfiguriert ist.

void AQRecorder::SetupAudioFormat(UInt32 inFormatID)
{
memset(&mRecordFormat, 0, sizeof(mRecordFormat));

UInt32 size = sizeof(mRecordFormat.mSampleRate);
XThrowIfError(AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareSampleRate,
                                          &size, 
                                          &mRecordFormat.mSampleRate), "couldn't get hardware sample rate");

size = sizeof(mRecordFormat.mChannelsPerFrame);
XThrowIfError(AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputNumberChannels, 
                                          &size, 
                                          &mRecordFormat.mChannelsPerFrame), "couldn't get input channel count");

mRecordFormat.mFormatID = inFormatID;
if (inFormatID == kAudioFormatLinearPCM)
{
    // if we want pcm, default to signed 16-bit little-endian
    mRecordFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
    mRecordFormat.mBitsPerChannel = 16;
    mRecordFormat.mBytesPerPacket = mRecordFormat.mBytesPerFrame = (mRecordFormat.mBitsPerChannel / 8) * mRecordFormat.mChannelsPerFrame;
    mRecordFormat.mFramesPerPacket = 1;
}
}

Und hier ist ein Teil des Codes, der ihn tatsächlich einrichtet:

    SetupAudioFormat(kAudioFormatLinearPCM);

    // create the queue
    XThrowIfError(AudioQueueNewInput(
                                  &mRecordFormat,
                                  MyInputBufferHandler,
                                  this /* userData */,
                                  NULL /* run loop */, NULL /* run loop mode */,
                                  0 /* flags */, &mQueue), "AudioQueueNewInput failed");

Und schließlich ist hier der Rückruf, der neue Audiodaten verarbeitet:

void AQRecorder::MyInputBufferHandler(void *inUserData,
                                  AudioQueueRef inAQ,
                                  AudioQueueBufferRef inBuffer,
                                  const AudioTimeStamp *inStartTime,
                                  UInt32 inNumPackets,
                                  const AudioStreamPacketDescription *inPacketDesc) {
AQRecorder *aqr = (AQRecorder *)inUserData;
try {
        if (inNumPackets > 0) {
            CAStreamBasicDescription queueFormat = aqr->DataFormat();
            SoundTouch *soundTouch = aqr->getSoundTouch();

            soundTouch->putSamples((const SAMPLETYPE *)inBuffer->mAudioData,
                                   inBuffer->mAudioDataByteSize / 2 / queueFormat.NumberChannels());

            SAMPLETYPE *samples = (SAMPLETYPE *)malloc(sizeof(SAMPLETYPE) * 10000 * queueFormat.NumberChannels());
            UInt32 numSamples;
            while((numSamples = soundTouch->receiveSamples((SAMPLETYPE *)samples, 10000))) {
                // write packets to file
                XThrowIfError(AudioFileWritePackets(aqr->mRecordFile,
                                                    FALSE,
                                                    numSamples * 2 * queueFormat.NumberChannels(),
                                                    NULL,
                                                    aqr->mRecordPacket,
                                                    &numSamples,
                                                    samples),
                              "AudioFileWritePackets failed");
                aqr->mRecordPacket += numSamples;
            }
            free(samples);
        }

        // if we're not stopping, re-enqueue the buffe so that it gets filled again
        if (aqr->IsRunning())
            XThrowIfError(AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL), "AudioQueueEnqueueBuffer failed");
} catch (CAXException e) {
    char buf[256];
    fprintf(stderr, "Error: %s (%s)\n", e.mOperation, e.FormatError(buf));
}
}

Sie können sehen, dass ich die Daten in @ übergeinBuffer->mAudioData zu SoundTouch. Was genau stellen die Bytes in meinem Rückruf dar, d. H. Wie extrahiere ich Samples aus mAudioData?

Antworten auf die Frage(4)

Ihre Antwort auf die Frage