Swift de iOS: fusiona y convierte archivos.wav a.mp3
audio lame (2)
Quiero fusionar dos o más archivos .wav en uno y luego convertirlo en .mp3 y esto me gustaría hacerlo en Swift (o al menos tener la opción de incluirlo en swift project).
Combinar dos archivos .wav en swift no es problema. Aquí está mi ejemplo. Ahora no sé cómo agregar la biblioteca cojo al proyecto swift y cómo usarlo (cómo cambiar la sintaxis de uso del código objetivo para usarlo en swift).
Me quedé atrapado en Swift, así que probé Lame Library con Objective C. Encontré un código de ejemplo para convertir .caf a .mp3, así que lo probé. Esto es lo que he intentado:
- (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
{
}
Pero el resultado de esto es simplemente .mp3 con ruido.
Así que necesito arreglar mis tres problemas:
- Crea el mp3 correcto de caf en Objective C
- Cambia el código para usarlo para el archivo wav
- Y cambiarlo para poder usarlo en Swift.
Sé que hay muchas preguntas sobre la codificación y conversión de mp3 en iOS, pero no puedo encontrar una con el ejemplo de Swift y no puedo encontrar un ejemplo con el código de Objective C en funcionamiento (solo el código de arriba). Gracias por la ayuda
Me gustaría publicar mi solución de trabajo porque tengo muchos pulgares hacia arriba y la respuesta de naresh no me ayuda mucho.
- He generado la biblioteca lame.framework de este proyecto https://github.com/wuqiong/mp3lame-for-iOS
- He agregado una biblioteca a mi proyecto Swift (Build Phases -> Link Binary With Libraries)
- He creado un contenedor para usar las funciones c en Objective C y, al enlazar el encabezado, lo uso en Swift.
- Para los archivos wav de concatenación, uso AVAssetExportSession con Swift
Y ahora los códigos fuente. Así que la primera envoltura. Es una clase para convertir archivos .wav a .mp3. Podría haber muchos cambios (quizás un parámetro para el archivo de salida y otras opciones) pero creo que todos podrían cambiarlo. Supongo que esto podría reescribirse a Swift pero no estaba seguro de cómo hacerlo. Así que es la clase de Objetivo 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];
}
}
Clase Swift AudioHelper para concatenar archivos de audio y método de llamada para convertir archivos .wav a .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)
}
}
El encabezado puente contiene:
#import "lame/lame.h"
#import "AudioWrapper.h"
Tenemos clases dedicadas a leer / escribir medios desde / a un archivo que son AVAssetReader
y AVAssetWriter
y con la ayuda de AVAssetExportSession
puede exportarlo como un archivo mp3. o puede usar https://github.com/michaeltyson/TPAACAudioConverter