0

Im having a issue with converting microphone data sampling to 16-bit PCM signed integer.

The app i have is in Adobe AIR with actionScript 3, but i have the service demo code which used Web Audio API and there it states:

/**
 * Creates a Blob type: 'audio/l16' with the
 * chunk coming from the microphone.
 */
var exportDataBuffer = function(buffer, bufferSize) {
  var pcmEncodedBuffer = null,
    dataView = null,
    index = 0,
    volume = 0x7FFF; //range from 0 to 0x7FFF to control the volume

  pcmEncodedBuffer = new ArrayBuffer(bufferSize * 2);
  dataView = new DataView(pcmEncodedBuffer);

  /* Explanation for the math: The raw values captured from the Web Audio API are
   * in 32-bit Floating Point, between -1 and 1 (per the specification).
   * The values for 16-bit PCM range between -32768 and +32767 (16-bit signed integer).
   * Multiply to control the volume of the output. We store in little endian.
   */
  for (var i = 0; i < buffer.length; i++) {
    dataView.setInt16(index, buffer[i] * volume, true);
    index += 2;
  }

  // l16 is the MIME type for 16-bit PCM
  return new Blob([dataView], { type: 'audio/l16' });
};

I need a way to convert my samples in the same way.

This is what i have but it doesn't seem to be working:

function micSampleDataHandler(event:SampleDataEvent):void
    {

        while(event.data.bytesAvailable)
        {
            var sample:Number = event.data.readFloat();
            var integer:int;
            sample = sample * 32768 ;
            if( sample > 32767 ) sample = 32767;
            if( sample < -32768 ) sample = -32768;
            integer = int(sample) ;
            soundBytes.writeInt(integer);
        }

    }

Any advice would help me a bunch, thanks

EDIT:

This is the WaveEncoder function i have. Can this be used to encode the samples into desired format :

public function encode( samples:ByteArray, channels:int=2, bits:int=16, rate:int=44100 ):ByteArray
        {
            var data:ByteArray = create( samples );

            _bytes.length = 0;
            _bytes.endian = Endian.LITTLE_ENDIAN;

            _bytes.writeUTFBytes( WaveEncoder.RIFF );
            _bytes.writeInt( uint( data.length + 44 ) );
            _bytes.writeUTFBytes( WaveEncoder.WAVE );
            _bytes.writeUTFBytes( WaveEncoder.FMT );
            _bytes.writeInt( uint( 16 ) );
            _bytes.writeShort( uint( 1 ) );
            _bytes.writeShort( channels );
            _bytes.writeInt( rate );
            _bytes.writeInt( uint( rate * channels * ( bits >> 3 ) ) );
            _bytes.writeShort( uint( channels * ( bits >> 3 ) ) );
            _bytes.writeShort( bits );
            _bytes.writeUTFBytes( WaveEncoder.DATA );
            _bytes.writeInt( data.length );
            _bytes.writeBytes( data );
            _bytes.position = 0;

            return _bytes;
        }

EDIT2:

Problem seems to be in : dataview.setInt16(byteOffset, value [, littleEndian])

How do i do the byteOffset in as3?

deloki
  • 1,729
  • 2
  • 18
  • 26
  • Check if you're writing a two-channel WAV instead of one-channel. If yes, write that int twice, one for each channel. Also check are the values read from bytearray sane (say a two-byte offset while reading floats will result in ridiculous values, and `readFloat()` won't catch this for you). – Vesper Jul 13 '15 at 13:25
  • i need the result to be 1channel. I checked the readFloat() it always returns a value between -1 and 1 :( – deloki Jul 13 '15 at 13:29

1 Answers1

0

Got it. writeInt() writes 32 bits, and you need to write only 16. Use writeShort() instead.

soundBytes.writeShort(integer);
Vesper
  • 18,599
  • 6
  • 39
  • 61
  • thanks, this is definitely something i need to use instead or writeInt, but it doesn't work yet. Something still seems to be missing – deloki Jul 13 '15 at 13:51
  • Maybe there's an error in setting the header for `soundBytes`. – Vesper Jul 13 '15 at 14:05
  • could you give me some more information about this? what exactly do you mean? i don't think I'm setting the headers anywhere – deloki Jul 13 '15 at 14:11
  • Well then, how do you export the data? You would need to create a valid WAV file header for the file to be readable elsewhere. You here are basically dumping raw signal into `soundBytes`, but then you'll have to wrap it into a structure to designate what type is this data. – Vesper Jul 13 '15 at 14:15
  • i edited my answer, please take a look. can this be used to properly encode the BA? – deloki Jul 13 '15 at 14:27
  • from the answer here, it seems that the problem is in my conversion algorithm. This seems to be the problematic part: dataView.setInt16(index, buffer[i] * volume, true); index += 2; https://developer.ibm.com/answers/questions/201894/speech-to-text-microphone-sampling.html#answer-201925 – deloki Jul 13 '15 at 14:31
  • Check if the constant `44` in header function applies to your case. I've calculated it to be 36. See [this question](http://stackoverflow.com/questions/30440999/audio-recorded-file-corrupted-issue-in-actionscript) for details on header. – Vesper Jul 13 '15 at 14:42
  • About this question on developers.ibm.com, `index` is in bytes, not values, therefore your conversion seems to be correct. – Vesper Jul 13 '15 at 14:44