【问题标题】:Wrong bytes generated to create WAV file为创建 WAV 文件而生成的错误字节
【发布时间】:2016-09-29 23:21:25
【问题描述】:

我的应用需要生成一个音频文件,我正在按照我的上一个 Android 版本编写文件生成器。在 Android 上它使用OKIO 处理 IO,而在 iOS 上它使用原生 NSData。

每个 WAV 文件都需要一个标头来通知数据读取器(媒体播放器)的一些参数。

它使用这个文件生成器,按照互联网上提供的一些规范写入字节。

//Audio file content, this variable will be used
//to storage the audio data (PCM).
var content = [UInt8]() //This is not empty.
var fileSize: Int = 0 //this is not zero.

//Total size of the file, with the header.
let totalFileSize = fileSize + HEADER_SIZE

//Header data
let header = NSMutableData()

//RIFF
header.append([UInt8]("RIFF".utf8), length: 4)

//Size of the entity file
header.append(Data(bytes: readInt(Int32(totalFileSize).littleEndian)))

//WAVE
header.append([UInt8]("WAVE".utf8), length: 4)

//FMT
header.append([UInt8]("fmt ".utf8), length: 4)

//BITRATE
header.append(Data(bytes: readInt(BITRATE.littleEndian)))

//Audio format
var audioFormat = AUDIO_FORMAT_PCM.littleEndian
header.append(&audioFormat, length: 2)

//Number of channels
var audioChannels = CHANNELS.littleEndian
header.append(&audioChannels, length: 2)

//Sample rate
var sampleRate = SAMPLE_RATE.littleEndian
header.append(&sampleRate, length: 4)

//Byte rate
var byteRate = ((SAMPLE_RATE*UInt32(CHANNELS)*UInt32(BYTES_PER_SAMPLE))/UInt32(8)).littleEndian
header.append(&byteRate, length: 4)

//Block align
var blockAlign = (UInt16(CHANNELS) * UInt16(BYTES_PER_SAMPLE) / UInt16(8)).littleEndian
header.append(&blockAlign, length: 2)

//Bytes per sample
var bytesPerSample = BYTES_PER_SAMPLE.littleEndian
header.append(&bytesPerSample, length: 2)

//Data
header.append([UInt8]("data".utf8), length: 4)

//Size of the audio data
var sizeLittleEndian = UInt32(fileSize).littleEndian
header.append(&sizeLittleEndian, length: 4)

print(header.length) //44

它使用这种方法将 Int 写入缓冲区:

func readInt(_ i: Int32) -> [UInt8] {
  return [UInt8(truncatingBitPattern: (i >> 24) & 0xff),
          UInt8(truncatingBitPattern: (i >> 16) & 0xff),
          UInt8(truncatingBitPattern: (i >>  8) & 0xff),
          UInt8(truncatingBitPattern: (i      ) & 0xff)]
}

在 Android 上,文件正在生成,没有任何问题。但在 iOS 上,这两个参数是错误的。看(大部分top文件是Android代码生成的,bottom文件是iOS代码生成的):

斯威夫特 3

我真的不知道发生了什么,你能帮帮我吗?

【问题讨论】:

  • 你解决过这个问题吗?
  • 是的 :) 解决了!!
  • 你能把答案贴在这里吗?

标签: swift avfoundation nsdata byte-shifting


【解决方案1】:

其中一个主要问题是readInt 函数返回大端,它必须是小端。

无论如何,这对我有用。这就是我初始化 WAV 文件的方式。希望它可以帮助某人。

func createHeader() {

    let sampleRate:Int32 = 44100
    let chunkSize:Int32 = 36
    let subChunkSize:Int32 = 16
    let format:Int16 = 1
    let channels:Int16 = 1
    let bitsPerSample:Int16 = 16
    let byteRate:Int32 = sampleRate * Int32(channels * bitsPerSample / 8)
    let blockAlign: Int16 = channels * 2
    let dataSize:Int32 = 0

    let header = NSMutableData()

    header.append([UInt8]("RIFF".utf8), length: 4)
    header.append(intToByteArray(chunkSize), length: 4)

    //WAVE
    header.append([UInt8]("WAVE".utf8), length: 4)

    //FMT
    header.append([UInt8]("fmt ".utf8), length: 4)

    header.append(intToByteArray(subChunkSize), length: 4)
    header.append(shortToByteArray(format), length: 2)
    header.append(shortToByteArray(channels), length: 2)
    header.append(intToByteArray(sampleRate), length: 4)
    header.append(intToByteArray(byteRate), length: 4)
    header.append(shortToByteArray(blockAlign), length: 2)
    header.append(shortToByteArray(bitsPerSample), length: 2)


    header.append([UInt8]("data".utf8), length: 4)

    header.append(intToByteArray(dataSize), length: 4)

    header.write(to: fileURL!, atomically: true)

}

func intToByteArray(_ i: Int32) -> [UInt8] {
    return [
            //little endian
            UInt8(truncatingBitPattern: (i      ) & 0xff),
            UInt8(truncatingBitPattern: (i >>  8) & 0xff),
            UInt8(truncatingBitPattern: (i >> 16) & 0xff),
            UInt8(truncatingBitPattern: (i >> 24) & 0xff)
    ]
}

func shortToByteArray(_ i: Int16) -> [UInt8] {
    return [
        //little endian
        UInt8(truncatingBitPattern: (i      ) & 0xff),
        UInt8(truncatingBitPattern: (i >>  8) & 0xff)
    ]
}

【讨论】:

    【解决方案2】:

    totalFileSize 在 iOS 上看起来很大,而在 Android 上看起来很小。也许你是 .littleEndianing 两次?

    iOS 的 data 块看起来也不正确,在 Android 上,data 之后有合理的样本值,但在 iOS 上,您似乎获取了一些 CoreAudio 结构的地址(可能是 AudioUnit ? 一个ExtAudioFile? 一个AudioConverter?)。

    【讨论】:

    • 我删除了提供数据的代码。但它只是读取一个 PCM 文件,获取字节,然后将这些字节放在临时缓冲区中。
    • 关于第一个问题,我真的不知道,这跟价值还是职位有关?
    • 啊,您已将.caf 文件的标题写入您的wav 文件。这不会有好的结局。是的,.caf 文件是 lpcm,但是什么格式?您可能需要先对其进行解码。 wav文件中totalFileSize的值错误
    • 不是,这是在写PCM文件,录音机使用kAudioFormatLinearPCM作为格式,比特率:16000,采样率:44100。这个问题不仅和totalFileSize的值有关,还有还有header.append(Data(bytes: readInt(BITRATE.littleEndian)))
    猜你喜欢
    • 1970-01-01
    • 2020-12-16
    • 2014-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-16
    • 2011-02-09
    相关资源
    最近更新 更多