|
|
|
|
|
|
|
|
#include <alsa/asoundlib.h> |
|
|
#include <alsa/asoundlib.h> |
|
|
#include <pthread.h> /* for threading */ |
|
|
#include <pthread.h> /* for threading */ |
|
|
#include <lo/lo.h> |
|
|
#include <lo/lo.h> |
|
|
#include "mapping.h" |
|
|
|
|
|
|
|
|
#include <unistd.h> |
|
|
|
|
|
|
|
|
|
|
|
#define ZONE_COUNT 0x1e |
|
|
|
|
|
#define PORT_COUNT 196 |
|
|
|
|
|
#define DISPLAY_COUNT 9 |
|
|
|
|
|
|
|
|
|
|
|
enum display_type { |
|
|
|
|
|
LABEL, |
|
|
|
|
|
VPOT |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
|
|
char zone; |
|
|
|
|
|
char port; |
|
|
|
|
|
void* io; |
|
|
|
|
|
} Hui_MIDI_port_t; |
|
|
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
|
|
int type; |
|
|
|
|
|
int id; |
|
|
|
|
|
void* io; |
|
|
|
|
|
} Hui_display_port_t; |
|
|
|
|
|
|
|
|
typedef struct { |
|
|
typedef struct { |
|
|
snd_rawmidi_t* midiin; |
|
|
snd_rawmidi_t* midiin; |
|
|
snd_rawmidi_t* midiout; |
|
|
snd_rawmidi_t* midiout; |
|
|
lo_address osc_out; |
|
|
lo_address osc_out; |
|
|
|
|
|
lo_server_thread osc_in; |
|
|
unsigned char hui_in_zone; |
|
|
unsigned char hui_in_zone; |
|
|
|
|
|
int hui_in_fader_hi[8]; |
|
|
|
|
|
Hui_MIDI_port_t MIDIouts[PORT_COUNT]; |
|
|
|
|
|
Hui_display_port_t display_outs[DISPLAY_COUNT]; |
|
|
} housicIO; |
|
|
} housicIO; |
|
|
|
|
|
|
|
|
typedef struct { |
|
|
typedef struct { |
|
|
|
|
|
|
|
|
char* address; |
|
|
char* address; |
|
|
} Item; |
|
|
} Item; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char *ZONES[] = { |
|
|
char *ZONES[] = { |
|
|
"channel_strip_1", |
|
|
"channel_strip_1", |
|
|
"channel_strip_2", |
|
|
"channel_strip_2", |
|
|
|
|
|
|
|
|
"misc" |
|
|
"misc" |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
char *BUTTONS[0x1e][8] = { |
|
|
|
|
|
|
|
|
char *BUTTONS[ZONE_COUNT][8] = { |
|
|
{"fader","select","mute","solo","auto","v-sel","insert","rec_rdy"}, |
|
|
{"fader","select","mute","solo","auto","v-sel","insert","rec_rdy"}, |
|
|
{"fader","select","mute","solo","auto","v-sel","insert","rec_rdy"}, |
|
|
{"fader","select","mute","solo","auto","v-sel","insert","rec_rdy"}, |
|
|
{"fader","select","mute","solo","auto","v-sel","insert","rec_rdy"}, |
|
|
{"fader","select","mute","solo","auto","v-sel","insert","rec_rdy"}, |
|
|
|
|
|
|
|
|
{"switch_1","switch_2","click","beep"} |
|
|
{"switch_1","switch_2","click","beep"} |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// function declarations: |
|
|
// function declarations: |
|
|
void alsa_error (const char *format, ...); |
|
|
void alsa_error (const char *format, ...); |
|
|
void* midiinfunction (void * arg); |
|
|
void* midiinfunction (void * arg); |
|
|
|
|
|
void* ping (void * arg); |
|
|
void midi_in_dispatch (void * arg, unsigned char * m); |
|
|
void midi_in_dispatch (void * arg, unsigned char * m); |
|
|
void lo_error (int num, const char *m, const char *path); |
|
|
void lo_error (int num, const char *m, const char *path); |
|
|
int osc_in_handler (const char *path, const char *types, lo_arg ** argv, |
|
|
int osc_in_handler (const char *path, const char *types, lo_arg ** argv, |
|
|
int argc, void *data, void *user_data); |
|
|
int argc, void *data, void *user_data); |
|
|
void hui_in_button (void *arg, unsigned char m); |
|
|
void hui_in_button (void *arg, unsigned char m); |
|
|
|
|
|
void hui_in_scroll (void *arg, unsigned char port, unsigned char vv); |
|
|
|
|
|
void hui_in_fader (void *arg, unsigned char fader, int val); |
|
|
void osc_send (void *arg, Item el, float value); |
|
|
void osc_send (void *arg, Item el, float value); |
|
|
void register_osc_receives(); |
|
|
|
|
|
|
|
|
void register_osc_receives(void *arg); |
|
|
|
|
|
int osc_in_button_handler(const char *path, const char *types, lo_arg ** argv, |
|
|
|
|
|
int argc, void *data, void *user_data); |
|
|
|
|
|
int osc_in_label_handler (const char *path, const char *types, lo_arg ** argv, |
|
|
|
|
|
int argc, void *data, void *user_data); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int main(int argc, char *argv[]) { |
|
|
int main(int argc, char *argv[]) { |
|
|
int status; |
|
|
int status; |
|
|
int mode = SND_RAWMIDI_SYNC; |
|
|
int mode = SND_RAWMIDI_SYNC; |
|
|
pthread_t midiinthread; |
|
|
pthread_t midiinthread; |
|
|
lo_server_thread st = lo_server_thread_new("7770", lo_error); |
|
|
|
|
|
housicIO IOs = {NULL,NULL,0,0}; |
|
|
|
|
|
|
|
|
pthread_t pingthread; |
|
|
|
|
|
housicIO IOs = {NULL,NULL,0,NULL,0,{0,0,0,0,0,0,0,0},0}; |
|
|
IOs.osc_out = lo_address_new(NULL,"7771"); |
|
|
IOs.osc_out = lo_address_new(NULL,"7771"); |
|
|
|
|
|
IOs.osc_in = lo_server_thread_new("7770", lo_error); |
|
|
|
|
|
|
|
|
const char* portname = "virtual"; |
|
|
const char* portname = "virtual"; |
|
|
|
|
|
|
|
|
// MIDI |
|
|
// MIDI |
|
|
|
|
|
if ((status = snd_rawmidi_open(NULL, &IOs.midiout, portname, mode)) < 0) { |
|
|
|
|
|
alsa_error("Problem opening MIDI output: %s", snd_strerror(status)); |
|
|
|
|
|
exit(1); |
|
|
|
|
|
} |
|
|
if ((status = snd_rawmidi_open(&IOs.midiin, NULL, portname, mode)) < 0) { |
|
|
if ((status = snd_rawmidi_open(&IOs.midiin, NULL, portname, mode)) < 0) { |
|
|
alsa_error("Problem opening MIDI input: %s", snd_strerror(status)); |
|
|
alsa_error("Problem opening MIDI input: %s", snd_strerror(status)); |
|
|
exit(1); |
|
|
exit(1); |
|
|
} |
|
|
} |
|
|
|
|
|
status = pthread_create(&pingthread,NULL, ping, &IOs); |
|
|
status = pthread_create(&midiinthread, NULL, midiinfunction, &IOs); |
|
|
status = pthread_create(&midiinthread, NULL, midiinfunction, &IOs); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// OSC |
|
|
// OSC |
|
|
register_osc_receives(); |
|
|
|
|
|
lo_server_thread_add_method(st, NULL, NULL, osc_in_handler, NULL); |
|
|
|
|
|
lo_server_thread_start(st); |
|
|
|
|
|
|
|
|
register_osc_receives(&IOs); |
|
|
|
|
|
//lo_server_thread_add_method(IOs.osc_in, NULL, NULL, osc_in_handler, NULL); |
|
|
|
|
|
lo_server_thread_start(IOs.osc_in); |
|
|
|
|
|
|
|
|
// wait for MIDI thread to end (will not happen) |
|
|
// wait for MIDI thread to end (will not happen) |
|
|
pthread_join(midiinthread, NULL); |
|
|
pthread_join(midiinthread, NULL); |
|
|
|
|
|
|
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////// |
|
|
|
|
|
// |
|
|
|
|
|
// ping -- It is important to send a ping in regular intervals. This |
|
|
|
|
|
// will keep the HUI in online mode. |
|
|
|
|
|
// |
|
|
|
|
|
void *ping(void *arg) { |
|
|
|
|
|
housicIO* IOs = (housicIO*)arg; |
|
|
|
|
|
char message[] = {0x90,0x00,0x00}; |
|
|
|
|
|
|
|
|
|
|
|
while (1) { |
|
|
|
|
|
sleep(1); |
|
|
|
|
|
snd_rawmidi_write(IOs->midiout,message,3); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////// |
|
|
////////////////////////////// |
|
|
// |
|
|
// |
|
|
// midiinfunction -- Thread function which waits around until a MIDI |
|
|
// midiinfunction -- Thread function which waits around until a MIDI |
|
|
// input byte arrives and then react correspondingly |
|
|
// input byte arrives and then react correspondingly |
|
|
// |
|
|
// |
|
|
void register_osc_receives() { |
|
|
|
|
|
|
|
|
void register_osc_receives(void *arg) { |
|
|
|
|
|
housicIO* IOs = (housicIO*)arg; |
|
|
|
|
|
int zone_c; |
|
|
|
|
|
int button_c; |
|
|
|
|
|
char address[32]; |
|
|
|
|
|
int address_c = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (zone_c=0; zone_c<ZONE_COUNT; zone_c++) { |
|
|
|
|
|
for (button_c=0; button_c<8; button_c++) { |
|
|
|
|
|
if (BUTTONS[zone_c][button_c]) { |
|
|
|
|
|
Hui_MIDI_port_t out = {zone_c,button_c,IOs}; |
|
|
|
|
|
IOs->MIDIouts[address_c] = out; |
|
|
|
|
|
sprintf(address,"/%s/%s",ZONES[zone_c],BUTTONS[zone_c][button_c]); |
|
|
|
|
|
lo_server_thread_add_method(IOs->osc_in, |
|
|
|
|
|
address, |
|
|
|
|
|
"i", |
|
|
|
|
|
osc_in_button_handler, |
|
|
|
|
|
&IOs->MIDIouts[address_c]); |
|
|
|
|
|
address_c++; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int i; |
|
|
|
|
|
int display_c = 0; |
|
|
|
|
|
for (i=0;i<9;i++) { |
|
|
|
|
|
Hui_display_port_t out = {LABEL,i,IOs}; |
|
|
|
|
|
IOs->display_outs[display_c] = out; |
|
|
|
|
|
sprintf(address,"/label/%d",i); |
|
|
|
|
|
lo_server_thread_add_method(IOs->osc_in, |
|
|
|
|
|
address, |
|
|
|
|
|
"s", |
|
|
|
|
|
osc_in_label_handler, |
|
|
|
|
|
&IOs->display_outs[display_c]); |
|
|
|
|
|
display_c++; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int osc_in_label_handler(const char *path, const char *types, lo_arg ** argv, |
|
|
|
|
|
int argc, void *data, void *user_data) { |
|
|
|
|
|
char* val; |
|
|
|
|
|
|
|
|
|
|
|
val = (char *)(lo_arg*) argv[0]->s; |
|
|
|
|
|
|
|
|
|
|
|
printf("%s: %d: %x\n",types,argc, argv); |
|
|
|
|
|
return 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////// |
|
|
|
|
|
// |
|
|
|
|
|
// osc_in_button_handler -- called when a button type message is |
|
|
|
|
|
// received and should be sent to the HUI |
|
|
|
|
|
// |
|
|
|
|
|
int osc_in_button_handler(const char *path, const char *types, lo_arg ** argv, |
|
|
|
|
|
int argc, void *data, void *user_data) { |
|
|
|
|
|
Hui_MIDI_port_t* out = (Hui_MIDI_port_t*)user_data; |
|
|
|
|
|
housicIO* IOs = (housicIO*) out->io; |
|
|
|
|
|
char value; |
|
|
|
|
|
int status; |
|
|
|
|
|
// char message[6]; |
|
|
|
|
|
char out_data; |
|
|
|
|
|
|
|
|
|
|
|
value = argv[0]->i; |
|
|
|
|
|
out_data = value ? 0x40 : 0x00; |
|
|
|
|
|
out_data |= out->port; |
|
|
|
|
|
unsigned char message[6] = {0xb0,0x0c,out->zone,0xb0,0x2c,out_data}; |
|
|
|
|
|
status = snd_rawmidi_write(IOs->midiout,message,6); |
|
|
|
|
|
printf("%s - %x %x %x %x %x %x\n",path, |
|
|
|
|
|
message[0],message[1],message[2],message[3],message[4],message[5]); |
|
|
|
|
|
return 1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////// |
|
|
////////////////////////////// |
|
|
// |
|
|
// |
|
|
// midiinfunction -- Thread function which waits around until a MIDI |
|
|
// midiinfunction -- Thread function which waits around until a MIDI |
|
|
|
|
|
|
|
|
for (i=1; i<=status;i++) { |
|
|
for (i=1; i<=status;i++) { |
|
|
message[3-i] = (unsigned char) buffer[status-i]; |
|
|
message[3-i] = (unsigned char) buffer[status-i]; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (status==2) { |
|
|
|
|
|
message[0] = 0xb0; |
|
|
|
|
|
} else if(0) { // only for debugging |
|
|
|
|
|
printf("%d: %x %x %x - %x %x %x\n", status, |
|
|
|
|
|
buffer[0],buffer[1],buffer[2], |
|
|
|
|
|
message[0], message[1], message[2]); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
midi_in_dispatch(IOs,message); |
|
|
midi_in_dispatch(IOs,message); |
|
|
|
|
|
|
|
|
fflush(stdout); |
|
|
fflush(stdout); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void midi_in_dispatch(void *arg, unsigned char *m) { |
|
|
void midi_in_dispatch(void *arg, unsigned char *m) { |
|
|
housicIO* IOs = (housicIO*)arg; |
|
|
housicIO* IOs = (housicIO*)arg; |
|
|
|
|
|
int fader_value; |
|
|
|
|
|
|
|
|
if (m[0] == 0xb0) { |
|
|
if (m[0] == 0xb0) { |
|
|
// received a CC message on MIDIchannel 1 |
|
|
// received a CC message on MIDIchannel 1 |
|
|
if (m[1] == 0x0f) { |
|
|
if (m[1] == 0x0f) { |
|
|
// received a zone select |
|
|
// received a zone select |
|
|
IOs->hui_in_zone = m[2]; |
|
|
IOs->hui_in_zone = m[2]; |
|
|
} else { |
|
|
|
|
|
if (m[1] == 0x2f) { |
|
|
|
|
|
// should always be true, if HUI is working. |
|
|
|
|
|
hui_in_button(IOs,m[2]); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
} else if (m[1] == 0x2f) { // switches |
|
|
|
|
|
hui_in_button(IOs,m[2]); |
|
|
|
|
|
} else if ((m[1] & 0xf0) == 0x40) { // V-pots: |
|
|
|
|
|
hui_in_scroll(IOs,m[1] & 0xf, m[2]); |
|
|
|
|
|
} else if (m[1] == 0x0d) { // jog wheel: |
|
|
|
|
|
hui_in_scroll(IOs,0xd,m[2]); |
|
|
|
|
|
} else if (m[1] < 0x08) { // fader Hi |
|
|
|
|
|
IOs->hui_in_fader_hi[m[1]] = (int) m[2]; |
|
|
|
|
|
} else if ((m[1] & 0xf0) == 0x20) { // fader Lo |
|
|
|
|
|
fader_value = (IOs->hui_in_fader_hi[m[1] & 0x0f] << 2) | (m[2] >> 5); |
|
|
|
|
|
hui_in_fader(IOs,m[1] & 0x0f,fader_value); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////// |
|
|
|
|
|
// |
|
|
|
|
|
// hui_in_fader -- fader positions |
|
|
|
|
|
// |
|
|
|
|
|
void hui_in_fader(void *arg, unsigned char port, int val) { |
|
|
|
|
|
housicIO* IOs = (housicIO*)arg; |
|
|
|
|
|
char address[32]; |
|
|
|
|
|
|
|
|
|
|
|
sprintf(address, "/fader/%d", port + 1); |
|
|
|
|
|
Item ee = {'f',address}; |
|
|
|
|
|
osc_send(IOs, ee, val); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////// |
|
|
|
|
|
// |
|
|
|
|
|
// hui_in_scroll -- user interacted with a button on the HUI |
|
|
|
|
|
// |
|
|
|
|
|
void hui_in_scroll(void *arg, unsigned char port, unsigned char vv) { |
|
|
|
|
|
housicIO* IOs = (housicIO*)arg; |
|
|
|
|
|
char address[32]; |
|
|
|
|
|
|
|
|
|
|
|
sprintf(address, "/vpot/%d", port + 1); |
|
|
|
|
|
Item ee = {'s', address}; |
|
|
|
|
|
if (vv > 0x40) { |
|
|
|
|
|
osc_send(IOs, ee, vv - 0x40); |
|
|
|
|
|
} else if (vv < 0x40) { |
|
|
|
|
|
osc_send(IOs, ee, -vv); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|