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.

238 lines
6.4KB

  1. #include <app/AudioWidget.hpp>
  2. #include <helpers.hpp>
  3. namespace rack {
  4. namespace app {
  5. struct AudioDriverItem : ui::MenuItem {
  6. audio::Port* port;
  7. int driverId;
  8. void onAction(const event::Action& e) override {
  9. port->setDriverId(driverId);
  10. }
  11. };
  12. struct AudioDriverChoice : LedDisplayChoice {
  13. audio::Port* port;
  14. void onAction(const event::Action& e) override {
  15. if (!port)
  16. return;
  17. ui::Menu* menu = createMenu();
  18. menu->addChild(createMenuLabel("Audio driver"));
  19. for (int driverId : port->getDriverIds()) {
  20. AudioDriverItem* item = new AudioDriverItem;
  21. item->port = port;
  22. item->driverId = driverId;
  23. item->text = port->getDriverName(driverId);
  24. item->rightText = CHECKMARK(item->driverId == port->driverId);
  25. menu->addChild(item);
  26. }
  27. }
  28. void step() override {
  29. text = (box.size.x >= 200.0) ? "Driver: " : "";
  30. std::string driverName = (port) ? port->getDriverName(port->driverId) : "";
  31. if (driverName != "") {
  32. text += driverName;
  33. color.a = 1.f;
  34. }
  35. else {
  36. text += "(No driver)";
  37. color.a = 0.5f;
  38. }
  39. }
  40. };
  41. struct AudioDeviceItem : ui::MenuItem {
  42. audio::Port* port;
  43. int deviceId;
  44. int offset;
  45. void onAction(const event::Action& e) override {
  46. port->setDeviceId(deviceId, offset);
  47. }
  48. };
  49. struct AudioDeviceChoice : LedDisplayChoice {
  50. audio::Port* port;
  51. /** Prevents devices with a ridiculous number of channels from being displayed */
  52. int maxTotalChannels = 128;
  53. void onAction(const event::Action& e) override {
  54. if (!port)
  55. return;
  56. ui::Menu* menu = createMenu();
  57. menu->addChild(createMenuLabel("Audio device"));
  58. int deviceCount = port->getDeviceCount();
  59. {
  60. AudioDeviceItem* item = new AudioDeviceItem;
  61. item->port = port;
  62. item->deviceId = -1;
  63. item->text = "(No device)";
  64. item->rightText = CHECKMARK(item->deviceId == port->deviceId);
  65. menu->addChild(item);
  66. }
  67. for (int deviceId = 0; deviceId < deviceCount; deviceId++) {
  68. int channels = std::min(maxTotalChannels, port->getDeviceChannels(deviceId));
  69. for (int offset = 0; offset < channels; offset += port->maxChannels) {
  70. AudioDeviceItem* item = new AudioDeviceItem;
  71. item->port = port;
  72. item->deviceId = deviceId;
  73. item->offset = offset;
  74. item->text = port->getDeviceDetail(deviceId, offset);
  75. item->rightText = CHECKMARK(item->deviceId == port->deviceId && item->offset == port->offset);
  76. menu->addChild(item);
  77. }
  78. }
  79. }
  80. void step() override {
  81. text = (box.size.x >= 200.0) ? "Device: " : "";
  82. std::string detail = (port) ? port->getDeviceDetail(port->deviceId, port->offset) : "";
  83. if (detail != "") {
  84. text += detail;
  85. color.a = (detail == "") ? 0.5f : 1.f;
  86. }
  87. else {
  88. text += "(No device)";
  89. color.a = 0.5f;
  90. }
  91. }
  92. };
  93. struct AudioSampleRateItem : ui::MenuItem {
  94. audio::Port* port;
  95. int sampleRate;
  96. void onAction(const event::Action& e) override {
  97. port->setSampleRate(sampleRate);
  98. }
  99. };
  100. struct AudioSampleRateChoice : LedDisplayChoice {
  101. audio::Port* port;
  102. void onAction(const event::Action& e) override {
  103. if (!port)
  104. return;
  105. ui::Menu* menu = createMenu();
  106. menu->addChild(createMenuLabel("Sample rate"));
  107. std::vector<int> sampleRates = port->getSampleRates();
  108. if (sampleRates.empty()) {
  109. menu->addChild(createMenuLabel("(Locked by device)"));
  110. }
  111. for (int sampleRate : sampleRates) {
  112. AudioSampleRateItem* item = new AudioSampleRateItem;
  113. item->port = port;
  114. item->sampleRate = sampleRate;
  115. item->text = string::f("%g kHz", sampleRate / 1000.0);
  116. item->rightText = CHECKMARK(item->sampleRate == port->sampleRate);
  117. menu->addChild(item);
  118. }
  119. }
  120. void step() override {
  121. text = (box.size.x >= 100.0) ? "Rate: " : "";
  122. if (port) {
  123. text += string::f("%g kHz", port->sampleRate / 1000.0);
  124. }
  125. else {
  126. text += "0 kHz";
  127. }
  128. }
  129. };
  130. struct AudioBlockSizeItem : ui::MenuItem {
  131. audio::Port* port;
  132. int blockSize;
  133. void onAction(const event::Action& e) override {
  134. port->setBlockSize(blockSize);
  135. }
  136. };
  137. struct AudioBlockSizeChoice : LedDisplayChoice {
  138. audio::Port* port;
  139. void onAction(const event::Action& e) override {
  140. if (!port)
  141. return;
  142. ui::Menu* menu = createMenu();
  143. menu->addChild(createMenuLabel("Block size"));
  144. std::vector<int> blockSizes = port->getBlockSizes();
  145. if (blockSizes.empty()) {
  146. menu->addChild(createMenuLabel("(Locked by device)"));
  147. }
  148. for (int blockSize : blockSizes) {
  149. AudioBlockSizeItem* item = new AudioBlockSizeItem;
  150. item->port = port;
  151. item->blockSize = blockSize;
  152. float latency = (float) blockSize / port->sampleRate * 1000.0;
  153. item->text = string::f("%d (%.1f ms)", blockSize, latency);
  154. item->rightText = CHECKMARK(item->blockSize == port->blockSize);
  155. menu->addChild(item);
  156. }
  157. }
  158. void step() override {
  159. text = (box.size.x >= 100.0) ? "Block size: " : "";
  160. if (port) {
  161. text += string::f("%d", port->blockSize);
  162. }
  163. else {
  164. text += "0";
  165. }
  166. }
  167. };
  168. void AudioWidget::setAudioPort(audio::Port* port) {
  169. clearChildren();
  170. math::Vec pos;
  171. AudioDriverChoice* driverChoice = createWidget<AudioDriverChoice>(pos);
  172. driverChoice->box.size.x = box.size.x;
  173. driverChoice->port = port;
  174. addChild(driverChoice);
  175. pos = driverChoice->box.getBottomLeft();
  176. this->driverChoice = driverChoice;
  177. this->driverSeparator = createWidget<LedDisplaySeparator>(pos);
  178. this->driverSeparator->box.size.x = box.size.x;
  179. addChild(this->driverSeparator);
  180. AudioDeviceChoice* deviceChoice = createWidget<AudioDeviceChoice>(pos);
  181. deviceChoice->box.size.x = box.size.x;
  182. deviceChoice->port = port;
  183. addChild(deviceChoice);
  184. pos = deviceChoice->box.getBottomLeft();
  185. this->deviceChoice = deviceChoice;
  186. this->deviceSeparator = createWidget<LedDisplaySeparator>(pos);
  187. this->deviceSeparator->box.size.x = box.size.x;
  188. addChild(this->deviceSeparator);
  189. AudioSampleRateChoice* sampleRateChoice = createWidget<AudioSampleRateChoice>(pos);
  190. sampleRateChoice->box.size.x = box.size.x / 2;
  191. sampleRateChoice->port = port;
  192. addChild(sampleRateChoice);
  193. this->sampleRateChoice = sampleRateChoice;
  194. this->sampleRateSeparator = createWidget<LedDisplaySeparator>(pos);
  195. this->sampleRateSeparator->box.pos.x = box.size.x / 2;
  196. this->sampleRateSeparator->box.size.y = this->sampleRateChoice->box.size.y;
  197. addChild(this->sampleRateSeparator);
  198. AudioBlockSizeChoice* bufferSizeChoice = createWidget<AudioBlockSizeChoice>(pos);
  199. bufferSizeChoice->box.pos.x = box.size.x / 2;
  200. bufferSizeChoice->box.size.x = box.size.x / 2;
  201. bufferSizeChoice->port = port;
  202. addChild(bufferSizeChoice);
  203. this->bufferSizeChoice = bufferSizeChoice;
  204. }
  205. } // namespace app
  206. } // namespace rack