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.

304 lines
7.7KB

  1. #include <assert.h>
  2. #include <mutex>
  3. #include <chrono>
  4. #include <thread>
  5. #include <mutex>
  6. #include <condition_variable>
  7. #include "core.hpp"
  8. #include "audio.hpp"
  9. #include "dsp/samplerate.hpp"
  10. #include "dsp/ringbuffer.hpp"
  11. #pragma GCC diagnostic push
  12. #pragma GCC diagnostic ignored "-Wsuggest-override"
  13. #include <RtAudio.h>
  14. #pragma GCC diagnostic pop
  15. #define MAX_OUTPUTS 8
  16. #define MAX_INPUTS 8
  17. static auto audioTimeout = std::chrono::milliseconds(100);
  18. using namespace rack;
  19. struct AudioInterfaceIO : AudioIO {
  20. std::mutex engineMutex;
  21. std::condition_variable engineCv;
  22. std::mutex audioMutex;
  23. std::condition_variable audioCv;
  24. // Audio thread produces, engine thread consumes
  25. DoubleRingBuffer<Frame<MAX_INPUTS>, (1<<15)> inputBuffer;
  26. // Audio thread consumes, engine thread produces
  27. DoubleRingBuffer<Frame<MAX_OUTPUTS>, (1<<15)> outputBuffer;
  28. AudioInterfaceIO() {
  29. maxOutputs = MAX_OUTPUTS;
  30. maxInputs = MAX_INPUTS;
  31. }
  32. void processStream(const float *input, float *output, int length) override {
  33. if (numInputs > 0) {
  34. // TODO Do we need to wait on the input to be consumed here?
  35. for (int i = 0; i < length; i++) {
  36. if (inputBuffer.full())
  37. break;
  38. Frame<MAX_INPUTS> f;
  39. memset(&f, 0, sizeof(f));
  40. memcpy(&f, &input[numInputs * i], numInputs * sizeof(float));
  41. inputBuffer.push(f);
  42. }
  43. }
  44. if (numOutputs > 0) {
  45. std::unique_lock<std::mutex> lock(audioMutex);
  46. auto cond = [&] {
  47. return outputBuffer.size() >= length;
  48. };
  49. if (audioCv.wait_for(lock, audioTimeout, cond)) {
  50. // Consume audio block
  51. for (int i = 0; i < length; i++) {
  52. Frame<MAX_OUTPUTS> f = outputBuffer.shift();
  53. memcpy(&output[numOutputs * i], &f, numOutputs * sizeof(float));
  54. }
  55. }
  56. else {
  57. // Timed out, fill output with zeros
  58. memset(output, 0, length * numOutputs * sizeof(float));
  59. }
  60. }
  61. // Notify engine when finished processing
  62. engineCv.notify_all();
  63. }
  64. void onCloseStream() override {
  65. inputBuffer.clear();
  66. outputBuffer.clear();
  67. }
  68. };
  69. struct AudioInterface : Module {
  70. enum ParamIds {
  71. NUM_PARAMS
  72. };
  73. enum InputIds {
  74. ENUMS(AUDIO_INPUT, MAX_INPUTS),
  75. NUM_INPUTS
  76. };
  77. enum OutputIds {
  78. ENUMS(AUDIO_OUTPUT, MAX_OUTPUTS),
  79. NUM_OUTPUTS
  80. };
  81. AudioInterfaceIO audioIO;
  82. SampleRateConverter<MAX_INPUTS> inputSrc;
  83. SampleRateConverter<MAX_OUTPUTS> outputSrc;
  84. // in rack's sample rate
  85. DoubleRingBuffer<Frame<MAX_INPUTS>, 16> inputBuffer;
  86. DoubleRingBuffer<Frame<MAX_OUTPUTS>, 16> outputBuffer;
  87. AudioInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {
  88. }
  89. void step() override;
  90. json_t *toJson() override {
  91. json_t *rootJ = json_object();
  92. json_object_set_new(rootJ, "driver", json_integer(audioIO.getDriver()));
  93. std::string deviceName = audioIO.getDeviceName(audioIO.device);
  94. json_object_set_new(rootJ, "deviceName", json_string(deviceName.c_str()));
  95. json_object_set_new(rootJ, "sampleRate", json_integer(audioIO.sampleRate));
  96. json_object_set_new(rootJ, "blockSize", json_integer(audioIO.blockSize));
  97. return rootJ;
  98. }
  99. void fromJson(json_t *rootJ) override {
  100. json_t *driverJ = json_object_get(rootJ, "driver");
  101. if (driverJ)
  102. audioIO.setDriver(json_number_value(driverJ));
  103. json_t *deviceNameJ = json_object_get(rootJ, "deviceName");
  104. if (deviceNameJ) {
  105. std::string deviceName = json_string_value(deviceNameJ);
  106. // Search for device ID with equal name
  107. for (int device = 0; device < audioIO.getDeviceCount(); device++) {
  108. if (audioIO.getDeviceName(device) == deviceName) {
  109. audioIO.device = device;
  110. break;
  111. }
  112. }
  113. }
  114. json_t *sampleRateJ = json_object_get(rootJ, "sampleRate");
  115. if (sampleRateJ)
  116. audioIO.sampleRate = json_integer_value(sampleRateJ);
  117. json_t *blockSizeJ = json_object_get(rootJ, "blockSize");
  118. if (blockSizeJ)
  119. audioIO.blockSize = json_integer_value(blockSizeJ);
  120. audioIO.openStream();
  121. }
  122. void onReset() override {
  123. audioIO.closeStream();
  124. }
  125. };
  126. void AudioInterface::step() {
  127. Frame<MAX_INPUTS> inputFrame;
  128. memset(&inputFrame, 0, sizeof(inputFrame));
  129. if (audioIO.numInputs > 0) {
  130. if (inputBuffer.empty()) {
  131. inputSrc.setRates(audioIO.sampleRate, engineGetSampleRate());
  132. int inLen = audioIO.inputBuffer.size();
  133. int outLen = inputBuffer.capacity();
  134. inputSrc.process(audioIO.inputBuffer.startData(), &inLen, inputBuffer.endData(), &outLen);
  135. audioIO.inputBuffer.startIncr(inLen);
  136. inputBuffer.endIncr(outLen);
  137. }
  138. }
  139. if (!inputBuffer.empty()) {
  140. inputFrame = inputBuffer.shift();
  141. }
  142. for (int i = 0; i < MAX_INPUTS; i++) {
  143. outputs[AUDIO_OUTPUT + i].value = 10.0 * inputFrame.samples[i];
  144. }
  145. if (audioIO.numOutputs > 0) {
  146. // Get and push output SRC frame
  147. if (!outputBuffer.full()) {
  148. Frame<MAX_OUTPUTS> f;
  149. for (int i = 0; i < audioIO.numOutputs; i++) {
  150. f.samples[i] = inputs[AUDIO_INPUT + i].value / 10.0;
  151. }
  152. outputBuffer.push(f);
  153. }
  154. if (outputBuffer.full()) {
  155. // Wait until outputs are needed
  156. std::unique_lock<std::mutex> lock(audioIO.engineMutex);
  157. auto cond = [&] {
  158. return audioIO.outputBuffer.size() < audioIO.blockSize;
  159. };
  160. if (audioIO.engineCv.wait_for(lock, audioTimeout, cond)) {
  161. // Push converted output
  162. outputSrc.setRates(engineGetSampleRate(), audioIO.sampleRate);
  163. int inLen = outputBuffer.size();
  164. int outLen = audioIO.outputBuffer.capacity();
  165. outputSrc.process(outputBuffer.startData(), &inLen, audioIO.outputBuffer.endData(), &outLen);
  166. outputBuffer.startIncr(inLen);
  167. audioIO.outputBuffer.endIncr(outLen);
  168. }
  169. else {
  170. // Give up on pushing output
  171. }
  172. }
  173. }
  174. audioIO.audioCv.notify_all();
  175. }
  176. AudioInterfaceWidget::AudioInterfaceWidget() {
  177. AudioInterface *module = new AudioInterface();
  178. setModule(module);
  179. box.size = Vec(15*12, 380);
  180. {
  181. Panel *panel = new LightPanel();
  182. panel->box.size = box.size;
  183. addChild(panel);
  184. }
  185. // addChild(createScrew<ScrewSilver>(Vec(15, 0)));
  186. // addChild(createScrew<ScrewSilver>(Vec(box.size.x-30, 0)));
  187. // addChild(createScrew<ScrewSilver>(Vec(15, 365)));
  188. // addChild(createScrew<ScrewSilver>(Vec(box.size.x-30, 365)));
  189. Vec margin = Vec(5, 2);
  190. float labelHeight = 15;
  191. float yPos = margin.y + 100;
  192. float xPos;
  193. {
  194. Label *label = new Label();
  195. label->box.pos = Vec(margin.x, yPos);
  196. label->text = "Outputs";
  197. addChild(label);
  198. yPos += labelHeight + margin.y;
  199. }
  200. yPos += 5;
  201. xPos = 10;
  202. for (int i = 0; i < 4; i++) {
  203. addInput(createInput<PJ3410Port>(Vec(xPos, yPos), module, AudioInterface::AUDIO_INPUT + i));
  204. Label *label = new Label();
  205. label->box.pos = Vec(xPos + 4, yPos + 28);
  206. label->text = stringf("%d", i + 1);
  207. addChild(label);
  208. xPos += 37 + margin.x;
  209. }
  210. yPos += 35 + margin.y;
  211. yPos += 5;
  212. xPos = 10;
  213. for (int i = 4; i < 8; i++) {
  214. addInput(createInput<PJ3410Port>(Vec(xPos, yPos), module, AudioInterface::AUDIO_INPUT + i));
  215. Label *label = new Label();
  216. label->box.pos = Vec(xPos + 4, yPos + 28);
  217. label->text = stringf("%d", i + 1);
  218. addChild(label);
  219. xPos += 37 + margin.x;
  220. }
  221. yPos += 35 + margin.y;
  222. {
  223. Label *label = new Label();
  224. label->box.pos = Vec(margin.x, yPos);
  225. label->text = "Inputs";
  226. addChild(label);
  227. yPos += labelHeight + margin.y;
  228. }
  229. yPos += 5;
  230. xPos = 10;
  231. for (int i = 0; i < 4; i++) {
  232. addOutput(createOutput<PJ3410Port>(Vec(xPos, yPos), module, AudioInterface::AUDIO_OUTPUT + i));
  233. Label *label = new Label();
  234. label->box.pos = Vec(xPos + 4, yPos + 28);
  235. label->text = stringf("%d", i + 1);
  236. addChild(label);
  237. xPos += 37 + margin.x;
  238. }
  239. yPos += 35 + margin.y;
  240. yPos += 5;
  241. xPos = 10;
  242. for (int i = 4; i < 8; i++) {
  243. addOutput(createOutput<PJ3410Port>(Vec(xPos, yPos), module, AudioInterface::AUDIO_OUTPUT + i));
  244. Label *label = new Label();
  245. label->box.pos = Vec(xPos + 4, yPos + 28);
  246. label->text = stringf("%d", i + 1);
  247. addChild(label);
  248. xPos += 37 + margin.x;
  249. }
  250. yPos += 35 + margin.y;
  251. AudioWidget *audioWidget = construct<USB_B_AudioWidget>();
  252. audioWidget->audioIO = &module->audioIO;
  253. addChild(audioWidget);
  254. }