【问题标题】:iOS Swift - Merge and convert .wav files to .mp3iOS Swift - 将 .wav 文件合并并转换为 .mp3
【发布时间】:2015-10-05 18:43:58
【问题描述】:

我想将两个或多个 .wav 文件合并为一个,然后将其转换为 .mp3,我想在 Swift 中完成此操作(或者至少可以选择将其包含到 swift 项目中)。

在 swift 中合并两个 .wav 文件不是问题。 Here is my example 现在我不知道如何将 lame 库添加到 swift 项目以及如何使用它(如何更改目标 c lame 代码使用语法以在 swift 中使用它)。

我坚持使用 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
{
}

但这样做的结果只是带有噪音的 .mp3。

所以我需要解决我的三个问题:

  • 在 Objective C 中从 caf 创建正确的 mp3
  • 更改代码以将其用于 wav 文件
  • 并将其更改为能够在 Swift 中使用它

我知道在 iOS 中有很多关于编码和转换 mp3 的问题,但我找不到 Swift 示例,也找不到使用 Objective C 代码的示例(只是上面的代码)。感谢您的帮助

【问题讨论】:

  • 在此代码中计数赏金如果更多的高内存 wav 文件然后崩溃代码...不将 wav 转换为 mp3 文件

标签: ios swift audio mp3 lame


【解决方案1】:

我想发布我的工作解决方案,因为我得到了很多赞,而 naresh 的回答对我没有多大帮助。

  1. 我已经从这个项目https://github.com/wuqiong/mp3lame-for-iOS生成了lame.framework库
  2. 我已将库添加到我的 Swift 项目(构建阶段 -> 将二进制文件与库链接)
  3. 我创建了用于在 Objective C 中使用 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"

【讨论】:

  • AudioWrapper 内部调用的 convertMp3Finish() 方法在哪里?
  • 它在Objective-C桥接文件中被调用,因为该库是用Objective-C完成的
  • 嗨,我在导入桥接时找不到“AudioWrapper.h”,你能帮忙吗?
【解决方案2】:

我们有专门的类来从/向文件读取/写入媒体,它们是 AVAssetReaderAVAssetWriter,在 AVAssetExportSession 的帮助下,您可以将其导出为 mp3 文件。 否则你可以使用https://github.com/michaeltyson/TPAACAudioConverter

【讨论】:

  • 我对您的回答的问题是,当我尝试将AVFileTypeMPEGLayer3outputFileTypeAVAssetExportSession 一起尝试时,我得到了异常Invalid output file type。我想我一开始需要 mp3 文件才能将它们导出为 mp3。使用库的第二个解决方案没有导出到 mp3,或者我没有找到任何相关信息。它将音频文件转换为 .m4a。
猜你喜欢
  • 2017-08-23
  • 2011-06-19
  • 1970-01-01
  • 1970-01-01
  • 2019-03-11
  • 2017-07-06
  • 2011-12-23
  • 2013-01-17
  • 2012-05-04
相关资源
最近更新 更多