From cf2f1d461c2bbe7ac5c61b130b97e97bea508112 Mon Sep 17 00:00:00 2001 From: Gabriel Lopes Rocha Date: Wed, 7 Aug 2024 16:54:01 -0300 Subject: [PATCH] Adicionei todos os arquivos --- Chords.c | 113 ++++++++ ControlTunes.c | 295 +++++++++++++++++++++ MIDI_functions.h | 118 +++++++++ MIDI_joystick.h | 224 ++++++++++++++++ README.md | 4 +- Talker.c | 353 +++++++++++++++++++++++++ control.py | 259 ++++++++++++++++++ map1.c | 452 ++++++++++++++++++++++++++++++++ map2.c | 669 +++++++++++++++++++++++++++++++++++++++++++++++ repeater.c | 41 +++ sequencer.py | 75 ++++++ 11 files changed, 2600 insertions(+), 3 deletions(-) create mode 100644 Chords.c create mode 100644 ControlTunes.c create mode 100644 MIDI_functions.h create mode 100644 MIDI_joystick.h create mode 100644 Talker.c create mode 100644 control.py create mode 100644 map1.c create mode 100644 map2.c create mode 100644 repeater.c create mode 100644 sequencer.py diff --git a/Chords.c b/Chords.c new file mode 100644 index 0000000..5281a93 --- /dev/null +++ b/Chords.c @@ -0,0 +1,113 @@ +#include +#include +#include + +//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);} +#define vel 60 + +//Parãmetros de entrada: +//handle: variável que guarda o handle do sequenciador (endereço de um ponteiro) +//port_id: variável que guarda o id da porta de saída (endereço de um inteiro) +//Descrição: +//Abre um cliente com o sequenciador ALSA e cria uma porta de saída para ele +int open_client(snd_seq_t** handle, int* port_id){ + CHK(snd_seq_open(handle, "default", SND_SEQ_OPEN_OUTPUT, 0), "Could not open sequencer"); + CHK(snd_seq_set_client_name(*handle, "Chords Client"), "Could not set client name"); + CHK(*port_id = snd_seq_create_simple_port(*handle, "Out", SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, SND_SEQ_PORT_TYPE_APPLICATION), "Could not open port"); +} + +//Parâmetros de entrada: +//handle: handle do sequenciador ALSA +//id: número de identificação da porta de saída +//note: nota que nomeia o acorde +//type: indica se deverá ser enviado um noteon ou um noteoff +//Descrição: +//Envia três eventos MIDI do tipo nota que formam um acorde maior da nota base(a nota mas a terceira e a quinta de sua escala) +void snd_chord(snd_seq_t* handle, int id, int note, int type){ + snd_seq_event_t event; + snd_seq_ev_set_subs(&event); + snd_seq_ev_set_direct(&event); + snd_seq_ev_set_source(&event, id); + if(type > 0){ + snd_seq_ev_set_noteon(&event, 0, note, vel); + snd_seq_event_output(handle, &event); + + snd_seq_ev_set_noteon(&event, 0, note + 2, vel); + snd_seq_event_output(handle, &event); + + snd_seq_ev_set_noteon(&event, 0, note + 4, vel); + snd_seq_event_output(handle, &event); + }else{ + snd_seq_ev_set_noteoff(&event, 0, note, 0); + snd_seq_event_output(handle, &event); + + snd_seq_ev_set_noteoff(&event, 0, note + 2, 0); + snd_seq_event_output(handle, &event); + + snd_seq_ev_set_noteoff(&event, 0, note + 4, 0); + snd_seq_event_output(handle, &event); + } + snd_seq_drain_output(handle); +} + +int main(int argc, char** argv){ + snd_seq_t* handle; + int port_id, i; + char key; +//O vetor state[] guarda se um acorde está ativo ou não +//Se o valor do vetor na posição correspondente ao acorde for 1 ele está inativo e a função snd_chord deve enviar eventos do tipo NOTEON +//Se o valor for -1, ele está ativo e a função snd_chord deve enviar eventos do tipo NOTEOFF +//Os 7 espaços do vetor estão associados às 7 notas Dó, Ré, Mi, Fá, Sol, Lá, Si respectivamente + int state[7]; + for(i = 0; i < 7; i++){ + state[i] = 1; + } + open_client(&handle, &port_id); + while(1){ + key = getchar(); + switch(key){ + case 'c': + snd_chord(handle, port_id, 60, state[0]); + state[0] = state[0] * -1; + break; + + case 'd': + snd_chord(handle, port_id, 62, state[1]); + state[1] = state[1] * -1; + break; + + case 'e': + snd_chord(handle, port_id, 64, state[2]); + state[2] = state[2] * -1; + break; + + case 'f': + snd_chord(handle, port_id, 65, state[3]); + state[3] = state[3] * -1; + break; + + case 'g': + snd_chord(handle, port_id, 67, state[4]); + state[4] = state[4] * -1; + break; + + case 'a': + snd_chord(handle, port_id, 69, state[5]); + state[5] = state[5] * -1; + break; + + case 'b': + snd_chord(handle, port_id, 71, state[6]); + state[6] = state[6] * -1; + break; + + default: + printf("wrong key\n"); + } + //Limpeza de buffer + while ((key = getchar()) != '\n' && key != EOF) { } + } + return 0; +} diff --git a/ControlTunes.c b/ControlTunes.c new file mode 100644 index 0000000..be6f291 --- /dev/null +++ b/ControlTunes.c @@ -0,0 +1,295 @@ +//Possui as funções MIDI +#include "MIDI_functions.c" +//Para o usleep +#include +//Para o open() +#include +//Contem a biblioteca da manete +#include +//Para utilizar os threads, compilar com -pthread +#include + +#include +#include +#include +#include + +//Constante da velocidade das notas +#define NOTEVEL 80 + +//Tem uma boa explicação sobre a API da manete no link abaixo +//https://www.kernel.org/doc/Documentation/input/joystick-api.txt + +//As variáveis abaixo guardam informações sobre os botões da manete +//button[x] == 0 <--> o botão x não está pressionado +int button[12]; +//axis[x] = valor da posição do eixo x (esse eixo pode ser horizontal ou vertical) +int axis[6]; +//note[x] = Última nota tocada pelo botão x +int note[4]; + +//step e base são usados para definir os caminhos entre as notas do controle +int step = 1; +int base = 60; + +//Parâmetros de entrada: +//msg: Struct contendo informações sobre o evento de entrada da manete +//handle: Handle do sequenciador MIDI +//port_id: ID da porta de saída +void joystick_callback(struct js_event msg, snd_seq_t* handle, int port_id){ + if(msg.type == JS_EVENT_BUTTON){ +//msg.number identifica o botão, msg.value diz se ele foi pressinado (1) ou solto (0) + button[msg.number] = msg.value; +//Este switch mapeia os botões da manete (escluindo o D-Pad) +//Esse mapeamento foi feito para a manete B-MAX (os valores variam de uma para a outra) + switch(msg.number){ + case 0: + //Triângulo + //Se o botão foi pressinado + if(msg.value){ + //Envio um NOTEON e guardo a nota que eu enviei + send_note(NOTEVEL, base, 0, handle, port_id); + note[0] = base; + //Se não + }else{ + //Envio um NOTEOFF para a nota guardada + send_note(0, note[0], 0, handle, port_id); + } + break; + case 1: + //Bolinha + if(msg.value){ + send_note(NOTEVEL, base + step, 0, handle, port_id); + note[1] = base + step; + }else{ + send_note(0, note[1], 0, handle, port_id); + } + break; + case 2: + //Xis + if(msg.value){ + send_note(NOTEVEL, base + 2*step, 0, handle, port_id); + note[2] = base + 2*step; + }else{ + send_note(0, note[2], 0, handle, port_id); + } + break; + case 3: + //Quadrado + if(msg.value){ + send_note(NOTEVEL, base + 3*step, 0, handle, port_id); + note[3] = base + 3*step; + }else{ + send_note(0, note[3], 0, handle, port_id); + } + break; + case 4: + //L2 + if(msg.value == 1){ + printf("L2 PRESSED\n"); + base -= 4; + }else{ + printf("L2 RELEASED\n"); + } + break; + case 5: + //R2 + if(msg.value == 1){ + printf("R2 PRESSED\n"); + base += 4; + }else{ + printf("R2 RELEASED\n"); + } + break; + case 6: + //L1 + if(msg.value == 1){ + printf("L1 PRESSED\n"); + base -= 1; + }else{ + printf("L1 RELEASED\n"); + } + break; + case 7: + //R1 + if(msg.value == 1){ + printf("R1 PRESSED\n"); + base += 1; + }else{ + printf("R1 RELEASED\n"); + } + break; + case 8: + //Select + //PANIC BUTTON + if(msg.value == 1){ + printf("SELECT PRESSED\n"); + int c; + for(c=0; c<128; c++){ + send_note(0, c, 0, handle, port_id); + } + }else{ + printf("SELECT RELEASED\n"); + } + break; + case 9: + //Start + if(msg.value == 1){ + printf("START PRESSED\n"); + }else{ + printf("START RELEASED\n"); + } + break; + case 10: + //L3 + if(msg.value == 1){ + printf("L3 PRESSED\n"); + }else{ + printf("L3 RELEASED\n"); + } + break; + case 11: + //R3 + if(msg.value == 1){ + printf("R3 PRESSED\n"); + }else{ + printf("R3 RELEASED\n"); + } + break; + } + }else if(msg.type == JS_EVENT_AXIS){ +//Nesse caso, msg.value guarda a posição do eixo + axis[msg.number] == msg.value; +//Este switch mapeia as alavancas e o D-PAD + switch(msg.number){ + case 0: +//Para eixos horizontais, os valores crescem da esquerda para a direita, com o 0 com centro + //L3 Horizontal + if(msg.value > 0){ + printf("AXIS 0 RIGHT\n"); + step = 3; + }else if(msg.value < 0){ + printf("AXIS 0 LEFT\n"); + step = 5; + }else{ + printf("AXIS 0 NEUTRAL\n"); + step = 1; + } + break; + case 1: +//Para eixoos verticais, os valores crescem de cima para baixo, com o 0 como centro + //L3 Vertical + if(msg.value > 0){ + printf("AXIS 1 DOWN\n"); + step = 4; + }else if(msg.value < 0){ + printf("AXIS 1 UP\n"); + step = 6; + }else{ + printf("AXIS 1 NEUTRAL\n"); + step = 1; + + } + break; + case 2: + //R3 Horizontal + if(msg.value > 0){ + printf("AXIS 2 RIGHT\n"); + }else if(msg.value < 0){ + printf("AXIS 2 LEFT\n"); + }else{ + printf("AXIS 2 NEUTRAL\n"); + } + break; + case 3: + //R3 Vertical + if(msg.value > 0){ + printf("AXIS 3 DOWN\n"); + }else if(msg.value < 0){ + printf("AXIS 3 UP\n"); + }else{ + printf("AXIS 3 NEUTRAL\n"); + } + break; + case 4: + //D-Pad Horizontal + if(msg.value > 0){ + printf("AXIS 4 RIGHT\n"); + }else if(msg.value < 0){ + printf("AXIS 4 LEFT\n"); + }else{ + printf("AXIS 4 NEUTRAL\n"); + } + break; + case 5: + //D-pad Vertical + if(msg.value > 0){ + printf("AXIS 5 DOWN\n"); + }else if(msg.value < 0){ + printf("AXIS 5 UP\n"); + }else{ + printf("AXIS 5 NEUTRAL\n"); + } + break; + } + } +} + +void *thread(void *vargp){ + struct js_event msg; + //Abre a conexão com a manete + char* device = "/dev/input/js0"; + int fd = open(device, O_RDONLY); + //Recebe o nome do dispositivo + char name[128]; + if (ioctl(fd, JSIOCGNAME(sizeof(name)), name) < 0) + strncpy(name, "Unknown", sizeof(name)); + //Recebe o número de eixos do dispositivo + char number_of_axes; + ioctl(fd, JSIOCGAXES, &number_of_axes); + //Recebe o número de botões do dispositivo + char number_of_buttons; + ioctl(fd, JSIOCGBUTTONS, &number_of_buttons); + //Abre um cliente com o sequenciador MIDI + snd_seq_t* handle; + int in_id, out_id; + open_client(&handle, &in_id, &out_id, "ControlTunes"); + + while(1){ + //Faz a leitura de um evento da manete, encerra a execução se não conseguir + if(read(fd, &msg, sizeof(struct js_event)) != sizeof(struct js_event)) { + exit(1); + }else{ + //Esse tipo de mensagem serve apenas para a inicialixação da manete e pode ser ignorada + if (msg.type == JS_EVENT_INIT){ + continue; + }else{ + //Chama a função de callback + joystick_callback(msg, handle, out_id); + } + usleep(10000); + } + } + + pthread_exit((void *)NULL); +} + +//Função de inicialização da manete +void joystick_inicialize(){ + int i; + //inicialização dos vetores do início do código + for(i=0; i<12; i++){ + button[i] = 0; + if(i<6) axis[i] = 0; + if(i<4) note[i] = -1; + } + pthread_t tid; + pthread_create(&tid, NULL, thread, NULL); + pthread_join(tid, NULL); + pthread_exit((void *)NULL); +} + +int main(){ + joystick_inicialize(); + return 0; +} diff --git a/MIDI_functions.h b/MIDI_functions.h new file mode 100644 index 0000000..33827ce --- /dev/null +++ b/MIDI_functions.h @@ -0,0 +1,118 @@ +#include //para compilar com essa biblioteca, precisa usar o -lasound + +//Algumas funções do ALSA retornam 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 cliente +//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 +//name: Nome do cliente +//Descrição: +//Abre um cliente com 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, char* name){ + CHK(snd_seq_open(handle, "default", SND_SEQ_OPEN_DUPLEX, 0), "Could not open sequencer"); +//Se não for necessário criar duas portas, basta mudar o valor acima para SND_SEQ_OPEN_INPUT (ou OUTPUT) e usar apenas uma das ultimas duas funções. + CHK(snd_seq_set_client_name(*handle, name), "Could not set client name"); +//A função acima define o nome do cliente, nesse caso "MIDI Client" + CHK(*out_port_id = snd_seq_create_simple_port(*handle, "Out", 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, "In", 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: +//vel: Velocidade do evento (0 - 127) +//note: Nota do evento (0 - 127) +//channel: Canal utilizado (Nota: para as aplicações atuais o canal pode ser o 0) +//handle: Handle do sequenciador +//port_id: id da porta de origem +//Descrição: +//Cria e faz o output de um evento MIDI do tipo NOTEON/NOTEOFF +void send_note(unsigned char vel, unsigned char note, int channel, snd_seq_t* handle, int port_id){ +//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, port_id); + snd_seq_ev_set_subs(&out_ev); + snd_seq_ev_set_direct(&out_ev); + snd_seq_ev_set_fixed(&out_ev); +//Se a velocidade do evento for 0, significa que ele é do tipo NOTEOFF + if(vel == 0){ + out_ev.type = SND_SEQ_EVENT_NOTEOFF; + }else{ + out_ev.type = SND_SEQ_EVENT_NOTEON; + } + out_ev.data.note.velocity = vel; + out_ev.data.note.channel = channel; + 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 +//param: Parâmetro do controle, indentifica qual controle foi utilizado (0 - 127) +//value: Valor do controle. Pode ser 127 ou 0 para um botão indicando se ele foi precionado ou solto respectivamente +// Para botões de deslizar, o valor varia dentro dessa faixa +//channel: Canda de destino do evento (Nota: para as aplicações atuais o canal pode ser o 0) +//handle: Handle do sequenciador +//port_id: id da porta de origem. +void send_control(unsigned char param, unsigned char value, int channel, snd_seq_t* handle, int port_id){ +//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, port_id); + snd_seq_ev_set_subs(&out_ev); + snd_seq_ev_set_direct(&out_ev); + snd_seq_ev_set_fixed(&out_ev); + + out_ev.type = SND_SEQ_EVENT_CONTROLLER; + + out_ev.data.control.param = param; + out_ev.data.control.value = value; + out_ev.data.control.channel = channel; +//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 +//param: Parâmetro do controle, indentifica qual controle foi utilizado (0 - 127) +//value: Valor do pitchbend. Varia entre -8192 e 8191. +//channel: Canda de destino do evento (Nota: para as aplicações atuais o canal pode ser o 0) +//handle: Handle do sequenciador +//port_id: id da porta de origem. +void send_pitchbend(unsigned char param, int value, int channel, snd_seq_t* handle, int port_id){ +//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, port_id); + snd_seq_ev_set_subs(&out_ev); + snd_seq_ev_set_direct(&out_ev); + snd_seq_ev_set_fixed(&out_ev); + + out_ev.type = SND_SEQ_EVENT_PITCHBEND; + + out_ev.data.control.param = param; + out_ev.data.control.value = value; + out_ev.data.control.channel = channel; +//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: +//seq_handle: Handle do sequenciador +//Descrição: +//Recebe o handle do sequenciador e retorna um evento MIDI recebido pela porta de entrada +//Nota: Eu acho que o snd_seq_event_input faz um malloc para preencher o ev. Nesse caso, seria necessário dar um free no ev depois. Preciso confirmar +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; +} diff --git a/MIDI_joystick.h b/MIDI_joystick.h new file mode 100644 index 0000000..0e98e72 --- /dev/null +++ b/MIDI_joystick.h @@ -0,0 +1,224 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "MIDI_functions.h" + +//Estrutura que encapsula o evento gerado por acionar a manete +typedef struct{ + int chain; + char* combo; //String de como caso esxista uma, NULL caso contrário + int* axis; //Vetor dos estados atuais dos eixos da manete + int* buttons; //Vetor dos estados atuais dos botões da manete + unsigned int type; //JS_EVENT_BUTTON, JS_EVENT_AXIS ou JS_EVENT_INIT + unsigned int id; //Identifica qual botão/eixo foi acionado + int value; //1(pressionado) ou 0(solto) para botões, [-32767, +32767] para eixos + unsigned int time; //tempo em que o botão foi pressionado em milisegundos + snd_seq_t* handle; //Handle do sequenciador MIDI alsa + int in_id; //ID da porta de entrada do sequenciador + int out_id; //ID da porta de saida do sequenciador +}t_mosaic_button_event; + +//Definição da assinatura da função callback de evento +typedef void (t_mosaic_joystick_event_callback_function)( + t_mosaic_button_event *event + ); + +//Deefinição da assinatura da função callback de registro +typedef void (t_mosaic_joystick_register_callback_function)( + char * device, + char * name, + char number_of_axes, + char number_of_buttons, + int driver_version + ); + +//Estrutura de cada device aberto, incluindo o caminho e as funções de callback +typedef struct { + t_mosaic_joystick_event_callback_function * event_callback_function; + t_mosaic_joystick_register_callback_function * register_callback_function; + char * device; +} t_mosaic_device_data; + +//Thread que abre e gerencia as informações e entradas de cada manete +void *joystick_thread(void *data){ + int buttons_pressed; + int chain; + //vetor que monitorará o estado atual dos eixos + int* axis; + //vetor que monitorará o estado atual dos butões + int* buttons; + //Variável auxiliar + int i; + //Se uma função de callback não foi especificada a thread se encerra logo no início + if (((t_mosaic_device_data *)data)->event_callback_function == NULL){ + pthread_exit((void *)NULL); + } + //Abertura do arquivo de entrada da manete + int fd = open(((t_mosaic_device_data *)data)->device, O_RDONLY); + //A chamada abaixo informa o nome do dispositivo + //Se o nome não puder ser recebido ele é definido como "Unknown" + char name[128]; + if (ioctl(fd, JSIOCGNAME(sizeof(name)), name) < 0) + strncpy(name, "Unknown", sizeof(name)); + //A chamada abaixo informa o número de eixos da manete + char number_of_axes; + ioctl(fd, JSIOCGAXES, &number_of_axes); + //Inicialização do vetor de eixos + axis = (int*)malloc((int)number_of_axes * sizeof(int)); + for(i = 0; i < (int)number_of_axes; i++) axis[i] = 0; + //A chamada abaixo informa o número de botões da manete + char number_of_buttons; + ioctl(fd, JSIOCGBUTTONS, &number_of_buttons); + //Inicialização do vetor de botões + buttons = (int*)malloc((int)number_of_buttons * sizeof(int)); + for(i = 0; i < number_of_buttons; i++) buttons[i] = 0; + //A chamada abaixo informa a versão do driver do dispositivo + int driver_version; + ioctl(fd,JSIOCGVERSION,&driver_version); + //Se houver uma função de callback para registro das informações, ela é chamada aqui + if (((t_mosaic_device_data *)data)->register_callback_function != NULL) + ((t_mosaic_device_data *)data)->register_callback_function( + ((t_mosaic_device_data *)data)->device, + name, + number_of_axes, + number_of_buttons, + driver_version); + + //Abre um cliente com o sequenciador MIDI + snd_seq_t* handle; + int in_id, out_id; + open_client(&handle, &in_id, &out_id, "ControlTunes"); + //A partir daqui os eventos das entradas da manete começam a serem lidos + t_mosaic_button_event *btn_event = (t_mosaic_button_event *) malloc(sizeof(btn_event)); + struct js_event msg; + //Primeiro os eventos de inicialização da manete são recebidos e ignorados + do{ + //Nesse e no laço abaixo, se ocorreu um erro na hora de ler o evento a thread se encerrra + if(read(fd, &msg, sizeof(struct js_event)) != sizeof(struct js_event)){ + printf("JOYSTICK INITIALAZING ERROR\n"); + pthread_exit((void *)NULL); + } + }while(msg.type == JS_EVENT_INIT); + //Combo Buffer + char* cbuffer; + int ccount; + unsigned int time; + cbuffer = (char*)malloc(128 * sizeof(char)); + ccount = 0; + time = 0; + buttons_pressed = 0; + //O laço abaixo faz o tratamento dos eventos verdadeiros + while(1) { + if(read(fd, &msg, sizeof(struct js_event)) != sizeof(struct js_event)){ + printf("EVENT READING ERROR\n"); + pthread_exit((void *)NULL); + } + //Esse trecho conta a quantidade de botões que estão em estado pressionado + if(msg.type == JS_EVENT_BUTTON){ + if(msg.value) buttons_pressed++; + else buttons_pressed--; + } + //Tratamento de Combo + if((msg.type == JS_EVENT_AXIS) && ((msg.number == 0) || (msg.number == 1) || (msg.number == 4) || (msg.number == 5))){ + if(ccount == 128) ccount = 0; + if((msg.time - time) > 500){ + ccount = 0; + } + if((msg.number % 2) != 0){ + if(msg.value == -32767){ + if(axis[msg.number - 1] == -32767) cbuffer[ccount++] = 7; + if(axis[msg.number - 1] == 0) cbuffer[ccount++] = 8; + if(axis[msg.number - 1] == 32767) cbuffer[ccount++] = 9; + } + if(msg.value == 32767){ + if(axis[msg.number - 1] == -32767) cbuffer[ccount++] = 1; + if(axis[msg.number - 1] == 0) cbuffer[ccount++] = 2; + if(axis[msg.number - 1] == 32767) cbuffer[ccount++] = 3; + } + if(msg.value == 0){ + if(axis[msg.number - 1] == -32767) cbuffer[ccount++] = 4; + //if(axis[msg.number - 1] == 0) ccount--; + if(axis[msg.number - 1] == 32767) cbuffer[ccount++] = 6; + } + }else{ + if(msg.value == -32767){ + if(axis[msg.number + 1] == -32767) cbuffer[ccount++] = 7; + if(axis[msg.number + 1] == 0) cbuffer[ccount++] = 4; + if(axis[msg.number + 1] == 32767) cbuffer[ccount++] = 1; + } + if(msg.value == 32767){ + if(axis[msg.number + 1] == -32767) cbuffer[ccount++] = 9; + if(axis[msg.number + 1] == 0) cbuffer[ccount++] = 6; + if(axis[msg.number + 1] == 32767) cbuffer[ccount++] = 3; + } + if(msg.value == 0){ + if(axis[msg.number + 1] == -32767) cbuffer[ccount++] = 8; + //if(axis[msg.number + 1] == 0) ccount--; + if(axis[msg.number + 1] == 32767) cbuffer[ccount++] = 2; + } + } + } + btn_event->combo = NULL; + //Se a entrada for um botão + if(msg.type == JS_EVENT_BUTTON){ + //Ele passará a string de combo caso ouver algum no buffer + if(ccount > 0){ + cbuffer[ccount] = '\0'; + btn_event->combo = cbuffer; + ccount = 0; + }else{ + //Se o botão for pressionado logo após outro e houver um combo desencadeado, ele também receberá o combo + //if(((msg.time - time) < 200) && chain && (msg.value == 1)) btn_event->combo = cbuffer; + //else chain = 0; + } + if(((msg.time - time) < 500)) btn_event->chain = 1; + else btn_event->chain = 0; + } + if(msg.type == JS_EVENT_AXIS){ + if(msg.number == 2 || msg.number == 3){ + if(ccount > 0){ + cbuffer[ccount] = '\0'; + btn_event->combo = cbuffer; + ccount = 0; + } + } + } + //Definição do btn_event + btn_event->type = msg.type; + btn_event->id = msg.number; + btn_event->value = msg.value; + btn_event->time = msg.time; + btn_event->handle = handle; + btn_event->in_id = in_id; + btn_event->out_id = out_id; + btn_event->axis = axis; + btn_event->buttons = buttons; + //A chamada da função de callback para os eventos se encontra aqui + ((t_mosaic_device_data *)data)->event_callback_function(btn_event); + //Atualização do estado do joystick + if(msg.type == JS_EVENT_AXIS) axis[msg.number] = msg.value; + if(msg.type == JS_EVENT_BUTTON) buttons[msg.number] = msg.value; + time = msg.time; + } +} + +//Parâmetros de entrada: +//device: string contendo o caminho para o arquivo de entrada +//event_callback_function: ponteiro para a função de callback para os eventos +//register_callback_function: ponteiro para a função de callback para o registro de informações +void joystick_inicialize(const char * device, + t_mosaic_joystick_event_callback_function * event_callback_function, + t_mosaic_joystick_register_callback_function * register_callback_function){ + t_mosaic_device_data * data = (t_mosaic_device_data *) malloc(sizeof(t_mosaic_device_data)); + data->device = (char *) malloc(strlen(device)); + strcpy(data->device, device); + data->event_callback_function = event_callback_function; + data->register_callback_function = register_callback_function; + pthread_t tid; + pthread_create(&tid, NULL, joystick_thread, data); +} diff --git a/README.md b/README.md index ccb1e66..b7aed1e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1 @@ -# MIDI - -Alguns códigos feitos para interagir com o protocolo MIDI. Inclui os códigos que transformam uma manete genérica de videogame em um controlador MIDI. \ No newline at end of file +This repository is related to my scientific recearch oriented by the professor Flávio Schiavoni in the Federal University of São João Del Rei (UFSJ) about aplications of the Computer Science in the artistic área. diff --git a/Talker.c b/Talker.c new file mode 100644 index 0000000..ffc35b7 --- /dev/null +++ b/Talker.c @@ -0,0 +1,353 @@ +#include +#include +#include + +//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; +} diff --git a/control.py b/control.py new file mode 100644 index 0000000..0974c94 --- /dev/null +++ b/control.py @@ -0,0 +1,259 @@ +#import evdev +from evdev import InputDevice, categorize, ecodes +import mido +import time +from threading import Thread +import signal +import sys + +#creates object 'gamepad' to store the data +#you can call it whatever you like +gamepad = InputDevice('/dev/input/event8') + +#prints out device info at start +print(gamepad) +outport = mido.open_output() + +class Note: + def __init__(self, cmd, val, vel, delay): + self.cmd = cmd + self.val = val + self.vel = vel + self.delay = delay + +class Loop(Thread): + def __init__ (self, ch): + Thread.__init__(self) + self.ch = ch + self.keep = True + self.time = 1 + self.seq = [] + + def run(self): + index = 0 + if len(self.seq) != 0: + while self.keep: + n = self.seq[index] + msg = mido.Message(n.cmd, note = n.val, velocity = n.vel) + outport.send(msg) + time.sleep(n.delay * self.time) + index = (index + 1)%len(self.seq) + +def terminateProcess(signalNumber, frame): + for i in range(0, 127): + msg = mido.Message('note_off', note = i, velocity = 0) + outport.send(msg) + print(' ') + sys.exit() + +buttons = { + 288: 60, + 289: 62, + 290: 64, + 291: 65, + 292: 67, + 293: 69, + 294: 71, + 295: 72 +} + +controls = { + 288: 0, + 289: 1, + 290: 2, + 291: 3, + 292: 4, + 293: 5, + 294: 6, + 295: 7, + 0: 8, + 1: 9, + 2: 10, + 5: 11, +} + +notes = { + 288: 0, + 289: 0, + 290: 0, + 291: 0, + 292: 0, + 293: 0, + 294: 0, + 295: 0 +} + +signal.signal(signal.SIGINT, terminateProcess) +Pad_X = 0 +Pad_Y = 0 +start = 0 +gravar = False + +def send_note(event): + if event.value == 1: + msg = mido.Message('note_on', note = buttons.get(event.code), velocity = 100) + notes[event.code] = buttons.get(event.code) + outport.send(msg) + else: + msg = mido.Message('note_off', note = notes.get(event.code), velocity = 0) + outport.send(msg) + +def send_control(event): + if event.type == 1: + msg = mido.Message('control_change', control = controls.get(event.code), value = event.value) + outport.send(msg) + if event.type == 3: + if event.code == 16: + if event.value == 1: + msg = mido.Message('control_change', control = 16, value = 1) + outport.send(msg) + Pad_X = 1 + if event.value == 0: + if Pad_X == 1: + msg = mido.Message('control_change', control = 16, value = 0) + outport.send(msg) + if Pad_X == -1: + msg = mido.Message('control_change', control = 17, value = 0) + outport.send(msg) + Pad_X = 0 + if event.value == -1: + msg = mido.Message('control_change', control = 17, value = 1) + outport.send(msg) + Pad_X = -1 + elif event.code == 17: + if event.value == 1: + msg = mido.Message('control_change', control = 18, value = 1) + outport.send(msg) + Pad_Y = 1 + if event.value == 0: + if Pad_Y == 1: + msg = mido.Message('control_change', control = 18, value = 0) + outport.send(msg) + if Pad_Y == -1: + msg = mido.Message('control_change', control = 17, value = 0) + outport.send(msg) + Pad_Y = 0 + if event.value == -1: + msg = mido.Message('control_change', control = 19, value = 1) + outport.send(msg) + Pad_Y = -1 + else: + val = int(event.value/255 * 127) + msg = mido.Message('control_change', control = controls.get(event.code), value = val) + outport.send(msg) + +def record(event, loop): + size = len(loop.seq) + if size > 0: + loop.seq[size - 1].delay = event.sec - loop.seq[size - 1].delay + if event.value == 1: + n = Note('note_on', buttons.get(event.code), 100, event.sec) + else: + n = Note('note_off', buttons.get(event.code), 0, event.sec) + loop.seq.append(n) + +#evdev takes care of polling the controller in a loop +for event in gamepad.read_loop(): + #print(event) + #Botão, codes 288 a 295 + if event.type == 1: + if event.code == 288: #TRIANGLE + #print("TRIANGLE") + send_note(event) + if gravar: + record(event, l) + if event.code == 289: #CIRCLE + #print("CIRCLE") + send_note(event) + if gravar: + record(event, l) + if event.code == 290: #XIS + #print("XIS") + send_note(event) + if gravar: + record(event, l) + if event.code == 291: #SQUARE + #print("SQUARE") + send_note(event) + if gravar: + record(event, l) + if event.code == 292: #L1 + #print("L1") + send_note(event) + if gravar: + record(event, l) + if event.code == 293: #R1 + #print("R1") + send_note(event) + if gravar: + record(event, l) + if event.code == 294: #L2 + #print("L2") + send_note(event) + if gravar: + record(event, l) + if event.code == 295: #R2 + #print("R2") + send_note(event) + if gravar: + record(event, l) + if event.code == 296: #SELECT + #print("SELECT") + send_control(event) + if event.code == 297: #START + #print("START") + if event.value == 1: + if start == 0: + gravar = True + l = Loop(1) + start = 1 + print("Gravando") + elif start == 1: + size = len(l.seq) + if size > 0: + l.seq[size - 1].delay = event.sec - l.seq[size - 1].delay + l.start() + print("Loop iniciado") + print(len(l.seq)) + for member in l.seq: + print(member.cmd) + print(member.val) + print(member.vel) + print(member.delay) + print(''); + start = 2 + else: + start = 0 + print("Loop nao iniciado") + gravar = False + elif start == 2: + l.keep = False + start = 0 + print("Loop interrompido") + + if event.code == 298: #L3 + #print("L3") + send_control(event) + if event.code == 299: #R3 + #print("R3") + send_control(event) + #Eixos + elif event.type == 3: + if event.code == 0: #LEFT JOYSTICK X AXIS + print("LEFT X AXIS") + send_control(event) + if event.code == 1: #LEFT JOYSTICK Y AXIS + print("LEFT Y AXIS") + send_control(event) + if event.code == 2: #RIGHT JOYSTICK X AXIS + print("RIGHT X AXIS") + send_control(event) + if event.code == 5: #RIGHT JOYSTICK Y AXIS + print("RIGHT Y AXIS") + send_control(event) + if event.code == 16: #D-PAD X AXIS + print("D-PAD X AXIS") + send_control(event) + if event.code == 17: #D-PAD Y AXIS + print("D-PAD Y AXIS") + send_control(event) diff --git a/map1.c b/map1.c new file mode 100644 index 0000000..0a06a6a --- /dev/null +++ b/map1.c @@ -0,0 +1,452 @@ +#include"MIDI_joystick.h" +#include + +char** combos; //Matriz de combos reconheciveis +int* entradas; //Vetor que guarda os combos reconhecidos +int base; //Valor base para a escala de notas na manete +int note_vel; //Valor da dinâmica da mensagem MIDI enviada +char** note; //Vetor que guarda as notas enviadas para ser efetuado um NOTEOFF depois + +void joystick_callback(t_mosaic_button_event *msg){ + //Declaração de variáveis + int i, s1, s2, aux; + //Interpretação da String de Combo + i = 0; + s1 = 0; + s2 = 0; + if(msg->combo){ + while(msg->combo[i] != '\0'){ + if(msg->combo[i] == combos[0][s1]){ + s1++; + if(s1 > 2){ + entradas[0]++; + s1 = 0; + } + }else s1 = 0; + if(msg->combo[i] == combos[1][s2]){ + s2++; + if(s2 > 2){ + entradas[1]++; + s2 = 0; + } + }else s2 = 0; + printf("%d ", msg->combo[i]); + i++; + } + printf("\n"); + } + //Interpretação do evento + handle = msg->handle; + port_id = msg->out_id; + if(msg->type == JS_EVENT_BUTTON){ + switch(msg->id){ + case 0: + //Triângulo + if(msg->value){ + send_note(note_vel, base + 9, 0, handle, port_id); + note[0][0] = base + 9; + //Combos + if(entradas[0]){ + send_note(note_vel, base + 13, 0, handle, port_id); + send_note(note_vel, base + 16, 0, handle, port_id); + note[0][1] = 1; + entradas[0] = 0; + } + if(entradas[1]){ + send_note(note_vel, base + 12, 0, handle, port_id); + send_note(note_vel, base + 16, 0, handle, port_id); + note[0][1] = 2; + entradas[1] = 0; + } + }else{ + send_note(0, note[0][0], 0, handle, port_id); + //Combos + if(note[0][1] & 1){ + send_note(0, note[0][0] + 4, 0, handle, port_id); + send_note(0, note[0][0] + 7, 0, handle, port_id); + note[0][1] = 0; + } + if(note[0][1] & 2){ + send_note(0, note[0][0] + 3, 0, handle, port_id); + send_note(0, note[0][0] + 7, 0, handle, port_id); + note[0][1] = 0; + } + } + break; + case 1: + //Bolinha + if(msg->value){ + send_note(note_vel, base + 12, 0, handle, port_id); + note[1][0] = base + 12; + //Combos + if(entradas[0]){ + send_note(note_vel, base + 16, 0, handle, port_id); + send_note(note_vel, base + 19, 0, handle, port_id); + note[1][1] = 1; + entradas[0] = 0; + } + if(entradas[1]){ + send_note(note_vel, base + 15, 0, handle, port_id); + send_note(note_vel, base + 19, 0, handle, port_id); + note[1][1] = 2; + entradas[1] = 0; + } + }else{ + send_note(0, note[1][0], 0, handle, port_id); + //Combos + if(note[1][1] & 1){ + send_note(0, note[1][0] + 4, 0, handle, port_id); + send_note(0, note[1][0] + 7, 0, handle, port_id); + note[1][1] = 0; + } + if(note[1][1] & 2){ + send_note(0, note[1][0] + 3, 0, handle, port_id); + send_note(0, note[1][0] + 7, 0, handle, port_id); + note[1][1] = 0; + } + } + break; + case 2: + //Xis + if(msg->value){ + send_note(note_vel, base + 11, 0, handle, port_id); + note[2][0] = base + 11; + //Combos + if(entradas[0]){ + send_note(note_vel, base + 15, 0, handle, port_id); + send_note(note_vel, base + 18, 0, handle, port_id); + note[2][1] |= 1; + entradas[0] = 0; + } + if(entradas[1]){ + send_note(note_vel, base + 14, 0, handle, port_id); + send_note(note_vel, base + 18, 0, handle, port_id); + note[2][1] |= 2; + entradas[1] = 0; + } + }else{ + send_note(0, note[2][0], 0, handle, port_id); + //Combos + if(note[2][1] & 1){ + send_note(0, note[2][0] + 4, 0, handle, port_id); + send_note(0, note[2][0] + 7, 0, handle, port_id); + note[2][1] -= 1; + } + if(note[2][1] & 2){ + send_note(0, note[2][0] + 3, 0, handle, port_id); + send_note(0, note[2][0] + 7, 0, handle, port_id); + note[2][1] -= 2; + } + } + break; + case 3: + //Quadrado + if(msg->value){ + send_note(note_vel, base + 7, 0, handle, port_id); + note[3][0] = base + 7; + //Combos + if(entradas[0]){ + send_note(note_vel, base + 11, 0, handle, port_id); + send_note(note_vel, base + 14, 0, handle, port_id); + note[3][1] = 1; + entradas[0] = 0; + } + if(entradas[1]){ + send_note(note_vel, base + 10, 0, handle, port_id); + send_note(note_vel, base + 14, 0, handle, port_id); + note[3][1] = 2; + entradas[1] = 0; + } + }else{ + send_note(0, note[3][0], 0, handle, port_id); + //Combos + if(note[3][1] & 1){ + send_note(0, note[3][0] + 4, 0, handle, port_id); + send_note(0, note[3][0] + 7, 0, handle, port_id); + note[3][1] = 0; + } + if(note[3][1] & 2){ + send_note(0, note[3][0] + 3, 0, handle, port_id); + send_note(0, note[3][0] + 7, 0, handle, port_id); + note[3][1] = 0; + } + } + break; + case 4: + //L2 + if(msg->value){ + send_note(note_vel, base, 0, handle, port_id); + note[4][0] = base; + //Combos + if(entradas[0]){ + send_note(note_vel, base + 4, 0, handle, port_id); + send_note(note_vel, base + 7, 0, handle, port_id); + note[4][1] = 1; + entradas[0] = 0; + } + if(entradas[1]){ + send_note(note_vel, base + 3, 0, handle, port_id); + send_note(note_vel, base + 7, 0, handle, port_id); + note[4][1] = 2; + entradas[1] = 0; + } + }else{ + send_note(0, note[4][0], 0, handle, port_id); + //Combos + if(note[4][1] & 1){ + send_note(0, note[4][0] + 4, 0, handle, port_id); + send_note(0, note[4][0] + 7, 0, handle, port_id); + note[4][1] = 0; + } + if(note[4][1] & 2){ + send_note(0, note[4][0] + 3, 0, handle, port_id); + send_note(0, note[4][0] + 7, 0, handle, port_id); + note[4][1] = 0; + } + } + break; + case 5: + //R2 + if(msg->value){ + send_note(note_vel, base + 2, 0, handle, port_id); + note[5][0] = base + 2; + //Combos + if(entradas[0]){ + send_note(note_vel, base + 6, 0, handle, port_id); + send_note(note_vel, base + 9, 0, handle, port_id); + note[5][1] = 1; + entradas[0] = 0; + } + if(entradas[1]){ + send_note(note_vel, base + 5, 0, handle, port_id); + send_note(note_vel, base + 9, 0, handle, port_id); + note[5][1] = 2; + entradas[1] = 0; + } + }else{ + send_note(0, note[5][0], 0, handle, port_id); + //Combos + if(note[5][1] & 1){ + send_note(0, note[5][0] + 4, 0, handle, port_id); + send_note(0, note[5][0] + 7, 0, handle, port_id); + note[5][1] = 0; + } + if(note[5][1] & 2){ + send_note(0, note[5][0] + 3, 0, handle, port_id); + send_note(0, note[5][0] + 7, 0, handle, port_id); + note[5][1] = 0; + } + } + break; + case 6: + //L1 + if(msg->value){ + send_note(note_vel, base + 4, 0, handle, port_id); + note[6][0] = base + 4; + //Combos + if(entradas[0]){ + send_note(note_vel, base + 8, 0, handle, port_id); + send_note(note_vel, base + 11, 0, handle, port_id); + note[6][1] = 1; + entradas[0] = 0; + } + if(entradas[1]){ + send_note(note_vel, base + 7, 0, handle, port_id); + send_note(note_vel, base + 11, 0, handle, port_id); + note[6][1] = 2; + entradas[1] = 0; + } + }else{ + send_note(0, note[6][0], 0, handle, port_id); + //Combos + if(note[6][1] & 1){ + send_note(0, note[6][0] + 4, 0, handle, port_id); + send_note(0, note[6][0] + 7, 0, handle, port_id); + note[6][1] = 0; + } + if(note[6][1] & 2){ + send_note(0, note[6][0] + 3, 0, handle, port_id); + send_note(0, note[6][0] + 7, 0, handle, port_id); + note[6][1] = 0; + } + } + break; + case 7: + //R1 + if(msg->value){ + send_note(note_vel, base + 5, 0, handle, port_id); + note[7][0] = base + 5; + //Combos + if(entradas[0]){ + send_note(note_vel, base + 9, 0, handle, port_id); + send_note(note_vel, base + 12, 0, handle, port_id); + note[7][1] = 1; + entradas[0] = 0; + } + if(entradas[1]){ + send_note(note_vel, base + 8, 0, handle, port_id); + send_note(note_vel, base + 12, 0, handle, port_id); + note[7][1] = 2; + entradas[1] = 0; + } + }else{ + send_note(0, note[7][0], 0, handle, port_id); + //Combos + if(note[7][1] & 1){ + send_note(0, note[7][0] + 4, 0, handle, port_id); + send_note(0, note[7][0] + 7, 0, handle, port_id); + note[7][1] = 0; + } + if(note[7][1] & 2){ + send_note(0, note[7][0] + 3, 0, handle, port_id); + send_note(0, note[7][0] + 7, 0, handle, port_id); + note[7][1] = 0; + } + } + break; + case 8: + //Select + //PANIC BUTTON + if(msg->value == 1){ + int c; + for(c=0; c<128; c++){ + send_note(0, c, 0, handle, port_id); + } + }else{ + + } + break; + case 9: + //Start + if(msg->value == 1){ + + }else{ + + } + break; + case 10: + //L3 + if(msg->value == 1){ + base -= 12; + printf("Base atual = %d\n", base); + }else{ + + } + break; + case 11: + //R3 + if(msg->value == 1){ + base += 12; + printf("Base atual = %d\n", base); + }else{ + + } + break; + } + }else if(msg->type == JS_EVENT_AXIS){ + switch(msg->id){ + case 0: + //Para eixos horizontais, os valores crescem da esquerda para a direita, com o 0 com centro + //L3 Horizontal + if(msg->value > 0){ + //Direita + }else if(msg->value < 0){ + //Esquerda + }else{ + //Neutro + } + break; + case 1: + //Para eixos verticais, os valores crescem de cima para baixo, com o 0 como centro + //L3 Vertical + if(msg->value > 0){ + //Baixo + }else if(msg->value < 0){ + //Cima + }else{ + //Neutro + } + break; + case 2: + //R3 Horizontal + //Este eixo envia uma mensagem MIDI de controle + aux = msg->value; + aux += 32767; + aux = (((double)aux / 65534.0) * 127); + send_control(1, (int)aux, 0, handle, port_id); + //______________________________________________ + if(msg->value > 0){ + //Direita + }else if(msg->value < 0){ + //Esquerda + }else{ + //Neutro + } + break; + case 3: + //R3 Vertical + //Este exio envia uma mensagem MIDI de Pitchbend + aux = msg->value; + aux = (((double)aux / 32767) * 8191); + send_pitchbend(3, (int)aux, 0, handle, port_id); + //_______________________________________________ + if(msg->value > 0){ + //Baixo + }else if(msg->value < 0){ + //Cima + }else{ + //Neutro + } + break; + case 4: + //D-Pad Horizontal + if(msg->value > 0){ + //Direita + }else if(msg->value < 0){ + //Esquerda + }else{ + //Neutro + } + break; + case 5: + //D-pad Vertical + if(msg->value > 0){ + //Baixo + }else if(msg->value < 0){ + //Cima + }else{ + //Neutro + } + break; + } + } +} + +int main(){ + //Definição dos Combos e das Entradas + int i; + base = 60; + note_vel = 80; + note = (char**)malloc(8 * sizeof(char*)); + for(i = 0; i < 8; i++){ + note[i] = (char*)malloc(2 * sizeof(char)); + note[i][0] = 0; + note[i][1] = -1; + } + entradas = (int*)malloc(2 * sizeof(int)); + combos = (char**)malloc(2 * sizeof(char*)); + for(i = 0; i < 2; i++){ + combos[i] = (char*)malloc(10 * sizeof(char)); + entradas[i] = 0; + } + combos[0][0] = 2; + combos[0][1] = 3; + combos[0][2] = 6; + combos[1][0] = 6; + combos[1][1] = 3; + combos[1][2] = 2; + //Inicialização da Manete + joystick_inicialize("/dev/input/js0", &joystick_callback, NULL); + while(1) usleep(10000); + return 0; +} diff --git a/map2.c b/map2.c new file mode 100644 index 0000000..66c920b --- /dev/null +++ b/map2.c @@ -0,0 +1,669 @@ +#include"MIDI_joystick.h" +#include + +char** combos; //Matriz de combos reconheciveis +int* comandos; //String contendo +int base; //Valor base para a escala de notas na manete +int note_vel; //Valor da dinâmica da mensagem MIDI enviada +char** note; //Vetor que guarda as notas enviadas para ser efetuado um NOTEOFF depois +#define c_qtd 5 +//Variaveis da alavanca direita +int R3_cmd[128]; +int R3toggle; +int ch; + +//Conexões atuais da controle +int axis_x; +int axis_y; +int rotation; + +void joystick_callback(t_mosaic_button_event *msg){ + //Declaração de variáveis + int i, j, k, t, aux, port_id, p_atual, p_anterior; + snd_seq_t* handle; + handle = msg->handle; + port_id = msg->out_id; + + if(!msg->chain){ + for(i = 0; i < 20; i++){ + comandos[i] = 0; + } + } + //Interpretação da String de Combo + if(msg->combo){ + j = 0; + while(msg->combo[j] != '\0'){ + printf("%d ", msg->combo[j]); + j++; + } + printf("\n"); + for(i = 0; i <= c_qtd; i++){ + j = 0; + k = 1; + //Navega pelo combo + while(msg->combo[j] != '\0'){ + //Verifica o padrão + if(msg->combo[j] == combos[i][k]){ + //Se padrão completo reconhecido + if(k == (combos[i][0])){ + comandos[i]++; + //Apago o trecho reconhecido para que ele não seja usado de novo + for(t = 0; t < k; t++){ + msg->combo[j - t] = 'x'; + } + k = 1; + }else{ + k++; + } + } + j++; + } + } + j = 0; + while(msg->combo[j] != '\0'){ + if(!comandos[c_qtd + 2]){ + if(msg->combo[j] == 4 && msg->combo[j+1] == 6){ + comandos[c_qtd + 1]++; + msg->combo[j] = 'x'; + msg->combo[j+1] = 'x'; + } + } + if(!comandos[c_qtd + 1]){ + if(msg->combo[j] == 6 && msg->combo[j+1] == 4){ + comandos[c_qtd + 2]++; + msg->combo[j] = 'x'; + msg->combo[j+1] = 'x'; + } + } + if(!comandos[c_qtd + 4]){ + if(msg->combo[j] == 2 && msg->combo[j+1] == 8){ + comandos[c_qtd + 3]++; + msg->combo[j] = 'x'; + msg->combo[j+1] = 'x'; + } + } + if(!comandos[c_qtd + 3]){ + if(msg->combo[j] == 8 && msg->combo[j+1] == 2){ + comandos[c_qtd + 4]++; + msg->combo[j] = 'x'; + msg->combo[j+1] = 'x'; + } + } + j++; + } + j = 0; + while(msg->combo[j] != '\0'){ + if(msg->combo[j] == 6) comandos[c_qtd + 5]++; + if(msg->combo[j] == 2) comandos[c_qtd + 6]++; + if(msg->combo[j] == 4) comandos[c_qtd + 7]++; + if(msg->combo[j] == 8) comandos[c_qtd + 8]++; + j++; + } + for(i = 0; i < 20; i++){ + printf("%d ", comandos[i]); + } + printf("\n"); + } + //Interpretação do evento + if(msg->type == JS_EVENT_BUTTON){ + //Mudança de oitava + while(comandos[c_qtd + 3] > 0){ + base += 12; + comandos[c_qtd + 3]--; + } + while(comandos[c_qtd + 4] > 0){ + base -= 12; + comandos[c_qtd + 4]--; + } + //Sustenido e Bemol + for(i = 0; i < comandos[c_qtd + 8]; i++){ + base++; + } + for(i = 0; i < comandos[c_qtd + 6]; i++){ + base--; + } + if(comandos[0]) ch = 3; + if(comandos[c_qtd + 7]) ch = 1; + if(comandos[c_qtd + 5]) ch = 2; + //Este switch identifica o botão pressionado + switch(msg->id){ + case 0: + //Triângulo + if(msg->value){ + //Envia uma nota MIDI caso pressionado + if(comandos[2]){ + send_note(note_vel, base + 9, ch, handle, port_id); + send_note(note_vel, base + 9 + 4, ch, handle, port_id); + send_note(note_vel, base + 9 + 7, ch, handle, port_id); + note[0][0] = base + 9; + note[0][1] = 0; + note[0][2] = ch; + }else{ + send_note(note_vel, base + 9, ch, handle, port_id); + note[0][0] = base + 9; + note[0][1] = -1; + note[0][2] = ch; + } + }else{ + //Envia um NOTEOFF para a ultima nota MIDI acionada + if(note[0][1] == -1){ + send_note(0, note[0][0], note[0][2], handle, port_id); + } + if(note[0][1] == 0){ + send_note(0, note[0][0], note[0][2], handle, port_id); + send_note(0, note[0][0] + 4, note[0][2], handle, port_id); + send_note(0, note[0][0] + 7, note[0][2], handle, port_id); + } + } + break; + case 1: + //Bolinha + if(msg->value){ + //Envia uma nota MIDI caso pressionado + if(comandos[2]){ + send_note(note_vel, base + 12, ch, handle, port_id); + send_note(note_vel, base + 12 + 4, ch, handle, port_id); + send_note(note_vel, base + 12 + 7, ch, handle, port_id); + note[1][0] = base + 12; + note[1][1] = 0; + note[1][2] = ch; + }else{ + send_note(note_vel, base + 12, ch, handle, port_id); + note[1][0] = base + 12; + note[1][1] = -1; + note[1][2] = ch; + } + }else{ + //Envia um NOTEOFF para a ultima nota MIDI acionada + if(note[1][1] == -1){ + send_note(0, note[1][0], note[1][2], handle, port_id); + } + if(note[1][1] == 0){ + send_note(0, note[1][0], note[1][2], handle, port_id); + send_note(0, note[1][0] + 4, note[1][2], handle, port_id); + send_note(0, note[1][0] + 7, note[1][2], handle, port_id); + } + } + break; + case 2: + //Xis + if(msg->value){ + //Envia uma nota MIDI caso pressionado + if(comandos[2]){ + send_note(note_vel, base + 11, ch, handle, port_id); + send_note(note_vel, base + 11 + 4, ch, handle, port_id); + send_note(note_vel, base + 11 + 7, ch, handle, port_id); + note[2][0] = base + 11; + note[2][1] = 0; + note[2][2] = ch; + }else{ + send_note(note_vel, base + 11, ch, handle, port_id); + note[2][0] = base + 11; + note[2][1] = -1; + note[2][2] = ch; + } + }else{ + //Envia um NOTEOFF para a ultima nota MIDI acionada + if(note[2][1] == -1){ + send_note(0, note[2][0], note[2][2], handle, port_id); + } + if(note[2][1] == 0){ + send_note(0, note[2][0], note[2][2], handle, port_id); + send_note(0, note[2][0] + 4, note[2][2], handle, port_id); + send_note(0, note[2][0] + 7, note[2][2], handle, port_id); + } + } + break; + case 3: + //Quadrado + if(msg->value){ + //Envia uma nota MIDI caso pressionado + if(comandos[2]){ + send_note(note_vel, base + 7, ch, handle, port_id); + send_note(note_vel, base + 7 + 4, ch, handle, port_id); + send_note(note_vel, base + 7 + 7, ch, handle, port_id); + note[3][0] = base + 7; + note[3][1] = 0; + note[3][2] = ch; + }else{ + send_note(note_vel, base + 7, ch, handle, port_id); + note[3][0] = base + 7; + note[3][1] = -1; + note[3][2] = ch; + } + }else{ + //Envia um NOTEOFF para a ultima nota MIDI acionada + if(note[3][1] == -1){ + send_note(0, note[3][0], note[3][2], handle, port_id); + } + if(note[3][1] == 0){ + send_note(0, note[3][0], note[3][2], handle, port_id); + send_note(0, note[3][0] + 4, note[3][2], handle, port_id); + send_note(0, note[3][0] + 7, note[3][2], handle, port_id); + } + } + break; + case 4: + //L2 + if(msg->value){ + //Envia uma nota MIDI caso pressionado + if(comandos[2]){ + send_note(note_vel, base, ch, handle, port_id); + send_note(note_vel, base + 4, ch, handle, port_id); + send_note(note_vel, base + 7, ch, handle, port_id); + note[4][0] = base; + note[4][1] = 0; + note[4][2] = ch; + }else{ + send_note(note_vel, base, ch, handle, port_id); + note[4][0] = base; + note[4][1] = -1; + note[4][2] = ch; + } + }else{ + //Envia um NOTEOFF para a ultima nota MIDI acionada + if(note[4][1] == -1){ + send_note(0, note[4][0], note[4][2], handle, port_id); + } + if(note[4][1] == 0){ + send_note(0, note[4][0], note[4][2], handle, port_id); + send_note(0, note[4][0] + 4, note[4][2], handle, port_id); + send_note(0, note[4][0] + 7, note[4][2], handle, port_id); + } + } + break; + case 5: + //R2 + if(msg->value){ + //Envia uma nota MIDI caso pressionado + if(comandos[2]){ + send_note(note_vel, base + 2, ch, handle, port_id); + send_note(note_vel, base + 2 + 4, ch, handle, port_id); + send_note(note_vel, base + 2 + 7, ch, handle, port_id); + note[5][0] = base + 2; + note[5][1] = 0; + note[5][2] = ch; + }else{ + send_note(note_vel, base + 2, ch, handle, port_id); + note[5][0] = base + 2; + note[5][1] = -1; + note[5][2] = ch; + } + }else{ + //Envia um NOTEOFF para a ultima nota MIDI acionada + if(note[5][1] == -1){ + send_note(0, note[5][0], note[5][2], handle, port_id); + } + if(note[5][1] == 0){ + send_note(0, note[5][0], note[5][2], handle, port_id); + send_note(0, note[5][0] + 4, note[5][2], handle, port_id); + send_note(0, note[5][0] + 7, note[5][2], handle, port_id); + } + } + break; + case 6: + //L1 + if(msg->value){ + //Envia uma nota MIDI caso pressionado + if(comandos[2]){ + send_note(note_vel, base + 4, ch, handle, port_id); + send_note(note_vel, base + 4 + 4, ch, handle, port_id); + send_note(note_vel, base + 4 + 7, ch, handle, port_id); + note[6][0] = base + 4; + note[6][1] = 0; + note[6][2] = ch; + }else{ + send_note(note_vel, base + 4, ch, handle, port_id); + note[6][0] = base + 4; + note[6][1] = -1; + note[6][2] = ch; + } + }else{ + //Envia um NOTEOFF para a ultima nota MIDI acionada + if(note[6][1] == -1){ + send_note(0, note[6][0], note[6][2], handle, port_id); + } + if(note[6][1] == 0){ + send_note(0, note[6][0], note[6][2], handle, port_id); + send_note(0, note[6][0] + 4, note[6][2], handle, port_id); + send_note(0, note[6][0] + 7, note[6][2], handle, port_id); + } + } + break; + case 7: + //R1 + if(msg->value){ + //Envia uma nota MIDI caso pressionado + if(comandos[2]){ + send_note(note_vel, base + 5, ch, handle, port_id); + send_note(note_vel, base + 5 + 4, ch, handle, port_id); + send_note(note_vel, base + 5 + 7, ch, handle, port_id); + note[7][0] = base + 5; + note[7][1] = 0; + note[7][2] = ch; + }else{ + send_note(note_vel, base + 5, ch, handle, port_id); + note[7][0] = base + 5; + note[7][1] = -1; + note[7][2] = ch; + } + }else{ + //Envia um NOTEOFF para a ultima nota MIDI acionada + if(note[7][1] == -1){ + send_note(0, note[7][0], note[7][2], handle, port_id); + } + if(note[7][1] == 0){ + send_note(0, note[7][0], note[7][2], handle, port_id); + send_note(0, note[7][0] + 4, note[7][2], handle, port_id); + send_note(0, note[7][0] + 7, note[7][2], handle, port_id); + } + } + break; + case 8: + //Select + //PANIC BUTTON + if(msg->value == 1){ + int c; + for(c=0; c<128; c++){ + send_note(0, c, 0, handle, port_id); + } + }else{ + + } + break; + case 9: + //Start + if(msg->value == 1){ + + }else{ + + } + break; + case 10: + //L3 + if(msg->value == 1){ + + }else{ + + } + break; + case 11: + //R3 + if(msg->value == 1){ + //Ativa/desativa a variável R3toggle cadavez que é pressionado + if(R3toggle == 0) R3toggle = 1; + else R3toggle = 0; + }else{ + + } + break; + } + for(i = 0; i < comandos[c_qtd + 8]; i++){ + base--; + } + for(i = 0; i < comandos[c_qtd + 6]; i++){ + base++; + } + ch = 0; + }else if(msg->type == JS_EVENT_AXIS){ + aux = -1; + if(comandos[c_qtd + 5]){ + while(comandos[c_qtd + 5]){ + aux = aux + 1; + comandos[c_qtd + 5]--; + } + }else if(comandos[c_qtd + 6] && !comandos[2] && !comandos[3]){ + aux = 15; + while(comandos[c_qtd + 6]){ + aux = aux + 1; + comandos[c_qtd + 6]--; + } + }else if(comandos[c_qtd + 7]){ + aux = 31; + while(comandos[c_qtd + 7]){ + aux = aux + 1; + comandos[c_qtd + 7]--; + } + }else if(comandos[c_qtd + 8] && !comandos[4] && !comandos[5]){ + aux = 47; + while(comandos[c_qtd + 8]){ + aux = aux + 1; + comandos[c_qtd + 8]--; + } + }else if(comandos[2]){ + aux = 63; + while(comandos[c_qtd + 6]){ + aux = aux + 1; + comandos[c_qtd + 6]--; + } + }else if(comandos[3]){ + aux = 78; + while(comandos[c_qtd + 6]){ + aux = aux + 1; + comandos[c_qtd + 6]--; + } + }else if(comandos[4]){ + aux = 94; + while(comandos[c_qtd + 8]){ + aux = aux + 1; + comandos[c_qtd + 8]--; + } + }else if(comandos[5]){ + aux = 110; + while(comandos[c_qtd + 8]){ + aux = aux + 1; + comandos[c_qtd + 8]--; + } + } + switch(msg->id){ + case 0: + //Para eixos horizontais, os valores crescem da esquerda para a direita, com o 0 com centro + //L3 Horizontal + if(msg->value > 0){ + //Direita + }else if(msg->value < 0){ + //Esquerda + }else{ + //Neutro + } + break; + case 1: + //Para eixos verticais, os valores crescem de cima para baixo, com o 0 como centro + //L3 Vertical + if(msg->value > 0){ + //Baixo + }else if(msg->value < 0){ + //Cima + }else{ + //Neutro + } + break; + case 2: + //R3 Horizontal + if(!R3toggle){ + if(aux > -1){ + axis_y = aux; + printf("Horizontal controlando %d\n", axis_y); + } + //______________________________________________ + //Este eixo envia uma mensagem MIDI de controle + aux = msg->value; + aux += 32767; + aux = (((double)aux / 65534.0) * 127); + send_control(axis_y, (int)aux, 0, handle, port_id); + //______________________________________________ + }else{ + //Seleção de controlador para a rotação + if(aux > -1){ + rotation = aux; + printf("Rotação controlando %d\n", rotation); + } + //___________________________________________ + if(msg->axis[3] == 32767){ + p_atual = msg->value + 32767; + p_atual = (((double)p_atual / 65534.0) * 4); + p_anterior = msg->axis[2] + 32767; + p_anterior = (((double)p_anterior / 65534.0) * 4); + if(p_atual > p_anterior) R3_cmd[rotation]--; + if(p_atual < p_anterior) R3_cmd[rotation]++; + } + if(msg->axis[3] == -32767){ + p_atual = msg->value + 32767; + p_atual = (((double)p_atual / 65534.0) * 4); + p_anterior = msg->axis[2] + 32767; + p_anterior = (((double)p_anterior / 65534.0) * 4); + if(p_atual > p_anterior) R3_cmd[rotation]++; + if(p_atual < p_anterior) R3_cmd[rotation]--; + } + if(R3_cmd[rotation] > 127) R3_cmd[rotation] = 127; + if(R3_cmd[rotation] < 0) R3_cmd[rotation] = 0; + send_control(rotation, R3_cmd[rotation], 0, handle, port_id); + } + if(msg->value > 0){ + //Direita + }else if(msg->value < 0){ + //Esquerda + }else{ + //Neutro + } + break; + case 3: + //R3 Vertical + if(!R3toggle){ + if(aux > -1){ + axis_x = aux; + printf("Vertical controlando %d\n", axis_x); + } + //Este exio envia uma mensagem MIDI de Pitchbend + aux = msg->value; + aux += 32767; + aux = (((double)aux / 65534.0) * 127); + send_control(axis_x, (int)aux, 0, handle, port_id); + //_______________________________________________ + }else{ + if(aux > -1){ + rotation = aux; + printf("Rotação controlando %d\n", rotation); + } + if(msg->axis[2] == 32767){ + p_atual = msg->value + 32767; + p_atual = (((double)p_atual / 65534.0) * 4); + p_anterior = msg->axis[3] + 32767; + p_anterior = (((double)p_anterior / 65534.0) * 4); + if(p_atual > p_anterior) R3_cmd[rotation]++; + if(p_atual < p_anterior) R3_cmd[rotation]--; + } + if(msg->axis[2] == -32767){ + p_atual = msg->value + 32767; + p_atual = (((double)p_atual / 65534.0) * 4); + p_anterior = msg->axis[3] + 32767; + p_anterior = (((double)p_anterior / 65534.0) * 4); + if(p_atual > p_anterior) R3_cmd[rotation]--; + if(p_atual < p_anterior) R3_cmd[rotation]++; + } + if(R3_cmd[rotation] > 127) R3_cmd[rotation] = 127; + if(R3_cmd[rotation] < 0) R3_cmd[rotation] = 0; + send_control(rotation, R3_cmd[rotation], 0, handle, port_id); + } + if(msg->value > 0){ + //Baixo + }else if(msg->value < 0){ + //Cima + }else{ + //Neutro + } + break; + case 4: + //D-Pad Horizontal + if(msg->value > 0){ + //Direita + }else if(msg->value < 0){ + //Esquerda + }else{ + //Neutro + } + break; + case 5: + //D-pad Vertical + if(msg->value > 0){ + //Baixo + }else if(msg->value < 0){ + //Cima + }else{ + //Neutro + } + break; + } + } +} + +int main(){ + int i; + //Inicialização de valores globais + base = 60; + note_vel = 80; + R3toggle = 0; + axis_x = 0; + axis_y = 1; + ch = 0; + rotation = 0; + //Inicialização do vetor de notas disparadas + //Este vetor é usado para dar NOTEOFF nas notas corretas + note = (char**)malloc(8 * sizeof(char*)); + for(i = 0; i < 8; i++){ + note[i] = (char*)malloc(3 * sizeof(char)); + note[i][0] = 0; + note[i][1] = -1; + note[i][2] = 0; + } + //Inicialização do vetor de comandos reconhecidos e do vetor de combos reconhecíveis + comandos = (int*)malloc(20 * sizeof(int)); + combos = (char**)malloc(20 * sizeof(char*)); + for(i = 0; i < 20; i++){ + combos[i] = (char*)malloc(10 * sizeof(char)); + comandos[i] = 0; + } + for(i = 0; i < 128; i++){ + R3_cmd[i] = 0; + } + //Lista de combos reconhecíveis + //41236 + combos[0][0] = 5; + combos[0][1] = 4; + combos[0][2] = 1; + combos[0][3] = 2; + combos[0][4] = 3; + combos[0][5] = 6; + //63214 + combos[1][0] = 5; + combos[1][1] = 6; + combos[1][2] = 3; + combos[1][3] = 2; + combos[1][4] = 1; + combos[1][5] = 4; + //236 + combos[2][0] = 3; + combos[2][1] = 2; + combos[2][2] = 3; + combos[2][3] = 6; + //214 + combos[3][0] = 3; + combos[3][1] = 2; + combos[3][2] = 1; + combos[3][3] = 4; + //896 + combos[4][0] = 3; + combos[4][1] = 8; + combos[4][2] = 9; + combos[4][3] = 6; + //874 + combos[5][0] = 3; + combos[5][1] = 8; + combos[5][2] = 7; + combos[5][3] = 4; + + //Inicialização da Manete + joystick_inicialize("/dev/input/js0", &joystick_callback, NULL); + while(1) usleep(10000); + return 0; +} diff --git a/repeater.c b/repeater.c new file mode 100644 index 0000000..3e3d13c --- /dev/null +++ b/repeater.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include + +//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);} + +int open_client(snd_seq_t** handle, int* port_id){ + CHK(snd_seq_open(handle, "default", SND_SEQ_OPEN_OUTPUT, 0), "Could not open sequencer"); + CHK(snd_seq_set_client_name(*handle, "Repetidor"), "Could not set client name"); + CHK(*port_id = snd_seq_create_simple_port(*handle, "Out", SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, SND_SEQ_PORT_TYPE_APPLICATION), "Could not open port"); +} + +int main(int argc, char** argv){ + snd_seq_t* handle; + int port_id, c, note; + open_client(&handle, &port_id); + snd_seq_event_t event; + snd_seq_ev_set_source(&event, port_id); + snd_seq_ev_set_subs(&event); + snd_seq_ev_set_direct(&event); + c = 1; + note = 36; + while(1){ + snd_seq_ev_set_noteon(&event, 0, note, 60); + snd_seq_event_output(handle, &event); + snd_seq_drain_output(handle); + + usleep(50000); + + snd_seq_ev_set_noteoff(&event, 0, note, 0); + snd_seq_event_output(handle, &event); + snd_seq_drain_output(handle); + + if(note == 96) c = -1; + else if(note == 32) c = 1; + note = note + c; + } +} diff --git a/sequencer.py b/sequencer.py new file mode 100644 index 0000000..cdb7a43 --- /dev/null +++ b/sequencer.py @@ -0,0 +1,75 @@ +import mido +import time +from threading import Thread +import signal +import sys + +class Note: + def __init__(self, cmd, val, vel, delay): + self.cmd = cmd + self.val = val + self.vel = vel + self.delay = delay + +class Loop(Thread): + def __init__ (self, ch): + Thread.__init__(self) + self.ch = ch + self.keep = True + self.time = 1 + self.seq = [] + + def run(self): + index = 0 + if len(self.seq) != 0: + while self.keep: + n = self.seq[index] + msg = mido.Message(n.cmd, note = n.val, velocity = n.vel) + outport.send(msg) + time.sleep(n.delay * self.time) + index = (index + 1)%len(self.seq) + +def terminateProcess(signalNumber, frame): + for i in range(0, 127): + msg = mido.Message('note_off', note = i, velocity = 0) + outport.send(msg) + print(' ') + sys.exit() + +signal.signal(signal.SIGINT, terminateProcess) +outport = mido.open_output() +l = Loop(1) + +n1 = Note('note_on', 60, 100, 0.5) +l.seq.append(n1) +n2 = Note('note_off', 60, 0, 0.01) +l.seq.append(n2) +n3 = Note('note_on', 62, 100, 0.5) +l.seq.append(n3) +n4 = Note('note_off', 62, 0, 0.01) +l.seq.append(n4) +n5 = Note('note_on', 64, 100, 0.5) +l.seq.append(n5) +n6 = Note('note_off', 64, 0, 0.01) +l.seq.append(n6) +n7 = Note('note_on', 65, 100, 0.5) +l.seq.append(n7) +n8 = Note('note_off', 65, 0, 0.01) +l.seq.append(n8) +n9 = Note('note_on', 67, 100, 0.5) +l.seq.append(n9) +n10 = Note('note_off', 67, 0, 0.01) +l.seq.append(n10) +n11 = Note('note_on', 69, 100, 0.5) +l.seq.append(n11) +n12 = Note('note_off', 69, 0, 0.01) +l.seq.append(n12) +n13 = Note('note_on', 71, 100, 0.5) +l.seq.append(n13) +n14 = Note('note_off', 71, 0, 0.01) +l.seq.append(n14) +n15 = Note('note_on', 72, 100, 0.5) +l.seq.append(n15) +n16 = Note('note_off', 72, 0, 0.01) +l.seq.append(n16) +l.start()