2016-09-29 60 views
1

我的应用程序需要生成一个音频文件,我正在写我的最后一个Android版本的文件生成器。在Android上,它使用OKIO来处理IO和iOS,它使用本地NSData。错误的字节生成创建WAV文件

每个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的代码生成的最顶层文件):

enter image description here

斯威夫特3

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

+0

你有没有解决这个问题? – astromme

+0

是:)解决了! –

+0

你可以在这里发布答案吗? – astromme

回答

0

编写的totalFileSize在iOS上看起来很大,而在Android上看起来很小。也许你会这样做两次吗?

iOS的data块看起来不正确或者,在Android上有合理的采样值data后,但在iOS上,它看起来像你已经采取了一些CoreAudio的结构(也许一个AudioUnitExtAudioFile地址?一AudioConverter?)。

+0

我删除了提供数据的代码。但它只是读取一个PCM文件,将字节和这些字节放在临时缓冲区中。 –

+0

关于第一个问题,我真的不知道,这与价值或职位有关吗? –

+0

啊,你已经将'.caf'文件的头文件写入了你的wav文件。这不会很好。是的,'.caf'文件是lpcm,但是是什么格式?你可能需要先解码。 wav文件中'totalFileSize'的值错误 –

0

其中一个主要问题是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) 
    ] 
}