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.

173 lines
4.4KB

  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
  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 <jack/jack.h>
  12. #include <string>
  13. #include <cstring>
  14. #include <err.h>
  15. #include <cstdio>
  16. #include <cassert>
  17. #include "Nio.h"
  18. #include "../Misc/Util.h"
  19. #include "../Misc/Master.h"
  20. #include "../Misc/Part.h"
  21. #include "../Misc/MiddleWare.h"
  22. #include "JackMultiEngine.h"
  23. extern MiddleWare *middleware;
  24. using std::string;
  25. struct jack_multi
  26. {
  27. jack_port_t *ports[NUM_MIDI_PARTS * 2 + 2];
  28. jack_client_t *client;
  29. bool running;
  30. };
  31. JackMultiEngine::JackMultiEngine(const SYNTH_T &synth)
  32. :AudioOut(synth), impl(new jack_multi())
  33. {
  34. impl->running = false;
  35. impl->client = NULL;
  36. name = "JACK-MULTI";
  37. }
  38. JackMultiEngine::~JackMultiEngine(void)
  39. {
  40. delete impl;
  41. }
  42. void JackMultiEngine::setAudioEn(bool nval)
  43. {
  44. if(nval)
  45. Start();
  46. else
  47. Stop();
  48. }
  49. bool JackMultiEngine::getAudioEn() const
  50. {
  51. return impl->running;
  52. }
  53. bool JackMultiEngine::Start(void)
  54. {
  55. if(impl->client)
  56. return true;
  57. string clientname = "zynaddsubfx";
  58. string postfix = Nio::getPostfix();
  59. if(!postfix.empty())
  60. clientname += "_" + postfix;
  61. if(Nio::pidInClientName)
  62. clientname += "_" + os_pid_as_padded_string();
  63. jack_status_t jackstatus;
  64. impl->client = jack_client_open(clientname.c_str(), JackNullOption, &jackstatus);
  65. if(!impl->client)
  66. errx(1, "failed to connect to jack...");
  67. //Create the set of jack ports
  68. char portName[20];
  69. memset(portName,0,sizeof(portName));
  70. #define JACK_REGISTER(x) jack_port_register(impl->client, x, \
  71. JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0)
  72. //Create the master wet port
  73. impl->ports[0] = JACK_REGISTER("out-L");
  74. impl->ports[1] = JACK_REGISTER("out-R");
  75. //Create all part's outputs
  76. for(int i = 0; i < NUM_MIDI_PARTS * 2; i += 2) {
  77. snprintf(portName, 19, "part%d/out-L", i / 2);
  78. impl->ports[2 + i] = JACK_REGISTER(portName);
  79. snprintf(portName, 19, "part%d/out-R", i / 2);
  80. impl->ports[3 + i] = JACK_REGISTER(portName);
  81. }
  82. //verify that all sample rate and buffer_size are the same in jack.
  83. //This insures that the connection can be made with no resampling or
  84. //buffering
  85. if(synth.samplerate != jack_get_sample_rate(impl->client))
  86. errx(1, "jack must have the same sample rate!");
  87. if(synth.buffersize != (int) jack_get_buffer_size(impl->client))
  88. errx(1, "jack must have the same buffer size");
  89. jack_set_process_callback(impl->client, _processCallback, this);
  90. //run
  91. if(jack_activate(impl->client))
  92. errx(1, "failed at starting the jack client");
  93. impl->running = true;
  94. return true;
  95. }
  96. int JackMultiEngine::_processCallback(jack_nframes_t nframes, void *arg)
  97. {
  98. return static_cast<JackMultiEngine *>(arg)->processAudio(nframes);
  99. }
  100. int JackMultiEngine::processAudio(jack_nframes_t nframes)
  101. {
  102. //Gather all buffers
  103. float *buffers[NUM_MIDI_PARTS * 2 + 2];
  104. for(int i = 0; i < NUM_MIDI_PARTS * 2 + 2; ++i) {
  105. //Abort if ports are only partially initialized
  106. if(!impl->ports[i])
  107. return false;
  108. buffers[i] =
  109. (float *)jack_port_get_buffer(impl->ports[i], nframes);
  110. assert(buffers[i]);
  111. }
  112. //Get the wet samples from OutMgr
  113. Stereo<float *> smp = getNext();
  114. memcpy(buffers[0], smp.l, synth.bufferbytes);
  115. memcpy(buffers[1], smp.r, synth.bufferbytes);
  116. //Gather other samples from individual parts
  117. Master &master = *middleware->spawnMaster();
  118. for(int i = 0; i < NUM_MIDI_PARTS; ++i) {
  119. memcpy(buffers[2*i + 2], master.part[i]->partoutl, synth.bufferbytes);
  120. memcpy(buffers[2*i + 3], master.part[i]->partoutr, synth.bufferbytes);
  121. }
  122. return false;
  123. }
  124. void JackMultiEngine::Stop()
  125. {
  126. for(int i = 0; i < NUM_MIDI_PARTS * 2 + 2; ++i) {
  127. jack_port_t *port = impl->ports[i];
  128. impl->ports[i] = NULL;
  129. if(port)
  130. jack_port_unregister(impl->client, port);
  131. }
  132. if(impl->client)
  133. jack_client_close(impl->client);
  134. impl->client = NULL;
  135. impl->running = false;
  136. }