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.

560 lines
15KB

  1. #include <assert.h>
  2. #include <mutex>
  3. #include <thread>
  4. #include <portaudio.h>
  5. #include "core.hpp"
  6. #include "dsp/samplerate.hpp"
  7. #include "dsp/ringbuffer.hpp"
  8. using namespace rack;
  9. static bool initialized = false;
  10. void audioInit() {
  11. if (initialized)
  12. return;
  13. PaError err = Pa_Initialize();
  14. if (err) {
  15. warn("Failed to initialize PortAudio: %s", Pa_GetErrorText(err));
  16. return;
  17. }
  18. initialized = true;
  19. }
  20. struct AudioInterface : Module {
  21. enum ParamIds {
  22. NUM_PARAMS
  23. };
  24. enum InputIds {
  25. AUDIO1_INPUT,
  26. NUM_INPUTS = AUDIO1_INPUT + 8
  27. };
  28. enum OutputIds {
  29. AUDIO1_OUTPUT,
  30. NUM_OUTPUTS = AUDIO1_OUTPUT + 8
  31. };
  32. PaStream *stream = NULL;
  33. // Stream properties
  34. int deviceId = -1;
  35. float sampleRate = 44100.0;
  36. int blockSize = 256;
  37. int numOutputs = 0;
  38. int numInputs = 0;
  39. // Used because the GUI thread and Rack thread can both interact with this class
  40. std::mutex bufferMutex;
  41. bool streamRunning;
  42. SampleRateConverter<8> inputSrc;
  43. SampleRateConverter<8> outputSrc;
  44. // in rack's sample rate
  45. DoubleRingBuffer<Frame<8>, 16> inputBuffer;
  46. DoubleRingBuffer<Frame<8>, (1<<15)> outputBuffer;
  47. // in device's sample rate
  48. DoubleRingBuffer<Frame<8>, (1<<15)> inputSrcBuffer;
  49. AudioInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {
  50. audioInit();
  51. }
  52. ~AudioInterface() {
  53. closeDevice();
  54. }
  55. void step() override;
  56. void stepStream(const float *input, float *output, int numFrames);
  57. int getDeviceCount();
  58. std::string getDeviceName(int deviceId);
  59. void openDevice(int deviceId, float sampleRate, int blockSize);
  60. void closeDevice();
  61. void setDeviceId(int deviceId) {
  62. openDevice(deviceId, sampleRate, blockSize);
  63. }
  64. void setSampleRate(float sampleRate) {
  65. openDevice(deviceId, sampleRate, blockSize);
  66. }
  67. void setBlockSize(int blockSize) {
  68. openDevice(deviceId, sampleRate, blockSize);
  69. }
  70. json_t *toJson() override {
  71. json_t *rootJ = json_object();
  72. if (deviceId >= 0) {
  73. std::string deviceName = getDeviceName(deviceId);
  74. json_object_set_new(rootJ, "deviceName", json_string(deviceName.c_str()));
  75. json_object_set_new(rootJ, "sampleRate", json_real(sampleRate));
  76. json_object_set_new(rootJ, "blockSize", json_integer(blockSize));
  77. }
  78. return rootJ;
  79. }
  80. void fromJson(json_t *rootJ) override {
  81. json_t *deviceNameJ = json_object_get(rootJ, "deviceName");
  82. if (deviceNameJ) {
  83. std::string deviceName = json_string_value(deviceNameJ);
  84. for (int i = 0; i < getDeviceCount(); i++) {
  85. if (deviceName == getDeviceName(i)) {
  86. setDeviceId(i);
  87. break;
  88. }
  89. }
  90. }
  91. json_t *sampleRateJ = json_object_get(rootJ, "sampleRate");
  92. if (sampleRateJ) {
  93. setSampleRate(json_number_value(sampleRateJ));
  94. }
  95. json_t *blockSizeJ = json_object_get(rootJ, "blockSize");
  96. if (blockSizeJ) {
  97. setBlockSize(json_integer_value(blockSizeJ));
  98. }
  99. }
  100. void reset() override {
  101. closeDevice();
  102. }
  103. };
  104. void AudioInterface::step() {
  105. if (!stream)
  106. return;
  107. // Read/write stream if we have enough input, OR the output buffer is empty if we have no input
  108. if (numOutputs > 0) {
  109. while (inputSrcBuffer.size() >= blockSize && streamRunning) {
  110. std::this_thread::sleep_for(std::chrono::duration<float>(100e-6));
  111. }
  112. }
  113. else if (numInputs > 0) {
  114. while (outputBuffer.empty() && streamRunning) {
  115. std::this_thread::sleep_for(std::chrono::duration<float>(100e-6));
  116. }
  117. }
  118. std::lock_guard<std::mutex> lock(bufferMutex);
  119. // Get input and pass it through the sample rate converter
  120. if (numOutputs > 0) {
  121. if (!inputBuffer.full()) {
  122. Frame<8> f;
  123. for (int i = 0; i < 8; i++) {
  124. f.samples[i] = inputs[AUDIO1_INPUT + i].value / 10.0;
  125. }
  126. inputBuffer.push(f);
  127. }
  128. // Once full, sample rate convert the input
  129. // inputBuffer -> SRC -> inputSrcBuffer
  130. if (inputBuffer.full()) {
  131. inputSrc.setRatio(sampleRate / engineGetSampleRate());
  132. int inLen = inputBuffer.size();
  133. int outLen = inputSrcBuffer.capacity();
  134. inputSrc.process(inputBuffer.startData(), &inLen, inputSrcBuffer.endData(), &outLen);
  135. inputBuffer.startIncr(inLen);
  136. inputSrcBuffer.endIncr(outLen);
  137. }
  138. }
  139. // Set output
  140. if (!outputBuffer.empty()) {
  141. Frame<8> f = outputBuffer.shift();
  142. for (int i = 0; i < 8; i++) {
  143. outputs[AUDIO1_OUTPUT + i].value = 10.0 * f.samples[i];
  144. }
  145. }
  146. }
  147. void AudioInterface::stepStream(const float *input, float *output, int numFrames) {
  148. if (numOutputs > 0) {
  149. // Wait for enough input before proceeding
  150. while (inputSrcBuffer.size() < numFrames) {
  151. if (!streamRunning)
  152. return;
  153. std::this_thread::sleep_for(std::chrono::duration<float>(100e-6));
  154. }
  155. }
  156. std::lock_guard<std::mutex> lock(bufferMutex);
  157. // input stream -> output buffer
  158. if (numInputs > 0) {
  159. Frame<8> inputFrames[numFrames];
  160. for (int i = 0; i < numFrames; i++) {
  161. for (int c = 0; c < 8; c++) {
  162. inputFrames[i].samples[c] = (c < numInputs) ? input[i*numInputs + c] : 0.0;
  163. }
  164. }
  165. // Pass output through sample rate converter
  166. outputSrc.setRatio(engineGetSampleRate() / sampleRate);
  167. int inLen = numFrames;
  168. int outLen = outputBuffer.capacity();
  169. outputSrc.process(inputFrames, &inLen, outputBuffer.endData(), &outLen);
  170. outputBuffer.endIncr(outLen);
  171. }
  172. // input buffer -> output stream
  173. if (numOutputs > 0) {
  174. for (int i = 0; i < numFrames; i++) {
  175. if (inputSrcBuffer.empty())
  176. break;
  177. Frame<8> f = inputSrcBuffer.shift();
  178. for (int c = 0; c < numOutputs; c++) {
  179. output[i*numOutputs + c] = (c < 8) ? clampf(f.samples[c], -1.0, 1.0) : 0.0;
  180. }
  181. }
  182. }
  183. }
  184. int AudioInterface::getDeviceCount() {
  185. return Pa_GetDeviceCount();
  186. }
  187. std::string AudioInterface::getDeviceName(int deviceId) {
  188. const PaDeviceInfo *info = Pa_GetDeviceInfo(deviceId);
  189. if (!info)
  190. return "";
  191. const PaHostApiInfo *apiInfo = Pa_GetHostApiInfo(info->hostApi);
  192. return stringf("%s: %s (%d in, %d out)", apiInfo->name, info->name, info->maxInputChannels, info->maxOutputChannels);
  193. }
  194. static int paCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData) {
  195. AudioInterface *p = (AudioInterface *) userData;
  196. p->stepStream((const float *) inputBuffer, (float *) outputBuffer, framesPerBuffer);
  197. return paContinue;
  198. }
  199. void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) {
  200. closeDevice();
  201. std::lock_guard<std::mutex> lock(bufferMutex);
  202. this->sampleRate = sampleRate;
  203. this->blockSize = blockSize;
  204. // Open new device
  205. if (deviceId >= 0) {
  206. PaError err;
  207. const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(deviceId);
  208. if (!deviceInfo) {
  209. warn("Failed to query audio device");
  210. return;
  211. }
  212. numOutputs = mini(deviceInfo->maxOutputChannels, 8);
  213. numInputs = mini(deviceInfo->maxInputChannels, 8);
  214. PaStreamParameters outputParameters;
  215. outputParameters.device = deviceId;
  216. outputParameters.channelCount = numOutputs;
  217. outputParameters.sampleFormat = paFloat32;
  218. outputParameters.suggestedLatency = deviceInfo->defaultLowOutputLatency;
  219. outputParameters.hostApiSpecificStreamInfo = NULL;
  220. PaStreamParameters inputParameters;
  221. inputParameters.device = deviceId;
  222. inputParameters.channelCount = numInputs;
  223. inputParameters.sampleFormat = paFloat32;
  224. inputParameters.suggestedLatency = deviceInfo->defaultLowInputLatency;
  225. inputParameters.hostApiSpecificStreamInfo = NULL;
  226. // Don't use stream parameters if 0 input or output channels
  227. err = Pa_OpenStream(&stream,
  228. numInputs == 0 ? NULL : &inputParameters,
  229. numOutputs == 0 ? NULL : &outputParameters,
  230. sampleRate, blockSize, paNoFlag, paCallback, this);
  231. if (err) {
  232. warn("Failed to open audio stream: %s", Pa_GetErrorText(err));
  233. return;
  234. }
  235. err = Pa_StartStream(stream);
  236. if (err) {
  237. warn("Failed to start audio stream: %s", Pa_GetErrorText(err));
  238. return;
  239. }
  240. // This should go after Pa_StartStream because sometimes it will call the callback once synchronously, and that time it should return early
  241. streamRunning = true;
  242. // Correct sample rate
  243. const PaStreamInfo *streamInfo = Pa_GetStreamInfo(stream);
  244. this->sampleRate = streamInfo->sampleRate;
  245. this->deviceId = deviceId;
  246. }
  247. }
  248. void AudioInterface::closeDevice() {
  249. std::lock_guard<std::mutex> lock(bufferMutex);
  250. if (stream) {
  251. PaError err;
  252. streamRunning = false;
  253. err = Pa_AbortStream(stream);
  254. // err = Pa_StopStream(stream);
  255. if (err) {
  256. warn("Failed to stop audio stream: %s", Pa_GetErrorText(err));
  257. }
  258. err = Pa_CloseStream(stream);
  259. if (err) {
  260. warn("Failed to close audio stream: %s", Pa_GetErrorText(err));
  261. }
  262. }
  263. // Reset stream settings
  264. stream = NULL;
  265. deviceId = -1;
  266. numOutputs = 0;
  267. numInputs = 0;
  268. // Clear buffers
  269. inputBuffer.clear();
  270. outputBuffer.clear();
  271. inputSrcBuffer.clear();
  272. inputSrc.reset();
  273. outputSrc.reset();
  274. }
  275. struct AudioItem : MenuItem {
  276. AudioInterface *audioInterface;
  277. int deviceId;
  278. void onAction(EventAction &e) override {
  279. audioInterface->setDeviceId(deviceId);
  280. }
  281. };
  282. struct AudioChoice : ChoiceButton {
  283. AudioInterface *audioInterface;
  284. void onAction(EventAction &e) override {
  285. Menu *menu = gScene->createMenu();
  286. menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round();
  287. menu->box.size.x = box.size.x;
  288. int deviceCount = audioInterface->getDeviceCount();
  289. {
  290. AudioItem *audioItem = new AudioItem();
  291. audioItem->audioInterface = audioInterface;
  292. audioItem->deviceId = -1;
  293. audioItem->text = "No device";
  294. menu->pushChild(audioItem);
  295. }
  296. for (int deviceId = 0; deviceId < deviceCount; deviceId++) {
  297. AudioItem *audioItem = new AudioItem();
  298. audioItem->audioInterface = audioInterface;
  299. audioItem->deviceId = deviceId;
  300. audioItem->text = audioInterface->getDeviceName(deviceId);
  301. menu->pushChild(audioItem);
  302. }
  303. }
  304. void step() override {
  305. std::string name = audioInterface->getDeviceName(audioInterface->deviceId);
  306. text = ellipsize(name, 24);
  307. }
  308. };
  309. struct SampleRateItem : MenuItem {
  310. AudioInterface *audioInterface;
  311. float sampleRate;
  312. void onAction(EventAction &e) override {
  313. audioInterface->setSampleRate(sampleRate);
  314. }
  315. };
  316. struct SampleRateChoice : ChoiceButton {
  317. AudioInterface *audioInterface;
  318. void onAction(EventAction &e) override {
  319. Menu *menu = gScene->createMenu();
  320. menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round();
  321. menu->box.size.x = box.size.x;
  322. const float sampleRates[6] = {44100, 48000, 88200, 96000, 176400, 192000};
  323. int sampleRatesLen = sizeof(sampleRates) / sizeof(sampleRates[0]);
  324. for (int i = 0; i < sampleRatesLen; i++) {
  325. SampleRateItem *item = new SampleRateItem();
  326. item->audioInterface = audioInterface;
  327. item->sampleRate = sampleRates[i];
  328. item->text = stringf("%.0f Hz", sampleRates[i]);
  329. menu->pushChild(item);
  330. }
  331. }
  332. void step() override {
  333. this->text = stringf("%.0f Hz", audioInterface->sampleRate);
  334. }
  335. };
  336. struct BlockSizeItem : MenuItem {
  337. AudioInterface *audioInterface;
  338. int blockSize;
  339. void onAction(EventAction &e) override {
  340. audioInterface->setBlockSize(blockSize);
  341. }
  342. };
  343. struct BlockSizeChoice : ChoiceButton {
  344. AudioInterface *audioInterface;
  345. void onAction(EventAction &e) override {
  346. Menu *menu = gScene->createMenu();
  347. menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round();
  348. menu->box.size.x = box.size.x;
  349. const int blockSizes[] = {64, 128, 256, 512, 1024, 2048, 4096};
  350. int blockSizesLen = sizeof(blockSizes) / sizeof(blockSizes[0]);
  351. for (int i = 0; i < blockSizesLen; i++) {
  352. BlockSizeItem *item = new BlockSizeItem();
  353. item->audioInterface = audioInterface;
  354. item->blockSize = blockSizes[i];
  355. item->text = stringf("%d", blockSizes[i]);
  356. menu->pushChild(item);
  357. }
  358. }
  359. void step() override {
  360. this->text = stringf("%d", audioInterface->blockSize);
  361. }
  362. };
  363. AudioInterfaceWidget::AudioInterfaceWidget() {
  364. AudioInterface *module = new AudioInterface();
  365. setModule(module);
  366. box.size = Vec(15*12, 380);
  367. {
  368. Panel *panel = new LightPanel();
  369. panel->box.size = box.size;
  370. addChild(panel);
  371. }
  372. // addChild(createScrew<ScrewSilver>(Vec(15, 0)));
  373. // addChild(createScrew<ScrewSilver>(Vec(box.size.x-30, 0)));
  374. // addChild(createScrew<ScrewSilver>(Vec(15, 365)));
  375. // addChild(createScrew<ScrewSilver>(Vec(box.size.x-30, 365)));
  376. float margin = 5;
  377. float labelHeight = 15;
  378. float yPos = margin;
  379. float xPos;
  380. {
  381. Label *label = new Label();
  382. label->box.pos = Vec(margin, yPos);
  383. label->text = "Audio device";
  384. addChild(label);
  385. yPos += labelHeight + margin;
  386. AudioChoice *choice = new AudioChoice();
  387. choice->audioInterface = dynamic_cast<AudioInterface*>(module);
  388. choice->box.pos = Vec(margin, yPos);
  389. choice->box.size.x = box.size.x - 2*margin;
  390. addChild(choice);
  391. yPos += choice->box.size.y + margin;
  392. }
  393. {
  394. Label *label = new Label();
  395. label->box.pos = Vec(margin, yPos);
  396. label->text = "Sample rate";
  397. addChild(label);
  398. yPos += labelHeight + margin;
  399. SampleRateChoice *choice = new SampleRateChoice();
  400. choice->audioInterface = dynamic_cast<AudioInterface*>(module);
  401. choice->box.pos = Vec(margin, yPos);
  402. choice->box.size.x = box.size.x - 2*margin;
  403. addChild(choice);
  404. yPos += choice->box.size.y + margin;
  405. }
  406. {
  407. Label *label = new Label();
  408. label->box.pos = Vec(margin, yPos);
  409. label->text = "Block size";
  410. addChild(label);
  411. yPos += labelHeight + margin;
  412. BlockSizeChoice *choice = new BlockSizeChoice();
  413. choice->audioInterface = dynamic_cast<AudioInterface*>(module);
  414. choice->box.pos = Vec(margin, yPos);
  415. choice->box.size.x = box.size.x - 2*margin;
  416. addChild(choice);
  417. yPos += choice->box.size.y + margin;
  418. }
  419. {
  420. Label *label = new Label();
  421. label->box.pos = Vec(margin, yPos);
  422. label->text = "Outputs";
  423. addChild(label);
  424. yPos += labelHeight + margin;
  425. }
  426. yPos += 5;
  427. xPos = 10;
  428. for (int i = 0; i < 4; i++) {
  429. addInput(createInput<PJ3410Port>(Vec(xPos, yPos), module, AudioInterface::AUDIO1_INPUT + i));
  430. Label *label = new Label();
  431. label->box.pos = Vec(xPos + 4, yPos + 28);
  432. label->text = stringf("%d", i + 1);
  433. addChild(label);
  434. xPos += 37 + margin;
  435. }
  436. yPos += 35 + margin;
  437. yPos += 5;
  438. xPos = 10;
  439. for (int i = 4; i < 8; i++) {
  440. addInput(createInput<PJ3410Port>(Vec(xPos, yPos), module, AudioInterface::AUDIO1_INPUT + i));
  441. Label *label = new Label();
  442. label->box.pos = Vec(xPos + 4, yPos + 28);
  443. label->text = stringf("%d", i + 1);
  444. addChild(label);
  445. xPos += 37 + margin;
  446. }
  447. yPos += 35 + margin;
  448. {
  449. Label *label = new Label();
  450. label->box.pos = Vec(margin, yPos);
  451. label->text = "Inputs";
  452. addChild(label);
  453. yPos += labelHeight + margin;
  454. }
  455. yPos += 5;
  456. xPos = 10;
  457. for (int i = 0; i < 4; i++) {
  458. addOutput(createOutput<PJ3410Port>(Vec(xPos, yPos), module, AudioInterface::AUDIO1_OUTPUT + i));
  459. Label *label = new Label();
  460. label->box.pos = Vec(xPos + 4, yPos + 28);
  461. label->text = stringf("%d", i + 1);
  462. addChild(label);
  463. xPos += 37 + margin;
  464. }
  465. yPos += 35 + margin;
  466. yPos += 5;
  467. xPos = 10;
  468. for (int i = 4; i < 8; i++) {
  469. addOutput(createOutput<PJ3410Port>(Vec(xPos, yPos), module, AudioInterface::AUDIO1_OUTPUT + i));
  470. Label *label = new Label();
  471. label->box.pos = Vec(xPos + 4, yPos + 28);
  472. label->text = stringf("%d", i + 1);
  473. addChild(label);
  474. xPos += 37 + margin;
  475. }
  476. yPos += 35 + margin;
  477. }