Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 8374

Graphics, sound and multimedia • Re: Midi, I2C, Pi 5 RP1 chip, which gpio lib???

$
0
0
Plz take a look, some new board and tty pull just announced. Maybe can take some inspiration?
Would this be compatible with the Slim Midi? I couldn't find any ref to specific ARM processors being used.

https://github.com/terioto/bento_ttymidi

New announced pro Audio Midi card for Pi4 and 5, uses Bento-ttymidi for midi communication

https://www.cnx-software.com/2025/06/27 ... amplifier/
A closer look u5 and u8 and u2 should be these three components, so no ARM ics...
Audio Input: Stereo Line In, 3.5 mm TRS, PCM1863 ADC
Audio Output: Stereo Line Out, 3.5 mm TRS, PCM5242 DAC
Headphone Output: 3.5 mm TRS jack, powered by TPA6130

dtoverlay driver patch here:
https://github.com/openwrt-es/lede/blob ... sion.patch

+MODULE_AUTHOR Joerg Schambacher <joerg@i2audio.com
+MODULE_AUTHOR Daniel Matuschek <daniel@hifiberry.com

I haven't seen mentioning any other install process other then Bento_ttymidi.
bento.jpg

What's this termios.h about? a ioct call struct termios tty (seems unique to bento_ttymidi) search get me POSIX

Use of ioctl() makes for nonportable programs. Use the POSIX interface described in
termios(3) whenever possible.

uses sys/ioctl.h as opposed to asm/ioctl.h

https://manpages.ubuntu.com/manpages/lu ... ctl.4.html

The bento_ttymidi.c in question:

Code:

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <errno.h>#include <termios.h>#include <pthread.h>#include <linux/serial.h>#include <sys/ioctl.h>#include <alsa/asoundlib.h>#define DEVICE "/dev/serial0"#define BAUDRATE 31250int serial_fd;snd_seq_t *seq;int out_port, in_port;int debug = 0;void set_custom_baudrate(int fd, int speed) {    struct serial_struct ser;    if (ioctl(fd, TIOCGSERIAL, &ser) < 0) {        perror("[ERROR] ioctl TIOCGSERIAL");        exit(1);    }    ser.custom_divisor = ser.baud_base / speed;    ser.flags &= ~ASYNC_SPD_MASK;    ser.flags |= ASYNC_SPD_CUST;    if (ioctl(fd, TIOCSSERIAL, &ser) < 0) {        perror("[ERROR] ioctl TIOCSSERIAL");        exit(1);    }    if (debug) printf("[INFO] Custom baudrate %d applied\n", speed);}void open_serial() {    struct termios tty;    serial_fd = open(DEVICE, O_RDWR | O_NOCTTY);    if (serial_fd < 0) {        perror("[ERROR] open serial device");        exit(1);    }    if (debug) printf("[INFO] Opened serial device: %s\n", DEVICE);    memset(&tty, 0, sizeof tty);    if (tcgetattr(serial_fd, &tty) != 0) {        perror("[ERROR] tcgetattr");        exit(1);    }    cfmakeraw(&tty);    cfsetspeed(&tty, B38400);    tty.c_cflag |= (CLOCAL | CREAD);    tty.c_cflag &= ~CRTSCTS;    if (tcsetattr(serial_fd, TCSANOW, &tty) != 0) {        perror("[ERROR] tcsetattr");        exit(1);    }    set_custom_baudrate(serial_fd, BAUDRATE);}void open_alsa_ports() {    int client_id;    if (snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) {        fprintf(stderr, "[ERROR] Cannot open ALSA sequencer\n");        exit(1);    }    snd_seq_set_client_name(seq, "bento_ttymidi");    client_id = snd_seq_client_id(seq);    out_port = snd_seq_create_simple_port(seq, "MIDI out",        SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ,        SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION);    in_port = snd_seq_create_simple_port(seq, "MIDI in",        SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE,        SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION);    if (debug) {        printf("[INFO] ALSA client ID: %d\n", client_id);        printf("[INFO] ALSA out port:  %d:%d\n", client_id, out_port);        printf("[INFO] ALSA in port:   %d:%d\n", client_id, in_port);        printf("[INFO] bento_ttymidi now listening for ALSA → UART ...\n");    }}void* serial_to_midi(void* arg) {    unsigned char buffer[3];    int state = 0;    snd_seq_event_t ev;    while (1) {        unsigned char byte;        if (read(serial_fd, &byte, 1) > 0) {            if (debug) printf("[RX] %02X\n", byte);            if ((byte & 0x80) != 0) {                buffer[0] = byte;                state = 1;            } else if (state == 1) {                buffer[1] = byte;                state = 2;            } else if (state == 2) {                buffer[2] = byte;                state = 0;                unsigned char status = buffer[0] & 0xF0;                unsigned char channel = buffer[0] & 0x0F;                snd_seq_ev_clear(&ev);                snd_seq_ev_set_source(&ev, out_port);                snd_seq_ev_set_subs(&ev);                snd_seq_ev_set_direct(&ev);                if (status == 0x90 && buffer[2] > 0) {                    ev.type = SND_SEQ_EVENT_NOTEON;                    ev.data.note.channel = channel;                    ev.data.note.note = buffer[1];                    ev.data.note.velocity = buffer[2];                } else if (status == 0x80 || (status == 0x90 && buffer[2] == 0)) {                    ev.type = SND_SEQ_EVENT_NOTEOFF;                    ev.data.note.channel = channel;                    ev.data.note.note = buffer[1];                    ev.data.note.velocity = buffer[2];                } else if (status == 0xA0) {                    ev.type = SND_SEQ_EVENT_KEYPRESS;                    ev.data.note.channel = channel;                    ev.data.note.note = buffer[1];                    ev.data.note.velocity = buffer[2];                } else if (status == 0xB0) {                    ev.type = SND_SEQ_EVENT_CONTROLLER;                    ev.data.control.channel = channel;                    ev.data.control.param = buffer[1];                    ev.data.control.value = buffer[2];                } else if (status == 0xC0) {                    ev.type = SND_SEQ_EVENT_PGMCHANGE;                    ev.data.control.channel = channel;                    ev.data.control.value = buffer[1];                    state = 0; // only 1 data byte                } else if (status == 0xD0) {                    ev.type = SND_SEQ_EVENT_CHANPRESS;                    ev.data.control.channel = channel;                    ev.data.control.value = buffer[1];                    state = 0;                } else if (status == 0xE0) {                    int value = buffer[1] | (buffer[2] << 7);                    ev.type = SND_SEQ_EVENT_PITCHBEND;                    ev.data.control.channel = channel;                    ev.data.control.value = value - 8192;                } else {                    continue;                }                snd_seq_event_output_direct(seq, &ev);            }        }    }    return NULL;}void send_bytes(const unsigned char *data, int len, int client, int port) {    write(serial_fd, data, len);    if (debug) {        printf("[TX] %d:%d -- ", client, port);        for (int i = 0; i < len; ++i) {            printf("%02X ", data[i]);        }        printf("\n");    }}int main(int argc, char *argv[]) {    if (argc > 1 && strcmp(argv[1], "--debug") == 0) {        debug = 1;    }    pthread_t thread;    open_serial();    open_alsa_ports();    pthread_create(&thread, NULL, serial_to_midi, NULL);    snd_seq_event_t* ev;    while (1) {        snd_seq_event_input(seq, &ev);        int client = ev->source.client;        int port = ev->source.port;        switch (ev->type) {            case SND_SEQ_EVENT_NOTEON: {                unsigned char data[3] = {                    0x90 | ev->data.note.channel,                    ev->data.note.note,                    ev->data.note.velocity                };                send_bytes(data, 3, client, port);                break;            }            case SND_SEQ_EVENT_NOTEOFF: {                unsigned char data[3] = {                    0x80 | ev->data.note.channel,                    ev->data.note.note,                    ev->data.note.velocity                };                send_bytes(data, 3, client, port);                break;            }            case SND_SEQ_EVENT_CONTROLLER: {                unsigned char data[3] = {                    0xB0 | ev->data.control.channel,                    ev->data.control.param,                    ev->data.control.value                };                send_bytes(data, 3, client, port);                break;            }            case SND_SEQ_EVENT_PGMCHANGE: {                unsigned char data[2] = {                    0xC0 | ev->data.control.channel,                    ev->data.control.value                };                send_bytes(data, 2, client, port);                break;            }            case SND_SEQ_EVENT_CHANPRESS: {                unsigned char data[2] = {                    0xD0 | ev->data.control.channel,                    ev->data.control.value                };                send_bytes(data, 2, client, port);                break;            }            case SND_SEQ_EVENT_KEYPRESS: {                unsigned char data[3] = {                    0xA0 | ev->data.note.channel,                    ev->data.note.note,                    ev->data.note.velocity                };                send_bytes(data, 3, client, port);                break;            }            case SND_SEQ_EVENT_PITCHBEND: {                int value = ev->data.control.value + 8192;                unsigned char data[3] = {                    0xE0 | ev->data.control.channel,                    value & 0x7F,                    (value >> 7) & 0x7F                };                send_bytes(data, 3, client, port);                break;            }            case SND_SEQ_EVENT_SYSEX:                send_bytes((unsigned char*)ev->data.ext.ptr, ev->data.ext.len, client, port);                break;            default:                if (debug)                    printf("[TX] %d:%d -- Unsupported MIDI event type: %d\n", client, port, ev->type);                break;        }    }    return 0;}
I can see a unusual call also here... the client_id specifically seems to be missing in ttymidi-sysex

snd_seq_set_client_name(seq, "bento_ttymidi");
client_id = snd_seq_client_id(seq);

Also it seems bento_ttymidiis being used as a or after a .service
Screenshot 2025-06-29 at 08.25.29.png
sudo nano /etc/systemd/system/bento_ttymidi.service

sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable bento_ttymidi.service
sudo systemctl start bento_ttymidi.service

https://github.com/terioto/bento_ttymid ... _ttymidi.c

Statistics: Posted by Zool64Pi — Sun Jun 29, 2025 5:56 am



Viewing all articles
Browse latest Browse all 8374

Trending Articles