Adicionei todos os arquivos

This commit is contained in:
bradoki 2024-08-07 16:54:01 -03:00
parent 8197b09d6b
commit cf2f1d461c
11 changed files with 2600 additions and 3 deletions

113
Chords.c Normal file
View File

@ -0,0 +1,113 @@
#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);}
#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;
}

295
ControlTunes.c Normal file
View File

@ -0,0 +1,295 @@
//Possui as funções MIDI
#include "MIDI_functions.c"
//Para o usleep
#include <unistd.h>
//Para o open()
#include <fcntl.h>
//Contem a biblioteca da manete
#include <linux/joystick.h>
//Para utilizar os threads, compilar com -pthread
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
//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;
}

118
MIDI_functions.h Normal file
View File

@ -0,0 +1,118 @@
#include <alsa/asoundlib.h> //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;
}

224
MIDI_joystick.h Normal file
View File

@ -0,0 +1,224 @@
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/joystick.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#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);
}

View File

@ -1,3 +1 @@
# MIDI 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.
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.

353
Talker.c Normal file
View File

@ -0,0 +1,353 @@
#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;
}

259
control.py Normal file
View File

@ -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)

452
map1.c Normal file
View File

@ -0,0 +1,452 @@
#include"MIDI_joystick.h"
#include<string.h>
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;
}

669
map2.c Normal file
View File

@ -0,0 +1,669 @@
#include"MIDI_joystick.h"
#include<string.h>
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;
}

41
repeater.c Normal file
View File

@ -0,0 +1,41 @@
#include <alsa/asoundlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.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);}
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;
}
}

75
sequencer.py Normal file
View File

@ -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()