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.

186 lines
4.6KB

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