Reputation: 1353
The problem I am having is getting a variable amount of silence to be placed in-between two wav files.
My approach thus far is as follows:
Firstly I create an AVMutableComposition
and an AVMutableCompositionTrack
AVMutableComposition* composition = [AVMutableComposition composition];
AVMutableCompositionTrack* appendedAudioTrack =
[composition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID:kCMPersistentTrackID_Invalid];
Then using AVURLAsset
I allocate my conveniently named first.wav file.
AVURLAsset* firstComponent = [[AVURLAsset alloc]
initWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource: @"first" ofType: @"wav"]] options:nil];
I then insert this into the mutable composition track I named appendedAudioTrack
earlier
NSArray *firstTrack = [firstComponent tracksWithMediaType:AVMediaTypeAudio];
CMTimeRange timeRange = CMTimeRangeMake(kCMTimeZero, firstComponent.duration);
[appendedAudioTrack insertTimeRange:timeRange
ofTrack:[firstTrack objectAtIndex:0]
atTime:kCMTimeZero
error:&error];
The second.wav file is inserted in the exact same way:
AVURLAsset* secondComponent = [[AVURLAsset alloc]
initWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource: @"second" ofType: @"wav"]] options:nil];
NSArray *secondTrack = [secondComponent tracksWithMediaType:AVMediaTypeAudio];
CMTimeRange timeRange2 = CMTimeRangeMake(kCMTimeZero, secondComponent.duration);
[appendedAudioTrack insertTimeRange:timeRange2
ofTrack:[secondTrack objectAtIndex:0]
atTime:kCMTimeZero
error:&error];
This so far successfully joins the two wav files end to end.
I then try to insert a variable amount of silence using insertEmptyTimeRange
like this:
CMTimeRange timeRange3 = CMTimeRangeFromTimeToTime(firstComponent.duration,CMTimeAdd(firstComponent.duration,CMTimeMake(interval,1)));
[appendedAudioTrack insertEmptyTimeRange:timeRange3];
The silence duration is a float
and for testing purposes is currently 0.49. Its variable name is interval
and it represents the desired silence in seconds.
An assumption i've made using CMTimeRange
is that AVURLAsset
's duration property can be considered as the finish CMTime
for the first audio track.
When I download the documents directory from organiser in Xcode, and look at the resulting m4a file in audacity the silence is in the file, but its at the start, not in the middle of both .wav files as desired.
Incorrectly it goes: SILENCE, first.wav, second.wav
I would like to know how to properly use insertEmptyTimeRange to produce first.wav, SILENCE, second.wav.
Note: I have seen this question (and others) which presents a very similar problem, however the approach they went for was to use a constant silence file. My silence is variable and determined at run time. And I am also aware that another answer provides what they say is a solution, but it has not worked for me. I have tried all the different methods I found on the internet but it seems I'm misunderstanding something as it never works correctly for me.
Just in case it matters, I export the file like so:
// Create a new audio file using the appendedAudioTrack
AVAssetExportSession* exportSession = [AVAssetExportSession
exportSessionWithAsset:composition
presetName:AVAssetExportPresetAppleM4A];
if (!exportSession)
{
// do something
return nil;
}
//This gives me an output URL to a file name that doesn't yet exist
NSString *path2;
NSArray *paths2 = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
path2 = [paths2 objectAtIndex:0];
path2 = [path2 stringByAppendingPathComponent:[string stringByAppendingString: @".m4a"]];
NSString* appendedAudioPath= path2;
exportSession.outputURL = [NSURL fileURLWithPath:appendedAudioPath];
exportSession.outputFileType = AVFileTypeAppleM4A;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch (exportSession.status)
{
case AVAssetExportSessionStatusFailed:
NSLog(@"%@",exportSession.error);
break;
case AVAssetExportSessionStatusCompleted:
break;
case AVAssetExportSessionStatusWaiting:
break;
default:
break;
}
Thanks
Upvotes: 4
Views: 2004
Reputation: 1353
It turns out the interval was not of the correct duration, when checked in audacity it was actually 0.049, not 0.49.
The problem I was having was with this
CMTimeMake(interval,1)
I thought this would yield interval/1
seconds but I was wrong.
Instead I used CMTimeMakeWithSeconds
along with NSEC_PER_SEC
like so
CMTimeRange timeRange3 = CMTimeRangeFromTimeToTime(firstComponent.duration,CMTimeAdd(firstComponent.duration,CMTimeMakeWithSeconds(interval ,NSEC_PER_SEC)));
[appendedAudioTrack insertEmptyTimeRange:timeRange3];
This then provided me with the desired silence of interval
seconds long, and in the right place.
Upvotes: 2