Как воспроизвести WAV в ActionScript? - PullRequest
1 голос
/ 29 мая 2010

Пожалуйста, смотрите класс, который я создал в http://textsnip.com/see/WAVinAS3 для анализа файла WAVE в ActionScript 3.0.

Этот класс правильно извлекает информацию из заголовка файла и фрагментов fmt, изолирует блок данных и создает новый массив ByteArray для хранения фрагмента данных. Он принимает несжатый файл WAVE с тегом формата 1. Файл WAVE внедряется в мой SWF-файл со следующим тегом встраивания Flex:

[Embed(source="some_sound.wav", mimeType="application/octet-stream")]
public var sound_class:Class;
public var wave:WaveFile = new WaveFile(new sound_class());

После разделения фрагмента данных класс пытается создать объект Sound, который может передавать сэмплы из фрагмента данных. У меня проблемы с процессом потоковой передачи, возможно потому, что я не очень хорош в математике и не знаю, что происходит с битами / байтами и т. Д.

Вот два документа, которые я использую в качестве ссылки для формата файла WAVE: http://www.lightlink.com/tjweber/StripWav/Canon.html https://ccrma.stanford.edu/courses/422/projects/WaveFormat/

Прямо сейчас файл воспроизводится! В реальном времени даже! Но ... звук действительно искажен. Что происходит?

1 Ответ

1 голос
/ 29 мая 2010

Проблема в обработчике onSampleData.

В вашем wav-файле амплитуды хранятся в виде шорт со знаком, то есть 16 бит целых чисел . Вы читаете их как 32-битные со знаком с плавающей точкой . Целые числа и числа с плавающей запятой по-разному представляются в двоичном формате, так что это никогда не будет работать правильно.

Теперь игрок ожидает плавания. Почему они использовали поплавки? Не знаю наверняка, но одна веская причина в том, что он позволяет игроку принимать нормализованное значение для каждого сэмпла. Таким образом, вам не нужно заботиться или знать, какой битпепт использует игрок: максимальное значение равно 1, а минимальное значение равно -1, и все.

Итак, ваша проблема в том, что вы должны преобразовать подписанный шорт в нормализованное число с плавающей запятой. Короткое замыкание занимает 16 бит, поэтому оно может хранить 2 ^ 16 (или 65 536) различных значений. Поскольку он подписан, а знак занимает один бит, максимальное значение будет 2 ^ 15. Итак, вы знаете, что ваш ввод - диапазон -32,768 ... 32,767.

Значение выборки нормализовано и должно находиться в диапазоне -1 ... 1, с другой стороны.

Итак, вы должны нормализовать ваш ввод. Это довольно просто. Просто возьмите считанное значение и разделите его на максимальное значение, и ваша входная амплитуда будет преобразована в диапазон -1 ... 1.

Примерно так:

    private function onSampleData(evt:SampleDataEvent):void 
    { 
        var amplitude:int = 0;
        var maxAmplitude:int = 1 << (bitsPerSample - 1); // or Math.pow(2, bitsPerSample - 1);
        var sample:Number = 0; 
        var actualSamples:int = 8192;
        var samplesPerChannel:int = actualSamples / channels;

        for ( var c:int = 0; c < samplesPerChannel ; c++ ) { 
            var i:int = 0;
            while(i < channels && data.bytesAvailable >= 2) {
                amplitude = data.readShort();
                sample = amplitude / maxAmplitude;
                evt.data.writeFloat(sample); 
                i++;
            }
        } 
    }  

Несколько замечаний:

  1. maxAmplitude может (и, вероятно, должен) рассчитываться при прочтении Глубина Я делаю это в метод, чтобы вы могли видеть это в вставленный код.

  2. Хотя maxAmplitude рассчитывается на основе прочитанного bitdepth и, таким образом, будет правильным для любой разрядности, Я читаю шорты в цикле, так если ваш WAV-файл использует разная глубина, эта функция не будет работать правильно. Вы могли бы добавить переключатель и прочитать необходимые количество данных (например, readInt, если разрядность 32). Тем не менее, 16 бит такой широко используемый стандарт, что я сомневаюсь, что это практически необходимо.

  3. Эта функция будет работать для стерео wavs. Если вы хотите, чтобы это работало для моно, напиши это, чтобы написать один и тот же образец дважды. То есть для каждого читать, вы делаете две записи (ваш вклад моно, но игрок ожидает 2 образцы).

  4. Я удалил EOF поймать, как вы можете знать, достаточно ли у вас данных для чтения из вашего буфера проверки bytesAvailable. Достигнув конца поток не является исключительным в любом Кстати, ИМО, так что я бы предпочел контролировать это случай без обработчика исключений, но это всего лишь личное предпочтение.

...