From e8d221ccb363fd7ae26fe47c141f768cef6b3ddb Mon Sep 17 00:00:00 2001 From: Anthony Nicholls Date: Thu, 9 Nov 2023 15:21:57 +0000 Subject: [PATCH 01/82] CoreAudio: Fix a bug when retrieving the index of a device nested inside an AudioIODeviceCombiner --- .../native/juce_CoreAudio_mac.cpp | 62 ++++--------------- 1 file changed, 13 insertions(+), 49 deletions(-) diff --git a/modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp b/modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp index 87aec679e7e2..7124e408dcf6 100644 --- a/modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp +++ b/modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp @@ -1462,6 +1462,12 @@ class AudioIODeviceCombiner final : public AudioIODevice, auto getDeviceWrappers() { return std::array< DeviceWrapper*, 2> { { &inputWrapper, &outputWrapper } }; } auto getDeviceWrappers() const { return std::array { { &inputWrapper, &outputWrapper } }; } + int getIndexOfDevice (bool asInput) const + { + return asInput ? inputWrapper.getIndexOfDevice (true) + : outputWrapper.getIndexOfDevice (false); + } + StringArray getOutputChannelNames() override { return outputWrapper.getChannelNames(); } StringArray getInputChannelNames() override { return inputWrapper .getChannelNames(); } BigInteger getActiveOutputChannels() const override { return outputWrapper.getActiveChannels(); } @@ -1469,46 +1475,16 @@ class AudioIODeviceCombiner final : public AudioIODevice, Array getAvailableSampleRates() override { - Array commonRates; - bool first = true; - - for (auto& d : getDeviceWrappers()) - { - auto rates = d->getAvailableSampleRates(); - - if (first) - { - first = false; - commonRates = rates; - } - else - { - commonRates.removeValuesNotIn (rates); - } - } + auto commonRates = inputWrapper.getAvailableSampleRates(); + commonRates.removeValuesNotIn (outputWrapper.getAvailableSampleRates()); return commonRates; } Array getAvailableBufferSizes() override { - Array commonSizes; - bool first = true; - - for (auto& d : getDeviceWrappers()) - { - auto sizes = d->getAvailableBufferSizes(); - - if (first) - { - first = false; - commonSizes = sizes; - } - else - { - commonSizes.removeValuesNotIn (sizes); - } - } + auto commonSizes = inputWrapper.getAvailableBufferSizes(); + commonSizes.removeValuesNotIn (outputWrapper.getAvailableBufferSizes()); return commonSizes; } @@ -1520,22 +1496,12 @@ class AudioIODeviceCombiner final : public AudioIODevice, int getCurrentBitDepth() override { - int depth = 32; - - for (auto& d : getDeviceWrappers()) - depth = jmin (depth, d->getCurrentBitDepth()); - - return depth; + return jmin (32, inputWrapper.getCurrentBitDepth(), outputWrapper.getCurrentBitDepth()); } int getDefaultBufferSize() override { - int size = 0; - - for (auto& d : getDeviceWrappers()) - size = jmax (size, d->getDefaultBufferSize()); - - return size; + return jmax (0, inputWrapper.getDefaultBufferSize(), outputWrapper.getDefaultBufferSize()); } AudioWorkgroup getWorkgroup() const override @@ -2238,9 +2204,7 @@ class CoreAudioIODeviceType final : public AudioIODeviceType, return d->getIndexOfDevice (asInput); if (auto* d = dynamic_cast (device)) - for (auto* dev : d->getDeviceWrappers()) - if (const auto index = dev->getIndexOfDevice (asInput); index >= 0) - return index; + return d->getIndexOfDevice (asInput); return -1; } From da68fe2b60aa016a7451ace8fd90bcec7f9d261a Mon Sep 17 00:00:00 2001 From: Anthony Nicholls Date: Thu, 9 Nov 2023 16:02:08 +0000 Subject: [PATCH 02/82] AudioDeviceSelector: Auto resize when showing or hiding advanced settings --- .../gui/juce_AudioDeviceSelectorComponent.cpp | 6 ++++++ .../gui/juce_AudioDeviceSelectorComponent.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp b/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp index ae27633d7bcc..2d505b606d85 100644 --- a/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp +++ b/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp @@ -1104,6 +1104,12 @@ void AudioDeviceSelectorComponent::resized() setSize (getWidth(), r.getY()); } +void AudioDeviceSelectorComponent::childBoundsChanged (Component* child) +{ + if (child == audioDeviceSettingsComp.get()) + resized(); +} + void AudioDeviceSelectorComponent::updateDeviceType() { if (auto* type = deviceManager.getAvailableDeviceTypes() [deviceTypeDropDown->getSelectedId() - 1]) diff --git a/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.h b/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.h index 8ab2e07dc9e8..f9b6714cb027 100644 --- a/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.h +++ b/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.h @@ -89,6 +89,9 @@ class JUCE_API AudioDeviceSelectorComponent : public Component, /** @internal */ void resized() override; + /** @internal */ + void childBoundsChanged (Component* child) override; + private: //============================================================================== void handleBluetoothButton(); From 21df8603852fb9c5001c6da85c08e074133e6b3b Mon Sep 17 00:00:00 2001 From: Anthony Nicholls Date: Fri, 10 Nov 2023 12:11:38 +0000 Subject: [PATCH 03/82] AudioDeviceSelector: Correctly display when there is no MIDI output device selected --- .../gui/juce_AudioDeviceSelectorComponent.cpp | 93 ++++++++++++------- .../gui/juce_AudioDeviceSelectorComponent.h | 5 +- 2 files changed, 61 insertions(+), 37 deletions(-) diff --git a/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp b/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp index 2d505b606d85..6d964bb0ef16 100644 --- a/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp +++ b/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp @@ -207,6 +207,63 @@ struct AudioDeviceSetupDetails static String getNoDeviceString() { return "<< " + TRANS ("none") + " >>"; } +//============================================================================== +class AudioDeviceSelectorComponent::MidiOutputSelector final : public Component, + private ChangeListener +{ +public: + explicit MidiOutputSelector (AudioDeviceManager& dm) + : deviceManager (dm) + { + deviceManager.addChangeListener (this); + selector.onChange = [&] + { + const auto selectedId = selector.getSelectedId(); + jassert (selectedId != 0); + + const auto deviceId = selectedId == -1 + ? String{} + : MidiOutput::getAvailableDevices()[selectedId - 1].identifier; + deviceManager.setDefaultMidiOutputDevice (deviceId); + }; + + updateListOfDevices(); + addAndMakeVisible (selector); + } + + ~MidiOutputSelector() final + { + deviceManager.removeChangeListener (this); + } + + void resized() final { selector.setBounds (getLocalBounds()); } + +private: + void updateListOfDevices() + { + selector.clear(); + + const auto midiOutputs = MidiOutput::getAvailableDevices(); + + selector.addItem (getNoDeviceString(), -1); + selector.setSelectedId (-1, dontSendNotification); + selector.addSeparator(); + + for (auto [id, midiOutput] : enumerate (midiOutputs, 1)) + { + selector.addItem (midiOutput.name, id); + + if (midiOutput.identifier == deviceManager.getDefaultMidiOutputIdentifier()) + selector.setSelectedId (id, dontSendNotification); + } + } + + void changeListenerCallback (ChangeBroadcaster*) final { updateListOfDevices(); } + + ComboBox selector; + AudioDeviceManager& deviceManager; +}; + //============================================================================== class AudioDeviceSettingsPanel : public Component, private ChangeListener @@ -1036,9 +1093,8 @@ AudioDeviceSelectorComponent::AudioDeviceSelectorComponent (AudioDeviceManager& if (showMidiOutputSelector) { - midiOutputSelector = std::make_unique(); + midiOutputSelector = std::make_unique (deviceManager); addAndMakeVisible (midiOutputSelector.get()); - midiOutputSelector->onChange = [this] { updateMidiOutput(); }; midiOutputLabel = std::make_unique