diff options
Diffstat (limited to 'tools/osx/simulator-osx.c')
-rw-r--r-- | tools/osx/simulator-osx.c | 111 |
1 files changed, 110 insertions, 1 deletions
diff --git a/tools/osx/simulator-osx.c b/tools/osx/simulator-osx.c index 08a7b9a..7298042 100644 --- a/tools/osx/simulator-osx.c +++ b/tools/osx/simulator-osx.c | |||
@@ -35,12 +35,19 @@ | |||
35 | 35 | ||
36 | #include <CoreMIDI/CoreMIDI.h> | 36 | #include <CoreMIDI/CoreMIDI.h> |
37 | 37 | ||
38 | #include <mach/mach_time.h> | ||
39 | |||
38 | ////////////////////////////////////////////////////////////////////////// | 40 | ////////////////////////////////////////////////////////////////////////// |
39 | static MIDIClientRef g_client = 0; | 41 | static MIDIClientRef g_client = 0; |
42 | |||
40 | static MIDIPortRef g_inDevPort = 0; | 43 | static MIDIPortRef g_inDevPort = 0; |
41 | static MIDIPortRef g_outDevPort = 0; | 44 | static MIDIPortRef g_outDevPort = 0; |
45 | |||
42 | static MIDIEndpointRef g_outDevEndpoint = 0; | 46 | static MIDIEndpointRef g_outDevEndpoint = 0; |
43 | 47 | ||
48 | static MIDIEndpointRef g_outVirtualEndpoint = 0; | ||
49 | static MIDIEndpointRef g_inVirtualEndpoint = 0; | ||
50 | |||
44 | static const float TIMER_INTERVAL_S = 0.001; //s | 51 | static const float TIMER_INTERVAL_S = 0.001; //s |
45 | 52 | ||
46 | // ____________________________________________________________________________ | 53 | // ____________________________________________________________________________ |
@@ -65,7 +72,22 @@ void hal_plot_led(u8 type, u8 index, u8 red, u8 green, u8 blue) | |||
65 | 72 | ||
66 | void hal_send_midi(u8 port, u8 status, u8 d1, u8 d2) | 73 | void hal_send_midi(u8 port, u8 status, u8 d1, u8 d2) |
67 | { | 74 | { |
68 | // TODO: send this up a virtual MIDI port? | 75 | if (port == DINMIDI) |
76 | { | ||
77 | // send this up the virtual "DIN" MIDI | ||
78 | u8 data[] = {status, d1, d2}; | ||
79 | |||
80 | // MIDI needs host absolute time, NOT the proper time! | ||
81 | |||
82 | uint64_t timeNow = mach_absolute_time(); | ||
83 | |||
84 | MIDIPacketList packetLst; | ||
85 | MIDIPacket *packet = MIDIPacketListInit(&packetLst); | ||
86 | MIDIPacketListAdd(&packetLst, 3, packet, timeNow, sizeof(data), data); | ||
87 | |||
88 | OSStatus err = MIDIReceived(g_outVirtualEndpoint, &packetLst); | ||
89 | int n=0; | ||
90 | } | ||
69 | } | 91 | } |
70 | 92 | ||
71 | void hal_send_sysex(u8 port, const u8* data, u16 length) | 93 | void hal_send_sysex(u8 port, const u8* data, u16 length) |
@@ -123,6 +145,45 @@ static void processPacket(const unsigned char *data, int length) | |||
123 | } | 145 | } |
124 | } | 146 | } |
125 | 147 | ||
148 | ////////////////////////////////////////////////////////////////////////// | ||
149 | static void processVirtualPortPacket(const unsigned char *data, int length) | ||
150 | { | ||
151 | // parse MIDI (very naively) | ||
152 | while (length > 0) | ||
153 | { | ||
154 | unsigned char status = data[0]; | ||
155 | |||
156 | // Wipe out channel (bottom four bits) | ||
157 | status &= 0xF0; | ||
158 | |||
159 | if (length >= 3) | ||
160 | { | ||
161 | switch (status) | ||
162 | { | ||
163 | case NOTEON: | ||
164 | case NOTEOFF: | ||
165 | case CC: | ||
166 | app_midi_event(DINMIDI, status, data[1], data[2]); | ||
167 | data += 3; | ||
168 | length -= 3; | ||
169 | break; | ||
170 | |||
171 | default: | ||
172 | // Don't know this message, so bail | ||
173 | length--; | ||
174 | data++; | ||
175 | break; | ||
176 | } | ||
177 | } | ||
178 | else | ||
179 | { | ||
180 | // We expected at least three bytes and didn't get them, so bail | ||
181 | length--; | ||
182 | data++; | ||
183 | } | ||
184 | } | ||
185 | } | ||
186 | |||
126 | static void readProc(const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon) | 187 | static void readProc(const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon) |
127 | { | 188 | { |
128 | // farm out the packets | 189 | // farm out the packets |
@@ -137,6 +198,20 @@ static void readProc(const MIDIPacketList *pktlist, void *readProcRefCon, void * | |||
137 | } | 198 | } |
138 | } | 199 | } |
139 | 200 | ||
201 | static void virtualReadProc(const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon) | ||
202 | { | ||
203 | // farm out the packets | ||
204 | const MIDIPacket *packet = &pktlist->packet[0]; | ||
205 | for (int i=0; i < pktlist->numPackets; ++i) | ||
206 | { | ||
207 | // process the packet - in our case, receive a surface message | ||
208 | processVirtualPortPacket(packet->data, packet->length); | ||
209 | |||
210 | // next | ||
211 | packet = MIDIPacketNext(packet); | ||
212 | } | ||
213 | } | ||
214 | |||
140 | static int findLaunchpadPro() | 215 | static int findLaunchpadPro() |
141 | { | 216 | { |
142 | // find the input hardware port | 217 | // find the input hardware port |
@@ -197,6 +272,34 @@ static int findLaunchpadPro() | |||
197 | return !(g_inDevPort && g_outDevPort); | 272 | return !(g_inDevPort && g_outDevPort); |
198 | } | 273 | } |
199 | 274 | ||
275 | static int openVirtualPorts() | ||
276 | { | ||
277 | // create the output port | ||
278 | CFStringRef name = CFStringCreateWithCString(NULL, "LPP Simulator Out", kCFStringEncodingMacRoman); | ||
279 | OSStatus result = MIDISourceCreate(g_client, name, &g_outVirtualEndpoint); | ||
280 | CFRelease(name); | ||
281 | |||
282 | if (noErr != result) | ||
283 | { | ||
284 | return -1; | ||
285 | } | ||
286 | |||
287 | MIDIObjectSetIntegerProperty(g_outVirtualEndpoint, kMIDIPropertyUniqueID, 12325436); | ||
288 | |||
289 | // create the input port | ||
290 | name = CFStringCreateWithCString(NULL, "LPP Simulator In", kCFStringEncodingMacRoman); | ||
291 | result = MIDIDestinationCreate(g_client, name, virtualReadProc, NULL, &g_inVirtualEndpoint); | ||
292 | CFRelease(name); | ||
293 | |||
294 | if (noErr != result) | ||
295 | { | ||
296 | return -1; | ||
297 | } | ||
298 | MIDIObjectSetIntegerProperty(g_outVirtualEndpoint, kMIDIPropertyUniqueID, 34534563); | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
200 | // ____________________________________________________________________________ | 303 | // ____________________________________________________________________________ |
201 | 304 | ||
202 | static void timerCallback(CFRunLoopTimerRef timer, void * info) | 305 | static void timerCallback(CFRunLoopTimerRef timer, void * info) |
@@ -226,6 +329,12 @@ int main(int argc, char * argv[]) | |||
226 | // no Launchpad Pro connected | 329 | // no Launchpad Pro connected |
227 | return -2; | 330 | return -2; |
228 | } | 331 | } |
332 | |||
333 | if (openVirtualPorts()) | ||
334 | { | ||
335 | // no Launchpad Pro connected | ||
336 | return -3; | ||
337 | } | ||
229 | 338 | ||
230 | // now start things up | 339 | // now start things up |
231 | app_init(); | 340 | app_init(); |