Работа с wave файлами


Содержание

Работа с WAV файлами. Создание реплик

Работа по компьютерно-музыкальному проекту Пианола-Трио потребовала использования нескольких вспомогательных программ, обрабатывающих WAV файлы. Иногда требовалось перевести файл из стерео в моно, изменить скорость раздачи семплов, разделить файл на дорожки, соединить файлы, создав общее одновременное звучание записанного в них звука.
И, наконец, просто считать информацию о файле и получить дамп небольшой части его начала, чтобы иметь более полное представление о нём.
В сочетании с возможностями простейшего редактора Wave Editor этот блок программ закрывает все вопросы, связанные с обработкой WAV файлов, и делает ненужным использование более сложных редакторов.
Новая утилита написана в среде Визуал бейсик. Она проста и удобна в работе. Скачать её вместе с исходниками можно отсюда — http://yadi.sk/d/bpW5I50k3NvNyu

Хочу рассказать об одной из возможностей утилиты — создание реплик, небольших кусочков информации, в которых кодируется рельеф звука музыкального инструмента внутри периода.
Для получения этих реплик можно использовать звук реального инструмента, звучащего соло. Реплика не связана с определённой частотой, она имеет ту длину, которая была задана. И соответственно, содержит столько же информационных точек. Длинная реплика детально описывает звук, короткая — упрощённо. Программа озвучивания Трио, в процессе создания музыкального WAV файла, воссоздаёт по реплике рельеф звука внутри периода.

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

Давайте, посмотрим на рисунок. Звуки скрипки с помощью утилиты WAV Манипулятор были переведены из стерео в моно запись. В начале фрагмента этой записи утилитой была сделана прямоугольная метка, которая затем в редакторе Wave Editor была скопирована в начало и в конец одного из периодов звукового колебания.
Скопированные метки Вы можете видеть на рисунке (в окне Wave Editor).
Снова обращаемся к утилите, указывая длину реплики (целая часть числа в скобках), и размах амплитуды от её максимального значения (дробная часть числа в скобках).
Кликнув кнопку «Выполнить», в файле REPL.txt получаем результат, тот, который в несколько облагороженном (повёрнутом) виде можно видеть на рисунке.
Мнемоническая запись амплитуд в строке соответствует принятой в Трио —
цифры 50 означают нулевую амплитуду, 99 — максимальную (положительную), 00 — максимальную с отрицательным значением.

По распечатке видно, что реплика хорошо отражает рельеф. Видно, как амплитуда звукового колебания (положение звёздочек на диаграмме) соотносится с двухзначными числами, представляющими её в реплике. Можно заметить, что на диаграмме рельеф представлен звёздочками в огрублённом виде — в действительности, репликой он передаётся в три раза точнее, что вполне достаточно для практических целей.
Для получения ещё одной реплики из другой части звука нужно разрушить поставленные метки (достаточно уменьшить количество семплов на их вершинах), и затем, поставить новые метки, обозначив интересующий нас период.

alexindima › Блог › Структура WAVE файла

Разрабатываю одно устройство на МК, и оно будет воспроизводить звук с флешки. Проще всего воспроизвести WAVE файлы, поэтому использоваться будут именно они. Конечно в интернете есть готовые библиотеки для AVR, но я люблю изучать все сам, проще искать ошибки потом. Поэтому эта статья больше для меня, чтобы собрать воедино найденную информацию.

Итак, WAVE является подвидом RIFF (Resource Interchange File Format — Формат Файла обмена данными), основной концепцией которого является chunk (кусок). Он мне напомнил чем-то структуры в языке Си. Я бы представил chunk примерно следующим видом (по аналогии с каким-нибудь языком программирования):

Ну а теперь подробнее и с примерами.
WAVE файл мы может открыть с помощью любого HEX редактора. В интернете есть много информации по заголовкам RIFF файлов, и практически везде написано что заголовок состоит из 44 байт, я пользовался этой статьей. Дальше я покажу что это не всегда так. Опишу такой заголовок.

Первые четыре байта 0-3 (chunk в ANSII.

Четыре байта 12-15 (subchunk1 >Байты 24-27 (sampleRate, оранжевый) — частота дискретизации, у нас AC44h=44100. Байты 28-31 (byteRate, темно-зеленый) — количество байт, переданных за секунду воспроизведения, 2B110h=176400. Байты 32,33 (blockAlign, серый) — Количество байт для одного сэмпла, включая все каналы. Байты 34,35 (bitsPerSample, темно-синий) — количество бит в сэмпле, «глубина» или точность звучания. У нас 10h=16.

Четыре байта 36-39 (subchunk2Id, коричневый) — название следующего куска «data», размер которого задают следующие четыре байта 40-43 (subchunk2Size, красный). Байты с 44 и дальше — как раз наши звуковые данные. О них чуть позже.

Если посчитать количество байт до звуковых данных и сложить их с количеством звуковых, можно заметить, что не хватает примерно 250 байт до размера файла. В них хранятся дополнительные данные, которые не важны при воспроизведении. Например, список авторов, кто создал файл, когда создал, жанр и тому подобное. Самое интересное, что разные программы располагают эти данные в разных местах, Audacity их располагает после куска «data», Freemake Audio Converter их располагает до куска «data». В связи с этим в интернете очень много вопросов, почему заголовок RIFF не 44 байта а больше. Вот вам и ответ.

Писать об этих данных много смысла нет, все можно найти тут. Да и построение у них точно такое же как и у обычных кусков. Просто для примера покажу их в WAVE файлах.

Теперь о звуковых данных. Если у нас моно с 8-битной глубиной звука то тут все просто, каждый байт отвечает за свой сэмпл. Моно 16 бит — каждые два байта — сэмпл. А вот если у нас стерео, то семплы чередуются, левый-правый-левый-правый и так далее.

Подводя итог, для воспроизведения нам необходимо следующее: открыть файл, найти «fmt», посмотреть частоту дискретизации и глубину звука, найти «data», посмотреть сколько байт в куске и считывать семплы. А дальше уже выводим на динамик через R2R матрицу или ШИМ.

Надеюсь что кому-нибудь еще статья будет полезна.

Разложение wav файла на массив байтов и выполнение БПФ

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

Теперь его и нужно отправлять на вход быстрого преобразования Фурье?

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

Что мне нужно сделать?

1 ответ 1

Согласно структуре WAV, первые 44 байта WAV файла служат для хранения служебной информации. Соответственно, вам нужно считать в byte[] только полезные амплитуды, хранящиеся в секции data .

Обычно на вход БПФ подаются вещественные значения амплитуд, поэтому вы должны сконвертировать секцию data , которую вы считали в byte[] в массив double[] , исходя из того, что каждая амплитуда кодируется 4-мя байтами.

Для БПФ можете воспользоваться бесплатным математическим пакетом Numerics, предварительно переписав ваши double[] в массив комплексных чисел Complex[] , оставляя мнимую часть пустой.

Введение

В этой статье мы рассмотрим практический пример использования SD карты с микроконтроллером AVR. По просьбе трудящихся я написал проект, который читает с SD карты wav файл и воспроизводит его.

Для проекта я использовал микроконтроллер atmega16, тактируемый от внешнего кварца с частотой 6 МГц. В качестве ЦАПа задействована функция формирования ШИМ сигнала таймера Т0. Wav файл для воспроизведения был выбран с такими параметрами: 8 бит, 22 кГц, моно.

Низкоуровневые функции для работы с SD картой

Чтобы использовать библиотеку Petit FatFs с SD картой, нужно реализовать три низкоуровневые функции для работы с ней — это функция инициализации, чтения и записи. Если вы читали предыдущий материал, в котором была описана библиотека Petit FatFs, то должны помнить, что «пустышки» этих функций находятся в файле diskio.c

На сайте Elm Chan`a есть примеры использования библиотеки с SD картами, поэтому можно взять уже готовые функции из этих проектов, что я и сделал. Я позаимствовал из одного примера файл mmc.c и заменил им файл diskio.c , однако файл mmc.c тоже потребовал небольшого «допиливания».

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

#define SELECT() — формирует низкий уровень на CS выводе карты
#define DESELECT() — формирует высокий уровень на СS выводе карты
#define MMC_SEL — возвращает единицу, если на выводе CS низкий уровень
#define init_spi() — инициализирует SPI модуль
#define dly_100us() — формирует задержку на 100 микросекунд
#define xmit_spi(d) — передает байт данных по SPI
#define rcv_spi() — принимает байт данных по SPI
#define FORWARD(d) — перенаправляет поток данных, этот макрос можно оставить пустым

Все эти макросы легко реализовать, если прочитать материал про SPI модуль AVR микроконтроллера. Я как раз взял оттуда spi драйвер и «прицепил» его к файлу mmc.c.

Короче, получается такая последовательность. Мы берем библиотеку Petit FatFs добавляем к ней файл mmc.c из примеров Elm Chan`a, описываем макросы реализующие spi и после этого можем работать с SD картой. Немного заморочено, но если один раз разобрался, то все становится понятно.

Итак, я все это проделал и теперь могу использовать SD карту. И чтобы показать, что это действительно работает, я написал проект, в котором микроконтроллер читает с SD карты wav файл и воспроизводит.

Воспроизведение звука микроконтроллером

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

В качестве файла для воспроизведения я взял произвольный mp3 трек (мне попалась песня группы Prodigy) и перекодировал его в wav файл с такими параметрами: 8 бит, 22 кГц, моно. Для конвертирования файла я использовал видео редактор Sony Vegas, но можно найти программу и попроще. Например, такая функция есть во многих аудио редакторах вроде Sound Forge, WaveLab, Cool Edit и т.д.

«8 бит» — это разрядность одной выборки аналогового сигнала. Звук хорошего качества обычно имеет разрядность 16 (CD качество) или 24 бита (студийная запись), но для микроконтроллерной «говорилки» 8-и разрядов хватит за глаза.

«22 кГц» — это частота дискретизации. То есть частота, с которой из аналогового сигнала «брались» выборки. С этой же частотой мы должны преобразовывать цифровые выборки сигнала в аналоговые напряжения. Цифровой звук хорошего качества обычно имеет частоту дискретизации 44.1 кГц (CD качество), 96 кГц ( студийная запись) и т.д.

«моно» — означает одну звуковую дорожку, которая будет воспроизводиться как в правом, так и в левом аудио каналах.

Итак, для воспроизведения wav файла с параметрами 8 бит, 22 кГц, моно, нам понадобится одноканальный 8-и разрядный ЦАП, способный формировать на выходе аналоговые напряжения с частотой 22 кГц. Поскольку у большинства AVR`ок нет встроенного цифро-аналогового преобразователя, мы можем использовать следующие варианты:

— аппаратный ШИМ,
— программный ШИМ,
— внешний интегральный ЦАП,
— внешняя схема ЦАП`a .

Реализация программного ШИМ`a требует от микроконтроллера большого быстродействия, поэтому я не захотел с ним связываться. Внешний ЦАП обычно использует SPI, который нужен для SD карты. Внешняя схема ЦАП`а, например схема R-2R, неплохой вариант, но под нее нужно отдать целый порт микроконтроллера.

Исходя из этого, я остановил свой выбор на аппаратном 8-и разрядном ШИМ`е. Во первых, эта функция есть во всех микроконтроллерах AVR, а во-вторых, для реализации ЦАП`а требуется всего один вывод микроконтроллера.

В одном из старых материалов я уже описывал принцип формирования аналогового сигнала с помощью ШИМ, однако в случае wav файла здесь не все так просто.

С какой частотой можно формировать аналоговые напряжения с помощью ШИМ? Это зависит от трех параметров: тактовой частоты микроконтроллера, делителя таймера и его разрядности. Например, для 8-и разрядного ШИМ сигнала при тактовой частоте микроконтроллера 16 МГц можно получить следующие частоты.

Тактовая частота микроконтроллера Fcpu = 16000000 Гц
Тактовая частота таймера Т0 Ftim = Fcpu/k , где k — 1, 8, 64, 256, 1024.
Частота ШИМ сигнала Fpwm = (Fcpu/k)/2^8 = Fcpu/(k*256)

при k = 1 Fpwm = 62500
при k = 8 Fpwm = 7812
при k = 64 Fpwm = 976
при k = 256 Fpwmn = 244
при k = 1024 Fpwm = 61


Ближайшая частота к требуемым 22 килогерцам — это 7812, но такая частота не подойдет. Файл, воспроизводимый с такой частотой, будет уж слишком замедленным. Надо подобрать такую тактовую частоту микроконтроллера, при которой можно получить требуемую частоту формирования аналоговых напряжений. Неплохой результат получается при 6 МГц и k = 1

Fcpu = 6000000 Гц
Fan = 6000000/(2^8 * 1) = 23437 Гц

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

Итак, аналоговые напряжения будут формироваться с помощью ШИМ функции аппаратного таймера Т0, но как разнести процесс чтения данных с процессом воспроизведения? Считывать с SD карты по одной выборке сигнала с частотой 22 кГц не получится, микроконтроллер не будет успевать это сделать.

Тут понадобится буфер, условно состоящий из двух одинаковых половинок. Пока одна часть буфера заполняется данными с SD карты, из другой части буфера данные передаются в ЦАП (в нашем случае таймеру). Нужно только выбрать такой размер буфера, при котором эти два процесса не будет «наезжать»друг на друга.

Я подбирал размер буфера следующим образом. Задал максимальную частоту SPI модуля микроконтроллера atmega16 и посмотрел сколько времени затрачивается на чтение данных с SD карты. То есть сколько времени выполняется функция pf_read(..).

При тактовый частоте Fcpu = 6 МГц эта функция выполнялась

2.5 мс, но иногда попадались циклы по 5 мс (наверное из-за чтения на границе секторов .. напишите в комментариях, если знаете). Причем это время не зависело от количества данных — и 32, и 64, и 128 байт читались за одно и то же время.

Затем я посчитал сколько данных будет передано в ЦАП за время 5 мс. Частота нашего псевдо ЦАП`a = 23437 Гц, соответственно период = 42.6 мкс. Делим 5 мс на 42.6 и получаем искомую цифру.

n = 0.005/(1/23437) = 117

То есть за 5 мс микроконтроллер выдаст 117 выборок сигнала, при этом за это же время успеет прочитать с карты 128 выборок. Получается, что если взять буфер размером 256 байт микроконтроллер будет успевать выполнять обе задачи и даже остается небольшой запас времени. Он, кстати, необходим, потому что в процесс чтения данных с SD карты, будут вклиниваться прерывания таймера Т0.

Так я и сделал. Выбрал размер буфера равным 256 байт.

Схема для проекта

Схема питается от двух стабилизаторов — 3.3 В и 5 В. Как вариант можно запитать все схему от 3-х вольтового источника (тогда даже не понадобятся преобразователи уровней) или понизить 5-и вольтовое напряжение с помощью трех последовательно включенных диодов и запитать таким образом SD карту.

Микроконтроллер тактируется от внешнего кварцевого резонатора с частотой 6 МГц. SD карта подключена к микроконтроллеру по одной из приведенных ранее схем.

Для преобразования ШИМ сигнала в постоянное напряжение используется низкочастотный RC фильтр из двух каскадов. Частота среза фильтра около 10 кГц, что соответствует полосе воспроизводимого цифрового сигнала.

Для индикации состояния устройства используется светодиод LED1. Если карта не считывается в момент включения устройства, светодиод начинает моргать.

Код проекта

Все основное действо заключено в файле main.c. При старте программы происходит инициализация переменных и настройка выводов — настраивается ШИМ выход и выход для светодиода.

Затем монтируется SD карта, открывается файл под названием 1.wav и из него (в буфер) читаются 256 байт. Далее проверяется результат выполнения операций с картой. Если операции завершились неудачно, программа зацикливается и начинает моргать светодиод. Если чтение прошло успешно, программа инициализирует таймер Т0 и зажигает светодиод.

Далее разрешаются прерывания и программа попадает в бесконечный цикл, внутри которого расположен конечный автомат с тремя состояниями. В первом состоянии идет заполнение нижней половины буфера, во втором — верхней половины, а в третьем программа ничего не делает. В третье состояние автомат переходит, когда wav файл заканчивается. При этом гасится светодиод и выключается таймер Т0.

Параллельно основному циклу программы выполняется прерывание таймера Т0. Оно сделано предельно коротким. В микроконтроллер загружает в регистр сравнения OCR0 содержимое ячейки буфера, на которую указывает индексная переменная, а затем инкрементирует ее. Поскольку размер буфера равен 256 байт, индексную переменную не приходится проверять на граничное значение.

Автомат, заполняющий буфер данными, проверяет индексную переменную. И по ее значению «понимает» в какую часть буфера можно писать данные.

Неиспользуемые функции библиотеки Petit FatFs я отключил в файле pff.h.

Из недостатков проекта можно отметить два момента:

— при воспроизведении не пропускается заголовок wav файла
— когда wav файл заканчивается таймер выключается, не «доигрывая» оставшееся содержимое буфера.

Заключение

Подведем итог. Wav файл — это последовательность выборок сигнала. Он имеет такие характеристики, как разрядность и частота дискретизации. Чтобы воспроизвести wav файл мы должны преобразовывать выборки сигнала в аналоговые напряжения, причем делать это с частотой дискретизации, иначе файл будет воспроизводиться замедленно или наоборот ускоренно.

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

Чтобы разнести процесс чтения данных с SD карты с процессом воспроизведения, можно использовать буфер. Из одной половины буфера данные будут читаться, в другую — записываться. Чтобы выбрать достаточный размер буфера, необходимо знать сколько времени требуется для чтения порции данных и сколько времени затрачивается на воспроизведение этой порции.

Работа с wave файлами

Формат WAV изначально использовался в системе Windows для сохранения цифровых аудиоданных. Это самый известный и широко поддерживаемый формат благодаря популярности платформы Windows и большому количеству написанных для неё программ. Почти любая современная программа, работающая со звуком, может прочитать или записать формат WAV, поэтому этот формат очень интересен для разработчиков программного обеспечения. Далее подробно описываются структуры данных формата WAV.

Илон Маск рекомендует:  Функции в PHP

[Форматы данных]

Поскольку формат WAV-файла пришел от операционной системы Windows, в которой традиционно использовались процессоры Intel, все значения данных формата хранятся как Little-Endian, т. е. самый младший значащий байт идет первым.

WAV-файлы могут содержать строки текста, например метки секций, информационные комментарии и т. д. Строки сохраняются таким образом, что первый байт указывает количество байт текста ASCII в строке.

7 ‘e’ ‘x’ ‘a’ ‘m’ ‘p’ ‘l’ ‘e’

Пример формата строки Wave

[Структура файла]

WAV-файл использует стандартную RIFF-структуру, которая группирует содержимое файла из отдельных секций (chunks) — формат выборок аудиоданных, аудиоданные, и т. п. Каждая секция имеет свой отдельный заголовок секции и отдельные данные секции. Заголовок секции указывает на тип секции и количество содержащихся в секции байт. Такой принцип организации позволяет программам анализировать только необходимые секции, пропуская остальные секции, которые не известны или которые не требуют обработки. Некоторые определенные секции могут иметь в своем составе подсекции (sub-chunks). Например, как можно увидеть на диаграмме, описывающий основной формат WAV-файла, секции «fmt » и «data» являются подсекциями секции «RIFF».

Chunk ID «RIFF»
Chunk Data Size
RIFF Type ID «WAVE»
Chunk ID «fmt »
Chunk Data Size
Sample Format Info
Chunk ID «data»
Chunk Data Size
Digital Audio Samples
Заголовок секции (Chunk Header)
Данные секции (Chunk Data Bytes)

Одна хитрая вещь, связанная с секциями файла RIFF, состоит в том, что адреса начала секций должны быть выровнены на размер слова (2 байта). Это означает, что общий размер секции должен быть кратен 2. Если секция содержит нечетное число байт данных (невыравненное до 2 байт), то добавляется дополнительный нулевой байт данных в конец данных секции. Этот дополнительный байт не учитывается в размере секции заголовка, таким образом программа всегда должна учитывать выравнивание для расчета смещения начала следующей секции.

[Заголовок WAV-файла, секция типа RIFF]

Заголовки WAV-файла используют стандартный формат RIFF. Первые 8 байт файла — стандартный заголовок секции RIFF, который имеет ID секции «RIFF» и размер секции, равный размеру файла минус 8 байт, используемых для RIFF-заголовка. Первые 4 байта данных в секции «RIFF» определяют тип ресурса, который можно найти в секции. WAV-файлы всегда используют тип ресурса «WAVE». После типа ресурса (ID «WAVE») идут все секции звукового файла, которые определяют аудиосигнал.

Смещение Размер Описание Значение
0x00 4 Chunk ID «RIFF» (0x52494646)
0x04 4 Chunk Data Size (file size) — 8
0x08 4 RIFF Type «WAVE» (0x57415645)
0x10 Wave chunks (секции WAV-файла)
Значения полей секции RIFF

[Секции WAV-файла]

Существует довольно много типов секций, заданных для файлов WAV, но большинство WAV-файлов содержат только две из них — секцию формата («fmt «) и секцию данных («data»). Это именно те секции, которые необходимы для описания формата выборок аудиоданных, и для хранения самих аудиоданных. Хотя официальная спецификация не задает жесткий порядок следования секций, наилучшей практикой будет размещение секции формата перед секцией данных. Многие программы ожидают именно такой порядок секций, и он наиболее разумен для передачи аудиоданных через медленные, последовательные источники наподобие Интернет. Иначе если формат придет после данных, то перед стартом воспроизведения необходимо считать и запомнить все аудиоданные, только после получения формата запускать воспроизведение.

Все секции формата RIFF и соответственно секции Wave сохраняются в следующем формате (см. диаграмму). Заметьте, что даже вышеупомянутая секция RIFF соответствует этому формату.

Смещение Размер Описание
0x00 4 Chunk ID
0x04 4 Chunk Data Size
0x08 Chunk Data Bytes
Формат секций RIFF и Wave

Остальная часть этой статьи посвящена описанию различных типов секций Wave, их формату данных и что эти данные означают.

[Секция формата — «fmt «]

Секция формата содержит информацию от том, как сохранены аудиоданные и как они должны воспроизводиться. Информация включает в себя тип используемой компрессии, количество каналов, скорость выдачи выборок (sample rate), количество бит в выборке (bits per sample) и другие атрибуты.


Смещение Размер Описание Значение
0x00 4 Chunk ID «fmt » (0x666D7420)
0x04 4 Chunk Data Size 16 + extra format bytes
0x08 2 Compression code 1 — 65,535
0x0a 2 Number of channels 1 — 65,535
0x0c 4 Sample rate 1 — 0xFFFFFFFF
0x10 4 Average bytes per second 1 — 0xFFFFFFFF
0x14 2 Block align 1 — 65,535
0x16 2 Significant bits per sample 2 — 65,535
0x18 2 Extra format bytes 0 — 65,535
0x1a Дополнительные данные формата (Extra format bytes) *

Значения секции формата (Wave Format Chunk), * читайте для подробностей текст далее

Идентификатор секции (Chunk ID) и объем данных (Data Size)
Идентификатор секции всегда «fmt » (0x666D7420) и объем данных равен размеру стандартного формата WAV (16 байт) плюс размер всех дополнительных байт формата, необходимых для поддержки специфических форматов звука, если он не содержит несжатых данных PCM. Обратите внимание, что идентификатор секции «fmt » оканчивается на символ пробела (0x20).

Код сжатия (Compression Code)
Первое слово данных формата указывает на тип сжатия, используемого для данных звука. В таблице содержится список кодов сжатия, используемых в настоящее время.

Код Описание
0 (0x0000) Unknown
1 (0x0001) PCM/uncompressed
2 (0x0002) Microsoft ADPCM
6 (0x0006) ITU G.711 a-law
7 (0x0007) ITU G.711 µ-law
17 (0x0011) IMA ADPCM
20 (0x0016) ITU G.723 ADPCM (Yamaha)
49 (0x0031) GSM 6.10
64 (0x0040) ITU G.721 ADPCM
80 (0x0050) MPEG
65,535 (0xFFFF) Experimental

Общеиспользуемые коды сжатия
(Common Wave Compression Codes)

Количество каналов (Number of Channels)
Количество каналов указывает, сколько отдельных аудиосигналов закодировано в секции данных звука (wave data chunk). Значение 1 означает монофонический сигнал, 2 означает стерео, и т. п.

Скорость выборок (Sample Rate)
Число выборок аудиосигнала, приходящихся на секунду. На эту величину не влияет количество каналов.

Среднее количество байт в секунду (Average Bytes Per Second)
Величина, показывающая, сколько байт за секунду данных должно быть пропущено через цифроаналоговый преобразователь (D/A converter, DAC) во время воспроизведения файла. эта информация полезна, чтобы определить — могут ли данные поступать от источника с нужной скоростью, чтобы не отставать от воспроизведения. Эта величина просто вычисляется по формуле:
AvgBytesPerSec = SampleRate * BlockAlign

Выравнивание блока (Block Align)
Количество байт на одну выборку. Эта величина может быть вычислена по формуле:
BlockAlign = SignificantBitsPerSample / 8 * NumChannels

Количество используемых бит на выборку (Significant Bits Per Sample)
Величина указывает количество бит, формирующих каждую выборку сигнала. Обычно эта величина 8, 16, 24 или 32. Если число бит не выравнено по байту (не делится нацело на 8), количество используемых байт на выборку округляется вверх к наименьшему количеству байт. Неиспользуемые биты устанавливаются в 0 и игнорируются. Такие форматы (с числом бит на выборку, некратным 8) встречаются редко.

Дополнительные данные формата (Extra Format Bytes)
Величина указывает, сколько далее идет дополнительных данных, описывающих формат. Она отсутствует, если код сжатия 1 (uncompressed PCM file), но может присутствовать и иметь любую другую величину для других типов сжатия, зависящую от количества необходимых для декодирования данных. Если величина не выравнена на слово (не делится нацело на 2), должен быть добавлен дополнительный байт в конец данных, но величина должна оставаться невыровненной.

Пример дампа WAV-файла без дополнительных данных. Пример дампа WAV-файла, где в заголовок «fmt » добавлены 256 байт дополнительных данных Extra Format Bytes.

Для наглядности отдельные секции стандартного заголовка выделены разными цветами. 256 байт в области Extra Format Bytes показаны розовым цветом, а их размер — красным .

[Секция данных — «data»]

Секция данных Wave (Wave Data Chunk) содержит данные цифровых выборок аудиосигнала, которые можно декодировать с использованием формата и метода компрессии, указанных в секции формата Wave (Wave Format Chunk). Если код компрессии 1 (несжатый PCM, Pulse Code Modulation), то данные представлены в виде сырых, непреобразованных (raw) величин выборок. Эта статья описывает, как сохранены несжатые данные PCM, однако не вдается в подробности многих используемых форматов с компрессией.

WAV-файлы обычно содержат только одну секцию данных, но секций может быть несколько, если они содержатся в секции списка Wave (Wave List Chunk «wavl»).

Смещение Длина Тип Описание Значение
0x00 4 char[4] chunk ID «data» (0x64617461)
0x04 4 dword chunk size зависит от количества выборок и компрессии
0x08 данные выборок (sample data)

Формат секции данных «data»

Аудиовыборки многоканального цифрового аудио сохраняются как чередуемые (interlaced) данные, которые просто означают последовательные аудиовыборки нескольких каналов (таких как стерео и каналы окружения surround). Выборки каналов сохранены последовательно друг за другом, перед тем как произойдет переход к следующему времени выборки. Это сделано с целью возможности последовательного проигрывания файла даже тогда, когда еще не весь файл прочитан целиком. Это удобно, когда проигрывается большой файл с диска (который не может быть размещен целиком в памяти) или файл передается в последовательном потоке данных через сетевое соединение (например Интернет). Значения в диаграмме ниже были бы сохранены в WAV-файле в порядке, как они перечислены в столбце значений (от начала до конца).

Время Канал Значение
1 (левый) 0x0053
2 (правый) 0x0024
1 1 (левый) 0x0057
2 (правый) 0x0029
2 1 (левый) 0x0063
2 (правый) 0x003C

Чередуемые выборки стерео Wave

Один момент, касающийся данных выборок, который может вызвать некоторое замешательство — когда выборки представлены 8 битами, они определены как значения без знака (unsigned). Все другие битовые размеры указываются как величины со знаком (signed). Например, выборка 16 бит может иметь значение в диапазоне от -32768 до +32767, где средняя точка (напряжение сигнала равно 0) соответствует значению 0.

Как уже было указано ранее, все секции RIFF (включая секции WAVE «data») должны быть выровнены по размеру на слово (2 байта). Если данные выборок содержатся в нечетном количестве байт, в конец данных выборок должен быть добавлен выравнивающий нулевой байт. За заголовке секции «data» размер не должен учитывать этот выравнивающий байт.

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

Секция fact содержит информацию о содержимом WAV-файла, зависящую от кода компрессии. Она требуется для всех форматов WAVE со сжатием, и требуется, если данные сигнала содержатся внутри секции списка (LIST) «wavl», но не требуется для несжатого формата PCM WAVE (код компрессии 1), который содержит аудиоданные в секции «data».

Смещение Размер Описание Величина
0x00 4 Chunk ID «fact» (0x66616374)
0x04 4 Chunk Data Size зависит от формата
0x08 Данные, зависящие от формата (Format Dependant Data)

Данные, зависящие от формата (Format Dependant Data)
В настоящий момент задано только одно поле для данных, зависящих от формата. Это единственное 4-байтное значение, которое указывает число выборок в секции данных аудиосигнала. Эта величина может использоваться вместе с количеством выборок в секунду (Samples Per Second value) указанном в секции формата — для вычисления продолжительности звучания сигнала в секундах.

По мере появления новых форматов WAVE секция fact будет расширена с добавлением полей после поля числа выборок. Программы могут использовать размер секции fact для определения, какие поля представлены в секции.

Секция списка wave (wave list chunk) используется для указания нескольких чередований секций «slnt» и «data». Эти секции могут помочь уменьшить размер файла путем указания слышимых сегментов выборок, когда поток аудиоданных содержит несколько интервалов тишины.

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

Смещение Размер Описание Значение
0x00 4 Chunk ID «wavl» (0x736C6E74)
0x04 4 Chunk Data Size зависит от размера секций «data» и «slnt»
0x08 Список чередования секций «slnt» и «data»

Формат секции Wave List

Секция тишины (silent chunk) используется для указания сегмента паузы звучания, которая имеет некоторую продолжительность в выборках сигнала. Секция тишины всегда содержится только внутри секции списка wave (wave list chunk). Когда эта секция объявляет тишину, не нужно задавать нулевую громкость или базовую выборку. Это фактически удерживается последняя выборка сигнала, считанная в предыдущей секции данных ((Wave Data Chunk)) секции списка Wave (wave list chunk). Если не было предыдущих секций данных, должно использоваться базовое значение выборки, равное 127 для 8-битных данных, 0 для 16-битных данных или всех данных с бОльшим количеством бит на выборку. Эти требования могут казаться тривиальными, но если это не выполнить, то могут появится нежелательные щелчки и перепады в аудиосигнале.

Смещение Размер Описание Величина
0x00 4 Chunk ID «slnt» (0x736C6E74)
0x04 4 Chunk Data Size 4
0x08 4 Number of Silent Samples 0 — 0xFFFFFFFF

Количество выборок тишины (Number of Silent Samples)
Эта величина указывает число выборок тишины, которое должно появиться в аудиосигнале на точке списка wave (wave list chunk).

Секция cue определяет один или более смещения выборок, которые часто используются, чтобы отметить примечательные разделы аудио. Например, у начала и конца стиха в песне могут быть метки, по которым легче найти начало и конец стиха. Секция cue является необязательной, и если она добавлена, то одна секция cue должна указать все примечательные точки для секции «WAVE». Не допускается больше одной секции cue внутри секции «WAVE».

Смещение Размер Описание Значение
0x00 4 Chunk ID «cue » (0x63756520)
0x04 4 Chunk Data Size depends on Num Cue Points
0x08 4 Num Cue Points количество точек cue в списке
0x0c Список интересующих точек (List of Cue Points)

Идентификатор ID секции и объем данных (Chunk ID and Data Size)
Идентификатор ID секции для секции cue всегда «cue » (0x666D7420). Обратите внимание, что строка ID оканчивается на символ пробела (0x20). Размер данных секции равен размеру Num Cue Points (4) плюс количество последующих точек cue, помноженное на размер данных каждой точки cue (24). Следующая формула может использоваться для вычисления размера данных секции Cue:
ChunkDataSize = 4 + (NumCuePoints * 24)

Количество примечательных точек (Num Cue Points)
Эта величина указывает количество последующих cue-точек в этой секции.

Список примечательных точек (List of Cue Points)
Список точек cue — просто набор описаний последовательных точек, который имеет следующий формат.

Смещение Размер Описание Значение
0x00 4 ID unique identification value
0x04 4 Position play order position
0x08 4 Data Chunk ID RIFF ID of corresponding data chunk
0x0c 4 Chunk Start Byte Offset of Data Chunk *
0x10 4 Block Start Byte Offset to sample of First Channel
0x14 4 Sample Offset Byte Offset to sample byte of First Channel

ID
Каждая примечательная (cue) точка имеет уникальное идентификационное значение, используемое для связи точек cue с информацией в других секциях. Например, секция метки (Label chunk) содержит текст, который описывает точку в WAV-файле со ссылкой на связанную точку cue.

Позиция (Position)
Позиция определяет смещение выборки, связанное точкой cue, с точки зрения позиции выборки в заключительном потоке выборок, сгенерированных списком воспроизведения. Другими словами, если указана секция списка воспроизведения (play list chunk), значение позиции равно номеру выборки, на которой эта точка cue встретится при воспроизведении всего списка (play list) в заданном порядке. Если нет секции списка воспроизведения (play list chunk), то значение позиции должно быть равно 0.

ID секции данных (Data Chunk ID)
Эта величина указывает ID из 4 байт, используемый секцией, содержащей выборку, которая соответствует этой точке cue. WAV-файл без списка воспроизведения (play list chunk) всегда имеет «data». WAV-файл, имеющий список воспроизведения (play list chunk) с секциями данных и тишины, может быть либо «data», либо «slnt».

Начало секции (Chunk Start)
Значение начала секции указывает байтовое смещение в секции списка Wave (Wave List Chunk) секции, содержащей выборку, соответствующую этой точке. Это та же самая секция, описанная значением ID секции данных (Data Chunk ID). Если в WAV-файле нет секции списка Wave (Wave List Chunk), эта величина равна 0, иначе эта величина равна смещению. в секцию «wavl». Первая секция в секции списка (Wave List Chunk) должна быть указана со значением 0.

Начало блока (Block Start)
Значение Block Start указывает смещение в байтах в секцию «data» или секцию «slnt» для начала блока, содержащего выборку. Начало блока задает первый байт несжатых данных звука PCM или последний байт в сжатых данных звука, где декомпрессия может начаться для нахождения значения соответствующего значения выборки.

Смещение выборки (Sample Offset)
Смещение выборки указывает смещение в блок (указанный Block Start) для выборки, соответствующей интересующей точке (cue point). В несжатых данных звука PCM это просто байтовое смещение в секцию «data». В сжатых данных звука это значение равно количеству выборок (которое может и не быть в байтах) от Block Start до выборки, соответствующей интересующей точке (cue point).

Секция плейлиста указывает порядок воспроизведения последовательности интересующих точек (cue points). Эти точки заданы в секции «cue «, где-то в другом месте файла. Плейлист состоит из массива сегментов, каждый из которых содержит информацию о том, какой сегмент откуда должен стартовать на проигрывание, какой длительности сегмент проигрывания (в выборках) и сколько раз должен повториться сегмент перед переходом к следующему по списку сегменту.

Смещение Размер Описание Величина
0x00 4 Chunk ID «plst» (0x736C6E74)
0x04 4 Chunk Data Size num segments * 12
0x08 4 Number of Segments 1 — 0xFFFFFFFF
0x0a List of Segments

Формат секции Playlist


Количество сегментов (Number of Segments)
Это значение задает количество последующих сегментов в секции плейлиста.

Список сегментов (List of Segments)
Список сегментов — просто набор следующих друг за другом описаний сегментов, которые составлены по формату, приведенному в таблице ниже. Сегменты не должны быть ни в каком определенном порядке, потому что для определения порядка воспроизведения используется позиция интересующей точки (cue point position), связанная с каждым описанием списка.

Смещение Размер Описание Величина
0x00 4 Cue Point ID 0 — 0xFFFFFFFF
0x04 4 Length (in samples) 1 — 0xFFFFFFFF
0x08 4 Number of Repeats 1 — 0xFFFFFFFF

Формат сегмента плейлиста

ID интересующей точки (Cue Point ID)
Cue Point ID указывает начальную выборку для этого сегмента путем указания значения Cue Point, заданного в списке Cue Point List. ID связывающий этот сегмент с интересующей точкой (Cue Point), должен быть уникальным по отношению ко всем другим ID интересующих точек (Cue Point ID).

Длина (Length)
Длина сегмента указывает количество выборок для воспроизведения или зацикливания от начальной выборки, заданной в связанной Cue Point.

Количество повторений (Number of Repeats)
Количество повторений определяет, сколько раз сегмент должен повторить свое воспроизведение, перед продолжением воспроизведения на следующем сегменте.

Секция связанного списка данных (Associated Data List Chunk) используется для задания текстовых меток и имен, которые связаны с интересующими точками — для предоставления для каждой позиции текстовой метки или имени.

Смещение Размер Описание Величина
0x00 4 Chunk ID «list» (0x6C696E74)
0x04 4 Chunk Data Size зависит от содержащегося текста
0x08 4 Type ID «adtl» (0x6164746C)
0x0c список текстовых меток и имен

Формат связанного списка данных

Type ID
Идентификатор типа (type ID) используется для обозначение типа связанного списка данных и всегда имеет значение «adtl».

Список текстовых меток и имен
Список текстовых меток и имен — просто список рассортированных секций, которые определяют текст различными способами. В файлах WAVE используются три основные типы секций — секция метки (Label Chunk), секция примечания (Note Chunk) и секция помеченного текста (Labeled Text Chunk).

Секция метки (Label Chunk) всегда содержится внутри секции связанного списка данных (associated data list chunk). Она используется для связывания текстовой метки с интересующей точкой (Cue Point). Эта информация часто отображается на маркерах или флажках в аудиоредакторах.

Смещение Размер Описание Величина
0x00 4 Chunk ID «labl» (0x6C61626C)
0x04 4 Chunk Data Size зависит от содержащегося текста
0x08 4 Cue Point ID 0 — 0xFFFFFFFF
0x0c текст
Илон Маск рекомендует:  Asp наследование свойств

Cue Point ID
Идентификатор интересующей точки (Cue Point ID) указывает точку расположения выборки, соответствующей этой текстовой метке, путем предоставления ID интересующей точки (Cue Point), заданной в списке интересующих точек (Cue Point List). ID, который связывает эту метку с интересующей точкой (Cue Point), должен быть уникальным по отношению ко всем другим идентификаторам интересующих точек (Cue Point ID).

Текст
Текст — строка символов, оканчивающихся нулем. Если количество символов в строке нечетно, к строке должно быть добавлено однобайтовое выравнивание. Добавленное выравнивание не учитывается в поле размера секции метки.

Секция примечания (Note Chunk) всегда содержится внутри секции связанного списка данных (associated data list chunk). Она используется для связывания текстового комментария с интересующей точкой (Cue Point). Эта информация сохраняется тем же самым способом, как и метки в секции метки.

Смещение Размер Описание Величина
0x00 4 Chunk ID «note» (0x6E6F7465)
0x04 4 Chunk Data Size зависит от содержащегося текста
0x08 4 Cue Point ID 0 — 0xFFFFFFFF
0x0C текст

Cue Point ID
Идентификатор интересующей точки (Cue Point ID) указывает точку расположения выборки, соответствующей этому текстовому примечанию, путем предоставления ID интересующей точки (Cue Point), заданной в списке интересующих точек (Cue Point List). ID, который связывает это примечание с интересующей точкой (Cue Point), должен быть уникальным по отношению ко всем другим идентификаторам интересующих точек (Cue Point ID).

Text
Текст — строка символов, оканчивающихся нулем. Если количество символов в строке нечетно, к строке должно быть добавлено однобайтовое выравнивание. Добавленное выравнивание не учитывается в поле размера секции примечания (комментария).

Секция помеченного текста (Labeled Text Chunk) всегда содержится внутри секции связанного списка данных (associated data list chunk). Она используется для связывания текстовой метки с регионом или секцией данных звука. Эта информация часто отображается в помеченных регионах звука в аудиоредакторах.

Смещение Размер Описание Величина
0x00 4 Chunk ID «ltxt» (0x6C747874)
0x04 4 Chunk Data Size зависит от содержащегося текста
0x08 4 Cue Point ID 0 — 0xFFFFFFFF
0x0c 4 Sample Length 0 — 0xFFFFFFFF
0x10 4 Purpose ID 0 — 0xFFFFFFFF
0x12 2 Country 0 — 0xFFFF
0x14 2 Language 0 — 0xFFFF
0x16 2 Dialect 0 — 0xFFFF
0x18 2 Code Page 0 — 0xFFFF
0x1A текст

Формат секции помеченного текста

Cue Point ID
Идентификатор интересующей точки (Cue Point ID) указывает начальную выборку, которая соответствует этой текстовой метке, с помощью предоставления ID интересующей точки, заданного в списке интересующих точек (Cue Point List). ID интересующей точки, связанный с этой меткой, должен быть уникальным по отношению ко всем другим ID интересующих точек.

Sample Length
Длина выборок (sample length) задает, сколько выборок входит в регион или интервал секции, начиная с интересующей точки.

Purpose ID
Поле предназначения указывает, для чего используется текст. Например, значение «scrp» означает текст скрипта, «capt» означает close-caption (поясняющая подпись, субтитр). Имеется несколько большее количество значений purpose ID, но они предназначены для использования с другими типами файлов формата RIFF (которые обычно не используются в файлах WAVE).

Country, Language, Dialect, Code Page
Эти поля (страна, язык, диалект, кодовая страница) используются для указания информации о месторасположении и языке, используемых в тексте. Обычно они нужны для запросов о получении информации от операционной системы.

Text
Текст — строка символов, оканчивающихся нулем. Если количество символов в строке нечетно, к строке должно быть добавлено однобайтовое выравнивание. Добавленное выравнивание не учитывается в поле размера секции.

Секция семплера (Sampler Chunk) задает основные параметры инструмента, как например семплер MIDI, который должен использоваться для воспроизведения данных звука. Наиболее важно, что он включает в себя информацию о зацикливаниях звука во время воспроизведения. Конечно, Вы можете найти, что это является дублированием информации, которую можно найти в секциях Cue и Playlist формата WAVE, но, к счастью, в секции семплера это сделано более гибко, непротиворечиво, и лучше задокументированным способом.

Смещение Размер Описание Величина
0x00 4 Chunk ID «smpl» (0x736D706C)
0x04 4 Chunk Data Size 36 + (Num Sample Loops * 24) + Sampler Data
0x08 4 Manufacturer 0 — 0xFFFFFFFF
0x0C 4 Product 0 — 0xFFFFFFFF
0x10 4 Sample Period 0 — 0xFFFFFFFF
0x14 4 MIDI Unity Note 0 — 127
0x18 4 MIDI Pitch Fraction 0 — 0xFFFFFFFF
0x1C 4 SMPTE Format 0, 24, 25, 29, 30
0x20 4 SMPTE Offset 0 — 0xFFFFFFFF
0x24 4 Num Sample Loops 0 — 0xFFFFFFFF
0x28 4 Sampler Data 0 — 0xFFFFFFFF
0x2C List of Sample Loops

Manufacturer
Поле производителя (manufacturer) указывает код MIDI Manufacturer’s Association (MMA) для семплера предназначенного для приема звука этого файла. Каждый производитель продукта MIDI имеет свой уникальный ID, который идентифицирует компанию. Если не указан конкретный производитель, то должно быть подставлено значение 0.

В значении имеется некоторая дополнительная информация, которую можно использовать для трансляции в величину, используемую в передаче на семплер формата MIDI System Exclusive. Старший байт показывает количество младших байт (1 или 3), которые значимы для кода производителя. Например, значение для Digidesign будет 0x01000013 (0x13) и значение для Microsoft будет 0x30000041 (0x00, 0x00, 0x41). См. список MIDI Manufacturers List.

Product
Поле продукта указывает ID модели MIDI, заданный производителем. Для получения идентификаторов продукта связывайтесь с производителем семплера. Если не указан конкретный продукт производителя, то должно быть подставлено значение 0.

Sample Period
Период выборки указывает длительность времени воспроизведения одной выборки в наносекундах (обычно равно 1 / [количество выборок в секунду], где [количество выборок в секунду] равно величине, указанной в секции формата).

MIDI Unity Note
MIDI unity note (что-то типа тональности MIDI, решил этот термин не переводить) — величина, имеющая то же самое значение как и MIDI Unshifted Note секции инструмента (instrument chunk). Поле MIDI Unshifted Note указывает музыкальную ноту, на которой выборка будет воспроизведена на её оригинальной скорости выборок sample rate (sample rate указано в секции формата).

MIDI Pitch Fraction
MIDI pitch fraction (тоже какой-то специфический музыкальный термин, что-то типа «доля высоты звука») указывает доли полутона вверх от величины, указанной в поле MIDI unity note. Значение 0x80000000 означает 1/2 полутона (50 cents) и значение 0x00000000 означает неточную настройку между полутонами (лично для меня это все звучит как китайская грамота).

SMPTE Format
SMPTE формат указывает формат времени Society of Motion Pictures and Television E, используемый в следующем поле SMPTE Offset. Если установлено значение 0, SMPTE Offset также должно быть равно 0.

Значение SMPTE Format
нет смещения SMPTE offset
24 24 фрейма в секунду
25 25 фреймов в секунду
29 30 фреймов в секунду с выпадением фрейма (30 выпадает)
30 30 фреймов в секунду

Значения формата SMPTE

SMPTE Offset
Смещение SMPTE Offset — величина, указывающая на смещение времени, используемое для синхронизации / калибровки первой выборки звука. Здесь используется форма 0xhhmmssff, где hh — число со знаком, указывающее количество часов (-23 .. 23), mm — беззнаковая величина количества минут (0 .. 59), ss — (0 .. 59) беззнаковая величина количества секунд и ff — беззнаковая величина количества фреймов (0 .. -1).

Sample Loops
Поле циклов выборок указывает количество определений зацикливания выборок в последующем списке (см. list of sample loops). Это значение может быть установлено в 0, что означает отсутствие последующих зацикливаний.

Sampler Data
Величина данных семплера (sampler data value) указывает количество байт, которые последуют за этой секцией (включая весь список sample loop list). Эта величина больше, чем 0, когда приложение нуждается в сохранении дополнительной информации. Эта величина отражена в значении chunks data size.

List of Sample Loops
Список зацикливаний (list of sample loops) — простой набор последовательных описаний циклов, которые следуют нижеописанному формату. Зацикливания не имеют какой-либо определенный порядок, поскольку каждый цикл выборок, связанный с интересующей точкой, используется для определения порядка воспроизведения. Секция семплера не является обязательной.

Смещение Размер Описание Величина
0x00 4 Cue Point ID 0 — 0xFFFFFFFF
0x04 4 Type 0 — 0xFFFFFFFF
0x08 4 Start 0 — 0xFFFFFFFF
0x0C 4 End 0 — 0xFFFFFFFF
0x10 4 Fraction 0 — 0xFFFFFFFF
0x14 4 Play Count 0 — 0xFFFFFFFF

Cue Point ID
Идентификатор интересующей точки (Cue Point ID) — указывает уникальный ID, который соответствует одной из заданных интересующих точек в списке (cue point list). Кроме того, этот ID соответствует любой из меток, заданных в связанной секции данных (data list chunk), которая позволяет назначать текстовые метки различным циклам выборок.

Type
Поле типа задает, каким образом зацикливаются выборки звука.

Значение Loop Type (тип зацикливания)
Цикл вперед (обычный)
1 Альтернативный цикл (вперед/назад, известный также как Ping Pong)
2 Цикл назад (обратный)
3 — 31 Зарезервировано для будущих стандартных типов
32 — 0xFFFFFFFF Специфические типы, относящиеся к семплеру (задаются производителем)

Start
Значение старта указывает байтовое смещение в данные звука первой выборки, проигрываемой в цикле.

End
Значение окончания указывает байтовое смещение в данные звука последней выборки, проигрываемой в цикле.

Fraction
Дробное (fractional) значение указывает дробную часть выборки, которая принадлежит циклу. Это позволяет точно настроить длительность цикла с точностью выше, чем позволяет одна выборка. Величина может находиться в диапазоне 0x00000000 .. 0xFFFFFFFF. Значение 0 означает отсутствие дробной части, значение 0x80000000 означает 1/2 от длительности выборки. Значение 0xFFFFFFFF соответствует минимальной дробной части выборки, которую можно задать.

Play Count
Значение счетчика воспроизведений (play count) определяет количество проигрываний цикла. 0 означает постоянный бесконечный цикл, который не прервется, пока не произойдет принудительное внешнее вмешательство (например, музыкант отпустит клавишу). Все другие значения указывают абсолютное количество проигрываний цикла.


Секция инструмента (instrument chunk) используется для описания — каким образом звук должен быть проигран как звук инструмента. Эта информация полезна для обмена музыкальной информацией между музыкальными редакторами-семплерами, основанными на выборках (семплах), трекерами или программными таблицами звука. Эта секция является необязательной, и не может встречаться в WAVE-файле больше одного раза.

Смещение Размер Описание Величина
0x00 4 Chunk ID «ltxt» (0x6C747874)
0x04 4 Chunk Data Size 7
0x08 1 Unshifted Note 0 — 127
0x09 1 Fine Tune (dB) -50 — +50
0x0A 1 Gain -64 — +64
0x0B 1 Low Note 0 — 127
0x0C 1 High Note 0 — 127
0x0D 1 Low Velocity 1 — 127
0x0E 1 High Velocity 1 — 127

Формат секции инструмента

Unshifted Note
Поле несмещенной ноты (unshifted note) имеет то же самое предназначение, что и у MIDI Unity Note секции семплера — указывает музыкальную ноту, на которой выборка будет проиграна с её оригинальной скоростью (sample rate, указывается в секции формата).

Fine Tune
Значение точной настройки (fine tune) указывает, насколько подача выборки должна быть изменена, когда звук воспроизведен в центах (1/100 полутона). Отрицательная величина означает, что высота тона должна быть снижена, а позитивная величина означает, что высота тона должна быть повышена.

Gain
Значение усиления (gain) указывает количество децибел для настройки выхода при проигрывании. Значение 0 dB означает отсутствие изменений, 6 dB означает удвоение амплитуды каждой выборки, -6 dB означает уменьшение амплитуды каждой выборки вдвое. Каждые дополнительные +/- 6 dB удваивают или делят амплитуду надвое соответственно.

Low Note и High Note
Поля нот указывают диапазон нот MIDI, в которых звук должен быть проигран, когда происходит событие приема ноты MIDI (от программного обеспечения или команды контроллера MIDI. Контроллером может выступать, например, клавиатура MIDI). Этот диапазон необязательно должен включать значение Unshifted Note.

Low Velocity и High Velocity
Поля скорости (velocity) указывают диапазон скоростей MIDI (MIDI velocity), с которыми должен проигрываться звук. 1 относится к самому легкому проигрыванию, 127 к самому жесткому.

[Изменения формата]

Обратная сторона популярности формата файла WAVE — из сотен программ, которые поддерживают этот формат, многие злоупотребляют или неправильно используют формат из-за плохого программирования и/или плохой документации. Как только некоторые из этих «непослушных» программ становятся довольно популярными и производят в большом количестве миллионы неправильных WAVE файлов, остальная часть отрасли программного обеспечения вынуждена иметь дело с этим и производить код, который может распознавать эти неправильные файлы. Новый код не должен записывать эти ошибки, но должен читать ошибочный WAVE-файл. Ниже описано несколько таких исключений, которые были сделаны в дополнение к строгому/исходному формату WAVE.

* Некорректная величина блока выравнивания (Block Alignment) — с этим можно иметь дело, вычисляя Block Alignment по указанной ранее формуле.
* Некорректная величина среднего количества выборок в секунду (Average Samples Per Second) — с этим можно иметь дело, вычисляя Average Samples Per Second по указанной ранее формуле.
* Отсутствие пустых байт для выравнивания на слово (Missing word alignment padding) — с этим трудно бороться, но можно давать пользователю предупреждение, если имеется нераспознанный ID блока, и одно смещение побайтового чтения дает возможность распознать ID блока. Это не полное решение, но оно обычно работает, даже если у программы нет полного списка легальных ID.

Международный журнал

гуманитарных и естественных наук

Кейп А.В. Разработка функционала для работы с не кодированными звуковыми файлами // Международный журнал социальных и гуманитарных наук. – 2020. – Т. 5. №1. – С. 233-237.

РАЗРАБОТКА ФУНКЦ ИОНАЛА ДЛЯ РАБОТЫ С НЕКОДИРОВАННЫМИ ЗВУКОВЫМИ ФАЙЛАМИ

А.В. Кейп , студент

Научный руководитель : Е.А. Слива, старший преподаватель

Нижневартовский государственный университет

(Россия, г. Нижневартовск)

Аннотация . В данной статье рассматриваются возможные сценарии работы с некодированным звуковым файлом в формате wav PCM ( Pulse-code modulation ). В работе рассматриваются методы считывания данных из файла, построения частотно-волнового спектра, изменения амплитуды волны аудиофайла и сохранения результата. В качестве результата исследования был создан простейший аудиоредактор, который может являться базой для разработки программного решения в области работы со звуком.

Ключевые слова: редактирование звука, программирование, разработка функций, аудиоформат, звуковой редактор.

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

В основе кодирования звука с использованием ПК лежит процесс преобразования колебаний воздуха в колебания электрического тока и последующая дискретизация аналогового электрического сигнала. Кодирование и воспроизведение звуковой информации осуществляется с помощью специальных программ (редактор звукозаписи ) [1]. В данной работе был разработан собственный вариант редактора звукозаписи. В качестве инструментария разработки были выбраны: язык программирования C ++, средой для разработки – Qt .

Считывание данных wav файла

Для начала работы с файлом необходимо открыть его в программе. Для связи файла с программой был выбра н стандартный класс Qt QFile . Для воспроизведения и чтения метаданных (длительность, исполнитель, заголовок) аудиофайла был использован класс QMediaPlayer . С помощью созданных объектов классов была написана функция открытия файла и подключения его к QMediaPlayer .

Анализ wav PCM файла

Спектрально-волновая диаграмма представляет собой подряд записанные значения амплитуды, которые воспроизводятся в конкретные временные отрезки. Значения положения и длительности этих отрезков определяются исходя из частоты дискретизации файла. Например, если частота дискретизации 44100 Гц, это означает, что за 1 секунду значение амплитуды может измениться 44100 раз. От значений амплитуды зависит громкость воспроизводимого звука, а от скорости изменени я звука – высота тона (рис . 1 ).

Рис. 1. Спектрально-волновая диаграмма

Для начального анализа был выбран несжатый формат . wav PCM . PCM ( Pulse — code modulation ) расшифровывается как и мпульсно-кодовая модуляция . При импульсно-кодовой модуляции аналоговый передаваемый сигнал преобразуется в цифровую форму посредством трёх операций: дискретизации по времени, квантования по амплитуде и кодирования [2]. Это значит, что в файле будут последовательно записаны данные амплитуды волны для каждой единицы времени. Формат . wav был выбран, т.к. он имеет простую структуру (таблица) [ 3 ] :

Таблица. Структура wav PCM файла

0.. 4 3 (4 4 байта)

Д анные о типе файла, такие как: частота дискретизации, глубина кодирования, количество каналов и т.д.

Непосредственно WAV-данные , содержащие значения амплитуды волны.

Для построения спектрально-волновой диаграммы необходимо было считать данные из секции data . Для этого следует использовать побайтовое чтение из файла , что было реализова но с помощью класса Qt QByteArray . В качестве ф айл а для анализа был выбран файл с глубиной кодирования звука 16 бит, значит одно значение амплитуды будет кодироваться 2-мя байтами.

Нужно было определить в каком порядке располагаются байты (старший-младший). Поскольку формат WAV-файла разрабатывался как формат для приложений операцион ной системы Windows, в которой традиционно использовались процессоры Intel, все значения данных формата хранятся как Little-Endian, т. е. самый младший значащий байт идет первым [ 4 ].

Так как одно значение амплитуды кодируется 2 байтами, то нужно использовать побитовое смещение старшего байта и дизъюнкцию его с младшим байтом, а далее преобразовывать это значение к какому-то диапазону (был выбран диапазон [-1..1]). Для чтения массива значений амплитуд была разработана функция getSpectrumArray . Данная функция считывает данные из файла и преобразует их в массив амплитуд для удобной работы со значениями в дальнейшем.

Отображение графика в программе

Для отображения графика на форме был создан объект QG raphicsView. На этом объекте поочередно строя тся линии, которые отобража ют зависимость амплитуды от времени. Для построения графика был выбран аудиофайл длительностью 10 секунд (небольшой размер для быстрой отрисовки). Так как рисовать линии абсолютно для всех изменений значений (а это 44100Гц * 10 сек = 441000 изменений) было бы слишком затратно по времени и ресурсам вычислительной машины, а такое точное отображение графика, как правило, н е будет востребовано , то было принято решение считывать изменения волны через определенные промежутки. После ряда тестов, по которым оценивались скорость отрисовки и точность измерения амплитуды волны, было выявлено, что оптимальным промежутком для считывания является 100 единиц. Но так как волна отображалась только через каждые 100 измерений, то между этими изменениями оставались пустые промежутки. Чтобы решить эту проблем у , было принято решение увеличить « плотность » волны на графике, уменьшив изменяемое значение отображения времени в 10 раз. Т ак как значения амплитуды волны находились в промежутке [-1;1], то необходимо было увеличить диапазон её отображения. Для этого каждое значение амплитуды было умножено на 200. Для отображения графика была разработана функция show Spectrum Array . Эта функция создана для отображения ранее полученного массива значений амплитуд.

Далее было проведено сравнение полученного результата (рис . 2 а ) с действительным спектром волны , полученным в другой программе (рис . 2б ). На рисунках видно, что полученная в результате анализа волна, очень похожа на ту, которую мы получили в известном аудиоредакторе Steinberg Cubase .

а ) . Полученный рисунок волны б ) . Действительный спектр волны

Рис. 2 Отображение графика амплитуды звуковой волны

Разработка инструмента изменения амплитуды волны

Как пример самого простого инструмента редактирования был выбран инструмент изменения громкости. Т.к. данные в нашем файле определяются всего 2 параметрами (значение времени, в котором воспроизводится звук определенной амплитуды, и само значение амплитуды), то ставится задача только увеличить значение амплитуды в определенный момент времени. Областью увеличения амплитуды будут служить параметры, передаваемые в функцию изменения амплитуды (значения времени, умноженные на частоту дискретизации, в секундах). Для реализации данной функции необходимо все байты, которые были считаны в массив QByteArray , в заданной области увеличить на заданное значение изменение громкости (в %). Т.к. для обра ботки был выбран файл с глубиной 16 бит, то каждое значение амплитуды должно кодироваться значением от -32768 до 32767. При выходе за границы данного диапазона было принято решение сжимать значение амплитуды до максимально допустимого. Для изменения громкости была разработана функция changeVolume . Данная функция редактировала содержимое ранее полученного массива значений амплитуд по заданному пользователем сценарию. Далее был открыт файл длиной в 11 секунд и обработан данной функцией следующим образом: первые 3 секунды были понижены в громкости на 80%, 3-5 секунды были увеличены на 70%, 5-7 секунды уменьшены в громкости на 100% и с 7 секунды громкость была увеличена на 30%. Исходная волна (рисунок 3а) и результат продемонстрированы ниже ( рисунок 3б ).

Илон Маск рекомендует:  filter в CSS

а ) . Исходная волна б ) . Отредактированная волна

Рис. 3. Редактирование амплитуды волны

Заключение

В ходе написания статьи был разработан аудиоредактор, с возможностью построения волнового спектра и изменения громкости несжатого . wav PCM файла. Данный проект показывает сценарии работы с аудио файлами и является простой основой для реализации собственного приложения для редактирования звука.

1. Кодирование звука в компьютере [Электронный ресурс] – url : http://informatika.sch880.ru/p23aa1.html

2. Панфилов И.П., Дырда В. Е. Теория электрической связи. – М.: Ра дио и связь, 1991. – 344 с.

DEVELOPMENT OF FUNCTIONALITY TO WORK WITH UNENCODED AUDIO FILES

A.V. Keyp , student


Supervisor : E.A. Sliva , senior lecturer

Nizhnevartovsk state university

Abstract. This article discusses possible scenarios with uncoded audio file in wav format, PCM (Pulse-code modulation). The paper deals with the methods of reading data from a file, methods of building a frequency-wave spectrum, methods of changing the amplitude of the wave audio file and methods of saving the result. A simple audio editor was created as a result of this research. It can be useful as a base for the development of software solutions in the field of working with sound.

Keywords: edit the sound, programming, development functions, audio format, sound editor.

Форум пользователей MATLAB и Simulink

Работа с wave файлами

Модератор: Admin

Работа с wave файлами

Сообщение Dikiton1993 » Сб июн 03, 2020 5:15 pm

Re: Работа с wave файлами

Сообщение sandy » Сб июн 03, 2020 8:46 pm

Re: Работа с wave файлами

Сообщение Dikiton1993 » Вс июн 04, 2020 4:13 am

Re: Работа с wave файлами

Сообщение sandy » Вс июн 04, 2020 9:50 am

Re: Работа с wave файлами

Сообщение Dikiton1993 » Вс июн 04, 2020 1:03 pm

Как демодулировать есть представления.
Просто столкнулся проблемами технической реализации.
Допустим для демодуляции psk сигналов, необходимо выделить несущую, для этого необходимо возвести несущую в квадрат, или 4 степень, в зависимости от вида манипуляции.

Re: Работа с wave файлами

Сообщение Dikiton1993 » Вс июн 04, 2020 1:22 pm

Как демодулировать есть представления.
Просто столкнулся проблемами технической реализации.
Допустим для демодуляции psk сигналов, необходимо выделить несущую, для этого необходимо возвести несущую в квадрат, или 4 степень, в зависимости от вида манипуляции, при этом на рисунке не видно несущей, картинка под ссылкой.
https://yadi.sk/i/ouRy6XAT3Joaax

Так же если посмотреть код

clear all
close all

% Спектральное представление сигнала
FftL2=FS;% Количество линий Фурье спектра
FftS2=abs(fft(Y,FS));% Амплитуды преобразования Фурье сигнала
FftS2=2*FftS2./FS;% Нормировка спектра по амплитуде
FftS2(1)=FftS2(1)/2;% Нормировка постоянной составляющей в спектре
FftSh2=abs(fft(Y,FS));% Амплитуды преобразования Фурье смеси сигнал+шум
FftSh2=2*FftSh2./FS;% Нормировка спектра по амплитуде
FftSh2(1)=FftSh2(1)/2;% Нормировка постоянной составляющей в спектре

F2=0:FS/FftL2:FS/2-1/FftL2;% Массив частот вычисляемого спектра Фурье
figure% Создаем новое окно
subplot(2,1,1);% Выбор области окна для построения
plot(F2,FftS2(1:length(F2)));% Построение спектра Фурье сигнала
title(‘Спектр сигнала wave’);% Подпись графика
s=FS/16;
%sonogram = vco(Y, [FS/FftL2,FS/2-1/FftL2], FS);

figure
specgram (Y, FS, FS, s);
title(‘sonogram’);% Подпись графика

%figure
%plot ();
%title(‘осцилограмма’);% Подпись графика

Я не пойму как работать с массивом Y, сразу уже можно работать для демодуляции с функцией pskdemod, и представление чисел в этом массиве.
Для демодуляции используется петля Костаса (рис. под ссылкой ниже)
https://yadi.sk/i/xlW0Cg2a3Jobwe
входные данные BPSK это уже мой массив Y, или требуется какая то фильтрация, для выделения полосы сигнала, т.к. по первой картинке он занимает не всю полосу, и как мне понять что это мой сигнал, а не шум.

Заранее большое спасибо.

Re: Работа с wave файлами

Сообщение sandy » Вс июн 04, 2020 7:10 pm

Re: Работа с wave файлами

Сообщение Dikiton1993 » Вс июн 04, 2020 8:06 pm

Просто задача и стоит научится анализировать, символьную скорость и несущую частоту, для демодуляции.

pskdemod- получается как векторный анализ в зависимости от времени?

сделать- следуя петле костаса правильно понимаю?

Еще несколько вопросов:
pskdemod-работает только с комплексной амплитудой, что бы от Y перейти к комплексной амплитуде, нужно умножить Y на exp^j*ф(t) или просто взять Imag от Y/

так с выделением несущей понял, а можно как то анализировать получившийся рисунок (ниже ссылка на рисунок), что бы в матлабе я определял автоматом несущую, ну соответственно после возведения в степень.
https://yadi.sk/i/OL-1XA_V3Jp7ct

Заранее большое спасибо.
С уважением

Re: Работа с wave файлами

Сообщение sandy » Пн июн 05, 2020 12:56 am

Re: Работа с wave файлами

Сообщение Dikiton1993 » Пн июн 05, 2020 7:45 pm

Спасибо за ответы.

У меня еще один вопрос, для получения скорости (спектра огибающей), мне необходимо прогнать сигнал по следующей схеме
https://yadi.sk/i/81ufm-ga3JrCtn

Но при при амплитудной демодуляции, с помощью функции «amdemod» , не работает с комплексными функциями, может еще есть способ узнать скорость?

Заранее большое спасибо.
С уважением

Re: Работа с wave файлами

Сообщение sandy » Пн июн 05, 2020 7:54 pm

Re: Работа с wave файлами


Сообщение Dikiton1993 » Вт июн 06, 2020 3:36 pm

Спасибо за ответ.

А можете посоветовать литературу или сайт по поводу, объяснения работы петли костаса и демодуляции PSK сигналов.

Re: Работа с wave файлами

Сообщение sandy » Вт июн 06, 2020 5:02 pm

Re: Работа с wave файлами

Сообщение Dikiton1993 » Чт июн 08, 2020 9:17 am

gun(1)=vco(0,fc,FS);
I=Y(i).*hilbert(gun(i)); %синфазная составляющая
Q=Y(i).*gun(i); %квадратурная состовляющая, выход демодулятора
[b, a]=butter(2, 2*Skorost(1)/FS); %параметры фильтра батерворта
Ifilt=filtfilt(b,a,I); %фильтрация синфазной состоавляющей фильтром ФНЧ
Qfilt=filtfilt(b,a,Q); %фильтрация синфазной состоавляющей фильтром ФНЧ
DecCos=Ifilt.*Qfilt; %перемножение отфильтрованных состовляющей детектор костаса
gun(i)=vco(DecCos,fc,FS); %генератор управляющий напряжением
%i=i+1;
end

Error using filtfilt>getCoeffsAndInitialConditions (line 182)
Data length must be larger than 6 samples.

Error in filtfilt (line 97)
[b,a,zi,nfact,L] = getCoeffsAndInitialConditions(b,a,Npts);

Error in first (line 68)
Ifilt=filtfilt(b,a,0.05); %фильтрация синфазной состоавляющей фильтром ФНЧ

Не понимаю в чем ошибка, точнее я понял, что требуется больше сэмплов, но как ее исправить я не понимаю может, кто посмотрит ошибка в самой демодуляции?

Заранее большое спасибо

Re: Работа с wave файлами

Сообщение sandy » Чт июн 08, 2020 9:39 am

Ммда. вы, похоже, к сожалению, не понимаете, как работают те матлабовские функции, которые пытаетесь использовать.

1. Реализовывать замкнутые следящие системы в матлабе — штука неудобная, так как это сразу же лишает вас почти всех достоинств MATLAB, не давая использовать векторизацию операций. Как следствие, работать код будет медленно. В Simulink это более естественно выглядит.

2. Функция hilbert не имеет отношения к делу — она работает с длинным сигналом целиком, а не с отдельными его отсчетами, как необходимо в данном случае. Да и вообще, зачем она вам? У вас же VCO просто синус/косинус должен выдавать, то есть Re/Im комплексной экспоненты.

3. Функция filtfilt нарушает принцип причинности, обрабатывая сигнал целиком в двух направлениях — от начала к концу и от конца к началу. Для обработки кусочков сигнала она непригодна. Если хотите реализовывать длинные фильтры, вам поможет только функция filter с использованием возможностей доступа к начальному/конечному внутреннему состоянию фильтра. Ну, или объекты фильтров, там тоже можно состояние сохранять от вызова к вызову.

4. Функция vco, опять-таки, генерирует длинный сигнал с заданным законом изменения мгновенной частоты. Она не позволяет управлять начальной фазой колебания и непригодна для использования в замкнутых системах с обратной связью.

Загрузка и воспроизведение несжатого wav-файла

В этой теме 0 ответов, 1 участник, последнее обновление Васильев Владимир Сергеевич 2 года/лет, 1 месяц назад.

Я не являюсь автором заметки (нашел ее у себя на компьютере, разбирая завалы). Материал полезный, но найти автора не получилось (как и найти этот же материал в интернете). Публикую, надеюсь автор не будет против (не для того ведь он писал это сокровище, чтобы оно пылилось только на моем жестком диске?).

1. Введение

В этой статье я расскажу о том, как загружать и проигрывать wav-файл, проигрывать будем при помощи DirectSound, поэтому, если у Вас не стоит DirectX SDK, то идите на microsoft.com, и скачайте там 9-ую версию. Писаться всё это дело будет под C++, примеры тестировались в MSDEV2005.

2. Структура wav – файла

Для начала рассмотрим структуру, wav-файла, я не раскрою Вам эту тайну полностью, но то о чём говорил в заголовке статьи, наверное, сделаю.

Wav-файл состоит из нескольких блоков, которые содержат информацию, причём вовсе не обязательно, что все эти блоки идут в определённом порядке.

Вот некоторые из этих блоков:

2.1. Блок RIFF

Тип Значение Комментарий
char[4] MAKEFOURCC(‘R’,’I’,’F’,’F’); Идентификатор RIFF, который присущ всем RIFF-файлам, wav – не исключение.
long Длина файла – 8 Длина без этого заголовка

2.2. Блок WAVE

Тип Значение Комментарий
char[4] MAKEFOURCC(‘W’,’A’,’V’,’E’); Идентификатор WAVE, есть у всех wav-файлов
char[4] MAKEFOURCC(‘f’,’m’,’t’,’ ’); Идентификатор fmt
long Обычно 16. (См. прим. ниже) Длина описания данных
WAVEFORMATEX В зависимости от файла Описание аудио-данных

2.3. Блок FACT(необязательный)

Тип Значение Комментарий
char[4] MAKEFOURCC(‘f’,’a’,’c’,’t’); Идентификатор ‘fact’, который говорит, что дальше идёт именно этот блок.
long Длина блока ‘fact’ Количество байт до следующего блока
. . Что тут находится, я не знаю, но это
не важно, ходят слухи, что тут хранится количество семплов (. ) в
файле, и то что он используется исключительно для сжатых wav-файлов…

2.4. Блок DATA:

Тип Значение Комментарий
char[4] MAKEFOURCC(‘d’,’a’,’t’,’a’); Информирование о блоке ‘data’
long Длина звуковых данных Количество байт до следующего блока
Аудиоданные То, ради чего мы всё это прокопали =)

Остальные блоки, такие, как комментарий, название исполнителя и т.д. нас не интересуют

3. Алгоритм

Вообще, мы не учтём то, что все блоки стоят не в нормальном порядке. Почему? А потому что стандартная виндовская программа «Звукозапись», читает любые нормальные wav-файлы, а пишет, нам нужные, а мы ведь пишем игру, а не плеер ;)?

Итак, сначала при откроем файл, потом прочитаем первые четыре байта, проверим, что они равны MAKEFOURCC(‘R’,’I’,’F’,’F’), или, если вы считывали в строку, то просто “RIFF”, и если проверка провалилась, то бьём тревогу, мол, это не wav-файл.

Далее пропускаем информацию о размере, и читаем ‘WAVE’-блок, так же проверяем, иначе бьём тревогу, далее идёт блок ‘fmt ‘, считываем ещё 4 байта и проверяем их, заметьте, что все буквы в блоке ‘fmt ‘ маленькие.

Дальше считываем длину блока ‘fmt ‘, нам от него нужна только структура WAVEFORMATEX, которую, нам нужно передать DirectSound. Её размер = 16 байт, а на всё остальное мы забиваем…

Кстати, в структуре WAVEFORMATEX, есть поле под названием “wFormatTag”, если оно не равно 1, значит данные либо запакованные, либо не нашего формата, короче вывод состоит в том, что прочитать мы его не сможем… Из этого следует, что лучше в этом случае считывание прекратить и выдать ошибку.

Дальше самое интересное при считывании этого вида файла. Когда я искал информацию по данному поводу, я зашёл на форум, задал вопрос, через месяц (. ) мне ответили и дали пример, я разобрался, и теперь пишу эту статью, но не один (. ) пример не был рассчитан на блок ‘fact’, что он делает полезного, я так и не понял, но я на него просто
забиваю, т.к. после наименования блока, обычно идёт его размер, так я и сделал, и теперь всё работает…

А теперь по делу, читаем 4-е байта, проверяем, если в них записано “fact”, то считываем 4-е байта, количество байтов, которое мы должны пропустить будет считанным числом. Тем самым мы добираемся до секции ‘data’.

Может быть такая ситуация, что Вы не найдёте блока ‘fact’, а найдёте сразу ‘data’, не пугайтесь в любом случае всё будет работать нормально.

Итак, обработка блока ‘data’, как обычно считываем имя блока (эти самые 4-е байта), если оно неравно ‘data’, то бунтуем, потом считываем размер данных, заметьте, что этот размер теперь для нас важен. Т.к. это тот размер, который обозначает размер аудио-данных.

Считали, а за ним, та самая вкусность ради которой мы всё это проделали =). Ням-ням, считываем, дальше всё раскидываем по буферам, и вуаля! Усе готово.

Теперь переходим непосредственно к коду.

4. Программная часть


Создаём консольное приложение, пустое, никаких сервисов, типа MFC не используем.

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

Не забываем подключить необходимые lib’ы:

Отключаем предупреждение об устаревшей функции…
#pragma warning(disable:4996) //ОТключаем предупреждение strcat
Используем пространство имен std:
using namespace std;
DirectSound у нас будет общим, поэтому мы его объявляем в глобальных переменных:
IDirectSound8 *g_pDirectSound;
Прототип функции, которая будет проигрывать файл:
void PlayWav(const char* szFileName);
Наша главная функция ��

В ней мы инициализируем DirectSound и проигрываем файл.

Теперь, непосредственно насчёт функции PlayWav:

Все файлы, которые нам указали лежат в папке «WINDOWSMedia», поэтому мы прицепляем это к каждому имени файла, мы ведь не знаем, на какой диск у пользователя установлен WINDOWS?

Проверяем файл на наличие, открываем, если такой имеется.

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

Далее проверяем сжат-ли файл, если сжат, то мы его прочесть не сможем…

Дальше идёт переломный момент с блоком ‘fact’, я это уже объяснял в теоретической части, теперь можно взглянуть и на код, возможно, будет более понятнее =)

Я думаю, что этот код понятен, мы просто проверяем стоит-ли перед блоком ‘data’, не нужный нам блок ‘fact’, и пропускаем его в случае нахождения.

Дальше непосредственно узнаём размер аудио-данных, выделяем для них память, и считываем, не забывая закрыть файл.

Теперь идёт работа с DirectSound, создаём буфер…

Задерживаем окончание выполнения функции до тех пор, пока проигрывается файл:

Suvitruf’s Blog :: Gamedev suffering

Блог о разработке игр и серверных технологиях

Основы Andro > 3 комментария

Для порта игры пришлось работать с OpenAL. Можно конечно было выкинуть весь C++ код и переписать всю работу со звуков на Java, но это не интересно. Решил поделиться опытом и показать как на Android работать с OpenAL и форматами WAV, OGG.

Подготовка

В первую нужно собрать OpenAL. Для работы с WAV этого достаточно, но мы же ещё хотим и с OGG поработать. Для OGG нужен декодер Tremor.

Собрать библиотеки

Сам OpenAL скачать можно отсюда. По сути, вам необходимо просто папку в проект добавить и в .mk файле прописать всё для сборки. Не помню уже, в репозитарии есть ли .mk файл или нет. В любом случае, внизу статьи сможете скачать мой проект готовый.

Android.mk для OpenAL

У Tremor есть всё, что необходимо. Просто добавьте всю папку в проект и сможете работать с .Ogg. Остаётся только подключить библиотеки в Android.mk основного проекта, добавив пару строчек в него:

А так же включить библиотеки все в Application.mk:

Структура WAV

Немного теории не повредит. Waveform Audio File Format (WAVE, WAV) — формат хранения оцифрованных аудио данных. Данный формат поддерживает данные различной битности, с различной частотой выборки и числом каналов. Суть его в том, что данные не закодированы, оттого и огромный размер таких файлов.

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

Чтение WAV

Собственно, наша задача — считать хэдеры и данные, а потом на основе них заполнить OpenAL структуры. Метод для чтения WAV:

Само чтение ничего экстраординарного вроде не представляет.

Чтение WAV

Ошибки в заголовках

Стоит сказать об WAV кое-что. Бывает такое, что файл на PC вроде прослушивается отлично, но в при работе в OpenAL с ним возникают ошибки. Это из-за косяков в заголовках файла. Я встречал много конвертеров, которые в хэдеры писал какую-то чушь (свой логотип как пример), как правило в dataSize.

Непосредственно сами данные аудио хранятся после хэдера и их размер в dataSize. Если с этим полем что-то не так, а вы будете читать данные в соответствии с этими данными, то будут ошибки. Можно правда посчитать размер в лоб. Размер данных = размер файла — размер хэдера. Так что, думаю, плееры берут размер данных вычитая, а не из хэдера.

В чём особенность Ogg по сравнению с WAV? Это сжатый формат. Ogg является всего лишь контейнером. Музыка или видео сжимаются кодеками, а результат обработки хранится в подобных контейнерах. Контейнеры Ogg могут хранить потоки, закодированные несколькими кодеками. Так что, перед там как записать данные в буфер OpenAL, нам необходимо данные декодировать. Загвоздка в том, что по умолчанию Vorbis (а мы будем использовать именно этот кодек) читает из FILE, так что нам необходимо переопределить все callback методы по работе с данными.

Определение callbacks

Теперь необходимо прочитать:

Само чтение Ogg файла

При запуске приложения вызываем C++ метод loadAudio, который вызывает load у NativeCallListener, который и грузит звуки:

Есть тут нюанс — аудио грузится целиком. Поэтому для звуков такое решение отличное, но для музыки нет. Представьте, сколько будет памяти потреблять распакованная .ogg песня. Поэтому, будет отлично, если кто-то на основе этого решения напишет проигрывание аудио со стримингом, а не полной загрузкой в буфер.

Теперь вы можете работать с OpenAL под Android. Код решил заливать на гитхаб. Так что исходники этого и предыдущих уроков можете скачать отсюда.

Расскажите по Wave Editor – как пользоваться программой для правки небольших WAV файлов?

Wave Editor — интересный аудио редактор от компании Nero, в функции которого встроена работа с небольшими звуковыми композициями.
Его функций будет достаточно для обрезки, перекодирования, добавления различных звуковых эффектов.

Программа поддерживает ряд самых популярных звуковых форматов — wav, wma, mp3, flacc, mp4, ogg, aif.
Для мобильных телефонов самым универсальным и подходящим практически ко всем моделям, будет wav и mp3.
Рассмотрим последний как более популярный.

Задача: олучается, что нам необходимо добавить в программу небольшой музыкальный файлик, немного с ним поработать обрезать его, добавить парочку эффектов, а потом, получившуюся композицию сохранить в формате mp3.

1. Запускаем программу.
С помощью меню Файл -> Открыть добавляем в программу ту композицию в формате wav, которую мы будем редактировать.

2. О всех возможностях редактирования аудио файлов, можно почитать в вопросе
“Как пользоваться Nero Wave editor для редактирования небольших аудио-файлов?”

3. После того, как вы с вашим файлом совершите задуманные манипуляции — обрежете его, добавите какие-то эффекты, сделаете нарастающую или убывающую громкость, полученный результат нужно будет сохранить.

Для этого нажимаем Файл -> Сохранить как и в появившемся меню нужно выбрать формат mp3 (он подойдет практически для всех мобильных телефонов).

4. Теперь перекиньте сохраненный файл себе на телефон и наслаждайтесь результатами своего творчества.

Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL