2011-01-07 10 views
7

Vorrei estrarre un canale audio da un file raw LPCM, ovvero estrarre il canale sinistro e destro di un file LPCM stereo. L'LPCM ha una profondità di 16 bit, interleaved, 2 canali, litle endian. Da quello che ho raccolto l'ordine di byte è {LeftChannel, RightChannel, LeftChannel, RightChannel ...} e dato che è a 16 bit di profondità ci saranno 2 byte di campione per ogni canale giusto?Estrazione del canale audio da Linear PCM

Quindi la mia domanda è se voglio estrarre il canale sinistro quindi vorrei prendere i byte in 0,2,4,6 ... n * 2 indirizzo? mentre il canale destro sarebbe 1,3,4, ... (n * 2 + 1).

Anche dopo aver estratto il canale audio, dovrei impostare il formato del canale estratto a 16 bit di profondità, 1 canale?

Grazie in anticipo

Questo è il codice che attualmente utilizzo per estrarre l'audio PCM da AssetReader .. Questo codice funziona bene con la scrittura di un file musicale, senza il suo canale viene estratto in modo che potrebbe essere causato dal formato o qualcosa del genere ...

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

Il formato di output con audiofileservices è la seguente:

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

risposta

4

suona quasi giusto - si dispone di un 16 bi t profondità, quindi questo significa che ogni campione prenderà 2 byte. Ciò significa che i dati del canale sinistro saranno espressi in byte {0,1}, {4,5}, {8,9} e così via. Interleaved significa che i campioni sono intercalati, non i byte. Oltre a questo, proverei a vedere se hai qualche problema con il tuo codice.

anche dopo l'estrazione del canale audio , devo impostare il formato del canale estratto come profondità di 16 bit , 1 canale?

Solo uno dei due canali rimane dopo l'estrazione, quindi sì, questo è corretto.

+0

Va bene, in realtà ho tentato questo e il risultato non è corretto ... Ho usato l'algoritmo di estrazione come hai detto ma l'output suona distorto ... distorto come in, suona "lento" ... – Samuel

+0

Il codice che ho usato per il suddetto algoritmo è stato inserito nel mio post. Gradirei qualsiasi input che ha causato un errore – Samuel

+0

Sei sicuro che la frequenza di campionamento in ingresso sia 44100? Se avessi quell'errore sbagliato spiegherebbe la riproduzione di "slow" – BrokenGlass

1

Ho avuto un errore simile a quello che l'audio suonava 'lento', il motivo per questo è che hai specificato mChannelsPerFrame di 1, mentre hai un suono a doppio canale. Impostalo su 2 e dovrebbe accelerare la riproduzione. Inoltre, verifica se l'output "suona" correttamente ... :)