Статьи

Извлечь выдержку из файла WAV

Хотя PHP хорошо известен для создания веб-страниц и приложений, он может сделать больше, чем это. Недавно мне нужно было извлечь фрагмент аудио из файла WAV на лету и позволить пользователю загрузить его через свой браузер. Я пытался найти библиотеку, которая соответствовала бы моим потребностям, но не увенчалась успехом, и мне пришлось самому писать код. Это была хорошая возможность подробно изучить, как создается WAV-файл. В этой статье я дам вам краткий обзор формата файлов WAV и объясню разработанную мной библиотеку Audero Wav Extractor .

Обзор формата WAV

Формат аудиофайла Waveform, также известный как WAVE или WAV, является стандартом формата файлов Microsoft для хранения цифровых аудиоданных. Файл WAV состоит из набора фрагментов разных типов, представляющих различные разделы аудиофайла. Вы можете представить формат в виде HTML-страницы: первые чанки похожи на раздел <head> веб-страницы, поэтому внутри него вы найдете несколько фрагментов информации о самом файле, тогда как чанк, содержащий сами аудиоданные, будет в разделе <body> страницы. В этом случае слово «чанк» относится к разделам данных, содержащимся в файле.

Наиболее важные фрагменты формата — это «RIFF», который содержит количество байтов файла, «Fmt», который содержит важную информацию, такую ​​как частота дискретизации и количество каналов, и «Data», который фактически имеет аудиопоток данные. Каждый кусок должен иметь как минимум два поля: идентификатор и размер. Кроме того, каждый действительный WAV должен иметь как минимум 2 блока: Fmt и Data. Первый обычно находится в начале файла, но после RIFF.

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

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

Еще одна интересная вещь для объяснения — как рассчитывается продолжительность файла WAV. Вся необходимая информация может быть получена из двух обязательных фрагментов, которые упоминались ранее: размер блока данных, частота дискретизации, количество каналов и биты на выборку. Формула для расчета времени файла в секундах следующая:

  time = dataChunkSize / (sampleRate * channelNumber * bitsPerSample / 8) 

Скажем, у нас есть:

  dataChunkSize = 4498170
 sampleRate = 22050
 channelNumber = 16
 bitsPerSample = 1

Применяя эти значения к формуле, имеем:

  время = 4498170 / (22050 * 1 * 16/8) 

И результат составляет 102 секунды (округлено).

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

Что такое Audero Wav Extractor

Audero Wav Extractor — это библиотека PHP, которая позволяет извлекать отрывок из файла WAV. Вы можете сохранить извлеченную выдержку на локальный жесткий диск, загрузить через браузер пользователя или вернуть ее в виде строки для последующей обработки. Единственное специальное требование к библиотеке — это PHP 5.3 или выше, поскольку она использует пространства имен.

Все классы библиотеки находятся в WavExtractor , но вы заметите, что есть дополнительный каталог Loader котором вы можете найти автозагрузчик библиотеки. Точкой входа для разработчиков является класс AuderoWavExtractor который имеет три основных метода проекта:

  • downloadChunk() : скачать отрывок
  • saveChunk() : чтобы сохранить его на жестком диске
  • getChunk() : для извлечения исключения в виде строки

Все эти методы имеют одинаковые первые два параметра: $start и $end которые представляют начальное и конечное время в миллисекундах части для извлечения соответственно. Более того, и downloadChunk() и saveChunk() принимают необязательный третий аргумент для установки имени извлеченного фрагмента. Если имя не указано, метод генерирует его самостоятельно в формате «InputFilename-Start-End.wav».

Внутри каталога WavExtractor есть две подпапки: Utility , содержащая класс Converter который имеет некоторые служебные методы, и Wav . Последний содержит классы Wav , Chunk и ChunkField . Первый, как и следовало ожидать, представляет файл WAV и состоит из одного или нескольких фрагментов (типа блока). Этот класс позволяет вам извлекать заголовки WAV, продолжительность аудио и некоторую другую полезную информацию. Его наиболее подходящим методом является getWavChunk() , который извлекает указанную аудио часть путем чтения байтов из файла.

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

Последний описанный класс — ChunkField . Как я уже говорил, каждый блок имеет свой собственный тип и поля, и каждый из них имеет разную длину (в байтах) и формат. Это очень важная информация, которую нужно знать, потому что вам нужно передать правильные параметры для правильного разбора байтов с помощью PHP-функций pack() и unpack() иначе вы получите ошибку. Чтобы помочь управлять данными, я решил обернуть их в класс, который сохраняет формат, размер и значение каждого поля.

Как использовать Audero Wav Extractor

Вы можете получить «Audero Wav Extractor» через Composer , добавив следующие строки в ваш файл composer.json и выполнив команду установки.

 "require": { "audero/audero-wav-extractor": "2.1.*" } 

Composer загрузит и поместит библиотеку в каталог проекта vendor/audero .

Кроме того, вы можете скачать библиотеку прямо из ее хранилища .

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

 <?php // include the Composer autoloader require_once "vendor/autoload.php"; $inputFile = "sample1.wav"; $outputFile = "excerpt.wav"; $start = 0 * 1000; // from 0 seconds $end = 2 * 1000; // to 2 seconds try { $extractor = new AuderoWavExtractorAuderoWavExtractor($inputFile); $extractor->downloadChunk($start, $end, $outputFile); echo "Chunk extraction completed. "; } catch (Exception $e) { echo "An error has occurred: " . $e->getMessage(); } 

В первых строках я включил автозагрузчик Composer, а затем установил значения, с которыми буду работать. Как видите, я указал исходный файл, путь вывода, включая имя файла и временной интервал, который я хочу извлечь. Затем я создал экземпляр AuderoWavExtractor , предоставив исходный файл в качестве параметра, а затем вызвал метод downloadChunk() . Обратите внимание, что поскольку выходной путь передается по ссылке, вам всегда нужно указывать его в переменной.

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

 <?php // set include path set_include_path(get_include_path() . PATH_SEPARATOR . __DIR__ . "/../src/"); // include the library autoloader require_once "AuderoLoaderAutoLoader.php"; // Set the classes' loader method spl_autoload_register("AuderoLoaderAutoLoader::autoload"); $inputFile = "sample2.wav"; $start = 0 * 1000; // from 0 seconds $end = 2 * 1000; // to 2 seconds try { $extractor = new AuderoWavExtractorAuderoWavExtractor($inputFile); $extractor->saveChunk($start, $end); echo "Chunk extraction completed."; } catch (Exception $e) { echo "An error has occurred: " . $e->getMessage(); } 

Помимо конфигурации загрузчика, фрагмент очень похож на предыдущий. На самом деле я сделал только два изменения: первое — это метод с именем saveChunk() вместо downloadChunk() , а второе — я не установил имя выходного файла (которое будет использовать формат по умолчанию, описанный ранее).

Вывод

В этой статье я показал вам «Audero Wav Extractor» и как вы можете легко извлечь один или несколько фрагментов из данного файла WAV. Я написал библиотеку для рабочего проекта с требованиями для работы с очень узким набором плиток, поэтому, если WAV или его заголовки сильно повреждены, библиотека, вероятно, выйдет из строя, но я написал код, чтобы попытаться по возможности восстановить ошибки , Не стесняйтесь играть с демо-версией и файлами, включенными в репозиторий, так как я выпустил его под лицензией CC BY-NC 3.0 .