The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

1171 lines
40KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-9 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #include "../../../core/juce_StandardHeader.h"
  19. BEGIN_JUCE_NAMESPACE
  20. #include "juce_AudioDeviceSelectorComponent.h"
  21. #include "../buttons/juce_TextButton.h"
  22. #include "../menus/juce_PopupMenu.h"
  23. #include "../windows/juce_AlertWindow.h"
  24. #include "../lookandfeel/juce_LookAndFeel.h"
  25. #include "../../../text/juce_LocalisedStrings.h"
  26. //==============================================================================
  27. class SimpleDeviceManagerInputLevelMeter : public Component,
  28. public Timer
  29. {
  30. public:
  31. SimpleDeviceManagerInputLevelMeter (AudioDeviceManager* const manager_)
  32. : manager (manager_),
  33. level (0)
  34. {
  35. startTimer (50);
  36. manager->enableInputLevelMeasurement (true);
  37. }
  38. ~SimpleDeviceManagerInputLevelMeter()
  39. {
  40. manager->enableInputLevelMeasurement (false);
  41. }
  42. void timerCallback()
  43. {
  44. const float newLevel = (float) manager->getCurrentInputLevel();
  45. if (fabsf (level - newLevel) > 0.005f)
  46. {
  47. level = newLevel;
  48. repaint();
  49. }
  50. }
  51. void paint (Graphics& g)
  52. {
  53. getLookAndFeel().drawLevelMeter (g, getWidth(), getHeight(),
  54. (float) exp (log (level) / 3.0)); // (add a bit of a skew to make the level more obvious)
  55. }
  56. private:
  57. AudioDeviceManager* const manager;
  58. float level;
  59. SimpleDeviceManagerInputLevelMeter (const SimpleDeviceManagerInputLevelMeter&);
  60. SimpleDeviceManagerInputLevelMeter& operator= (const SimpleDeviceManagerInputLevelMeter&);
  61. };
  62. //==============================================================================
  63. class MidiInputSelectorComponentListBox : public ListBox,
  64. public ListBoxModel
  65. {
  66. public:
  67. //==============================================================================
  68. MidiInputSelectorComponentListBox (AudioDeviceManager& deviceManager_,
  69. const String& noItemsMessage_,
  70. const int minNumber_,
  71. const int maxNumber_)
  72. : ListBox (String::empty, 0),
  73. deviceManager (deviceManager_),
  74. noItemsMessage (noItemsMessage_),
  75. minNumber (minNumber_),
  76. maxNumber (maxNumber_)
  77. {
  78. items = MidiInput::getDevices();
  79. setModel (this);
  80. setOutlineThickness (1);
  81. }
  82. ~MidiInputSelectorComponentListBox()
  83. {
  84. }
  85. int getNumRows()
  86. {
  87. return items.size();
  88. }
  89. void paintListBoxItem (int row,
  90. Graphics& g,
  91. int width, int height,
  92. bool rowIsSelected)
  93. {
  94. if (((unsigned int) row) < (unsigned int) items.size())
  95. {
  96. if (rowIsSelected)
  97. g.fillAll (findColour (TextEditor::highlightColourId)
  98. .withMultipliedAlpha (0.3f));
  99. const String item (items [row]);
  100. bool enabled = deviceManager.isMidiInputEnabled (item);
  101. const int x = getTickX();
  102. const float tickW = height * 0.75f;
  103. getLookAndFeel().drawTickBox (g, *this, x - tickW, (height - tickW) / 2, tickW, tickW,
  104. enabled, true, true, false);
  105. g.setFont (height * 0.6f);
  106. g.setColour (findColour (ListBox::textColourId, true).withMultipliedAlpha (enabled ? 1.0f : 0.6f));
  107. g.drawText (item, x, 0, width - x - 2, height, Justification::centredLeft, true);
  108. }
  109. }
  110. void listBoxItemClicked (int row, const MouseEvent& e)
  111. {
  112. selectRow (row);
  113. if (e.x < getTickX())
  114. flipEnablement (row);
  115. }
  116. void listBoxItemDoubleClicked (int row, const MouseEvent&)
  117. {
  118. flipEnablement (row);
  119. }
  120. void returnKeyPressed (int row)
  121. {
  122. flipEnablement (row);
  123. }
  124. void paint (Graphics& g)
  125. {
  126. ListBox::paint (g);
  127. if (items.size() == 0)
  128. {
  129. g.setColour (Colours::grey);
  130. g.setFont (13.0f);
  131. g.drawText (noItemsMessage,
  132. 0, 0, getWidth(), getHeight() / 2,
  133. Justification::centred, true);
  134. }
  135. }
  136. int getBestHeight (const int preferredHeight)
  137. {
  138. const int extra = getOutlineThickness() * 2;
  139. return jmax (getRowHeight() * 2 + extra,
  140. jmin (getRowHeight() * getNumRows() + extra,
  141. preferredHeight));
  142. }
  143. //==============================================================================
  144. juce_UseDebuggingNewOperator
  145. private:
  146. AudioDeviceManager& deviceManager;
  147. const String noItemsMessage;
  148. StringArray items;
  149. int minNumber, maxNumber;
  150. void flipEnablement (const int row)
  151. {
  152. if (((unsigned int) row) < (unsigned int) items.size())
  153. {
  154. const String item (items [row]);
  155. deviceManager.setMidiInputEnabled (item, ! deviceManager.isMidiInputEnabled (item));
  156. }
  157. }
  158. int getTickX() const
  159. {
  160. return getRowHeight() + 5;
  161. }
  162. MidiInputSelectorComponentListBox (const MidiInputSelectorComponentListBox&);
  163. MidiInputSelectorComponentListBox& operator= (const MidiInputSelectorComponentListBox&);
  164. };
  165. //==============================================================================
  166. class AudioDeviceSettingsPanel : public Component,
  167. public ComboBoxListener,
  168. public ChangeListener,
  169. public ButtonListener
  170. {
  171. public:
  172. AudioDeviceSettingsPanel (AudioIODeviceType* type_,
  173. AudioIODeviceType::DeviceSetupDetails& setup_,
  174. const bool hideAdvancedOptionsWithButton)
  175. : type (type_),
  176. setup (setup_)
  177. {
  178. sampleRateDropDown = 0;
  179. sampleRateLabel = 0;
  180. bufferSizeDropDown = 0;
  181. bufferSizeLabel = 0;
  182. outputDeviceDropDown = 0;
  183. outputDeviceLabel = 0;
  184. inputDeviceDropDown = 0;
  185. inputDeviceLabel = 0;
  186. testButton = 0;
  187. inputLevelMeter = 0;
  188. showUIButton = 0;
  189. inputChanList = 0;
  190. outputChanList = 0;
  191. inputChanLabel = 0;
  192. outputChanLabel = 0;
  193. showAdvancedSettingsButton = 0;
  194. if (hideAdvancedOptionsWithButton)
  195. {
  196. addAndMakeVisible (showAdvancedSettingsButton = new TextButton (TRANS("Show advanced settings...")));
  197. showAdvancedSettingsButton->addButtonListener (this);
  198. }
  199. type->scanForDevices();
  200. setup.manager->addChangeListener (this);
  201. changeListenerCallback (0);
  202. }
  203. ~AudioDeviceSettingsPanel()
  204. {
  205. setup.manager->removeChangeListener (this);
  206. deleteAndZero (outputDeviceLabel);
  207. deleteAndZero (inputDeviceLabel);
  208. deleteAndZero (sampleRateLabel);
  209. deleteAndZero (bufferSizeLabel);
  210. deleteAndZero (showUIButton);
  211. deleteAndZero (inputChanLabel);
  212. deleteAndZero (outputChanLabel);
  213. deleteAndZero (showAdvancedSettingsButton);
  214. deleteAllChildren();
  215. }
  216. void resized()
  217. {
  218. const int lx = proportionOfWidth (0.35f);
  219. const int w = proportionOfWidth (0.4f);
  220. const int h = 24;
  221. const int space = 6;
  222. const int dh = h + space;
  223. int y = 0;
  224. if (outputDeviceDropDown != 0)
  225. {
  226. outputDeviceDropDown->setBounds (lx, y, w, h);
  227. if (testButton != 0)
  228. testButton->setBounds (proportionOfWidth (0.77f),
  229. outputDeviceDropDown->getY(),
  230. proportionOfWidth (0.18f),
  231. h);
  232. y += dh;
  233. }
  234. if (inputDeviceDropDown != 0)
  235. {
  236. inputDeviceDropDown->setBounds (lx, y, w, h);
  237. inputLevelMeter->setBounds (proportionOfWidth (0.77f),
  238. inputDeviceDropDown->getY(),
  239. proportionOfWidth (0.18f),
  240. h);
  241. y += dh;
  242. }
  243. const int maxBoxHeight = 100;//(getHeight() - y - dh * 2) / numBoxes;
  244. if (outputChanList != 0)
  245. {
  246. const int bh = outputChanList->getBestHeight (maxBoxHeight);
  247. outputChanList->setBounds (lx, y, proportionOfWidth (0.55f), bh);
  248. y += bh + space;
  249. }
  250. if (inputChanList != 0)
  251. {
  252. const int bh = inputChanList->getBestHeight (maxBoxHeight);
  253. inputChanList->setBounds (lx, y, proportionOfWidth (0.55f), bh);
  254. y += bh + space;
  255. }
  256. y += space * 2;
  257. if (showAdvancedSettingsButton != 0)
  258. {
  259. showAdvancedSettingsButton->changeWidthToFitText (h);
  260. showAdvancedSettingsButton->setTopLeftPosition (lx, y);
  261. }
  262. if (sampleRateDropDown != 0)
  263. {
  264. sampleRateDropDown->setVisible (showAdvancedSettingsButton == 0
  265. || ! showAdvancedSettingsButton->isVisible());
  266. sampleRateDropDown->setBounds (lx, y, w, h);
  267. y += dh;
  268. }
  269. if (bufferSizeDropDown != 0)
  270. {
  271. bufferSizeDropDown->setVisible (showAdvancedSettingsButton == 0
  272. || ! showAdvancedSettingsButton->isVisible());
  273. bufferSizeDropDown->setBounds (lx, y, w, h);
  274. y += dh;
  275. }
  276. if (showUIButton != 0)
  277. {
  278. showUIButton->setVisible (showAdvancedSettingsButton == 0
  279. || ! showAdvancedSettingsButton->isVisible());
  280. showUIButton->changeWidthToFitText (h);
  281. showUIButton->setTopLeftPosition (lx, y);
  282. }
  283. }
  284. void comboBoxChanged (ComboBox* comboBoxThatHasChanged)
  285. {
  286. if (comboBoxThatHasChanged == 0)
  287. return;
  288. AudioDeviceManager::AudioDeviceSetup config;
  289. setup.manager->getAudioDeviceSetup (config);
  290. String error;
  291. if (comboBoxThatHasChanged == outputDeviceDropDown
  292. || comboBoxThatHasChanged == inputDeviceDropDown)
  293. {
  294. if (outputDeviceDropDown != 0)
  295. config.outputDeviceName = outputDeviceDropDown->getSelectedId() < 0 ? String::empty
  296. : outputDeviceDropDown->getText();
  297. if (inputDeviceDropDown != 0)
  298. config.inputDeviceName = inputDeviceDropDown->getSelectedId() < 0 ? String::empty
  299. : inputDeviceDropDown->getText();
  300. if (! type->hasSeparateInputsAndOutputs())
  301. config.inputDeviceName = config.outputDeviceName;
  302. if (comboBoxThatHasChanged == inputDeviceDropDown)
  303. config.useDefaultInputChannels = true;
  304. else
  305. config.useDefaultOutputChannels = true;
  306. error = setup.manager->setAudioDeviceSetup (config, true);
  307. showCorrectDeviceName (inputDeviceDropDown, true);
  308. showCorrectDeviceName (outputDeviceDropDown, false);
  309. updateControlPanelButton();
  310. resized();
  311. }
  312. else if (comboBoxThatHasChanged == sampleRateDropDown)
  313. {
  314. if (sampleRateDropDown->getSelectedId() > 0)
  315. {
  316. config.sampleRate = sampleRateDropDown->getSelectedId();
  317. error = setup.manager->setAudioDeviceSetup (config, true);
  318. }
  319. }
  320. else if (comboBoxThatHasChanged == bufferSizeDropDown)
  321. {
  322. if (bufferSizeDropDown->getSelectedId() > 0)
  323. {
  324. config.bufferSize = bufferSizeDropDown->getSelectedId();
  325. error = setup.manager->setAudioDeviceSetup (config, true);
  326. }
  327. }
  328. if (error.isNotEmpty())
  329. {
  330. AlertWindow::showMessageBox (AlertWindow::WarningIcon,
  331. T("Error when trying to open audio device!"),
  332. error);
  333. }
  334. }
  335. void buttonClicked (Button* button)
  336. {
  337. if (button == showAdvancedSettingsButton)
  338. {
  339. showAdvancedSettingsButton->setVisible (false);
  340. resized();
  341. }
  342. else if (button == showUIButton)
  343. {
  344. AudioIODevice* const device = setup.manager->getCurrentAudioDevice();
  345. if (device != 0 && device->showControlPanel())
  346. {
  347. setup.manager->closeAudioDevice();
  348. setup.manager->restartLastAudioDevice();
  349. getTopLevelComponent()->toFront (true);
  350. }
  351. }
  352. else if (button == testButton && testButton != 0)
  353. {
  354. setup.manager->playTestSound();
  355. }
  356. }
  357. void updateControlPanelButton()
  358. {
  359. AudioIODevice* const currentDevice = setup.manager->getCurrentAudioDevice();
  360. deleteAndZero (showUIButton);
  361. if (currentDevice != 0 && currentDevice->hasControlPanel())
  362. {
  363. addAndMakeVisible (showUIButton = new TextButton (TRANS ("show this device's control panel"),
  364. TRANS ("opens the device's own control panel")));
  365. showUIButton->addButtonListener (this);
  366. }
  367. resized();
  368. }
  369. void changeListenerCallback (void*)
  370. {
  371. AudioIODevice* const currentDevice = setup.manager->getCurrentAudioDevice();
  372. if (setup.maxNumOutputChannels > 0 || ! type->hasSeparateInputsAndOutputs())
  373. {
  374. if (outputDeviceDropDown == 0)
  375. {
  376. outputDeviceDropDown = new ComboBox (String::empty);
  377. outputDeviceDropDown->addListener (this);
  378. addAndMakeVisible (outputDeviceDropDown);
  379. outputDeviceLabel = new Label (String::empty,
  380. type->hasSeparateInputsAndOutputs() ? TRANS ("output:")
  381. : TRANS ("device:"));
  382. outputDeviceLabel->attachToComponent (outputDeviceDropDown, true);
  383. if (setup.maxNumOutputChannels > 0)
  384. {
  385. addAndMakeVisible (testButton = new TextButton (TRANS ("Test")));
  386. testButton->addButtonListener (this);
  387. }
  388. }
  389. addNamesToDeviceBox (*outputDeviceDropDown, false);
  390. }
  391. if (setup.maxNumInputChannels > 0 && type->hasSeparateInputsAndOutputs())
  392. {
  393. if (inputDeviceDropDown == 0)
  394. {
  395. inputDeviceDropDown = new ComboBox (String::empty);
  396. inputDeviceDropDown->addListener (this);
  397. addAndMakeVisible (inputDeviceDropDown);
  398. inputDeviceLabel = new Label (String::empty, TRANS ("input:"));
  399. inputDeviceLabel->attachToComponent (inputDeviceDropDown, true);
  400. addAndMakeVisible (inputLevelMeter
  401. = new SimpleDeviceManagerInputLevelMeter (setup.manager));
  402. }
  403. addNamesToDeviceBox (*inputDeviceDropDown, true);
  404. }
  405. updateControlPanelButton();
  406. showCorrectDeviceName (inputDeviceDropDown, true);
  407. showCorrectDeviceName (outputDeviceDropDown, false);
  408. if (currentDevice != 0)
  409. {
  410. if (setup.maxNumOutputChannels > 0
  411. && setup.minNumOutputChannels < setup.manager->getCurrentAudioDevice()->getOutputChannelNames().size())
  412. {
  413. if (outputChanList == 0)
  414. {
  415. addAndMakeVisible (outputChanList
  416. = new ChannelSelectorListBox (setup, ChannelSelectorListBox::audioOutputType,
  417. TRANS ("(no audio output channels found)")));
  418. outputChanLabel = new Label (String::empty, TRANS ("active output channels:"));
  419. outputChanLabel->attachToComponent (outputChanList, true);
  420. }
  421. outputChanList->refresh();
  422. }
  423. else
  424. {
  425. deleteAndZero (outputChanLabel);
  426. deleteAndZero (outputChanList);
  427. }
  428. if (setup.maxNumInputChannels > 0
  429. && setup.minNumInputChannels < setup.manager->getCurrentAudioDevice()->getInputChannelNames().size())
  430. {
  431. if (inputChanList == 0)
  432. {
  433. addAndMakeVisible (inputChanList
  434. = new ChannelSelectorListBox (setup, ChannelSelectorListBox::audioInputType,
  435. TRANS ("(no audio input channels found)")));
  436. inputChanLabel = new Label (String::empty, TRANS ("active input channels:"));
  437. inputChanLabel->attachToComponent (inputChanList, true);
  438. }
  439. inputChanList->refresh();
  440. }
  441. else
  442. {
  443. deleteAndZero (inputChanLabel);
  444. deleteAndZero (inputChanList);
  445. }
  446. // sample rate..
  447. {
  448. if (sampleRateDropDown == 0)
  449. {
  450. addAndMakeVisible (sampleRateDropDown = new ComboBox (String::empty));
  451. sampleRateDropDown->addListener (this);
  452. delete sampleRateLabel;
  453. sampleRateLabel = new Label (String::empty, TRANS ("sample rate:"));
  454. sampleRateLabel->attachToComponent (sampleRateDropDown, true);
  455. }
  456. else
  457. {
  458. sampleRateDropDown->clear();
  459. sampleRateDropDown->removeListener (this);
  460. }
  461. const int numRates = currentDevice->getNumSampleRates();
  462. for (int i = 0; i < numRates; ++i)
  463. {
  464. const int rate = roundToInt (currentDevice->getSampleRate (i));
  465. sampleRateDropDown->addItem (String (rate) + T(" Hz"), rate);
  466. }
  467. sampleRateDropDown->setSelectedId (roundToInt (currentDevice->getCurrentSampleRate()), true);
  468. sampleRateDropDown->addListener (this);
  469. }
  470. // buffer size
  471. {
  472. if (bufferSizeDropDown == 0)
  473. {
  474. addAndMakeVisible (bufferSizeDropDown = new ComboBox (String::empty));
  475. bufferSizeDropDown->addListener (this);
  476. delete bufferSizeLabel;
  477. bufferSizeLabel = new Label (String::empty, TRANS ("audio buffer size:"));
  478. bufferSizeLabel->attachToComponent (bufferSizeDropDown, true);
  479. }
  480. else
  481. {
  482. bufferSizeDropDown->clear();
  483. }
  484. const int numBufferSizes = currentDevice->getNumBufferSizesAvailable();
  485. double currentRate = currentDevice->getCurrentSampleRate();
  486. if (currentRate == 0)
  487. currentRate = 48000.0;
  488. for (int i = 0; i < numBufferSizes; ++i)
  489. {
  490. const int bs = currentDevice->getBufferSizeSamples (i);
  491. bufferSizeDropDown->addItem (String (bs)
  492. + T(" samples (")
  493. + String (bs * 1000.0 / currentRate, 1)
  494. + T(" ms)"),
  495. bs);
  496. }
  497. bufferSizeDropDown->setSelectedId (currentDevice->getCurrentBufferSizeSamples(), true);
  498. }
  499. }
  500. else
  501. {
  502. jassert (setup.manager->getCurrentAudioDevice() == 0); // not the correct device type!
  503. deleteAndZero (sampleRateLabel);
  504. deleteAndZero (bufferSizeLabel);
  505. deleteAndZero (sampleRateDropDown);
  506. deleteAndZero (bufferSizeDropDown);
  507. if (outputDeviceDropDown != 0)
  508. outputDeviceDropDown->setSelectedId (-1, true);
  509. if (inputDeviceDropDown != 0)
  510. inputDeviceDropDown->setSelectedId (-1, true);
  511. }
  512. resized();
  513. setSize (getWidth(), getLowestY() + 4);
  514. }
  515. private:
  516. AudioIODeviceType* const type;
  517. const AudioIODeviceType::DeviceSetupDetails setup;
  518. ComboBox* outputDeviceDropDown;
  519. ComboBox* inputDeviceDropDown;
  520. ComboBox* sampleRateDropDown;
  521. ComboBox* bufferSizeDropDown;
  522. Label* outputDeviceLabel;
  523. Label* inputDeviceLabel;
  524. Label* sampleRateLabel;
  525. Label* bufferSizeLabel;
  526. Label* inputChanLabel;
  527. Label* outputChanLabel;
  528. TextButton* testButton;
  529. Component* inputLevelMeter;
  530. TextButton* showUIButton;
  531. TextButton* showAdvancedSettingsButton;
  532. void showCorrectDeviceName (ComboBox* const box, const bool isInput)
  533. {
  534. if (box != 0)
  535. {
  536. AudioIODevice* const currentDevice = dynamic_cast <AudioIODevice*> (setup.manager->getCurrentAudioDevice());
  537. const int index = type->getIndexOfDevice (currentDevice, isInput);
  538. box->setSelectedId (index + 1, true);
  539. if (testButton != 0 && ! isInput)
  540. testButton->setEnabled (index >= 0);
  541. }
  542. }
  543. void addNamesToDeviceBox (ComboBox& combo, bool isInputs)
  544. {
  545. const StringArray devs (type->getDeviceNames (isInputs));
  546. combo.clear (true);
  547. for (int i = 0; i < devs.size(); ++i)
  548. combo.addItem (devs[i], i + 1);
  549. combo.addItem (TRANS("<< none >>"), -1);
  550. combo.setSelectedId (-1, true);
  551. }
  552. int getLowestY() const
  553. {
  554. int y = 0;
  555. for (int i = getNumChildComponents(); --i >= 0;)
  556. y = jmax (y, getChildComponent (i)->getBottom());
  557. return y;
  558. }
  559. public:
  560. //==============================================================================
  561. class ChannelSelectorListBox : public ListBox,
  562. public ListBoxModel
  563. {
  564. public:
  565. enum BoxType
  566. {
  567. audioInputType,
  568. audioOutputType
  569. };
  570. //==============================================================================
  571. ChannelSelectorListBox (const AudioIODeviceType::DeviceSetupDetails& setup_,
  572. const BoxType type_,
  573. const String& noItemsMessage_)
  574. : ListBox (String::empty, 0),
  575. setup (setup_),
  576. type (type_),
  577. noItemsMessage (noItemsMessage_)
  578. {
  579. refresh();
  580. setModel (this);
  581. setOutlineThickness (1);
  582. }
  583. ~ChannelSelectorListBox()
  584. {
  585. }
  586. void refresh()
  587. {
  588. items.clear();
  589. AudioIODevice* const currentDevice = setup.manager->getCurrentAudioDevice();
  590. if (currentDevice != 0)
  591. {
  592. if (type == audioInputType)
  593. items = currentDevice->getInputChannelNames();
  594. else if (type == audioOutputType)
  595. items = currentDevice->getOutputChannelNames();
  596. if (setup.useStereoPairs)
  597. {
  598. StringArray pairs;
  599. for (int i = 0; i < items.size(); i += 2)
  600. {
  601. String name (items[i]);
  602. String name2 (items[i + 1]);
  603. String commonBit;
  604. for (int j = 0; j < name.length(); ++j)
  605. if (name.substring (0, j).equalsIgnoreCase (name2.substring (0, j)))
  606. commonBit = name.substring (0, j);
  607. pairs.add (name.trim()
  608. + " + "
  609. + name2.substring (commonBit.length()).trim());
  610. }
  611. items = pairs;
  612. }
  613. }
  614. updateContent();
  615. repaint();
  616. }
  617. int getNumRows()
  618. {
  619. return items.size();
  620. }
  621. void paintListBoxItem (int row,
  622. Graphics& g,
  623. int width, int height,
  624. bool rowIsSelected)
  625. {
  626. if (((unsigned int) row) < (unsigned int) items.size())
  627. {
  628. if (rowIsSelected)
  629. g.fillAll (findColour (TextEditor::highlightColourId)
  630. .withMultipliedAlpha (0.3f));
  631. const String item (items [row]);
  632. bool enabled = false;
  633. AudioDeviceManager::AudioDeviceSetup config;
  634. setup.manager->getAudioDeviceSetup (config);
  635. if (setup.useStereoPairs)
  636. {
  637. if (type == audioInputType)
  638. enabled = config.inputChannels [row * 2] || config.inputChannels [row * 2 + 1];
  639. else if (type == audioOutputType)
  640. enabled = config.outputChannels [row * 2] || config.outputChannels [row * 2 + 1];
  641. }
  642. else
  643. {
  644. if (type == audioInputType)
  645. enabled = config.inputChannels [row];
  646. else if (type == audioOutputType)
  647. enabled = config.outputChannels [row];
  648. }
  649. const int x = getTickX();
  650. const float tickW = height * 0.75f;
  651. getLookAndFeel().drawTickBox (g, *this, x - tickW, (height - tickW) / 2, tickW, tickW,
  652. enabled, true, true, false);
  653. g.setFont (height * 0.6f);
  654. g.setColour (findColour (ListBox::textColourId, true).withMultipliedAlpha (enabled ? 1.0f : 0.6f));
  655. g.drawText (item, x, 0, width - x - 2, height, Justification::centredLeft, true);
  656. }
  657. }
  658. void listBoxItemClicked (int row, const MouseEvent& e)
  659. {
  660. selectRow (row);
  661. if (e.x < getTickX())
  662. flipEnablement (row);
  663. }
  664. void listBoxItemDoubleClicked (int row, const MouseEvent&)
  665. {
  666. flipEnablement (row);
  667. }
  668. void returnKeyPressed (int row)
  669. {
  670. flipEnablement (row);
  671. }
  672. void paint (Graphics& g)
  673. {
  674. ListBox::paint (g);
  675. if (items.size() == 0)
  676. {
  677. g.setColour (Colours::grey);
  678. g.setFont (13.0f);
  679. g.drawText (noItemsMessage,
  680. 0, 0, getWidth(), getHeight() / 2,
  681. Justification::centred, true);
  682. }
  683. }
  684. int getBestHeight (int maxHeight)
  685. {
  686. return getRowHeight() * jlimit (2, jmax (2, maxHeight / getRowHeight()),
  687. getNumRows())
  688. + getOutlineThickness() * 2;
  689. }
  690. //==============================================================================
  691. juce_UseDebuggingNewOperator
  692. private:
  693. const AudioIODeviceType::DeviceSetupDetails setup;
  694. const BoxType type;
  695. const String noItemsMessage;
  696. StringArray items;
  697. void flipEnablement (const int row)
  698. {
  699. jassert (type == audioInputType || type == audioOutputType);
  700. if (((unsigned int) row) < (unsigned int) items.size())
  701. {
  702. AudioDeviceManager::AudioDeviceSetup config;
  703. setup.manager->getAudioDeviceSetup (config);
  704. if (setup.useStereoPairs)
  705. {
  706. BitArray bits;
  707. BitArray& original = (type == audioInputType ? config.inputChannels
  708. : config.outputChannels);
  709. int i;
  710. for (i = 0; i < 256; i += 2)
  711. bits.setBit (i / 2, original [i] || original [i + 1]);
  712. if (type == audioInputType)
  713. {
  714. config.useDefaultInputChannels = false;
  715. flipBit (bits, row, setup.minNumInputChannels / 2, setup.maxNumInputChannels / 2);
  716. }
  717. else
  718. {
  719. config.useDefaultOutputChannels = false;
  720. flipBit (bits, row, setup.minNumOutputChannels / 2, setup.maxNumOutputChannels / 2);
  721. }
  722. for (i = 0; i < 256; ++i)
  723. original.setBit (i, bits [i / 2]);
  724. }
  725. else
  726. {
  727. if (type == audioInputType)
  728. {
  729. config.useDefaultInputChannels = false;
  730. flipBit (config.inputChannels, row, setup.minNumInputChannels, setup.maxNumInputChannels);
  731. }
  732. else
  733. {
  734. config.useDefaultOutputChannels = false;
  735. flipBit (config.outputChannels, row, setup.minNumOutputChannels, setup.maxNumOutputChannels);
  736. }
  737. }
  738. String error (setup.manager->setAudioDeviceSetup (config, true));
  739. if (! error.isEmpty())
  740. {
  741. //xxx
  742. }
  743. }
  744. }
  745. static void flipBit (BitArray& chans, int index, int minNumber, int maxNumber)
  746. {
  747. const int numActive = chans.countNumberOfSetBits();
  748. if (chans [index])
  749. {
  750. if (numActive > minNumber)
  751. chans.setBit (index, false);
  752. }
  753. else
  754. {
  755. if (numActive >= maxNumber)
  756. {
  757. const int firstActiveChan = chans.findNextSetBit();
  758. chans.setBit (index > firstActiveChan
  759. ? firstActiveChan : chans.getHighestBit(),
  760. false);
  761. }
  762. chans.setBit (index, true);
  763. }
  764. }
  765. int getTickX() const
  766. {
  767. return getRowHeight() + 5;
  768. }
  769. ChannelSelectorListBox (const ChannelSelectorListBox&);
  770. ChannelSelectorListBox& operator= (const ChannelSelectorListBox&);
  771. };
  772. private:
  773. ChannelSelectorListBox* inputChanList;
  774. ChannelSelectorListBox* outputChanList;
  775. AudioDeviceSettingsPanel (const AudioDeviceSettingsPanel&);
  776. AudioDeviceSettingsPanel& operator= (const AudioDeviceSettingsPanel&);
  777. };
  778. //==============================================================================
  779. AudioDeviceSelectorComponent::AudioDeviceSelectorComponent (AudioDeviceManager& deviceManager_,
  780. const int minInputChannels_,
  781. const int maxInputChannels_,
  782. const int minOutputChannels_,
  783. const int maxOutputChannels_,
  784. const bool showMidiInputOptions,
  785. const bool showMidiOutputSelector,
  786. const bool showChannelsAsStereoPairs_,
  787. const bool hideAdvancedOptionsWithButton_)
  788. : deviceManager (deviceManager_),
  789. deviceTypeDropDown (0),
  790. deviceTypeDropDownLabel (0),
  791. audioDeviceSettingsComp (0),
  792. minOutputChannels (minOutputChannels_),
  793. maxOutputChannels (maxOutputChannels_),
  794. minInputChannels (minInputChannels_),
  795. maxInputChannels (maxInputChannels_),
  796. showChannelsAsStereoPairs (showChannelsAsStereoPairs_),
  797. hideAdvancedOptionsWithButton (hideAdvancedOptionsWithButton_)
  798. {
  799. jassert (minOutputChannels >= 0 && minOutputChannels <= maxOutputChannels);
  800. jassert (minInputChannels >= 0 && minInputChannels <= maxInputChannels);
  801. if (deviceManager_.getAvailableDeviceTypes().size() > 1)
  802. {
  803. deviceTypeDropDown = new ComboBox (String::empty);
  804. for (int i = 0; i < deviceManager_.getAvailableDeviceTypes().size(); ++i)
  805. {
  806. deviceTypeDropDown
  807. ->addItem (deviceManager_.getAvailableDeviceTypes().getUnchecked(i)->getTypeName(),
  808. i + 1);
  809. }
  810. addAndMakeVisible (deviceTypeDropDown);
  811. deviceTypeDropDown->addListener (this);
  812. deviceTypeDropDownLabel = new Label (String::empty, TRANS ("audio device type:"));
  813. deviceTypeDropDownLabel->setJustificationType (Justification::centredRight);
  814. deviceTypeDropDownLabel->attachToComponent (deviceTypeDropDown, true);
  815. }
  816. if (showMidiInputOptions)
  817. {
  818. addAndMakeVisible (midiInputsList
  819. = new MidiInputSelectorComponentListBox (deviceManager,
  820. TRANS("(no midi inputs available)"),
  821. 0, 0));
  822. midiInputsLabel = new Label (String::empty, TRANS ("active midi inputs:"));
  823. midiInputsLabel->setJustificationType (Justification::topRight);
  824. midiInputsLabel->attachToComponent (midiInputsList, true);
  825. }
  826. else
  827. {
  828. midiInputsList = 0;
  829. midiInputsLabel = 0;
  830. }
  831. if (showMidiOutputSelector)
  832. {
  833. addAndMakeVisible (midiOutputSelector = new ComboBox (String::empty));
  834. midiOutputSelector->addListener (this);
  835. midiOutputLabel = new Label ("lm", TRANS("Midi Output:"));
  836. midiOutputLabel->attachToComponent (midiOutputSelector, true);
  837. }
  838. else
  839. {
  840. midiOutputSelector = 0;
  841. midiOutputLabel = 0;
  842. }
  843. deviceManager_.addChangeListener (this);
  844. changeListenerCallback (0);
  845. }
  846. AudioDeviceSelectorComponent::~AudioDeviceSelectorComponent()
  847. {
  848. deviceManager.removeChangeListener (this);
  849. deleteAllChildren();
  850. }
  851. void AudioDeviceSelectorComponent::resized()
  852. {
  853. const int lx = proportionOfWidth (0.35f);
  854. const int w = proportionOfWidth (0.4f);
  855. const int h = 24;
  856. const int space = 6;
  857. const int dh = h + space;
  858. int y = 15;
  859. if (deviceTypeDropDown != 0)
  860. {
  861. deviceTypeDropDown->setBounds (lx, y, proportionOfWidth (0.3f), h);
  862. y += dh + space * 2;
  863. }
  864. if (audioDeviceSettingsComp != 0)
  865. {
  866. audioDeviceSettingsComp->setBounds (0, y, getWidth(), audioDeviceSettingsComp->getHeight());
  867. y += audioDeviceSettingsComp->getHeight() + space;
  868. }
  869. if (midiInputsList != 0)
  870. {
  871. const int bh = midiInputsList->getBestHeight (jmin (h * 8, getHeight() - y - space - h));
  872. midiInputsList->setBounds (lx, y, w, bh);
  873. y += bh + space;
  874. }
  875. if (midiOutputSelector != 0)
  876. midiOutputSelector->setBounds (lx, y, w, h);
  877. }
  878. void AudioDeviceSelectorComponent::childBoundsChanged (Component* child)
  879. {
  880. if (child == audioDeviceSettingsComp)
  881. resized();
  882. }
  883. void AudioDeviceSelectorComponent::buttonClicked (Button*)
  884. {
  885. AudioIODevice* const device = deviceManager.getCurrentAudioDevice();
  886. if (device != 0 && device->hasControlPanel())
  887. {
  888. if (device->showControlPanel())
  889. deviceManager.restartLastAudioDevice();
  890. getTopLevelComponent()->toFront (true);
  891. }
  892. }
  893. void AudioDeviceSelectorComponent::comboBoxChanged (ComboBox* comboBoxThatHasChanged)
  894. {
  895. if (comboBoxThatHasChanged == deviceTypeDropDown)
  896. {
  897. AudioIODeviceType* const type = deviceManager.getAvailableDeviceTypes() [deviceTypeDropDown->getSelectedId() - 1];
  898. if (type != 0)
  899. {
  900. deleteAndZero (audioDeviceSettingsComp);
  901. deviceManager.setCurrentAudioDeviceType (type->getTypeName(), true);
  902. changeListenerCallback (0); // needed in case the type hasn't actally changed
  903. }
  904. }
  905. else if (comboBoxThatHasChanged == midiOutputSelector)
  906. {
  907. deviceManager.setDefaultMidiOutput (midiOutputSelector->getText());
  908. }
  909. }
  910. void AudioDeviceSelectorComponent::changeListenerCallback (void*)
  911. {
  912. if (deviceTypeDropDown != 0)
  913. {
  914. deviceTypeDropDown->setText (deviceManager.getCurrentAudioDeviceType(), false);
  915. }
  916. if (audioDeviceSettingsComp == 0
  917. || audioDeviceSettingsCompType != deviceManager.getCurrentAudioDeviceType())
  918. {
  919. audioDeviceSettingsCompType = deviceManager.getCurrentAudioDeviceType();
  920. deleteAndZero (audioDeviceSettingsComp);
  921. AudioIODeviceType* const type
  922. = deviceManager.getAvailableDeviceTypes() [deviceTypeDropDown == 0
  923. ? 0 : deviceTypeDropDown->getSelectedId() - 1];
  924. if (type != 0)
  925. {
  926. AudioIODeviceType::DeviceSetupDetails details;
  927. details.manager = &deviceManager;
  928. details.minNumInputChannels = minInputChannels;
  929. details.maxNumInputChannels = maxInputChannels;
  930. details.minNumOutputChannels = minOutputChannels;
  931. details.maxNumOutputChannels = maxOutputChannels;
  932. details.useStereoPairs = showChannelsAsStereoPairs;
  933. audioDeviceSettingsComp = new AudioDeviceSettingsPanel (type, details, hideAdvancedOptionsWithButton);
  934. if (audioDeviceSettingsComp != 0)
  935. {
  936. addAndMakeVisible (audioDeviceSettingsComp);
  937. audioDeviceSettingsComp->resized();
  938. }
  939. }
  940. }
  941. if (midiInputsList != 0)
  942. {
  943. midiInputsList->updateContent();
  944. midiInputsList->repaint();
  945. }
  946. if (midiOutputSelector != 0)
  947. {
  948. midiOutputSelector->clear();
  949. const StringArray midiOuts (MidiOutput::getDevices());
  950. midiOutputSelector->addItem (TRANS("<< none >>"), -1);
  951. midiOutputSelector->addSeparator();
  952. for (int i = 0; i < midiOuts.size(); ++i)
  953. midiOutputSelector->addItem (midiOuts[i], i + 1);
  954. int current = -1;
  955. if (deviceManager.getDefaultMidiOutput() != 0)
  956. current = 1 + midiOuts.indexOf (deviceManager.getDefaultMidiOutputName());
  957. midiOutputSelector->setSelectedId (current, true);
  958. }
  959. resized();
  960. }
  961. END_JUCE_NAMESPACE