2010-11-21 105 views
8

我想實現一項功能,讓用戶修剪他先前錄製的音頻文件(.caf)。錄音部分已經可以工作了,但是我如何添加類似於Voicememos應用程序中的修剪功能。蘋果公司使用的音頻微調器有api嗎? 任何幫助將是偉大的...使用iOS修剪音頻

回答

20

如何使用AVFoundation?將音頻文件導入到AVAsset(合成等)中,然後可以將它導出(將首選時間+持續時間)設置爲文件。

我之前寫過一個股票函數,用於將資產導出到文件中,您還可以指定一個audiomix。如下所示,它會導出所有文件,但是您可以將NSTimeRange添加到exporter.timeRange,然後您可以繼續。我還沒有測試,但應該工作(?)。另一種方法是在創建AVAsset +音軌時調整時間範圍。當然,出口商只處理m4a(AAC)。對不起,如果這不是你想要的。

-(void)exportAsset:(AVAsset*)asset toFile:(NSString*)filename overwrite:(BOOL)overwrite withMix:(AVAudioMix*)mix { 
//NSArray* availablePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:asset]; 

AVAssetExportSession* exporter = [AVAssetExportSession exportSessionWithAsset:asset presetName:AVAssetExportPresetAppleM4A]; 

if (exporter == nil) { 
    DLog(@"Failed creating exporter!"); 
    return; 
} 

DLog(@"Created exporter! %@", exporter); 

// Set output file type 
DLog(@"Supported file types: %@", exporter.supportedFileTypes); 
for (NSString* filetype in exporter.supportedFileTypes) { 
    if ([filetype isEqualToString:AVFileTypeAppleM4A]) { 
     exporter.outputFileType = AVFileTypeAppleM4A; 
     break; 
    } 
} 
if (exporter.outputFileType == nil) { 
    DLog(@"Needed output file type not found? (%@)", AVFileTypeAppleM4A); 
    return; 
} 

// Set outputURL 
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
NSString* parentDir = [NSString stringWithFormat:@"%@/", [paths objectAtIndex:0]]; 

NSString* outPath = [NSString stringWithFormat:@"%@%@", parentDir, filename]; 

NSFileManager* manager = [NSFileManager defaultManager]; 
if ([manager fileExistsAtPath:outPath]) { 
    DLog(@"%@ already exists!", outPath); 
    if (!overwrite) { 
     DLog(@"Not overwriting, uh oh!"); 
     return; 
    } 
    else { 
     // Overwrite 
     DLog(@"Overwrite! (delete first)"); 
     NSError* error = nil; 
     if (![manager removeItemAtPath:outPath error:&error]) { 
      DLog(@"Failed removing %@, error: %@", outPath, error.description); 
      return; 
     } 
     else { 
      DLog(@"Removed %@", outPath); 
     } 
    } 
} 

NSURL* const outUrl = [NSURL fileURLWithPath:outPath]; 
exporter.outputURL = outUrl; 
// Specify a time range in case only part of file should be exported 
//exporter.timeRange = 

if (mix != nil) 
    exporter.audioMix = mix; // important 

DLog(@"Starting export! (%@)", exporter.outputURL); 
[exporter exportAsynchronouslyWithCompletionHandler:^(void) { 
    // Export ended for some reason. Check in status 
    NSString* message; 
    switch (exporter.status) { 
     case AVAssetExportSessionStatusFailed: 
      message = [NSString stringWithFormat:@"Export failed. Error: %@", exporter.error.description]; 
      DLog(@"%@", message); 
      [self showAlert:message]; 
      break; 
     case AVAssetExportSessionStatusCompleted: { 
      /*if (playfileWhenExportFinished) { 
      DLog(@"playfileWhenExportFinished!"); 
      [self playfileAfterExport:exporter.outputURL]; 
      playfileWhenExportFinished = NO; 
      }*/ 
      message = [NSString stringWithFormat:@"Export completed: %@", filename]; 
      DLog(@"%@", message); 
      [self showAlert:message]; 
      break; 
     } 
     case AVAssetExportSessionStatusCancelled: 
      message = [NSString stringWithFormat:@"Export cancelled!"]; 
      DLog(@"%@", message); 
      [self showAlert:message]; 
      break; 
     default: 
      DLog(@"Export unhandled status: %d", exporter.status); 
      break; 
    }  
}]; 
} 
+3

但這種方法只允許聲音保存在M4A格式,是什麼如果你喜歡修剪一個MP3或一個caf文件並保持fo RMAT? – tommys 2012-02-24 20:38:57

+1

修剪MP3也工作,輸出存儲在m4a格式 2年後,你仍然救我的生命:) – 2013-11-29 09:36:11

1

@Jonny的上面的答案是正確的。這裏是我添加AudioMixer的使用,以添加音頻修整時的淡入效果。

輸出:音頻資產修剪至20秒,在10秒的褪色 被設置裝飾了在代碼段發生在30秒 標記資產的,因此,軌道持續時間應在至少 50秒。

- (BOOL)exportAssettoFilePath:(NSString *)filePath { 


NSString *inputFilePath = <inputFilePath>; 

NSURL *videoToTrimURL = [NSURL fileURLWithPath:inputFilePath]; 
AVAsset *avAsset = [AVAsset assetWithURL:videoToTrimURL]; 

// we need the audio asset to be at least 50 seconds long for this snippet 
CMTime assetTime = [avAsset duration]; 
Float64 duration = CMTimeGetSeconds(assetTime); 
if (duration < 50.0) return NO; 

// get the first audio track 
NSArray *tracks = [avAsset tracksWithMediaType:AVMediaTypeAudio]; 
if ([tracks count] == 0) return NO; 

AVAssetTrack *track = [tracks objectAtIndex:0]; 

// create the export session 
// no need for a retain here, the session will be retained by the 
// completion handler since it is referenced there 
AVAssetExportSession *exportSession = [AVAssetExportSession 
             exportSessionWithAsset:avAsset 
             presetName:AVAssetExportPresetAppleM4A]; 
if (nil == exportSession) return NO; 

// create trim time range - 20 seconds starting from 30 seconds into the asset 
CMTime startTime = CMTimeMake(30, 1); 
CMTime stopTime = CMTimeMake(50, 1); 
CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime, stopTime); 

// create fade in time range - 10 seconds starting at the beginning of trimmed asset 
CMTime startFadeInTime = startTime; 
CMTime endFadeInTime = CMTimeMake(40, 1); 
CMTimeRange fadeInTimeRange = CMTimeRangeFromTimeToTime(startFadeInTime, 
                 endFadeInTime); 

// setup audio mix 
AVMutableAudioMix *exportAudioMix = [AVMutableAudioMix audioMix]; 
AVMutableAudioMixInputParameters *exportAudioMixInputParameters = 
[AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:track]; 

[exportAudioMixInputParameters setVolumeRampFromStartVolume:0.0 toEndVolume:1.0 
                timeRange:fadeInTimeRange]; 
exportAudioMix.inputParameters = [NSArray 
            arrayWithObject:exportAudioMixInputParameters]; 

// configure export session output with all our parameters 
exportSession.outputURL = [NSURL fileURLWithPath:filePath]; // output path 
exportSession.outputFileType = AVFileTypeAppleM4A; // output file type 
exportSession.timeRange = exportTimeRange; // trim time range 
//exportSession.audioMix = exportAudioMix; // fade in audio mix 

// perform the export 
[exportSession exportAsynchronouslyWithCompletionHandler:^{ 

    if (AVAssetExportSessionStatusCompleted == exportSession.status) { 
     NSLog(@"AVAssetExportSessionStatusCompleted"); 
    } else if (AVAssetExportSessionStatusFailed == exportSession.status) { 
     // a failure may happen because of an event out of your control 
     // for example, an interruption like a phone call comming in 
     // make sure and handle this case appropriately 
     NSLog(@"AVAssetExportSessionStatusFailed"); 
    } else { 
     NSLog(@"Export Session Status: %ld", (long)exportSession.status); 
    } 
}]; 

return YES;} 

感謝

瞭解更多詳情:

https://developer.apple.com/library/ios/qa/qa1730/_index.html