← Октябрь 2003 → | ||||||
1
|
3
|
4
|
5
|
|||
---|---|---|---|---|---|---|
6
|
7
|
8
|
9
|
10
|
11
|
12
|
13
|
14
|
15
|
16
|
17
|
18
|
19
|
20
|
21
|
22
|
23
|
24
|
25
|
26
|
27
|
28
|
29
|
31
|
За последние 60 дней 2 выпусков (1-2 раза в 2 месяца)
Сайт рассылки:
http://rsdn.ru
Открыта:
14-06-2000
Статистика
-5 за неделю
Программирование на Visual С++ - No.99 Обработка звуковых файлов в Windows
Информационный Канал Subscribe.Ru |
|
РАССЫЛКА САЙТА
RSDN.RU |
Здравствуйте! CТАТЬЯ Обработка звуковых файлов в Windows Автор: Евгений Музыченко
|
Смещение в файле | Содержимое |
---|---|
0 | Заголовок раздела RIFF (два двойных слова) |
8 | Тип формы (одно двойное слово) |
12 | Область подразделов (переменная длина) |
Поле размера раздела RIFF в его заголовке содержит суммарный размер всех подразделов плюс размер двойного слова, содержащего тип формы (четыре байта). В правильно оформленном RIFF-файле поле размера раздела RIFF равно общему размеру файла минус размер RIFF-заголовка (восемь байтов).
В этой статье описывается только структура файлов типа WAVE, код типа формы для которого также представляется строкой "WAVE".
Ключи мультимедийных файлов
Как и в случае обычных файлов Windows, для доступа к мультимедийному файлу используется его ключ - числовое значение, возвращаемое функцией mmioOpen. Фактически, ключ файла представляет собой указатель системного описателя файла, расположенного в памяти подсистемы MMIO.
Ключи обычных и мультимедийных файлов несовместимы между собой, однако уже открытый обычный файл можно повторно открыть в подсистеме MMIO, передав его ключ (типа HANDLE) функции mmioOpen.
Информационная структура файла
Для каждого открытого файла подсистема MMIO поддерживает информационную структуру, описывающую режимы работы с файлом и его параметры. Базовая информационная структура находится внутри самой подсистемы MMIO, приложение может поддерживать собственную локальную копию типа MMIOINFO в своей собственной области памяти. Некоторые функции MMIO требуют от приложения указания локальной структуры MMIOINFO, и управляют полями структур таким образом, чтобы отразить операции, выполненные как приложением, так и самой подсистемой MMIO. Приложение также может непосредственно запросить копию системной структуры функцией mmioGetInfo, и модифицировать системную структуру функцией mmioSetInfo.
Буферизация файлового обмена
Обмен информацией с файлом может быть непосредственным или буферизованным.
Непосредственный обмен подразумевает прямое чтение информации с диска и запись ее обратно на диск, и эффективен в том случае, когда обмен с файлом идет большими (несколько килобайт или больше) блоками данных, размеры которых кратны размеру сектора диска (обычно 512 байтов), и сами блоки начинаются также на границе сектора. При обмене мелкими (несколько десятков или сотен байтов), или некратными сектору блоками резко возрастают накладные расходы.
При буферизованном обмене между приложением и файлом находится так называемый буфер файла. При чтении из файла вначале неявно считывается полный буфер, а последующие функции чтения выбирают нужные порции данных из буфера, не обращаясь при этом к диску. При записи все работает наоборот: функции записи вначале заполняют буфер, а затем полностью записанный буфер неявно переносится в файл одной операцией записи.
Строго говоря, в MMIO даже непосредственный обмен с файлом включает простую скрытую буферизацию в самой подсистеме, так как минимальной единицей обмена данными с диском является сектор.
Скрытая и явная буферизация
Буферизация файлов в MMIO может быть скрытой и явной.
Скрытая буферизация работает так же, как и в базовом файловом обмене: файловая подсистема создает буфер, через который проходят все операции чтения/записи, выполняемые приложением. Работа буфера в этом случае приложению не видна, однако возможны накладные расходы при пересылке данных между буферами приложения и файлов.
При явной буферизации приложение имеет непосредственный доступ к буферу для чтения и записи. В этом случае оно самостоятельно заносит данные в буфер при записи и извлекает их при чтении. Для уведомления файловой подсистемы об изменении состояния буфера служит функция продвижения по файлу, которая корректирует рабочие указатели буфера и при необходимости выполняет непосредственно обмен буфера с файлом.
Как при скрытой, так и при явной буферизации приложение может полностью управлять и размером буфера, и местом его размещения в памяти.
Текущая позиция в буфере
При работе с буферизованным файлом используется понятие указателя текущей позиции буфера. В начале работы указатель устанавливается на начало буфера, в процессе считывания или записи данных он движется в сторону конца буфера. При достижении конца буфера или специального ограничителя содержимое буфера записывается в файл либо обновляется из него, и указатель текущей позиции снова возвращается в начало буфера.
Вместе с указателем текущей позицией файловая подсистема использует два специальных ограничителя буфера - ограничитель чтения и ограничитель записи, которые являются "барьерами" для указателя текущей позиции. Фактически, оба ограничителя представляют собой указатели, ссылающиеся на байты сразу за концом области буфера, доступной для чтения и записи соответственно. Таким образом, последним доступным для чтения или записи является адрес, на единицу меньший значения соответствующего ограничителя. Размер доступной для чтения или записи области определяется разностью соответствующего ограничителя и указателя текущей позиции.
Текущая позиция буфера не имеет никакого отношения к текущей позиции самого файла. Позиция в файле изменяется только при операциях непосредственного обращения к файлу, позиция буфера - при работе с буфером. Текущие позиции буфера и ограничителей находятся в информационной структуре файла.
Файлы в оперативной памяти
Вместо внешнего устройства файл может находиться в оперативной памяти. Механизм виртуальной памяти Windows позволяет таким файлам иметь практически любой размер, ограниченный лишь объемом доступного на диске пространства для файла подкачки (swapfile).
Размещение файла в памяти позволяет максимально быстро работать с данными, используя обычный файловый интерфейс, что в ряде случаев может быть удобнее, чем использование стандартных средств управления памятью Windows.
Файл, размещаемый в памяти, на самом деле состоит из одного лишь буфера, размер которого увеличивается по мере записи в файл. Стандартная процедура обмена для файлов в памяти управляет указателем текущей позиции, ограничителями чтения/записи и размером буфера, что с точки зрения приложения неотличимо от работы с реальным дисковым файлом.
Процедуры обмена данными
Файловые функции MMIO на самом деле являются промежуточными. Весь фактический обмен с файлом выполняют так называемые процедуры обмена (I/O Procedures). Стандартные процедуры обмена обслуживают файлы на дисковых устройствах и в оперативной памяти; пользовательские процедуры могут обслуживать файлы на любом носителе, или даже полностью виртуальные файлы, не имеющие физического представления.
Обращения приложения к файловым функциям MMIO транслируются подсистемой в сообщения к соответствующей процедуре обмена, которая выполняет запрос и возвращает соответствующий код результата.
Можно сказать, что процедура обмена, как оконечный интерфейс, определяет среду хранения (storage system) файла.
Установленные и явные процедуры обмена
Процедуры обмена могут быть установленными и явными. Установленная процедура вносится во внутренний список подсистемы MMIO и снабжается собственным уникальным символьным кодом, по которому она может быть найдена и подключена к открываемому файлу. Явная процедура задается непосредственно своим указателем при открывании файла, и не имеет собственного кода.
В подсистеме MMIO имеются две стандартные процедуры обмена: DOS - интерфейс с дисковыми устройствами, и MEM - интерфейс с оперативной памятью для файлов в памяти. Их коды определяются константами FOURCC_DOS и FOURCC_MEM.
Глобальные и локальные процедуры обмена
Установленные процедуры обмена делятся на глобальные и локальные. Глобальные процедуры доступны всем процессам системы, локальные - только установившему их процессу. Поиск процедуры по коду начинается со списка локальных процедур, которые в этом случае имеют приоритет.
Разделение процедур обмена между процессами возможно только в Win16; в Win32 это дает непредсказуемые результаты.
Структура звуковых файлов RIFF/WAVE
Файлы типа RIFF/WAVE служат для хранения оцифрованных звуковых потоков в различных звуковых форматах - PCM, ADPCM, a-Law, GSM, Audio MPEG и т.п. Стандартное расширение для файлов этого типа - WAV.
Минимальный состав WAVE-формы включает два подраздела: формата и данных. Раздел формата имеет код "fmt", и содержит описатель формата звуковых данных в виде расширенной структуры WAVEFORMATEX. Раздел данных состоит либо из одного подраздела "data", содержащего единый поток звуковых данных в цифровом виде, либо из подраздела-списка "wavl", содержащего последовательность из подразделов "data" и "slnt" (silent - тихий). Каждый подраздел "data" задает отдельный фрагмент звучания, подраздел "slnt" - фрагмент тишины (паузу) заданной длительности.
Для форматов, отличных от PCM, и в случае использования списка "wavl" после раздела "fmt" вставляется дополнительный раздел "fact". Первое двойное слово (DWORD) области данных раздела "fact" содержит общее количество звуковых отсчетов (samples) в файле. При помощи этого параметра можно определить время воспроизведения файла, поделив количество отсчетов на значение поля nSamplesPerSec в описателе формата, или вычислить объем, который поток займет после восстановления в PCM - умножив количество отсчетов на значение поля nBlockAlign в описателе выбранного для восстановления формата PCM.
В настоящее время область данных раздела "fact" включает только описанное поле, однако в будущем она может быть расширена добавлением дополнительных полей. Это необходимо иметь в виду, ориентируясь на размер области данных раздела, указанный в его заголовке. По размеру области данных можно узнать о наличии в разделе полей расширения.
В качестве необязательных элементов звукового файла перед разделом данных могут присутствовать разделы "cue" (список "флажков", или "закладок" внутри звукового потока - cue points), "plst" (порядок воспроизведения фрагментов - playlist), "adtl" (раздел типа "LIST", разная дополнительная информация о файле - associated data list) и т.п. Полное и подробное описание возможной структуры звукового файла выходит за рамки данной статьи.
Программирование MMIO
Для программирования ACM необходим любой стандартный SDK (Win16 или Win32), содержащий файлы заголовка MMSYSTEM.H и библиотеки WINMM.LIB.
Типовые схемы применения средств MMIO
Открывание/закрывание файла
При открывании файла функцией mmioOpen указываются необходимые виды доступа, режимы совместного использования и буферизации. Функция открывания дискового файла в MMIO в конечном счете раскрывается в базовые функции открывания файла Windows, поэтому подробности о режимах открывания и совместного использования файлов можно получить из описания функции CreateFile.
Возможно использование в подсистеме MMIO уже открытого базового файла Windows; для этого предусмотрен частный случай использования функции mmioOpen.
При открывании файла, либо впоследствии, для него может быть установлен режим буферизации функцией mmioSetBuffer. В зависимости от набора функций, используемых для чтения/записи, буферизация может быть скрытой или явной.
После завершения работы с файлом он должен быть закрыт функцией mmioClose. Если файл был принят для обработки в MMIO посредством передачи ключа открытого базового файла Windows - базовый файл также будет закрыт, если в функции mmioClose не указан соответствующий флаг.
Чтение/запись без использования явного буфера
В этом режиме работа с файлом происходит точно так же, как в базовой файловой подсистеме Windows или встроенных средствах поддержки файлов языка C. Сразу после открывания файла для чтения/записи доступны функции mmioRead/mmioWrite, для смены позиции - функции mmioSeek. Для того, чтобы гарантированно записать в файл содержимое внутренних буферов, применяется функция mmioFlush.
Чтение/запись с явной буферизацией
Обработка файла с явной буферизацией может начинаться в любое время - сразу после открывания, либо после частичной обработки в обычных режимах. Перед началом обработки с явной буферизацией приложение должно любым из способов, предусмотренных в MMIO, задать буфер для файла. Затем приложение запрашивает копию информационной структуры файла функцией mmioGetInfo, после чего приступает к работе с буфером, используя указатели позиций буфера в полях pchNext, pchEndRead, pchEndWrite.
Если данные в буфере изменяются при записи или модификации буфера - приложение должно установить флаг DIRTY в слове флагов информационной структуры. При достижении конца буфера вызывается функция mmioAdvance, продвигающая буфер по файлу и соответствующим образом изменяющая указатели позиций.
Сеанс обработки файла в буферизованном режиме завершается вызовом функции mmioSetInfo, окончательно фиксирующей текущее состояние буфера в файле. После этого обработка файла может быть продолжена в обычном режиме.
Функция mmioSetInfo вызывается также в том случае, когда необходима фактическая запись на диск еще не заполненного буфера; при этом должен быть установлен флаг DIRTY.
Перед использованием функций работы с разделами RIFF файл должен находиться в обычном режиме. Например, существующий файл открывается в обычном режиме, затем функциями mmioDescend в нем находятся нужные разделы, после чего файл переводится в режим явной буферизации и считывается в этом режиме.
Формирование RIFF-файла
В созданном или открытом для перезаписи файле при помощи функции mmioCreateChunk создаются необходимые разделы и подразделы, заполняются данными в любом из режимов буферизации, после чего разделы закрываются функцией mmioAscend.
Чтение RIFF-файла
Для открытого файла вызывается функция mmioDescend, выполняющая поиск нужного раздела или подраздела, затем данные найденных разделов считываются и обрабатываются в любом из режимов буферизации.
Использование собственных процедур обмена
Если приложение поддерживает собственные устройства и методы хранения данных, и хочет использовать для них функции MMIO - оно может установить собственные процедуры обмена для этих файлов функцией mmioInstallIOProc, после чего работать с файлами посредством любых функций MMIO. Например, таким образом удобно работать с RIFF-файлами на нестандартных носителях информации.
Структуры, используемые в MMIO
MMCKINFO - описатель раздела файла
Описывает раздел файла типа RIFF. Первые три поля структуры представляют собой заголовок раздела в том же виде, в котором он присутствует в файле; поле fccType присутствует только в заголовках главных разделов.
FOURCC ckid; DWORD cksize; FOURCC fccType; DWORD dwDataOffset; DWORD dwFlags;
- ckid - код (идентификатор) раздела.
- cksize - размер области данных раздела в байтах. Поле отражает точный размер области данных; в него не входит размер заголовка и возможный дополнительный байт, автоматически дописываемый к области данных нечетного размера.
- fccType - тип главного раздела, если в поле ckid указан код "RIFF" и "LIST".
- dwDataOffset - смещение области данных раздела относительно начала файла. Значение этого поля удобно использовать в функции mmioSeek для позиционирования на начало области данных.
- dwFlags - флаги состояния раздела. На данный момент определен единственный флаг MMIO_DIRTY, означающий, что заголовок раздела в файле (поле cksize) должно быть обновлено - например, после изменения размера области данных раздела. Этот флаг устанавливается функцией mmioCreateChunk и анализируется функцией mmioAscend, которая корректирует поле длины в заголовке в соответствии с реальным размером области данных.
MMIOINFO - информационная структура файла
Описывает состояние открытого файла, его буфера и процедуры обмена данными.
DWORD dwFlags; FOURCC fccIOProc; LPMMIOPROC pIOProc; UINT wErrorRet; HTASK hTask; LONG cchBuffer; HPSTR pchBuffer; HPSTR pchNext; HPSTR pchEndRead; HPSTR pchEndWrite; LONG lBufOffset; LONG lDiskOffset; DWORD adwInfo [4]; DWORD dwReserved1; DWORD dwReserved2; HMMIO hmmio;
- dwFlags - режимы открывания/опроса и флаги состояния файла, копируемые из параметра Mode функции mmioOpen. Дополнительно определены следующие константы, имеющие префикс MMIO_:
DIRTY | Флаг, показывающий, что содержимое буфера было изменено и требует записи на диск. Устанавливается либо MMIO при скрытой буферизации, либо приложением - при явной буферизации. Сбрасывается MMIO после фактической записи буфера на диск. |
---|---|
RWMODE | Битовая маска, включающая все флаги вида доступа к файлу. |
SHAREMODE | Битовая маска, включающая все флаги режимов совместного доступа к файлу. |
- fccIOProc - код установленной процедуры обмена. Если функция не является установленной - поле имеет нулевое значение. Для файлов универсальной структуры стандартная функция обмена имеет код "DOS".
- pIOProc - указатель процедуры обмена. Если приложение не использует процедуру обмена, в этом поле находится указатель стандартной процедуры обмена файловой подсистемы.
- wErrorRet - код ошибки, возвращаемый при неудачном завершении функции mmioOpen.
- hTask - ключ задачи (task), созданной для процедуры обмена.
- cchBuffer - размер буфера файла. Для файлов без буфера поле имеет нулевое значение.
- pchBuffer - указатель буфера файла. Для файлов без буфера поле имеет нулевое значение.
- pchNext - указатель текущей позиции в буфере.
- pchEndRead - ограничитель чтения в буфере.
- pchEndWrite - ограничитель записи в буфере.
- lBufOffset - зарезервированное поле для служебного использования.
- lDiskOffset - текущее смещение внутри файла. Поле управляется процедурами обмена.
- adwInfo - дополнительная информация, используемая процедурами обмена. Используется также для передачи дополнительных данных при открывании файла.
- dwReserved1, dwReserved2 - зарезервированные поля.
- hmmio - ключ открытого файла.
Функции MMIO
Классы функций
Средства мультимедийной файловой подсистемы включают три основных класса функций:
- базовые - открывание, закрывание, чтение и запись файлов. Этот класс практически аналогичен стандартным средствам работы с файлами языка C.
- управления буферизацией - создание или установка промежуточного буфера и манипуляции с ним, а также - с текущей позицией буфера.
- работы с форматом RIFF - операции с файлами универсального формата RIFF.
Все функции интерфейса имеют имена с префиксом mmio. В заголовке описания каждой функции этот префикс опущен; полное имя каждой функции приведено в ее прототипе.
Большая часть функций получает параметром ключ открытого файла. Такие функции имеют в прототипе параметр File типа HMMIO. В целях экономии места этот параметр не описывается в каждом из описаний функций.
Перечень базовых функций:
mmioStringToFOURCC | Преобразование строки ASCIZ в код FOURCC |
---|---|
mmioOpen | Открывание или опрос файла |
mmioClose | Закрывание файла |
mmioRename | Переименование файла |
mmioRead | Чтение из файла |
mmioWrite | Запись в файл |
mmioSeek | Позиционирование по файлу |
Перечень функций управления буферизацией:
mmioGetInfo | Запрос информационной структуры файла |
---|---|
mmioSetInfo | Модификация информационной структуры файла |
mmioSetBuffer | Установка буфера для файла |
mmioAdvance | Продвижение по файлу |
mmioFlush | Принудительная запись буфера в файл |
Перечень функций работы с форматом RIFF:
mmioCreateChunk | Создание раздела |
---|---|
mmioAscend | Выход из раздела |
mmioDescend | Вход в раздел |
Перечень остальных функций интерфейса:
mmioSendMessage | Посылка произвольного сообщения процедуре обмена |
---|---|
mmioInstallIOProc | Установка процедуры обмена |
IOProc | Прототип процедуры обмена |
Возвращаемые значения
Для функций, возвращающих значения типа MMRESULT, а также для ряд других, определены константы кодов завершения с префиксами MMSYSERR_ и MMIOERR_. Константы первой группы были описаны в статье "Низкоуровневое программирование звука в Windows"), константы второй группы перечислены в таблице:
FILENOTFOUND | Файл не найден |
---|---|
OUTOFMEMORY | Недостаточно памяти |
CANNOTOPEN | Невозможно открыть файл |
CANNOTCLOSE | Невозможно закрыть файл |
CANNOTREAD | Невозможно прочитать из файла |
CANNOTWRITE | Невозможно записать в файл |
CANNOTSEEK | Невозможно позиционировать файл |
CANNOTEXPAND | Невозможно расширить файл |
CHUNKNOTFOUND | Раздел не найден |
UNBUFFERED | Файл открыт для непосредственного доступа |
PATHNOTFOUND | Недопустимый путь (устройство и/или каталог) |
ACCESSDENIED | Доступ к файлу запрещен |
SHARINGVIOLATION | Нарушение условий совместного доступа |
NETWORKERROR | Ошибка сетевой подсистемы |
TOOMANYOPENFILES | Нет свободных описателей ключей для нового файла |
INVALIDFILE | Общая ошибка, неудача по неизвестной причине |
Базовые функции
MAKEFOURCC и mmioFOURCC - формирование кода FOURCC
Эти два макроса формируют 32-разрядное значение типа FOURCC (DWORD) из четырех заданных символов (значений типа char):
MAKEFOURCC (ch0, ch1, ch2, ch3) mmioFOURCC (ch0, ch1, ch2, ch3)
Оба макроса полностью идентичны - mmioFOURCC определяется через MAKEFOURCC. Результатом вызова любого из макросов является "склейка" четырех символьных значений в одно 32-разрядное:
mmioFOURCC ('c', 'u', 'e', ' ') преобразуется в 0x20657563
StringToFOURCC - преобразование строки в код FOURCC
Преобразует заданную строку ASCIZ в код FOURCC.
FOURCC mmioStringToFOURCC ( LPCSTR Str, UINT Flags );
- Str - исходная строка ASCIZ, содержащая сочетание символов кода.
- Flags - флаги режимов преобразования. Определен единственный флаг MMIO_TOUPPER, при наличии которого преобразуемые символы приводятся к верхнему регистру.
Функция формирует из заданной строки соответствующий четырехсимвольный код, при необходимости дополняя строку пробелами либо отбрасывая лишние символы. Например, результатом преобразования строки "fmt" будет числовое значение 0x20746D66.
Open - открывание файла
Открывает существующий или вновь создаваемый файл, либо выполняет один из видов опроса файла без его фактического открывания.
HMMIO mmioOpen ( LPSTR FileName, MMIOINFO *Info, DWORD Mode );
- FileName - строка имени файла. Вопреки тому, что стандартное описание ограничивает эту строку 128 символами, фактически воспринимается 238 символов пути. Возможно три варианта установки этого поля:
- Обыкновенное имя, не содержащее знака "+". В этом случае открывается обычный двоичный файл со стандартной процедурой обмена, формат которого будет определяться приложением.
- Структурное имя, в формате "имя.тип+элем". В этом случае открываемому файлу автоматически назначается процедура обмена, выбираемая по указанному типу, а внутри файла открывается указанный элемент данных.
- Нулевое значение - в случае открывания файла в памяти, либо стандартного файла Windows по его ключу типа HANDLE.
- Info - указатель локальной информационной структуры файла, типа MMIOINFO. Задается в тех случаях, когда открывается файл в памяти, файл с не установленной процедурой обмена, либо приложение самостоятельно задает параметры буферизации файла. В этих случаях все поля структуры, кроме явно заданных, должны быть нулевыми. В остальных случаях параметр должен иметь нулевое значение.
- Mode - флаги режимов открывания/опроса и флаги, уточняющие способ открывания файла. Имена констант для значений имеют префикс MMIO_.
Флаги режимов открывания:
CREATE | Запрашивает создание нового файла, либо усечение существующеего файла до нулевого размера. |
---|---|
DELETE | Запрашивает удаление существующего файла. При успешном завершении возвращается TRUE, в противном случае - FALSE. Этот режим перекрывает все остальные режимы открывания файла. |
ALLOCBUF | Запрашивает автоматическое выделение буфера для файла. Если указатель информационной структуры не задан, либо ее поле cchBuffer имеет нулевое значение, выделяется буфер размером MMIO_DEFAULTBUFFER (8 кб), в противном случае поле cchBuffer задает размер выделяемого буфера. |
Коды режимов опроса, без фактического открывания файла:
PARSE | Запрашивает возврат полного имени (пути) для заданного имени файла. Существование самого файла не проверяется. При успешном завершении функция возвращает значение TRUE; в противном случае возвращается значение FALSE. |
---|---|
EXIST | Аналогично PARSE, но проверяется существование заданного файла. |
GETTEMP | Запрашивает формирование уникального имени для временного файла. Временное имя дописывается к исходной строке имени. Функция возвращает нулевое значение при успешном завершении, и значение MMIOERR_FILENOTFOUND при неудаче. Этот флаг перекрывает все остальные флаги режима опроса. |
ПРИМЕЧАНИЕ
При использовании этих трех режимов сформированное имя файла возвращается в область памяти по указателю FileName. С константами этой группы не допускается указание констант из других групп.
Флаги вида доступа (access mode):
READ | Файл открывается только для чтения. |
---|---|
WRITE | Файл открывается только для записи. |
READWRITE | Файл открывается для чтения и записи одновременно. |
Флаги режимов разделяемого доступа (sharing mode):
COMPAT | Совместимый режим (compatibility mode), не накладывающий ограничений на одновременное открывание файла другими процессами в таком же совместимом режиме. |
---|---|
DENYNONE | Другим процессам разрешаются все операции с этим файлом. |
DENYREAD | Другим процессам запрещаются операции чтения с этим файлом. |
DENYWRITE | Другим процессам запрещаются операции записи с этим файлом. |
EXCLUSIVE | Запрещается любое повторное открывание этого файла, даже в текущем процессе. |
ПРИМЕЧАНИЕ
Режимы разделяемого доступа работают "в обе стороны" - не позволяя другим процессам открывать файл в запрещенных режимах после успешного завершения функции, и не позволяя функции завершиться успешно, если файл уже открыт другим процессом в одном из запрещенных режимов. Одновременное открывание файла в совместимом и в одном из разделяемых режимов также недопустимо.
В случае задания локальной информационной структуры файла она должна быть заполнена в соответствии со следующими правилами:
- Для подключения нужной процедуры обмена необходимо установить либо код установленной процедуры в поле fccIOProc, либо указатель явной процедуры в поле pIOProc.
- Для подключения установленной процедуры обмена, определяемой символьным кодом, необходимо установить оба вышеописанных поля в нулевые значения. При этом строка имени файла должна иметь вид "имя.тип+элем", где тип - расширение файла (1..4 символа), определяющее одну из установленных процедур, а элем - элемент внутри структуры файла, который необходимо открыть.
- Для открывания файлов в памяти в поле fccIOProc должен быть задан код стандартной процедуры обмена для оперативной памяти - FOURCC_MEM. Поле cchBuffer в этом случае задает начальный размер буфера файла, а поле adwInfo [0] - величину приращения размера буфера при его расширении. По умолчанию содержимое буфера файла доступно для операций чтения (ограничитель pchEndRead в информационной структуре находится за концом буфера); чтобы файл открывался "пустым" (ограничитель pchEndRead установлен на начало буфера) - необходимо указать флаг CREATE в параметре Mode.
- Чтобы буфер для файла в памяти создавался автоматически, поле pchBuffer должно иметь нулевое значение. Если значение поля отлично от нуля - оно трактуется, как адрес буфера, предоставленного приложением. В этом случае, если задана величина приращения в поле adwInfo [0], MMIO использует для расширения функцию GlobalReAlloc. Эта функция может работать только с областями памяти, адреса которых получены посредством функций GlobalAlloc / GlobalLock. В Win32 нет различий между глобальными и локальными функциями динамической памяти, поэтому память для буфера может выделяться функциями LocalAlloc / LocalLock. Если буфер получен другим способом - величина приращения должна быть нулевой, и расширение буфера должно выполняться самим приложением.
- Для открывания посредством MMIO уже открытого стандартного файла Windows, ключ которого имеет тип HANDLE, значение ключа заносится в поле adwInfo [0]. В этом случае поле fccIOProc должно иметь значение FOURCC_DOS, а поле pchBuffer - нуль. MMIO будет работать со стандартным файлом посредством функций ReadFile, WriteFile и т.п.
Если было запрошено открывание файла, функция при успешном завершении возвращает ключ открытого файла, который впоследствии используется в большинстве остальных функций работы с файлами. При неудачном завершении возвращается нулевое значение, а код ошибки заносится в поле wErrorRet локальной информационной структуры, если она указана.
Если был запрошен один из других режимов - возвращается соответствующее значение, приведенное к типу HMMIO.
Локальная информационная структура файла, передаваемая параметром Info, служит только для передачи параметров в функцию, которая устанавливает значения внутренней информационной структуры MMIO. Никакие поля локальной структуры, включая указатель текущей позиции и ограничители чтения/записи, не заполняются функцией. Для получения копии текущего значения структуры необходимо использовать функцию mmioGetInfo.
Close - закрывание файла
Закрывает файл, открытый функцией mmioOpen, либо завершает работу со стандартным файлом Windows, повторно открытым функцией mmioOpen.
MMRESULT mmioClose ( HMMIO File, UINT Flags );
- Flags - флаги режимов закрывания файла. Определен единственный флаг MMIO_FHOPEN, который должен быть указан при завершении работы с повторно открытым стандартным файлом Windows. В этом случае стандартный файл остается доступен по своему "родному" ключу типа HANDLE, в противном случае стандартный файл закрывается.
Если буфер файла помечен, как требующий дозаписи на диск, функция неявно вызывает mmioFlush. Если в процессе работы mmioFlush возникает ошибка (например, переполнение диска) - код ошибки будет возвращен функцией mmioClose.
После успешного завершения mmioClose ключ File становится недоступным и обращение к нему приведет к ошибке.
Rename - переименование файла
Переименует заданный файл.
MMRESULT mmioRename ( LPCSTR Name, LPCSTR NewName, const MMIOINFO *Info, DWORD Reserved );
- Name - строка имени исходного файла.
- NewName - строка нового имени файла.
- Info - указатель локальной информационной структуры файла. Роль этой структуры в операции переименования неясна, документация требует либо нулевого значения этого параметра, либо нулевых значений "неиспользуемых полей". Какие именно поля используются, и каким образом - в документации не сказано, поэтому лучше всего оставлять этот параметр нулевым.
- Reserved - зарезервированный параметр, должен иметь нулевое значение.
Функция не накладывает ограничений на взаимное расположение исходного и нового файлов. Если их каталоги различны - выполняется перенос файла из каталога в каталог, если различны устройства - выполняется копирование файла с последующим удалением исходного.
Read - чтение из файла
Считывает из файла указанное количество байтов.
LONG mmioRead ( HMMIO File, char *Buffer, LONG Size );
- Buffer - указатель области памяти, в которую считываются данные из файла.
- Size - размер считываемой порции данных в байтах.
Функция возвращает размер реально считанной и занесенной в буфер порции данных. Если данных в файле больше нет (достигнут конец файла) - возвращается нулевое значение. При ошибке чтения возвращается -1.
Write - запись в файл
Записывает в файл указанное количество байтов.
LONG mmioWrite ( HMMIO File, const char *Data, LONG Size );
- Data - указатель области памяти, содержащей записываемую порцию данных.
- Size - размер порции данных в байтах.
Возвращается количество реально записанных в файл байтов, либо -1 в случае ошибки.
Успешное завершение функции означает, что данные успешно перенесены в скрытый внутренний буфер файла, поддерживаемый MMIO. Непосредственно в файл записываются только полные буферы, остаток данных остается в буфере до вызова функций mmioFlush или mmioClose.
Flush - принудительная запись буфера на диск
Служит для принудительной записи скрытого системного буфера файла на диск.
MMRESULT mmioFlush ( HMMIO File, UINT Flags );
- Flags - управляющие флаги операции. Флаг MMIO_EMPTYBUF требует аннулирования содержимого буфера (пометки буфера, как пустого) после записи. Это означает, что последующая операция чтения того же участка файла, данные которого содержались в буфере на момент вызова mmioFlush, вызовет повторное считывание данных из файла в буфер.
Функция используется, когда приложение хочет быть уверенным, что все данные, записанные ранее функцией mmioWrite, на самом деле записаны в файл, а не остались в скрытом промежуточным буфере. При успешном завершении mmioFlush содержимое буфера записывается в файл.
Строго говоря, даже в этом случае нет гарантии, что данные уже находятся на диске - в Windows работает система кэширования с отложенной записью, задерживающая фактическую запись данных на диски на несколько секунд, либо до закрывания файла.
Seek - позиционирование в файле
Перемещает текущую позицию файла в заданное место.
LONG mmioSeek ( HMMIO File, LONG Offset, int Origin );
Offset - смещение в байтах относительно заданной точки. Может быть положительным, нулевым, либо отрицательным.
Origin - точка, относительно которой выполняется позиционирование. Возможно три варианта задания исходной точки:
- SEEK_SET - начало файла
- SEEK_CUR - текущая позиция в файле
- SEEK_END - конец файла (точка за последним записанным байтом в файле)
Функция возвращает новую текущую позицию относительно начала файла, либо -1 в случае ошибки. При установке текущей позиции за концом файла функция может выполниться успешно, однако последующие операции чтения/записи могут привести к ошибке.
Функция часто используется для получения длины файла - путем позиционирования на 0 байтов относительно конца файла; возвращаемое значение при этом представляет длину файла в байтах.
Функции управления буферизацией
GetInfo - запрос копии информационной структуры файла
Заполняет указанную область данными системной информационной структуры файла, которая поддерживается для каждого открытого файла внутри подсистемы MMIO.
MMRESULT mmioGetInfo ( HMMIO File, MMIOINFO *Info, UINT Reserved );
- Info - указатель области памяти для локальной копии информационной структуры, типа MMIOINFO.
- Reserved - зарезервированный параметр, должен иметь нулевое значение.
Функция создает в указанной области памяти локальную копию текущего состояния информационной структуры файла, и обязательно должна быть вызвана перед началом работы с файлом в режиме явной буферизации. После завершения работы в этом режиме системная информационная структура MMIO должна быть обновлена текущими значениями из локальной копии при помощи функции mmioSetInfo.
SetInfo - установка системной информационной структуры файла
Передает данные из локальной копии информационной структуры файла, поддерживаемой приложением, в системную структуру MMIO.
MMRESULT mmioSetInfo ( HMMIO File, const MMIOINFO *Info, UINT Reserved );
- Info - указатель локальной копии информационной структуры, типа MMIOINFO.
- Reserved - зарезервированный параметр, должен иметь нулевое значение.
Функция используется для завершения обработки файла в режиме явной буферизации. Состояние буфера, в котором его оставило приложение, передается MMIO, и с этого момента приложение не должно пользоваться функциями явной буферизации, работая с файлом обычными методами до повторного переключения в режим явной буферизации.
Если содержимое буфера было изменено приложением, перед вызовом функции необходимо установить флаг DIRTY. Фактическая запись буфера на диск выполняется только при наличии этого флага.
SetBuffer - установка буфера файла
Устанавливает или отменяет буферизацию файла.
MMRESULT mmioSetBuffer ( HMMIO File, LPSTR Buffer, LONG Size, UINT Reserved );
- Buffer - указатель буфера файла, если буфер предоставляется приложением, либо нуль, если буфер должен быть выделен подсистемой MMIO.
- Size - размер буфера приложения или MMIO в байтах, либо нуль, если буферизация отменяется. В последнем случае указатель буфера также должен быть нулевым.
- Reserved - зарезервированный параметр, должен иметь нулевое значение.
Функция выполняет затребованную смену режима буферизации для указанного файла. Если в данный момент для файла используется внутренний буфер, а функция вызывается в режиме задания размера внутреннего буфера - MMIO изменяет размер буфера функцией GlobalRealloc.
Advance - продвижение по файлу в режиме явной буферизации
Считывает в явный буфер очередную порцию данных из файла, либо записывает содержимое буфера в файл.
MMRESULT mmioAdvance ( HMMIO File, MMIOINFO *Info, UINT Mode );
- Info - указатель локальной копии информационной структуры файла, типа MMIOINFO.
- Mode - режим продвижения: MMIO_READ - чтение в буфер из файла, MMIO_WRITE - запись буфера в файл.
Для того, чтобы в режиме записи буфер был действительно записан в файл, необходимо наличие в локальной копии информационной структуры флага DIRTY. Если этот флаг не установлен, операция MMIO_WRITE лишь сдвигает текущую позицию файла, не выполняя фактической записи данных из буфера.
После успешного выполнения чтения или записи функция обновляет значения полей pchNext, pchEndRead, pchEndWrite, lDiskOffset локальной информационной структуры в соответствии с новым состоянием буфера и файла.
При достижении конца файла в режиме чтения функция всегда завершается успешно, а реальный объем считанных в буфер данных определяется разностью указателей pchEndRead и pchNext.
Функции работы с файлами RIFF
CreateChunk - создание раздела
Создает новый раздел в файле.
MMRESULT mmioCreateChunk ( HMMIO File, MMCKINFO *Chunk, UINT Type );
Chunk - указатель описателя создаваемого раздела, типа MMCKINFO:
- в поле ckid должен быть указан код создаваемого раздела, кроме случая явного создания главного раздела типа RIFF или LIST путем задания значения в поле Type. При создании главных разделов в поле fccType должен быть указан тип формы или списка, а поле ckid автоматически заполняется MMIO.
- в поле cksize задается размер области данных раздела, если он известен на данный момент, в противном случае поле оставляется произвольным. Для занесения в заголовок фактического размера раздела после завершения его формирования вызывается функция mmioAscend.
Type - тип создаваемого раздела:
- MMIO_CREATERIFF - создание главного раздела RIFF
- MMIO_CREATELIST - создание главного раздела LIST
- нуль - создание раздела другого типа.
Функция создает с текущей позиции файла заголовок раздела заданного типа. Раздел создается путем простой записи заголовка с текущей позиции, средства MMIO не выполняют вставки новых разделов между существующими.
При успешном завершении функции текущая позиция файла устанавливается на начало его области данных, а для режимов CREATERIFF / CREATELIST - сразу за двойным словом типа раздела (12 байтов от начала заголовка). Функция также устанавливает флаг DIRTY в описателе раздела, чтобы вызванная впоследствии функция mmioAscend могла проверить и скорректировать фактический размер области данных раздела.
Ascend - выход из раздела
Выполняет выход из раздела, который был создан функцией mmioCreateChunk, либо в который был выполнен вход функцией mmioDescend.
MMRESULT mmioAscend ( HMMIO File, MMCKINFO *Chunk, UINT Reserved );
- Chunk - указатель описателя создаваемого раздела, типа MMCKINFO.
- Reserved - зарезервированный параметр, должен иметь нулевое значение.
Смысл выхода из раздела состоит в позиционировании файла сразу за концом раздела, которым является конец области данных, автоматически дополненный при необходимости для четности нулевым выравнивающим байтом. Выход из раздела выполняется двумя способами, в зависимости от наличия в описателе раздела флага DIRTY.
Если флаг не установлен - функция сразу выполняет позиционирование за конец раздела в соответствии со значениями полей dwDataOffset и cksize описателя, полагая, что размер раздела не был изменен после входа в него функцией mmioDescend.
Если флаг установлен - функция трактует текущую позицию файла, как конец области данных сформированного или измененного раздела, при необходимости дописывает выравнивающий байт, вычисляет фактический размер области данных и сравнивает его со значением поля cksize. Если значения отличаются - функция корректирует значение поля cksize в заголовке раздела, отражая там его фактический размер. После этого выполняется позиционирование за конец раздела, как и в первом случае.
Функция вызывается сразу после завершения формирования нового раздела, длина области данных которого заранее неизвестна, либо после изменения длины существующего раздела.
Descend - вход в существующий раздел
Выполняет поиск указанного раздела и вход в него.
MMRESULT mmioDescend ( HMMIO File, MMCKINFO *Chunk, const MMCKINFO *Parent, UINT Mode );
Chunk - указатель описателя искомого раздела, типа MMCKINFO. В поле ckid должен быть указан код искомого раздела, кроме случаев явного поиска разделов RIFF/LIST путем задания значения параметра Mode.
Parent - указатель описателя главного раздела, типа MMCKINFO. Если задан - требуемый раздел ищется внутри указанного главного раздела, вход в который был ранее выполнен функцией mmioDescend.
Mode - вид выполняемой операции:
- нуль - вход в раздел, расположенный с текущей позиции файла.
- MMIO_FINDRIFF - поиск главного раздела RIFF заданного типа.
- MMIO_FINDLIST - поиск главного раздела LIST заданного типа.
- MMIO_FINDCHUNK - поиск произвольного раздела.
Функция ищет в файле раздел, код которого задан Если ищется раздел RIFF или LIST - функция автоматически заносит в это поле соответствующее значение. В этом случае в поле fccType должен быть указан тип искомого главного раздела.
Если требуется найти любой из главных разделов, независимо от типа - в поле ckid описателя искомого раздела необходимо занести соответствующий код, а в параметре Mode указать значение MMIO_FINDCHUNK.
Текущая позиция файла перед вызовом функции должна быть либо в начале какого-либо раздела, либо внутри указанного главного раздела. Поиск начинается с текущей позиции и продолжается до конца файла или указанного главного раздела.
При обнаружении нужного раздела функция считывает его заголовок в заданный описатель, заносит в поле dwDataOffset позицию начала области данных в файле, и устанавливет текущую позицию на начало области данных раздела. Для режимов FINDRIFF / FINDLIST позиция устанавливается сразу за двойным словом типа раздела (12 байтов от начала заголовка).
Флаг DIRTY в описателе раздела сбрасывается. Если требуется расширить, усечь или перезаписать область данных раздела - после этого необходимо установить флаг DIRTY и выполнить выход из раздела функцией mmioAscend для коррекции поля длины в заголовке. Для разделов, длина которых не изменяется, выход выполнять не требуется.
Если искомый раздел не найден - текущая позиция файла не определена.
Прочие функции
SendMessage - посылка произвольного сообщения
Посылает произвольное сообщение процедуре обмена, связанной с открытым файлом.
LRESULT mmioSendMessage ( HMMIO File, UINT Msg, LPARAM Param1, LPARAM Param2 );
- Msg - код передаваемого сообщения. Коды пользовательских сообщений начинаются со значения MMIOM_USER.
- Param1, Param2 - параметры сообщения. Смысл параметров определяется видом конкретного сообщения.
Фактически почти все вызываемые приложением функции MMIO преобразуются в сообщения с кодами MMIOM_xxx, передаваемые процедуре обмена. Если процедура обмена поддерживает какие-либо дополнительные сообщения - например, средства расширенного управления - функция mmioSendMessage позволяет передать такое сообщение с нужными параметрами. Функция возвращает значение, возвращенное процедурой обмена в ответ на переданное ей сообщение.
Поскольку стандартные сообщения MMIOM_OPEN, MMIOM_READ и т.п. генерируются подсистемой MMIO в ответ на обращение приложения к стандартным функциям MMIO, формально не допускается прямая передача таких сообщений процедуре обмена посредством функции mmioSendMessage. Однако, при хорошем понимании внутреннего устройства MMIO и принципа взаимодействия с процедурой обмена, возможно непосредственное общение приложения с процедурой обмена, если при этом соблюдаются все внутренние соглашения Windows и MMIO.
InstallIOProc - установка локальной процедуры обмена
Устанавливает собственную процедуру обмена внутри приложения и делает ее доступной для подключения к открываемым файлам. Позволяет также найти или удалить нужную установленную процедуру.
LPMMIOPROC mmioInstallIOProc ( FOURCC ProcCode, LPMMIOPROC ProcAddr, DWORD Flags );
ProcCode - код процедуры обмена, над которой выполняется требуемая операция. Код должен быть составлен только из символов верхнего регистра (заглавные буквы).
ProcAddr - адрес внутренней функции для устанавливаемой процедуры обмена. Функция должна быть оформлена в соответствии с заданным прототипом. Для случаев поиска или удаления процедуры этот параметр должен быть нулевым.
Flags - код выполняемой операции и дополнительные флаги:
- MMIO_INSTALLPROC - установка процедуры с заданными адресом и кодом. Вместе с этим кодом операции может быть задан флаг MMIO_GLOBALPROC, указывающий, что процедура устанавливается глобально.
- MMIO_REMOVEPROC - удаление установленной процедуры с заданным кодом.
- MMIO_FINDPROC - поиск установленной процедуры с заданным кодом.
Функция возвращает адрес установленной, удаленной или найденной процедуры обмена, либо нулевое значение в случае ошибки.
Новые процедуры обмена заносятся в начало внутреннего списка MMIO, и при установке процедуры для уже имеющегося кода новая процедура будет использоваться вместо старой. При поиске/удалении список просматривается от начала к концу, и найдена/удалена будет последняя из установленных процедур с подходящим кодом. Таким образом, удаление процедур должно происходить в порядке, обратном порядку их установки.
В Win32 глобально установленные процедуры становятся "видимыми" из других процессов - другой процесс может получить адрес установленной процедуры, удалить ее, а также попытаться подключить ее к открываемому файлу посредством указания структурного имени в функции mmioOpen. Однако, из-за использования различными процессами разных адресных пространств, обращение к "чужой" процедуре обмена в общем случае приведет к ошибке.
IOProc - прототип функции для процедуры обмена
Задает правила оформления внутренней программной функции, выступающей в роли процедуры обмена. Установка функции в качестве процедуры обмена выполняется сервисной функцией mmioInstallIOProc.
LRESULT CALLBACK IOProc ( LPSTR Info, UINT Msg, LONG Param1, LONG Param2 );
- Info - указатель структуры MMIOINFO, описывающей текущее состояние открытого файла. По непонятной причине этот параметр имеет тип LPSTR (char *), поэтому требуется его явное приведение к типу (MMIOINFO *).
- Msg - код сообщения, определяющего выполняемое процедурой действие.
- Param1, Param2 - параметры сообщения, уточняющие смысл выполняемой операции.
Процедура обмена отвечает за поддержание правильного значения поля lDiskOffset в информационной структуре файла. Для линейных последовательных файлов, на диске или в памяти, это поле отражает текущее смещение внутри файла.
Процедура обмена вызывается обычным обращением к подпрограмме из той же задачи (thread), которая запросила файловую операцию посредством одной из функций MMIO. Отдельной задачи для процедуры обмена не создается.
Для хранения своих служебных данных процедура обмена может пользоваться массивом adwInfo в информационной структуре. Прочие поля структуры управляются только MMIO; процедура обмена не должна изменять их значений.
В ответ на стандартное сообщение функция должна возвратить значение, определяемое типом обрабатываемого сообщения. В том случае, если возвращаемое значение имеет тип MMRESULT, при успешном выполнении операции должно возвращаться значение MMSYSERR_NOERROR (нуль), а при неудаче - код ошибки. При возникновении типовых ошибок (файл не найден, недостаточно памяти и т.п.) должны возвращаться стандартные коды ошибок. Введение дополнительных кодов ошибок для стандартных сообщений допускается лишь в тех случаях, когда среди стандартных кодов нет подходящего.
В ответ на пользовательские сообщения могут возвращаться любые коды завершения, они без изменения передаются приложению.
Константы для кодов стандартных сообщений, передаваемых подсистемой MMIO, имеют префиксы MMIOM_:
OPEN | Открывание файла. В параметре Param1 передается указатель строки имени открываемого файла. Поле dwFlags информационной структуры содержит коды режимов открывания файла и дополнительные флаги. Поле lDiskOffset в этот момент имеет нулевое значение. Возвращается значение типа MMRESULT. |
---|---|
CLOSE | Закрывание файла. В параметре Param1 передается значение параметра Flags функции mmioClose. Возвращается значение типа MMRESULT. |
RENAME | Переименование файла. В параметре Param1 передается указатель строки имени исходного файла, в параметре Param2 - указатель строки нового имени. Возвращается значение типа MMRESULT. |
READ | Чтение из файла. В параметре Param1 передается указатель буфера, в который считываются данные, в параметре Param2 - размер считываемого фрагмента. Возвращается реальное количество считанных байтов, либо -1 в случае ошибки. |
WRITE | Запись в файл. В параметре Param1 передается указатель буфера, содержащего записываемые данные, в параметре Param2 - размер записываемого фрагмента. Возвращается реальное количество записанных байтов, либо -1 в случае ошибки. |
WRITEFLUSH | Аналогично WRITE, требует фактической записи на диск внутренних буферов файла после выполнения операции. |
SEEK | Смена текущей позиции файла. В параметре Param1 передается величина смещения в байтах, в параметре Param2 - код исходной точки для позиционирования, как в функции mmioSeek. Возвращается новая позиция относительно начала файла, либо -1 в случае ошибки. |
Недостатки интерфейса MMIO
Механизм глобальных процедур обмена работает нормально только в Win16 благодаря общей системе адресации памяти. В Win32, несмотря на отсутствие формального запрета на использование глобальных процедур, их разделение между процессами невозможно, так как вызов процедуры обмена выполняется обычным образом, по адресу, без переключения процессов или задач. При попытке обращения к процедуре обмена, установленной другим процессом, MMIO пытается выполнить вызов локальной функции с адресом, по которому процедура находится в установившем ее процессе. В вызывающем же процессе по этому адресу может находиться все, что угодно - в результате возникает неустранимая ошибка.
Разделение процедур обмена в Windows 95/98 принципиально возможно путем помещения процедуры обмена в область общих адресов (начиная с 0x80000000), где она будет "видна" остальным процессам. Однако ее вызов в любом случае будет выполняться локально, и вызываемая процедура будет работать от имени вызывающего процесса и пользоваться его ресурсами.
Пример программы, использующей MMIO
В качестве иллюстрации схемы обработки звуковых файлов приведена программа ACMPlay. Программа переделана из опубликованной в прошлом номере программы RTComp, предназначенной для сжатия и записи звука в файл в реальном времени. Фактически, ACMPlay является "обратно" к RTComp - она открывает существующий WAV-файл, находит в нем требуемые разделы, после чего восстанавливает данные в формат PCM и воспроизводит на заданном Wave-устройстве.
Для воспроизведения файла необходимо выбрать звуковое устройство, после чего выбрать звуковой файл кнопкой "Файл". Фильтр типов файлов в диалоге выбора пропускает только файлы с расширением WAV. После успешного выбора воспроизведение запускается автоматически. В процессе воспроизведения кнопка переименовывается в "Стоп" для досрочной остановки воспроизведения.
Для поиска разделов RIFF/WAVE, fmt, data используются функции mmioDescend. Файл обрабатывается в режиме явной буферизации, причем буфер файла используется как исходный буфер при преобразовании порций данных в потоке ACM. Размер буфера округляется до 4096 байтов, чтобы он мог вместить полный блок в форматах MS ADPCM и IMA ADPCM.
После открывания устройство вывода устанавливается в режим паузы, затем в его очереди накапливаются пустые звуковые буферы, после чего выполняется сброс функцией waveOutReset, в результате чего все буферы сразу же передаются задаче уведомления. Такой подход позволил сосредоточить всю работу с буферами звукового устройства только внутри его задачи уведомления, которая считывает исходные данные из файла, восстанавливает их в формат PCM посредством подсистемы ACM, заполняет восстановленными данными возвращенные звуковым драйвером буферы, и передает их обратно для проигрывания.
Ведущий рассылки: Алекс Jenter jenter@rsdn.ru
Публикуемые в рассылке материалы принадлежат сайту RSDN.
http://subscribe.ru/
E-mail: ask@subscribe.ru |
Отписаться
Убрать рекламу |
В избранное | ||