2016-09-29 9 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 эти 2 параметра ошибочны. Посмотрите (Самый верхний файл, созданный на Android код и внизу был сгенерирован IOS код):

enter image description here

Swift 3

Я действительно не знаю, что происходит, вы можете мне помочь?

+0

Вы когда-нибудь разрешали это? – astromme

+0

Да :) Решено! –

+0

Можете ли вы разместить ответ здесь? – astromme

ответ

0

Написано totalFileSize выглядит большим энтузиастом на iOS, а на Android оно мало. Может быть, вы забыли .littleEndian?

КСН data блок выглядит не так, как на Android есть правдоподобные значения образца после data, но прошивка это выглядит, как вы сделали адрес некоторой структуры CoreAudio (может быть, AudioUnit? ExtAudioFile? AudioConverter?).

+0

Я удалил код, который предоставляет данные. Но он просто читает файл PCM, получает байты и эти байты во временном буфере. –

+0

О первом вопросе, я действительно не знаю, связано ли это со значением или положением? –

+0

ах, вы написали заголовок файла '.caf' в ваш wav-файл. это не закончится хорошо. да, файл '.caf' - lpcm, но какой формат? вам, скорее всего, придется сначала его декодировать. значение 'totalFileSize' неверно в wav-файле –

0

Одна из основных проблем заключается в том, что функция readInt возвращает big-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) 
    ] 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^