Запись звука работает, воспроизведение выполняется слишком быстро - PullRequest
3 голосов
/ 21 февраля 2012

Я записываю аудиовход с микрофона, используя следующую функцию:

    private function handleSampleData(p_sampleEvent:SampleDataEvent) :void
    {
        var data :Number;
        while (p_sampleEvent.data.bytesAvailable)
        {
            data = p_sampleEvent.data.readFloat();
            _buffer.writeFloat(data);
            _buffer.writeFloat(data);
        }
    }

Это похоже на работу. После того, как я закончил запись, я копирую записанные данные в другой буфер следующим образом:

            _buffer.position = 0;
            _lastRecord = new ByteArray();
            while (_buffer.bytesAvailable)
            {
                _lastRecord.writeFloat(_buffer.readFloat());
            }
            _lastRecord.position = 0;

И после этого я использую play () для вновь созданного звука и передаю ему буфер _lastRecord, используя эту функцию:

    public function handlePlaybackSampleData(p_sampleEvent:SampleDataEvent) :void 
    {
        // Read data until either MAX_SAMPLES or all available samples are reached.
        var i:int = 0;
        var data :Number = 0;
        while( i < 8192 )
        {
            if( _lastRecord.bytesAvailable )
            {
                data = _lastRecord.readFloat();
                p_sampleEvent.data.writeFloat(data);
                i++;
                continue;
            }
            else 
            {
                break;
            }
        }
    }

Хотя в принципе это работает, воспроизводимый звук воспроизводится слишком быстро. Я взял большую часть кода из примера, в котором это прекрасно работает. Я не вижу больше существенных различий между моим кодом и этим: http://labs.makemachine.net/2011/04/record-visualize-save-microphone-input/

Тем не менее, звук выходит слишком быстро. Если я добавлю еще больше данных в _buffer, добавив еще «_buffer.writeFloat (data);», он станет лучше, и когда у меня будет 12 строк этого, это будет желаемая скорость. Но даже это помогает, только когда я ударяюсь о свой микрофон. Если я на самом деле говорю, этого тоже недостаточно.

Но как это получается? И как получается, что в примере, из которого я взял этот код, достаточно только двух строк? Есть ли способ определить, сколько данных мне нужно записать в буфер во время записи?

1 Ответ

4 голосов
/ 21 февраля 2012

Частота дискретизации микрофона по умолчанию в FlashPlayer составляет 8 кГц моно, или, если она недоступна, первая из доступных: 11,025 кГц, 22,05 кГц или 44,1 кГц. Аудио выход всегда 44,1 кГц стерео. Это означает, что образцов, которые вы получаете, слишком мало: 44,1 / 8 ~ = 5,5.

Это можно исправить, установив частоту дискретизации записи на 44,1 кГц:

microphone.rate = 44; // Yes, the API doesn't want the decimals

Вы также можете оставить курс, например, на 22 или 11, а затем записать дополнительные дубликаты сэмплов в буфер (простая «повышающая дискретизация») при записи - то есть записать 4 числа с плавающей запятой, а не 2, если запись на 22 кГц, 8, если запись на 11 кГц.

Еще одна вещь, о которой следует помнить, это то, что выходной сэмпл - это не одно с плавающей точкой, а два - по одному на каждый канал. Таким образом, микрофон выдаст вам 8192 моносэмпла, которые вы - как и должны - применить к обоим каналам, записав каждый семпл дважды. Теперь у вас есть 8192 "стерео" семпла.

Однако, когда вы пишете вывод, вы пишете не более 8192 с плавающей точкой (i) - что соответствует 4096 стерео сэмплам. Другая половина - я полагаю из вашего кода и ваших результатов - выброшена.

В итоге получается первая половина из 8192 сэмплов, записанных с частотой дискретизации, примерно в 5,5 раз меньшей, чем частота сэмплирования воспроизведения. Это означает, что звук будет воспроизводиться в 2 * 5,5 = 11 раз быстрее.

Обязательно запишите все сэмплы на выход и запишите их с частотой 44,1 кГц (или с повышением частоты, как описано выше), и он должен воспроизводиться с правильной скоростью.

В sidenote, event.data.writeBytes, вероятно, будет много быстрее для копирования буфера (предположительно - на самом деле не проверял):

_lastRecord = new ByteArray();
_lastRecord.writeBytes(_buffer, 0, _buffer.bytesAvailable);

То же самое для записи данных примера:

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
   );
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...