command-line utility to translate between Mackie HUI and Open Sound Control
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

268 linhas
7.0KB

  1. /*
  2. * Programmer: Dominik Schmidt-Philipp <schmidt-philipp@kulturteknologi.no>
  3. * Filename: main.c
  4. *
  5. * Dedicated to seleomlivet
  6. *
  7. */
  8. #include <alsa/asoundlib.h>
  9. #include <pthread.h> /* for threading */
  10. #include <lo/lo.h>
  11. #include "mapping.h"
  12. typedef struct {
  13. snd_rawmidi_t* midiin;
  14. snd_rawmidi_t* midiout;
  15. lo_address osc_out;
  16. unsigned char hui_in_zone;
  17. } housicIO;
  18. typedef struct {
  19. char type;
  20. char* address;
  21. } Item;
  22. char *ZONES[] = {
  23. "channel_strip_1",
  24. "channel_strip_2",
  25. "channel_strip_3",
  26. "channel_strip_4",
  27. "channel_strip_5",
  28. "channel_strip_6",
  29. "channel_strip_7",
  30. "channel_strip_8",
  31. "keyboard_shortcuts",
  32. "window",
  33. "channel_selection",
  34. "assignment_1",
  35. "assignment_2",
  36. "cursor",
  37. "transport_main",
  38. "transport_add1",
  39. "transport_add2",
  40. "monitor_input",
  41. "monitor_output",
  42. "num_pad_1",
  43. "num_pad_2",
  44. "num_pad_3",
  45. "timecode",
  46. "auto_enable",
  47. "auto_mode",
  48. "status_group",
  49. "edit",
  50. "fn_keys",
  51. "parameter_edit",
  52. "misc"
  53. };
  54. char *BUTTONS[0x1e][8] = {
  55. {"fader","select","mute","solo","auto","v-sel","insert","rec_rdy"},
  56. {"fader","select","mute","solo","auto","v-sel","insert","rec_rdy"},
  57. {"fader","select","mute","solo","auto","v-sel","insert","rec_rdy"},
  58. {"fader","select","mute","solo","auto","v-sel","insert","rec_rdy"},
  59. {"fader","select","mute","solo","auto","v-sel","insert","rec_rdy"},
  60. {"fader","select","mute","solo","auto","v-sel","insert","rec_rdy"},
  61. {"fader","select","mute","solo","auto","v-sel","insert","rec_rdy"},
  62. {"fader","select","mute","solo","auto","v-sel","insert","rec_rdy"},
  63. {"ctrl","shift","editmode","undo","alt","option","edittool","save"},
  64. {"mix","edit","transprt","mem-loc","status","alt"},
  65. {"chan_left","bank_left","chanl_right","bank_right"},
  66. {"output","input","pan","send_e","send_d","send_c","send_b","send_a"},
  67. {"assign","default","suspend","shift","mute","bypass","recrdyall"},
  68. {"down","left","mode","right","up","scrub","shuttle"},
  69. {"talkback","rewind","fast_fwd","stop","play","record"},
  70. {"rtz","end","on_line","loop","quick_punch"},
  71. {"audition","pre","in","out","post"},
  72. {"input_3 ","input_2","input_1","mute","discrete"},
  73. {"output_3","output_2","output_1","dim","mono"},
  74. {"0","1","4","2","5",".","3","6"},
  75. {"enter","+"},
  76. {"7","8","9","-","clr","=","divide","multiply"},
  77. {"timecode","feet","beats","rudesolo"},
  78. {"plug_in","pan","fader","sendmute","send","mute"},
  79. {"trim","latch","read","off","write","touch"},
  80. {"phase","monitor","auto","suspend","create","group"},
  81. {"paste","cut","capture","delete","copy","separate"},
  82. {"f1","f2","f3","f4","f5","f6","f7","f8"},
  83. {"insert","assign","select_1","select_2","select_3","select_4","bypass","compare"},
  84. {"switch_1","switch_2","click","beep"}
  85. };
  86. // function declarations:
  87. void alsa_error (const char *format, ...);
  88. void* midiinfunction (void * arg);
  89. void midi_in_dispatch (void * arg, unsigned char * m);
  90. void lo_error (int num, const char *m, const char *path);
  91. int osc_in_handler (const char *path, const char *types, lo_arg ** argv,
  92. int argc, void *data, void *user_data);
  93. void hui_in_button (void *arg, unsigned char m);
  94. void osc_send (void *arg, Item el, float value);
  95. void register_osc_receives();
  96. int main(int argc, char *argv[]) {
  97. int status;
  98. int mode = SND_RAWMIDI_SYNC;
  99. pthread_t midiinthread;
  100. lo_server_thread st = lo_server_thread_new("7770", lo_error);
  101. housicIO IOs = {NULL,NULL,0,0};
  102. IOs.osc_out = lo_address_new(NULL,"7771");
  103. const char* portname = "virtual";
  104. // MIDI
  105. if ((status = snd_rawmidi_open(&IOs.midiin, NULL, portname, mode)) < 0) {
  106. alsa_error("Problem opening MIDI input: %s", snd_strerror(status));
  107. exit(1);
  108. }
  109. status = pthread_create(&midiinthread, NULL, midiinfunction, &IOs);
  110. // OSC
  111. register_osc_receives();
  112. lo_server_thread_add_method(st, NULL, NULL, osc_in_handler, NULL);
  113. lo_server_thread_start(st);
  114. // wait for MIDI thread to end (will not happen)
  115. pthread_join(midiinthread, NULL);
  116. return 0;
  117. }
  118. //////////////////////////////
  119. //
  120. // midiinfunction -- Thread function which waits around until a MIDI
  121. // input byte arrives and then react correspondingly
  122. //
  123. void register_osc_receives() {
  124. }
  125. //////////////////////////////
  126. //
  127. // midiinfunction -- Thread function which waits around until a MIDI
  128. // input byte arrives and then react correspondingly
  129. //
  130. void *midiinfunction(void *arg) {
  131. housicIO* IOs = (housicIO*)arg;
  132. snd_rawmidi_t* midiin = IOs->midiin;
  133. int status;
  134. int i = 0;
  135. char buffer[3];
  136. unsigned char message[3];
  137. while (1) {
  138. if ((status = snd_rawmidi_read(midiin, buffer, 3)) < 0) {
  139. alsa_error("Problem reading MIDI input: %s", snd_strerror(status));
  140. }
  141. // in case of MIDI running status, value bytes need to not override status byte
  142. for (i=1; i<=status;i++) {
  143. message[3-i] = (unsigned char) buffer[status-i];
  144. }
  145. midi_in_dispatch(IOs,message);
  146. fflush(stdout);
  147. }
  148. }
  149. //////////////////////////////
  150. //
  151. // midi_in_dispatch -- Thread function which waits around until a MIDI
  152. // input byte arrives and then react correspondingly
  153. //
  154. void midi_in_dispatch(void *arg, unsigned char *m) {
  155. housicIO* IOs = (housicIO*)arg;
  156. if (m[0] == 0xb0) {
  157. // received a CC message on MIDIchannel 1
  158. if (m[1] == 0x0f) {
  159. // received a zone select
  160. IOs->hui_in_zone = m[2];
  161. } else {
  162. if (m[1] == 0x2f) {
  163. // should always be true, if HUI is working.
  164. hui_in_button(IOs,m[2]);
  165. }
  166. }
  167. }
  168. }
  169. //////////////////////////////
  170. //
  171. // hui_in_button -- user interacted with a button on the HUI
  172. //
  173. void hui_in_button(void *arg, unsigned char m) {
  174. housicIO* IOs = (housicIO*)arg;
  175. char address[32];
  176. char zone = IOs->hui_in_zone;
  177. int dir = m & 0xf0;
  178. int port = m & 0x0f;
  179. sprintf(address, "/%s/%s",ZONES[zone],BUTTONS[zone][port]);
  180. Item ee = {'b',address};
  181. if (dir == 0x40) {
  182. // down
  183. osc_send(IOs, ee, 1);
  184. } else if (dir == 0x00) {
  185. // up
  186. osc_send(IOs, ee, 0);
  187. }
  188. }
  189. //////////////////////////////
  190. //
  191. // osc_send --
  192. //
  193. void osc_send(void *arg, Item el, float value) {
  194. housicIO* IOs = (housicIO*)arg;
  195. lo_send(IOs->osc_out, el.address, "f", value );
  196. }
  197. //////////////////////////////
  198. //
  199. // osc_in_handler -- receive incoming OSC messages
  200. //
  201. int osc_in_handler (const char *path, const char *types, lo_arg ** argv,
  202. int argc, void *data, void *user_data) {
  203. int i;
  204. printf("path: <%s>\n", path);
  205. for (i = 0; i < argc; i++) {
  206. printf("arg %d '%c' ", i, types[i]);
  207. lo_arg_pp((lo_type)types[i], argv[i]);
  208. printf("\n");
  209. }
  210. printf("\n");
  211. fflush(stdout);
  212. return 1;
  213. }
  214. //////////////////////////////
  215. //
  216. // error -- print error message
  217. //
  218. void alsa_error(const char *format, ...) {
  219. va_list ap;
  220. va_start(ap, format);
  221. vfprintf(stderr, format, ap);
  222. va_end(ap);
  223. putc('\n', stderr);
  224. }
  225. void lo_error(int num, const char *msg, const char *path)
  226. {
  227. printf("liblo server error %d in path %s: %s\n", num, path, msg);
  228. fflush(stdout);
  229. }