|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* Programmer: Dominik Schmidt-Philipp <schmidt-philipp@kulturteknologi.no> |
|
|
|
|
|
* Filename: main.c |
|
|
|
|
|
* |
|
|
|
|
|
* Dedicated to seleomlivet |
|
|
|
|
|
* |
|
|
|
|
|
*/ |
|
|
|
|
|
#include <alsa/asoundlib.h> |
|
|
|
|
|
#include <pthread.h> /* for threading */ |
|
|
|
|
|
#include <lo/lo.h> |
|
|
|
|
|
#include <unistd.h> |
|
|
|
|
|
|
|
|
|
|
|
#define ZONE_COUNT 0x1e |
|
|
|
|
|
#define PORT_COUNT 196 |
|
|
|
|
|
#define DISPLAY_COUNT 38 |
|
|
|
|
|
#define HDR 0xf0, 0x00, 0x00, 0x66, 0x05, 0x00 |
|
|
|
|
|
|
|
|
|
|
|
enum display_type { |
|
|
|
|
|
LABEL, |
|
|
|
|
|
VPOT, |
|
|
|
|
|
MAIN_DISPLAY, |
|
|
|
|
|
TIMECODE, |
|
|
|
|
|
METER |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/* enum vpot_mode { */ |
|
|
|
|
|
/* POINTER, */ |
|
|
|
|
|
/* CENTERED_FILL, */ |
|
|
|
|
|
/* FILL, */ |
|
|
|
|
|
/* WIDTH */ |
|
|
|
|
|
/* }; */ |
|
|
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
|
|
char zone; |
|
|
|
|
|
char port; |
|
|
|
|
|
void* io; |
|
|
|
|
|
} Hui_MIDI_port_t; |
|
|
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
|
|
int type; |
|
|
|
|
|
int id; |
|
|
|
|
|
char state; |
|
|
|
|
|
void* io; |
|
|
|
|
|
} Hui_display_port_t; |
|
|
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
|
|
snd_rawmidi_t* midiin; |
|
|
|
|
|
snd_rawmidi_t* midiout; |
|
|
|
|
|
lo_address osc_out; |
|
|
|
|
|
lo_server_thread osc_in; |
|
|
|
|
|
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; |
|
|
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
|
|
char type; |
|
|
|
|
|
char* address; |
|
|
|
|
|
} Item; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char *ZONES[] = { |
|
|
|
|
|
"channel_strip_1", |
|
|
|
|
|
"channel_strip_2", |
|
|
|
|
|
"channel_strip_3", |
|
|
|
|
|
"channel_strip_4", |
|
|
|
|
|
"channel_strip_5", |
|
|
|
|
|
"channel_strip_6", |
|
|
|
|
|
"channel_strip_7", |
|
|
|
|
|
"channel_strip_8", |
|
|
|
|
|
"keyboard_shortcuts", |
|
|
|
|
|
"window", |
|
|
|
|
|
"channel_selection", |
|
|
|
|
|
"assignment_1", |
|
|
|
|
|
"assignment_2", |
|
|
|
|
|
"cursor", |
|
|
|
|
|
"transport_main", |
|
|
|
|
|
"transport_add1", |
|
|
|
|
|
"transport_add2", |
|
|
|
|
|
"monitor_input", |
|
|
|
|
|
"monitor_output", |
|
|
|
|
|
"num_pad_1", |
|
|
|
|
|
"num_pad_2", |
|
|
|
|
|
"num_pad_3", |
|
|
|
|
|
"timecode", |
|
|
|
|
|
"auto_enable", |
|
|
|
|
|
"auto_mode", |
|
|
|
|
|
"status_group", |
|
|
|
|
|
"edit", |
|
|
|
|
|
"fn_keys", |
|
|
|
|
|
"parameter_edit", |
|
|
|
|
|
"misc" |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
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"}, |
|
|
|
|
|
{"fader","select","mute","solo","auto","v-sel","insert","rec_rdy"}, |
|
|
|
|
|
{"fader","select","mute","solo","auto","v-sel","insert","rec_rdy"}, |
|
|
|
|
|
{"ctrl","shift","editmode","undo","alt","option","edittool","save"}, |
|
|
|
|
|
{"mix","edit","transprt","mem-loc","status","alt"}, |
|
|
|
|
|
{"chan_left","bank_left","chanl_right","bank_right"}, |
|
|
|
|
|
{"output","input","pan","send_e","send_d","send_c","send_b","send_a"}, |
|
|
|
|
|
{"assign","default","suspend","shift","mute","bypass","recrdyall"}, |
|
|
|
|
|
{"down","left","mode","right","up","scrub","shuttle"}, |
|
|
|
|
|
{"talkback","rewind","fast_fwd","stop","play","record"}, |
|
|
|
|
|
{"rtz","end","on_line","loop","quick_punch"}, |
|
|
|
|
|
{"audition","pre","in","out","post"}, |
|
|
|
|
|
{"input_3 ","input_2","input_1","mute","discrete"}, |
|
|
|
|
|
{"output_3","output_2","output_1","dim","mono"}, |
|
|
|
|
|
{"0","1","4","2","5",".","3","6"}, |
|
|
|
|
|
{"enter","+"}, |
|
|
|
|
|
{"7","8","9","-","clr","=","divide","multiply"}, |
|
|
|
|
|
{"timecode","feet","beats","rudesolo"}, |
|
|
|
|
|
{"plug_in","pan","fader","sendmute","send","mute"}, |
|
|
|
|
|
{"trim","latch","read","off","write","touch"}, |
|
|
|
|
|
{"phase","monitor","auto","suspend","create","group"}, |
|
|
|
|
|
{"paste","cut","capture","delete","copy","separate"}, |
|
|
|
|
|
{"f1","f2","f3","f4","f5","f6","f7","f8"}, |
|
|
|
|
|
{"insert","assign","select_1","select_2","select_3","select_4","bypass","compare"}, |
|
|
|
|
|
{"switch_1","switch_2","click","beep"} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// function declarations: |
|
|
|
|
|
void alsa_error (const char *format, ...); |
|
|
|
|
|
void* midiinfunction (void * arg); |
|
|
|
|
|
void* ping (void * arg); |
|
|
|
|
|
void midi_in_dispatch (void * arg, unsigned char * m); |
|
|
|
|
|
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 argc, void *data, void *user_data); |
|
|
|
|
|
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 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_display_handler (const char *path, const char *types, lo_arg ** argv, |
|
|
|
|
|
int argc, void *data, void *user_data); |
|
|
|
|
|
int osc_in_vpot_handler (const char *path, const char *types, lo_arg ** argv, |
|
|
|
|
|
int argc, void *data, void *user_data); |
|
|
|
|
|
int osc_in_meter_handler (const char *path, const char *types, lo_arg ** argv, |
|
|
|
|
|
int argc, void *data, void *user_data); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int main(int argc, char *argv[]) { |
|
|
|
|
|
int status; |
|
|
|
|
|
int mode = SND_RAWMIDI_SYNC; |
|
|
|
|
|
pthread_t midiinthread; |
|
|
|
|
|
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_in = lo_server_thread_new("7770", lo_error); |
|
|
|
|
|
|
|
|
|
|
|
const char* portname = "virtual"; |
|
|
|
|
|
|
|
|
|
|
|
// 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) { |
|
|
|
|
|
alsa_error("Problem opening MIDI input: %s", snd_strerror(status)); |
|
|
|
|
|
exit(1); |
|
|
|
|
|
} |
|
|
|
|
|
status = pthread_create(&pingthread,NULL, ping, &IOs); |
|
|
|
|
|
status = pthread_create(&midiinthread, NULL, midiinfunction, &IOs); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// OSC |
|
|
|
|
|
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) |
|
|
|
|
|
pthread_join(midiinthread, NULL); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
// input byte arrives and then react correspondingly |
|
|
|
|
|
// |
|
|
|
|
|
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; |
|
|
|
|
|
|
|
|
|
|
|
// Labels |
|
|
|
|
|
for (i=0;i<9;i++) { |
|
|
|
|
|
Hui_display_port_t out = {LABEL, i, 0, IOs}; |
|
|
|
|
|
IOs->display_outs[display_c] = out; |
|
|
|
|
|
sprintf(address,"/label/%d",i); |
|
|
|
|
|
lo_server_thread_add_method(IOs->osc_in, |
|
|
|
|
|
address, |
|
|
|
|
|
"s", |
|
|
|
|
|
osc_in_display_handler, |
|
|
|
|
|
&IOs->display_outs[display_c]); |
|
|
|
|
|
display_c++; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Main display: |
|
|
|
|
|
for (i=0;i<8;i++) { |
|
|
|
|
|
Hui_display_port_t out = {MAIN_DISPLAY, i, 0, IOs}; |
|
|
|
|
|
IOs->display_outs[display_c] = out; |
|
|
|
|
|
sprintf(address,"/main_display/%d",i); |
|
|
|
|
|
lo_server_thread_add_method(IOs->osc_in, |
|
|
|
|
|
address, |
|
|
|
|
|
"s", |
|
|
|
|
|
osc_in_display_handler, |
|
|
|
|
|
&IOs->display_outs[display_c]); |
|
|
|
|
|
display_c++; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Timecode |
|
|
|
|
|
Hui_display_port_t out = {TIMECODE, 0, 0, IOs}; |
|
|
|
|
|
IOs->display_outs[display_c] = out; |
|
|
|
|
|
sprintf(address,"/timecode"); |
|
|
|
|
|
lo_server_thread_add_method(IOs->osc_in, |
|
|
|
|
|
address, |
|
|
|
|
|
NULL, |
|
|
|
|
|
osc_in_display_handler, |
|
|
|
|
|
&IOs->display_outs[display_c]); |
|
|
|
|
|
display_c++; |
|
|
|
|
|
|
|
|
|
|
|
// Vpots |
|
|
|
|
|
for (i=0;i<12;i++) { |
|
|
|
|
|
Hui_display_port_t out = {VPOT, i, 0, IOs}; |
|
|
|
|
|
IOs->display_outs[display_c] = out; |
|
|
|
|
|
sprintf(address,"/vpot/%d",i+1); |
|
|
|
|
|
lo_server_thread_add_method(IOs->osc_in, |
|
|
|
|
|
address, |
|
|
|
|
|
NULL, |
|
|
|
|
|
osc_in_vpot_handler, |
|
|
|
|
|
&IOs->display_outs[display_c]); |
|
|
|
|
|
display_c++; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Meters |
|
|
|
|
|
for (i=0;i<8;i++) { |
|
|
|
|
|
Hui_display_port_t out = {METER, i, 0, IOs}; |
|
|
|
|
|
IOs->display_outs[display_c] = out; |
|
|
|
|
|
sprintf(address,"/meter/%d",i+1); |
|
|
|
|
|
lo_server_thread_add_method(IOs->osc_in, |
|
|
|
|
|
address, |
|
|
|
|
|
"ff", |
|
|
|
|
|
osc_in_meter_handler, |
|
|
|
|
|
&IOs->display_outs[display_c]); |
|
|
|
|
|
display_c++; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int osc_in_meter_handler(const char *path, const char *types, lo_arg ** argv, |
|
|
|
|
|
int argc, void *data, void *user_data) { |
|
|
|
|
|
Hui_display_port_t* out = (Hui_display_port_t*)user_data; |
|
|
|
|
|
housicIO* IOs = (housicIO*) out->io; |
|
|
|
|
|
unsigned char message[3]; |
|
|
|
|
|
int i; |
|
|
|
|
|
char val; |
|
|
|
|
|
char side = 0; |
|
|
|
|
|
if (out->type == METER) { |
|
|
|
|
|
message[0] = 0xa0; |
|
|
|
|
|
message[1] = (0x0 | out->id); |
|
|
|
|
|
side = (char)argv[0]->f; |
|
|
|
|
|
if (side) { |
|
|
|
|
|
side = 0x10; |
|
|
|
|
|
} |
|
|
|
|
|
val = (char)argv[1]->f; |
|
|
|
|
|
if ( val <= 0xc) { |
|
|
|
|
|
message[2] = side | val; |
|
|
|
|
|
snd_rawmidi_write(IOs->midiout,message,3); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int osc_in_vpot_handler(const char *path, const char *types, lo_arg ** argv, |
|
|
|
|
|
int argc, void *data, void *user_data) { |
|
|
|
|
|
Hui_display_port_t* out = (Hui_display_port_t*)user_data; |
|
|
|
|
|
housicIO* IOs = (housicIO*) out->io; |
|
|
|
|
|
unsigned char message[3]; |
|
|
|
|
|
int i; |
|
|
|
|
|
int size; |
|
|
|
|
|
|
|
|
|
|
|
if (out->type == VPOT) { |
|
|
|
|
|
size = 3; |
|
|
|
|
|
message[0] = 0xb0; |
|
|
|
|
|
for (i=0; i<argc; i++) { |
|
|
|
|
|
if (types[i] == 's') { |
|
|
|
|
|
// p: POINTER |
|
|
|
|
|
// c: CENTERED_FILL |
|
|
|
|
|
// f: FILL |
|
|
|
|
|
// w: WIDTH |
|
|
|
|
|
if (argv[i]->s == 'p' ) { |
|
|
|
|
|
out->state = (out->state & 0x0f) | 0x00; |
|
|
|
|
|
} else if (argv[i]->s == 'c' ) { |
|
|
|
|
|
out->state = (out->state & 0x0f) | 0x10; |
|
|
|
|
|
} else if (argv[i]->s == 'f' ) { |
|
|
|
|
|
out->state = (out->state & 0x0f) | 0x20; |
|
|
|
|
|
} else if (argv[i]->s == 'w' ) { |
|
|
|
|
|
out->state = (out->state & 0x0f) | 0x30; |
|
|
|
|
|
} |
|
|
|
|
|
} else if (types[i] == 'f') { |
|
|
|
|
|
if (argv[i]->f < 12) { |
|
|
|
|
|
out->state = ((unsigned char)argv[i]->f & 0x0f) | (out->state & 0xf0); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
message[1] = (0x10 | out->id); |
|
|
|
|
|
message[2] = out->state; |
|
|
|
|
|
snd_rawmidi_write(IOs->midiout,message,size); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int osc_in_display_handler(const char *path, const char *types, lo_arg ** argv, |
|
|
|
|
|
int argc, void *data, void *user_data) { |
|
|
|
|
|
Hui_display_port_t* out = (Hui_display_port_t*)user_data; |
|
|
|
|
|
housicIO* IOs = (housicIO*) out->io; |
|
|
|
|
|
char* val = (char*)argv[0]; |
|
|
|
|
|
int i; |
|
|
|
|
|
int size; |
|
|
|
|
|
char message[52] = {HDR}; |
|
|
|
|
|
char timecode[8]; |
|
|
|
|
|
|
|
|
|
|
|
if (out->type == LABEL) { |
|
|
|
|
|
size=13; |
|
|
|
|
|
message[6] = 0x10; |
|
|
|
|
|
message[7] = out->id; |
|
|
|
|
|
for (i=0; i<4; i++) { |
|
|
|
|
|
message[8+i] = val[i] ? val[i] & 0x7f : 0x20; |
|
|
|
|
|
} |
|
|
|
|
|
} else if (out->type == MAIN_DISPLAY) { |
|
|
|
|
|
size=19; |
|
|
|
|
|
message[6] = 0x12; |
|
|
|
|
|
message[7] = out->id; |
|
|
|
|
|
for (i=0; i<10; i++) { |
|
|
|
|
|
message[8+i] = (val[i] > 0x10) ? val[i] & 0x7f : 0x20; |
|
|
|
|
|
} |
|
|
|
|
|
} else if (out->type == TIMECODE) { |
|
|
|
|
|
size=0; |
|
|
|
|
|
message[6] = 0x11; |
|
|
|
|
|
printf("%s \n",types); |
|
|
|
|
|
for (i=0; i<argc; i++) { |
|
|
|
|
|
// size keeps track of how many digits have been entered |
|
|
|
|
|
// make sure we only read 8 digits |
|
|
|
|
|
if (types[i] == 'f' && size < 8) { |
|
|
|
|
|
timecode[size] = (unsigned char) argv[i]->f & 0xf; |
|
|
|
|
|
size++; |
|
|
|
|
|
} else if (types[i] == 's') { |
|
|
|
|
|
if (argv[i]->s == '.') { |
|
|
|
|
|
// a dot behind a digit has 5th bit set |
|
|
|
|
|
timecode[size-1] = timecode[size-1] + 0x10; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
for (i=0;i<size;i++) { |
|
|
|
|
|
// write timecode to message with a leading LSB |
|
|
|
|
|
// also LSB must be below 10 because it has no point (read doc) |
|
|
|
|
|
message[7+i] = i ? timecode[size-1-i]: timecode[size-1-i] & 0xf; |
|
|
|
|
|
} |
|
|
|
|
|
message[7+size] = 0xf7; |
|
|
|
|
|
size += 8; |
|
|
|
|
|
} else if (out->type == METER) { |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
message[size-1] = 0xf7; |
|
|
|
|
|
|
|
|
|
|
|
snd_rawmidi_write(IOs->midiout,message,size); |
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
// input byte arrives and then react correspondingly |
|
|
|
|
|
// |
|
|
|
|
|
|
|
|
|
|
|
void *midiinfunction(void *arg) { |
|
|
|
|
|
housicIO* IOs = (housicIO*)arg; |
|
|
|
|
|
snd_rawmidi_t* midiin = IOs->midiin; |
|
|
|
|
|
int status; |
|
|
|
|
|
int i = 0; |
|
|
|
|
|
char buffer[3]; |
|
|
|
|
|
unsigned char message[3]; |
|
|
|
|
|
|
|
|
|
|
|
while (1) { |
|
|
|
|
|
if ((status = snd_rawmidi_read(midiin, buffer, 3)) < 0) { |
|
|
|
|
|
alsa_error("Problem reading MIDI input: %s", snd_strerror(status)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// in case of MIDI running status, value bytes need to not override status byte |
|
|
|
|
|
for (i=1; i<=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); |
|
|
|
|
|
|
|
|
|
|
|
fflush(stdout); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////// |
|
|
|
|
|
// |
|
|
|
|
|
// midi_in_dispatch -- Thread function which waits around until a MIDI |
|
|
|
|
|
// input byte arrives and then react correspondingly |
|
|
|
|
|
// |
|
|
|
|
|
|
|
|
|
|
|
void midi_in_dispatch(void *arg, unsigned char *m) { |
|
|
|
|
|
housicIO* IOs = (housicIO*)arg; |
|
|
|
|
|
int fader_value; |
|
|
|
|
|
|
|
|
|
|
|
if (m[0] == 0xb0) { |
|
|
|
|
|
// received a CC message on MIDIchannel 1 |
|
|
|
|
|
if (m[1] == 0x0f) { |
|
|
|
|
|
// received a zone select |
|
|
|
|
|
IOs->hui_in_zone = 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); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////// |
|
|
|
|
|
// |
|
|
|
|
|
// hui_in_button -- user interacted with a button on the HUI |
|
|
|
|
|
// |
|
|
|
|
|
void hui_in_button(void *arg, unsigned char m) { |
|
|
|
|
|
housicIO* IOs = (housicIO*)arg; |
|
|
|
|
|
char address[32]; |
|
|
|
|
|
|
|
|
|
|
|
char zone = IOs->hui_in_zone; |
|
|
|
|
|
int dir = m & 0xf0; |
|
|
|
|
|
int port = m & 0x0f; |
|
|
|
|
|
|
|
|
|
|
|
sprintf(address, "/%s/%s",ZONES[zone],BUTTONS[zone][port]); |
|
|
|
|
|
Item ee = {'b',address}; |
|
|
|
|
|
if (dir == 0x40) { |
|
|
|
|
|
// down |
|
|
|
|
|
osc_send(IOs, ee, 1); |
|
|
|
|
|
} else if (dir == 0x00) { |
|
|
|
|
|
// up |
|
|
|
|
|
osc_send(IOs, ee, 0); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////// |
|
|
|
|
|
// |
|
|
|
|
|
// osc_send -- |
|
|
|
|
|
// |
|
|
|
|
|
void osc_send(void *arg, Item el, float value) { |
|
|
|
|
|
housicIO* IOs = (housicIO*)arg; |
|
|
|
|
|
|
|
|
|
|
|
lo_send(IOs->osc_out, el.address, "f", value ); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////// |
|
|
|
|
|
// |
|
|
|
|
|
// osc_in_handler -- receive incoming OSC messages |
|
|
|
|
|
// |
|
|
|
|
|
int osc_in_handler (const char *path, const char *types, lo_arg ** argv, |
|
|
|
|
|
int argc, void *data, void *user_data) { |
|
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
|
|
printf("path: <%s>\n", path); |
|
|
|
|
|
for (i = 0; i < argc; i++) { |
|
|
|
|
|
printf("arg %d '%c' ", i, types[i]); |
|
|
|
|
|
lo_arg_pp((lo_type)types[i], argv[i]); |
|
|
|
|
|
printf("\n"); |
|
|
|
|
|
} |
|
|
|
|
|
printf("\n"); |
|
|
|
|
|
fflush(stdout); |
|
|
|
|
|
|
|
|
|
|
|
return 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////// |
|
|
|
|
|
// |
|
|
|
|
|
// error -- print error message |
|
|
|
|
|
// |
|
|
|
|
|
|
|
|
|
|
|
void alsa_error(const char *format, ...) { |
|
|
|
|
|
va_list ap; |
|
|
|
|
|
va_start(ap, format); |
|
|
|
|
|
vfprintf(stderr, format, ap); |
|
|
|
|
|
va_end(ap); |
|
|
|
|
|
putc('\n', stderr); |
|
|
|
|
|
} |
|
|
|
|
|
void lo_error(int num, const char *msg, const char *path) |
|
|
|
|
|
{ |
|
|
|
|
|
printf("liblo server error %d in path %s: %s\n", num, path, msg); |
|
|
|
|
|
fflush(stdout); |
|
|
|
|
|
} |