- 録音した音声を保存してから指定秒数でトリミング
- 数個の音声ファイルを結合
これら2つの機能を組み合わせて使いたかったので、
その際のメモ兼備忘録。
前提
AVAudioSessionとAVAudioRecorderを使ってデバイス内に音声ファイルが保存されていること。
トリミング(Crop)
音声ファイルの末尾から規定秒数分を切り出すケース
まずは切り出し開始位置を決める。
(audioRecorderは録音中のAVAudioRecorderオブジェクト)
let cropTime:TimeInterval = 10 // 10秒分切り出す
let recordedTime = audioRecorder.currentTime
audioRecorder.stop()
切り出し位置が決まったら、Export用にコードを実装する。
(cropTimeより短い時間のファイルなら何もしない)
if recordedTime > cropTime {
let croppedFileSaveURL = NSURL(fileURLWithPath: "fineName.caf")
let trimStartTime = recordedTime - cropTime
// arg1 / arg2 = CMTimeらしいので、とりあえず1で除算
// 本当はもっと厳密にやったほうが良いかも
let startTime = CMTimeMake(Int64(trimStartTime), 1)
let endTime = CMTimeMake(Int64(recordedTime), 1)
// 開始時間、終了時間からCropするTimeRangeを作成
let exportTimeRange = CMTimeRangeFromTimeToTime(startTime, endTime)
// AssetにInputとなるファイルのUrlをセット
let asset = AVAsset(url: audioRecorder.url)
// cafファイルとしてExportする
let exporter = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetPassthrough)
exporter?.outputFileType = AVFileTypeCoreAudioFormat
exporter?.timeRange = exportTimeRange
exporter?.outputURL = croppedFileSaveURL
// Export
exporter!.exportAsynchronously(completionHandler: {
switch exporter!.status {
case .completed:
print("Crop Success! Url -> \(croppedFileSaveURL)")
case .failed, .cancelled:
print("error = \(exporter?.error)")
default:
print("error = \(exporter?.error)")
}
})
}
結合(Concat)
複数の音声ファイルを1つのファイルに結合するケース
let audioFileURLs = [fileA_Url, fileB_Url, fileC_Url]
var nextStartTime = kCMTimeZero
let composition = AVMutableComposition()
let track = composition.addMutableTrack(withMediaType: AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid)
// 結合するファイル毎に、timerangeを作りtrackにinsertする
for url in audioFileURLs {
let asset = AVURLAsset(url: url as URL)
if let assetTrack = asset.tracks(withMediaType: AVMediaTypeAudio).first {
let timeRange = CMTimeRange(start: kCMTimeZero, duration: asset.duration)
do {
try track.insertTimeRange(timeRange, of: assetTrack, at: nextSoundStartTime)
nextSoundStartTime = CMTimeAdd(nextSoundStartTime, timeRange.duration)
} catch {
print("concatenateError : \(error)")
}
}
}
if let exportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetPassthrough) {
let concatFileSaveURL = NSURL(fileURLWithPath: "fineName.caf")
exportSession.outputFileType = AVFileTypeCoreAudioFormat
exportSession.outputURL = concatFileSaveURL as URL
exportSession.exportAsynchronously(completionHandler: {
switch exportSession.status {
case .completed:
print("Concat Success! Url -> \(concatFileSaveURL)")
case .failed, .cancelled:
print("error = \(exporter?.error)")
default:
print("error = \(exporter?.error)")
})
}