2015-05-25 16 views
5

Ich nahm Sprachaufnahmen von meinem Mikrofon mit Adobe Flash Builder 4.6/AIR auf, Sprachaufnahmen wurden erfolgreich aufgenommen. Ich konvertierte zuerst Sprachdaten (Byte-Array) in Base64-Format in Actionscript, dann wandelte ich diese Base64-Daten in WAV-Datei mit meinem PHP-Code. aber diese WAV-Datei verursacht ein beschädigtes Datei-Problem in RiffPad.Fehler bei der Aufnahme von Audioaufnahmen in Actionscript

RIFFPad ist ein Viewer für RIFF-formatierte Dateien wie WAV, AVI.

erwartete WAV-Datei-Spezifikation:

Abtastrate: 22kHz

// -- saves the current audio data as a .wav file 
    protected function onSubmit(event:Event):void { 
     alertBox.show("Processing ... please wait."); 

     stopPlayback(); 
     stopRecording(); 
     playBtn.enabled = recordBtn.enabled = submitBtn.enabled = false; 
     var position:int = capture.buffer.position; 
     var wavWriter:WAVWriter = new WAVWriter() 
     var wavWriter1:WaveEncoder = new WaveEncoder() 
     wavWriter.numOfChannels = 1; 
     wavWriter.samplingRate = 22050; 
     wavWriter.sampleBitRate = 16; 
     var wavBytes:ByteArray = new ByteArray; 
     capture.buffer.position = 0; 
     wavWriter.processSamples(wavBytes, capture.buffer, capture.microphone.rate * 1000, 1); 
     Settings.alertBox3.show("RATE :"+capture.microphone.rate); //Here show RATE: 8 
     //wavWriter.processSamples(wavBytes, capture.buffer, 22050, 1); 
     //wavBytes = wavWriter1.encode(capture.buffer, 1, 16, 22050); 
     capture.buffer.position = position; 
     wavBytes.position=0; 
     submitVoiceSample(Base64_new.encodeByteArray(wavBytes)); 
    } 

WAV Writer Kopffunktion:

public var samplingRate = 22050; 
public var sampleBitRate:int = 8; 
public var numOfChannels:int = 2; 
private var compressionCode:int = 1; 

private function header(dataOutput:IDataOutput, fileSize:Number):void 
{ 
    dataOutput.writeUTFBytes("RIFF"); 
    dataOutput.writeUnsignedInt(fileSize); // Size of whole file 
    dataOutput.writeUTFBytes("WAVE"); 
    // WAVE Chunk 
    dataOutput.writeUTFBytes("fmt "); // Chunk ID 
    dataOutput.writeUnsignedInt(16); // Header Chunk Data Size 
    dataOutput.writeShort(compressionCode); // Compression code - 1 = PCM 
    dataOutput.writeShort(numOfChannels); // Number of channels 
    dataOutput.writeUnsignedInt(samplingRate); // Sample rate 
    dataOutput.writeUnsignedInt(samplingRate * numOfChannels * sampleBitRate/8); // Byte Rate == SampleRate * NumChannels * BitsPerSample/8  
    dataOutput.writeShort(numOfChannels * sampleBitRate/8); // Block align == NumChannels * BitsPerSample/8 
    dataOutput.writeShort(sampleBitRate); // Bits Per Sample 
} 

WAV-Datei Writer-Funktion:

public function processSamples(dataOutput:IDataOutput, dataInput:ByteArray, inputSamplingRate:int, inputNumChannels:int = 1):void 
{ 
    if (!dataInput || dataInput.bytesAvailable <= 0) // Return if null 
     throw new Error("No audio data"); 

    // 16 bit values are between -32768 to 32767. 
    var bitResolution:Number = (Math.pow(2, sampleBitRate)/2)-1; 
    var soundRate:Number = samplingRate/inputSamplingRate; 
    var dataByteLength:int = ((dataInput.length/4) * soundRate * sampleBitRate/8); 
    // data.length is in 4 bytes per float, where we want samples * sampleBitRate/8 for bytes 
    //var fileSize:int = 32 + 8 + dataByteLength; 
    var fileSize:int = 32 + 4 + dataByteLength; 
    // WAV format requires little-endian 
    dataOutput.endian = Endian.LITTLE_ENDIAN; 
    // RIFF WAVE Header Information 
    header(dataOutput, fileSize); 
    // Data Chunk Header 
    dataOutput.writeUTFBytes("data"); 
    dataOutput.writeUnsignedInt(dataByteLength); // Size of whole file 

    // Write data to file 
    dataInput.position = 0; 
    var tempData:ByteArray = new ByteArray(); 
    tempData.endian = Endian.LITTLE_ENDIAN; 

    // Write to file in chunks of converted data. 
    while (dataInput.bytesAvailable > 0) 
    { 
     tempData.clear(); 
     // Resampling logic variables 
     var minSamples:int = Math.min(dataInput.bytesAvailable/4, 8192); 
     var readSampleLength:int = minSamples;//Math.floor(minSamples/soundRate); 
     var resampleFrequency:int = 100; // Every X frames drop or add frames 
     var resampleFrequencyCheck:int = (soundRate-Math.floor(soundRate))*resampleFrequency; 
     var soundRateCeil:int = Math.ceil(soundRate); 
     var soundRateFloor:int = Math.floor(soundRate); 
     var jlen:int = 0; 
     var channelCount:int = (numOfChannels-inputNumChannels); 
     /* 
     trace("resampleFrequency: " + resampleFrequency + " resampleFrequencyCheck: " + resampleFrequencyCheck 
      + " soundRateCeil: " + soundRateCeil + " soundRateFloor: " + soundRateFloor); 
     */ 
     var value:Number = 0; 
     // Assumes data is in samples of float value 
     for (var i:int = 0;i < readSampleLength;i+=4) 
     { 
      value = dataInput.readFloat(); 
      // Check for sanity of float value 
      if (value > 1 || value < -1) 
       throw new Error("Audio samples not in float format"); 

      // Special case with 8bit WAV files 
      if (sampleBitRate == 8) 
       value = (bitResolution * value) + bitResolution; 
      else 
       value = bitResolution * value; 

      // Resampling Logic for non-integer sampling rate conversions 
      jlen = (resampleFrequencyCheck > 0 && i % resampleFrequency < resampleFrequencyCheck) ? soundRateCeil : soundRateFloor; 
      for (var j:int = 0; j < jlen; j++) 
      { 
       writeCorrectBits(tempData, value, channelCount); 
      } 
     } 
     dataOutput.writeBytes(tempData); 
    } 
} 

ich sende, dass Base64 Daten zu meiner Dienstanforderung php Seite Ich habe die '$ this-> request-> voiceSample' Parameter und dekodieren Base64-Datei in .wav

file_put_contents('name.wav', base64_decode($this->request->voiceSample)); 

Nach Last, dass "name.wav" Datei in Riffpad ich habe Ausgabe

Es gibt zusätzlichen Müll am Ende der Datei.

Jeder bitte den Rat geben Sie mir, dieses Problem zu lösen ...

+0

Überprüfen Sie, ob Ihr Base64-String-Encoder korrekt ist, indem Sie ihn mit öffentlich aktivierten Encodern vergleichen. Überprüfen Sie auch, ob Ihr PHP-Decoder richtig geschrieben ist (es sei denn, es handelt sich um eine eingebaute Funktion). Überprüfen Sie auch, ob Ihre Flash-Seite vom Byte-Endian abhängt (es gibt eine versteckte Abhängigkeit in 'c = Daten [int (i ++)] << 16 | Daten [int (i ++)] << 8 | Daten [int (i ++)]; "Teil zumindest"). – Vesper

+0

Hallo Vesper, ich benutze Codierung [Base64] (http://www.sociodox.com/base64.html) Lib für ByteArray zu Base64-Konvertierung. In der PHP-Seite verwende ich eingebaute Funktion. – VijayRagavan

+0

Wenn Sie die dekodierte Datei über den Hex-Editor anzeigen, hat sie eine "RIFF" -Signatur in den ersten 4 Bytes? Wenn nicht, müssen Sie Ihre Konvertierungsroutine (n) debuggen. – Vesper

Antwort

2

Es ist eine inhärente Fehler in dieser Zeile:

wavWriter.processSamples(wavBytes, capture.buffer, capture.microphone.rate * 1000, 1); 

Die Microphone.rate Handbuch erklärt, dass tatsächliche Abtastfrequenz unterscheidet sich von microphone.rate*1000 wie von diesem Code erwartet. Die aktuelle Tabelle ist wie folgt:

rate Actual frequency 
44  44,100 Hz 
22  22,050 Hz 
11  11,025 Hz 
8  8,000 Hz 
5  5,512 Hz 

So, während Ihr Code Kommentare Zustand, dass rate als 8 berichtet wird, ist dies nicht der Fall auf der Client-Seite im Allgemeinen sein könnte, so führt den Nachschlag vor dem abgeleitet vorbei Abtastrate in wavWriter.processSamples().

Als nächstes berechnen Sie dataByteLength über Fließkommaberechnung, dies könnte am Ende ungenau sein, da Sie dann die Daten byteweise abtasten, also ist es besser, zuerst resample, dann Datenlänge sammeln und erst dann alle Daten in schreiben dataOutput, wie folgt aus:

public function processSamples(dataOutput:IDataOutput, dataInput:ByteArray, inputSamplingRate:int, inputNumChannels:int = 1):void 
{ 
    if (!dataInput || dataInput.bytesAvailable <= 0) // Return if null 
     throw new Error("No audio data"); 

    // 16 bit values are between -32768 to 32767. 
    var bitResolution:Number = (Math.pow(2, sampleBitRate)/2)-1; 
    // var soundRate:Number = samplingRate/inputSamplingRate; 
    // var fileSize:int = 32 + 4 + dataByteLength; kept for reference 
    // fmt tag is 4+4+16, data header is 8 bytes in size, and 4 bytes for WAVE 
    // but the data length is not yet determined 
    // WAV format requires little-endian 
    dataOutput.endian = Endian.LITTLE_ENDIAN; 
    // Prepare data for data to file 
    dataInput.position = 0; 
    var tempData:ByteArray = new ByteArray(); 
    tempData.endian = Endian.LITTLE_ENDIAN; 
    // Writing in chunks is no longer possible, because we don't have the header ready 

    // Let's precalculate the data needed in the loop 
    var step:Number=inputSamplingRate/samplingRate; // how far we should step into the input data to get next sample 
    var totalOffset:Number=1.0-1e-8; // accumulator for step 
    var oldChannels:Array=[]; 
    var i:int; 
    for (i=0;i<numOfChannels;i++) oldChannels.push(0.0); 
    // previous channels' sample holder 
    var newChannels:Array=oldChannels.slice(); // same for new channels that are to be read from byte array 
    // reading first sample set from input byte array 
    if (dataInput.bytesAvailable>=inputNumChannels*4) { 
     for (i=0;i<inputNumChannels;i++) { 
      var buf:Number=dataInput.readFloat(); 
      if (buf > 1) buf=1; if (buf < -1) buf=-1; 
      newChannels[i]=buf; 
     } 
     // if there's one channel, copy data to other channels 
     if ((inputNumChannels==1) && (numOfChannels>1)) { 
      for (i=1;i<numOfChannels;i++) newChannels[i]=newChannels[0];     
     } 
    } 
    while ((dataInput.bytesAvailable>=inputNumChannels*4) || (totalOffset<1.0)) 
    { 
     // sample next value for output wave file 
     var value:Number; 
     for (i=0;i<numOfChannels;i++) { 
      value = (totalOffset*newChannels[i])+(1.0-totalOffset)*oldChannels[i]; 
      // linear interpolation between old sample and new sample 
      // Special case with 8bit WAV files 
      if (sampleBitRate == 8) 
       value = (bitResolution * value) + bitResolution; 
      else 
       value = bitResolution * value; 
      // writing one channel into tempData 
      writeCorrectBits(tempData, value, 0); 
     } 
     totalOffset+=step; // advance per output sample 
     while ((totalOffset>1) && (dataInput.bytesAvailable>=inputNumChannels*4)) { 
      // we need a new sample, and have a sample to process in input 
      totalOffset-=1; 
      for (i=0;i<numOfChannels;i++) oldChannels[i]=newChannels[i]; // store old sample 
      // get another sample, copypasted from above 
      for (i=0;i<inputNumChannels;i++) { 
       value=dataInput.readFloat(); 
       if (value > 1) value=1; if (value < -1) value=-1; // sanity check 
       // I made it clip instead of throwing exception, replace if necessary 
       // if (value > 1 || value < -1) throw new Error("Audio samples not in float format"); 
       newChannels[i]=value; 
      } 
      if ((inputNumChannels==1) && (numOfChannels>1)) { 
       for (i=1;i<numOfChannels;i++) newChannels[i]=newChannels[0]; 
      } 
     } // end advance by totalOffset 
    } // end main loop 
    var dataBytesLength:uint=tempData.length; // now the length will be correct by definition 
    header(dataOutput, 32+4+dataBytesLength); 
    dataOutput.writeUTFBytes("data"); 
    dataOutput.writeUnsignedInt(dataBytesLength); 
    dataOutput.writeBytes(tempData); 

} 

ich die Resampling Routine neu geschrieben haben Schiebefenster-Algorithmus zu verwenden (funktioniert am besten, wenn neue Sample-Rate höher als alt, aber akzeptiert jedes Verhältnis). Dieser Algorithmus verwendet eine lineare Interpolation zwischen Abtastwerten, anstatt den alten Abtastwert über die Länge der interpolierten Sequenz einfach wiederzuverwenden. Fühlen Sie sich frei, durch Ihre eigene Schleife zu ersetzen.Der Prinzipal, der beibehalten werden sollte, besteht darin, dass Sie zuerst fulltempData kompilieren und erst dann den Header mit der jetzt korrekt definierten Datenlänge schreiben.

Bitte Probleme melden, wenn es welche gibt.

+0

Ich habe die umgeschriebene Routine verwendet, die die Audiodatei ohne Junk erzeugt, aber die Audiodatei ist sehr klein und die Datei nicht, die wir aufgenommen haben kein Audio wurde gehört, als wir es spielten – VijayRagavan

+0

Autsch, es gab einen Tippfehler bei der Bestimmung von "step" -Wert, ich habe durch eine falsche Variable geteilt, ich hätte es durch "samplingRate" nicht "soundRate" teilen sollen. Fest. – Vesper

+0

Jetzt ist die Audiodatei erzeugt worden, aber die Datei ist zu lang, das ist 375kb und auch als ich versuchte, den Ton abzuspielen, war der Ton nicht genau wir notierten – VijayRagavan