2016-09-29 1 views
1

Meine App muss eine Audiodatei generieren und ich schreibe den Dateigenerator nach meiner letzten Android-Version. Auf Android verwendet es OKIO, um mit IO und iOS umzugehen, es verwendet die nativen NSData.Falsche Bytes erzeugt, um WAV-Datei zu erstellen

Jede WAV-Datei benötigt eine Kopfzeile, um einige Parameter für den Datenleser (Media Player) zu informieren.

Es verwendet diesen Dateigenerator, Bytes schreiben, die einigen Spezifikationen folgen, die auf dem Internet zur Verfügung gestellt werden.

//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 

Es nutzt diese Methode Int auf den Puffer zu schreiben:

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)] 
} 

Auf Android, wird die Datei ohne Probleme erzeugt werden. Aber auf iOS sind diese 2 Parameter falsch. Schauen Sie (die meisten Top-Datei generiert auf Android-Code und der Unterseite von iOS-Code generiert wurde):

enter image description here

Swift 3

Ich weiß wirklich nicht, was passiert ist, können Sie mir helfen?

+0

Haben Sie das jemals gelöst? – astromme

+0

Ja :) Gelöst !! –

+0

Können Sie die Antwort hier posten? – astromme

Antwort

0

Die geschriebenen totalFileSize sieht Big Endian auf iOS, während auf Android es klein ist. Vielleicht bist du .littleEndian ing es zweimal?

Der iOS data Block auch nicht richtig sieht, auf Android gibt es plausible Beispielwerte nach data, aber auf iOS sieht es aus wie Sie die Adresse einiger CoreAudio- Struktur genommen haben (vielleicht ein AudioUnit? Ein ExtAudioFile? Ein AudioConverter?).

+0

Ich entfernte den Code, der die Daten bereitstellt. Aber es liest einfach eine PCM-Datei, holt Bytes und und diese Bytes auf einem temporären Puffer. –

+0

Über die erste Frage, die ich wirklich nicht weiß, hängt das mit dem Wert oder der Position zusammen? –

+0

ah, Sie haben den Header einer '.caf' Datei in Ihre wav Datei geschrieben. das wird nicht gut enden. Ja, die '.caf' Datei ist lpcm, aber welches Format? Sie werden es wahrscheinlich zuerst entschlüsseln müssen. der Wert von 'totalFileSize' ist in der wav-Datei falsch –

0

Eines der Hauptprobleme ist, dass die readInt Funktion Big-Endian zurückgibt, muss es Little-Endian sein.

Wie auch immer, das funktionierte für mich. So initialisiere ich eine WAV-Datei. Hoffe es hilft jemandem.

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) 
    ] 
} 
Verwandte Themen