2011-01-07 9 views
7

Chciałbym wyodrębnić kanał audio z surowego pliku LPCM, tj. Wyodrębnić lewy i prawy kanał stereofonicznego pliku LPCM. LPCM ma 16 bitów głębokości, przeplatany, 2 kanały, litowy endian. Z tego co wiem, kolejność bajtów to {LeftChannel, RightChannel, LeftChannel, RightChannel ...}, a ponieważ ma ona 16-bitową głębię, będzie 2 bajty próbki dla każdego kanału po prawej?Wyodrębnianie kanału audio z Linear PCM

Moje pytanie brzmi, czy chcę wyodrębnić lewy kanał, a następnie wziąłbym bajty w adresie 0,2,4,6 ... n * 2? podczas gdy prawy kanał będzie 1,3,4, ... (n * 2 + 1).

Czy po wyodrębnieniu kanału audio należy ustawić format wyodrębnionego kanału jako 16-bitową głębię, 1 kanał?

góry dzięki

Jest to kod, który stosuje obecnie wyodrębnić audio PCM z AssetReader .. Ten kod działa poprawnie z zapisywania pliku muzycznego bez jego kanale wyodrębniania więc może to być spowodowane przez format albo coś ...

NSURL *assetURL = [song valueForProperty:MPMediaItemPropertyAssetURL]; 
AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:assetURL options:nil]; 
NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys: 
           [NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey, 
           [NSNumber numberWithFloat:44100.0], AVSampleRateKey, 
           [NSNumber numberWithInt:2], AVNumberOfChannelsKey, 
          // [NSData dataWithBytes:&channelLayout length:sizeof(AudioChannelLayout)], AVChannelLayoutKey, 
           [NSNumber numberWithInt:16], AVLinearPCMBitDepthKey, 
           [NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved, 
           [NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey, 
           [NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey, 
           nil]; 
NSError *assetError = nil; 
AVAssetReader *assetReader = [[AVAssetReader assetReaderWithAsset:songAsset 
                  error:&assetError] 
           retain]; 
if (assetError) { 
    NSLog (@"error: %@", assetError); 
    return; 
} 

AVAssetReaderOutput *assetReaderOutput = [[AVAssetReaderAudioMixOutput 
              assetReaderAudioMixOutputWithAudioTracks:songAsset.tracks 
              audioSettings: outputSettings] 
              retain]; 
if (! [assetReader canAddOutput: assetReaderOutput]) { 
    NSLog (@"can't add reader output... die!"); 
    return; 
} 
[assetReader addOutput: assetReaderOutput]; 


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

//CODE TO SPLIT STEREO 
[self setupAudioWithFormatMono:kAudioFormatLinearPCM]; 
NSString *splitExportPath = [[documentsDirectoryPath stringByAppendingPathComponent:@"monoleft.caf"] retain]; 
if ([[NSFileManager defaultManager] fileExistsAtPath:splitExportPath]) { 
    [[NSFileManager defaultManager] removeItemAtPath:splitExportPath error:nil]; 
} 

AudioFileID mRecordFile; 
NSURL *splitExportURL = [NSURL fileURLWithPath:splitExportPath]; 


OSStatus status = AudioFileCreateWithURL(splitExportURL, kAudioFileCAFType, &_streamFormat, kAudioFileFlags_EraseFile, 
              &mRecordFile); 

NSLog(@"status os %d",status); 

[assetReader startReading]; 

CMSampleBufferRef sampBuffer = [assetReaderOutput copyNextSampleBuffer]; 
UInt32 countsamp= CMSampleBufferGetNumSamples(sampBuffer); 
NSLog(@"number of samples %d",countsamp); 

SInt64 countByteBuf = 0; 
SInt64 countPacketBuf = 0; 
UInt32 numBytesIO = 0; 
UInt32 numPacketsIO = 0; 
NSMutableData * bufferMono = [NSMutableData new]; 
while (sampBuffer) { 


    AudioBufferList audioBufferList; 
    CMBlockBufferRef blockBuffer; 
    CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampBuffer, NULL, &audioBufferList, sizeof(audioBufferList), NULL, NULL, 0, &blockBuffer); 
    for (int y=0; y<audioBufferList.mNumberBuffers; y++) { 
     AudioBuffer audioBuffer = audioBufferList.mBuffers[y]; 
     //frames = audioBuffer.mData; 
     NSLog(@"the number of channel for buffer number %d is %d",y,audioBuffer.mNumberChannels); 
     NSLog(@"The buffer size is %d",audioBuffer.mDataByteSize); 






     //Append mono left to buffer data 
     for (int i=0; i<audioBuffer.mDataByteSize; i= i+4) { 
      [bufferMono appendBytes:(audioBuffer.mData+i) length:2]; 
     } 

     //the number of bytes in the mutable data containing mono audio file 
     numBytesIO = [bufferMono length]; 
     numPacketsIO = numBytesIO/2; 
     NSLog(@"numpacketsIO %d",numPacketsIO); 
     status = AudioFileWritePackets(mRecordFile, NO, numBytesIO, &_packetFormat, countPacketBuf, &numPacketsIO, audioBuffer.mData); 
     NSLog(@"status for writebyte %d, packets written %d",status,numPacketsIO); 
     if(numPacketsIO != (numBytesIO/2)){ 
      NSLog(@"Something wrong"); 
      assert(0); 
     } 


     countPacketBuf = countPacketBuf + numPacketsIO; 
     [bufferMono setLength:0]; 


    } 

    sampBuffer = [assetReaderOutput copyNextSampleBuffer]; 
    countsamp= CMSampleBufferGetNumSamples(sampBuffer); 
    NSLog(@"number of samples %d",countsamp); 
} 
AudioFileClose(mRecordFile); 
[assetReader cancelReading]; 
[self performSelectorOnMainThread:@selector(updateCompletedSizeLabel:) 
         withObject:0 
        waitUntilDone:NO]; 

Format wyjściowy z audiofileservices się następująco:

 _streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; 
    _streamFormat.mBitsPerChannel = 16; 
    _streamFormat.mChannelsPerFrame = 1; 
    _streamFormat.mBytesPerPacket = 2; 
    _streamFormat.mBytesPerFrame = 2;// (_streamFormat.mBitsPerChannel/8) * _streamFormat.mChannelsPerFrame; 
    _streamFormat.mFramesPerPacket = 1; 
    _streamFormat.mSampleRate = 44100.0; 

    _packetFormat.mStartOffset = 0; 
    _packetFormat.mVariableFramesInPacket = 0; 
    _packetFormat.mDataByteSize = 2; 

Odpowiedz

4

Brzmi prawie prawo - masz 16 BI t głębokość, więc oznacza to, że każda próbka zajmie 2 bajty. Oznacza to, że dane lewego kanału będą w bajtach {0,1}, {4,5}, {8,9} i tak dalej. Przeplatane oznacza, że ​​próbki są przeplatane, a nie bajty. Poza tym chciałbym wypróbować i sprawdzić, czy masz problemy z kodem.

Również po ekstrakcji kanał audio , należy ustawić format wyodrębnione kanału jako 16-bitowa głębia , 1 kanał?

Po ekstrakcji pozostanie tylko jeden z dwóch kanałów, więc tak, jest to poprawne.

+0

Dobra, faktycznie próbowałem tego, a wynik nie jest właściwy ... Użyłem algorytmu wyciągu, tak jak powiedziałeś, ale dźwięki wyjściowe są zniekształcone ... zniekształcone, ponieważ brzmią "wolno" ... – Samuel

+0

Kod który wykorzystałem dla tego algorytmu, został umieszczony w moim poście. Z radością przyjmuję wszelkie dane wejściowe, które spowodowały, że wszystko poszło nie tak – Samuel

+0

Czy jesteś pewien, że częstotliwość próbkowania wejściowego wynosi 44100? Jeśli miałeś jeden błąd, który wyjaśniałby to, odtwarzając "powolny" – BrokenGlass

1

Miałem podobny błąd, że dźwięk brzmiał "wolno". Powodem tego jest to, że podałeś mChannelsPerFrame równe 1, a masz dźwięk dwukanałowy. Ustaw na 2 i powinno przyspieszyć odtwarzanie. Również powiedz, czy po wykonaniu tego wynik "brzmi" poprawnie ... :)