2015-05-25 24 views
5

tôi ghi lại mẫu giọng nói từ micro của tôi sử dụng Adobe Flash Builder 4.6/AIR, giọng nói ghi nhận thành công. Lần đầu tiên tôi chuyển đổi dữ liệu thoại (mảng byte) thành định dạng base64 trong actionscript sau đó tôi chuyển đổi dữ liệu base64 đó thành tệp WAV bằng cách sử dụng mã PHP của tôi. nhưng tập tin WAV đó ném tập tin bị hỏng trong RiffPad.âm thanh ghi lại tập tin bị hỏng vấn đề trong Actionscript

RIFFPad là một người xem cho các tập tin định dạng RIFF như WAV, AVI.

dự kiến ​​tập tin wav đặc điểm kỹ thuật:

Tỷ lệ lấy mẫu: 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 chức năng tiêu đề Writer:

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 tập tin Writer chức năng:

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

tôi gửi dữ liệu base64 để yêu cầu dịch vụ của tôi php bên tôi đã nhận '$ this-> request-> voiceSample' tham số và giải mã Base64 để .wav tập tin

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

Sau khi tải rằng "name.wav" tập tin trong Riffpad tôi có vấn đề

Có thêm rác ở cuối tệp.

Bất kỳ một hãy cho tôi những lời khuyên để giải quyết vấn đề này ...

+0

Kiểm tra xem chuỗi base64 mã hóa của bạn là chính xác bằng cách so sánh với các bộ mã hóa công khai được kích hoạt. Ngoài ra, hãy kiểm tra xem bộ giải mã PHP của bạn có được viết chính xác hay không (trừ khi nó được tích hợp sẵn chức năng). Ngoài ra kiểm tra xem Flash của bạn phụ thuộc vào byte endian (có một phụ thuộc ẩn trong 'c = dữ liệu [int (i + +)] << 16 | dữ liệu [int (i + +)] << 8 | dữ liệu [int (i ++)]; 'một phần ít nhất). – Vesper

+0

Hi vesper, tôi đang sử dụng mã hóa [base64] (http://www.sociodox.com/base64.html) lib cho byteArray để chuyển đổi base64. Ở phía PHP, tôi đang sử dụng chức năng dựng sẵn. – VijayRagavan

+0

Khi bạn xem tệp được giải mã qua trình chỉnh sửa hex, nó có chữ ký 'RIFF' trong 4 byte đầu tiên không? Nếu không, bạn sẽ phải gỡ lỗi (các) thói quen chuyển đổi của mình. – Vesper

Trả lời

2

Có một sai lầm cố hữu trong dòng này:

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

Các Microphone.rate thủ quốc gia rằng tần số lấy mẫu thực tế khác với microphone.rate*1000 như mong đợi bằng mã này. Bảng thực tế là như sau:

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

Vì vậy, trong khi nhà nước mã bình luận của bạn rằng rate được báo cáo là 8, đây không phải có thể là trường hợp trên các mặt hàng nói chung, vì vậy thực hiện các tra cứu trước khi đi qua các suy luận tỷ lệ lấy mẫu vào wavWriter.processSamples().

Tiếp theo, bạn đang precalculating dataByteLength qua tính toán dấu chấm động, điều này có thể kết thúc được không chính xác như bạn sau đó lấy mẫu byte dữ liệu bằng byte, vì vậy nó là tốt hơn để resample đầu tiên, sau đó thu thập chiều dài dữ liệu và chỉ sau đó viết tất cả các dữ liệu vào dataOutput, như thế này:

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); 

} 

tôi đã viết lại các thói quen resample để sử dụng thuật toán trượt cửa sổ (chỉ hoạt động tốt nhất nếu tỷ lệ mẫu mới là cao hơn so với tuổi, nhưng chấp nhận bất kỳ ratio). Thuật toán này sử dụng phép nội suy tuyến tính giữa các mẫu thay vì sử dụng lại mẫu cũ một cách rõ ràng theo chiều dài của chuỗi nội suy. Hãy thay thế bằng vòng lặp của riêng bạn.Hiệu trưởng mà nên được giữ lại là lần đầu tiên bạn biên dịch đầy đủtempData và chỉ sau đó viết tiêu đề với chiều dài dữ liệu hiện nay được xác định một cách chính xác.

Hãy báo cáo vấn đề nếu có bất kỳ.

+0

Tôi đã sử dụng các thói quen viết lại của bạn nó tạo ra các tập tin âm thanh mà không cần bất kỳ tin rác nhưng kích thước tập tin âm thanh là rất thấp và các tập tin không phải là chúng tôi ghi không có âm thanh được nghe nói khi chúng tôi chơi nó – VijayRagavan

+0

Ouch, có một lỗi đánh máy trong việc xác định giá trị 'step', tôi đã chia cho một biến sai, tôi phải chia nó bởi 'samplingRate' không' soundRate'. Đã sửa. – Vesper

+0

Bây giờ các tập tin âm thanh đã được tạo ra nhưng file quá dài đó là 375kb và cũng có khi tôi đã cố gắng để chơi âm thanh âm thanh là không chính xác, chúng tôi ghi nhận – VijayRagavan

Các vấn đề liên quan