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.

JackMultiEngine.cpp 4.4KB

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