iOS Swift - объединяйте и конвертируйте файлы .wav в .mp3

Я хочу объединить два или более файла .wav в один, а затем преобразовать его в .mp3, и это я хотел бы сделать в Swift (или, по крайней мере, иметь возможность включить его в проект Swift).

Объединить два файла .wav в swift - не проблема. Вот мой пример. Теперь я не знаю, как добавить хромую библиотеку в быстрый проект и как ее использовать (как чтобы изменить объективный синтаксис использования кода, чтобы использовать его быстро).

Я застрял в быстром, поэтому я попробовал библиотеку Lame с Objective C. Я нашел пример кода для преобразования .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
{
}

Но в результате получается просто .mp3 с шумом.

Итак, мне нужно исправить три мои проблемы:

  • Создать правильный mp3 из caf в Objective C
  • Измените код, чтобы использовать его для файла wav
  • И измените его, чтобы можно было использовать его в Swift

Я знаю, что есть много вопросов о кодировании и преобразовании mp3 в iOS, но я не могу найти ни одного с примером Swift, и я не могу найти пример с рабочим кодом Objective C (только код выше). Спасибо за помощь


person Libor Zapletal    schedule 16.07.2015    source источник
comment
в этом коде подсчет щедрости, если больше их wav файла с высокой памятью, затем код сбоя ... не конвертировать wav в файл mp3   -  person Ramani Hitesh    schedule 12.09.2018


Ответы (2)


Я хотел бы опубликовать свое рабочее решение, потому что я получаю очень много внимания, а ответ от naresh мне не очень помогает.

  1. Я создал библиотеку lame.framework из этого проекта https://github.com/wuqiong/mp3lame-for-iOS
  2. Я добавил библиотеку в свой проект Swift (Этапы сборки -> Связать двоичный файл с библиотеками)
  3. Я создал оболочку для использования функций c в Objective C и, связав заголовок, использую его в Swift.
  4. Для объединения файлов wav я использую AVAssetExportSession с Swift

А теперь исходники. Итак, первая обертка. Это класс для преобразования файлов .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 для объединения аудиофайлов и вызова метода преобразования файла .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)
    }
}

Заголовок моста содержит:

#import "lame/lame.h"
#import "AudioWrapper.h"
person Libor Zapletal    schedule 27.08.2015
comment
Где находится метод convertMp3Finish (), который вызывается внутри AudioWrapper? - person Dylan Moore; 16.10.2017
comment
Он вызывается в файле Objective-C Bridged, потому что библиотека создана с помощью Objective-C - person J A S K I E R; 11.04.2020
comment
привет, у меня AudioWrapper.h не найден при импорте в мост, вы можете помочь? - person famfamfam; 30.03.2021

У нас есть специальные классы для чтения / записи носителей из / в файл, это AVAssetReader и AVAssetWriter, и с помощью AVAssetExportSession вы можете экспортировать его как файл mp3. или вы можете использовать https://github.com/michaeltyson/TPAACAudioConverter

person naresh    schedule 24.07.2015
comment
Моя проблема с вашим ответом заключается в том, что когда я попробовал AVFileTypeMPEGLayer3 как outputFileType с AVAssetExportSession, я получил исключение Invalid output file type. Я думаю, мне нужны файлы mp3 для начала, чтобы иметь возможность экспортировать их в mp3. Второе решение с библиотекой не экспортируется в mp3, или я не нашел об этом никакой информации. Он конвертирует аудиофайлы в формат .m4a. - person Libor Zapletal; 28.07.2015