I am recording audio input from microphone using the following function:
private function handleSampleData(p_sampleEvent:SampleDataEvent) :void
{
The default sample rate of the microphone in FlashPlayer is 8 kHz mono - or, if that's not available, the first available of 11.025 kHz, 22.05 kHz or 44.1 kHz. Audio output is always 44.1 kHz stereo. This means, that the samples you're getting are too few: 44.1 / 8 ~= 5.5.
You can fix this by setting the recording sample rate to 44.1 kHz:
microphone.rate = 44; // Yes, the API doesn't want the decimals
You could also keep the rate at e.g. 22 or 11 and then write additional duplicate samples to your buffer (simple "upsampling") when recording - i.e. write 4 floats, rather than 2, if recording at 22 kHz, 8 if recording at 11 kHz.
One other thing to be aware of is that an output sample isn't a single float, but two - one for each channel. So, the microphone will give you 8192 mono samples, which you - like you should - apply to both channels by writing each sample twice. You now have 8192 "stereo" samples.
When you're writing the output, however, you're writing at most 8192 floats (i
) - which correspond to 4096 stereo samples. The other half - I'd assume from your code and your results - is thrown out.
In the end, what you get is the first half of 8192 samples recorded at a samplerate approximately 5.5 times lower than the playback samplerate. Meaning the sound will appear to play 2*5.5 = 11 times too fast.
Make sure to write all the samples to the output, and record at 44.1 kHz (or upsample as described above), and it should play back at the right speed.
On a sidenote, event.data.writeBytes
is likely to be a lot faster for copying the buffer (assumption - haven't actually checked):
_lastRecord = new ByteArray();
_lastRecord.writeBytes(_buffer, 0, _buffer.bytesAvailable);
Same for writing the sample data:
public function handlePlaybackSampleData(p_sampleEvent:SampleDataEvent) :void
{
// Maximum amount of samples we're allowed to write: 8192
// Copying bytes here, rather than floats, so:
// 8192 samples * 2 channels * 4 bytes per float = 65536:
var bytesToCopy:int = Math.min(_lastRecord.bytesAvailable, 65536);
// Using _lastRecord.position since some of it may have been written on the
// last call to handlePlaybackSampleData if it had more than 8192 samples:
p_sampleEvent.data.writeBytes(
_lastRecord,
_lastRecord.position,
bytesToCopy
);
}