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.

205 lines
5.0KB

  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. OutMgr.cpp - Audio Output Manager
  4. Copyright (C) 2016 Mark McCurry
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation; either version 2
  8. of the License, or (at your option) any later version.
  9. */
  10. #include "OutMgr.h"
  11. #include <algorithm>
  12. #include <iostream>
  13. #include <cassert>
  14. #include "AudioOut.h"
  15. #include "Engine.h"
  16. #include "EngineMgr.h"
  17. #include "InMgr.h"
  18. #include "WavEngine.h"
  19. #include "../Misc/Master.h"
  20. #include "../Misc/Util.h" //for set_realtime()
  21. using namespace std;
  22. namespace zyncarla {
  23. OutMgr &OutMgr::getInstance(const SYNTH_T *synth)
  24. {
  25. static OutMgr instance(synth);
  26. return instance;
  27. }
  28. OutMgr::OutMgr(const SYNTH_T *synth_)
  29. :wave(new WavEngine(*synth_)),
  30. priBuf(new float[4096],
  31. new float[4096]), priBuffCurrent(priBuf),
  32. master(NULL), stales(0), synth(*synth_)
  33. {
  34. assert(synth_);
  35. currentOut = NULL;
  36. //init samples
  37. outr = new float[synth.buffersize];
  38. outl = new float[synth.buffersize];
  39. memset(outl, 0, synth.bufferbytes);
  40. memset(outr, 0, synth.bufferbytes);
  41. }
  42. OutMgr::~OutMgr()
  43. {
  44. delete wave;
  45. delete [] priBuf.l;
  46. delete [] priBuf.r;
  47. delete [] outr;
  48. delete [] outl;
  49. }
  50. /* Sequence of a tick
  51. * 1) Lets remove old/stale samples
  52. * 2) Apply appliciable midi events
  53. * 3) Lets see if we need to generate samples
  54. * 4) Lets generate some
  55. * 5) Goto 2 if more are needed
  56. * 6) Lets return those samples to the primary and secondary outputs
  57. * 7) Lets wait for another tick
  58. */
  59. const Stereo<float *> OutMgr::tick(unsigned int frameSize)
  60. {
  61. InMgr &midi = InMgr::getInstance();
  62. //SysEv->execute();
  63. removeStaleSmps();
  64. int i=0;
  65. while(frameSize > storedSmps()) {
  66. if(!midi.empty()) {
  67. midi.flush(i*synth.buffersize, (i+1)*synth.buffersize);
  68. }
  69. master->AudioOut(outl, outr);
  70. addSmps(outl, outr);
  71. i++;
  72. }
  73. stales = frameSize;
  74. return priBuf;
  75. }
  76. AudioOut *OutMgr::getOut(string name)
  77. {
  78. return dynamic_cast<AudioOut *>(EngineMgr::getInstance().getEng(name));
  79. }
  80. string OutMgr::getDriver() const
  81. {
  82. return currentOut->name;
  83. }
  84. bool OutMgr::setSink(string name)
  85. {
  86. AudioOut *sink = getOut(name);
  87. if(!sink)
  88. return false;
  89. if(currentOut)
  90. currentOut->setAudioEn(false);
  91. currentOut = sink;
  92. currentOut->setAudioEn(true);
  93. bool success = currentOut->getAudioEn();
  94. //Keep system in a valid state (aka with a running driver)
  95. if(!success)
  96. (currentOut = getOut("NULL"))->setAudioEn(true);
  97. return success;
  98. }
  99. string OutMgr::getSink() const
  100. {
  101. if(currentOut)
  102. return currentOut->name;
  103. else {
  104. cerr << "BUG: No current output in OutMgr " << __LINE__ << endl;
  105. return "ERROR";
  106. }
  107. return "ERROR";
  108. }
  109. void OutMgr::setMaster(Master *master_)
  110. {
  111. master=master_;
  112. }
  113. void OutMgr::applyOscEventRt(const char *msg)
  114. {
  115. master->applyOscEvent(msg);
  116. }
  117. //perform a cheap linear interpolation for resampling
  118. //This will result in some distortion at frame boundries
  119. //returns number of samples produced
  120. static size_t resample(float *dest,
  121. const float *src,
  122. float s_in,
  123. float s_out,
  124. size_t elms)
  125. {
  126. size_t out_elms = elms * s_out / s_in;
  127. float r_pos = 0.0f;
  128. for(int i = 0; i < (int)out_elms; ++i, r_pos += s_in / s_out)
  129. dest[i] = interpolate(src, elms, r_pos);
  130. return out_elms;
  131. }
  132. void OutMgr::addSmps(float *l, float *r)
  133. {
  134. //allow wave file to syphon off stream
  135. wave->push(Stereo<float *>(l, r), synth.buffersize);
  136. const int s_out = currentOut->getSampleRate(),
  137. s_sys = synth.samplerate;
  138. if(s_out != s_sys) { //we need to resample
  139. const size_t steps = resample(priBuffCurrent.l,
  140. l,
  141. s_sys,
  142. s_out,
  143. synth.buffersize);
  144. resample(priBuffCurrent.r, r, s_sys, s_out, synth.buffersize);
  145. priBuffCurrent.l += steps;
  146. priBuffCurrent.r += steps;
  147. }
  148. else { //just copy the samples
  149. memcpy(priBuffCurrent.l, l, synth.bufferbytes);
  150. memcpy(priBuffCurrent.r, r, synth.bufferbytes);
  151. priBuffCurrent.l += synth.buffersize;
  152. priBuffCurrent.r += synth.buffersize;
  153. }
  154. }
  155. void OutMgr::removeStaleSmps()
  156. {
  157. if(!stales)
  158. return;
  159. const int leftover = storedSmps() - stales;
  160. assert(leftover > -1);
  161. //leftover samples [seen at very low latencies]
  162. if(leftover) {
  163. memmove(priBuf.l, priBuffCurrent.l - leftover, leftover * sizeof(float));
  164. memmove(priBuf.r, priBuffCurrent.r - leftover, leftover * sizeof(float));
  165. priBuffCurrent.l = priBuf.l + leftover;
  166. priBuffCurrent.r = priBuf.r + leftover;
  167. }
  168. else
  169. priBuffCurrent = priBuf;
  170. stales = 0;
  171. }
  172. }