MIDI/Talker.c

354 lines
9.9 KiB
C
Raw Normal View History

2024-08-07 16:54:01 -03:00
#include <alsa/asoundlib.h>
#include <stdio.h>
#include <stdlib.h>
//As funções do ALSA costumam retornar valores negativos para indicar falhas de execução. Este #define permite encapsular as chamadas de função em uma estrutura que verifica esse retorno e
//exibe uma mensagem de erro
#define CHK(stmt, msg) if((stmt) < 0) {puts("ERROR: "#msg); exit(1);}
//Parâmetros de entrada:
//handle: Varíavel que guarda o handle do sequenciador
//in_port_id: Variável que guarda o id da porta de entrada
//out_port_id: Variável que guarda o ida da porta de saída
//Descrição:
//Abre o ALSA Sequencer para entrada e saida e cria uma porta para cada função
int open_client(snd_seq_t** handle, int* in_port_id, int* out_port_id){
CHK(snd_seq_open(handle, "default", SND_SEQ_OPEN_DUPLEX, 0), "Could not open sequencer");
CHK(snd_seq_set_client_name(*handle, "Talker Client"), "Could not set client name");
CHK(*out_port_id = snd_seq_create_simple_port(*handle, "O-port", SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, SND_SEQ_PORT_TYPE_APPLICATION), "Could not open port");
CHK(*in_port_id = snd_seq_create_simple_port(*handle, "I-port", SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_APPLICATION), "Could not open port");
return 0;
}
//Parâmetros de entrada:
//seq_handle: Handle do sequenciador
//Descrição:
//Recebe o handle do sequenciador e retorna um evento mid recebido pela porta de entrada
snd_seq_event_t *midi_read(snd_seq_t* seq_handle)
{
snd_seq_event_t* ev = NULL;
snd_seq_event_input(seq_handle, &ev);
return ev;
}
//Parâmetros de entrada:
//value: Valor de controle do evento de entrada
//vel: Velocidade do evento de saída
//note: Nota do evento de saida
//handle: Handle do sequenciador
//Descrição:
//Traduz um evento do tipo controlador para um evento do tipo nota de acordo com a tecla que foi apertada
void send_note(int value, unsigned char vel, unsigned char note, snd_seq_t* handle){
//Declaração do evento de saida
snd_seq_event_t out_ev;
//Este trecho é necessário para preparar um evento para envio
snd_seq_ev_clear(&out_ev);
snd_seq_ev_set_source(&out_ev, 0);
snd_seq_ev_set_subs(&out_ev);
snd_seq_ev_set_direct(&out_ev);
snd_seq_ev_set_fixed(&out_ev);
//Quando um botão do controlador é apertado, ele envia um evento cujo valor de controle é 127
//Quando ele é solto, ele envia um segundo evento cujo o valor de controle é 0
//Assim, se o valor do controle for 0, o evento gerado pela tradução deve ser um NOTEOFF
if(value == 0){
out_ev.type = SND_SEQ_EVENT_NOTEOFF;
out_ev.data.note.velocity = 0;
}else{
out_ev.type = SND_SEQ_EVENT_NOTEON;
out_ev.data.note.velocity = vel;
}
out_ev.data.note.channel = 0;
out_ev.data.note.note = note;
//Os dois comandos abaixo são utilizados para fazer o envio do evento criado
snd_seq_event_output(handle, &out_ev);
snd_seq_drain_output(handle);
}
//Parâmetros de entrada:
//value: Valor de controle do evento de entrada
//vel: Velocidade da nota do evento de saída
//current_note: Nota que se encontra ativa
//handle: Handle do sequenciador
//Descrição:
//Essa é uma função similar a acima, porem adaptada para os botões de deslizar
//A ideia é que quando você mova o botão ele envie notas como se você estivesse deslizando a mão sobre teclas de piano
//A nota correspondente à posição que ele parou será mantida até que o botão seja movido de novo
//As notas só param quando o botão volta para a posição 0
int send_note_const(int value, unsigned char vel, unsigned char current_note, snd_seq_t* handle){
//Esse trecho é igual ao da função acima
snd_seq_event_t out_ev;
snd_seq_ev_clear(&out_ev);
snd_seq_ev_set_source(&out_ev, 0);
snd_seq_ev_set_subs(&out_ev);
snd_seq_ev_set_direct(&out_ev);
snd_seq_ev_set_fixed(&out_ev);
//____________________________________________________________
//Primeiro o programa envia um NOTEOFF para a nota que está tocando atualmente
out_ev.type = SND_SEQ_EVENT_NOTEOFF;
out_ev.data.note.channel = 0;
out_ev.data.note.note = current_note;
out_ev.data.note.velocity = 0;
snd_seq_event_output(handle, &out_ev);
snd_seq_drain_output(handle);
//Depois, se o valor de controle não for zero, ele envia um NOTEON para a nova nota que irá tocar
if(value != 0){
out_ev.type = SND_SEQ_EVENT_NOTEON;
out_ev.data.note.channel = 0;
//Note que a nota é determinada pelo valor de controle do evento de entrada
//O botão de deslizar varia o valor entre 0 e 127
//As notas MIDI são determinadas por números também dentro deste intervalo
out_ev.data.note.note = value;
out_ev.data.note.velocity = vel;
snd_seq_event_output(handle, &out_ev);
snd_seq_drain_output(handle);
}
}
int main(void){
//Declaração do handle(necessário para manipular o sequenciador) e do evento de entrada
snd_seq_t* handle;
snd_seq_event_t* ev;
//Essas variáveis guardam o número de identificação das portas de entrada e saida respectivamente
int id_in, id_out;
//O vetor vel[] guarda a velocidade definida pelos controles designados à função de regulá-la
//O vetor note[] guarda a nota que está sendo mantida pelos botões de deslizar
unsigned char vel[8];
unsigned char note[8];
//Inicialização dos vetores
int i;
for(i=0; i < 8; i++){
vel[i] = 0;
note[i] = 0;
}
//Abertura do Sequenciador ALSA
open_client(&handle, &id_in, &id_out);
//Este switch mapeia as teclas do controlador MIDI que eu estou usando (nanoKONTROL2)
while(1){
//Neste ponto o evento de entrada é lido
ev = midi_read(handle);
if(ev->type != SND_SEQ_EVENT_CONTROLLER) continue;
switch(ev->data.control.param){
case 58:
printf("ctrl: %d\n", ev->data.control.param);
break;
case 46:
printf("ctrl: %d\n", ev->data.control.param);
break;
case 43:
printf("ctrl: %d\n", ev->data.control.param);
break;
case 59:
printf("ctrl: %d\n", ev->data.control.param);
break;
case 44:
printf("ctrl: %d\n", ev->data.control.param);
break;
case 60:
printf("ctrl: %d\n", ev->data.control.param);
break;
case 42:
printf("ctrl: %d\n", ev->data.control.param);
break;
case 61:
printf("ctrl: %d\n", ev->data.control.param);
break;
case 41:
printf("ctrl: %d\n", ev->data.control.param);
break;
case 62:
printf("ctrl: %d\n", ev->data.control.param);
break;
case 45:
printf("ctrl: %d\n", ev->data.control.param);
break;
case 32:
send_note(ev->data.control.value, vel[0], 60, handle);
break;
case 48:
send_note(ev->data.control.value, vel[0], 61, handle);
break;
case 64:
send_note(ev->data.control.value, vel[0], 62, handle);
break;
case 16:
vel[0] = (unsigned char) ev->data.control.value;
break;
case 0:
send_note_const(ev->data.control.value, vel[0], note[0], handle);
note[0] = ev->data.control.value;
break;
case 33:
send_note(ev->data.control.value, vel[1], 63, handle);
break;
case 49:
send_note(ev->data.control.value, vel[1], 64, handle);
break;
case 65:
send_note(ev->data.control.value, vel[1], 65, handle);
break;
case 17:
vel[1] = (unsigned char) ev->data.control.value;
break;
case 1:
send_note_const(ev->data.control.value, vel[1], note[1], handle);
note[1] = ev->data.control.value;
break;
case 34:
send_note(ev->data.control.value, vel[2], 66, handle);
break;
case 50:
send_note(ev->data.control.value, vel[2], 67, handle);
break;
case 66:
send_note(ev->data.control.value, vel[2], 68, handle);
break;
case 18:
vel[2] = (unsigned char) ev->data.control.value;
break;
case 2:
send_note_const(ev->data.control.value, vel[2], note[2], handle);
note[2] = ev->data.control.value;
break;
case 35:
send_note(ev->data.control.value, vel[3], 69, handle);
break;
case 51:
send_note(ev->data.control.value, vel[3], 70, handle);
break;
case 67:
send_note(ev->data.control.value, vel[3], 71, handle);
break;
case 19:
vel[3] = (unsigned char) ev->data.control.value;
break;
case 3:
send_note_const(ev->data.control.value, vel[3], note[3], handle);
note[3] = ev->data.control.value;
break;
case 36:
send_note(ev->data.control.value, vel[4], 72, handle);
break;
case 52:
send_note(ev->data.control.value, vel[4], 73, handle);
break;
case 68:
send_note(ev->data.control.value, vel[4], 74, handle);
break;
case 20:
vel[4] = (unsigned char) ev->data.control.value;
break;
case 4:
send_note_const(ev->data.control.value, vel[4], note[4], handle);
note[4] = ev->data.control.value;
break;
case 37:
send_note(ev->data.control.value, vel[5], 75, handle);
break;
case 53:
send_note(ev->data.control.value, vel[5], 76, handle);
break;
case 69:
send_note(ev->data.control.value, vel[5], 77, handle);
break;
case 21:
vel[5] = (unsigned char) ev->data.control.value;
break;
case 5:
send_note_const(ev->data.control.value, vel[5], note[5], handle);
note[5] = ev->data.control.value;
break;
case 38:
send_note(ev->data.control.value, vel[6], 78, handle);
break;
case 54:
send_note(ev->data.control.value, vel[6], 79, handle);
break;
case 70:
send_note(ev->data.control.value, vel[6], 80, handle);
break;
case 22:
vel[6] = (unsigned char) ev->data.control.value;
break;
case 6:
send_note_const(ev->data.control.value, vel[6], note[6], handle);
note[6] = ev->data.control.value;
break;
case 39:
send_note(ev->data.control.value, vel[7], 81, handle);
break;
case 55:
send_note(ev->data.control.value, vel[7], 82, handle);
break;
case 71:
send_note(ev->data.control.value, vel[7], 83, handle);
break;
case 23:
vel[7] = (unsigned char) ev->data.control.value;
break;
case 7:
send_note_const(ev->data.control.value, vel[7], note[7], handle);
note[7] = ev->data.control.value;
break;
default:
printf("Unknow controller\n");
}
}
return 0;
}