我的应用需要生成一个音频文件,并且我在上一个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上这两个参数是错误的。看(Android代码生成的大多数顶级文件,底部是由iOS代码生成的):
Swift 3
我真的不知道发生了什么,你能帮助我吗?
答案 0 :(得分:1)
其中一个主要问题是readInt
函数正在返回big-endian,它需要是little-endian。
无论如何,这对我有用。这是我初始化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)
]
}
答案 1 :(得分:0)
书面totalFileSize
在iOS上看起来很大端,而在Android上看起来很小。也许你会{{}}两次?
iOS .littleEndian
块看起来也不正常,在Android上data
之后有合理的样本值,但在iOS上看起来你已经采取了一些地址CoreAudio结构(可能是data
?AudioUnit
?ExtAudioFile
?)。