ТехноСаратов → Блог

.NET. Программирование ASIOБлогПрограммирование

Multitoolbox — новый сайт от создателей этого поратала

ASIO (Audio Stream Input/Output) – это протокол для драйверов звуковых карт … разработанный фирмой Steinberg, предоставляющий приложениям унифицированный интерфейс к аппаратным ресурсам. А также технология, решающая две существующие на сегодняшний момент проблемы:

1. Минимизация задержек записи и воспроизведения
2. Предоставление универсального интерфейса для мультиканального ввода и вывода звуковой информации

Стандартные драйвера Linux способны обеспечивать практически такие же малые задержки как и ASIO, но для Windows это является настоящим бичом. Так, например, не особенно утешительные заявления Microsoft о том что DirectSound обеспечивает задержки в 20мс не являются истиной. На практике достигаются лишь задержки в 50-80 мс. Достаточно низкоуровневая технология Kernel Streaming обеспечивает задержки не менее 20-21мс (пример тому программа Guitar FXBox). Такая задержка уже практически не заметна для неопытного человека, однако к ней добавляются задержки вносимые фильтрами обработки аудио (для процессоров эффектов), сетевые задержки, задержки вносимые работой других приложений (в не real-time ОС) и т.д.

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

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

Процесс работы приложения с ASIO разделяется на несколько основных этапов:

1. Инициализация, выбор драйвера
2. Создания аудио буферов
3. Запуск драйвера
4. Работаем с драйвером, копируя данные из входных буферов и в выходные
5. Останавливаем драйвер
6. Удаляем аудио буферы
7. Отключаем драйвер от приложения

Следующий рисунок (из описания ASIO SDK 2.2) хорошо иллюстрирует этот процесс.

http://technosaratov.ru/galleries/29/552.jpg

Для .NET существует API драйвера написанный на смеси C++ и C#, хотя для реальной работы мне пришлось над ним немного поработать. Скачать исходники и дёмку можно тут (для скачки придется зарегистрироваться, но ресурс отличный, по тому не влом).

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

Получение списка драйверов:

Список драйверов постоянно находится в статическом компоненте AsioDriver.InstalledDrivers. Его можно например поместить в ComboBox и предоставить возможность пользователю выбрать нужный из существующих в системе.

Для выбора драйвера методу AsioDriver.SelectDriver нужно передать один из объектов списка AsioDriver.InstalledDrivers, примерно так:

Для полной инициализации драйвера нужно вызвать следующую последовательность методов:

Метод воспроизведения:

Здесь мы просто копируем имеющиеся у нас данные в выходной аудио буфер. Метод достаточно гибкий: он воспроизводит данные только в один канал, по этому если у нас стерео система или квадро, то мы можем им воспроизводить в каждый канал свои данные, или по своему обработанные данные. Переменная channel содержит номер канала и может выбираться в диапазоне существующих выходных каналов. Например, в одном из режимов моей звуковой карты (Creative Live 5.1) есть режим 8+8 каналов (8 входных и 8 выходных), следовательно я могу выбирать номера выходных каналов из диапазона 0..7. Если на физических выводах к ним подключены устройства воспроизведения, то я буду слышать звук. Так для воспроизведения на гарнитуру я могу написать:

Соответственно для записи звука со входа используем следующий метод:

Здесь все аналогично, только копирование данных происходит в обратном направлении.

Вызывать эти методы следует из обработчика сообщения драйвера BufferUpdate, который мы зарегистрировали при инициализации драйвера. Ниже определим обработчик который просто копирует вход на выход:

Как правило, выходные каналы существуют, по этому, для определения размера аудио буферов драйвера, когда это требуется, можно использовать строчку driver.OutputChannels[0].BufferSize. Все буфера (и входные и выходные) имеют одинаковые размеры.

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

Пара исправлений

Библиотека работает только в 32-х битном режиме звука. Имея старенькую 16-ти битную звуковушку мне пришлось немного исправить драйвер. А именно в файлах Channel.h и Channel.cpp заменить

На

И также исправить все работающие с этими массивами методы.

Второе исправление касалось невозможности прямо указывать размер буффера. По тому пришлось перегрузить метод void CreateBuffers(bool useMaxBufferSize) так:


Единственное ограничение при использовании этого перегруженного метода – в качестве размеров буферов нужно выберать только поддерживаемые звуковыми картами значения! Разные звуковые карты могут поддерживать разные размеры, так Live 5.1 поддерживает размеры буферов кратные степени двойки, длительность аудио данных в которых выражется дробным количеством миллисекунд, карты E-MU 0404 только буферы длительностью в целые миллисекунды.

На этом пока все. Хотя есть еще одна проблема с созданием релизной версии библиотеки, но сейчас я ее описывать не стану. А когда появится файлообменник, приаттачу (если вспомню 🙂 ) файл с исходниками релизной библиотечки.