Audio plugin host https://kx.studio/carla
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.

JackEngine.cpp 12KB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. JackEngine.cpp - Jack Driver
  4. Copyright (C) 2009 Alan Calvert
  5. Copyright (C) 2014 Mark McCurry
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or (at your option) any later version.
  10. */
  11. #include <iostream>
  12. #include <jack/midiport.h>
  13. #ifdef JACK_HAS_METADATA_API
  14. # include <jack/metadata.h>
  15. #endif // JACK_HAS_METADATA_API
  16. #include "jack_osc.h"
  17. #include <fcntl.h>
  18. #include <sys/stat.h>
  19. #include <cassert>
  20. #include <cstring>
  21. #include <unistd.h> // access()
  22. #include <fstream> // std::istream
  23. #include "Nio.h"
  24. #include "OutMgr.h"
  25. #include "InMgr.h"
  26. #include "Misc/Util.h"
  27. #include "JackEngine.h"
  28. using namespace std;
  29. extern char *instance_name;
  30. JackEngine::JackEngine(const SYNTH_T &synth)
  31. :AudioOut(synth), jackClient(NULL)
  32. {
  33. name = "JACK";
  34. audio.jackSamplerate = 0;
  35. audio.jackNframes = 0;
  36. for(int i = 0; i < 2; ++i) {
  37. audio.ports[i] = NULL;
  38. audio.portBuffs[i] = NULL;
  39. }
  40. midi.inport = NULL;
  41. midi.jack_sync = false;
  42. osc.oscport = NULL;
  43. }
  44. bool JackEngine::connectServer(string server)
  45. {
  46. bool autostart_jack = true;
  47. if(jackClient)
  48. return true;
  49. string clientname = "zynaddsubfx";
  50. string postfix = Nio::getPostfix();
  51. if(!postfix.empty())
  52. clientname += "_" + postfix;
  53. if(Nio::pidInClientName)
  54. clientname += "_" + os_pid_as_padded_string();
  55. jack_status_t jackstatus;
  56. bool use_server_name = server.size() && server.compare("default") != 0;
  57. jack_options_t jopts = (jack_options_t)
  58. (((!instance_name
  59. && use_server_name) ? JackServerName :
  60. JackNullOption)
  61. | ((autostart_jack) ? JackNullOption :
  62. JackNoStartServer));
  63. if(instance_name)
  64. jackClient = jack_client_open(instance_name, jopts, &jackstatus);
  65. else {
  66. if(use_server_name)
  67. jackClient = jack_client_open(
  68. clientname.c_str(), jopts, &jackstatus,
  69. server.c_str());
  70. else
  71. jackClient = jack_client_open(
  72. clientname.c_str(), jopts, &jackstatus);
  73. }
  74. if(NULL != jackClient)
  75. return true;
  76. else
  77. cerr << "Error, failed to open jack client on server: " << server
  78. << " status " << jackstatus << endl;
  79. return false;
  80. }
  81. bool JackEngine::connectJack()
  82. {
  83. connectServer("");
  84. if(NULL != jackClient) {
  85. setBufferSize(jack_get_buffer_size(jackClient));
  86. jack_set_error_function(_errorCallback);
  87. jack_set_info_function(_infoCallback);
  88. if(jack_set_buffer_size_callback(jackClient, _bufferSizeCallback, this))
  89. cerr << "Error setting the bufferSize callback" << endl;
  90. if((jack_set_xrun_callback(jackClient, _xrunCallback, this)))
  91. cerr << "Error setting jack xrun callback" << endl;
  92. if(jack_set_process_callback(jackClient, _processCallback, this)) {
  93. cerr << "Error, JackEngine failed to set process callback" << endl;
  94. return false;
  95. }
  96. if(jack_activate(jackClient)) {
  97. cerr << "Error, failed to activate jack client" << endl;
  98. return false;
  99. }
  100. return true;
  101. }
  102. else
  103. cerr << "Error, NULL jackClient through Start()" << endl;
  104. return false;
  105. }
  106. void JackEngine::disconnectJack()
  107. {
  108. if(jackClient) {
  109. cout << "Deactivating and closing JACK client" << endl;
  110. jack_deactivate(jackClient);
  111. jack_client_close(jackClient);
  112. jackClient = NULL;
  113. }
  114. }
  115. bool JackEngine::Start()
  116. {
  117. return openMidi() && openAudio();
  118. }
  119. void JackEngine::Stop()
  120. {
  121. stopMidi();
  122. stopAudio();
  123. }
  124. void JackEngine::setMidiEn(bool nval)
  125. {
  126. if(nval)
  127. openMidi();
  128. else
  129. stopMidi();
  130. }
  131. bool JackEngine::getMidiEn() const
  132. {
  133. return midi.inport;
  134. }
  135. void JackEngine::setAudioEn(bool nval)
  136. {
  137. if(nval)
  138. openAudio();
  139. else
  140. stopAudio();
  141. }
  142. bool JackEngine::getAudioEn() const
  143. {
  144. return audio.ports[0];
  145. }
  146. bool JackEngine::openAudio()
  147. {
  148. if(getAudioEn())
  149. return true;
  150. if(!getMidiEn())
  151. if(!connectJack())
  152. return false;
  153. const char *portnames[] = { "out_1", "out_2" };
  154. for(int port = 0; port < 2; ++port)
  155. audio.ports[port] = jack_port_register(
  156. jackClient,
  157. portnames[port],
  158. JACK_DEFAULT_AUDIO_TYPE,
  159. JackPortIsOutput
  160. | JackPortIsTerminal,
  161. 0);
  162. if((NULL != audio.ports[0]) && (NULL != audio.ports[1])) {
  163. audio.jackSamplerate = jack_get_sample_rate(jackClient);
  164. audio.jackNframes = jack_get_buffer_size(jackClient);
  165. samplerate = audio.jackSamplerate;
  166. bufferSize = audio.jackNframes;
  167. //Attempt to autoConnect when specified
  168. if(Nio::autoConnect) {
  169. const char **outPorts = jack_get_ports(
  170. jackClient,
  171. NULL,
  172. NULL,
  173. JackPortIsPhysical
  174. | JackPortIsInput);
  175. if(outPorts != NULL) {
  176. //Verify that stereo is available
  177. assert(outPorts[0]);
  178. assert(outPorts[1]);
  179. //Connect to physical outputs
  180. jack_connect(jackClient, jack_port_name(
  181. audio.ports[0]), outPorts[0]);
  182. jack_connect(jackClient, jack_port_name(
  183. audio.ports[1]), outPorts[1]);
  184. }
  185. else
  186. cerr << "Warning, No outputs to autoconnect to" << endl;
  187. }
  188. midi.jack_sync = true;
  189. osc.oscport = jack_port_register(jackClient, "osc",
  190. JACK_DEFAULT_OSC_TYPE, JackPortIsInput, 0);
  191. #ifdef JACK_HAS_METADATA_API
  192. jack_uuid_t uuid = jack_port_uuid(osc.oscport);
  193. jack_set_property(jackClient, uuid, "http://jackaudio.org/metadata/event-types", JACK_EVENT_TYPE__OSC, "text/plain");
  194. #endif // JACK_HAS_METADATA_API
  195. return true;
  196. }
  197. else
  198. cerr << "Error, failed to register jack audio ports" << endl;
  199. midi.jack_sync = false;
  200. return false;
  201. }
  202. void JackEngine::stopAudio()
  203. {
  204. for(int i = 0; i < 2; ++i) {
  205. jack_port_t *port = audio.ports[i];
  206. audio.ports[i] = NULL;
  207. if(jackClient != NULL && NULL != port)
  208. jack_port_unregister(jackClient, port);
  209. }
  210. midi.jack_sync = false;
  211. if(osc.oscport) {
  212. if (jackClient != NULL) {
  213. jack_port_unregister(jackClient, osc.oscport);
  214. #ifdef JACK_HAS_METADATA_API
  215. jack_uuid_t uuid = jack_port_uuid(osc.oscport);
  216. jack_remove_property(jackClient, uuid, "http://jackaudio.org/metadata/event-types");
  217. #endif // JACK_HAS_METADATA_API
  218. }
  219. }
  220. if(!getMidiEn())
  221. disconnectJack();
  222. }
  223. bool JackEngine::openMidi()
  224. {
  225. if(getMidiEn())
  226. return true;
  227. if(!getAudioEn())
  228. if(!connectJack())
  229. return false;
  230. midi.inport = jack_port_register(jackClient, "midi_input",
  231. JACK_DEFAULT_MIDI_TYPE,
  232. JackPortIsInput | JackPortIsTerminal, 0);
  233. return midi.inport;
  234. }
  235. void JackEngine::stopMidi()
  236. {
  237. jack_port_t *port = midi.inport;
  238. midi.inport = NULL;
  239. if(port)
  240. jack_port_unregister(jackClient, port);
  241. if(!getAudioEn())
  242. disconnectJack();
  243. }
  244. int JackEngine::clientId()
  245. {
  246. if(NULL != jackClient)
  247. return (long)jack_client_thread_id(jackClient);
  248. else
  249. return -1;
  250. }
  251. string JackEngine::clientName()
  252. {
  253. if(NULL != jackClient)
  254. return string(jack_get_client_name(jackClient));
  255. else
  256. cerr << "Error, clientName() with null jackClient" << endl;
  257. return string("Oh, yoshimi :-(");
  258. }
  259. int JackEngine::_processCallback(jack_nframes_t nframes, void *arg)
  260. {
  261. return static_cast<JackEngine *>(arg)->processCallback(nframes);
  262. }
  263. int JackEngine::processCallback(jack_nframes_t nframes)
  264. {
  265. bool okaudio = true;
  266. handleMidi(nframes);
  267. if((NULL != audio.ports[0]) && (NULL != audio.ports[1]))
  268. okaudio = processAudio(nframes);
  269. return okaudio ? 0 : -1;
  270. }
  271. bool JackEngine::processAudio(jack_nframes_t nframes)
  272. {
  273. //handle rt osc events first
  274. void *oscport = jack_port_get_buffer(osc.oscport, nframes);
  275. size_t osc_packets = jack_osc_get_event_count(oscport);
  276. for(size_t i = 0; i < osc_packets; ++i) {
  277. jack_osc_event_t event;
  278. if(jack_osc_event_get(&event, oscport, i))
  279. continue;
  280. if(*event.buffer!='/') //Bundles are unhandled
  281. continue;
  282. //TODO validate message length
  283. OutMgr::getInstance().applyOscEventRt((char*)event.buffer);
  284. }
  285. for(int port = 0; port < 2; ++port) {
  286. audio.portBuffs[port] =
  287. (jsample_t *)jack_port_get_buffer(audio.ports[port], nframes);
  288. if(NULL == audio.portBuffs[port]) {
  289. cerr << "Error, failed to get jack audio port buffer: "
  290. << port << endl;
  291. return false;
  292. }
  293. }
  294. Stereo<float *> smp = getNext();
  295. //Assumes size of smp.l == nframes
  296. memcpy(audio.portBuffs[0], smp.l, bufferSize * sizeof(float));
  297. memcpy(audio.portBuffs[1], smp.r, bufferSize * sizeof(float));
  298. return true;
  299. }
  300. int JackEngine::_xrunCallback(void *)
  301. {
  302. cerr << "Jack reports xrun" << endl;
  303. return 0;
  304. }
  305. void JackEngine::_errorCallback(const char *msg)
  306. {
  307. cerr << "Jack reports error: " << msg << endl;
  308. }
  309. void JackEngine::_infoCallback(const char *msg)
  310. {
  311. cerr << "Jack info message: " << msg << endl;
  312. }
  313. int JackEngine::_bufferSizeCallback(jack_nframes_t nframes, void *arg)
  314. {
  315. return static_cast<JackEngine *>(arg)->bufferSizeCallback(nframes);
  316. }
  317. int JackEngine::bufferSizeCallback(jack_nframes_t nframes)
  318. {
  319. cerr << "Jack buffer resized" << endl;
  320. setBufferSize(nframes);
  321. return 0;
  322. }
  323. void JackEngine::handleMidi(unsigned long frames)
  324. {
  325. if(!midi.inport)
  326. return;
  327. void *midi_buf = jack_port_get_buffer(midi.inport, frames);
  328. jack_midi_event_t jack_midi_event;
  329. jack_nframes_t event_index = 0;
  330. unsigned char *midi_data;
  331. unsigned char type;
  332. while(jack_midi_event_get(&jack_midi_event, midi_buf,
  333. event_index++) == 0) {
  334. MidiEvent ev;
  335. midi_data = jack_midi_event.buffer;
  336. type = midi_data[0] & 0xF0;
  337. ev.channel = midi_data[0] & 0x0F;
  338. ev.time = midi.jack_sync ? jack_midi_event.time : 0;
  339. switch(type) {
  340. case 0x80: /* note-off */
  341. ev.type = M_NOTE;
  342. ev.num = midi_data[1];
  343. ev.value = 0;
  344. InMgr::getInstance().putEvent(ev);
  345. break;
  346. case 0x90: /* note-on */
  347. ev.type = M_NOTE;
  348. ev.num = midi_data[1];
  349. ev.value = midi_data[2];
  350. InMgr::getInstance().putEvent(ev);
  351. break;
  352. case 0xA0: /* pressure, aftertouch */
  353. ev.type = M_PRESSURE;
  354. ev.num = midi_data[1];
  355. ev.value = midi_data[2];
  356. InMgr::getInstance().putEvent(ev);
  357. break;
  358. case 0xB0: /* controller */
  359. ev.type = M_CONTROLLER;
  360. ev.num = midi_data[1];
  361. ev.value = midi_data[2];
  362. InMgr::getInstance().putEvent(ev);
  363. break;
  364. case 0xC0: /* program change */
  365. ev.type = M_PGMCHANGE;
  366. ev.num = midi_data[1];
  367. ev.value = 0;
  368. InMgr::getInstance().putEvent(ev);
  369. break;
  370. case 0xE0: /* pitch bend */
  371. ev.type = M_CONTROLLER;
  372. ev.num = C_pitchwheel;
  373. ev.value = ((midi_data[2] << 7) | midi_data[1]) - 8192;
  374. InMgr::getInstance().putEvent(ev);
  375. break;
  376. /* XXX TODO: handle MSB/LSB controllers and RPNs and NRPNs */
  377. }
  378. }
  379. }