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.

178 lines
4.7KB

  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. JackMultiEngine.cpp - Channeled Audio output JACK
  4. Copyright (C) 2012-2012 Mark McCurry
  5. Author: Mark McCurry
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of version 2 of the GNU General Public License
  8. as published by the Free Software Foundation.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License (version 2 or later) for more details.
  13. You should have received a copy of the GNU General Public License (version 2)
  14. along with this program; if not, write to the Free Software Foundation,
  15. Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. */
  17. #include <jack/jack.h>
  18. #include <string>
  19. #include <cstring>
  20. #include <err.h>
  21. #include <cstdio>
  22. #include <cassert>
  23. #include "Nio.h"
  24. #include "../Misc/Util.h"
  25. #include "../Misc/Master.h"
  26. #include "../Misc/Part.h"
  27. #include "../Misc/MiddleWare.h"
  28. #include "JackMultiEngine.h"
  29. extern MiddleWare *middleware;
  30. using std::string;
  31. struct jack_multi
  32. {
  33. jack_port_t *ports[NUM_MIDI_PARTS * 2 + 2];
  34. jack_client_t *client;
  35. bool running;
  36. };
  37. JackMultiEngine::JackMultiEngine(const SYNTH_T &synth)
  38. :AudioOut(synth), impl(new jack_multi())
  39. {
  40. impl->running = false;
  41. impl->client = NULL;
  42. name = "JACK-MULTI";
  43. }
  44. JackMultiEngine::~JackMultiEngine(void)
  45. {
  46. delete impl;
  47. }
  48. void JackMultiEngine::setAudioEn(bool nval)
  49. {
  50. if(nval)
  51. Start();
  52. else
  53. Stop();
  54. }
  55. bool JackMultiEngine::getAudioEn() const
  56. {
  57. return impl->running;
  58. }
  59. bool JackMultiEngine::Start(void)
  60. {
  61. if(impl->client)
  62. return true;
  63. string clientname = "zynaddsubfx";
  64. string postfix = Nio::getPostfix();
  65. if(!postfix.empty())
  66. clientname += "_" + postfix;
  67. if(Nio::pidInClientName)
  68. clientname += "_" + os_pid_as_padded_string();
  69. jack_status_t jackstatus;
  70. impl->client = jack_client_open(clientname.c_str(), JackNullOption, &jackstatus);
  71. if(!impl->client)
  72. errx(1, "failed to connect to jack...");
  73. //Create the set of jack ports
  74. char portName[20];
  75. memset(portName,0,sizeof(portName));
  76. #define JACK_REGISTER(x) jack_port_register(impl->client, x, \
  77. JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0)
  78. //Create the master wet port
  79. impl->ports[0] = JACK_REGISTER("out-L");
  80. impl->ports[1] = JACK_REGISTER("out-R");
  81. //Create all part's outputs
  82. for(int i = 0; i < NUM_MIDI_PARTS * 2; i += 2) {
  83. snprintf(portName, 19, "part%d/out-L", i / 2);
  84. impl->ports[2 + i] = JACK_REGISTER(portName);
  85. snprintf(portName, 19, "part%d/out-R", i / 2);
  86. impl->ports[3 + i] = JACK_REGISTER(portName);
  87. }
  88. //verify that all sample rate and buffer_size are the same in jack.
  89. //This insures that the connection can be made with no resampling or
  90. //buffering
  91. if(synth.samplerate != jack_get_sample_rate(impl->client))
  92. errx(1, "jack must have the same sample rate!");
  93. if(synth.buffersize != (int) jack_get_buffer_size(impl->client))
  94. errx(1, "jack must have the same buffer size");
  95. jack_set_process_callback(impl->client, _processCallback, this);
  96. //run
  97. if(jack_activate(impl->client))
  98. errx(1, "failed at starting the jack client");
  99. impl->running = true;
  100. return true;
  101. }
  102. int JackMultiEngine::_processCallback(jack_nframes_t nframes, void *arg)
  103. {
  104. return static_cast<JackMultiEngine *>(arg)->processAudio(nframes);
  105. }
  106. int JackMultiEngine::processAudio(jack_nframes_t nframes)
  107. {
  108. //Gather all buffers
  109. float *buffers[NUM_MIDI_PARTS * 2 + 2];
  110. for(int i = 0; i < NUM_MIDI_PARTS * 2 + 2; ++i) {
  111. buffers[i] =
  112. (float *)jack_port_get_buffer(impl->ports[i], nframes);
  113. assert(buffers[i]);
  114. }
  115. //Get the wet samples from OutMgr
  116. Stereo<float *> smp = getNext();
  117. memcpy(buffers[0], smp.l, synth.bufferbytes);
  118. memcpy(buffers[1], smp.r, synth.bufferbytes);
  119. //Gather other samples from individual parts
  120. Master &master = *middleware->spawnMaster();
  121. for(int i = 0; i < NUM_MIDI_PARTS; ++i) {
  122. memcpy(buffers[2*i + 2], master.part[i]->partoutl, synth.bufferbytes);
  123. memcpy(buffers[2*i + 3], master.part[i]->partoutr, synth.bufferbytes);
  124. }
  125. return false;
  126. }
  127. void JackMultiEngine::Stop()
  128. {
  129. for(int i = 0; i < NUM_MIDI_PARTS * 2 + 2; ++i) {
  130. jack_port_t *port = impl->ports[i];
  131. impl->ports[i] = NULL;
  132. if(port)
  133. jack_port_unregister(impl->client, port);
  134. }
  135. if(impl->client)
  136. jack_client_close(impl->client);
  137. impl->client = NULL;
  138. impl->running = false;
  139. }