![]() |
Модераторы: Snowy, Alexeis, MetalFan |
![]() ![]() ![]() |
|
Alexeis |
|
||||||||||||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 55 Всего: 459 |
В связи с недостаточной информацией на русском языке, представляю вам свой перевод фрагмента одной из наиболее удачных статей(на мой взгляд). В эту статью не вошло описание дополнительных чанков, а также оскорбительные высказывания в сторону авторов WAVE формата. Все структуры переписаны в формат record Object pascal.
HTML вариант здесь ---------------------------------------------------------------------------------------- Формат WAVE файлов WAVE – это формат хранения оцифрованных аудио данных. Данный формат поддерживает данные различной битности, с различной частотой выборки и числом каналов. Данный формат весьма популярен на платформах стандарта IBM PC (и совместимых с ним). Этот формат подразумевает хранение аудио данных в особых блоках, которые называют чанками (chunks). Форматы данных ID = array[1..4] of Char; - идентификатор чанка. Организация данных Все данные хранятся в виде 8-ми битовых чисел, расположенных таким образом, что младшая часть слова данных записывается первой. Byte : | байт 0 |. Word : | байт 0 | байт 1 | Integer : | байт 0 | байт 1 | байт 2 | | байт 3 | Структура файла Wav файл представляет собой набор из многочисленных чанков разного типа. Важнейшим чанком является чанк формата (Format chunk – «fmt»), который содержит важные параметры звуковых данных, например частоту выборки. Другим важным чанком является чанк данных (Data chunk), который и определяет форму аудио сигнала. Присутствие других дополнительных чанков (optional chunks) не обязательно. Все приложения использующие wav файлы должны уметь читать обязательные чанки, и уметь выборочно игнорировать дополнительные чанки. Программы, предназначенные для копирования wav файлов должны копировать все чанки, даже те которые он не может интерпретировать. Порядок следования чанков разного типа может быть произвольным. Исключение составляет чанк формата, который должен предшествовать чанку данных. Некоторые грубо написанные программы всегда интерпретируют первый чанк (после RIFF заголовка) как чанк формата, хотя в спецификации формата подразумевается, что первый чанк может быть не только чанком формата, но и дополнительным чанком. Рассмотрим схему простейшего wav файла
Формат wav файла создавался и модифицировался без всякой координации множеством авторов (каждый из которых вносил свои специфические чанки). В результате он получился отчасти противоречивым, например 8-ми битные данные являются беззнаковыми, а 16-битные – числа со знаком. Элементы выборок и фреймы Важнейшими понятиями при интерпретация wave файлов, являются понятия элементы выборок и фреймы. Элемент выборки представляет собой мгновенное значение амплитуды сигнала. Данные длинной более 8-ми бит хранятся в виде блока размером от 9 до 32 бит состоящего из двух смежных слов (определяется значением поля wBitsPerSample, в чанке формата, для несжатого подстандарта PCM). Например для 16 битного формата (2х8 бит) диапазон значений амплитуд от -32768 ($8000) до 32767 ($7FFF). Для формата 8бит и меньше (1 беззнаковый байт) диапазон значений амплитуд от 0 до 255. В связи с архитектурой современных процессоров было решено, что при сохранении данных размер выборки будет округлятся до величины кратной 8-битам. Для АЦП с разрядностью не более 8-бит данные сохраняются в 8-ми битном формате. Для АЦП с разрядностью от 9 до 16 бит элемент выборки будет 16 битным числом со знаком. Для АЦП с разрядностью от 17 до 24 бит выборка будет 3-х байтной. Для АЦП с разрядностью от 25 до32 бит выборка будет двойным знаковым 32 битным словом. И т.д. Кроме того, биты данных (не кратных 8) должны быть выровнены по левому краю. Например 12 битные данные (записываются 16-ти битным словом) выравниваются следующим образом – данные выборки записываются с 4-го по 15 бит включительно, биты от 0 до 3 устанавливаются в нуль. Т.о. число 101000010111 записывается как
При многоканальной записи элементы выборок записываются поочередно. Так для стерео записи в начале пишется одна выборка левого канала, затем правого, затем следующая выборка левого и т.д. Такое расположение выборок упрощает пересылку данных в ЦАП. Блок из нескольких выборок воспроизводимых одновременно называется фреймом. В нашем примере фрейм это блок, состоящий из двух выборок (левого и правого каналов)
Для одноканальной записи, фрейм состоит просто из одной выборки. Для многоканальной записи правила составления фрейма следующие:
Выборки в пределах одного фрейма записываются непрерывно один за другим без неиспользованных байтов между ними. Следует отметить, что все вышеупомянутое относится к формату записи без сжатия (PCM). Добавлено @ 10:12 Чанк формат (Format Chunk) Чанк Формат («fmt») описывает фундаментальные параметры данных, частоту выборки, разрядность данных и число каналов цифровой звукозаписи.
ChankFormat – может иметь и дополнительные поля, поэтому нельзя игнорировать поле chunkSize – определяющее размер записи минус 8 бит (поля chunkID и chunkSize),. Значение chunkedID всегда равно “fmt “. Звуковые данные могут хранится без сжатия, тогда выборки хранятся как было описано в разделе Элементы выборок и фреймы. В случае формата со сжатием размеры выборок могут отличаться от разрядности звуковых данных. На наличие сжатия указывает поле wFormatTag. В этом случае его значение wFormatTag отличается от единицы. Кроме того в ChankFormat появятся несколько полей идентифицирующие метод сжатия. - Первое дополнительное поле (типа Word) определяет длину добавочного блока(после этого поля). -Далее следует специальный чанк (Fact chunk) содержащий переменную типа Cardinal, определяющую размер всех аудио данных (в несжатом ввиде). Размер задается в выборках. Существует большое количество методов сжатия. Детальное описание каждого из них можно посмотреть на сайте Microsoft. Если никакое сжатие не используется (то есть, wFormatTag = 1), то после ChankFormat нет дополнительных служебных полей. Поле wChannels содержит число звуковых каналов. Значение 1 указывает на моно звучание, значение 2 стерео ,4 четыре канала звука и т.д. Напомню, что выборки многоканальных записей чередуются, а элементарный блок из таких данных образуют Фрейм. Реальные данные хранятся в чанке данных (Data Chunk), который будет описан позже. -Поле dwSamplesPerSec хранит частоту выборок в секунду (то есть, Герц). Существуют три стандарта MPC - 11025, 22050, и 44100 ГЦ, хотя допускается использование других частот. - Поле dwAvgBytesPerSec указывает, сколько байтов проигрываются каждую секунду. dwAvgBytesPerSec может использоваться приложением, чтобы оценить, буфер какого размера необходим, для того чтобы должным образом воспроизводить звук без проблем связанных с прерыванием воспроизведения звука. Его значение должно быть равно результату произведения dwSamplesPerSec * wBlockAlign округленного в большую сторону. - Поле wBlockAlign должно быть равно значению выражения wChannels * (wBitsPerSample div 8) округленному в большую сторону. По существу, wBlockAlign - размер фреймов в байтов. (т.о. фрейм для 16-битовой выборки равен 2 байтом, фрейм для 16-битовой стерео выборки 4 байта. И т.д). В каждом звуковом файле может быть не более одного чанка формата. Чанк данных (Data Chunk) Чанк данных содержит фреймы звуковых данных (все каналы звуковых данных) Рассмотрим структуру
-Значение ID всегда равно ‘data’. - chunkSize - число байтов в чанке минус 8 байт (поля ID и chunkSize) кроме того, не учитываются байты выравнивания структуры. Помните, что описание данных хранится в чанке формата. Все вышеперечисленное относится только к несжатому формату. -Массив waveformData содержит собственно выборки, порядок их следования и выравнивание описано в разделе выборки и фреймы. Число фреймов можно вычислить, разделив значение chunkSize на wBlockAlign чанка формата. Чанк данных является необходимой частью любого звукового файла. В одном файле может присутствовать только один чанк данных. В заключение хочется напомнить, что существуют множество других чанков таких как например Cue Chunk(вроде описания данного аудио файла), Playlist chunk, Associated Data List, Label Chunk, Note Chunk, Labeled Text Chunk, Sampler Chunk, Instrument Chunk Format. Для воспроизведения аудио их надо просто игнорировать. Это сообщение отредактировал(а) alexeis1 - 12.4.2006, 08:59 -------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
||||||||||||
|
|||||||||||||
Alexeis |
|
|||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 55 Всего: 459 |
В данной статье автор упустил важный на мой взгляд момент связанный с разбором и поиском чанков в Wav файле. А дело вот в чем. Все чанки имеют следующую общую структуру
Теперь, зная это, можно однозначно читать файл, примерно так: 1) Читаем заголовок wav (единственный чанк не соответствующий указанной структуре, но он всегда первый, поэтому проблем не будет) 2) Читаем 4 байта - идентификатор чанка chunkID и 4 - байта - длина остаточной части чанка (до конца чанка) chunkSize 3) Сравниваем идентификатор чанка chunkID с тем идентификатором того чанка который ищем. Если совпало то читаем чило байт chunkSize, иначе пропускаем это же число байт chunkSize и переходим к шагу №2. Таким образом программа будет всегда устойчиво работать, даже если появятся новые типы чанков или в конце любого чанка добавятся новые поля. ------------------------------------------ далее попробую написать код реализующий этот алгоритм.... -------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
|||
|
||||
Alexeis |
|
|||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 55 Всего: 459 |
В перевод внесены следующие исправления
1) После заголовка 'RIFF' - следует размер оставшегося файла 2)тип данных поля wFormatTag заголовка формата правельно SmallInt (был ShortInt). В некоторых источниках описан как word, однако в нашем случае не критично (если значение не превышает приблизительно 32000) А теперь попробуем правильно прочитать прочитать wav файл как этого требует формат.
Строки Form1.memo1.Lines.Add пошагово выводят информацию в memo и могут быть удалены. Также можно (но очень не желательно) удалить все проверки на ошибки чтения и т.д. Данный код читает PCM не сжатый формат и возвращает дастаточный минимум информации, однако этот метод позволяет правельно прочитать и любой сжатый формат(однако возвращаемой информации для интерпретации таких данных не достаточно) Данные возвращаются ввиде потока TMemoryStream откуда их можно извлекать в соответствии с их форматом. Перед чтением данных из потока необходимо убедится, что отсутствовали ошибки при чтении файла. тему не закрываю далее будет запись хотя по правде говоря с записью проблем быть не должно(ведь можно использовать минимум чанков) Это сообщение отредактировал(а) Alexeis - 20.10.2009, 12:31 -------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
|||
|
||||
Black_Joker |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 212 Регистрация: 9.11.2002 Где: Таганрог Репутация: нет Всего: нет |
Как получить значения амплитуд и частот (тон) звука?
Это сообщение отредактировал(а) Black_Joker - 5.4.2006, 11:58 |
|||
|
||||
Alexeis |
|
|||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 55 Всего: 459 |
Black_Joker, В результате работы функции
Function ReadWave(FileName : AnsiString) : TWaveResult;возвращается результат в виде записи TWaveResult одно из полей которой Data - т.е. звуковые данные(амплитуда выборки) в формате потока TMemoryStream Чтение данных из потока производится в соответствии с их форматом (описанно в статье), при помощи метода readBuffer({переменная куда запишутся данные}, {Размер блока}) Размер блока - завит от того сколько данных читаем, если одну выборку, то размер выборки в байтах, если фрейм целиком, то размер фрейма, если данные например за секунду времени - то размер фрейма * частоту выборки и т.д. Добавлено @ 12:32 Значение частот в wav файле не хранится его можно получить выполнив дискретное преобразование фурье над блоком данных некоторой длины. Алгоритмы дискретного преобразования фурье очень хорошо описаны во многих статьях и учебниках, достаточно запустить поиск, а затем разгребать ![]() -------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
|||
|
||||
Black_Joker |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 212 Регистрация: 9.11.2002 Где: Таганрог Репутация: нет Всего: нет |
Я имею в виду не кол-во точек в сеукунду (частоту дискретизации) а высоту звака (ультрозвук - инфрозвук).
|
|||
|
||||
londinium |
|
|||
Новичок Профиль Группа: Участник Сообщений: 39 Регистрация: 21.1.2006 Репутация: нет Всего: нет |
Здравствуйте!
Насколько я помню ультразвук и инфразвук как раз и определяются частотой сигнала. Если не ошибаюсь, частота ультразвука >20 кГц, а инфразвука < 20 Гц. Londinium |
|||
|
||||
Alexeis |
|
|||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 55 Всего: 459 |
Black_Joker, В любом случае wav файл хранит только амплитуды выборок и ни в коем случае ни тон, ни частоты, ни спектр. Посмотрите РИСУНОК и все станет ясно
-------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
|||
|
||||
Alexeis |
|
|||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 55 Всего: 459 |
Наконец дошли руки написал процедуру записи wav файлов.
Отмечаю следующие особенности: Запись TWaveHeaderChank следует обявлять с директивой packed, в связи с тем, что формат wav подразумевает выравнивание на границу 2 байт, а delphi по умалчанию выравнивает на границу 4 байт. Т.о. размер структуры TWaveHeaderChank без диретивы packed будет занимать 20 байт(структура в примере программ) вместо положенных 18. Следующая программа записывает одноканальный wav файл длительностью 10 сек, 16 бит выборка. Звук будет напоминать свисты коротковолнового радиоприемника.
-------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
|||
|
||||
Alexeis |
|
|||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 55 Всего: 459 |
-------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
|||
|
||||
marykone |
|
||||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2722 Регистрация: 2.5.2006 Где: Краснодар Репутация: нет Всего: 67 |
alexeis1 по поводу функции readwave
в этой части кода пропущена строка
-------------------- получил ответ, пометь вопрос как решенный (правый верхний угол вашей темы). |
||||||||
|
|||||||||
Alexeis |
|
|||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 55 Всего: 459 |
marykone, спасибо за замечание! На самом деле эта ошибка в последней части уже была исправлена. Конечно же wSamplesPerSec куда полезней чем wAvgBytesPerSec. Код первой части поправил.
![]() -------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
|||
|
||||
GOST800 |
|
|||
![]() Новичок Профиль Группа: Участник Сообщений: 22 Регистрация: 25.7.2008 Репутация: нет Всего: нет |
а можно в функции чтения(ReadWave) записывать данные в Data минуя заголовок?
Это сообщение отредактировал(а) GOST800 - 28.7.2008, 21:47 |
|||
|
||||
Alexeis |
|
|||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 55 Всего: 459 |
Можно структуру типа TWaveResult заполнить самому и передать на сохранение, для этого функция ReadWave вообще не нужна.
-------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
|||
|
||||
GOST800 |
|
|||
![]() Новичок Профиль Группа: Участник Сообщений: 22 Регистрация: 25.7.2008 Репутация: нет Всего: нет |
Не, думаю, лучше наверное через ReadWave заполнить TWaveResult, но как откинуть заголовок?
так? Это сообщение отредактировал(а) GOST800 - 29.7.2008, 10:46 |
|||
|
||||
![]() ![]() ![]() |
Правила форума "Delphi: Звук, графика и видео" | |
|
Запрещено: 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делится вскрытыми компонентами
FAQ раздела лежит здесь! Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Girder, Snowy. |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Delphi: Звук, графика и видео | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |