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.

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