Технологии программирования миди

 Навигация:

 Поиск:

 Новости:

17.02.2007
Полностью переработан дизайн сайта.

6.01.2007
Добавлен раздел Наработки Полезные и интересные программы и их исходники от автора.

19.11.2006
Функции WriteVarLen и ReadVarLen портированы с СИ на Delphi читать

14.11.2006
Появилась cтатья Midi-протокол глазами программиста

24.10.2006
Написана вторая часть MMSystem Функции midiOutGetVolume midiOutSetVolume midiOutMessage midiOutShortMsg и midiOutLongMsg

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

1.09.2006
Добавлен раздел MMSystem в котором находятся
подробные опсания функций winmm.dll, определенных в модуле mmSystem.pas,
с примерами их использования в Delphi.

13.08.2006
Опубликован исходник приложения, записывающего игру на клавиатуре
в стандартный midi-файл SMF - 0

4.07.2006
Добавлен раздел Структура формата миди-файла

 Счетчики:
Rambler's Top100 Яндекс цитирования Rambler's Top100
 Контент:

Уведомления, передаваемые программе подсистемой MIDI

Для сообщения программе о наступлении различных событий в отношении устройств и потоков подсистема MIDI может использовать три вида уведомлений: установку объекта программного события (event), вызов заданной программной функции (callback), либо посылку сообщения заданному окну (window) или задаче (thread). В первом варианте программа получает информацию лишь о самом факте некоторого события, и сама должна выяснять, что именно произошло; во втором и третьем вариантах передается код события и уточняющая информация (параметры события).

Уведомление при помощи программного события возможно только в отношении объектов вывода (выводной порт или поток вывода).

Типы событий, о которых сообщается приложению

В подсистеме MIDI возможно возникновение шести различных событий. В скобках приведены общие части имен констант, кодирующих виды событий. Имена параметров указаны традиционные — параметры wParam, lParam относятся к сообщениям Windows, а Param1, Param2 — к вызовам callback–функций:

  • Открывание устройства или потока (OPEN). В параметре wParam передается ключ объекта — устройства или потока.
  • Закрытие устройства или потока (CLOSE). В параметре wParam передается ключ объекта.
  • Приход короткого сообщения (DATA/MOREDATA/ERROR). В параметре lParam или Param1 передается упакованное короткое MIDI-сообщение — полное и достоверное для событий DATA/MOREDATA, и неполное или ошибочное — для события ERROR. Функции в параметре Param2 дополнительно передается время прихода сообщения относительно запуска приема (timestamp).
  • Приход длинного сообщения (LONGDATA/LONGERROR). В параметре lParam или Param1 передается указатель заголовка буфера данных, содержащего либо достоверное, либо незавершенное или ошибочное сообщение. Функции в параметре Param2 дополнительно передается время прихода сообщения.
  • Завершение вывода длинного сообщения или буфера потока (DONE). В параметре lParam или Param1 передается указатель заголовка обработанного буфера данных. В параметре wParam сообщения дополнительно передается ключ объекта, к которому относится событие.
  • Достижение заданной позиции в потоке (POSITIONCB). Возникает, когда интерпретатор потока вывода встречает описатель события, имеющий в байте состояния флаг MEVT_F_CALLBACK. При уведомлении передаются те же параметры, что и в событии DONE. Поле dwOffset в заголовке буфера содержит смещение внутри буфера, по которому расположен описатель события с флагом MEVT_F_CALLBACK.

Первые два события являются синхронными и возникают точно в момент выполнения функций Open/Close, остальные — асинхронными, возникающими в произвольный момент времени.

Имена констант для кодов событий, передаваемых при уведомлении, имеют различные префиксы в зависимости от вида уведомления: MIM_xxx / MOM_xxx — при использовании функции, MM_MIM_xxx / MM_MOM_xxx — при использовании задачи или окна. Аббревиатура MIM используется в константах сообщений от устройств ввода, MOM — от устройств или потоков вывода. Например: MM_MIM_LONGDATA — код сообщения окну или задаче от устройства ввода, MOM_CLOSE — сообщение функции от устройства или потока вывода.

Разница между событиями DATA и MOREDATA заключается в ограничениях на время их обработки. Событие DATA возбуждается драйвером, когда его входной буфер пуст или почти пуст, и приложение может потратить на обработку несколько десятков миллисекунд. Событие MOREDATA возбуждается, если буфер практически заполнен, и обработка событий должна выполняться максимально быстро. При получении события MOREDATA лучшим действием приложения будет просто занести MIDI-сообщение в буфер с быстрым доступом и немедленно закончить обработку события; запрещается даже обращаться к функции PostMessage. После освобождения входного буфера драйвер возвращается в обычный режим, посылая приложению события DATA.

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

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

Набор интерфейсных функций подсистемы MIDI

Как и в статье, описывающей базовую звуковую подсистему, я буду придерживаться универсальной системы именования функций, указывая лишь смысловую часть имени, и опуская префикс, содержащий тип и «ориентацию» устройства. Например, говоря о функции GetDevCaps, я буду подразумевать две функции — midiInGetDevCaps и midiOutGetDevCaps, а в случае функции Open — сразу три: midiInOpen, midiOutOpen, midiStreamOpen. При этом будут оговариваться лишь их различия для объектов разного типа. Это потребует от читателя «конструирования» полного имени функции в каждом конкретном случае, однако позволит подойти к описанию более широко и систематически. В прототипе функции префикс будет обозначаться последовательностью «xxx».

Первым параметром большинства функций указывается ключ (handle) открытого устройства или потока, имеющий тип HMIDIIN, HMIDIOUT или HMIDISTRM; в прототипе его тип обозначается HMIDIx. Для экономии места этот параметр не упоминается при описании каждой из функций.

Как уже говорилось, ключи всех объектов можно хранить в переменных совместимого типа HMIDI, если не определена макропеременная STRICT, включающая строгую проверку типов Windows.

Перечень интерфейсных функций

GetNumDevs

Запрос количества устройств

GetDevCaps

Запрос параметров и возможностей устройства

Open

Открывание устройства/потока

Close

Закрытие устройства/потока

ShortMsg

Вывод короткого сообщения

PrepareHeader

Подготовка (фиксация в памяти) буфера данных

UnprepareHeader

Освобождение (снятие фиксации) буфера данных

AddBuffer / LongMsg / Out

Передача очередного буфера

Stop / Pause

Остановка передачи данных

Start / Restart

Запуск передачи данных

Reset / Stop

Сброс режима передачи данных или потока

Position

Запрос позиции потока вывода

Property

Установка/запрос параметров потока вывода

SetVolume / GetVolume

Установка/запрос громкости звука на выходе синтезатора

CachePatches / CacheDrumPatches

Управление набором тембров в памяти синтезатора

Connect / Disconnect

Установка/разрыв виртуального соединения портов

GetID

Запрос номера устройства по ключу

GetErrorText

Запрос текста сообщения об ошибке по коду

Message

Передача драйверу нестандартного сообщения

CallbackProc

Шаблон функции уведомления

Значения, возвращаемые интерфейсными функциями

За редким исключением, все функции интерфейса возвращают результат типа MMRESULT, эквивалентный типу UINT. Значение MMSYSERR_NOERROR, равное нулю, означает успешное выполнение функции, любое другое значение указывает на ошибку. Константы для кодов ошибок имеют префиксы MMSYSERR_ (общая ошибка мультимедийной подсистемы) и MIDIRR_ (ошибка драйвера MIDI-устройства):

 

MMSYSERR_BADDEVICEID

Недопустимый номер устройства

MMSYSERR_NOTENABLED

Драйвер не активизирован

MMSYSERR_ALLOCATED

Устройство занято другим приложением

MMSYSERR_INVALHANDLE

Недопустимый ключ открытого устройства

MMSYSERR_NODRIVER

Драйвер отсутствует

MMSYSERR_NOMEM

Недостаточно памяти

MMSYSERR_NOTSUPPORTED

Запрошенная функция не поддерживается

MMSYSERR_BADERRNUM

Код ошибки вне допустимого диапазона

MMSYSERR_INVALFLAG

Недопустимый флаг

MMSYSERR_INVALPARAM

Недопустимый параметр

MMSYSERR_HANDLEBUSY

Над ключом выполняется операция от другой задачи (thread)

MMSYSERR_ERROR

Неопределенная ошибка

MMSYSERR_NODRIVERCB

Драйвер не выполнил уведомления (callback)

MIDIERR_UNPREPARED

Заголовок буфера не подготовлен функцией PrepareHeader

MIDIERR_STILLPLAYING

В потоке/устройстве идет воспроизведение

MIDIERR_NOMAP

В MIDI Mapper нет карты инструментов

MIDIERR_NOTREADY

Устройство не готово

MIDIERR_NODEVICE

Устройства нет в системе

MIDIERR_INVALIDSETUP

Недопустимый файл параметров MIDI Mapper

MIDIERR_BADOPENMODE

Недопустимый режим открывания (попытка послать неполное сообщение параллельно потоку вывода)

Описание интерфейсных функций

Макрос MEVT_EVENTTYPE — выделение кода MIDI-события

Служит для выделения кода события из комплексного поля dwEvent описателя события в потоке вывода.

BYTE MEVT_EVENTTYPE (DWORD Event);
  • Event — упакованное представление события в структуре MIDIEVENT.

Возвращает байт кода события и дополнительных флагов.

Фактически макрос выделяет из двойного слова старший байт и реализован при помощи выражения:

#define MEVT_EVENTTYPE(x) ((BYTE) (((x)>>24)&0xFF))

В начало

В начало

Макрос MEVT_EVENTPARM — выделение параметров MIDI-события

Служит для выделения параметров события из упакованного поля dwEvent описателя события в потоке вывода.

DWORD MEVT_EVENTPARM (DWORD Event);
  • Event — упакованное представление события в структуре MIDIEVENT.

Возвращает 24-разрядное слово параметров события.

Фактически макрос выделяет из двойного слова три младших байта и реализован при помощи выражения:

#define MEVT_EVENTPARM(x) ((DWORD) ((x)&0x00FFFFFFL))

GetNumDevs — запрос количества устройств

UINT xxxGetNumDevs (void);

Возвращает количество установленных в системе устройств ввода или вывода.

GetDevCaps — запрос параметров и возможностей устройств

MMRESULT xxxGetDevCaps (
   UINT DevId,
   MIDIxCAPS *Caps,
   UINT CapsSize
 );

Служит для определения параметров и возможностей устройства.

  • DevId — номер устройства, начиная с нуля, либо ключ ранее открытого устройства, либо константа MIDI_MAPPER. В последнем случае возвращаются параметры стандартного системного устройства.
  • Caps — указатель структуры типа MIDIINCAPS или MIDIOUTCAPS.
  • CapsSize — размер структуры в байтах.

При успешном завершении функция заполняет поля переданной указателем структуры параметрами устройства. Если были запрошены параметры MIDI Mapper — в качестве имени устройства возвращается название службы переназначения.

Open — открывание устройства или потока вывода

MMRESULT xxxOpen (
   HMIDIx *ForHandle,
   UINT DevId,
   DWORD Callback,
   DWORD Instance,
   DWORD OpenFlags
 );
MMRESULT midiStreamOpen (
   HMIDISTRM *ForHandle,
   UINT *DevId,
   DWORD Midi,
   DWORD Callback,
   DWORD Instance,
   DWORD OpenFlags
 );
  • ForHandle — указатель переменной типа HMIDIIN, HMIDIOUT или HMIDISTRM, в которую при успешном завершении операции записывается ключ открытого объекта.
  • DevId — номер устройства, начиная с нуля, либо ключ ранее открытого устройства, либо значение MIDI_MAPPER (-1). В последнем случае все операции переадресуются службой переназначения на устройство, заданное в ее настройках.В функции открывания потока вывода параметр DevId является указателем переменной, содержащей одно из перечисленных значений.
  • Midi — зарезервированный параметр в функции открывания потока вывода, должен иметь значение 1.
  • Callback — объект, которому будут передаваться уведомления подсистемы. Задается ключом (handle) окна или события, указателем функции, либо идентификатором задачи (thread id).
  • Instance — 32-разрядное информационное слово, которое будет передаваться в параметрах вызова функции уведомления. Например, при разработке универсального интерфейса с разными устройствами это может быть указатель описателя устройства (структуры или объекта класса).
  • OpenFlags — вид уведомления дополнительные флаги. Константы видов уведомления имеют префикс CALLBACK_:

NULL

Уведомления не используются. Этот режим берется по умолчанию.

EVENT

Параметр Callback является ключом объекта события (event handle). Может использоваться только с выводным устройствами или потоком.

THREAD

Параметр Callback является идентификатором задачи (thread id).

WINDOW

Параметр Callback является ключом окна (window handle).

FUNCTION

Параметр Callback является указателем функции.

 

При открывании устройств ввода в параметре OpenFlags дополнительно может быть задан флаг MIDI_IO_STATUS, требующий от драйвера слежения за состоянием входного буфера и уведомления о его близком переполнении событиями типа MOREDATA.

В случае успешного открывания объекта подсистема возвращает в переменную, на которую ссылается указатель ForHandle, ключ (handle) открытого объекта.

Устройства ввода открываются в режиме «стоп», поступающие на вход интерфейса сообщения не будут получены приложением, если не вызвана функция Start. Потоки вывода также открываются в остановленном режиме, и для их запуска требуется функция Restart.

Устройства вывода сразу после открывания готовы к передаче, и вывода сообщений достаточно выполнить нужную функцию (ShortMsg/LongMsg).

При открывании потока вывода указанное устройство вывода открывается автоматически, и автоматически же закрывается при закрытии потока.

При завершении работы с устройством его необходимо закрыть функцией Close, в противном случае открытое устройство может «зависнуть». В отличие от файловой, подсистема MIDI в Windows гораздо более чувствительна к ошибкам, и не всегда в состоянии отследить завершение программы, чтобы аварийно закрыть все устройства.

Close — закрытие устройства или потока

MMRESULT xxxClose (HMIDIx Handle);

Закрывает устройство или поток вывода. Закрытие допустимо только после завершения обмена данными и возврата приложению всех переданных ранее буферов, иначе подсистема возвращает код ошибки MIDIRR_STILLPLAYING. Поэтому перед вызовом функции необходимо либо дождаться возврата всех буферов в обычном порядке, либо вызвать функцию Reset (для устройства) или Stop (для потока), в результате чего буферы будут возвращены немедленно.

PrepareHeader — подготовка буфера данных и его заголовка

MMRESULT xxxPrepareHeader (HMIDIx Handle, MIDIHDR *Hdr, UINT HSize);
  • Hdr — указатель заголовка буфера данных устройства ввода или вывода.
  • HSize — размер структуры заголовка.

Подготавливает буфер данных к передаче драйверу. Обычно подготовка заключается в фиксации буфера в памяти, чтобы во время внепроцессорной передачи (DMA) он не оказался вытесненным (откачанным) на диск. В слове состояния заголовка подготовленного буфера подсистемой устанавливается флаг MHDR_PREPARED.

Перед вызовом функции в заголовке буфера должны быть заполнены поля lpData, dwBufferLength, dwFlags.

Для буферов данных потоков вывода предварительной подготовки не требуется.

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

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

UnprepareHeader — отмена подготовительных действий для буфера

MMRESULT xxxUnprepareHeader (HMIDIx Handle, MIDIHDR *Hdr, UINT HSize);
  • Hdr — указатель заголовка буфера данных.
  • HSize — размер структуры заголовка.

Отменяет подготовительные действия, выполненные ранее функцией PrepareHeader. Обычно это состоит в снятии режима фиксации буфера в памяти.

При успешном выполнении функции в слове состояния заголовка буфера сбрасывается флаг MHDR_PREPARED.

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

ShortMsg — вывод короткого сообщения

MMRESULT midiOutShortMsg (HMIDIOUT Handle, DWORD Msg);
  • Msg — короткое MIDI-сообщение в упакованном виде.

Выводит заданное сообщение на устройство либо в поток вывода. В последнем случае параметр Handle задает ключ потока.

Сообщение может быть оформлено либо полностью (с байтом состояния), либо в соответствии с правилами режима Running Status. Если сообщение выводится в поток вывода — оно обязательно должно быть полным, иначе возвращается код ошибки MIDIERR_BADOPENMODE.

Синхронный MIDI-драйвер не возвращает управления до тех пор, пока все сообщение не будет полностью обработано.

AddBuffer/LongMsg/Out — передача буфера данных устройству или потоку

MMRESULT midiInAddBuffer (HMIDIIN Handle, MIDIHDR *Hdr, UINT HSize);
MMRESULT midiOutLongMsg (HMIDIOUT Handle, MIDIHDR *Hdr, UINT HSize);
MMRESULT midiStreamOut (HMIDISTRM Handle, MIDIHDR *Hdr, UINT HSize);
  • Hdr — указатель заголовка буфера данных.
  • HSize — размер структуры заголовка.

Передает буфер данных для ввода длинного сообщения (AddBuffer), вывода длинного сообщения (LongMsg), либо для вывода серии сообщений потока (Out). В первых двух случаях буфер должен быть подготовлен функцией PrepareHeader, иначе драйвер откажется его принять.

Для потоков вывода размер буфера не должен превышать 64 кб.

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

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

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

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

Stop/Pause — остановка ввода сообщений/воспроизведения потока

MMRESULT midiInStop (HMIDIIN Handle);
MMRESULT midiStreamPause (HMIDISTRM Handle);

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

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

При остановленном потоке функция не выполняет никаких действий и завершается успешно.

Start/Restart — запуск ввода/воспроизведения потока

MMRESULT midiInStart (HMIDIIN Handle);
MMRESULT midiStreamRestart (HMIDISTRM Handle);

Для устройства ввода разрешает прием входящих сообщений. Счетчик времени, относительно которого помечаются входящие сообщения (timestamp), устанавливается в нуль.

Для потока вывода запускает обработку последовательности событий с текущей позиции потока.

Reset/Stop — сброс устройства или остановка потока

MMRESULT xxxReset (HMIDIx Handle);
MMRESULT midiStreamStop (HMIDISTRM Handle);

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

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

Position — запрос текущей позиции потока

MMRESULT midiStreamPosition (HMIDISTRM Handle, MMTIME *Time, UINT TSize);
  • Time — указатель структуры типа MMTIME. В поле wType должен быть установлен код единиц, в которых запрашивается позиция.
  • TSize — размер структуры в байтах.

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

SetVolume — установка громкости звука на выходе синтезатора

MMRESULT midiOutSetVolume (HMIDIOUT Handle, DWORD Volume);
  • Volume — громкость по левому и правому каналу. Младшее слово задает громкость левого канала, старшее — правого. Значение 0xFFFF задает максимальную громкость, 0 — минимальную. Для драйверов, не поддерживающих независимую регулировку громкости по каналам, младшее слово задает громкость в обоих каналах синтезатора.

Функция устанавливает уровень выходного сигнала синтезатора. Несмотря на то, что функцией допускается 65536 уровней громкости, синтезатор может поддерживать гораздо меньше — 8, 32 или 128 уровней. В таких случаях значащими является только от трех до семи старших разрядов значения громкости, младшие разряды игнорируются. Такая трактовка позволяет использовать одну и ту же шкалу громкости, изменяя лишь степень ступенчатости регулировки.

Функция поддерживается только драйверами, в свойствах которых установлен флаг MIDICAPS_VOLUME. Раздельная регулировка по каналам поддерживается только при наличии флага MIDICAPC_LRVOLUME.

GetVolume — запрос текущей громкости воспроизведения

MMRESULT midiOutGetVolume (HMIDIx Handle, LPDWORD ForVolume);
  • ForVolume — указатель переменной типа DWORD, в которую заносятся текущие уровни громкости.

Функция опрашивает текущий установленный уровень выходного сигнала. Трактовка переменной, на которую ссылается указатель ForVolume, аналогична используемому в функции SetVolume.

Property — запрос/установка параметров потока

MMRESULT midiStreamProperty (
   HMIDISTRM Handle,
   BYTE *Data,
   DWORD Op
 );
  • Data — указатель области данных, в которой находится устанавливаемый параметр потока вывода, либо в которую записывается запрашиваемый параметр потока. Поскольку описатели параметров имеют разные типы, требуется явное приведение к типу (BYTE *).
  • Op — вид операции и тип параметра. Константы для этих кодов имеют префикс MIDIPROP_ и объединяются операцией «логическое Или».

Виды операций с параметрами:

GET

Запрос значения параметра

SET

Установка значения параметра

Типы параметров:

TEMPO

Темп воспроизведения потока (описатель MIDIPROPTEMPO). Может быть установлен в любой момент. События MEVT_TEMPO в потоке приводят к изменению текущего темпа.

TIMEDIV

Временная шкала потока (описатель MIDIPROPTIMEDIV). Может быть установлен только при остановленном потоке.

 

Запрос параметров потока может выполняться в любой момент времени.

Connect/Disconnect — установка/разрыв виртуального соединения

MMRESULT midiConnect (HMIDI In, HMIDIOUT Out, VOID *Reserved);
MMRESULT midiDisconnect (HMIDI In, HMIDIOUT Out, VOID *Reserved);
  • In — ключ устройства ввода.
  • Out — ключ устройства вывода.
  • Reserved — резервный параметр, должен иметь нулевое значение.

Функция Connect выполняет виртуальное соединение двух устройств — вводного и выводного, имитируя аппаратную реализацию входного ретранслятора MIDI-интерфейса (Thru). При появлении сообщений в устройстве ввода они автоматически будут дублироваться указанному устройству вывода.

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

Функция Disconnect разрывает ранее установленное соединение устройств.

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

CachePatches/CacheDrumPatches — управление набором тембров (патчей)

MMRESULT midiOutCachePatches (
   HMIDIOUT Handle,
   UINT Bank,
   WORD *PatchArray,
   UINT Op
 );
MMRESULT midiOutCacheDrumPatches (   HMIDIOUT Handle,   UINT Patch,   WORD *KeyArray,   UINT Op );
  • Bank / Patch — номер банка мелодических инструментов (для CachePatches) или набора ударных инструментов (для CacheDrumPatches). В случае обращения к банку или набору по умолчанию параметр должен быть нулевым.
  • PatchArray / KeyArray — массив данных мелодических тембров (для CachePatches) или нот ударных звуков (для CacheDrumPatches). Массив имеет тип WORD, его длина определяется константой MIDIPATCHSIZE (128). Для удобства определены типы PATCHARRAY и KEYARRAY. Каждый элемент массива определяет набор MIDI-каналов, в которых используется соответствующий номеру элемента тембр (звук). Отсчет номеров тембров, как и элементов массива, ведется с нуля. Использующие тембр каналы отмечаются установленными разрядами в элементе массива, каналу 1 соответствует бит 0. Например, если тембр с номером 17 используется каналами 1 и 4, 17-й элемент массива должен быть равен 9 (двоичное 1001).
  • Op — код выполняемой операции. Константы для кодов операций имеют префикс MIDI_:

CACHE_ALL

Загрузка всех указанных тембров. Если памяти синтезатора не хватает для загрузки всего приведенного списка — функция не загружает ничего, обнуляет массив тембров и возвращает код MMSYSERR_NOMEM.

CACHE_BESTFIT

Загрузка максимально возможного подмножества тембров. Функция пытается загрузить наибольшее возможное количество тембров; если памяти синтезатора недостаточно — в массиве обнуляются элементы незагруженных тембров и возвращается код MMSYSERR_NOMEM.

CACHE_QUERY

Запрос множества тембров, загруженных в настоящее время. Массив заполняется данными о загруженных тембрах.

UNCACHE

Удаление из памяти синтезатора тембров, отмеченных в массиве. После выполнения операции массив обнуляется.

 

Таким образом, каждая операция поддерживает массив тембров в виде, отражающем текущее состояние памяти синтезатора.

GetID — запрос номера устройства по ключу

MMRESULT xxxGetID (HMIDIx Handle, UINT *ForID);
  • ForID — указатель переменной типа UINT, в которую заносится номер устройства.

Функция определяет номер устройства, при открывании которого системой был возвращен заданный ключ. В том случае, если при открывании была использована служба переназначения (значение MIDI_MAPPER вместо номера) функция возвращает значение MIDI_MAPPER.

Документация Microsoft утверждает, будто эта функция поддерживается только для совместимости, и для получения номера достаточно привести ключ к нужному типу, однако это совсем не так. Ключ открытого устройства является адресом описателя, принадлежащего подсистеме, и в Win32 размещается в общей области памяти. Единственный способ получить номер устройства по ключу — использование функции GetID.

GetErrorText — запрос текстового сообщения об ошибке по коду

MMRESULT xxxGetErrorText (MMRESULT Error, char *Buf, UINT Size);
  • Error — код ошибки, возвращенный одной из интерфейсных функций.
  • Buf — указатель текстового буфера (массива типа char).
  • Size — размер текстового буфера в байтах.

Функция заносит в заданный буфер текстовое описание ошибки с заданным кодом. Записанный текст завершается нулевым байтом. Если буфер недостаточно велик — конец текста обрезается; нулевой байт записывается в буфер в любом случае. Размер буфера, способного вместить любое сообщение об ошибке, определяется константой MAXERRORLENGTH.

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

Message — передача сообщения драйверу устройства

MMRESULT xxxMessage (HMIDIx Handle, UINT Msg, DWORD P1, DWORD P2);
  • Msg — код передаваемого сообщения.
  • P1, P2 — параметры сообщения.

Функция используется для прямой передачи сообщения драйверу. Все интерфейсные функции, кроме GetID и GetErrorText и функций работы с потоками вывода, транслируются подсистемой в сообщения, передаваемые драйверу; при этом каждое сообщение имеет два параметра типа DWORD, в которые преобразуются параметры интерфейсных функций. Если драйвер устройства поддерживает нестандартные сообщения — они могут быть переданы ему при помощи функций Message. Возвращаемое значение при этом определяется самим драйвером.

CallbackProc — функция приложения, вызываемая при уведомлении

Эта функция определяется приложением, подсистема MIDI вызывает ее при выполнении уведомлений, передавая в ее аргументах код и параметры события. Прототип функции имеет следующий вид (имя CallbackProc приведено для примера, реальное имя выбирается приложением):

void CALLBACK CallbackProc (
   HMIDIx Handle,
   UINT Msg,
   DWORD Instance,
   DWORD Param1,
   DWORD Param2
 );
  • Handle — ключ устройства. Имеет тип HMIDIIN или HMIDIOUT; допустимо использование универсального типа HMIDI, если не определена макропеременная STRICT.
  • Msg — код типа события.
  • Instance — 32-разрядное информационное слово, указанное программой при открывании устройства. Подсистема и драйвер никак не используют это значение, а лишь передают его при каждом вызове функции.
  • Param1, Param2 — параметры события.

В Win16 функция может вызываться в контексте обработчика прерывания, поэтому безопасно может использовать лишь ограниченный набор функций Windows: EnterCriticalSection, LeaveCriticalSection, midiOutLongMsg, midiOutShortMsg, OutputDebugString, PostMessage, PostThreadMessage, SetEvent, timeGetSystemTime, timeGetTime, timeKillEvent, timeSetEvent. Обращение к другим системным функциям, как и к функциям подсистемы, может вызвать непредсказуемые последствия.

Обратите внимание, что функция-обработчик может обращаться к функциям midiOutShortMsg, midiOutLongMsg. Это означает, что логика переназначения/отражения MIDI-сообщений может быть реализована непосредственно в этой функции.

В Win32 для вызова функции подсистема создает отдельную задачу (thread) с повышенным (ABOVE_NORMAL) приоритетом. В отличие от передачи сообщений окну/задаче, которые обрабатываются в порядке очереди, вызов функции происходит параллельно с работой остальных задач процесса, поэтому необходимо заботиться о синхронизации доступа функции и других задач к общим переменным и структурам данных.

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

Недостатки подсистемы MME/MIDI

В Windows 95/98 подсистема MME и ее драйверы так и остались 16-разрядными, как и в Windows 3.x. Из-за этого каждое обращение к драйверу из Win32–приложения сопровождается двойной сменой режима исполнения (thunking), приводящее, увы, к дополнительным накладным расходам, доходящим до единиц миллисекунд.

Кроме этого, вся мультимедийная подсистема Windows 3.x и 95/98 отличается низкой устойчивостью к ошибкам. Это чаще всего проявляется в том, что при аварийном завершении программы, открывшей устройства и работающей с ними, система не выполняет корректного закрытия (cleanup) используемых устройств. В результате этого в ряде случаев после такого аварийного завершения может потребоваться перезагрузка, а до тех пор незакрытые устройства будут недоступны другим приложениям. Кроме этого, 16-разрядные подсистемы защищены от ошибок гораздо меньше 32-разрядных, так что серьезные ошибки в звуковых программах могут приводить к сбоям и зависаниям всей системы Windows.

В Windows NT/2000 все подсистемы сделаны изначально 32-разрядными, так что описанных проблем там не возникает.


 Bash.org.ru:

 Реклама:

 ©Copyright:
http://www.last.h16.ru - программирование миди. Идея, разработка и поддержка : Mo-skin © 2006-2007
X