Схема хранения музыкальных параметров клавиш
Поможем в ✍️ написании учебной работы
Поможем с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой

Во время нажатия клавиши клавиатура генерирует скан-код и флаг (эта информация находится в структуре KEYBOARD_INPUT_DATA).

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

Для нескольких клавиш может быть сгенерирован один и тот же скан-код, например для левого и правого Shift. Их возможно различить только по флагу. Не более чем трём клавишам может сооответствовать один скан-код. Поэтому скан-код нельзя использовать как индекс массива, в котором хранятся музыкальные данные только для одной клавиши – эти музыкальные данные будут использоваться для нескольких клавиш с одинаковым скан-кодом.

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

Схема реализована в модуле keys.

Схема такова:

typedef struct _KEY_SCANS_TABLE

{UCHAR Usage;

UCHAR ScanMake;

UCHAR ScanE0;

UCHAR ScanE1;

} KEY_SCANS_TABLE, * PKEY_SCANS_TABLE;

typedef struct _KEY_MIDI_TABLE

{UCHAR Used;

UCHAR Channel;

UCHAR Instrument;

UCHAR Note;

} KEY_MIDI_TABLE, * PKEY_MIDI_TABLE;

Создаётся массив структур KEY_SCANS_TABLE, где индекс массива – реальный скан-код, генерируемый клавиатурой, а в полях ScanMake, ScanE0, ScanE1 хранится позиция клавиши, соответствующая тому или иному значению флага клавиши, генерируемого клавиатурой. В поле Usage число единичных бит равно числу установленных клавиш, соответствующих одному скан-коду.

Создаётся массив структур KEY_MIDI_TABLE, где индекс массива – позиция клавиши, в полях структуры содержится музыкальная информация о клавише:

Used – используется в схеме или нет. Если используется: нажата или отпущена.

Channel – канал, в котором звучит нота. Существует 16 каналов - 0..15.

Instrument – инструмент ноты. Существует 128 инструментов - 0..127.

Note – нота. Существует 128 нот для каждого инструмента - 0..127.

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

На обычной клавиатуре находится 104 клавиши. Поэтому в данной курсовой работе используется 104 позиции (0..103).

Функции установки и выборки музыкальной информации

NTSTATUS KeyMidiInit()

Выделяет память для двух таблиц и заполняет их нулями.

NTSTATUS KeyMidiFree()

Освобождает память, выделенную для таблиц.

NTSTATUS KeyMidiSetNote(IN UCHAR ScanCode, IN UCHAR Flag,

IN UCHAR Position,

IN UCHAR Channel, IN UCHAR Instrument,

IN UCHAR Note, IN UCHAR Used)

Устанавливает в первой таблице для скан-кода и флага позицию. Для позиции во второй таблице устанавливает музыкальные параметры.

NTSTATUS KeyMidiGetPosition(IN UCHAR ScanCode, IN UCHAR Flag,

OUT PUCHAR Position)

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

NTSTATUS KeyMidiGetNote(IN UCHAR Position, PUCHAR Channel,

OUT PUCHAR Instrument, OUT PUCHAR Note,

OUT PUCHAR Used)

Используя позицию клавиши, получает музыкальные данные из второй таблицы.

NTSTATUS KeyMidiSetUsed(IN UCHAR Position, IN UCHAR Used)

Используя позицию клавиши, устанавливает состояние клавиши KEY_RELEASED (отпущена) или KEY_PRESSED (нажата).

Разделение задачи на потоки

Функция MyFilterReadComplete, которая получает буфер нажатых клавиш как массив структур KEYBOARD_INPUT_DATA, выполняется на IRQL <= DISPATCH_LEVEL.

Функция PinMidiNoteOn работает только при IRQL = PASSIVE_LEVEL.

Это значит, что функцию PinMidiNoteOn нельзя вызывать внутри функции MyFilterReadComplete.

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

Дата: 2019-12-22, просмотров: 200.