Oh, dammit - the same thing happens in the demo app. Ok - it’s a bug in AudioDeviceSelectorComponent - here’s some new code for it:
[code]/*
This file is part of the JUCE library - "Jules’ Utility Class Extensions"
Copyright 2004-6 by Raw Material Software ltd.
JUCE can be redistributed and/or modified under the terms of the
GNU General Public License, as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any later version.
JUCE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JUCE; if not, visit www.gnu.org/licenses or write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
If you’d like to release a closed-source product which uses JUCE, commercial
licenses are also available: visit www.rawmaterialsoftware.com/juce for
more information.
==============================================================================
*/
BEGIN_JUCE_NAMESPACE
//==============================================================================
class MidiInputListBox : public SimpleListBox,
public SimpleListBoxModel
{
public:
//==============================================================================
MidiInputListBox (AudioDeviceManager& deviceManager_)
: SimpleListBox (T(“midi”), 0),
deviceManager (deviceManager_)
{
devices = MidiInput::getDevices();
setModel (this);
setOutlineColour (getLookAndFeel().comboBoxOutline, 1);
}
~MidiInputListBox()
{
}
int getNumRows()
{
return devices.size();
}
void paintListBoxItem (int row,
Graphics& g,
int width, int height,
bool rowIsSelected)
{
if (row >= 0 && row < devices.size())
{
if (rowIsSelected)
g.fillAll (getLookAndFeel().textEditorHighlight.withMultipliedAlpha (0.3f));
const String device (devices [row]);
const bool enabled = deviceManager.isMidiInputEnabled (device);
const int x = getTickX();
const int tickW = height - height / 4;
getLookAndFeel().drawTickBox (g, x - tickW, (height - tickW) / 2, tickW, tickW,
enabled, true, true, false);
g.setFont (height * 0.6f);
g.setColour (Colours::black.withAlpha (enabled ? 1.0f : 0.6f));
g.drawText (device, x, 0, width - x - 2, height, Justification::centredLeft, true);
}
}
void listBoxItemClicked (int row, const MouseEvent& e)
{
selectRow (row);
if (e.x < getTickX())
flipEnablement (row);
}
void listBoxItemDoubleClicked (int row, const MouseEvent&)
{
flipEnablement (row);
}
void paint (Graphics& g)
{
SimpleListBox::paint (g);
if (getNumRows() == 0)
{
g.setColour (Colours::grey);
g.setFont (13.0f);
g.drawText (TRANS("(no midi inputs available)"),
0, 0, getWidth(), getHeight() / 2, Justification::centred, true);
}
}
//==============================================================================
juce_UseDebuggingNewOperator
private:
AudioDeviceManager& deviceManager;
StringArray devices;
void flipEnablement (const int row)
{
if (row >= 0 && row < devices.size())
{
const String device (devices [row]);
deviceManager.setMidiInputEnabled (device, ! deviceManager.isMidiInputEnabled (device));
}
}
int getTickX() const throw()
{
return getRowHeight() + 5;
}
MidiInputListBox (const MidiInputListBox&);
const MidiInputListBox& operator= (const MidiInputListBox&);
};
//==============================================================================
AudioDeviceSelectorComponent::AudioDeviceSelectorComponent (AudioDeviceManager& deviceManager_,
const int minInputChannels_,
const int maxInputChannels_,
const int minOutputChannels_,
const int maxOutputChannels_,
const bool showMidiOptions_)
: deviceManager (deviceManager_),
minOutputChannels (minOutputChannels_),
maxOutputChannels (maxOutputChannels_),
minInputChannels (minInputChannels_),
maxInputChannels (maxInputChannels_),
showMidiOptions (showMidiOptions_),
sampleRateDropDown (0),
inputChansDropDown (0),
inputsLabel (0),
outputChansDropDown (0),
outputsLabel (0),
sampleRateLabel (0),
bufferSizeDropDown (0),
bufferSizeLabel (0),
launchUIButton (0)
{
jassert (minOutputChannels >= 0 && minOutputChannels <= maxOutputChannels);
jassert (minInputChannels >= 0 && minInputChannels <= maxInputChannels);
audioDeviceDropDown = new ComboBox (T("device"));
deviceManager_.addDeviceNamesToComboBox (*audioDeviceDropDown);
audioDeviceDropDown->setSelectedId (-1);
if (deviceManager_.getCurrentAudioDeviceName().isNotEmpty())
audioDeviceDropDown->setText (deviceManager_.getCurrentAudioDeviceName());
audioDeviceDropDown->addListener (this);
addAndMakeVisible (audioDeviceDropDown);
Label* label = new Label (T("l1"), TRANS ("audio device:"));
label->attachToComponent (audioDeviceDropDown, true);
if (showMidiOptions)
{
addAndMakeVisible (midiInputsList = new MidiInputListBox (deviceManager));
midiInputsLabel = new Label (T("lm"), TRANS ("active midi inputs:"));
midiInputsLabel->setJustificationType (Justification::topRight);
midiInputsLabel->attachToComponent (midiInputsList, true);
}
else
{
midiInputsList = 0;
midiInputsLabel = 0;
}
deviceManager_.addChangeListener (this);
changeListenerCallback (0);
}
AudioDeviceSelectorComponent::~AudioDeviceSelectorComponent()
{
deviceManager.removeChangeListener (this);
deleteAllChildren();
}
void AudioDeviceSelectorComponent::resized()
{
int lx = proportionOfWidth (0.35f);
int w = proportionOfWidth (0.55f);
int y = 15;
const int h = 24;
const int dh = 30;
audioDeviceDropDown->setBounds (lx, y, w, h);
y += dh;
if (sampleRateDropDown != 0)
{
sampleRateDropDown->setBounds (lx, y, w, h);
y += dh;
}
if (bufferSizeDropDown != 0)
{
bufferSizeDropDown->setBounds (lx, y, w, h);
y += dh;
}
if (outputChansDropDown != 0)
{
outputChansDropDown->setBounds (lx, y, w, h);
y += dh;
}
if (inputChansDropDown != 0)
{
inputChansDropDown->setBounds (lx, y, w, h);
y += dh;
}
if (launchUIButton != 0)
{
launchUIButton->setBounds (lx, y, 150, h);
((TextButton*) launchUIButton)->changeWidthToFitText();
y += dh;
}
if (midiInputsList != 0)
{
midiInputsList->setBounds (lx, y, w, jmin (h * 4, getHeight() - y - 2));
y += dh;
}
}
void AudioDeviceSelectorComponent::buttonClicked (Button*)
{
AudioIODevice* const device = deviceManager.getCurrentAudioDevice();
if (device != 0 && device->hasControlPanel())
{
const String lastDevice (device->getName());
if (device->showControlPanel())
{
deviceManager.setAudioDevice (String::empty);
deviceManager.setAudioDevice (lastDevice);
}
getTopLevelComponent()->toFront (true);
}
}
void AudioDeviceSelectorComponent::comboBoxChanged (ComboBox* comboBoxThatHasChanged)
{
AudioIODevice* const audioDevice = deviceManager.getCurrentAudioDevice();
if (comboBoxThatHasChanged == audioDeviceDropDown)
{
if (audioDeviceDropDown->getSelectedId() < 0)
{
deviceManager.setAudioDevice (String::empty);
}
else
{
String error (deviceManager.setAudioDevice (audioDeviceDropDown->getText()));
if (error.isNotEmpty())
{
AlertWindow::showMessageBox (AlertWindow::WarningIcon,
T("Error while opening \"")
+ audioDeviceDropDown->getText()
+ T("\""),
error);
}
}
if (deviceManager.getCurrentAudioDeviceName().isNotEmpty())
audioDeviceDropDown->setText (deviceManager.getCurrentAudioDeviceName());
else
audioDeviceDropDown->setSelectedId (-1);
}
else if (audioDevice != 0)
{
if (bufferSizeDropDown != 0 && comboBoxThatHasChanged == bufferSizeDropDown)
{
if (bufferSizeDropDown->getSelectedId() > 0)
deviceManager.setAudioDevice (audioDevice->getName(),
bufferSizeDropDown->getSelectedId(),
audioDevice->getCurrentSampleRate());
}
else if (sampleRateDropDown != 0 && comboBoxThatHasChanged == sampleRateDropDown)
{
if (sampleRateDropDown->getSelectedId() > 0)
deviceManager.setAudioDevice (audioDevice->getName(),
audioDevice->getCurrentBufferSizeSamples(),
sampleRateDropDown->getSelectedId());
}
else if (outputChansDropDown != 0 && comboBoxThatHasChanged == outputChansDropDown)
{
const int bit = (outputChansDropDown->getSelectedId() - 1) * maxOutputChannels;
BitArray chans;
for (int i = 0; i < maxOutputChannels; ++i)
chans.setBit (bit + i);
deviceManager.setAudioDevice (audioDevice->getName(),
audioDevice->getCurrentBufferSizeSamples(),
audioDevice->getCurrentSampleRate(),
0, &chans);
}
else if (inputChansDropDown != 0 && comboBoxThatHasChanged == inputChansDropDown)
{
const int bit = (inputChansDropDown->getSelectedId() - 1) * maxInputChannels;
BitArray chans;
for (int i = 0; i < maxInputChannels; ++i)
chans.setBit (bit + i);
deviceManager.setAudioDevice (audioDevice->getName(),
audioDevice->getCurrentBufferSizeSamples(),
audioDevice->getCurrentSampleRate(),
&chans, 0);
}
}
}
void AudioDeviceSelectorComponent::changeListenerCallback (void*)
{
deleteAndZero (sampleRateDropDown);
deleteAndZero (inputChansDropDown);
deleteAndZero (inputsLabel);
deleteAndZero (outputChansDropDown);
deleteAndZero (outputsLabel);
deleteAndZero (sampleRateLabel);
deleteAndZero (bufferSizeDropDown);
deleteAndZero (bufferSizeLabel);
deleteAndZero (launchUIButton);
AudioIODevice* const currentDevice = deviceManager.getCurrentAudioDevice();
if (currentDevice != 0)
{
// sample rate
addAndMakeVisible (sampleRateDropDown = new ComboBox (T("samplerate")));
sampleRateLabel = new Label (T("l2"), TRANS ("sample rate:"));
sampleRateLabel->attachToComponent (sampleRateDropDown, true);
const int numRates = currentDevice->getNumSampleRates();
int i;
for (i = 0; i < numRates; ++i)
{
const int rate = roundDoubleToInt (currentDevice->getSampleRate (i));
sampleRateDropDown->addItem (String (rate) + T(" Hz"), rate);
}
const double currentRate = currentDevice->getCurrentSampleRate();
sampleRateDropDown->setSelectedId (roundDoubleToInt (currentRate), true);
sampleRateDropDown->addListener (this);
// buffer size
addAndMakeVisible (bufferSizeDropDown = new ComboBox (T("buffersize")));
bufferSizeLabel = new Label (T("l2"), TRANS ("audio buffer size:"));
bufferSizeLabel->attachToComponent (bufferSizeDropDown, true);
const int numBufferSizes = currentDevice->getNumBufferSizesAvailable();
for (i = 0; i < numBufferSizes; ++i)
{
const int bs = currentDevice->getBufferSizeSamples (i);
bufferSizeDropDown->addItem (String (bs)
+ T(" samples (")
+ String (bs * 1000.0 / currentRate, 1)
+ T(" ms)"),
bs);
}
bufferSizeDropDown->setSelectedId (currentDevice->getCurrentBufferSizeSamples(), true);
bufferSizeDropDown->addListener (this);
// output chans
if (maxOutputChannels > 0)
{
addAndMakeVisible (outputChansDropDown = new ComboBox (T("outs")));
outputsLabel = new Label (T("l3"), TRANS ("output channels:"));
outputsLabel->attachToComponent (outputChansDropDown, true);
StringArray outs (currentDevice->getOutputChannelNames());
if (outs.size() == 0)
{
outputChansDropDown->addItem (TRANS ("<< none available >>"), -1);
}
else
{
if (minOutputChannels == 0)
{
outputChansDropDown->addItem (T("<< none >>"), -1);
outputChansDropDown->addSeparator();
}
for (int i = 0; i < outs.size() / maxOutputChannels; ++i)
{
String name;
for (int j = 0; j < maxOutputChannels; ++j)
{
name += outs [i * maxOutputChannels + j];
if (j < maxOutputChannels - 1)
name += T(" & ");
}
outputChansDropDown->addItem (name, i + 1);
}
}
const int lowestBit = deviceManager.getOutputChannels().findNextSetBit (0);
outputChansDropDown->setSelectedId ((lowestBit < 0) ? -1 : lowestBit / maxOutputChannels + 1, true);
outputChansDropDown->addListener (this);
}
// input chans
if (maxInputChannels > 0)
{
addAndMakeVisible (inputChansDropDown = new ComboBox (T("ins")));
inputsLabel = new Label (T("l4"), TRANS("input channels:"));
inputsLabel->attachToComponent (inputChansDropDown, true);
StringArray ins (currentDevice->getInputChannelNames());
if (ins.size() == 0)
{
inputChansDropDown->addItem (T("<< none available >>"), -1);
}
else
{
if (minInputChannels == 0)
{
inputChansDropDown->addItem (T("<< none >>"), -1);
inputChansDropDown->addSeparator();
}
for (int i = 0; i < ins.size() / maxInputChannels; ++i)
{
String name;
for (int j = 0; j < maxInputChannels; ++j)
{
name += ins [i * maxInputChannels + j];
if (j < maxInputChannels - 1)
name += T(" & ");
}
inputChansDropDown->addItem (name, i + 1);
}
}
const int lowestBit = deviceManager.getInputChannels().findNextSetBit (0);
inputChansDropDown->setSelectedId ((lowestBit < 0) ? -1 : lowestBit / maxInputChannels + 1, true);
inputChansDropDown->addListener (this);
}
if (currentDevice->hasControlPanel())
{
addAndMakeVisible (launchUIButton = new TextButton (T("show this device's control panel"),
T("opens the device's own control panel")));
launchUIButton->addButtonListener (this);
}
if (midiInputsList != 0)
midiInputsList->updateContent();
}
else
{
audioDeviceDropDown->setSelectedId (-1);
}
resized();
}
END_JUCE_NAMESPACE
[/code]
Silly mistake, really. I’ll patch the new version to fix this, I think.