jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

437 lines
15KB

  1. /*
  2. Copyright (C) 2009 Grame
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #include "JackCoreMidiDriver.h"
  16. #include "JackGraphManager.h"
  17. #include "JackServer.h"
  18. #include "JackEngineControl.h"
  19. #include "JackDriverLoader.h"
  20. #include <mach/mach_time.h>
  21. #include <assert.h>
  22. #include <iostream>
  23. #include <sstream>
  24. #include <string>
  25. namespace Jack
  26. {
  27. static MIDITimeStamp MIDIGetCurrentHostTime()
  28. {
  29. return mach_absolute_time();
  30. }
  31. void JackCoreMidiDriver::ReadProcAux(const MIDIPacketList *pktlist, jack_ringbuffer_t* ringbuffer)
  32. {
  33. // Write the number of packets
  34. size_t size = jack_ringbuffer_write_space(ringbuffer);
  35. if (size < sizeof(UInt32)) {
  36. jack_error("ReadProc : ring buffer is full, skip events...");
  37. return;
  38. }
  39. jack_ringbuffer_write(ringbuffer, (char*)&pktlist->numPackets, sizeof(UInt32));
  40. for (unsigned int i = 0; i < pktlist->numPackets; ++i) {
  41. MIDIPacket *packet = (MIDIPacket *)pktlist->packet;
  42. // TODO : use timestamp
  43. // Check available size first..
  44. size = jack_ringbuffer_write_space(ringbuffer);
  45. if (size < (sizeof(UInt16) + packet->length)) {
  46. jack_error("ReadProc : ring buffer is full, skip events...");
  47. return;
  48. }
  49. // Write length of each packet first
  50. jack_ringbuffer_write(ringbuffer, (char*)&packet->length, sizeof(UInt16));
  51. // Write event actual data
  52. jack_ringbuffer_write(ringbuffer, (char*)packet->data, packet->length);
  53. packet = MIDIPacketNext(packet);
  54. }
  55. }
  56. void JackCoreMidiDriver::ReadProc(const MIDIPacketList *pktlist, void *refCon, void *connRefCon)
  57. {
  58. jack_ringbuffer_t* ringbuffer = (jack_ringbuffer_t*)connRefCon;
  59. ReadProcAux(pktlist, ringbuffer);
  60. }
  61. void JackCoreMidiDriver::ReadVirtualProc(const MIDIPacketList *pktlist, void *refCon, void *connRefCon)
  62. {
  63. jack_ringbuffer_t* ringbuffer = (jack_ringbuffer_t*)refCon;
  64. ReadProcAux(pktlist, ringbuffer);
  65. }
  66. void JackCoreMidiDriver::NotifyProc(const MIDINotification *message, void *refCon)
  67. {
  68. jack_log("NotifyProc %d", message->messageID);
  69. }
  70. JackCoreMidiDriver::JackCoreMidiDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table)
  71. : JackMidiDriver(name, alias, engine, table), fMidiClient(NULL), fInputPort(NULL), fOutputPort(NULL), fRealCaptureChannels(0), fRealPlaybackChannels(0)
  72. {}
  73. JackCoreMidiDriver::~JackCoreMidiDriver()
  74. {}
  75. int JackCoreMidiDriver::Open(bool capturing,
  76. bool playing,
  77. int inchannels,
  78. int outchannels,
  79. bool monitor,
  80. const char* capture_driver_name,
  81. const char* playback_driver_name,
  82. jack_nframes_t capture_latency,
  83. jack_nframes_t playback_latency)
  84. {
  85. OSStatus err;
  86. CFStringRef coutputStr;
  87. std::string str;
  88. // Get real input/output number
  89. fRealCaptureChannels = MIDIGetNumberOfSources();
  90. fRealPlaybackChannels = MIDIGetNumberOfDestinations();
  91. // Generic JackMidiDriver Open
  92. if (JackMidiDriver::Open(capturing, playing, inchannels + fRealCaptureChannels, outchannels + fRealPlaybackChannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0)
  93. return -1;
  94. coutputStr = CFStringCreateWithCString(0, "JackMidi", CFStringGetSystemEncoding());
  95. err = MIDIClientCreate(coutputStr, NotifyProc, this, &fMidiClient);
  96. CFRelease(coutputStr);
  97. if (!fMidiClient) {
  98. jack_error("Cannot create CoreMidi client");
  99. goto error;
  100. }
  101. err = MIDIInputPortCreate(fMidiClient, CFSTR("Input port"), ReadProc, this, &fInputPort);
  102. if (!fInputPort) {
  103. jack_error("Cannot open CoreMidi in port\n");
  104. goto error;
  105. }
  106. err = MIDIOutputPortCreate(fMidiClient, CFSTR("Output port"), &fOutputPort);
  107. if (!fOutputPort) {
  108. jack_error("Cannot open CoreMidi out port\n");
  109. goto error;
  110. }
  111. fMidiDestination = new MIDIEndpointRef[inchannels + fRealCaptureChannels];
  112. assert(fMidiDestination);
  113. // Virtual input
  114. for (int i = 0; i < inchannels; i++) {
  115. std::stringstream num;
  116. num << i;
  117. str = "JackMidi" + num.str();
  118. coutputStr = CFStringCreateWithCString(0, str.c_str(), CFStringGetSystemEncoding());
  119. err = MIDIDestinationCreate(fMidiClient, coutputStr, ReadVirtualProc, fRingBuffer[i], &fMidiDestination[i]);
  120. CFRelease(coutputStr);
  121. if (!fMidiDestination[i]) {
  122. jack_error("Cannot create CoreMidi destination");
  123. goto error;
  124. }
  125. }
  126. // Real input
  127. for (int i = 0; i < fRealCaptureChannels; i++) {
  128. fMidiDestination[i + inchannels] = MIDIGetSource(i);
  129. MIDIPortConnectSource(fInputPort, fMidiDestination[i + inchannels], fRingBuffer[i + inchannels]);
  130. }
  131. fMidiSource = new MIDIEndpointRef[outchannels + fRealPlaybackChannels];
  132. assert(fMidiSource);
  133. // Virtual output
  134. for (int i = 0; i < outchannels; i++) {
  135. std::stringstream num;
  136. num << i;
  137. str = "JackMidi" + num.str();
  138. coutputStr = CFStringCreateWithCString(0, str.c_str(), CFStringGetSystemEncoding());
  139. err = MIDISourceCreate(fMidiClient, coutputStr, &fMidiSource[i]);
  140. CFRelease(coutputStr);
  141. if (!fMidiSource[i]) {
  142. jack_error("Cannot create CoreMidi source");
  143. goto error;
  144. }
  145. }
  146. // Real output
  147. for (int i = 0; i < fRealPlaybackChannels; i++) {
  148. fMidiSource[i + outchannels] = MIDIGetDestination(i);
  149. }
  150. return 0;
  151. error:
  152. Close();
  153. return -1;
  154. }
  155. int JackCoreMidiDriver::Close()
  156. {
  157. // Generic midi driver close
  158. int res = JackMidiDriver::Close();
  159. if (fInputPort)
  160. MIDIPortDispose(fInputPort);
  161. if (fOutputPort)
  162. MIDIPortDispose(fOutputPort);
  163. // Only dispose "virtual" endpoints
  164. for (int i = 0; i < fCaptureChannels - fRealCaptureChannels; i++) {
  165. if (fMidiDestination)
  166. MIDIEndpointDispose(fMidiDestination[i]);
  167. }
  168. delete[] fMidiDestination;
  169. // Only dispose "virtual" endpoints
  170. for (int i = 0; i < fPlaybackChannels - fRealPlaybackChannels; i++) {
  171. if (fMidiSource[i])
  172. MIDIEndpointDispose(fMidiSource[i]);
  173. }
  174. delete[] fMidiSource;
  175. if (fMidiClient)
  176. MIDIClientDispose(fMidiClient);
  177. return res;
  178. }
  179. int JackCoreMidiDriver::Attach()
  180. {
  181. OSStatus err;
  182. JackPort* port;
  183. CFStringRef pname;
  184. jack_port_id_t port_index;
  185. char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
  186. char endpoint_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
  187. char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
  188. jack_latency_range_t latency_range;
  189. jack_nframes_t latency = fEngineControl->fBufferSize;
  190. int i;
  191. jack_log("JackCoreMidiDriver::Attach fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
  192. latency_range.max = latency_range.min = latency;
  193. for (i = 0; i < fCaptureChannels; i++) {
  194. err = MIDIObjectGetStringProperty(fMidiDestination[i], kMIDIPropertyName, &pname);
  195. if (err == noErr) {
  196. CFStringGetCString(pname, endpoint_name, sizeof(endpoint_name), 0);
  197. CFRelease(pname);
  198. snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, endpoint_name, i + 1);
  199. } else {
  200. snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, fCaptureDriverName, i + 1);
  201. }
  202. snprintf(name, sizeof(name) - 1, "%s:capture_%d", fClientControl.fName, i + 1);
  203. if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE, CaptureDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) {
  204. jack_error("driver: cannot register port for %s", name);
  205. return -1;
  206. }
  207. port = fGraphManager->GetPort(port_index);
  208. port->SetAlias(alias);
  209. port->SetLatencyRange(JackCaptureLatency, &latency_range);
  210. fCapturePortList[i] = port_index;
  211. jack_log("JackCoreMidiDriver::Attach fCapturePortList[i] port_index = %ld", port_index);
  212. }
  213. if (!fEngineControl->fSyncMode) {
  214. latency += fEngineControl->fBufferSize;;
  215. latency_range.max = latency_range.min = latency;
  216. }
  217. for (i = 0; i < fPlaybackChannels; i++) {
  218. err = MIDIObjectGetStringProperty(fMidiSource[i], kMIDIPropertyName, &pname);
  219. if (err == noErr) {
  220. CFStringGetCString(pname, endpoint_name, sizeof(endpoint_name), 0);
  221. CFRelease(pname);
  222. snprintf(alias, sizeof(alias) - 1, "%s:%s:in%d", fAliasName, endpoint_name, i + 1);
  223. } else {
  224. snprintf(alias, sizeof(alias) - 1, "%s:%s:in%d", fAliasName, fPlaybackDriverName, i + 1);
  225. }
  226. snprintf(name, sizeof(name) - 1, "%s:playback_%d", fClientControl.fName, i + 1);
  227. if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE, PlaybackDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) {
  228. jack_error("driver: cannot register port for %s", name);
  229. return -1;
  230. }
  231. port = fGraphManager->GetPort(port_index);
  232. port->SetAlias(alias);
  233. port->SetLatencyRange(JackPlaybackLatency, &latency_range);
  234. fPlaybackPortList[i] = port_index;
  235. jack_log("JackCoreMidiDriver::Attach fPlaybackPortList[i] port_index = %ld", port_index);
  236. }
  237. return 0;
  238. }
  239. int JackCoreMidiDriver::Read()
  240. {
  241. for (int chan = 0; chan < fCaptureChannels; chan++) {
  242. if (fGraphManager->GetConnectionsNum(fCapturePortList[chan]) > 0) {
  243. // Get JACK port
  244. JackMidiBuffer* midi_buffer = GetInputBuffer(chan);
  245. if (jack_ringbuffer_read_space(fRingBuffer[chan]) == 0) {
  246. // Reset buffer
  247. midi_buffer->Reset(midi_buffer->nframes);
  248. } else {
  249. while (jack_ringbuffer_read_space(fRingBuffer[chan]) > 0) {
  250. // Read event number
  251. int ev_count = 0;
  252. jack_ringbuffer_read(fRingBuffer[chan], (char*)&ev_count, sizeof(int));
  253. for (int j = 0; j < ev_count; j++) {
  254. // Read event length
  255. UInt16 event_len;
  256. jack_ringbuffer_read(fRingBuffer[chan], (char*)&event_len, sizeof(UInt16));
  257. // Read event actual data
  258. jack_midi_data_t* dest = midi_buffer->ReserveEvent(0, event_len);
  259. jack_ringbuffer_read(fRingBuffer[chan], (char*)dest, event_len);
  260. }
  261. }
  262. }
  263. } else {
  264. // Consume ring buffer
  265. jack_ringbuffer_read_advance(fRingBuffer[chan], jack_ringbuffer_read_space(fRingBuffer[chan]));
  266. }
  267. }
  268. return 0;
  269. }
  270. int JackCoreMidiDriver::Write()
  271. {
  272. MIDIPacketList* pktlist = (MIDIPacketList*)fMIDIBuffer;
  273. for (int chan = 0; chan < fPlaybackChannels; chan++) {
  274. if (fGraphManager->GetConnectionsNum(fPlaybackPortList[chan]) > 0) {
  275. MIDIPacket* packet = MIDIPacketListInit(pktlist);
  276. JackMidiBuffer* midi_buffer = GetOutputBuffer(chan);
  277. // TODO : use timestamp
  278. for (unsigned int j = 0; j < midi_buffer->event_count; j++) {
  279. JackMidiEvent* ev = &midi_buffer->events[j];
  280. packet = MIDIPacketListAdd(pktlist, sizeof(fMIDIBuffer), packet, MIDIGetCurrentHostTime(), ev->size, ev->GetData(midi_buffer));
  281. }
  282. if (packet) {
  283. if (chan < fPlaybackChannels - fRealPlaybackChannels) {
  284. OSStatus err = MIDIReceived(fMidiSource[chan], pktlist);
  285. if (err != noErr)
  286. jack_error("MIDIReceived error");
  287. } else {
  288. OSStatus err = MIDISend(fOutputPort, fMidiSource[chan], pktlist);
  289. if (err != noErr)
  290. jack_error("MIDISend error");
  291. }
  292. }
  293. }
  294. }
  295. return 0;
  296. }
  297. } // end of namespace
  298. #ifdef __cplusplus
  299. extern "C"
  300. {
  301. #endif
  302. SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor()
  303. {
  304. jack_driver_desc_t * desc;
  305. unsigned int i;
  306. desc = (jack_driver_desc_t*)calloc (1, sizeof (jack_driver_desc_t));
  307. strcpy(desc->name, "coremidi"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1
  308. strcpy(desc->desc, "Apple CoreMIDI API based MIDI backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
  309. desc->nparams = 2;
  310. desc->params = (jack_driver_param_desc_t*)calloc (desc->nparams, sizeof (jack_driver_param_desc_t));
  311. i = 0;
  312. strcpy(desc->params[i].name, "inchannels");
  313. desc->params[i].character = 'i';
  314. desc->params[i].type = JackDriverParamInt;
  315. desc->params[i].value.ui = 0;
  316. strcpy(desc->params[i].short_desc, "CoreMIDI virtual bus");
  317. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  318. i++;
  319. strcpy(desc->params[i].name, "outchannels");
  320. desc->params[i].character = 'o';
  321. desc->params[i].type = JackDriverParamInt;
  322. desc->params[i].value.ui = 0;
  323. strcpy(desc->params[i].short_desc, "CoreMIDI virtual bus");
  324. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  325. return desc;
  326. }
  327. SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
  328. {
  329. const JSList * node;
  330. const jack_driver_param_t * param;
  331. int virtual_in = 0;
  332. int virtual_out = 0;
  333. for (node = params; node; node = jack_slist_next (node)) {
  334. param = (const jack_driver_param_t *) node->data;
  335. switch (param->character) {
  336. case 'i':
  337. virtual_in = param->value.ui;
  338. break;
  339. case 'o':
  340. virtual_out = param->value.ui;
  341. break;
  342. }
  343. }
  344. Jack::JackDriverClientInterface* driver = new Jack::JackCoreMidiDriver("system_midi", "coremidi", engine, table);
  345. if (driver->Open(1, 1, virtual_in, virtual_out, false, "in", "out", 0, 0) == 0) {
  346. return driver;
  347. } else {
  348. delete driver;
  349. return NULL;
  350. }
  351. }
  352. #ifdef __cplusplus
  353. }
  354. #endif