I want to merge two or more .wav files to one and then convert it to .mp3 and this I would like to done in Swift (or at least to have option to include it to swift project).
我想将两个或多个.wav文件合并为一个,然后将其转换为.mp3,我想在Swift中完成(或者至少可以选择将它包含在swift项目中)。
Merge two .wav files in swift isn't problem. Here is my example Now I don't know how to add lame library to swift project and how to use it (how to change objective c lame code usage syntax to use it in swift).
在swift中合并两个.wav文件不是问题。这是我的示例现在我不知道如何将lame库添加到swift项目以及如何使用它(如何更改客观的蹩脚代码使用语法以在swift中使用它)。
I stuck in swift so I tried Lame library with Objective C. I found example code for converting .caf to .mp3 so I tried it. Here is what I've tried:
我坚持使用swift,所以我尝试了使用Objective C的Lame库。我找到了将.caf转换为.mp3的示例代码,所以我试了一下。这是我尝试过的:
- (void) toMp3
{
NSString *cafFilePath = [[NSBundle mainBundle] pathForResource:@"sound" ofType:@"caf"];
NSString *mp3FileName = @"Mp3File";
mp3FileName = [mp3FileName stringByAppendingString:@".mp3"];
NSString *mp3FilePath = [[NSHomeDirectory() stringByAppendingFormat:@"/Documents/"] stringByAppendingPathComponent:mp3FileName];
NSLog(@"%@", mp3FilePath);
@try {
int read, write;
FILE *pcm = fopen([cafFilePath cStringUsingEncoding:1], "rb"); //source
fseek(pcm, 4*1024, SEEK_CUR); //skip file header
FILE *mp3 = fopen([mp3FilePath cStringUsingEncoding:1], "wb"); //output
const int PCM_SIZE = 8192;
const int MP3_SIZE = 8192;
short int pcm_buffer[PCM_SIZE*2];
unsigned char mp3_buffer[MP3_SIZE];
lame_t lame = lame_init();
lame_set_in_samplerate(lame, 44100);
lame_set_VBR(lame, vbr_default);
lame_init_params(lame);
do {
read = fread(pcm_buffer, 2*sizeof(short int), PCM_SIZE, pcm);
if (read == 0)
write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
else
write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);
fwrite(mp3_buffer, write, 1, mp3);
} while (read != 0);
lame_close(lame);
fclose(mp3);
fclose(pcm);
}
@catch (NSException *exception) {
NSLog(@"%@",[exception description]);
}
@finally {
[self performSelectorOnMainThread:@selector(convertMp3Finish)
withObject:nil
waitUntilDone:YES];
}
}
- (void) convertMp3Finish
{
}
But result of this is just .mp3 with noise.
但结果只是带有噪音的.mp3。
- Here is example .caf file.
- 这是示例.caf文件。
- And here is result .mp3 file.
- 这是结果.mp3文件。
So I need fix my three problems:
所以我需要解决我的三个问题:
- Create correct mp3 from caf in Objective C
- 在Objective C中从caf创建正确的mp3
- Change code to use it for wav file
- 更改代码以将其用于wav文件
- And change it to be able to use it in Swift
- 并将其更改为能够在Swift中使用它
I know that there are many questions about encoding and converting mp3 in iOS but I can't find one with Swift example and I can't find example with working Objective C code (just code above). Thanks for help
我知道在iOS中有很多关于编码和转换mp3的问题,但是我找不到一个使用Swift的例子,我找不到使用Objective C代码的例子(只是上面的代码)。感谢帮助
2 个解决方案
#1
10
I would like to post my working solution because I get so many thumbs up and answer from naresh doesn't help me much.
我想发布我的工作解决方案,因为我得到了很多赞许,来自naresh的回答对我没什么帮助。
- I have generated lame.framework library from this project https://github.com/wuqiong/mp3lame-for-iOS
- 我从这个项目生成了lame.framework库https://github.com/wuqiong/mp3lame-for-iOS
- I've added library to my Swift project (Build Phases -> Link Binary With Libraries)
- 我已经将库添加到我的Swift项目中(Build Phases - > Link Binary with Libraries)
- I've created wrapper for using c functions in Objective C and by bridging header I use it in Swift.
- 我已经创建了在Objective C中使用c函数的包装器,并通过桥接头我在Swift中使用它。
- For concatenate wav files I use AVAssetExportSession with Swift
- 对于连接wav文件,我使用AVAssetExportSession和Swift
And now source codes. So first wrapper. It's class for converting .wav files to .mp3. There could be many changes (maybe parameter for output file and other options) but I think everyone could change it. I guess this could be rewritten to Swift but I wasn't sure how to do it. So it's Objective C class:
现在源代码。首先包装。它是将.wav文件转换为.mp3的类。可能会有很多变化(可能是输出文件和其他选项的参数),但我认为每个人都可以改变它。我想这可以改写为Swift,但我不知道该怎么做。所以它是Objective C类:
#import "AudioWrapper.h"
#import "lame/lame.h"
@implementation AudioWrapper
+ (void)convertFromWavToMp3:(NSString *)filePath {
NSString *mp3FileName = @"Mp3File";
mp3FileName = [mp3FileName stringByAppendingString:@".mp3"];
NSString *mp3FilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:mp3FileName];
NSLog(@"%@", mp3FilePath);
@try {
int read, write;
FILE *pcm = fopen([filePath cStringUsingEncoding:1], "rb"); //source
fseek(pcm, 4*1024, SEEK_CUR); //skip file header
FILE *mp3 = fopen([mp3FilePath cStringUsingEncoding:1], "wb"); //output
const int PCM_SIZE = 8192;
const int MP3_SIZE = 8192;
short int pcm_buffer[PCM_SIZE*2];
unsigned char mp3_buffer[MP3_SIZE];
lame_t lame = lame_init();
lame_set_in_samplerate(lame, 44100);
lame_set_VBR(lame, vbr_default);
lame_init_params(lame);
do {
read = fread(pcm_buffer, 2*sizeof(short int), PCM_SIZE, pcm);
if (read == 0)
write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
else
write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);
fwrite(mp3_buffer, write, 1, mp3);
} while (read != 0);
lame_close(lame);
fclose(mp3);
fclose(pcm);
}
@catch (NSException *exception) {
NSLog(@"%@",[exception description]);
}
@finally {
[self performSelectorOnMainThread:@selector(convertMp3Finish)
withObject:nil
waitUntilDone:YES];
}
}
Swift AudioHelper class for concatening audio files and calling method for converting .wav file to .mp3:
用于连接音频文件的Swift AudioHelper类和用于将.wav文件转换为.mp3的调用方法:
import UIKit
import AVFoundation
protocol AudioHelperDelegate {
func assetExportSessionDidFinishExport(session: AVAssetExportSession, outputUrl: NSURL)
}
class AudioHelper: NSObject {
var delegate: AudioHelperDelegate?
func concatenate(audioUrls: [NSURL]) {
//Create AVMutableComposition Object.This object will hold our multiple AVMutableCompositionTrack.
var composition = AVMutableComposition()
var compositionAudioTrack:AVMutableCompositionTrack = composition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: CMPersistentTrackID())
//create new file to receive data
var documentDirectoryURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first! as! NSURL
var fileDestinationUrl = NSURL(fileURLWithPath: NSTemporaryDirectory().stringByAppendingPathComponent("resultmerge.wav"))
println(fileDestinationUrl)
StorageManager.sharedInstance.deleteFileAtPath(NSTemporaryDirectory().stringByAppendingPathComponent("resultmerge.wav"))
var avAssets: [AVURLAsset] = []
var assetTracks: [AVAssetTrack] = []
var durations: [CMTime] = []
var timeRanges: [CMTimeRange] = []
var insertTime = kCMTimeZero
for audioUrl in audioUrls {
let avAsset = AVURLAsset(URL: audioUrl, options: nil)
avAssets.append(avAsset)
let assetTrack = avAsset.tracksWithMediaType(AVMediaTypeAudio)[0] as! AVAssetTrack
assetTracks.append(assetTrack)
let duration = assetTrack.timeRange.duration
durations.append(duration)
let timeRange = CMTimeRangeMake(kCMTimeZero, duration)
timeRanges.append(timeRange)
compositionAudioTrack.insertTimeRange(timeRange, ofTrack: assetTrack, atTime: insertTime, error: nil)
insertTime = CMTimeAdd(insertTime, duration)
}
//AVAssetExportPresetPassthrough => concatenation
var assetExport = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetPassthrough)
assetExport.outputFileType = AVFileTypeWAVE
assetExport.outputURL = fileDestinationUrl
assetExport.exportAsynchronouslyWithCompletionHandler({
self.delegate?.assetExportSessionDidFinishExport(assetExport, outputUrl: fileDestinationUrl!)
})
}
func exportTempWavAsMp3() {
let wavFilePath = NSTemporaryDirectory().stringByAppendingPathComponent("resultmerge.wav")
AudioWrapper.convertFromWavToMp3(wavFilePath)
}
}
Bridging header contains:
桥接头包含:
#import "lame/lame.h"
#import "AudioWrapper.h"
#2
6
We have dedicated classes to read/write media from/to a file they are AVAssetReader
and AVAssetWriter
and with the help of AVAssetExportSession
you can export it as mp3 file. or else you can use https://github.com/michaeltyson/TPAACAudioConverter
我们有专门的类来从/向AVAssetReader和AVAssetWriter文件读取/写入媒体,并且在AVAssetExportSession的帮助下,您可以将其导出为mp3文件。或者你可以使用https://github.com/michaeltyson/TPAACAudioConverter
#1
10
I would like to post my working solution because I get so many thumbs up and answer from naresh doesn't help me much.
我想发布我的工作解决方案,因为我得到了很多赞许,来自naresh的回答对我没什么帮助。
- I have generated lame.framework library from this project https://github.com/wuqiong/mp3lame-for-iOS
- 我从这个项目生成了lame.framework库https://github.com/wuqiong/mp3lame-for-iOS
- I've added library to my Swift project (Build Phases -> Link Binary With Libraries)
- 我已经将库添加到我的Swift项目中(Build Phases - > Link Binary with Libraries)
- I've created wrapper for using c functions in Objective C and by bridging header I use it in Swift.
- 我已经创建了在Objective C中使用c函数的包装器,并通过桥接头我在Swift中使用它。
- For concatenate wav files I use AVAssetExportSession with Swift
- 对于连接wav文件,我使用AVAssetExportSession和Swift
And now source codes. So first wrapper. It's class for converting .wav files to .mp3. There could be many changes (maybe parameter for output file and other options) but I think everyone could change it. I guess this could be rewritten to Swift but I wasn't sure how to do it. So it's Objective C class:
现在源代码。首先包装。它是将.wav文件转换为.mp3的类。可能会有很多变化(可能是输出文件和其他选项的参数),但我认为每个人都可以改变它。我想这可以改写为Swift,但我不知道该怎么做。所以它是Objective C类:
#import "AudioWrapper.h"
#import "lame/lame.h"
@implementation AudioWrapper
+ (void)convertFromWavToMp3:(NSString *)filePath {
NSString *mp3FileName = @"Mp3File";
mp3FileName = [mp3FileName stringByAppendingString:@".mp3"];
NSString *mp3FilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:mp3FileName];
NSLog(@"%@", mp3FilePath);
@try {
int read, write;
FILE *pcm = fopen([filePath cStringUsingEncoding:1], "rb"); //source
fseek(pcm, 4*1024, SEEK_CUR); //skip file header
FILE *mp3 = fopen([mp3FilePath cStringUsingEncoding:1], "wb"); //output
const int PCM_SIZE = 8192;
const int MP3_SIZE = 8192;
short int pcm_buffer[PCM_SIZE*2];
unsigned char mp3_buffer[MP3_SIZE];
lame_t lame = lame_init();
lame_set_in_samplerate(lame, 44100);
lame_set_VBR(lame, vbr_default);
lame_init_params(lame);
do {
read = fread(pcm_buffer, 2*sizeof(short int), PCM_SIZE, pcm);
if (read == 0)
write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
else
write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);
fwrite(mp3_buffer, write, 1, mp3);
} while (read != 0);
lame_close(lame);
fclose(mp3);
fclose(pcm);
}
@catch (NSException *exception) {
NSLog(@"%@",[exception description]);
}
@finally {
[self performSelectorOnMainThread:@selector(convertMp3Finish)
withObject:nil
waitUntilDone:YES];
}
}
Swift AudioHelper class for concatening audio files and calling method for converting .wav file to .mp3:
用于连接音频文件的Swift AudioHelper类和用于将.wav文件转换为.mp3的调用方法:
import UIKit
import AVFoundation
protocol AudioHelperDelegate {
func assetExportSessionDidFinishExport(session: AVAssetExportSession, outputUrl: NSURL)
}
class AudioHelper: NSObject {
var delegate: AudioHelperDelegate?
func concatenate(audioUrls: [NSURL]) {
//Create AVMutableComposition Object.This object will hold our multiple AVMutableCompositionTrack.
var composition = AVMutableComposition()
var compositionAudioTrack:AVMutableCompositionTrack = composition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: CMPersistentTrackID())
//create new file to receive data
var documentDirectoryURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first! as! NSURL
var fileDestinationUrl = NSURL(fileURLWithPath: NSTemporaryDirectory().stringByAppendingPathComponent("resultmerge.wav"))
println(fileDestinationUrl)
StorageManager.sharedInstance.deleteFileAtPath(NSTemporaryDirectory().stringByAppendingPathComponent("resultmerge.wav"))
var avAssets: [AVURLAsset] = []
var assetTracks: [AVAssetTrack] = []
var durations: [CMTime] = []
var timeRanges: [CMTimeRange] = []
var insertTime = kCMTimeZero
for audioUrl in audioUrls {
let avAsset = AVURLAsset(URL: audioUrl, options: nil)
avAssets.append(avAsset)
let assetTrack = avAsset.tracksWithMediaType(AVMediaTypeAudio)[0] as! AVAssetTrack
assetTracks.append(assetTrack)
let duration = assetTrack.timeRange.duration
durations.append(duration)
let timeRange = CMTimeRangeMake(kCMTimeZero, duration)
timeRanges.append(timeRange)
compositionAudioTrack.insertTimeRange(timeRange, ofTrack: assetTrack, atTime: insertTime, error: nil)
insertTime = CMTimeAdd(insertTime, duration)
}
//AVAssetExportPresetPassthrough => concatenation
var assetExport = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetPassthrough)
assetExport.outputFileType = AVFileTypeWAVE
assetExport.outputURL = fileDestinationUrl
assetExport.exportAsynchronouslyWithCompletionHandler({
self.delegate?.assetExportSessionDidFinishExport(assetExport, outputUrl: fileDestinationUrl!)
})
}
func exportTempWavAsMp3() {
let wavFilePath = NSTemporaryDirectory().stringByAppendingPathComponent("resultmerge.wav")
AudioWrapper.convertFromWavToMp3(wavFilePath)
}
}
Bridging header contains:
桥接头包含:
#import "lame/lame.h"
#import "AudioWrapper.h"
#2
6
We have dedicated classes to read/write media from/to a file they are AVAssetReader
and AVAssetWriter
and with the help of AVAssetExportSession
you can export it as mp3 file. or else you can use https://github.com/michaeltyson/TPAACAudioConverter
我们有专门的类来从/向AVAssetReader和AVAssetWriter文件读取/写入媒体,并且在AVAssetExportSession的帮助下,您可以将其导出为mp3文件。或者你可以使用https://github.com/michaeltyson/TPAACAudioConverter