114 lines
3.7 KiB
C
114 lines
3.7 KiB
C
#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;
|
|
}
|