2016-09-29 56 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) 
    ] 
}