簡體   English   中英

使用音頻單元錄制音頻,每個文件以X秒數分割

[英]Recording audio with Audio Unit with files segmented in X number of seconds each

我已經來這幾天了。 我對框架的音頻單元層不是很熟悉。 有人可以給我指出一個完整的示例,該示例說明如何讓用戶以x個間隔即時記錄和寫入文件。 例如,用戶按下記錄,我想每10秒寫入一個文件,在第11秒,它將寫入下一個文件,而在第21秒,這是同一件事。 因此,當我錄制25秒的音頻字時,它將產生3個不同的文件。

我已經使用AVCapture嘗試過此操作,但它會在中間產生點擊和彈出聲。 我已經閱讀了它,這是由於讀寫操作之間的毫秒數所致。 我已經嘗試過Audio Queue Services,但是知道我正在使用的應用程序之后,我需要對音頻層進行完全控制。 所以我決定選擇Audio Unit。

我想我越來越近了……仍然迷路了。 我最終使用了超凡音頻引擎(TAAE)。 我現在正在看AEAudioReceiver,我的回調代碼如下所示。 我認為從邏輯上講是正確的,但我認為它沒有正確實施。

當前的任務:以AAC格式記錄〜5秒的片段。

嘗試:使用AEAudioReciever回調並將AudioBufferList存儲在循環緩沖區中。 跟蹤記錄器類中已接收音頻的秒數; 一旦超過5秒標記(可能會稍稍超過6秒)。 調用Obj-c方法以使用AEAudioFileWriter寫入文件

結果:沒用,錄音聽起來很慢,並且不斷有很多噪音。 我可以聽到一些錄音的聲音; 所以我知道那里有一些數據,但是好像我正在丟失很多數據。 我什至不知道如何調試它(我將繼續嘗試,但此刻相當迷茫)。

另一個項目正在轉換為AAC,我是否首先以PCM格式寫入文件而不是轉換為AAC,還是可以僅將音頻段轉換為AAC?

謝謝您的幫助!

-----循環緩沖區初始化-----

//trying to get 5 seconds audio, how do I know what the length is if I don't know the frame size yet? and is that even the right question to ask?
TPCircularBufferInit(&_buffer, 1024 * 256);  

----- AEAudioReceiver回調------

static void receiverCallback(__unsafe_unretained MyAudioRecorder *THIS,
                         __unsafe_unretained AEAudioController *audioController,
                         void *source,
                         const AudioTimeStamp *time,
                         UInt32 frames,
                         AudioBufferList *audio) {
//store the audio into the buffer
TPCircularBufferCopyAudioBufferList(&THIS->_buffer, audio, time, kTPCircularBufferCopyAll, NULL);

//increase the time interval to track by THIS    
THIS.numberOfSecondInCurrentRecording += AEConvertFramesToSeconds(THIS.audioController, frames);

//if number of seconds passed an interval of 5 seconds, than write the last 5 seconds of the buffer to a file
if (THIS.numberOfSecondInCurrentRecording > 5 * THIS->_currentSegment + 1) {

    NSLog(@"Segment %d is full, writing file", THIS->_currentSegment);
    [THIS writeBufferToFile];

   //segment tracking variables
    THIS->_numberOfReceiverLoop = 0;
    THIS.lastTimeStamp = nil;
    THIS->_currentSegment += 1;
} else {
    THIS->_numberOfReceiverLoop += 1;
}

// Do something with 'audio'
if (!THIS.lastTimeStamp) {
    THIS.lastTimeStamp = (AudioTimeStamp *)time;
}
}

----寫入文件(MyAudioRecorderClass內部的方法)----

- (void)writeBufferToFileHandler {

NSString *documentsFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)
                             objectAtIndex:0];

NSString *filePath = [documentsFolder stringByAppendingPathComponent:[NSString stringWithFormat:@"Segment_%d.aiff", _currentSegment]];

NSError *error = nil;

//setup audio writer, should the buffer be converted to aac first or save the file than convert; and how the heck do you do that?
AEAudioFileWriter *writeFile = [[AEAudioFileWriter alloc] initWithAudioDescription:_audioController.inputAudioDescription];
[writeFile beginWritingToFileAtPath:filePath fileType:kAudioFileAIFFType error:&error];

if (error) {
    NSLog(@"Error in init. the file: %@", error);
    return;
}

int i = 1;
//loop to write all the AudioBufferLists that is in the Circular Buffer; retrieve the ones based off of the _lastTimeStamp; but I had it in NULL too and worked the same way.
while (1) {

//NSLog(@"Processing buffer file list for segment [%d] and buffer index [%d]", _currentSegment, i);
    i += 1;
    // Discard any buffers with an incompatible format, in the event of a format change

    AudioBufferList *nextBuffer = TPCircularBufferNextBufferList(&_buffer, _lastTimeStamp);
    Float32 *frame = (Float32*) &nextBuffer->mBuffers[0].mData;

    //if buffer runs out, than we are done writing it and exit loop to close the file       
    if ( !nextBuffer ) {
        NSLog(@"Ran out of frames, there were [%d] AudioBufferList", i - 1);
        break;
    }
    //Adding audio using AudioFileWriter, is the length correct?
    OSStatus status = AEAudioFileWriterAddAudio(writeFile, nextBuffer, sizeof(nextBuffer->mBuffers[0].mDataByteSize));
    if (status) {
      NSLog(@"Writing Error? %d", status);
    }

    //consume/clear the buffer
    TPCircularBufferConsumeNextBufferList(&_buffer);
}

//close the file and hope it worked
[writeFile finishWriting];
}

-----音頻控制器AudioStreamBasicDescription ------

//interleaved16BitStereoAudioDescription
AudioStreamBasicDescription audioDescription;
memset(&audioDescription, 0, sizeof(audioDescription));
audioDescription.mFormatID          = kAudioFormatLinearPCM;
audioDescription.mFormatFlags       = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked | kAudioFormatFlagsNativeEndian;
audioDescription.mChannelsPerFrame  = 2;
audioDescription.mBytesPerPacket    = sizeof(SInt16)*audioDescription.mChannelsPerFrame;
audioDescription.mFramesPerPacket   = 1;
audioDescription.mBytesPerFrame     = sizeof(SInt16)*audioDescription.mChannelsPerFrame;
audioDescription.mBitsPerChannel    = 8 * sizeof(SInt16);
audioDescription.mSampleRate        = 44100.0;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM