#include #include #include #include #include #include #include #include #include "midimcast.h" bool midimcast_debug; int snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, const char *name, snd_seq_t *seq_handle, int port, int merge, int mode); static void env_read_server(const char **const midi_in) { *midi_in = getenv("MIDI_IN"); if (!*midi_in) err("`MIDI_IN` unset"); debug("Using MIDI input %s", *midi_in); } // TODO: Debug messages // TODO: Const stuff static void midi_open(const char *const midi_in, snd_seq_t **seq, snd_rawmidi_t **input) { err_snd(snd_seq_open, seq, "default", SND_SEQ_OPEN_INPUT, 0); err_snd(snd_seq_set_client_name, *seq, "MIDI Broadcaster"); const int port = snd_seq_create_simple_port(*seq, "MIDI Broadcaster Input", SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SYNC_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_MIDI_GENERIC); err_snd(snd_rawmidi_virtual_open, input, NULL, "MIDI Broadcaster", *seq, port, true, SND_RAWMIDI_READ_STANDARD); snd_seq_client_info_t *client_info; snd_seq_client_info_alloca(&client_info); snd_seq_client_info_set_client(client_info, -1); snd_seq_addr_t src, dst; for (;;) { if (snd_seq_query_next_client(*seq, client_info)) err("Input '%s' absent", midi_in); if (strcmp(snd_seq_client_info_get_name(client_info), midi_in) == 0) { src.client = snd_seq_client_info_get_client(client_info); snd_seq_port_info_t *port_info; snd_seq_port_info_alloca(&port_info); snd_seq_port_info_set_client(port_info, src.client); snd_seq_port_info_set_port(port_info, -1); if (snd_seq_query_next_port(*seq, port_info)) err("Input '%s' has no ports", midi_in); src.port = snd_seq_port_info_get_port(port_info); break; } } dst.client = snd_seq_client_id(*seq); dst.port = port; snd_seq_port_subscribe_t *sub; snd_seq_port_subscribe_alloca(&sub); snd_seq_port_subscribe_set_sender(sub, &src); snd_seq_port_subscribe_set_dest(sub, &dst); err_snd(snd_seq_subscribe_port, *seq, sub); } // TODO: Naming static int sock_init(struct sockaddr_in *addr, const char *const mcast_group, const uint16_t mcast_port) { memset(addr, 0, sizeof(*addr)); addr->sin_family = AF_INET; addr->sin_addr.s_addr = inet_addr(mcast_group); addr->sin_port = htons(mcast_port); return err_std_neg(socket, AF_INET, SOCK_DGRAM, 0); } static void msg_write(struct msg *const msg, const size_t midi_size, const int out_sock, struct sockaddr_in *addr) { msg->ts = htole64(msg->ts); const size_t header_size = (void *)&msg->midi - (void *)&msg->ts; const size_t msg_size = header_size + midi_size; err_std_neg(sendto, out_sock, msg, msg_size, 0, (struct sockaddr *)addr, sizeof(*addr)); // TODO: Check enough written? } int main() { const char *mcast_group; uint16_t mcast_port; const char *midi_in; env_read_common(&mcast_group, &mcast_port); env_read_server(&midi_in); snd_seq_t *seq; snd_rawmidi_t *input; midi_open(midi_in, &seq, &input); struct sockaddr_in addr; const int sock = sock_init(&addr, mcast_group, mcast_port); for (;;) { struct msg msg; ssize_t nread = err_snd_neg(snd_rawmidi_read, input, &msg.midi, sizeof(msg.midi)); debug("Read %ld bytes", nread); msg.ts = now(); msg_write(&msg, nread, sock, &addr); } // TODO: Make these run err_snd(snd_rawmidi_close, input); err_snd(snd_seq_close, seq); err_std(close, sock); return EXIT_SUCCESS; }