Werner's Miscellanea
Sign in or create your account | Project List | Help
Werner's Miscellanea Commit Details
Date: | 2011-11-24 06:51:10 (12 years 4 months ago) |
---|---|
Author: | Werner Almesberger |
Commit: | 2d50444b1b1b66984839a46da533f46a4f4c67cb |
Message: | midi2osc: added channel and control number mapping |
Files: |
midi2osc/README (1 diff) midi2osc/midi2osc.c (5 diffs) |
Change Details
midi2osc/README | ||
---|---|---|
19 | 19 | - in the "Connections" window, drag a connection from each MIDI device |
20 | 20 | you want to connect to midi2osc |
21 | 21 | - MIDI events will now show up in the MIDI settings dialog, etc. |
22 | ||
23 | midi2osc can also remap MIDI controls. The syntax is | |
24 | ||
25 | c<chan>[.<control>]=c<chan>[.<control>] | |
26 | ||
27 | where <chan> is a channel number and <control> is the optional control | |
28 | number. For example, | |
29 | ||
30 | ./midi2osc c8.1=c0.1 c8.2=c0.2 c9.1=c0.3 c9.2=c0.4 c0.7=c0.5 c7.7=c0.6 m1 | |
31 | ||
32 | would map the joysticks and two faders of a Faderfox LV3 to the | |
33 | controls 1 through 6 on channel 0, and send the OSC messages to | |
34 | a host called "m1". |
midi2osc/midi2osc.c | ||
---|---|---|
24 | 24 | static int debug = 0; |
25 | 25 | |
26 | 26 | |
27 | static struct map { | |
28 | int chan_in, ctrl_in; | |
29 | int chan_out, ctrl_out; | |
30 | struct map *next; | |
31 | } *mappings = NULL; | |
32 | ||
33 | ||
34 | static void add(int chan_in, int ctrl_in, int chan_out, int ctrl_out) | |
35 | { | |
36 | struct map *new; | |
37 | ||
38 | new = malloc(sizeof(struct map)); | |
39 | new->chan_in = chan_in; | |
40 | new->ctrl_in = ctrl_in; | |
41 | new->chan_out = chan_out; | |
42 | new->ctrl_out = ctrl_out; | |
43 | new->next = mappings; | |
44 | mappings = new; | |
45 | } | |
46 | ||
47 | ||
48 | static void add_mapping(const char *s) | |
49 | { | |
50 | unsigned chan_in, ctrl_in, chan_out, ctrl_out; | |
51 | ||
52 | if (sscanf(s, "c%u.%u=c%u.%u", | |
53 | &chan_in, &ctrl_in, &chan_out, &ctrl_out) == 4) | |
54 | add(chan_in, ctrl_in, chan_out, ctrl_out); | |
55 | else if (sscanf(s, "c%u.%u=c%u", &chan_in, &ctrl_in, &chan_out) == 3) | |
56 | add(chan_in, ctrl_in, chan_out, -1); | |
57 | else if (sscanf(s, "c%u=c%u.%u", &chan_in, &chan_out, &ctrl_out) == 3) | |
58 | add(chan_in, -1, chan_out, ctrl_out); | |
59 | else if (sscanf(s, "c%u=c%u", &chan_in, &chan_out) == 2) | |
60 | add(chan_in, -1, chan_out, -1); | |
61 | else { | |
62 | fprintf(stderr, "unrecognized mapping syntax\n"); | |
63 | exit(1); | |
64 | } | |
65 | } | |
66 | ||
67 | ||
68 | static void map(uint8_t *chan, uint8_t *ctrl) | |
69 | { | |
70 | const struct map *m; | |
71 | ||
72 | for (m = mappings; m; m = m->next) | |
73 | if ((m->chan_in == -1 || m->chan_in == *chan) && | |
74 | (m->ctrl_in == -1 || m->ctrl_in == *ctrl)) { | |
75 | if (m->chan_out != -1) | |
76 | *chan = m->chan_out; | |
77 | if (m->ctrl_out != -1) | |
78 | *ctrl = m->ctrl_out; | |
79 | return; | |
80 | } | |
81 | } | |
82 | ||
83 | ||
27 | 84 | static void forward(snd_seq_t *midi, lo_address osc) |
28 | 85 | { |
29 | 86 | snd_seq_event_t *ev; |
30 | 87 | uint8_t msg[4] = { 0, }; |
88 | uint8_t chan, ctrl; | |
31 | 89 | |
32 | 90 | while (snd_seq_event_input(midi, &ev)) { |
33 | 91 | switch (ev->type) { |
... | ... | |
37 | 95 | msg[3] = ev->data.note.velocity; |
38 | 96 | break; |
39 | 97 | case SND_SEQ_EVENT_CONTROLLER: |
40 | msg[1] = 0xb0 | ev->data.control.channel; | |
41 | msg[2] = ev->data.control.param; | |
98 | chan = ev->data.control.channel; | |
99 | ctrl = ev->data.control.param; | |
100 | map(&chan, &ctrl); | |
42 | 101 | msg[3] = ev->data.control.value; |
43 | 102 | if (debug) |
44 | fprintf(stderr, "CC(%u) %u %u\n", | |
45 | ev->data.control.channel, msg[2], msg[3]); | |
103 | fprintf(stderr, "c%u.%u(%u) -> c%u.%u\n", | |
104 | ev->data.control.channel, | |
105 | ev->data.control.param, msg[3], | |
106 | chan, ctrl); | |
107 | msg[1] = 0xb0 | chan; | |
108 | msg[2] = ctrl; | |
46 | 109 | break; |
47 | 110 | case SND_SEQ_EVENT_PITCHBEND: |
48 | 111 | msg[1] = 0xe0 | ev->data.control.channel; |
... | ... | |
64 | 127 | static void usage(const char *name) |
65 | 128 | { |
66 | 129 | fprintf(stderr, |
67 | "usage: %s hostname [-d] [port]\n\n" | |
130 | "usage: %s hostname [-d] [mapping ...] [port]\n\n" | |
131 | " mappings are of the form c<chan>[.<control>]=c<chan>[.<control>]\n\n" | |
68 | 132 | " -d debug mode: print all MIDI messages\n", |
69 | 133 | name); |
70 | 134 | exit(1); |
... | ... | |
76 | 140 | const char *port = "4444"; /* Milkymist One OSC port */ |
77 | 141 | lo_address osc; |
78 | 142 | snd_seq_t *midi; |
79 | int c; | |
80 | ||
143 | int c, arg; | |
81 | 144 | |
82 | 145 | while ((c = getopt(argc, argv, "d")) != EOF) |
83 | 146 | switch (c) { |
... | ... | |
88 | 151 | usage(*argv); |
89 | 152 | } |
90 | 153 | |
91 | switch (argc-optind) { | |
154 | for (arg = optind; arg != argc; arg++) { | |
155 | if (!strchr(argv[arg], '=')) | |
156 | break; | |
157 | add_mapping(argv[arg]); | |
158 | } | |
159 | switch (argc-arg) { | |
92 | 160 | case 1: |
93 | 161 | break; |
94 | 162 | case 2: |
95 | port = argv[optind+1]; | |
163 | port = argv[arg+1]; | |
96 | 164 | break; |
97 | 165 | default: |
98 | 166 | usage(*argv); |
99 | 167 | } |
100 | 168 | |
101 | osc = lo_address_new(argv[optind], port); | |
169 | osc = lo_address_new(argv[arg], port); | |
102 | 170 | if (!osc) { |
103 | fprintf(stderr, "invalid address %s %s\n", argv[optind], port); | |
171 | fprintf(stderr, "invalid address %s %s\n", argv[arg], port); | |
104 | 172 | exit(1); |
105 | 173 | } |
106 | 174 |
Branches:
master