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.

361 lines
17KB

  1. #include "plugin.hpp"
  2. #include <audio.hpp>
  3. #include <app.hpp>
  4. #include <mutex>
  5. #include <chrono>
  6. #include <thread>
  7. #include <mutex>
  8. #include <condition_variable>
  9. namespace rack {
  10. namespace core {
  11. template <int AUDIO_OUTPUTS, int AUDIO_INPUTS>
  12. struct AudioInterfacePort : audio::Port {
  13. std::mutex engineMutex;
  14. std::condition_variable engineCv;
  15. std::mutex audioMutex;
  16. std::condition_variable audioCv;
  17. // Audio thread produces, engine thread consumes
  18. dsp::DoubleRingBuffer < dsp::Frame<AUDIO_INPUTS>, (1 << 15) > inputBuffer;
  19. // Audio thread consumes, engine thread produces
  20. dsp::DoubleRingBuffer < dsp::Frame<AUDIO_OUTPUTS>, (1 << 15) > outputBuffer;
  21. bool active = false;
  22. ~AudioInterfacePort() {
  23. // Close stream here before destructing AudioInterfacePort, so the mutexes are still valid when waiting to close.
  24. setDeviceId(-1, 0);
  25. }
  26. void processStream(const float* input, float* output, int frames) override {
  27. // Reactivate idle stream
  28. if (!active) {
  29. active = true;
  30. inputBuffer.clear();
  31. outputBuffer.clear();
  32. }
  33. if (numInputs > 0) {
  34. // TODO Do we need to wait on the input to be consumed here? Experimentally, it works fine if we don't.
  35. for (int i = 0; i < frames; i++) {
  36. if (inputBuffer.full())
  37. break;
  38. dsp::Frame<AUDIO_INPUTS> inputFrame;
  39. std::memset(&inputFrame, 0, sizeof(inputFrame));
  40. std::memcpy(&inputFrame, &input[numInputs * i], numInputs * sizeof(float));
  41. inputBuffer.push(inputFrame);
  42. }
  43. }
  44. if (numOutputs > 0) {
  45. std::unique_lock<std::mutex> lock(audioMutex);
  46. auto cond = [&] {
  47. return (outputBuffer.size() >= (size_t) frames);
  48. };
  49. auto timeout = std::chrono::milliseconds(100);
  50. if (audioCv.wait_for(lock, timeout, cond)) {
  51. // Consume audio block
  52. for (int i = 0; i < frames; i++) {
  53. dsp::Frame<AUDIO_OUTPUTS> f = outputBuffer.shift();
  54. for (int j = 0; j < numOutputs; j++) {
  55. output[numOutputs * i + j] = clamp(f.samples[j], -1.f, 1.f);
  56. }
  57. }
  58. }
  59. else {
  60. // Timed out, fill output with zeros
  61. std::memset(output, 0, frames * numOutputs * sizeof(float));
  62. // DEBUG("Audio Interface Port underflow");
  63. }
  64. }
  65. // Notify engine when finished processing
  66. engineCv.notify_one();
  67. }
  68. void onCloseStream() override {
  69. inputBuffer.clear();
  70. outputBuffer.clear();
  71. }
  72. void onChannelsChange() override {
  73. }
  74. };
  75. template <int AUDIO_OUTPUTS, int AUDIO_INPUTS>
  76. struct AudioInterface : Module {
  77. enum ParamIds {
  78. NUM_PARAMS
  79. };
  80. enum InputIds {
  81. ENUMS(AUDIO_INPUT, AUDIO_INPUTS),
  82. NUM_INPUTS
  83. };
  84. enum OutputIds {
  85. ENUMS(AUDIO_OUTPUT, AUDIO_OUTPUTS),
  86. NUM_OUTPUTS
  87. };
  88. enum LightIds {
  89. ENUMS(INPUT_LIGHT, AUDIO_INPUTS / 2),
  90. ENUMS(OUTPUT_LIGHT, AUDIO_OUTPUTS / 2),
  91. NUM_LIGHTS
  92. };
  93. AudioInterfacePort<AUDIO_OUTPUTS, AUDIO_INPUTS> port;
  94. int lastSampleRate = 0;
  95. int lastNumOutputs = -1;
  96. int lastNumInputs = -1;
  97. dsp::SampleRateConverter<AUDIO_INPUTS> inputSrc;
  98. dsp::SampleRateConverter<AUDIO_OUTPUTS> outputSrc;
  99. // in rack's sample rate
  100. dsp::DoubleRingBuffer<dsp::Frame<AUDIO_INPUTS>, 16> inputBuffer;
  101. dsp::DoubleRingBuffer<dsp::Frame<AUDIO_OUTPUTS>, 16> outputBuffer;
  102. AudioInterface() {
  103. config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
  104. port.maxChannels = std::max(AUDIO_OUTPUTS, AUDIO_INPUTS);
  105. onSampleRateChange();
  106. }
  107. void process(const ProcessArgs& args) override {
  108. // Update SRC states
  109. inputSrc.setRates(port.sampleRate, args.sampleRate);
  110. outputSrc.setRates(args.sampleRate, port.sampleRate);
  111. inputSrc.setChannels(port.numInputs);
  112. outputSrc.setChannels(port.numOutputs);
  113. // Inputs: audio engine -> rack engine
  114. if (port.active && port.numInputs > 0) {
  115. // Wait until inputs are present
  116. // Give up after a timeout in case the audio device is being unresponsive.
  117. std::unique_lock<std::mutex> lock(port.engineMutex);
  118. auto cond = [&] {
  119. return (!port.inputBuffer.empty());
  120. };
  121. auto timeout = std::chrono::milliseconds(200);
  122. if (port.engineCv.wait_for(lock, timeout, cond)) {
  123. // Convert inputs
  124. int inLen = port.inputBuffer.size();
  125. int outLen = inputBuffer.capacity();
  126. inputSrc.process(port.inputBuffer.startData(), &inLen, inputBuffer.endData(), &outLen);
  127. port.inputBuffer.startIncr(inLen);
  128. inputBuffer.endIncr(outLen);
  129. }
  130. else {
  131. // Give up on pulling input
  132. port.active = false;
  133. // DEBUG("Audio Interface underflow");
  134. }
  135. }
  136. // Take input from buffer
  137. dsp::Frame<AUDIO_INPUTS> inputFrame;
  138. if (!inputBuffer.empty()) {
  139. inputFrame = inputBuffer.shift();
  140. }
  141. else {
  142. std::memset(&inputFrame, 0, sizeof(inputFrame));
  143. }
  144. for (int i = 0; i < port.numInputs; i++) {
  145. outputs[AUDIO_OUTPUT + i].setVoltage(10.f * inputFrame.samples[i]);
  146. }
  147. for (int i = port.numInputs; i < AUDIO_INPUTS; i++) {
  148. outputs[AUDIO_OUTPUT + i].setVoltage(0.f);
  149. }
  150. // Outputs: rack engine -> audio engine
  151. if (port.active && port.numOutputs > 0) {
  152. // Get and push output SRC frame
  153. if (!outputBuffer.full()) {
  154. dsp::Frame<AUDIO_OUTPUTS> outputFrame;
  155. for (int i = 0; i < AUDIO_OUTPUTS; i++) {
  156. outputFrame.samples[i] = inputs[AUDIO_INPUT + i].getVoltageSum() / 10.f;
  157. }
  158. outputBuffer.push(outputFrame);
  159. }
  160. if (outputBuffer.full()) {
  161. // Wait until enough outputs are consumed
  162. // Give up after a timeout in case the audio device is being unresponsive.
  163. auto cond = [&] {
  164. return (port.outputBuffer.size() < (size_t) port.blockSize);
  165. };
  166. if (!cond())
  167. APP->engine->yieldWorkers();
  168. std::unique_lock<std::mutex> lock(port.engineMutex);
  169. auto timeout = std::chrono::milliseconds(200);
  170. if (port.engineCv.wait_for(lock, timeout, cond)) {
  171. // Push converted output
  172. int inLen = outputBuffer.size();
  173. int outLen = port.outputBuffer.capacity();
  174. outputSrc.process(outputBuffer.startData(), &inLen, port.outputBuffer.endData(), &outLen);
  175. outputBuffer.startIncr(inLen);
  176. port.outputBuffer.endIncr(outLen);
  177. }
  178. else {
  179. // Give up on pushing output
  180. port.active = false;
  181. outputBuffer.clear();
  182. // DEBUG("Audio Interface underflow");
  183. }
  184. }
  185. // Notify audio thread that an output is potentially ready
  186. port.audioCv.notify_one();
  187. }
  188. // Turn on light if at least one port is enabled in the nearby pair
  189. for (int i = 0; i < AUDIO_INPUTS / 2; i++)
  190. lights[INPUT_LIGHT + i].setBrightness(port.active && port.numOutputs >= 2 * i + 1);
  191. for (int i = 0; i < AUDIO_OUTPUTS / 2; i++)
  192. lights[OUTPUT_LIGHT + i].setBrightness(port.active && port.numInputs >= 2 * i + 1);
  193. }
  194. json_t* dataToJson() override {
  195. json_t* rootJ = json_object();
  196. json_object_set_new(rootJ, "audio", port.toJson());
  197. return rootJ;
  198. }
  199. void dataFromJson(json_t* rootJ) override {
  200. json_t* audioJ = json_object_get(rootJ, "audio");
  201. port.fromJson(audioJ);
  202. }
  203. void onReset() override {
  204. port.setDeviceId(-1, 0);
  205. }
  206. };
  207. struct AudioInterface8Widget : ModuleWidget {
  208. typedef AudioInterface<8, 8> TAudioInterface;
  209. AudioInterface8Widget(TAudioInterface* module) {
  210. setModule(module);
  211. setPanel(APP->window->loadSvg(asset::system("res/Core/AudioInterface.svg")));
  212. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
  213. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  214. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  215. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  216. addInput(createInput<PJ301MPort>(mm2px(Vec(3.7069211, 55.530807)), module, TAudioInterface::AUDIO_INPUT + 0));
  217. addInput(createInput<PJ301MPort>(mm2px(Vec(15.307249, 55.530807)), module, TAudioInterface::AUDIO_INPUT + 1));
  218. addInput(createInput<PJ301MPort>(mm2px(Vec(26.906193, 55.530807)), module, TAudioInterface::AUDIO_INPUT + 2));
  219. addInput(createInput<PJ301MPort>(mm2px(Vec(38.506519, 55.530807)), module, TAudioInterface::AUDIO_INPUT + 3));
  220. addInput(createInput<PJ301MPort>(mm2px(Vec(3.7069209, 70.144905)), module, TAudioInterface::AUDIO_INPUT + 4));
  221. addInput(createInput<PJ301MPort>(mm2px(Vec(15.307249, 70.144905)), module, TAudioInterface::AUDIO_INPUT + 5));
  222. addInput(createInput<PJ301MPort>(mm2px(Vec(26.906193, 70.144905)), module, TAudioInterface::AUDIO_INPUT + 6));
  223. addInput(createInput<PJ301MPort>(mm2px(Vec(38.506519, 70.144905)), module, TAudioInterface::AUDIO_INPUT + 7));
  224. addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.7069209, 92.143906)), module, TAudioInterface::AUDIO_OUTPUT + 0));
  225. addOutput(createOutput<PJ301MPort>(mm2px(Vec(15.307249, 92.143906)), module, TAudioInterface::AUDIO_OUTPUT + 1));
  226. addOutput(createOutput<PJ301MPort>(mm2px(Vec(26.906193, 92.143906)), module, TAudioInterface::AUDIO_OUTPUT + 2));
  227. addOutput(createOutput<PJ301MPort>(mm2px(Vec(38.506519, 92.143906)), module, TAudioInterface::AUDIO_OUTPUT + 3));
  228. addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.7069209, 108.1443)), module, TAudioInterface::AUDIO_OUTPUT + 4));
  229. addOutput(createOutput<PJ301MPort>(mm2px(Vec(15.307249, 108.1443)), module, TAudioInterface::AUDIO_OUTPUT + 5));
  230. addOutput(createOutput<PJ301MPort>(mm2px(Vec(26.906193, 108.1443)), module, TAudioInterface::AUDIO_OUTPUT + 6));
  231. addOutput(createOutput<PJ301MPort>(mm2px(Vec(38.506523, 108.1443)), module, TAudioInterface::AUDIO_OUTPUT + 7));
  232. addChild(createLight<SmallLight<GreenLight>>(mm2px(Vec(12.524985, 54.577202)), module, TAudioInterface::INPUT_LIGHT + 0));
  233. addChild(createLight<SmallLight<GreenLight>>(mm2px(Vec(35.725647, 54.577202)), module, TAudioInterface::INPUT_LIGHT + 1));
  234. addChild(createLight<SmallLight<GreenLight>>(mm2px(Vec(12.524985, 69.158226)), module, TAudioInterface::INPUT_LIGHT + 2));
  235. addChild(createLight<SmallLight<GreenLight>>(mm2px(Vec(35.725647, 69.158226)), module, TAudioInterface::INPUT_LIGHT + 3));
  236. addChild(createLight<SmallLight<GreenLight>>(mm2px(Vec(12.524985, 91.147583)), module, TAudioInterface::OUTPUT_LIGHT + 0));
  237. addChild(createLight<SmallLight<GreenLight>>(mm2px(Vec(35.725647, 91.147583)), module, TAudioInterface::OUTPUT_LIGHT + 1));
  238. addChild(createLight<SmallLight<GreenLight>>(mm2px(Vec(12.524985, 107.17003)), module, TAudioInterface::OUTPUT_LIGHT + 2));
  239. addChild(createLight<SmallLight<GreenLight>>(mm2px(Vec(35.725647, 107.17003)), module, TAudioInterface::OUTPUT_LIGHT + 3));
  240. AudioWidget* audioWidget = createWidget<AudioWidget>(mm2px(Vec(3.2122073, 14.837339)));
  241. audioWidget->box.size = mm2px(Vec(44, 28));
  242. audioWidget->setAudioPort(module ? &module->port : NULL);
  243. addChild(audioWidget);
  244. }
  245. };
  246. struct AudioInterface16Widget : ModuleWidget {
  247. typedef AudioInterface<16, 16> TAudioInterface;
  248. AudioInterface16Widget(TAudioInterface* module) {
  249. setModule(module);
  250. setPanel(APP->window->loadSvg(asset::system("res/Core/AudioInterface16.svg")));
  251. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
  252. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  253. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  254. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  255. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.661, 59.638)), module, TAudioInterface::AUDIO_INPUT + 0));
  256. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(19.26, 59.638)), module, TAudioInterface::AUDIO_INPUT + 1));
  257. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(30.86, 59.638)), module, TAudioInterface::AUDIO_INPUT + 2));
  258. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(42.461, 59.638)), module, TAudioInterface::AUDIO_INPUT + 3));
  259. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(54.06, 59.638)), module, TAudioInterface::AUDIO_INPUT + 4));
  260. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(65.661, 59.638)), module, TAudioInterface::AUDIO_INPUT + 5));
  261. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(77.26, 59.638)), module, TAudioInterface::AUDIO_INPUT + 6));
  262. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(88.86, 59.638)), module, TAudioInterface::AUDIO_INPUT + 7));
  263. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.661, 74.251)), module, TAudioInterface::AUDIO_INPUT + 8));
  264. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(19.26, 74.251)), module, TAudioInterface::AUDIO_INPUT + 9));
  265. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(30.86, 74.251)), module, TAudioInterface::AUDIO_INPUT + 10));
  266. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(42.461, 74.251)), module, TAudioInterface::AUDIO_INPUT + 11));
  267. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(54.06, 74.251)), module, TAudioInterface::AUDIO_INPUT + 12));
  268. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(65.661, 74.251)), module, TAudioInterface::AUDIO_INPUT + 13));
  269. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(77.26, 74.251)), module, TAudioInterface::AUDIO_INPUT + 14));
  270. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(88.86, 74.251)), module, TAudioInterface::AUDIO_INPUT + 15));
  271. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.661, 96.251)), module, TAudioInterface::AUDIO_OUTPUT + 0));
  272. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(19.26, 96.251)), module, TAudioInterface::AUDIO_OUTPUT + 1));
  273. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(30.86, 96.251)), module, TAudioInterface::AUDIO_OUTPUT + 2));
  274. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(42.461, 96.251)), module, TAudioInterface::AUDIO_OUTPUT + 3));
  275. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(54.06, 96.251)), module, TAudioInterface::AUDIO_OUTPUT + 4));
  276. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(65.661, 96.251)), module, TAudioInterface::AUDIO_OUTPUT + 5));
  277. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(77.26, 96.251)), module, TAudioInterface::AUDIO_OUTPUT + 6));
  278. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(88.86, 96.251)), module, TAudioInterface::AUDIO_OUTPUT + 7));
  279. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.661, 112.252)), module, TAudioInterface::AUDIO_OUTPUT + 8));
  280. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(19.26, 112.252)), module, TAudioInterface::AUDIO_OUTPUT + 9));
  281. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(30.86, 112.252)), module, TAudioInterface::AUDIO_OUTPUT + 10));
  282. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(42.461, 112.252)), module, TAudioInterface::AUDIO_OUTPUT + 11));
  283. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(54.06, 112.252)), module, TAudioInterface::AUDIO_OUTPUT + 12));
  284. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(65.661, 112.252)), module, TAudioInterface::AUDIO_OUTPUT + 13));
  285. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(77.26, 112.252)), module, TAudioInterface::AUDIO_OUTPUT + 14));
  286. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(88.86, 112.252)), module, TAudioInterface::AUDIO_OUTPUT + 15));
  287. addChild(createLightCentered<SmallLight<GreenLight>>(mm2px(Vec(13.46, 55.667)), module, TAudioInterface::INPUT_LIGHT + 0));
  288. addChild(createLightCentered<SmallLight<GreenLight>>(mm2px(Vec(36.661, 55.667)), module, TAudioInterface::INPUT_LIGHT + 1));
  289. addChild(createLightCentered<SmallLight<GreenLight>>(mm2px(Vec(59.861, 55.667)), module, TAudioInterface::INPUT_LIGHT + 2));
  290. addChild(createLightCentered<SmallLight<GreenLight>>(mm2px(Vec(83.061, 55.667)), module, TAudioInterface::INPUT_LIGHT + 3));
  291. addChild(createLightCentered<SmallLight<GreenLight>>(mm2px(Vec(13.46, 70.248)), module, TAudioInterface::INPUT_LIGHT + 4));
  292. addChild(createLightCentered<SmallLight<GreenLight>>(mm2px(Vec(36.661, 70.248)), module, TAudioInterface::INPUT_LIGHT + 5));
  293. addChild(createLightCentered<SmallLight<GreenLight>>(mm2px(Vec(59.861, 70.248)), module, TAudioInterface::INPUT_LIGHT + 6));
  294. addChild(createLightCentered<SmallLight<GreenLight>>(mm2px(Vec(83.061, 70.248)), module, TAudioInterface::INPUT_LIGHT + 7));
  295. addChild(createLightCentered<SmallLight<GreenLight>>(mm2px(Vec(13.46, 92.238)), module, TAudioInterface::OUTPUT_LIGHT + 0));
  296. addChild(createLightCentered<SmallLight<GreenLight>>(mm2px(Vec(36.661, 92.238)), module, TAudioInterface::OUTPUT_LIGHT + 1));
  297. addChild(createLightCentered<SmallLight<GreenLight>>(mm2px(Vec(59.861, 92.238)), module, TAudioInterface::OUTPUT_LIGHT + 2));
  298. addChild(createLightCentered<SmallLight<GreenLight>>(mm2px(Vec(83.061, 92.238)), module, TAudioInterface::OUTPUT_LIGHT + 3));
  299. addChild(createLightCentered<SmallLight<GreenLight>>(mm2px(Vec(13.46, 108.259)), module, TAudioInterface::OUTPUT_LIGHT + 4));
  300. addChild(createLightCentered<SmallLight<GreenLight>>(mm2px(Vec(36.661, 108.259)), module, TAudioInterface::OUTPUT_LIGHT + 5));
  301. addChild(createLightCentered<SmallLight<GreenLight>>(mm2px(Vec(59.861, 108.259)), module, TAudioInterface::OUTPUT_LIGHT + 6));
  302. addChild(createLightCentered<SmallLight<GreenLight>>(mm2px(Vec(83.061, 108.259)), module, TAudioInterface::OUTPUT_LIGHT + 7));
  303. AudioWidget* audioWidget = createWidget<AudioWidget>(mm2px(Vec(2.57, 14.839)));
  304. audioWidget->box.size = mm2px(Vec(91.382, 28.0));
  305. audioWidget->setAudioPort(module ? &module->port : NULL);
  306. addChild(audioWidget);
  307. }
  308. };
  309. Model* modelAudioInterface = createModel<AudioInterface<8, 8>, AudioInterface8Widget>("AudioInterface");
  310. Model* modelAudioInterface16 = createModel<AudioInterface<16, 16>, AudioInterface16Widget>("AudioInterface16");
  311. } // namespace core
  312. } // namespace rack