从 C++ 发送 midi 消息

2022-01-05 00:00:00 raspberry-pi midi c++ alsa

我使用的是树莓派,所以它有点像 Debian (Raspbian)

I'm using a raspberry pi, so it is sort of Debian (Raspbian)

我有一个正在运行的合成器 (Zynaddsubfx),我想通过代码向他发送 MIDI 消息并让它为我播放音乐.为此,我将使用 ALSA.

I have a synthesizer running (Zynaddsubfx) and I want to send him midi messages from code and have it playing the music for me. I will use ALSA for that.

我通过执行以下操作设法在我的程序中创建了一个发射端口":

I managed to create a "emitting port" in my program by doing:

snd_seq_create_simple_port(seq_handle, "My own sequencer",
    SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
    SND_SEQ_PORT_TYPE_APPLICATION)

现在我可以在 aconnect -ol 中看到 ZynSubAddFX,在 aconnect -il 中看到我自己的音序器.我可以连接它们:

now I can see ZynSubAddFX in aconnect -ol and my own sequencer in aconnect -il. And I'm able to connect them:

pi@cacharro:~/projects/tests$ aconnect 129:0 128:0
pi@cacharro:~/projects/tests$ Info, alsa midi port connected

为此,正如 CL 所建议的那样,我使用打开的 snd_seq_open,存储序列,然后使用 snd_seq_create_simple_port .. 但是:

for doing that, as sugested by CL I used opened snd_seq_open, stored the sequence and then used snd_seq_create_simple_port.. BUT :

正如之前所评论的,我只想在用户交互下向 zynsubaddfx 发送命令,因此创建队列、添加节奏等不是要走的路.

As commented before I just wanna send commands to zynsubaddfx under user interaction so creating queues, adding tempo and so on is not the way to go.

有没有办法通过我打开的端口发送简单的midi命令,比如note on/note off???

Is there a way to send simple midi comands like note on/note off through my opened port ???

推荐答案

在特定时间发送一些事件:

To send some events at a specific time:

  • 打开音序器;
  • 创建您自己的(源)端口;
  • 构建并发送一些事件.

要打开音序器,请调用 snd_seq_open.(您可以通过 snd_seq_client_id 获取您的客户编号.)

To open the sequencer, call snd_seq_open. (You can get your client number with snd_seq_client_id.)

    snd_seq_t seq;
    snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, 0);

要创建一个端口,分配一个端口信息对象snd_seq_port_info_alloca,设置端口参数snd_seq_port_info_set_xxx,并调用snd_seq_create_port.或者直接调用 snd_seq_create_simple_port.

To create a port, allocate a port info object with snd_seq_port_info_alloca, set port parameters with snd_seq_port_info_set_xxx, and call snd_seq_create_port. Or simply call snd_seq_create_simple_port.

    int port;
    port = snd_seq_create_simple_port(seq, "my port",
            SND_SEQ_PORT_CAP_READ | SND_SEQ_POR_CAP_WRITE,
            SND_SEQ_PORT_TYPE_APPLICATION);

要发送一个事件,分配一个事件结构(只需对于更改,您可以使用本地 snd_seq_event_t 变量),并调用各种snd_seq_ev_xxx 函数来设置其属性.然后在发送完所有内容后调用 snd_seq_event_outputsnd_seq_drain_output事件.

To send an event, allocate an event structure (just for a change, you can use a local snd_seq_event_t variable), and call various snd_seq_ev_xxx functions to set its properties. Then call snd_seq_event_output, and snd_seq_drain_output after you've sent all events.

    snd_seq_event_t ev;
    snd_seq_ev_clear(&ev);
    snd_seq_ev_set_direct(&ev);

    /* either */
    snd_seq_ev_set_dest(&ev, 64, 0); /* send to 64:0 */
    /* or */
    snd_seq_ev_set_subs(&ev);        /* send to subscribers of source port */

    snd_seq_ev_set_noteon(&ev, 0, 60, 127);
    snd_seq_event_output(seq, &ev);

    snd_seq_ev_set_noteon(&ev, 0, 67, 127);
    snd_seq_event_output(seq, &ev);

    snd_seq_drain_output(seq);

相关文章