The website "dmilvdv.narod.ru." is not registered with uCoz.
If you are absolutely sure your website must be here,
please contact our Support Team.
If you were searching for something on the Internet and ended up here, try again:

About uCoz web-service

Community

Legal information

Глава 9. Интерфейс RawMIDI

Глава 9. Интерфейс RawMIDI

Предыдущая  Содержание  Следующая V*D*V

Обзор

Интерфейс raw MIDI (необработанный MIDI) используется для доступа к аппаратным портам MIDI, которые могут быть доступны как поток байтов. Он не используется для чипов-синтезаторов, которые непосредственно не понимают MIDI.

 

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

 

API rawMIDI определён в <sound/rawmidi.h>.

Конструктор

Чтобы создать устройство rawmidi, вызовите функцию snd_rawmidi_new:

 

struct snd_rawmidi *rmidi;

err = snd_rawmidi_new(chip->card, "MyMIDI", 0, outs, ins, &rmidi);

if (err < 0)

    return err;

rmidi->private_data = chip;

strcpy(rmidi->name, "My MIDI");

rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |

                    SNDRV_RAWMIDI_INFO_INPUT |

                    SNDRV_RAWMIDI_INFO_DUPLEX;

 

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

 

Третий аргумент является индексом этого компонента. Вы можете создать до 8 устройств rawmidi.

 

Четвертый и пятый аргументы - это количество выходных и входных субпотоков, соответственно, этого устройства (субпоток эквивалентен порту MIDI).

 

Чтобы указать возможности устройства, установите поле info_flags.

Установите SNDRV_RAWMIDI_INFO_OUTPUT, если есть хотя бы один выходной порт, SNDRV_RAWMIDI_INFO_INPUT, если есть хотя бы один входной порт, и SNDRV_RAWMIDI_INFO_DUPLEX, если устройство может одновременно обрабатывать ввод и вывод.

 

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

 

snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_mymidi_output_ops);

snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_mymidi_input_ops);

 

Операции обычно определяются следующим образом:

 

static struct snd_rawmidi_ops snd_mymidi_output_ops = {

    .open = snd_mymidi_output_open,

    .close = snd_mymidi_output_close,

    .trigger = snd_mymidi_output_trigger,

};

 

Эти обратные вызовы описаны в разделе Обратные вызовы.

 

Если есть более одного субпотока, каждому из них необходимо дать уникальное имя:

 

struct snd_rawmidi_substream *substream;

list_for_each_entry(substream,

                    &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams,

                    list)

{

    sprintf(substream->name, "My MIDI Port %d", substream->number + 1);

}

/* что-нибудь для SNDRV_RAWMIDI_STREAM_INPUT */

 

Обратные вызовы

Во всех обратных вызовах закрытые данные, которые установлены для устройства rawmidi, могут быть доступны как substream->rmidi->private_data.

 

Если имеется более одного порта, ваши обратные вызовы могут определить индекс порта из данных структуры snd_rawmidi_substream, передаваемой в каждый обратный вызов:

 

struct snd_rawmidi_substream *substream;

int index = substream->number;

 

Обратный вызов open

 

static int snd_xxx_open(struct snd_rawmidi_substream *substream);

 

Он вызывается, когда субпоток открывается. Вы можете здесь проинициализировать оборудование, но ещё не должны начинать передачу/приём данных.

Обратный вызов close

 

static int snd_xxx_close(struct snd_rawmidi_substream *substream);

 

Угадайте, зачем.

 

Последовательность работы обратных вызовов open и close устройства rawmidi управляется с помощью мьютекса и они могут спать.

Обратный вызов trigger для выходных субпотоков

 

static void snd_xxx_output_trigger(struct snd_rawmidi_substream *substream, int up);

 

Он вызывается с ненулевым параметром up, когда есть данные в буфере субпотока, который должен быть передан.

 

Чтобы прочитать данные из буфера, вызовите snd_rawmidi_transmit_peek. Она вернёт количество прочитанных байт; оно будет меньше, чем количество запрошенных байтов, если в буфер нет больше данных. После того, как данные были успешно переданы, вызовите snd_rawmidi_transmit_ack, чтобы удалить данные из буфера субпотока:

 

unsigned char data;

while (snd_rawmidi_transmit_peek(substream, &data, 1) == 1) {

    if (snd_mychip_try_to_transmit(data))

        snd_rawmidi_transmit_ack(substream, 1);

    else

        break; /* аппаратный буфер FIFO полон */

}

 

Если вы знаете заранее, что оборудование примет данные, можно использовать функцию snd_rawmidi_transmit, которая считывает данные и сразу удаляет их из буфера:

 

while (snd_mychip_transmit_possible()) {

    unsigned char data;

    if (snd_rawmidi_transmit(substream, &data, 1) != 1)

        break; /* данных больше нет */

    snd_mychip_transmit(data);

}

 

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

 

Обратный вызов trigger не должен спать. Если перед передачей буфера субпотока оказалось, что аппаратный FIFO полон, вы должны продолжить передавать данные позже, либо в обработчике прерывания, либо с помощью таймера, если оборудование не имеет прерывания передачи MIDI.

 

Обратный вызов trigger вызывается с нулевым параметром up, если передача данных должна быть прервана.

Обратный вызов trigger для субпотоков ввода

 

static void snd_xxx_input_trigger(struct snd_rawmidi_substream *substream, int up);

 

Он вызывается с ненулевым параметром up для разрешения получения данных, или с нулевым параметром up для запрета приёма данных.

 

Обратный вызов trigger не должен спать; фактическое чтение данных из устройства обычно выполняется в обработчике прерывания.

 

Если приём данных разрешён, ваш обработчик прерывания должен вызывать snd_rawmidi_receive для всех полученных данных:

 

void snd_mychip_midi_interrupt(...)

{

    while (mychip_midi_available()) {

        unsigned char data;

        data = mychip_midi_read();

        snd_rawmidi_receive(substream, &data, 1);

    }

}

 

Обратный вызов drain

 

static void snd_xxx_drain(struct snd_rawmidi_substream *substream);

 

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

 

Этот обратный вызов не является обязательным. Если drain не установлен в структуре struct snd_rawmidi_ops, ALSA  вместо этого будет просто ждать в течение 50 миллисекунд.

 

Предыдущая  Содержание  Следующая