mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-22 01:34:21 +00:00
This commit is contained in:
parent
ad56914057
commit
3b59053b2c
15 changed files with 4828 additions and 1574 deletions
|
|
@ -78,7 +78,7 @@ static void getDeviceSampleRates (snd_pcm_t* handle, Array <int>& rates)
|
|||
if (snd_pcm_hw_params_any (handle, hwParams) >= 0
|
||||
&& snd_pcm_hw_params_test_rate (handle, hwParams, ratesToTry[i], 0) == 0)
|
||||
{
|
||||
rates.add (ratesToTry[i]);
|
||||
rates.addIfNotAlreadyThere (ratesToTry[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -102,6 +102,9 @@ static void getDeviceProperties (const String& id,
|
|||
unsigned int& maxChansIn,
|
||||
Array <int>& rates)
|
||||
{
|
||||
if (id.isEmpty())
|
||||
return;
|
||||
|
||||
snd_ctl_t* handle;
|
||||
|
||||
if (snd_ctl_open (&handle, id.upToLastOccurrenceOf (T(","), false, false), SND_CTL_NONBLOCK) >= 0)
|
||||
|
|
@ -149,7 +152,7 @@ static void getDeviceProperties (const String& id,
|
|||
class ALSADevice
|
||||
{
|
||||
public:
|
||||
ALSADevice (const String& deviceName,
|
||||
ALSADevice (const String& id,
|
||||
const bool forInput)
|
||||
: handle (0),
|
||||
bitDepth (16),
|
||||
|
|
@ -157,7 +160,7 @@ public:
|
|||
isInput (forInput),
|
||||
sampleFormat (AudioDataConverters::int16LE)
|
||||
{
|
||||
failed (snd_pcm_open (&handle, deviceName,
|
||||
failed (snd_pcm_open (&handle, id,
|
||||
forInput ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
|
||||
SND_PCM_ASYNC));
|
||||
}
|
||||
|
|
@ -364,12 +367,14 @@ private:
|
|||
class ALSAThread : public Thread
|
||||
{
|
||||
public:
|
||||
ALSAThread (const String& deviceName_)
|
||||
ALSAThread (const String& inputId_,
|
||||
const String& outputId_)
|
||||
: Thread ("Juce ALSA"),
|
||||
sampleRate (0),
|
||||
bufferSize (0),
|
||||
callback (0),
|
||||
deviceName (deviceName_),
|
||||
inputId (inputId_),
|
||||
outputId (outputId_),
|
||||
outputDevice (0),
|
||||
inputDevice (0),
|
||||
numCallbacks (0),
|
||||
|
|
@ -402,16 +407,9 @@ public:
|
|||
currentInputChans.clear();
|
||||
currentOutputChans.clear();
|
||||
|
||||
numChannelsRunning = jmax (inputChannels.getHighestBit(),
|
||||
outputChannels.getHighestBit()) + 1;
|
||||
|
||||
numChannelsRunning = jmin (maxNumChans, jlimit ((int) minChansIn,
|
||||
(int) maxChansIn,
|
||||
numChannelsRunning));
|
||||
|
||||
if (inputChannels.getHighestBit() >= 0)
|
||||
{
|
||||
for (int i = 0; i < numChannelsRunning; ++i)
|
||||
for (int i = 0; i <= inputChannels.getHighestBit(); ++i)
|
||||
{
|
||||
inputChannelData [i] = (float*) juce_calloc (sizeof (float) * bufferSize);
|
||||
|
||||
|
|
@ -425,7 +423,7 @@ public:
|
|||
|
||||
if (outputChannels.getHighestBit() >= 0)
|
||||
{
|
||||
for (int i = 0; i < numChannelsRunning; ++i)
|
||||
for (int i = 0; i <= outputChannels.getHighestBit(); ++i)
|
||||
{
|
||||
outputChannelData [i] = (float*) juce_calloc (sizeof (float) * bufferSize);
|
||||
|
||||
|
|
@ -437,9 +435,9 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
if (totalNumOutputChannels > 0)
|
||||
if (totalNumOutputChannels > 0 && outputId.isNotEmpty())
|
||||
{
|
||||
outputDevice = new ALSADevice (deviceName, false);
|
||||
outputDevice = new ALSADevice (outputId, false);
|
||||
|
||||
if (outputDevice->error.isNotEmpty())
|
||||
{
|
||||
|
|
@ -448,7 +446,9 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
if (! outputDevice->setParameters ((unsigned int) sampleRate, numChannelsRunning, bufferSize))
|
||||
if (! outputDevice->setParameters ((unsigned int) sampleRate,
|
||||
currentOutputChans.getHighestBit() + 1,
|
||||
bufferSize))
|
||||
{
|
||||
error = outputDevice->error;
|
||||
deleteAndZero (outputDevice);
|
||||
|
|
@ -456,9 +456,9 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
if (totalNumInputChannels > 0)
|
||||
if (totalNumInputChannels > 0 && inputId.isNotEmpty())
|
||||
{
|
||||
inputDevice = new ALSADevice (deviceName, true);
|
||||
inputDevice = new ALSADevice (inputId, true);
|
||||
|
||||
if (inputDevice->error.isNotEmpty())
|
||||
{
|
||||
|
|
@ -467,7 +467,9 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
if (! inputDevice->setParameters ((unsigned int) sampleRate, numChannelsRunning, bufferSize))
|
||||
if (! inputDevice->setParameters ((unsigned int) sampleRate,
|
||||
currentInputChans.getHighestBit() + 1,
|
||||
bufferSize))
|
||||
{
|
||||
error = inputDevice->error;
|
||||
deleteAndZero (inputDevice);
|
||||
|
|
@ -527,7 +529,6 @@ public:
|
|||
zeromem (inputChannelDataForCallback, sizeof (inputChannelDataForCallback));
|
||||
totalNumOutputChannels = 0;
|
||||
totalNumInputChannels = 0;
|
||||
numChannelsRunning = 0;
|
||||
|
||||
numCallbacks = 0;
|
||||
}
|
||||
|
|
@ -544,8 +545,6 @@ public:
|
|||
{
|
||||
if (inputDevice != 0)
|
||||
{
|
||||
jassert (numChannelsRunning >= inputDevice->numChannelsRunning);
|
||||
|
||||
if (! inputDevice->read (inputChannelData, bufferSize))
|
||||
{
|
||||
DBG ("ALSA: read failure");
|
||||
|
|
@ -584,7 +583,6 @@ public:
|
|||
|
||||
failed (snd_pcm_avail_update (outputDevice->handle));
|
||||
|
||||
jassert (numChannelsRunning >= outputDevice->numChannelsRunning);
|
||||
if (! outputDevice->write (outputChannelData, bufferSize))
|
||||
{
|
||||
DBG ("ALSA: write failure");
|
||||
|
|
@ -619,7 +617,7 @@ public:
|
|||
|
||||
private:
|
||||
//==============================================================================
|
||||
const String deviceName;
|
||||
const String inputId, outputId;
|
||||
ALSADevice* outputDevice;
|
||||
ALSADevice* inputDevice;
|
||||
int numCallbacks;
|
||||
|
|
@ -632,7 +630,6 @@ private:
|
|||
float* inputChannelData [maxNumChans];
|
||||
float* inputChannelDataForCallback [maxNumChans];
|
||||
int totalNumOutputChannels;
|
||||
int numChannelsRunning;
|
||||
|
||||
unsigned int minChansOut, maxChansOut;
|
||||
unsigned int minChansIn, maxChansIn;
|
||||
|
|
@ -656,8 +653,10 @@ private:
|
|||
maxChansOut = 0;
|
||||
minChansIn = 0;
|
||||
maxChansIn = 0;
|
||||
unsigned int dummy = 0;
|
||||
|
||||
getDeviceProperties (deviceName, minChansOut, maxChansOut, minChansIn, maxChansIn, sampleRates);
|
||||
getDeviceProperties (inputId, dummy, dummy, minChansIn, maxChansIn, sampleRates);
|
||||
getDeviceProperties (outputId, minChansOut, maxChansOut, dummy, dummy, sampleRates);
|
||||
|
||||
unsigned int i;
|
||||
for (i = 0; i < maxChansOut; ++i)
|
||||
|
|
@ -674,13 +673,16 @@ class ALSAAudioIODevice : public AudioIODevice
|
|||
{
|
||||
public:
|
||||
ALSAAudioIODevice (const String& deviceName,
|
||||
const String& deviceId)
|
||||
const String& inputId_,
|
||||
const String& outputId_)
|
||||
: AudioIODevice (deviceName, T("ALSA")),
|
||||
inputId (inputId_),
|
||||
outputId (outputId_),
|
||||
isOpen_ (false),
|
||||
isStarted (false),
|
||||
internal (0)
|
||||
{
|
||||
internal = new ALSAThread (deviceId);
|
||||
internal = new ALSAThread (inputId, outputId);
|
||||
}
|
||||
|
||||
~ALSAAudioIODevice()
|
||||
|
|
@ -839,6 +841,8 @@ public:
|
|||
return internal->error;
|
||||
}
|
||||
|
||||
String inputId, outputId;
|
||||
|
||||
private:
|
||||
bool isOpen_, isStarted;
|
||||
ALSAThread* internal;
|
||||
|
|
@ -863,10 +867,14 @@ public:
|
|||
//==============================================================================
|
||||
void scanForDevices()
|
||||
{
|
||||
hasScanned = true;
|
||||
if (hasScanned)
|
||||
return;
|
||||
|
||||
names.clear();
|
||||
ids.clear();
|
||||
hasScanned = true;
|
||||
inputNames.clear();
|
||||
inputIds.clear();
|
||||
outputNames.clear();
|
||||
outputIds.clear();
|
||||
|
||||
snd_ctl_t* handle;
|
||||
snd_ctl_card_info_t* info;
|
||||
|
|
@ -874,7 +882,7 @@ public:
|
|||
|
||||
int cardNum = -1;
|
||||
|
||||
while (ids.size() <= 24)
|
||||
while (outputIds.size() + inputIds.size() <= 32)
|
||||
{
|
||||
snd_card_next (&cardNum);
|
||||
|
||||
|
|
@ -900,18 +908,26 @@ public:
|
|||
String id, name;
|
||||
id << "hw:" << cardId << ',' << device;
|
||||
|
||||
if (testDevice (id))
|
||||
bool isInput, isOutput;
|
||||
|
||||
if (testDevice (id, isInput, isOutput))
|
||||
{
|
||||
name << snd_ctl_card_info_get_name (info);
|
||||
|
||||
if (name.isEmpty())
|
||||
name = id;
|
||||
|
||||
if (device > 0)
|
||||
name << " (" << (device + 1) << ')';
|
||||
if (isInput)
|
||||
{
|
||||
inputNames.add (name);
|
||||
inputIds.add (id);
|
||||
}
|
||||
|
||||
ids.add (id);
|
||||
names.add (name);
|
||||
if (isOutput)
|
||||
{
|
||||
outputNames.add (name);
|
||||
outputIds.add (id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -919,35 +935,54 @@ public:
|
|||
snd_ctl_close (handle);
|
||||
}
|
||||
}
|
||||
|
||||
inputNames.appendNumbersToDuplicates (false, true);
|
||||
outputNames.appendNumbersToDuplicates (false, true);
|
||||
}
|
||||
|
||||
const StringArray getDeviceNames (const bool /*preferInputNames*/) const
|
||||
const StringArray getDeviceNames (const bool wantInputNames) const
|
||||
{
|
||||
jassert (hasScanned); // need to call scanForDevices() before doing this
|
||||
|
||||
StringArray namesCopy (names);
|
||||
namesCopy.removeDuplicates (true);
|
||||
|
||||
return namesCopy;
|
||||
return wantInputNames ? inputNames : outputNames;
|
||||
}
|
||||
|
||||
const String getDefaultDeviceName (const bool /*preferInputNames*/,
|
||||
const int /*numInputChannelsNeeded*/,
|
||||
const int /*numOutputChannelsNeeded*/) const
|
||||
int getDefaultDeviceIndex (const bool forInput) const
|
||||
{
|
||||
jassert (hasScanned); // need to call scanForDevices() before doing this
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool hasSeparateInputsAndOutputs() const { return true; }
|
||||
|
||||
int getIndexOfDevice (AudioIODevice* device, const bool asInput) const
|
||||
{
|
||||
jassert (hasScanned); // need to call scanForDevices() before doing this
|
||||
|
||||
return names[0];
|
||||
ALSAAudioIODevice* const d = dynamic_cast <ALSAAudioIODevice*> (device);
|
||||
if (d == 0)
|
||||
return -1;
|
||||
|
||||
return asInput ? inputIds.indexOf (d->inputId)
|
||||
: outputIds.indexOf (d->outputId);
|
||||
}
|
||||
|
||||
AudioIODevice* createDevice (const String& deviceName)
|
||||
AudioIODevice* createDevice (const String& outputDeviceName,
|
||||
const String& inputDeviceName)
|
||||
{
|
||||
jassert (hasScanned); // need to call scanForDevices() before doing this
|
||||
|
||||
const int index = names.indexOf (deviceName);
|
||||
const int inputIndex = inputNames.indexOf (inputDeviceName);
|
||||
const int outputIndex = outputNames.indexOf (outputDeviceName);
|
||||
|
||||
String deviceName (outputDeviceName);
|
||||
if (deviceName.isEmpty())
|
||||
deviceName = inputDeviceName;
|
||||
|
||||
if (index >= 0)
|
||||
return new ALSAAudioIODevice (deviceName, ids [index]);
|
||||
return new ALSAAudioIODevice (deviceName,
|
||||
inputIds [inputIndex],
|
||||
outputIds [outputIndex]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -956,10 +991,10 @@ public:
|
|||
juce_UseDebuggingNewOperator
|
||||
|
||||
private:
|
||||
StringArray names, ids;
|
||||
StringArray inputNames, outputNames, inputIds, outputIds;
|
||||
bool hasScanned;
|
||||
|
||||
static bool testDevice (const String& id)
|
||||
static bool testDevice (const String& id, bool& isInput, bool& isOutput)
|
||||
{
|
||||
unsigned int minChansOut = 0, maxChansOut = 0;
|
||||
unsigned int minChansIn = 0, maxChansIn = 0;
|
||||
|
|
@ -972,7 +1007,10 @@ private:
|
|||
+ T(" ins=") + String ((int) minChansIn) + T("-") + String ((int) maxChansIn)
|
||||
+ T(" rates=") + String (rates.size()));
|
||||
|
||||
return (maxChansOut > 0 || maxChansIn > 0) && rates.size() > 0;
|
||||
isInput = maxChansIn > 0;
|
||||
isOutput = maxChansOut > 0;
|
||||
|
||||
return (isInput || isOutput) && rates.size() > 0;
|
||||
}
|
||||
|
||||
ALSAAudioIODeviceType (const ALSAAudioIODeviceType&);
|
||||
|
|
|
|||
|
|
@ -40,6 +40,11 @@ BEGIN_JUCE_NAMESPACE
|
|||
#include "../../../src/juce_core/threads/juce_ScopedLock.h"
|
||||
#include "../../../src/juce_core/threads/juce_Thread.h"
|
||||
#include "../../../src/juce_core/text/juce_LocalisedStrings.h"
|
||||
#include "../../../src/juce_appframework/gui/components/buttons/juce_TextButton.h"
|
||||
#include "../../../src/juce_appframework/gui/components/lookandfeel/juce_LookAndFeel.h"
|
||||
#include "../../../src/juce_appframework/gui/components/controls/juce_ComboBox.h"
|
||||
#include "../../../src/juce_appframework/gui/components/special/juce_AudioDeviceSelectorComponent.h"
|
||||
#include "../../../src/juce_appframework/gui/components/windows/juce_AlertWindow.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -613,7 +618,7 @@ public:
|
|||
for (i = numOutputChans; --i >= 0;)
|
||||
{
|
||||
const CallbackDetailsForChannel& info = outputChannelInfo[i];
|
||||
const float* src = tempOutputBuffers [info.sourceChannelNum];
|
||||
const float* src = tempOutputBuffers [i];
|
||||
float* dest = ((float*) outOutputData->mBuffers[info.streamNum].mData)
|
||||
+ info.dataOffsetSamples;
|
||||
const int stride = info.dataStrideSamples;
|
||||
|
|
@ -833,31 +838,52 @@ class CoreAudioIODevice : public AudioIODevice
|
|||
{
|
||||
public:
|
||||
CoreAudioIODevice (const String& deviceName,
|
||||
AudioDeviceID deviceId1)
|
||||
AudioDeviceID inputDeviceId,
|
||||
const int inputIndex_,
|
||||
AudioDeviceID outputDeviceId,
|
||||
const int outputIndex_)
|
||||
: AudioIODevice (deviceName, "CoreAudio"),
|
||||
inputIndex (inputIndex_),
|
||||
outputIndex (outputIndex_),
|
||||
isOpen_ (false),
|
||||
isStarted (false)
|
||||
{
|
||||
internal = 0;
|
||||
CoreAudioInternal* device = 0;
|
||||
|
||||
CoreAudioInternal* device = new CoreAudioInternal (deviceId1);
|
||||
lastError = device->error;
|
||||
|
||||
if (lastError.isNotEmpty())
|
||||
if (outputDeviceId == 0 || outputDeviceId == inputDeviceId)
|
||||
{
|
||||
deleteAndZero (device);
|
||||
jassert (inputDeviceId != 0);
|
||||
|
||||
device = new CoreAudioInternal (inputDeviceId);
|
||||
lastError = device->error;
|
||||
|
||||
if (lastError.isNotEmpty())
|
||||
deleteAndZero (device);
|
||||
}
|
||||
else
|
||||
{
|
||||
CoreAudioInternal* secondDevice = device->getRelatedDevice();
|
||||
device = new CoreAudioInternal (outputDeviceId);
|
||||
lastError = device->error;
|
||||
|
||||
if (secondDevice != 0)
|
||||
if (lastError.isNotEmpty())
|
||||
{
|
||||
if (device->inChanNames.size() > secondDevice->inChanNames.size())
|
||||
swapVariables (device, secondDevice);
|
||||
deleteAndZero (device);
|
||||
}
|
||||
else if (inputDeviceId != 0)
|
||||
{
|
||||
CoreAudioInternal* secondDevice = new CoreAudioInternal (inputDeviceId);
|
||||
lastError = device->error;
|
||||
|
||||
device->inputDevice = secondDevice;
|
||||
secondDevice->isSlaveDevice = true;
|
||||
if (lastError.isNotEmpty())
|
||||
{
|
||||
delete secondDevice;
|
||||
}
|
||||
else
|
||||
{
|
||||
device->inputDevice = secondDevice;
|
||||
secondDevice->isSlaveDevice = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1035,6 +1061,8 @@ public:
|
|||
return lastError;
|
||||
}
|
||||
|
||||
int inputIndex, outputIndex;
|
||||
|
||||
juce_UseDebuggingNewOperator
|
||||
|
||||
private:
|
||||
|
|
@ -1065,6 +1093,326 @@ private:
|
|||
const CoreAudioIODevice& operator= (const CoreAudioIODevice&);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class CoreAudioDevicePanel : public Component,
|
||||
public ComboBoxListener,
|
||||
public ChangeListener,
|
||||
public ButtonListener
|
||||
{
|
||||
public:
|
||||
CoreAudioDevicePanel (AudioIODeviceType* type_,
|
||||
AudioIODeviceType::DeviceSetupDetails& setup_)
|
||||
: type (type_),
|
||||
setup (setup_)
|
||||
{
|
||||
sampleRateDropDown = 0;
|
||||
sampleRateLabel = 0;
|
||||
bufferSizeDropDown = 0;
|
||||
bufferSizeLabel = 0;
|
||||
outputDeviceDropDown = 0;
|
||||
outputDeviceLabel = 0;
|
||||
inputDeviceDropDown = 0;
|
||||
inputDeviceLabel = 0;
|
||||
testButton = 0;
|
||||
inputLevelMeter = 0;
|
||||
|
||||
type->scanForDevices();
|
||||
|
||||
if (setup.maxNumOutputChannels > 0)
|
||||
{
|
||||
outputDeviceDropDown = new ComboBox (String::empty);
|
||||
addNamesToDeviceBox (*outputDeviceDropDown, false);
|
||||
outputDeviceDropDown->addListener (this);
|
||||
addAndMakeVisible (outputDeviceDropDown);
|
||||
|
||||
outputDeviceLabel = new Label (String::empty, TRANS ("output:"));
|
||||
outputDeviceLabel->attachToComponent (outputDeviceDropDown, true);
|
||||
|
||||
addAndMakeVisible (testButton = new TextButton (TRANS ("Test")));
|
||||
testButton->addButtonListener (this);
|
||||
}
|
||||
|
||||
if (setup.maxNumInputChannels > 0)
|
||||
{
|
||||
inputDeviceDropDown = new ComboBox (String::empty);
|
||||
addNamesToDeviceBox (*inputDeviceDropDown, true);
|
||||
inputDeviceDropDown->addListener (this);
|
||||
addAndMakeVisible (inputDeviceDropDown);
|
||||
|
||||
inputDeviceLabel = new Label (String::empty, TRANS ("input:"));
|
||||
inputDeviceLabel->attachToComponent (inputDeviceDropDown, true);
|
||||
|
||||
addAndMakeVisible (inputLevelMeter = AudioDeviceSelectorComponent::createSimpleLevelMeterComponent (setup_.manager));
|
||||
}
|
||||
|
||||
setup.manager->addChangeListener (this);
|
||||
changeListenerCallback (0);
|
||||
}
|
||||
|
||||
~CoreAudioDevicePanel()
|
||||
{
|
||||
setup.manager->removeChangeListener (this);
|
||||
|
||||
deleteAndZero (outputDeviceLabel);
|
||||
deleteAndZero (inputDeviceLabel);
|
||||
deleteAndZero (sampleRateLabel);
|
||||
deleteAndZero (bufferSizeLabel);
|
||||
deleteAllChildren();
|
||||
}
|
||||
|
||||
void resized()
|
||||
{
|
||||
const int lx = proportionOfWidth (0.35f);
|
||||
const int w = proportionOfWidth (0.5f);
|
||||
const int h = 24;
|
||||
const int space = 6;
|
||||
const int dh = h + space;
|
||||
int y = 0;
|
||||
|
||||
if (outputDeviceDropDown != 0)
|
||||
{
|
||||
outputDeviceDropDown->setBounds (lx, y, w, h);
|
||||
testButton->setBounds (outputDeviceDropDown->getRight() + 8,
|
||||
outputDeviceDropDown->getY(),
|
||||
getWidth() - outputDeviceDropDown->getRight() - 10,
|
||||
h);
|
||||
y += dh;
|
||||
}
|
||||
|
||||
if (inputDeviceDropDown != 0)
|
||||
{
|
||||
inputDeviceDropDown->setBounds (lx, y, w, h);
|
||||
|
||||
inputLevelMeter->setBounds (inputDeviceDropDown->getRight() + 8,
|
||||
inputDeviceDropDown->getY(),
|
||||
getWidth() - inputDeviceDropDown->getRight() - 10,
|
||||
h);
|
||||
y += dh;
|
||||
}
|
||||
|
||||
y += space * 2;
|
||||
|
||||
if (sampleRateDropDown != 0)
|
||||
{
|
||||
sampleRateDropDown->setBounds (lx, y, w, h);
|
||||
y += dh;
|
||||
}
|
||||
|
||||
if (bufferSizeDropDown != 0)
|
||||
{
|
||||
bufferSizeDropDown->setBounds (lx, y, w, h);
|
||||
y += dh;
|
||||
}
|
||||
}
|
||||
|
||||
void comboBoxChanged (ComboBox* comboBoxThatHasChanged)
|
||||
{
|
||||
if (comboBoxThatHasChanged == 0)
|
||||
return;
|
||||
|
||||
AudioDeviceManager::AudioDeviceSetup config;
|
||||
setup.manager->getAudioDeviceSetup (config);
|
||||
String error;
|
||||
|
||||
if (comboBoxThatHasChanged == outputDeviceDropDown
|
||||
|| comboBoxThatHasChanged == inputDeviceDropDown)
|
||||
{
|
||||
config.outputDeviceName = outputDeviceDropDown->getSelectedId() < 0 ? String::empty
|
||||
: outputDeviceDropDown->getText();
|
||||
config.inputDeviceName = inputDeviceDropDown->getSelectedId() < 0 ? String::empty
|
||||
: inputDeviceDropDown->getText();
|
||||
|
||||
if (comboBoxThatHasChanged == inputDeviceDropDown)
|
||||
config.useDefaultInputChannels = true;
|
||||
else
|
||||
config.useDefaultOutputChannels = true;
|
||||
|
||||
error = setup.manager->setAudioDeviceSetup (config, true);
|
||||
|
||||
showCorrectDeviceName (inputDeviceDropDown, true);
|
||||
showCorrectDeviceName (outputDeviceDropDown, false);
|
||||
}
|
||||
else if (comboBoxThatHasChanged == sampleRateDropDown)
|
||||
{
|
||||
if (sampleRateDropDown->getSelectedId() > 0)
|
||||
{
|
||||
config.sampleRate = sampleRateDropDown->getSelectedId();
|
||||
error = setup.manager->setAudioDeviceSetup (config, true);
|
||||
}
|
||||
}
|
||||
else if (comboBoxThatHasChanged == bufferSizeDropDown)
|
||||
{
|
||||
if (bufferSizeDropDown->getSelectedId() > 0)
|
||||
{
|
||||
config.bufferSize = bufferSizeDropDown->getSelectedId();
|
||||
error = setup.manager->setAudioDeviceSetup (config, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (error.isNotEmpty())
|
||||
{
|
||||
AlertWindow::showMessageBox (AlertWindow::WarningIcon,
|
||||
T("Error when trying to open audio device!"),
|
||||
error);
|
||||
}
|
||||
}
|
||||
|
||||
void buttonClicked (Button*)
|
||||
{
|
||||
setup.manager->playTestSound();
|
||||
}
|
||||
|
||||
void changeListenerCallback (void*)
|
||||
{
|
||||
AudioIODevice* const currentDevice = setup.manager->getCurrentAudioDevice();
|
||||
|
||||
if (currentDevice != 0)
|
||||
{
|
||||
showCorrectDeviceName (inputDeviceDropDown, true);
|
||||
showCorrectDeviceName (outputDeviceDropDown, false);
|
||||
|
||||
// sample rate..
|
||||
{
|
||||
if (sampleRateDropDown == 0)
|
||||
{
|
||||
addAndMakeVisible (sampleRateDropDown = new ComboBox (String::empty));
|
||||
sampleRateDropDown->addListener (this);
|
||||
|
||||
delete sampleRateLabel;
|
||||
sampleRateLabel = new Label (String::empty, TRANS ("sample rate:"));
|
||||
sampleRateLabel->attachToComponent (sampleRateDropDown, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
sampleRateDropDown->clear();
|
||||
sampleRateDropDown->removeListener (this);
|
||||
}
|
||||
|
||||
const int numRates = currentDevice->getNumSampleRates();
|
||||
|
||||
for (int i = 0; i < numRates; ++i)
|
||||
{
|
||||
const int rate = roundDoubleToInt (currentDevice->getSampleRate (i));
|
||||
sampleRateDropDown->addItem (String (rate) + T(" Hz"), rate);
|
||||
}
|
||||
|
||||
sampleRateDropDown->setSelectedId (roundDoubleToInt (currentDevice->getCurrentSampleRate()), true);
|
||||
sampleRateDropDown->addListener (this);
|
||||
}
|
||||
|
||||
// buffer size
|
||||
{
|
||||
if (bufferSizeDropDown == 0)
|
||||
{
|
||||
addAndMakeVisible (bufferSizeDropDown = new ComboBox (String::empty));
|
||||
bufferSizeDropDown->addListener (this);
|
||||
|
||||
delete bufferSizeLabel;
|
||||
bufferSizeLabel = new Label (String::empty, TRANS ("audio buffer size:"));
|
||||
bufferSizeLabel->attachToComponent (bufferSizeDropDown, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
bufferSizeDropDown->clear();
|
||||
}
|
||||
|
||||
const int numBufferSizes = currentDevice->getNumBufferSizesAvailable();
|
||||
double currentRate = currentDevice->getCurrentSampleRate();
|
||||
if (currentRate == 0)
|
||||
currentRate = 44100.0;
|
||||
|
||||
for (int 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);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
jassert (setup.manager->getCurrentAudioDevice() == 0); // not the correct device type!
|
||||
|
||||
deleteAndZero (sampleRateLabel);
|
||||
deleteAndZero (bufferSizeLabel);
|
||||
deleteAndZero (sampleRateDropDown);
|
||||
deleteAndZero (bufferSizeDropDown);
|
||||
|
||||
if (outputDeviceDropDown != 0)
|
||||
outputDeviceDropDown->setSelectedId (-1, true);
|
||||
|
||||
if (inputDeviceDropDown != 0)
|
||||
inputDeviceDropDown->setSelectedId (-1, true);
|
||||
}
|
||||
|
||||
resized();
|
||||
setSize (getWidth(), getLowestY() + 4);
|
||||
}
|
||||
|
||||
private:
|
||||
AudioIODeviceType* const type;
|
||||
const AudioIODeviceType::DeviceSetupDetails setup;
|
||||
|
||||
ComboBox* outputDeviceDropDown;
|
||||
ComboBox* inputDeviceDropDown;
|
||||
ComboBox* sampleRateDropDown;
|
||||
ComboBox* bufferSizeDropDown;
|
||||
Label* outputDeviceLabel;
|
||||
Label* inputDeviceLabel;
|
||||
Label* sampleRateLabel;
|
||||
Label* bufferSizeLabel;
|
||||
TextButton* testButton;
|
||||
Component* inputLevelMeter;
|
||||
|
||||
void showCorrectDeviceName (ComboBox* const box, const bool isInput)
|
||||
{
|
||||
if (box != 0)
|
||||
{
|
||||
CoreAudioIODevice* const currentDevice = dynamic_cast <CoreAudioIODevice*> (setup.manager->getCurrentAudioDevice());
|
||||
|
||||
const int index = (currentDevice == 0) ? -1
|
||||
: (isInput ? currentDevice->inputIndex
|
||||
: currentDevice->outputIndex);
|
||||
|
||||
if (index >= 0)
|
||||
box->setText (type->getDeviceNames (isInput) [index], true);
|
||||
else
|
||||
box->setSelectedId (-1, true);
|
||||
|
||||
if (! isInput)
|
||||
testButton->setEnabled (index >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
void addNamesToDeviceBox (ComboBox& combo, bool isInputs)
|
||||
{
|
||||
const StringArray devs (type->getDeviceNames (isInputs));
|
||||
|
||||
for (int i = 0; i < devs.size(); ++i)
|
||||
combo.addItem (devs[i], i + 1);
|
||||
|
||||
combo.addItem (TRANS("<< none >>"), -1);
|
||||
combo.setSelectedId (-1, true);
|
||||
}
|
||||
|
||||
int getLowestY() const
|
||||
{
|
||||
int y = 0;
|
||||
|
||||
for (int i = getNumChildComponents(); --i >= 0;)
|
||||
y = jmax (y, getChildComponent (i)->getBottom());
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
CoreAudioDevicePanel (const CoreAudioDevicePanel&);
|
||||
const CoreAudioDevicePanel& operator= (const CoreAudioDevicePanel&);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class CoreAudioIODeviceType : public AudioIODeviceType
|
||||
|
|
@ -1086,8 +1434,10 @@ public:
|
|||
{
|
||||
hasScanned = true;
|
||||
|
||||
names.clear();
|
||||
ids.clear();
|
||||
inputDeviceNames.clear();
|
||||
outputDeviceNames.clear();
|
||||
inputIds.clear();
|
||||
outputIds.clear();
|
||||
|
||||
UInt32 size;
|
||||
if (OK (AudioHardwareGetPropertyInfo (kAudioHardwarePropertyDevices, &size, 0)))
|
||||
|
|
@ -1109,8 +1459,20 @@ public:
|
|||
if (! alreadyLogged)
|
||||
log (T("CoreAudio device: ") + nameString);
|
||||
|
||||
names.add (nameString);
|
||||
ids.add (devs[i]);
|
||||
const int numIns = getNumChannels (devs[i], true);
|
||||
const int numOuts = getNumChannels (devs[i], false);
|
||||
|
||||
if (numIns > 0)
|
||||
{
|
||||
inputDeviceNames.add (nameString);
|
||||
inputIds.add (devs[i]);
|
||||
}
|
||||
|
||||
if (numOuts > 0)
|
||||
{
|
||||
outputDeviceNames.add (nameString);
|
||||
outputIds.add (devs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1119,52 +1481,83 @@ public:
|
|||
|
||||
juce_free (devs);
|
||||
}
|
||||
|
||||
inputDeviceNames.appendNumbersToDuplicates (false, true);
|
||||
outputDeviceNames.appendNumbersToDuplicates (false, true);
|
||||
}
|
||||
|
||||
const StringArray getDeviceNames (const bool /*preferInputNames*/) const
|
||||
const StringArray getDeviceNames (const bool wantInputNames) const
|
||||
{
|
||||
jassert (hasScanned); // need to call scanForDevices() before doing this
|
||||
|
||||
StringArray namesCopy (names);
|
||||
namesCopy.removeDuplicates (true);
|
||||
|
||||
return namesCopy;
|
||||
if (wantInputNames)
|
||||
return inputDeviceNames;
|
||||
else
|
||||
return outputDeviceNames;
|
||||
}
|
||||
|
||||
const String getDefaultDeviceName (const bool preferInputNames,
|
||||
const int numInputChannelsNeeded,
|
||||
const int numOutputChannelsNeeded) const
|
||||
int getDefaultDeviceIndex (const bool forInput) const
|
||||
{
|
||||
jassert (hasScanned); // need to call scanForDevices() before doing this
|
||||
|
||||
String result (names[0]);
|
||||
|
||||
AudioDeviceID deviceID;
|
||||
UInt32 size = sizeof (deviceID);
|
||||
|
||||
// if they're asking for any input channels at all, use the default input, so we
|
||||
// get the built-in mic rather than the built-in output with no inputs..
|
||||
if (AudioHardwareGetProperty (numInputChannelsNeeded > 0
|
||||
? kAudioHardwarePropertyDefaultInputDevice
|
||||
: kAudioHardwarePropertyDefaultOutputDevice,
|
||||
if (AudioHardwareGetProperty (forInput ? kAudioHardwarePropertyDefaultInputDevice
|
||||
: kAudioHardwarePropertyDefaultOutputDevice,
|
||||
&size, &deviceID) == noErr)
|
||||
{
|
||||
for (int i = ids.size(); --i >= 0;)
|
||||
if (ids[i] == deviceID)
|
||||
result = names[i];
|
||||
if (forInput)
|
||||
{
|
||||
for (int i = inputIds.size(); --i >= 0;)
|
||||
if (inputIds[i] == deviceID)
|
||||
return i;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = outputIds.size(); --i >= 0;)
|
||||
if (outputIds[i] == deviceID)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
AudioIODevice* createDevice (const String& deviceName)
|
||||
int getIndexOfDevice (AudioIODevice* device, const bool asInput) const
|
||||
{
|
||||
jassert (hasScanned); // need to call scanForDevices() before doing this
|
||||
|
||||
const int index = names.indexOf (deviceName);
|
||||
CoreAudioIODevice* const d = dynamic_cast <CoreAudioIODevice*> (device);
|
||||
if (d == 0)
|
||||
return -1;
|
||||
|
||||
return asInput ? d->inputIndex
|
||||
: d->outputIndex;
|
||||
}
|
||||
|
||||
bool hasSeparateInputsAndOutputs() const { return true; }
|
||||
|
||||
AudioIODevice* createDevice (const String& outputDeviceName,
|
||||
const String& inputDeviceName)
|
||||
{
|
||||
jassert (hasScanned); // need to call scanForDevices() before doing this
|
||||
|
||||
const int inputIndex = inputDeviceNames.indexOf (inputDeviceName);
|
||||
const int outputIndex = outputDeviceNames.indexOf (outputDeviceName);
|
||||
|
||||
String deviceName (outputDeviceName);
|
||||
if (deviceName.isEmpty())
|
||||
deviceName = inputDeviceName;
|
||||
|
||||
if (index >= 0)
|
||||
return new CoreAudioIODevice (deviceName, ids [index]);
|
||||
return new CoreAudioIODevice (deviceName,
|
||||
inputIds [inputIndex],
|
||||
inputIndex,
|
||||
outputIds [outputIndex],
|
||||
outputIndex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1173,11 +1566,37 @@ public:
|
|||
juce_UseDebuggingNewOperator
|
||||
|
||||
private:
|
||||
StringArray names;
|
||||
Array <AudioDeviceID> ids;
|
||||
StringArray inputDeviceNames, outputDeviceNames;
|
||||
Array <AudioDeviceID> inputIds, outputIds;
|
||||
|
||||
bool hasScanned;
|
||||
|
||||
static int getNumChannels (AudioDeviceID deviceID, bool input)
|
||||
{
|
||||
int total = 0;
|
||||
UInt32 size;
|
||||
|
||||
if (OK (AudioDeviceGetPropertyInfo (deviceID, 0, input, kAudioDevicePropertyStreamConfiguration, &size, 0)))
|
||||
{
|
||||
AudioBufferList* const bufList = (AudioBufferList*) juce_calloc (size);
|
||||
|
||||
if (OK (AudioDeviceGetProperty (deviceID, 0, input, kAudioDevicePropertyStreamConfiguration, &size, bufList)))
|
||||
{
|
||||
const int numStreams = bufList->mNumberBuffers;
|
||||
|
||||
for (int i = 0; i < numStreams; ++i)
|
||||
{
|
||||
const AudioBuffer& b = bufList->mBuffers[i];
|
||||
total += b.mNumberChannels;
|
||||
}
|
||||
}
|
||||
|
||||
juce_free (bufList);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
CoreAudioIODeviceType (const CoreAudioIODeviceType&);
|
||||
const CoreAudioIODeviceType& operator= (const CoreAudioIODeviceType&);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -66,12 +66,17 @@
|
|||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "../../../src/juce_appframework/audio/devices/juce_AudioIODeviceType.h"
|
||||
#include "../../../src/juce_appframework/audio/devices/juce_AudioDeviceManager.h"
|
||||
#include "../../../src/juce_appframework/gui/components/buttons/juce_TextButton.h"
|
||||
#include "../../../src/juce_appframework/gui/components/lookandfeel/juce_LookAndFeel.h"
|
||||
#include "../../../src/juce_core/threads/juce_ScopedLock.h"
|
||||
#include "../../../src/juce_appframework/gui/components/juce_Component.h"
|
||||
#include "../../../src/juce_core/basics/juce_Time.h"
|
||||
#include "../../../src/juce_core/threads/juce_Thread.h"
|
||||
#include "../../../src/juce_appframework/events/juce_Timer.h"
|
||||
#include "../../../src/juce_appframework/events/juce_MessageManager.h"
|
||||
#include "../../../src/juce_appframework/gui/components/windows/juce_AlertWindow.h"
|
||||
#include "../../../src/juce_appframework/gui/components/controls/juce_ListBox.h"
|
||||
#include "../../../src/juce_core/text/juce_LocalisedStrings.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -120,7 +125,6 @@ static const int maxASIOChannels = 160;
|
|||
|
||||
//==============================================================================
|
||||
class JUCE_API ASIOAudioIODevice : public AudioIODevice,
|
||||
private Thread,
|
||||
private Timer
|
||||
{
|
||||
public:
|
||||
|
|
@ -128,7 +132,6 @@ public:
|
|||
|
||||
ASIOAudioIODevice (const String& name_, const CLSID classId_, const int slotNumber)
|
||||
: AudioIODevice (name_, T("ASIO")),
|
||||
Thread ("Juce ASIO"),
|
||||
asioObject (0),
|
||||
classId (classId_),
|
||||
currentBitDepth (16),
|
||||
|
|
@ -496,8 +499,6 @@ public:
|
|||
{
|
||||
buffersCreated = true;
|
||||
|
||||
jassert (! isThreadRunning());
|
||||
|
||||
juce_free (tempBuffer);
|
||||
|
||||
tempBuffer = (float*) juce_calloc (totalBuffers * currentBlockSizeSamples * sizeof (float) + 128);
|
||||
|
|
@ -601,7 +602,6 @@ public:
|
|||
}
|
||||
|
||||
isOpen_ = true;
|
||||
isThreadReady = false;
|
||||
|
||||
log ("starting ASIO");
|
||||
calledback = false;
|
||||
|
|
@ -808,26 +808,6 @@ public:
|
|||
return done;
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
isThreadReady = true;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
event1.wait();
|
||||
|
||||
if (threadShouldExit())
|
||||
break;
|
||||
|
||||
processBuffer();
|
||||
}
|
||||
|
||||
if (bufferIndex < 0)
|
||||
{
|
||||
log ("! ASIO callback never called");
|
||||
}
|
||||
}
|
||||
|
||||
void resetRequest() throw()
|
||||
{
|
||||
needToReset = true;
|
||||
|
|
@ -912,7 +892,7 @@ private:
|
|||
bool isOpen_, isStarted;
|
||||
bool volatile isASIOOpen;
|
||||
bool volatile calledback;
|
||||
bool volatile littleEndian, postOutput, needToReset, isReSync, isThreadReady;
|
||||
bool volatile littleEndian, postOutput, needToReset, isReSync;
|
||||
bool volatile insideControlPanelModalLoop;
|
||||
bool volatile shouldUsePreferredSize;
|
||||
|
||||
|
|
@ -1809,46 +1789,65 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
const StringArray getDeviceNames (const bool /*preferInputNames*/) const
|
||||
const StringArray getDeviceNames (const bool /*wantInputNames*/) const
|
||||
{
|
||||
jassert (hasScanned); // need to call scanForDevices() before doing this
|
||||
|
||||
return deviceNames;
|
||||
}
|
||||
|
||||
const String getDefaultDeviceName (const bool /*preferInputNames*/,
|
||||
const int /*numInputChannelsNeeded*/,
|
||||
const int /*numOutputChannelsNeeded*/) const
|
||||
int getDefaultDeviceIndex (const bool) const
|
||||
{
|
||||
jassert (hasScanned); // need to call scanForDevices() before doing this
|
||||
|
||||
return deviceNames [0];
|
||||
for (int i = deviceNames.size(); --i >= 0;)
|
||||
if (deviceNames[i].containsIgnoreCase (T("asio4all")))
|
||||
return i; // asio4all is a safe choice for a default..
|
||||
|
||||
#if JUCE_DEBUG
|
||||
if (deviceNames.size() > 1 && deviceNames[0].containsIgnoreCase (T("digidesign")))
|
||||
return 1; // (the digi m-box driver crashes the app when you run
|
||||
// it in the debugger, which can be a bit annoying)
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
AudioIODevice* createDevice (const String& deviceName)
|
||||
static int findFreeSlot()
|
||||
{
|
||||
for (int i = 0; i < numElementsInArray (currentASIODev); ++i)
|
||||
if (currentASIODev[i] == 0)
|
||||
return i;
|
||||
|
||||
jassertfalse; // unfortunately you can only have a finite number
|
||||
// of ASIO devices open at the same time..
|
||||
return -1;
|
||||
}
|
||||
|
||||
int getIndexOfDevice (AudioIODevice* d, const bool /*asInput*/) const
|
||||
{
|
||||
jassert (hasScanned); // need to call scanForDevices() before doing this
|
||||
|
||||
const int index = deviceNames.indexOf (deviceName);
|
||||
return d == 0 ? -1 : deviceNames.indexOf (d->getName());
|
||||
}
|
||||
|
||||
bool hasSeparateInputsAndOutputs() const { return false; }
|
||||
|
||||
AudioIODevice* createDevice (const String& outputDeviceName,
|
||||
const String& inputDeviceName)
|
||||
{
|
||||
jassert (inputDeviceName == outputDeviceName);
|
||||
(void) inputDeviceName;
|
||||
jassert (hasScanned); // need to call scanForDevices() before doing this
|
||||
|
||||
const int index = deviceNames.indexOf (outputDeviceName);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
int freeSlot = -1;
|
||||
|
||||
for (int i = 0; i < numElementsInArray (currentASIODev); ++i)
|
||||
{
|
||||
if (currentASIODev[i] == 0)
|
||||
{
|
||||
freeSlot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
jassert (freeSlot >= 0); // unfortunately you can only have a finite number
|
||||
// of ASIO devices open at the same time..
|
||||
const int freeSlot = findFreeSlot();
|
||||
|
||||
if (freeSlot >= 0)
|
||||
return new ASIOAudioIODevice (deviceName, *(classIds [index]), freeSlot);
|
||||
return new ASIOAudioIODevice (outputDeviceName, *(classIds [index]), freeSlot);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1923,6 +1922,7 @@ private:
|
|||
return ok;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void addDriverInfo (const String& keyName, HKEY hk)
|
||||
{
|
||||
HKEY subKey;
|
||||
|
|
@ -1974,6 +1974,17 @@ AudioIODeviceType* juce_createASIOAudioIODeviceType()
|
|||
return new ASIOAudioIODeviceType();
|
||||
}
|
||||
|
||||
AudioIODevice* juce_createASIOAudioIODeviceForGUID (const String& name,
|
||||
void* guid)
|
||||
{
|
||||
const int freeSlot = ASIOAudioIODeviceType::findFreeSlot();
|
||||
|
||||
if (freeSlot < 0)
|
||||
return 0;
|
||||
|
||||
return new ASIOAudioIODevice (name, *(CLSID*) guid, freeSlot);
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
||||
|
|
|
|||
|
|
@ -141,12 +141,16 @@ DECLARE_INTERFACE_(IDirectSoundCaptureBuffer, IUnknown)
|
|||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "../../../src/juce_appframework/audio/devices/juce_AudioIODeviceType.h"
|
||||
#include "../../../src/juce_appframework/audio/devices/juce_AudioDeviceManager.h"
|
||||
#include "../../../src/juce_appframework/application/juce_Application.h"
|
||||
#include "../../../src/juce_appframework/gui/components/windows/juce_AlertWindow.h"
|
||||
#include "../../../src/juce_core/threads/juce_Thread.h"
|
||||
#include "../../../src/juce_core/basics/juce_Singleton.h"
|
||||
#include "../../../src/juce_core/basics/juce_Time.h"
|
||||
#include "../../../src/juce_core/containers/juce_OwnedArray.h"
|
||||
#include "../../../src/juce_core/text/juce_LocalisedStrings.h"
|
||||
#include "../../../src/juce_appframework/gui/components/buttons/juce_TextButton.h"
|
||||
#include "../../../src/juce_appframework/gui/components/special/juce_AudioDeviceSelectorComponent.h"
|
||||
|
||||
|
||||
static const String getDSErrorMessage (HRESULT hr)
|
||||
|
|
@ -949,7 +953,7 @@ public:
|
|||
};
|
||||
|
||||
//==============================================================================
|
||||
static int findBestMatchForName (const String& name, const StringArray& names)
|
||||
/*static int findBestMatchForName (const String& name, const StringArray& names)
|
||||
{
|
||||
int i = names.indexOf (name);
|
||||
|
||||
|
|
@ -978,21 +982,21 @@ static int findBestMatchForName (const String& name, const StringArray& names)
|
|||
}
|
||||
|
||||
return bestResult;
|
||||
}
|
||||
}*/
|
||||
|
||||
class DSoundAudioIODevice : public AudioIODevice,
|
||||
public Thread
|
||||
{
|
||||
public:
|
||||
DSoundAudioIODevice (const String& deviceName,
|
||||
const int index,
|
||||
const int inputIndex_)
|
||||
const int outputDeviceIndex_,
|
||||
const int inputDeviceIndex_)
|
||||
: AudioIODevice (deviceName, "DirectSound"),
|
||||
Thread ("Juce DSound"),
|
||||
isOpen_ (false),
|
||||
isStarted (false),
|
||||
deviceIndex (index),
|
||||
inputIndex (inputIndex_),
|
||||
outputDeviceIndex (outputDeviceIndex_),
|
||||
inputDeviceIndex (inputDeviceIndex_),
|
||||
inChans (4),
|
||||
outChans (4),
|
||||
numInputBuffers (0),
|
||||
|
|
@ -1004,6 +1008,17 @@ public:
|
|||
callback (0),
|
||||
bufferSizeSamples (0)
|
||||
{
|
||||
if (outputDeviceIndex_ >= 0)
|
||||
{
|
||||
outChannels.add (TRANS("Left"));
|
||||
outChannels.add (TRANS("Right"));
|
||||
}
|
||||
|
||||
if (inputDeviceIndex_ >= 0)
|
||||
{
|
||||
inChannels.add (TRANS("Left"));
|
||||
inChannels.add (TRANS("Right"));
|
||||
}
|
||||
}
|
||||
|
||||
~DSoundAudioIODevice()
|
||||
|
|
@ -1176,13 +1191,13 @@ public:
|
|||
juce_UseDebuggingNewOperator
|
||||
|
||||
StringArray inChannels, outChannels;
|
||||
int outputDeviceIndex, inputDeviceIndex;
|
||||
|
||||
private:
|
||||
bool isOpen_;
|
||||
bool isStarted;
|
||||
String lastError;
|
||||
|
||||
int deviceIndex, inputIndex;
|
||||
OwnedArray <DSoundInternalInChannel> inChans;
|
||||
OwnedArray <DSoundInternalOutChannel> outChans;
|
||||
WaitableEvent startEvent;
|
||||
|
|
@ -1381,6 +1396,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class DSoundAudioIODeviceType : public AudioIODeviceType
|
||||
{
|
||||
|
|
@ -1413,72 +1429,46 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
const StringArray getDeviceNames (const bool preferInputNames) const
|
||||
const StringArray getDeviceNames (const bool wantInputNames) const
|
||||
{
|
||||
jassert (hasScanned); // need to call scanForDevices() before doing this
|
||||
|
||||
return preferInputNames ? inputDeviceNames
|
||||
: outputDeviceNames;
|
||||
return wantInputNames ? inputDeviceNames
|
||||
: outputDeviceNames;
|
||||
}
|
||||
|
||||
const String getDefaultDeviceName (const bool preferInputNames,
|
||||
const int /*numInputChannelsNeeded*/,
|
||||
const int /*numOutputChannelsNeeded*/) const
|
||||
int getDefaultDeviceIndex (const bool /*forInput*/) const
|
||||
{
|
||||
jassert (hasScanned); // need to call scanForDevices() before doing this
|
||||
|
||||
return getDeviceNames (preferInputNames) [0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
AudioIODevice* createDevice (const String& deviceName)
|
||||
int getIndexOfDevice (AudioIODevice* device, const bool asInput) const
|
||||
{
|
||||
jassert (hasScanned); // need to call scanForDevices() before doing this
|
||||
|
||||
if (deviceName.isEmpty() || deviceName.equalsIgnoreCase (T("DirectSound")))
|
||||
{
|
||||
DSoundAudioIODevice* device = new DSoundAudioIODevice (deviceName, -1, -1);
|
||||
DSoundAudioIODevice* const d = dynamic_cast <DSoundAudioIODevice*> (device);
|
||||
if (d == 0)
|
||||
return -1;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < outputDeviceNames.size(); ++i)
|
||||
{
|
||||
device->outChannels.add (outputDeviceNames[i] + TRANS(" (left)"));
|
||||
device->outChannels.add (outputDeviceNames[i] + TRANS(" (right)"));
|
||||
}
|
||||
return asInput ? d->inputDeviceIndex
|
||||
: d->outputDeviceIndex;
|
||||
}
|
||||
|
||||
for (i = 0; i < inputDeviceNames.size(); ++i)
|
||||
{
|
||||
device->inChannels.add (inputDeviceNames[i] + TRANS(" (left)"));
|
||||
device->inChannels.add (inputDeviceNames[i] + TRANS(" (right)"));
|
||||
}
|
||||
bool hasSeparateInputsAndOutputs() const { return true; }
|
||||
|
||||
return device;
|
||||
}
|
||||
else if (outputDeviceNames.contains (deviceName)
|
||||
|| inputDeviceNames.contains (deviceName))
|
||||
{
|
||||
int outputIndex = outputDeviceNames.indexOf (deviceName);
|
||||
int inputIndex = findBestMatchForName (deviceName, inputDeviceNames);
|
||||
AudioIODevice* createDevice (const String& outputDeviceName,
|
||||
const String& inputDeviceName)
|
||||
{
|
||||
jassert (hasScanned); // need to call scanForDevices() before doing this
|
||||
|
||||
if (outputIndex < 0)
|
||||
{
|
||||
// using an input device name instead..
|
||||
inputIndex = inputDeviceNames.indexOf (deviceName);
|
||||
outputIndex = jmax (0, findBestMatchForName (deviceName, outputDeviceNames));
|
||||
}
|
||||
const int outputIndex = outputDeviceNames.indexOf (outputDeviceName);
|
||||
const int inputIndex = inputDeviceNames.indexOf (inputDeviceName);
|
||||
|
||||
DSoundAudioIODevice* device = new DSoundAudioIODevice (deviceName, outputIndex, inputIndex);
|
||||
|
||||
device->outChannels.add (TRANS("Left"));
|
||||
device->outChannels.add (TRANS("Right"));
|
||||
|
||||
if (inputIndex >= 0)
|
||||
{
|
||||
device->inChannels.add (TRANS("Left"));
|
||||
device->inChannels.add (TRANS("Right"));
|
||||
}
|
||||
|
||||
return device;
|
||||
}
|
||||
if (outputIndex >= 0 || inputIndex >= 0)
|
||||
return new DSoundAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName
|
||||
: inputDeviceName,
|
||||
outputIndex, inputIndex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1619,8 +1609,8 @@ const String DSoundAudioIODevice::openDevice (const BitArray& inputChannels,
|
|||
right = inputBuffers[numIns++] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
|
||||
|
||||
if (left != 0 || right != 0)
|
||||
inChans.add (new DSoundInternalInChannel (dlh.inputDeviceNames [i / 2],
|
||||
dlh.inputGuids [i / 2],
|
||||
inChans.add (new DSoundInternalInChannel (dlh.inputDeviceNames [inputDeviceIndex],
|
||||
dlh.inputGuids [inputDeviceIndex],
|
||||
(int) sampleRate, bufferSizeSamples,
|
||||
left, right));
|
||||
}
|
||||
|
|
@ -1647,8 +1637,8 @@ const String DSoundAudioIODevice::openDevice (const BitArray& inputChannels,
|
|||
right = outputBuffers[numOuts++] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
|
||||
|
||||
if (left != 0 || right != 0)
|
||||
outChans.add (new DSoundInternalOutChannel (dlh.outputDeviceNames[i / 2],
|
||||
dlh.outputGuids [i / 2],
|
||||
outChans.add (new DSoundInternalOutChannel (dlh.outputDeviceNames[outputDeviceIndex],
|
||||
dlh.outputGuids [outputDeviceIndex],
|
||||
(int) sampleRate, bufferSizeSamples,
|
||||
left, right));
|
||||
}
|
||||
|
|
@ -1714,6 +1704,7 @@ const String DSoundAudioIODevice::openDevice (const BitArray& inputChannels,
|
|||
return error;
|
||||
}
|
||||
|
||||
|
||||
#undef log
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ void AudioFilterStreamingDeviceManager::setFilter (AudioProcessor* filterToStrea
|
|||
{
|
||||
if (streamer != 0)
|
||||
{
|
||||
removeMidiInputCallback (streamer);
|
||||
removeMidiInputCallback (String::empty, streamer);
|
||||
setAudioCallback (0);
|
||||
|
||||
delete streamer;
|
||||
|
|
|
|||
|
|
@ -479,7 +479,7 @@ public:
|
|||
|
||||
~AudioDemo()
|
||||
{
|
||||
audioDeviceManager.removeMidiInputCallback (&synthSource.midiCollector);
|
||||
audioDeviceManager.removeMidiInputCallback (String::empty, &synthSource.midiCollector);
|
||||
audioDeviceManager.setAudioCallback (0);
|
||||
|
||||
transportSource.removeChangeListener (this);
|
||||
|
|
|
|||
2989
juce_amalgamated.cpp
2989
juce_amalgamated.cpp
File diff suppressed because it is too large
Load diff
|
|
@ -196,7 +196,7 @@
|
|||
/** Enabling this builds support for VST audio plugins.
|
||||
@see VSTPluginFormat, AudioPluginFormat, AudioPluginFormatManager, JUCE_PLUGINHOST_AU
|
||||
*/
|
||||
#define JUCE_PLUGINHOST_VST 1
|
||||
//#define JUCE_PLUGINHOST_VST 1
|
||||
|
||||
/** Enabling this builds support for AudioUnit audio plugins.
|
||||
@see AudioUnitPluginFormat, AudioPluginFormat, AudioPluginFormatManager, JUCE_PLUGINHOST_VST
|
||||
|
|
@ -4138,6 +4138,8 @@ public:
|
|||
@param minutes minutes 0 to 59
|
||||
@param seconds seconds 0 to 59
|
||||
@param milliseconds milliseconds 0 to 999
|
||||
@param useLocalTime if true, encode using the current machine's local time; if
|
||||
false, it will always work in GMT.
|
||||
*/
|
||||
Time (const int year,
|
||||
const int month,
|
||||
|
|
@ -4145,7 +4147,8 @@ public:
|
|||
const int hours,
|
||||
const int minutes,
|
||||
const int seconds = 0,
|
||||
const int milliseconds = 0) throw();
|
||||
const int milliseconds = 0,
|
||||
const bool useLocalTime = true) throw();
|
||||
|
||||
/** Destructor. */
|
||||
~Time() throw();
|
||||
|
|
@ -12994,6 +12997,11 @@ public:
|
|||
*/
|
||||
static void JUCE_CALLTYPE setCurrentModuleInstanceHandle (void* newHandle) throw();
|
||||
|
||||
/** WIN32 ONLY - Gets the command-line params as a string.
|
||||
|
||||
This is needed to avoid unicode problems with the argc type params.
|
||||
*/
|
||||
static const String JUCE_CALLTYPE getCurrentCommandLineParams() throw();
|
||||
#endif
|
||||
|
||||
/** Clears the floating point unit's flags.
|
||||
|
|
@ -20315,6 +20323,13 @@ public:
|
|||
/** Tries to give the window keyboard focus. */
|
||||
virtual void grabFocus() = 0;
|
||||
|
||||
/** Tells the window that text input may be required at the given position.
|
||||
|
||||
This may cause things like a virtual on-screen keyboard to appear, depending
|
||||
on the OS.
|
||||
*/
|
||||
virtual void textInputRequired (int x, int y) = 0;
|
||||
|
||||
/** Called when the window gains keyboard focus. */
|
||||
void handleFocusGain();
|
||||
/** Called when the window loses keyboard focus. */
|
||||
|
|
@ -31673,6 +31688,9 @@ private:
|
|||
#ifndef __JUCE_AUDIOIODEVICETYPE_JUCEHEADER__
|
||||
#define __JUCE_AUDIOIODEVICETYPE_JUCEHEADER__
|
||||
|
||||
class AudioDeviceManager;
|
||||
class Component;
|
||||
|
||||
/**
|
||||
Represents a type of audio driver, such as DirectSound, ASIO, CoreAudio, etc.
|
||||
|
||||
|
|
@ -31709,19 +31727,6 @@ class JUCE_API AudioIODeviceType
|
|||
{
|
||||
public:
|
||||
|
||||
/** Creates a list of available types.
|
||||
|
||||
This will add a set of new AudioIODeviceType objects to the specified list, to
|
||||
represent each available types of device.
|
||||
|
||||
The objects that are created should be managed by the caller (the OwnedArray
|
||||
will delete them when the array is itself deleted).
|
||||
|
||||
When created, the objects are uninitialised, so you should call scanForDevices()
|
||||
on each one before getting its list of devices.
|
||||
*/
|
||||
static void createDeviceTypes (OwnedArray <AudioIODeviceType>& list);
|
||||
|
||||
/** Returns the name of this type of driver that this object manages.
|
||||
|
||||
This will be something like "DirectSound", "ASIO", "CoreAudio", "ALSA", etc.
|
||||
|
|
@ -31739,34 +31744,46 @@ public:
|
|||
|
||||
The scanForDevices() method must have been called to create this list.
|
||||
|
||||
@param preferInputNames only really used by DirectSound where devices are split up
|
||||
into inputs and outputs, this indicates whether to use
|
||||
the input or output name to refer to a pair of devices.
|
||||
@param wantInputNames only really used by DirectSound where devices are split up
|
||||
into inputs and outputs, this indicates whether to use
|
||||
the input or output name to refer to a pair of devices.
|
||||
*/
|
||||
virtual const StringArray getDeviceNames (const bool preferInputNames = false) const = 0;
|
||||
virtual const StringArray getDeviceNames (const bool wantInputNames = false) const = 0;
|
||||
|
||||
/** Returns the name of the default device.
|
||||
|
||||
This will be one of the names from the getDeviceNames() list.
|
||||
|
||||
@param preferInputNames only really used by DirectSound where devices are split up
|
||||
into inputs and outputs, this indicates whether to use
|
||||
the input or output name to refer to a pair of devices.
|
||||
@param numInputChannelsNeeded the number of input channels the user is expecting to need - this
|
||||
may be used to help decide which device would be most suitable
|
||||
@param numOutputChannelsNeeded the number of output channels the user is expecting to need - this
|
||||
may be used to help decide which device would be most suitable
|
||||
@param forInput if true, this means that a default input device should be
|
||||
returned; if false, it should return the default output
|
||||
*/
|
||||
virtual const String getDefaultDeviceName (const bool preferInputNames,
|
||||
const int numInputChannelsNeeded,
|
||||
const int numOutputChannelsNeeded) const = 0;
|
||||
virtual int getDefaultDeviceIndex (const bool forInput) const = 0;
|
||||
|
||||
/** Returns the index of a given device in the list of device names.
|
||||
If asInput is true, it shows the index in the inputs list, otherwise it
|
||||
looks for it in the outputs list.
|
||||
*/
|
||||
virtual int getIndexOfDevice (AudioIODevice* device, const bool asInput) const = 0;
|
||||
|
||||
/** Returns true if two different devices can be used for the input and output.
|
||||
*/
|
||||
virtual bool hasSeparateInputsAndOutputs() const = 0;
|
||||
|
||||
/** Creates one of the devices of this type.
|
||||
|
||||
The deviceName must be one of the strings returned by getDeviceNames(), and
|
||||
scanForDevices() must have been called before this method is used.
|
||||
*/
|
||||
virtual AudioIODevice* createDevice (const String& deviceName) = 0;
|
||||
virtual AudioIODevice* createDevice (const String& outputDeviceName,
|
||||
const String& inputDeviceName) = 0;
|
||||
|
||||
struct DeviceSetupDetails
|
||||
{
|
||||
AudioDeviceManager* manager;
|
||||
int minNumInputChannels, maxNumInputChannels;
|
||||
int minNumOutputChannels, maxNumOutputChannels;
|
||||
bool useStereoPairs;
|
||||
};
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~AudioIODeviceType();
|
||||
|
|
@ -33561,52 +33578,41 @@ public:
|
|||
*/
|
||||
XmlElement* createStateXml() const;
|
||||
|
||||
/** Returns a list of the audio devices that can be used.
|
||||
|
||||
On Windows, this will include both DSound and ASIO devices if they are available. On
|
||||
the Mac, it'll be a list of the CoreAudio devices.
|
||||
|
||||
These names are used by setAudioDevice() when changing devices.
|
||||
/**
|
||||
*/
|
||||
const StringArray getAvailableAudioDeviceNames() const;
|
||||
struct AudioDeviceSetup
|
||||
{
|
||||
AudioDeviceSetup();
|
||||
|
||||
/** Rescans the list of known audio devices, in case it's changed. */
|
||||
void refreshDeviceList() const;
|
||||
bool operator== (const AudioDeviceSetup& other) const;
|
||||
|
||||
/** Sets a flag to indicate that when listing audio device names, it should treat them
|
||||
as inputs rather than outputs.
|
||||
/**
|
||||
*/
|
||||
String outputDeviceName;
|
||||
/**
|
||||
*/
|
||||
String inputDeviceName;
|
||||
/**
|
||||
*/
|
||||
double sampleRate;
|
||||
/**
|
||||
*/
|
||||
int bufferSize;
|
||||
/**
|
||||
*/
|
||||
BitArray inputChannels;
|
||||
bool useDefaultInputChannels;
|
||||
/**
|
||||
*/
|
||||
BitArray outputChannels;
|
||||
bool useDefaultOutputChannels;
|
||||
};
|
||||
|
||||
This only really applies to DirectSound, where input and output devices are
|
||||
separate. On ASIO and CoreAudio this makes no difference.
|
||||
|
||||
@see getAvailableAudioDeviceNames
|
||||
/**
|
||||
*/
|
||||
void setInputDeviceNamesUsed (const bool useInputNames);
|
||||
void getAudioDeviceSetup (AudioDeviceSetup& setup);
|
||||
|
||||
/** Just adds the list of device names to a combo box.
|
||||
|
||||
The only reason this is in this class is so that it can divide DSound
|
||||
and ASIO devices into labelled sections, which makes it look much neater.
|
||||
*/
|
||||
void addDeviceNamesToComboBox (ComboBox& combo) const;
|
||||
|
||||
/** Changes the audio device that should be used.
|
||||
|
||||
If deviceName is empty or not a valid name returned by getAvailableAudioDeviceNames(),
|
||||
it will disable the current device.
|
||||
|
||||
@param deviceName the name of the device you want to use (or an empty string to
|
||||
deselect the current device)
|
||||
@param blockSizeToUse the samples-per-block you want to use, or 0 to use a default
|
||||
value
|
||||
@param sampleRateToUse the target sample-rate, or 0 to use a default that the device
|
||||
is capable of
|
||||
@param inputChans which of the audio device's input channels to open - pass 0 to
|
||||
open as many of the the first ones as are needed for the number
|
||||
of input channels that the app has requested
|
||||
@param outputChans which of the audio device's input channels to open - pass 0 to
|
||||
open as many of the the first ones as are needed for the number
|
||||
of output channels that the app has requested
|
||||
/**
|
||||
@param treatAsChosenDevice if this is true and if the device opens correctly, these new
|
||||
settings will be taken as having been explicitly chosen by the
|
||||
user, and the next time createStateXml() is called, these settings
|
||||
|
|
@ -33614,15 +33620,17 @@ public:
|
|||
temporary or default device, and a call to createStateXml() will
|
||||
return either the last settings that were made with treatAsChosenDevice
|
||||
as true, or the last XML settings that were passed into initialise().
|
||||
|
||||
@returns an error message if anything went wrong, or an empty string if it worked ok.
|
||||
*/
|
||||
const String setAudioDevice (const String& deviceName,
|
||||
int blockSizeToUse,
|
||||
double sampleRateToUse,
|
||||
const BitArray* inputChans,
|
||||
const BitArray* outputChans,
|
||||
const bool treatAsChosenDevice);
|
||||
const String setAudioDeviceSetup (const AudioDeviceSetup& newSetup,
|
||||
const bool treatAsChosenDevice);
|
||||
|
||||
/** Returns the currently-active audio device. */
|
||||
AudioIODevice* getCurrentAudioDevice() const throw() { return currentAudioDevice; }
|
||||
|
||||
const String getCurrentAudioDeviceType() const throw() { return currentDeviceType; }
|
||||
void setCurrentAudioDeviceType (const String& type,
|
||||
const bool treatAsChosenDevice);
|
||||
|
||||
/** Closes the currently-open device.
|
||||
|
||||
|
|
@ -33641,59 +33649,6 @@ public:
|
|||
*/
|
||||
void restartLastAudioDevice();
|
||||
|
||||
/** Returns the name of the currently selected audio device.
|
||||
|
||||
This will be an empty string if none is active.
|
||||
*/
|
||||
const String getCurrentAudioDeviceName() const;
|
||||
|
||||
/** Returns the currently-active audio device. */
|
||||
AudioIODevice* getCurrentAudioDevice() const throw() { return currentAudioDevice; }
|
||||
|
||||
/** Returns the set of audio input channels currently being used.
|
||||
|
||||
To select different channels, use setInputChannels(), or call setAudioDevice() to
|
||||
reopen the device with a different set of channels.
|
||||
*/
|
||||
const BitArray getInputChannels() const throw() { return inputChannels; }
|
||||
|
||||
/** Changes the active set of input channels.
|
||||
|
||||
@param newEnabledChannels the set of channels to enable
|
||||
@param treatAsChosenDevice if this is true and if the device opens correctly, these new
|
||||
settings will be taken as having been explicitly chosen by the
|
||||
user, and the next time createStateXml() is called, these settings
|
||||
will be returned. If it's false, then the device is treated as a
|
||||
temporary or default device, and a call to createStateXml() will
|
||||
return either the last settings that were made with treatAsChosenDevice
|
||||
as true, or the last XML settings that were passed into initialise().
|
||||
@see getInputChannels
|
||||
*/
|
||||
void setInputChannels (const BitArray& newEnabledChannels,
|
||||
const bool treatAsChosenDevice);
|
||||
|
||||
/** Returns the set of audio output channels currently being used.
|
||||
|
||||
To select different channels, use setOutputChannels(), or call setAudioDevice() to
|
||||
reopen the device with a different set of channels.
|
||||
*/
|
||||
const BitArray getOutputChannels() const throw() { return outputChannels; }
|
||||
|
||||
/** Changes the active set of output channels.
|
||||
|
||||
@param newEnabledChannels the set of channels to enable
|
||||
@param treatAsChosenDevice if this is true and if the device opens correctly, these new
|
||||
settings will be taken as having been explicitly chosen by the
|
||||
user, and the next time createStateXml() is called, these settings
|
||||
will be returned. If it's false, then the device is treated as a
|
||||
temporary or default device, and a call to createStateXml() will
|
||||
return either the last settings that were made with treatAsChosenDevice
|
||||
as true, or the last XML settings that were passed into initialise().
|
||||
@see getOutputChannels
|
||||
*/
|
||||
void setOutputChannels (const BitArray& newEnabledChannels,
|
||||
const bool treatAsChosenDevice);
|
||||
|
||||
/** Gives the manager an audio callback to use.
|
||||
|
||||
The manager will redirect callbacks from whatever audio device is currently
|
||||
|
|
@ -33751,7 +33706,8 @@ public:
|
|||
|
||||
/** Removes a listener that was previously registered with addMidiInputCallback().
|
||||
*/
|
||||
void removeMidiInputCallback (MidiInputCallback* callback);
|
||||
void removeMidiInputCallback (const String& midiInputDeviceName,
|
||||
MidiInputCallback* callback);
|
||||
|
||||
/** Sets a midi output device to use as the default.
|
||||
|
||||
|
|
@ -33782,19 +33738,69 @@ public:
|
|||
*/
|
||||
MidiOutput* getDefaultMidiOutput() const throw() { return defaultMidiOutput; }
|
||||
|
||||
/**
|
||||
*/
|
||||
const OwnedArray <AudioIODeviceType>& getAvailableDeviceTypes() const throw() { return availableDeviceTypes; }
|
||||
|
||||
/** Creates a list of available types.
|
||||
|
||||
This will add a set of new AudioIODeviceType objects to the specified list, to
|
||||
represent each available types of device.
|
||||
|
||||
You can override this if your app needs to do something specific, like avoid
|
||||
using DirectSound devices, etc.
|
||||
*/
|
||||
virtual void createAudioDeviceTypes (OwnedArray <AudioIODeviceType>& types);
|
||||
|
||||
/** Plays a beep through the current audio device.
|
||||
|
||||
This is here to allow the audio setup UI panels to easily include a "test"
|
||||
button so that the user can check where the audio is coming from.
|
||||
*/
|
||||
void playTestSound();
|
||||
|
||||
/** Turns on level-measuring.
|
||||
|
||||
When enabled, the device manager will measure the peak input level
|
||||
across all channels, and you can get this level by calling getCurrentInputLevel().
|
||||
|
||||
This is mainly intended for audio setup UI panels to use to create a mic
|
||||
level display, so that the user can check that they've selected the right
|
||||
device.
|
||||
|
||||
A simple filter is used to make the level decay smoothly, but this is
|
||||
only intended for giving rough feedback, and not for any kind of accurate
|
||||
measurement.
|
||||
*/
|
||||
void enableInputLevelMeasurement (const bool enableMeasurement);
|
||||
|
||||
/** Returns the current input level.
|
||||
|
||||
To use this, you must first enable it by calling enableInputLevelMeasurement().
|
||||
|
||||
See enableInputLevelMeasurement() for more info.
|
||||
*/
|
||||
double getCurrentInputLevel() const;
|
||||
|
||||
juce_UseDebuggingNewOperator
|
||||
|
||||
private:
|
||||
|
||||
OwnedArray <AudioIODeviceType> availableDeviceTypes;
|
||||
OwnedArray <AudioDeviceSetup> lastDeviceTypeConfigs;
|
||||
|
||||
AudioDeviceSetup currentSetup;
|
||||
AudioIODevice* currentAudioDevice;
|
||||
AudioIODeviceCallback* currentCallback;
|
||||
int numInputChansNeeded, numOutputChansNeeded;
|
||||
String currentDeviceType;
|
||||
BitArray inputChannels, outputChannels;
|
||||
XmlElement* lastExplicitSettings;
|
||||
mutable bool listNeedsScanning;
|
||||
bool useInputNames;
|
||||
bool useInputNames, inputLevelMeasurementEnabled;
|
||||
double inputLevel;
|
||||
AudioSampleBuffer* testSound;
|
||||
int testSoundPosition;
|
||||
|
||||
StringArray midiInsFromXml;
|
||||
OwnedArray <MidiInput> enabledMidiInputs;
|
||||
|
|
@ -33826,11 +33832,6 @@ private:
|
|||
};
|
||||
|
||||
CallbackHandler callbackHandler;
|
||||
String lastRunningDevice;
|
||||
int lastRunningBlockSize;
|
||||
double lastRunningSampleRate;
|
||||
BitArray lastRunningIns, lastRunningOuts;
|
||||
|
||||
friend class CallbackHandler;
|
||||
|
||||
void audioDeviceIOCallbackInt (const float** inputChannelData,
|
||||
|
|
@ -33849,6 +33850,15 @@ private:
|
|||
|
||||
void updateXml();
|
||||
|
||||
void createDeviceTypesIfNeeded();
|
||||
void scanDevicesIfNeeded();
|
||||
void deleteCurrentDevice();
|
||||
double chooseBestSampleRate (double preferred) const;
|
||||
AudioIODeviceType* getCurrentDeviceTypeObject() const;
|
||||
void insertDefaultDeviceNames (AudioDeviceSetup& setup) const;
|
||||
|
||||
AudioIODeviceType* findType (const String& inputName, const String& outputName);
|
||||
|
||||
AudioDeviceManager (const AudioDeviceManager&);
|
||||
const AudioDeviceManager& operator= (const AudioDeviceManager&);
|
||||
};
|
||||
|
|
@ -49093,8 +49103,8 @@ private:
|
|||
|
||||
@see DirectoryContentsList, FileTreeComponent
|
||||
*/
|
||||
class JUCE_API FileListComponent : public DirectoryContentsDisplayComponent,
|
||||
public ListBox,
|
||||
class JUCE_API FileListComponent : public ListBox,
|
||||
public DirectoryContentsDisplayComponent,
|
||||
private ListBoxModel,
|
||||
private ChangeListener
|
||||
{
|
||||
|
|
@ -49454,8 +49464,8 @@ private:
|
|||
|
||||
@see DirectoryContentsList, FileListComponent
|
||||
*/
|
||||
class JUCE_API FileTreeComponent : public DirectoryContentsDisplayComponent,
|
||||
public TreeView
|
||||
class JUCE_API FileTreeComponent : public TreeView,
|
||||
public DirectoryContentsDisplayComponent
|
||||
{
|
||||
public:
|
||||
|
||||
|
|
@ -50416,7 +50426,7 @@ private:
|
|||
#ifndef __JUCE_AUDIODEVICESELECTORCOMPONENT_JUCEHEADER__
|
||||
#define __JUCE_AUDIODEVICESELECTORCOMPONENT_JUCEHEADER__
|
||||
|
||||
class AudioDeviceSelectorComponentListBox;
|
||||
class MidiInputSelectorComponentListBox;
|
||||
|
||||
/**
|
||||
A component containing controls to let the user change the audio settings of
|
||||
|
|
@ -50467,23 +50477,22 @@ public:
|
|||
/** @internal */
|
||||
void changeListenerCallback (void*);
|
||||
|
||||
/** Called by the device-specific displays to create a little level meter that
|
||||
just displays the current total input levels from the given device manager.
|
||||
*/
|
||||
static Component* createSimpleLevelMeterComponent (AudioDeviceManager* managerToDisplay);
|
||||
|
||||
juce_UseDebuggingNewOperator
|
||||
|
||||
private:
|
||||
AudioDeviceManager& deviceManager;
|
||||
ComboBox* audioDeviceDropDown;
|
||||
ComboBox* deviceTypeDropDown;
|
||||
Label* deviceTypeDropDownLabel;
|
||||
Component* audioDeviceSettingsComp;
|
||||
String audioDeviceSettingsCompType;
|
||||
const int minOutputChannels, maxOutputChannels, minInputChannels, maxInputChannels;
|
||||
|
||||
ComboBox* sampleRateDropDown;
|
||||
AudioDeviceSelectorComponentListBox* inputChansBox;
|
||||
Label* inputsLabel;
|
||||
AudioDeviceSelectorComponentListBox* outputChansBox;
|
||||
Label* outputsLabel;
|
||||
Label* sampleRateLabel;
|
||||
ComboBox* bufferSizeDropDown;
|
||||
Label* bufferSizeLabel;
|
||||
Button* launchUIButton;
|
||||
AudioDeviceSelectorComponentListBox* midiInputsList;
|
||||
MidiInputSelectorComponentListBox* midiInputsList;
|
||||
Label* midiInputsLabel;
|
||||
ComboBox* midiOutputSelector;
|
||||
Label* midiOutputLabel;
|
||||
|
|
@ -51562,7 +51571,7 @@ public:
|
|||
|
||||
@see newOpenGLContextCreated()
|
||||
*/
|
||||
OpenGLContext* getCurrentContext() const throw();
|
||||
OpenGLContext* getCurrentContext() const throw() { return context; }
|
||||
|
||||
/** Makes this component the current openGL context.
|
||||
|
||||
|
|
@ -53340,23 +53349,24 @@ END_JUCE_NAMESPACE
|
|||
|
||||
#ifdef _CONSOLE
|
||||
#define START_JUCE_APPLICATION(AppClass) \
|
||||
int main (int argc, char* argv[]) \
|
||||
int main (int, char* argv[]) \
|
||||
{ \
|
||||
return JUCE_NAMESPACE::JUCEApplication::main (argc, argv, new AppClass()); \
|
||||
JUCE_NAMESPACE::String commandLineString (JUCE_NAMESPACE::PlatformUtilities::getCurrentCommandLineParams()); \
|
||||
return JUCE_NAMESPACE::JUCEApplication::main (commandLineString, new AppClass()); \
|
||||
}
|
||||
#elif ! defined (_AFXDLL)
|
||||
#ifdef _WINDOWS_
|
||||
#define START_JUCE_APPLICATION(AppClass) \
|
||||
int WINAPI WinMain (HINSTANCE, HINSTANCE, LPSTR commandLine, int) \
|
||||
int WINAPI WinMain (HINSTANCE, HINSTANCE, LPSTR, int) \
|
||||
{ \
|
||||
JUCE_NAMESPACE::String commandLineString (commandLine); \
|
||||
JUCE_NAMESPACE::String commandLineString (JUCE_NAMESPACE::PlatformUtilities::getCurrentCommandLineParams()); \
|
||||
return JUCE_NAMESPACE::JUCEApplication::main (commandLineString, new AppClass()); \
|
||||
}
|
||||
#else
|
||||
#define START_JUCE_APPLICATION(AppClass) \
|
||||
int __stdcall WinMain (int, int, const char* commandLine, int) \
|
||||
int __stdcall WinMain (int, int, const char*, int) \
|
||||
{ \
|
||||
JUCE_NAMESPACE::String commandLineString (commandLine); \
|
||||
JUCE_NAMESPACE::String commandLineString (JUCE_NAMESPACE::PlatformUtilities::getCurrentCommandLineParams()); \
|
||||
return JUCE_NAMESPACE::JUCEApplication::main (commandLineString, new AppClass()); \
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -36,8 +36,30 @@ BEGIN_JUCE_NAMESPACE
|
|||
#include "juce_AudioDeviceManager.h"
|
||||
#include "../../gui/components/juce_Desktop.h"
|
||||
#include "../../../juce_core/text/juce_LocalisedStrings.h"
|
||||
#include "../dsp/juce_AudioSampleBuffer.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
AudioDeviceManager::AudioDeviceSetup::AudioDeviceSetup()
|
||||
: sampleRate (0),
|
||||
bufferSize (0),
|
||||
useDefaultInputChannels (true),
|
||||
useDefaultOutputChannels (true)
|
||||
{
|
||||
}
|
||||
|
||||
bool AudioDeviceManager::AudioDeviceSetup::operator== (const AudioDeviceManager::AudioDeviceSetup& other) const
|
||||
{
|
||||
return outputDeviceName == other.outputDeviceName
|
||||
&& inputDeviceName == other.inputDeviceName
|
||||
&& sampleRate == other.sampleRate
|
||||
&& bufferSize == other.bufferSize
|
||||
&& inputChannels == other.inputChannels
|
||||
&& useDefaultInputChannels == other.useDefaultInputChannels
|
||||
&& outputChannels == other.outputChannels
|
||||
&& useDefaultOutputChannels == other.useDefaultOutputChannels;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
AudioDeviceManager::AudioDeviceManager()
|
||||
: currentAudioDevice (0),
|
||||
|
|
@ -47,6 +69,9 @@ AudioDeviceManager::AudioDeviceManager()
|
|||
lastExplicitSettings (0),
|
||||
listNeedsScanning (true),
|
||||
useInputNames (false),
|
||||
inputLevelMeasurementEnabled (false),
|
||||
inputLevel (0),
|
||||
testSound (0),
|
||||
enabledMidiInputs (4),
|
||||
midiCallbacks (4),
|
||||
midiCallbackDevices (4),
|
||||
|
|
@ -55,19 +80,59 @@ AudioDeviceManager::AudioDeviceManager()
|
|||
timeToCpuScale (0)
|
||||
{
|
||||
callbackHandler.owner = this;
|
||||
|
||||
AudioIODeviceType::createDeviceTypes (availableDeviceTypes);
|
||||
}
|
||||
|
||||
AudioDeviceManager::~AudioDeviceManager()
|
||||
{
|
||||
stopDevice();
|
||||
deleteAndZero (currentAudioDevice);
|
||||
deleteAndZero (defaultMidiOutput);
|
||||
delete lastExplicitSettings;
|
||||
delete testSound;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
void AudioDeviceManager::createDeviceTypesIfNeeded()
|
||||
{
|
||||
if (availableDeviceTypes.size() == 0)
|
||||
{
|
||||
createAudioDeviceTypes (availableDeviceTypes);
|
||||
|
||||
while (lastDeviceTypeConfigs.size() < availableDeviceTypes.size())
|
||||
lastDeviceTypeConfigs.add (new AudioDeviceSetup());
|
||||
|
||||
if (availableDeviceTypes.size() > 0)
|
||||
currentDeviceType = availableDeviceTypes.getUnchecked(0)->getTypeName();
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
extern AudioIODeviceType* juce_createDefaultAudioIODeviceType();
|
||||
|
||||
#if JUCE_WIN32 && JUCE_ASIO
|
||||
extern AudioIODeviceType* juce_createASIOAudioIODeviceType();
|
||||
#endif
|
||||
|
||||
#if JUCE_WIN32 && JUCE_WDM_AUDIO
|
||||
extern AudioIODeviceType* juce_createWDMAudioIODeviceType();
|
||||
#endif
|
||||
|
||||
void AudioDeviceManager::createAudioDeviceTypes (OwnedArray <AudioIODeviceType>& list)
|
||||
{
|
||||
AudioIODeviceType* const defaultDeviceType = juce_createDefaultAudioIODeviceType();
|
||||
|
||||
if (defaultDeviceType != 0)
|
||||
list.add (defaultDeviceType);
|
||||
|
||||
#if JUCE_WIN32 && JUCE_ASIO
|
||||
list.add (juce_createASIOAudioIODeviceType());
|
||||
#endif
|
||||
|
||||
#if JUCE_WIN32 && JUCE_WDM_AUDIO
|
||||
list.add (juce_createWDMAudioIODeviceType());
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const String AudioDeviceManager::initialise (const int numInputChannelsNeeded,
|
||||
const int numOutputChannelsNeeded,
|
||||
|
|
@ -75,26 +140,51 @@ const String AudioDeviceManager::initialise (const int numInputChannelsNeeded,
|
|||
const bool selectDefaultDeviceOnFailure,
|
||||
const String& preferredDefaultDeviceName)
|
||||
{
|
||||
if (listNeedsScanning)
|
||||
refreshDeviceList();
|
||||
scanDevicesIfNeeded();
|
||||
|
||||
numInputChansNeeded = numInputChannelsNeeded;
|
||||
numOutputChansNeeded = numOutputChannelsNeeded;
|
||||
|
||||
if (e != 0 && e->hasTagName (T("DEVICESETUP")))
|
||||
{
|
||||
delete lastExplicitSettings;
|
||||
lastExplicitSettings = new XmlElement (*e);
|
||||
|
||||
BitArray ins, outs;
|
||||
ins.parseString (e->getStringAttribute (T("audioDeviceInChans"), T("11")), 2);
|
||||
outs.parseString (e->getStringAttribute (T("audioDeviceOutChans"), T("11")), 2);
|
||||
String error;
|
||||
AudioDeviceSetup setup;
|
||||
|
||||
String error (setAudioDevice (e->getStringAttribute (T("audioDeviceName")),
|
||||
e->getIntAttribute (T("audioDeviceBufferSize")),
|
||||
e->getDoubleAttribute (T("audioDeviceRate")),
|
||||
e->hasAttribute (T("audioDeviceInChans")) ? &ins : 0,
|
||||
e->hasAttribute (T("audioDeviceOutChans")) ? &outs : 0,
|
||||
true));
|
||||
if (e->getStringAttribute (T("audioDeviceName")).isNotEmpty())
|
||||
{
|
||||
setup.inputDeviceName = setup.outputDeviceName
|
||||
= e->getStringAttribute (T("audioDeviceName"));
|
||||
}
|
||||
else
|
||||
{
|
||||
setup.inputDeviceName = e->getStringAttribute (T("audioInputDeviceName"));
|
||||
setup.outputDeviceName = e->getStringAttribute (T("audioOutputDeviceName"));
|
||||
}
|
||||
|
||||
currentDeviceType = e->getStringAttribute (T("deviceType"));
|
||||
if (currentDeviceType.isEmpty())
|
||||
{
|
||||
AudioIODeviceType* const type = findType (setup.inputDeviceName, setup.outputDeviceName);
|
||||
|
||||
if (type != 0)
|
||||
currentDeviceType = type->getTypeName();
|
||||
else if (availableDeviceTypes.size() > 0)
|
||||
currentDeviceType = availableDeviceTypes[0]->getTypeName();
|
||||
}
|
||||
|
||||
setup.bufferSize = e->getIntAttribute (T("audioDeviceBufferSize"));
|
||||
setup.sampleRate = e->getDoubleAttribute (T("audioDeviceRate"));
|
||||
|
||||
setup.inputChannels.parseString (e->getStringAttribute (T("audioDeviceInChans"), T("11")), 2);
|
||||
setup.outputChannels.parseString (e->getStringAttribute (T("audioDeviceOutChans"), T("11")), 2);
|
||||
|
||||
setup.useDefaultInputChannels = ! e->hasAttribute (T("audioDeviceInChans"));
|
||||
setup.useDefaultOutputChannels = ! e->hasAttribute (T("audioDeviceOutChans"));
|
||||
|
||||
error = setAudioDeviceSetup (setup, true);
|
||||
|
||||
midiInsFromXml.clear();
|
||||
forEachXmlChildElementWithTagName (*e, c, T("MIDIINPUT"))
|
||||
|
|
@ -115,33 +205,54 @@ const String AudioDeviceManager::initialise (const int numInputChannelsNeeded,
|
|||
}
|
||||
else
|
||||
{
|
||||
setInputDeviceNamesUsed (numOutputChannelsNeeded == 0);
|
||||
|
||||
String defaultDevice;
|
||||
AudioDeviceSetup setup;
|
||||
|
||||
if (preferredDefaultDeviceName.isNotEmpty())
|
||||
{
|
||||
for (int i = 0; i < availableDeviceTypes.size(); ++i)
|
||||
for (int j = availableDeviceTypes.size(); --j >= 0;)
|
||||
{
|
||||
const StringArray devs (availableDeviceTypes.getUnchecked(i)->getDeviceNames());
|
||||
AudioIODeviceType* const type = availableDeviceTypes.getUnchecked(j);
|
||||
|
||||
for (int j = 0; j < devs.size(); ++j)
|
||||
StringArray outs (type->getDeviceNames (false));
|
||||
|
||||
int i;
|
||||
for (i = 0; i < outs.size(); ++i)
|
||||
{
|
||||
if (devs[j].matchesWildcard (preferredDefaultDeviceName, true))
|
||||
if (outs[i].matchesWildcard (preferredDefaultDeviceName, true))
|
||||
{
|
||||
defaultDevice = devs[j];
|
||||
setup.outputDeviceName = outs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
StringArray ins (type->getDeviceNames (true));
|
||||
|
||||
for (i = 0; i < ins.size(); ++i)
|
||||
{
|
||||
if (ins[i].matchesWildcard (preferredDefaultDeviceName, true))
|
||||
{
|
||||
setup.inputDeviceName = ins[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultDevice.isEmpty() && availableDeviceTypes [0] != 0)
|
||||
defaultDevice = availableDeviceTypes[0]->getDefaultDeviceName (numOutputChannelsNeeded == 0,
|
||||
numInputChannelsNeeded,
|
||||
numOutputChannelsNeeded);
|
||||
insertDefaultDeviceNames (setup);
|
||||
return setAudioDeviceSetup (setup, false);
|
||||
}
|
||||
}
|
||||
|
||||
return setAudioDevice (defaultDevice, 0, 0, 0, 0, false);
|
||||
void AudioDeviceManager::insertDefaultDeviceNames (AudioDeviceSetup& setup) const
|
||||
{
|
||||
AudioIODeviceType* type = getCurrentDeviceTypeObject();
|
||||
if (type != 0)
|
||||
{
|
||||
if (setup.outputDeviceName.isEmpty())
|
||||
setup.outputDeviceName = type->getDeviceNames (false) [type->getDefaultDeviceIndex (false)];
|
||||
|
||||
if (setup.inputDeviceName.isEmpty())
|
||||
setup.inputDeviceName = type->getDeviceNames (true) [type->getDefaultDeviceIndex (true)];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -151,144 +262,372 @@ XmlElement* AudioDeviceManager::createStateXml() const
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
const StringArray AudioDeviceManager::getAvailableAudioDeviceNames() const
|
||||
void AudioDeviceManager::scanDevicesIfNeeded()
|
||||
{
|
||||
if (listNeedsScanning)
|
||||
refreshDeviceList();
|
||||
|
||||
StringArray names;
|
||||
|
||||
for (int i = 0; i < availableDeviceTypes.size(); ++i)
|
||||
names.addArray (availableDeviceTypes[i]->getDeviceNames (useInputNames));
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
void AudioDeviceManager::refreshDeviceList() const
|
||||
{
|
||||
listNeedsScanning = false;
|
||||
|
||||
for (int i = 0; i < availableDeviceTypes.size(); ++i)
|
||||
availableDeviceTypes[i]->scanForDevices();
|
||||
}
|
||||
|
||||
void AudioDeviceManager::setInputDeviceNamesUsed (const bool useInputNames_)
|
||||
{
|
||||
useInputNames = useInputNames_;
|
||||
sendChangeMessage (this);
|
||||
}
|
||||
|
||||
void AudioDeviceManager::addDeviceNamesToComboBox (ComboBox& combo) const
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
for (int i = 0; i < availableDeviceTypes.size(); ++i)
|
||||
{
|
||||
AudioIODeviceType* const type = availableDeviceTypes[i];
|
||||
listNeedsScanning = false;
|
||||
|
||||
if (availableDeviceTypes.size() > 1)
|
||||
combo.addSectionHeading (type->getTypeName() + T(" devices:"));
|
||||
createDeviceTypesIfNeeded();
|
||||
|
||||
const StringArray names (type->getDeviceNames (useInputNames));
|
||||
for (int i = availableDeviceTypes.size(); --i >= 0;)
|
||||
availableDeviceTypes.getUnchecked(i)->scanForDevices();
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < names.size(); ++j)
|
||||
combo.addItem (names[j], ++n);
|
||||
AudioIODeviceType* AudioDeviceManager::findType (const String& inputName, const String& outputName)
|
||||
{
|
||||
scanDevicesIfNeeded();
|
||||
|
||||
combo.addSeparator();
|
||||
for (int i = availableDeviceTypes.size(); --i >= 0;)
|
||||
{
|
||||
AudioIODeviceType* const type = availableDeviceTypes.getUnchecked(i);
|
||||
|
||||
if ((inputName.isNotEmpty() && type->getDeviceNames (true).contains (inputName, true))
|
||||
|| (outputName.isNotEmpty() && type->getDeviceNames (false).contains (outputName, true)))
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
combo.addItem (TRANS("<< no audio device >>"), -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const String AudioDeviceManager::getCurrentAudioDeviceName() const
|
||||
void AudioDeviceManager::getAudioDeviceSetup (AudioDeviceSetup& setup)
|
||||
{
|
||||
if (currentAudioDevice != 0)
|
||||
return currentAudioDevice->getName();
|
||||
|
||||
return String::empty;
|
||||
setup = currentSetup;
|
||||
}
|
||||
|
||||
const String AudioDeviceManager::setAudioDevice (const String& deviceNameToUse,
|
||||
int blockSizeToUse,
|
||||
double sampleRateToUse,
|
||||
const BitArray* inChans,
|
||||
const BitArray* outChans,
|
||||
const bool treatAsChosenDevice)
|
||||
void AudioDeviceManager::deleteCurrentDevice()
|
||||
{
|
||||
deleteAndZero (currentAudioDevice);
|
||||
currentSetup.inputDeviceName = String::empty;
|
||||
currentSetup.outputDeviceName = String::empty;
|
||||
}
|
||||
|
||||
void AudioDeviceManager::setCurrentAudioDeviceType (const String& type,
|
||||
const bool treatAsChosenDevice)
|
||||
{
|
||||
for (int i = 0; i < availableDeviceTypes.size(); ++i)
|
||||
{
|
||||
if (availableDeviceTypes.getUnchecked(i)->getTypeName() == type
|
||||
&& currentDeviceType != type)
|
||||
{
|
||||
currentDeviceType = type;
|
||||
|
||||
AudioDeviceSetup s (*lastDeviceTypeConfigs.getUnchecked(i));
|
||||
insertDefaultDeviceNames (s);
|
||||
|
||||
setAudioDeviceSetup (s, treatAsChosenDevice);
|
||||
|
||||
sendChangeMessage (this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AudioIODeviceType* AudioDeviceManager::getCurrentDeviceTypeObject() const
|
||||
{
|
||||
for (int i = 0; i < availableDeviceTypes.size(); ++i)
|
||||
if (availableDeviceTypes[i]->getTypeName() == currentDeviceType)
|
||||
return availableDeviceTypes[i];
|
||||
|
||||
return availableDeviceTypes[0];
|
||||
}
|
||||
|
||||
const String AudioDeviceManager::setAudioDeviceSetup (const AudioDeviceSetup& newSetup,
|
||||
const bool treatAsChosenDevice)
|
||||
{
|
||||
jassert (&newSetup != ¤tSetup); // this will have no effect
|
||||
|
||||
if (newSetup == currentSetup && currentAudioDevice != 0)
|
||||
return String::empty;
|
||||
|
||||
if (! (newSetup == currentSetup))
|
||||
sendChangeMessage (this);
|
||||
|
||||
stopDevice();
|
||||
String error;
|
||||
AudioIODeviceType* type = getCurrentDeviceTypeObject();
|
||||
|
||||
if (type == 0 || (newSetup.inputDeviceName.isEmpty()
|
||||
&& newSetup.outputDeviceName.isEmpty()))
|
||||
{
|
||||
deleteCurrentDevice();
|
||||
|
||||
if (treatAsChosenDevice)
|
||||
updateXml();
|
||||
|
||||
return String::empty;
|
||||
}
|
||||
|
||||
if (currentSetup.inputDeviceName != newSetup.inputDeviceName
|
||||
|| currentSetup.outputDeviceName != newSetup.outputDeviceName
|
||||
|| currentAudioDevice == 0)
|
||||
{
|
||||
deleteCurrentDevice();
|
||||
scanDevicesIfNeeded();
|
||||
|
||||
if (newSetup.outputDeviceName.isNotEmpty()
|
||||
&& ! type->getDeviceNames (false).contains (newSetup.outputDeviceName))
|
||||
{
|
||||
return "No such device: " + newSetup.outputDeviceName;
|
||||
}
|
||||
|
||||
if (newSetup.inputDeviceName.isNotEmpty()
|
||||
&& ! type->getDeviceNames (true).contains (newSetup.inputDeviceName))
|
||||
{
|
||||
return "No such device: " + newSetup.outputDeviceName;
|
||||
}
|
||||
|
||||
currentAudioDevice = type->createDevice (newSetup.outputDeviceName,
|
||||
newSetup.inputDeviceName);
|
||||
|
||||
if (currentAudioDevice == 0)
|
||||
error = "Can't open device";
|
||||
else
|
||||
error = currentAudioDevice->getLastError();
|
||||
|
||||
if (error.isNotEmpty())
|
||||
{
|
||||
deleteCurrentDevice();
|
||||
return error;
|
||||
}
|
||||
|
||||
inputChannels.clear();
|
||||
inputChannels.setRange (0, numInputChansNeeded, true);
|
||||
outputChannels.clear();
|
||||
outputChannels.setRange (0, numOutputChansNeeded, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! newSetup.useDefaultInputChannels)
|
||||
inputChannels = newSetup.inputChannels;
|
||||
|
||||
if (! newSetup.useDefaultOutputChannels)
|
||||
outputChannels = newSetup.outputChannels;
|
||||
}
|
||||
|
||||
currentSetup = newSetup;
|
||||
|
||||
currentSetup.sampleRate = chooseBestSampleRate (newSetup.sampleRate);
|
||||
|
||||
error = currentAudioDevice->open (inputChannels,
|
||||
outputChannels,
|
||||
currentSetup.sampleRate,
|
||||
currentSetup.bufferSize);
|
||||
|
||||
if (error.isEmpty())
|
||||
{
|
||||
currentDeviceType = currentAudioDevice->getTypeName();
|
||||
|
||||
currentAudioDevice->start (&callbackHandler);
|
||||
|
||||
currentSetup.sampleRate = currentAudioDevice->getCurrentSampleRate();
|
||||
currentSetup.bufferSize = currentAudioDevice->getCurrentBufferSizeSamples();
|
||||
currentSetup.inputChannels = currentAudioDevice->getActiveInputChannels();
|
||||
currentSetup.outputChannels = currentAudioDevice->getActiveOutputChannels();
|
||||
|
||||
for (int i = 0; i < availableDeviceTypes.size(); ++i)
|
||||
if (availableDeviceTypes.getUnchecked (i)->getTypeName() == currentDeviceType)
|
||||
*(lastDeviceTypeConfigs.getUnchecked (i)) = currentSetup;
|
||||
|
||||
if (treatAsChosenDevice)
|
||||
updateXml();
|
||||
}
|
||||
else
|
||||
{
|
||||
deleteCurrentDevice();
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
double AudioDeviceManager::chooseBestSampleRate (double rate) const
|
||||
{
|
||||
jassert (currentAudioDevice != 0);
|
||||
|
||||
if (rate > 0)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
for (int i = currentAudioDevice->getNumSampleRates(); --i >= 0;)
|
||||
{
|
||||
const double sr = currentAudioDevice->getSampleRate (i);
|
||||
|
||||
if (sr == rate)
|
||||
ok = true;
|
||||
}
|
||||
|
||||
if (! ok)
|
||||
rate = 0;
|
||||
}
|
||||
|
||||
if (rate == 0)
|
||||
{
|
||||
double lowestAbove44 = 0.0;
|
||||
|
||||
for (int i = currentAudioDevice->getNumSampleRates(); --i >= 0;)
|
||||
{
|
||||
const double sr = currentAudioDevice->getSampleRate (i);
|
||||
|
||||
if (sr >= 44100.0 && (lowestAbove44 == 0 || sr < lowestAbove44))
|
||||
lowestAbove44 = sr;
|
||||
}
|
||||
|
||||
if (lowestAbove44 == 0.0)
|
||||
rate = currentAudioDevice->getSampleRate (0);
|
||||
else
|
||||
rate = lowestAbove44;
|
||||
}
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
/*const String AudioDeviceManager::setAudioDevices (const String& outputDeviceName,
|
||||
const String& inputDeviceName,
|
||||
int blockSizeToUse,
|
||||
double sampleRateToUse,
|
||||
const BitArray* inChans,
|
||||
const BitArray* outChans,
|
||||
const bool treatAsChosenDevice)
|
||||
{
|
||||
stopDevice();
|
||||
|
||||
String error;
|
||||
|
||||
if (deviceNameToUse.isNotEmpty())
|
||||
if (outputDeviceName.isNotEmpty() || inputDeviceName.isNotEmpty())
|
||||
{
|
||||
const StringArray devNames (getAvailableAudioDeviceNames());
|
||||
const StringArray outputNames (getAvailableAudioOutputDeviceNames());
|
||||
int outputIndex = outputNames.indexOf (outputDeviceName);
|
||||
|
||||
int index = devNames.indexOf (deviceNameToUse, true);
|
||||
|
||||
if (index >= 0)
|
||||
if (outputIndex < 0 && outputDeviceName.isNotEmpty())
|
||||
{
|
||||
if (currentAudioDevice == 0
|
||||
|| currentAudioDevice->getLastError().isNotEmpty()
|
||||
|| ! deviceNameToUse.equalsIgnoreCase (currentAudioDevice->getName()))
|
||||
deleteDevices();
|
||||
error << "No such device: " << outputDeviceName;
|
||||
return error;
|
||||
}
|
||||
|
||||
const StringArray inputNames (getAvailableAudioInputDeviceNames());
|
||||
int inputIndex = inputNames.indexOf (inputDeviceName);
|
||||
|
||||
if (inputIndex < 0 && inputDeviceName.isNotEmpty())
|
||||
{
|
||||
deleteDevices();
|
||||
error << "No such device: " << inputDeviceName;
|
||||
return error;
|
||||
}
|
||||
|
||||
if (currentAudioInputDevice == 0
|
||||
|| currentAudioInputDevice->getLastError().isNotEmpty()
|
||||
|| ! inputDeviceName.equalsIgnoreCase (currentAudioInputDevice->getName())
|
||||
|| currentAudioOutputDevice == 0
|
||||
|| currentAudioOutputDevice->getLastError().isNotEmpty()
|
||||
|| ! outputDeviceName.equalsIgnoreCase (currentAudioOutputDevice->getName()))
|
||||
{
|
||||
// change of device..
|
||||
deleteDevices();
|
||||
|
||||
int n = 0;
|
||||
|
||||
for (int i = 0; i < availableDeviceTypes.size(); ++i)
|
||||
{
|
||||
// change of device..
|
||||
deleteAndZero (currentAudioDevice);
|
||||
AudioIODeviceType* const type = availableDeviceTypes[i];
|
||||
const StringArray names (type->getDeviceNames (true));
|
||||
|
||||
int n = 0;
|
||||
if (inputIndex >= n && inputIndex < n + names.size())
|
||||
{
|
||||
currentAudioInputDevice = type->createDevice (inputDeviceName);
|
||||
|
||||
if (currentAudioInputDevice == 0)
|
||||
error = "Can't open device: " + inputDeviceName;
|
||||
else
|
||||
error = currentAudioInputDevice->getLastError();
|
||||
|
||||
if (error.isNotEmpty())
|
||||
{
|
||||
deleteDevices();
|
||||
return error;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
n += names.size();
|
||||
}
|
||||
|
||||
//xxx
|
||||
if (true)//inputDeviceName != outputDeviceName)
|
||||
{
|
||||
// Using different input and output devices..
|
||||
n = 0;
|
||||
for (int i = 0; i < availableDeviceTypes.size(); ++i)
|
||||
{
|
||||
AudioIODeviceType* const type = availableDeviceTypes[i];
|
||||
const StringArray names (type->getDeviceNames (useInputNames));
|
||||
const StringArray names (type->getDeviceNames (false));
|
||||
|
||||
if (index >= n && index < n + names.size())
|
||||
if (outputIndex >= n && outputIndex < n + names.size())
|
||||
{
|
||||
currentAudioDevice = type->createDevice (deviceNameToUse);
|
||||
currentAudioOutputDevice = type->createDevice (outputDeviceName);
|
||||
|
||||
if (currentAudioOutputDevice == 0)
|
||||
error = "Can't open device: " + outputDeviceName;
|
||||
else
|
||||
error = currentAudioOutputDevice->getLastError();
|
||||
|
||||
if (error.isNotEmpty())
|
||||
{
|
||||
deleteDevices();
|
||||
return error;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
n += names.size();
|
||||
}
|
||||
|
||||
error = currentAudioDevice->getLastError();
|
||||
|
||||
if (error.isNotEmpty())
|
||||
if (currentAudioInputDevice != 0 && currentAudioOutputDevice != 0)
|
||||
{
|
||||
deleteAndZero (currentAudioDevice);
|
||||
return error;
|
||||
//xxx enable this optim
|
||||
}
|
||||
|
||||
inputChannels.clear();
|
||||
inputChannels.setRange (0, numInputChansNeeded, true);
|
||||
outputChannels.clear();
|
||||
outputChannels.setRange (0, numOutputChansNeeded, true);
|
||||
ConglomeratingAudioIODevice* const combiner = new ConglomeratingAudioIODevice();
|
||||
combiner->addDevice (currentAudioInputDevice, false, true);
|
||||
combiner->addDevice (currentAudioOutputDevice, true, false);
|
||||
|
||||
currentAudioDevice = combiner;
|
||||
}
|
||||
|
||||
if (inChans != 0)
|
||||
inputChannels = *inChans;
|
||||
|
||||
if (outChans != 0)
|
||||
outputChannels = *outChans;
|
||||
|
||||
error = restartDevice (blockSizeToUse,
|
||||
sampleRateToUse,
|
||||
inputChannels,
|
||||
outputChannels);
|
||||
|
||||
if (error.isNotEmpty())
|
||||
else
|
||||
{
|
||||
deleteAndZero (currentAudioDevice);
|
||||
// Using a single device for in + out..
|
||||
currentAudioOutputDevice = currentAudioInputDevice;
|
||||
currentAudioDevice = currentAudioInputDevice;
|
||||
}
|
||||
|
||||
inputChannels.clear();
|
||||
inputChannels.setRange (0, numInputChansNeeded, true);
|
||||
outputChannels.clear();
|
||||
outputChannels.setRange (0, numOutputChansNeeded, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
deleteAndZero (currentAudioDevice);
|
||||
error << "No such device: " << deviceNameToUse;
|
||||
}
|
||||
|
||||
if (inChans != 0)
|
||||
inputChannels = *inChans;
|
||||
|
||||
if (outChans != 0)
|
||||
outputChannels = *outChans;
|
||||
|
||||
error = restartDevice (blockSizeToUse,
|
||||
sampleRateToUse,
|
||||
inputChannels,
|
||||
outputChannels);
|
||||
|
||||
if (error.isNotEmpty())
|
||||
deleteDevices();
|
||||
}
|
||||
else
|
||||
{
|
||||
deleteAndZero (currentAudioDevice);
|
||||
deleteDevices();
|
||||
}
|
||||
|
||||
if (treatAsChosenDevice && error.isEmpty())
|
||||
|
|
@ -342,7 +681,7 @@ const String AudioDeviceManager::restartDevice (int blockSizeToUse,
|
|||
}
|
||||
|
||||
const String error (currentAudioDevice->open (inChans, outChans,
|
||||
sampleRateToUse, blockSizeToUse));
|
||||
sampleRateToUse, blockSizeToUse));
|
||||
|
||||
if (error.isEmpty())
|
||||
currentAudioDevice->start (&callbackHandler);
|
||||
|
|
@ -350,7 +689,7 @@ const String AudioDeviceManager::restartDevice (int blockSizeToUse,
|
|||
sendChangeMessage (this);
|
||||
return error;
|
||||
}
|
||||
|
||||
*/
|
||||
void AudioDeviceManager::stopDevice()
|
||||
{
|
||||
if (currentAudioDevice != 0)
|
||||
|
|
@ -359,25 +698,16 @@ void AudioDeviceManager::stopDevice()
|
|||
|
||||
void AudioDeviceManager::closeAudioDevice()
|
||||
{
|
||||
if (currentAudioDevice != 0)
|
||||
{
|
||||
lastRunningDevice = currentAudioDevice->getName();
|
||||
lastRunningBlockSize = currentAudioDevice->getCurrentBufferSizeSamples();
|
||||
lastRunningSampleRate = currentAudioDevice->getCurrentSampleRate();
|
||||
lastRunningIns = inputChannels;
|
||||
lastRunningOuts = outputChannels;
|
||||
|
||||
stopDevice();
|
||||
|
||||
setAudioDevice (String::empty, 0, 0, 0, 0, false);
|
||||
}
|
||||
stopDevice();
|
||||
deleteAndZero (currentAudioDevice);
|
||||
}
|
||||
|
||||
void AudioDeviceManager::restartLastAudioDevice()
|
||||
{
|
||||
if (currentAudioDevice == 0)
|
||||
{
|
||||
if (lastRunningDevice.isEmpty())
|
||||
if (currentSetup.inputDeviceName.isEmpty()
|
||||
&& currentSetup.outputDeviceName.isEmpty())
|
||||
{
|
||||
// This method will only reload the last device that was running
|
||||
// before closeAudioDevice() was called - you need to actually open
|
||||
|
|
@ -386,50 +716,19 @@ void AudioDeviceManager::restartLastAudioDevice()
|
|||
return;
|
||||
}
|
||||
|
||||
setAudioDevice (lastRunningDevice,
|
||||
lastRunningBlockSize,
|
||||
lastRunningSampleRate,
|
||||
&lastRunningIns,
|
||||
&lastRunningOuts,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDeviceManager::setInputChannels (const BitArray& newEnabledChannels,
|
||||
const bool treatAsChosenDevice)
|
||||
{
|
||||
if (currentAudioDevice != 0
|
||||
&& newEnabledChannels != inputChannels)
|
||||
{
|
||||
setAudioDevice (currentAudioDevice->getName(),
|
||||
currentAudioDevice->getCurrentBufferSizeSamples(),
|
||||
currentAudioDevice->getCurrentSampleRate(),
|
||||
&newEnabledChannels, 0,
|
||||
treatAsChosenDevice);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDeviceManager::setOutputChannels (const BitArray& newEnabledChannels,
|
||||
const bool treatAsChosenDevice)
|
||||
{
|
||||
if (currentAudioDevice != 0
|
||||
&& newEnabledChannels != outputChannels)
|
||||
{
|
||||
setAudioDevice (currentAudioDevice->getName(),
|
||||
currentAudioDevice->getCurrentBufferSizeSamples(),
|
||||
currentAudioDevice->getCurrentSampleRate(),
|
||||
0, &newEnabledChannels,
|
||||
treatAsChosenDevice);
|
||||
AudioDeviceSetup s (currentSetup);
|
||||
setAudioDeviceSetup (s, false);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDeviceManager::updateXml()
|
||||
{
|
||||
delete lastExplicitSettings;
|
||||
|
||||
lastExplicitSettings = new XmlElement (T("DEVICESETUP"));
|
||||
|
||||
lastExplicitSettings->setAttribute (T("audioDeviceName"), getCurrentAudioDeviceName());
|
||||
lastExplicitSettings->setAttribute (T("deviceType"), currentDeviceType);
|
||||
lastExplicitSettings->setAttribute (T("audioOutputDeviceName"), currentSetup.outputDeviceName);
|
||||
lastExplicitSettings->setAttribute (T("audioInputDeviceName"), currentSetup.inputDeviceName);
|
||||
|
||||
if (currentAudioDevice != 0)
|
||||
{
|
||||
|
|
@ -438,8 +737,11 @@ void AudioDeviceManager::updateXml()
|
|||
if (currentAudioDevice->getDefaultBufferSize() != currentAudioDevice->getCurrentBufferSizeSamples())
|
||||
lastExplicitSettings->setAttribute (T("audioDeviceBufferSize"), currentAudioDevice->getCurrentBufferSizeSamples());
|
||||
|
||||
lastExplicitSettings->setAttribute (T("audioDeviceInChans"), inputChannels.toString (2));
|
||||
lastExplicitSettings->setAttribute (T("audioDeviceOutChans"), outputChannels.toString (2));
|
||||
if (! currentSetup.useDefaultInputChannels)
|
||||
lastExplicitSettings->setAttribute (T("audioDeviceInChans"), currentSetup.inputChannels.toString (2));
|
||||
|
||||
if (! currentSetup.useDefaultOutputChannels)
|
||||
lastExplicitSettings->setAttribute (T("audioDeviceOutChans"), currentSetup.outputChannels.toString (2));
|
||||
}
|
||||
|
||||
for (int i = 0; i < enabledMidiInputs.size(); ++i)
|
||||
|
|
@ -497,21 +799,43 @@ void AudioDeviceManager::setAudioCallback (AudioIODeviceCallback* newCallback)
|
|||
}
|
||||
|
||||
void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelData,
|
||||
int totalNumInputChannels,
|
||||
int numInputChannels,
|
||||
float** outputChannelData,
|
||||
int totalNumOutputChannels,
|
||||
int numOutputChannels,
|
||||
int numSamples)
|
||||
{
|
||||
const ScopedLock sl (audioCallbackLock);
|
||||
|
||||
if (inputLevelMeasurementEnabled)
|
||||
{
|
||||
for (int j = 0; j < numSamples; ++j)
|
||||
{
|
||||
float s = 0;
|
||||
|
||||
for (int i = 0; i < numInputChannels; ++i)
|
||||
s += fabsf (inputChannelData[i][j]);
|
||||
|
||||
s /= numInputChannels;
|
||||
|
||||
const double decayFactor = 0.99992;
|
||||
|
||||
if (s > inputLevel)
|
||||
inputLevel = s;
|
||||
else if (inputLevel > 0.001f)
|
||||
inputLevel *= decayFactor;
|
||||
else
|
||||
inputLevel = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentCallback != 0)
|
||||
{
|
||||
const double callbackStartTime = Time::getMillisecondCounterHiRes();
|
||||
|
||||
currentCallback->audioDeviceIOCallback (inputChannelData,
|
||||
totalNumInputChannels,
|
||||
numInputChannels,
|
||||
outputChannelData,
|
||||
totalNumOutputChannels,
|
||||
numOutputChannels,
|
||||
numSamples);
|
||||
|
||||
const double msTaken = Time::getMillisecondCounterHiRes() - callbackStartTime;
|
||||
|
|
@ -520,9 +844,25 @@ void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelDat
|
|||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < totalNumOutputChannels; ++i)
|
||||
if (outputChannelData [i] != 0)
|
||||
zeromem (outputChannelData[i], sizeof (float) * numSamples);
|
||||
for (int i = 0; i < numOutputChannels; ++i)
|
||||
zeromem (outputChannelData[i], sizeof (float) * numSamples);
|
||||
}
|
||||
|
||||
if (testSound != 0)
|
||||
{
|
||||
const int numSamps = jmin (numSamples, testSound->getNumSamples() - testSoundPosition);
|
||||
const float* const src = testSound->getSampleData (0, testSoundPosition);
|
||||
|
||||
for (int i = 0; i < numOutputChannels; ++i)
|
||||
for (int j = 0; j < numSamps; ++j)
|
||||
outputChannelData [i][j] += src[j];
|
||||
|
||||
testSoundPosition += numSamps;
|
||||
if (testSoundPosition >= testSound->getNumSamples())
|
||||
{
|
||||
delete testSound;
|
||||
testSound = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -605,7 +945,7 @@ bool AudioDeviceManager::isMidiInputEnabled (const String& name) const
|
|||
void AudioDeviceManager::addMidiInputCallback (const String& name,
|
||||
MidiInputCallback* callback)
|
||||
{
|
||||
removeMidiInputCallback (callback);
|
||||
removeMidiInputCallback (name, callback);
|
||||
|
||||
if (name.isEmpty())
|
||||
{
|
||||
|
|
@ -632,13 +972,24 @@ void AudioDeviceManager::addMidiInputCallback (const String& name,
|
|||
}
|
||||
}
|
||||
|
||||
void AudioDeviceManager::removeMidiInputCallback (MidiInputCallback* callback)
|
||||
void AudioDeviceManager::removeMidiInputCallback (const String& name,
|
||||
MidiInputCallback* /*callback*/)
|
||||
{
|
||||
const ScopedLock sl (midiCallbackLock);
|
||||
|
||||
const int index = midiCallbacks.indexOf (callback);
|
||||
midiCallbacks.remove (index);
|
||||
midiCallbackDevices.remove (index);
|
||||
for (int i = midiCallbacks.size(); --i >= 0;)
|
||||
{
|
||||
String devName;
|
||||
|
||||
if (midiCallbackDevices.getUnchecked(i) != 0)
|
||||
devName = midiCallbackDevices.getUnchecked(i)->getName();
|
||||
|
||||
if (devName == name)
|
||||
{
|
||||
midiCallbacks.remove (i);
|
||||
midiCallbackDevices.remove (i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDeviceManager::handleIncomingMidiMessageInt (MidiInput* source,
|
||||
|
|
@ -678,12 +1029,12 @@ void AudioDeviceManager::setDefaultMidiOutput (const String& deviceName)
|
|||
|
||||
//==============================================================================
|
||||
void AudioDeviceManager::CallbackHandler::audioDeviceIOCallback (const float** inputChannelData,
|
||||
int totalNumInputChannels,
|
||||
int numInputChannels,
|
||||
float** outputChannelData,
|
||||
int totalNumOutputChannels,
|
||||
int numOutputChannels,
|
||||
int numSamples)
|
||||
{
|
||||
owner->audioDeviceIOCallbackInt (inputChannelData, totalNumInputChannels, outputChannelData, totalNumOutputChannels, numSamples);
|
||||
owner->audioDeviceIOCallbackInt (inputChannelData, numInputChannels, outputChannelData, numOutputChannels, numSamples);
|
||||
}
|
||||
|
||||
void AudioDeviceManager::CallbackHandler::audioDeviceAboutToStart (AudioIODevice* device)
|
||||
|
|
@ -701,5 +1052,56 @@ void AudioDeviceManager::CallbackHandler::handleIncomingMidiMessage (MidiInput*
|
|||
owner->handleIncomingMidiMessageInt (source, message);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void AudioDeviceManager::playTestSound()
|
||||
{
|
||||
audioCallbackLock.enter();
|
||||
AudioSampleBuffer* oldSound = testSound;
|
||||
testSound = 0;
|
||||
audioCallbackLock.exit();
|
||||
delete oldSound;
|
||||
|
||||
testSoundPosition = 0;
|
||||
|
||||
if (currentAudioDevice != 0)
|
||||
{
|
||||
const double sampleRate = currentAudioDevice->getCurrentSampleRate();
|
||||
const int soundLength = (int) sampleRate;
|
||||
|
||||
AudioSampleBuffer* const newSound = new AudioSampleBuffer (1, soundLength);
|
||||
float* samples = newSound->getSampleData (0);
|
||||
|
||||
const double frequency = MidiMessage::getMidiNoteInHertz (80);
|
||||
const float amplitude = 0.5f;
|
||||
|
||||
const double phasePerSample = double_Pi * 2.0 / (sampleRate / frequency);
|
||||
|
||||
for (int i = 0; i < soundLength; ++i)
|
||||
samples[i] = amplitude * (float) sin (i * phasePerSample);
|
||||
|
||||
newSound->applyGainRamp (0, 0, soundLength / 10, 0.0f, 1.0f);
|
||||
newSound->applyGainRamp (0, soundLength - soundLength / 4, soundLength / 4, 1.0f, 0.0f);
|
||||
|
||||
const ScopedLock sl (audioCallbackLock);
|
||||
testSound = newSound;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDeviceManager::enableInputLevelMeasurement (const bool enableMeasurement)
|
||||
{
|
||||
if (inputLevelMeasurementEnabled != enableMeasurement)
|
||||
{
|
||||
const ScopedLock sl (audioCallbackLock);
|
||||
inputLevelMeasurementEnabled = enableMeasurement;
|
||||
inputLevel = 0;
|
||||
}
|
||||
}
|
||||
|
||||
double AudioDeviceManager::getCurrentInputLevel() const
|
||||
{
|
||||
jassert (inputLevelMeasurementEnabled); // you need to call enableInputLevelMeasurement() before using this!
|
||||
return inputLevel;
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#include "juce_MidiOutput.h"
|
||||
#include "../../../juce_core/text/juce_XmlElement.h"
|
||||
#include "../../gui/components/controls/juce_ComboBox.h"
|
||||
#include "../dsp/juce_AudioSampleBuffer.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -130,54 +131,42 @@ public:
|
|||
*/
|
||||
XmlElement* createStateXml() const;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a list of the audio devices that can be used.
|
||||
|
||||
On Windows, this will include both DSound and ASIO devices if they are available. On
|
||||
the Mac, it'll be a list of the CoreAudio devices.
|
||||
|
||||
These names are used by setAudioDevice() when changing devices.
|
||||
/**
|
||||
*/
|
||||
const StringArray getAvailableAudioDeviceNames() const;
|
||||
struct AudioDeviceSetup
|
||||
{
|
||||
AudioDeviceSetup();
|
||||
|
||||
/** Rescans the list of known audio devices, in case it's changed. */
|
||||
void refreshDeviceList() const;
|
||||
bool operator== (const AudioDeviceSetup& other) const;
|
||||
|
||||
/** Sets a flag to indicate that when listing audio device names, it should treat them
|
||||
as inputs rather than outputs.
|
||||
/**
|
||||
*/
|
||||
String outputDeviceName;
|
||||
/**
|
||||
*/
|
||||
String inputDeviceName;
|
||||
/**
|
||||
*/
|
||||
double sampleRate;
|
||||
/**
|
||||
*/
|
||||
int bufferSize;
|
||||
/**
|
||||
*/
|
||||
BitArray inputChannels;
|
||||
bool useDefaultInputChannels;
|
||||
/**
|
||||
*/
|
||||
BitArray outputChannels;
|
||||
bool useDefaultOutputChannels;
|
||||
};
|
||||
|
||||
This only really applies to DirectSound, where input and output devices are
|
||||
separate. On ASIO and CoreAudio this makes no difference.
|
||||
|
||||
@see getAvailableAudioDeviceNames
|
||||
/**
|
||||
*/
|
||||
void setInputDeviceNamesUsed (const bool useInputNames);
|
||||
void getAudioDeviceSetup (AudioDeviceSetup& setup);
|
||||
|
||||
/** Just adds the list of device names to a combo box.
|
||||
|
||||
The only reason this is in this class is so that it can divide DSound
|
||||
and ASIO devices into labelled sections, which makes it look much neater.
|
||||
*/
|
||||
void addDeviceNamesToComboBox (ComboBox& combo) const;
|
||||
|
||||
/** Changes the audio device that should be used.
|
||||
|
||||
If deviceName is empty or not a valid name returned by getAvailableAudioDeviceNames(),
|
||||
it will disable the current device.
|
||||
|
||||
@param deviceName the name of the device you want to use (or an empty string to
|
||||
deselect the current device)
|
||||
@param blockSizeToUse the samples-per-block you want to use, or 0 to use a default
|
||||
value
|
||||
@param sampleRateToUse the target sample-rate, or 0 to use a default that the device
|
||||
is capable of
|
||||
@param inputChans which of the audio device's input channels to open - pass 0 to
|
||||
open as many of the the first ones as are needed for the number
|
||||
of input channels that the app has requested
|
||||
@param outputChans which of the audio device's input channels to open - pass 0 to
|
||||
open as many of the the first ones as are needed for the number
|
||||
of output channels that the app has requested
|
||||
/**
|
||||
@param treatAsChosenDevice if this is true and if the device opens correctly, these new
|
||||
settings will be taken as having been explicitly chosen by the
|
||||
user, and the next time createStateXml() is called, these settings
|
||||
|
|
@ -185,15 +174,18 @@ public:
|
|||
temporary or default device, and a call to createStateXml() will
|
||||
return either the last settings that were made with treatAsChosenDevice
|
||||
as true, or the last XML settings that were passed into initialise().
|
||||
|
||||
@returns an error message if anything went wrong, or an empty string if it worked ok.
|
||||
*/
|
||||
const String setAudioDevice (const String& deviceName,
|
||||
int blockSizeToUse,
|
||||
double sampleRateToUse,
|
||||
const BitArray* inputChans,
|
||||
const BitArray* outputChans,
|
||||
const bool treatAsChosenDevice);
|
||||
const String setAudioDeviceSetup (const AudioDeviceSetup& newSetup,
|
||||
const bool treatAsChosenDevice);
|
||||
|
||||
|
||||
/** Returns the currently-active audio device. */
|
||||
AudioIODevice* getCurrentAudioDevice() const throw() { return currentAudioDevice; }
|
||||
|
||||
const String getCurrentAudioDeviceType() const throw() { return currentDeviceType; }
|
||||
void setCurrentAudioDeviceType (const String& type,
|
||||
const bool treatAsChosenDevice);
|
||||
|
||||
/** Closes the currently-open device.
|
||||
|
||||
|
|
@ -212,59 +204,7 @@ public:
|
|||
*/
|
||||
void restartLastAudioDevice();
|
||||
|
||||
/** Returns the name of the currently selected audio device.
|
||||
|
||||
This will be an empty string if none is active.
|
||||
*/
|
||||
const String getCurrentAudioDeviceName() const;
|
||||
|
||||
/** Returns the currently-active audio device. */
|
||||
AudioIODevice* getCurrentAudioDevice() const throw() { return currentAudioDevice; }
|
||||
|
||||
/** Returns the set of audio input channels currently being used.
|
||||
|
||||
To select different channels, use setInputChannels(), or call setAudioDevice() to
|
||||
reopen the device with a different set of channels.
|
||||
*/
|
||||
const BitArray getInputChannels() const throw() { return inputChannels; }
|
||||
|
||||
/** Changes the active set of input channels.
|
||||
|
||||
@param newEnabledChannels the set of channels to enable
|
||||
@param treatAsChosenDevice if this is true and if the device opens correctly, these new
|
||||
settings will be taken as having been explicitly chosen by the
|
||||
user, and the next time createStateXml() is called, these settings
|
||||
will be returned. If it's false, then the device is treated as a
|
||||
temporary or default device, and a call to createStateXml() will
|
||||
return either the last settings that were made with treatAsChosenDevice
|
||||
as true, or the last XML settings that were passed into initialise().
|
||||
@see getInputChannels
|
||||
*/
|
||||
void setInputChannels (const BitArray& newEnabledChannels,
|
||||
const bool treatAsChosenDevice);
|
||||
|
||||
/** Returns the set of audio output channels currently being used.
|
||||
|
||||
To select different channels, use setOutputChannels(), or call setAudioDevice() to
|
||||
reopen the device with a different set of channels.
|
||||
*/
|
||||
const BitArray getOutputChannels() const throw() { return outputChannels; }
|
||||
|
||||
/** Changes the active set of output channels.
|
||||
|
||||
@param newEnabledChannels the set of channels to enable
|
||||
@param treatAsChosenDevice if this is true and if the device opens correctly, these new
|
||||
settings will be taken as having been explicitly chosen by the
|
||||
user, and the next time createStateXml() is called, these settings
|
||||
will be returned. If it's false, then the device is treated as a
|
||||
temporary or default device, and a call to createStateXml() will
|
||||
return either the last settings that were made with treatAsChosenDevice
|
||||
as true, or the last XML settings that were passed into initialise().
|
||||
@see getOutputChannels
|
||||
*/
|
||||
void setOutputChannels (const BitArray& newEnabledChannels,
|
||||
const bool treatAsChosenDevice);
|
||||
|
||||
//==============================================================================
|
||||
/** Gives the manager an audio callback to use.
|
||||
|
||||
The manager will redirect callbacks from whatever audio device is currently
|
||||
|
|
@ -274,6 +214,7 @@ public:
|
|||
*/
|
||||
void setAudioCallback (AudioIODeviceCallback* newCallback);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the average proportion of available CPU being spent inside the audio callbacks.
|
||||
|
||||
Returns a value between 0 and 1.0
|
||||
|
|
@ -323,7 +264,8 @@ public:
|
|||
|
||||
/** Removes a listener that was previously registered with addMidiInputCallback().
|
||||
*/
|
||||
void removeMidiInputCallback (MidiInputCallback* callback);
|
||||
void removeMidiInputCallback (const String& midiInputDeviceName,
|
||||
MidiInputCallback* callback);
|
||||
|
||||
//==============================================================================
|
||||
/** Sets a midi output device to use as the default.
|
||||
|
|
@ -355,6 +297,51 @@ public:
|
|||
*/
|
||||
MidiOutput* getDefaultMidiOutput() const throw() { return defaultMidiOutput; }
|
||||
|
||||
/**
|
||||
*/
|
||||
const OwnedArray <AudioIODeviceType>& getAvailableDeviceTypes() const throw() { return availableDeviceTypes; }
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a list of available types.
|
||||
|
||||
This will add a set of new AudioIODeviceType objects to the specified list, to
|
||||
represent each available types of device.
|
||||
|
||||
You can override this if your app needs to do something specific, like avoid
|
||||
using DirectSound devices, etc.
|
||||
*/
|
||||
virtual void createAudioDeviceTypes (OwnedArray <AudioIODeviceType>& types);
|
||||
|
||||
//==============================================================================
|
||||
/** Plays a beep through the current audio device.
|
||||
|
||||
This is here to allow the audio setup UI panels to easily include a "test"
|
||||
button so that the user can check where the audio is coming from.
|
||||
*/
|
||||
void playTestSound();
|
||||
|
||||
/** Turns on level-measuring.
|
||||
|
||||
When enabled, the device manager will measure the peak input level
|
||||
across all channels, and you can get this level by calling getCurrentInputLevel().
|
||||
|
||||
This is mainly intended for audio setup UI panels to use to create a mic
|
||||
level display, so that the user can check that they've selected the right
|
||||
device.
|
||||
|
||||
A simple filter is used to make the level decay smoothly, but this is
|
||||
only intended for giving rough feedback, and not for any kind of accurate
|
||||
measurement.
|
||||
*/
|
||||
void enableInputLevelMeasurement (const bool enableMeasurement);
|
||||
|
||||
/** Returns the current input level.
|
||||
|
||||
To use this, you must first enable it by calling enableInputLevelMeasurement().
|
||||
|
||||
See enableInputLevelMeasurement() for more info.
|
||||
*/
|
||||
double getCurrentInputLevel() const;
|
||||
|
||||
//==============================================================================
|
||||
juce_UseDebuggingNewOperator
|
||||
|
|
@ -362,14 +349,20 @@ public:
|
|||
private:
|
||||
//==============================================================================
|
||||
OwnedArray <AudioIODeviceType> availableDeviceTypes;
|
||||
OwnedArray <AudioDeviceSetup> lastDeviceTypeConfigs;
|
||||
|
||||
AudioDeviceSetup currentSetup;
|
||||
AudioIODevice* currentAudioDevice;
|
||||
AudioIODeviceCallback* currentCallback;
|
||||
int numInputChansNeeded, numOutputChansNeeded;
|
||||
String currentDeviceType;
|
||||
BitArray inputChannels, outputChannels;
|
||||
XmlElement* lastExplicitSettings;
|
||||
mutable bool listNeedsScanning;
|
||||
bool useInputNames;
|
||||
bool useInputNames, inputLevelMeasurementEnabled;
|
||||
double inputLevel;
|
||||
AudioSampleBuffer* testSound;
|
||||
int testSoundPosition;
|
||||
|
||||
StringArray midiInsFromXml;
|
||||
OwnedArray <MidiInput> enabledMidiInputs;
|
||||
|
|
@ -402,11 +395,6 @@ private:
|
|||
};
|
||||
|
||||
CallbackHandler callbackHandler;
|
||||
String lastRunningDevice;
|
||||
int lastRunningBlockSize;
|
||||
double lastRunningSampleRate;
|
||||
BitArray lastRunningIns, lastRunningOuts;
|
||||
|
||||
friend class CallbackHandler;
|
||||
|
||||
void audioDeviceIOCallbackInt (const float** inputChannelData,
|
||||
|
|
@ -425,6 +413,15 @@ private:
|
|||
|
||||
void updateXml();
|
||||
|
||||
void createDeviceTypesIfNeeded();
|
||||
void scanDevicesIfNeeded();
|
||||
void deleteCurrentDevice();
|
||||
double chooseBestSampleRate (double preferred) const;
|
||||
AudioIODeviceType* getCurrentDeviceTypeObject() const;
|
||||
void insertDefaultDeviceNames (AudioDeviceSetup& setup) const;
|
||||
|
||||
AudioIODeviceType* findType (const String& inputName, const String& outputName);
|
||||
|
||||
AudioDeviceManager (const AudioDeviceManager&);
|
||||
const AudioDeviceManager& operator= (const AudioDeviceManager&);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -307,6 +307,7 @@ public:
|
|||
*/
|
||||
virtual int getInputLatencyInSamples() = 0;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** True if this device can show a pop-up control panel for editing its settings.
|
||||
|
||||
|
|
|
|||
|
|
@ -46,33 +46,5 @@ AudioIODeviceType::~AudioIODeviceType()
|
|||
{
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
extern AudioIODeviceType* juce_createDefaultAudioIODeviceType();
|
||||
|
||||
#if JUCE_WIN32 && JUCE_ASIO
|
||||
extern AudioIODeviceType* juce_createASIOAudioIODeviceType();
|
||||
#endif
|
||||
|
||||
#if JUCE_WIN32 && JUCE_WDM_AUDIO
|
||||
extern AudioIODeviceType* juce_createWDMAudioIODeviceType();
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
void AudioIODeviceType::createDeviceTypes (OwnedArray <AudioIODeviceType>& list)
|
||||
{
|
||||
AudioIODeviceType* const defaultDeviceType = juce_createDefaultAudioIODeviceType();
|
||||
|
||||
if (defaultDeviceType != 0)
|
||||
list.add (defaultDeviceType);
|
||||
|
||||
#if JUCE_WIN32 && JUCE_ASIO
|
||||
list.add (juce_createASIOAudioIODeviceType());
|
||||
#endif
|
||||
|
||||
#if JUCE_WIN32 && JUCE_WDM_AUDIO
|
||||
list.add (juce_createWDMAudioIODeviceType());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@
|
|||
#define __JUCE_AUDIOIODEVICETYPE_JUCEHEADER__
|
||||
|
||||
#include "juce_AudioIODevice.h"
|
||||
|
||||
class AudioDeviceManager;
|
||||
class Component;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
|
|
@ -71,20 +72,6 @@
|
|||
class JUCE_API AudioIODeviceType
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a list of available types.
|
||||
|
||||
This will add a set of new AudioIODeviceType objects to the specified list, to
|
||||
represent each available types of device.
|
||||
|
||||
The objects that are created should be managed by the caller (the OwnedArray
|
||||
will delete them when the array is itself deleted).
|
||||
|
||||
When created, the objects are uninitialised, so you should call scanForDevices()
|
||||
on each one before getting its list of devices.
|
||||
*/
|
||||
static void createDeviceTypes (OwnedArray <AudioIODeviceType>& list);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the name of this type of driver that this object manages.
|
||||
|
||||
|
|
@ -104,35 +91,47 @@ public:
|
|||
|
||||
The scanForDevices() method must have been called to create this list.
|
||||
|
||||
@param preferInputNames only really used by DirectSound where devices are split up
|
||||
into inputs and outputs, this indicates whether to use
|
||||
the input or output name to refer to a pair of devices.
|
||||
@param wantInputNames only really used by DirectSound where devices are split up
|
||||
into inputs and outputs, this indicates whether to use
|
||||
the input or output name to refer to a pair of devices.
|
||||
*/
|
||||
virtual const StringArray getDeviceNames (const bool preferInputNames = false) const = 0;
|
||||
virtual const StringArray getDeviceNames (const bool wantInputNames = false) const = 0;
|
||||
|
||||
/** Returns the name of the default device.
|
||||
|
||||
This will be one of the names from the getDeviceNames() list.
|
||||
|
||||
@param preferInputNames only really used by DirectSound where devices are split up
|
||||
into inputs and outputs, this indicates whether to use
|
||||
the input or output name to refer to a pair of devices.
|
||||
@param numInputChannelsNeeded the number of input channels the user is expecting to need - this
|
||||
may be used to help decide which device would be most suitable
|
||||
@param numOutputChannelsNeeded the number of output channels the user is expecting to need - this
|
||||
may be used to help decide which device would be most suitable
|
||||
@param forInput if true, this means that a default input device should be
|
||||
returned; if false, it should return the default output
|
||||
*/
|
||||
virtual const String getDefaultDeviceName (const bool preferInputNames,
|
||||
const int numInputChannelsNeeded,
|
||||
const int numOutputChannelsNeeded) const = 0;
|
||||
virtual int getDefaultDeviceIndex (const bool forInput) const = 0;
|
||||
|
||||
/** Returns the index of a given device in the list of device names.
|
||||
If asInput is true, it shows the index in the inputs list, otherwise it
|
||||
looks for it in the outputs list.
|
||||
*/
|
||||
virtual int getIndexOfDevice (AudioIODevice* device, const bool asInput) const = 0;
|
||||
|
||||
/** Returns true if two different devices can be used for the input and output.
|
||||
*/
|
||||
virtual bool hasSeparateInputsAndOutputs() const = 0;
|
||||
|
||||
/** Creates one of the devices of this type.
|
||||
|
||||
The deviceName must be one of the strings returned by getDeviceNames(), and
|
||||
scanForDevices() must have been called before this method is used.
|
||||
*/
|
||||
virtual AudioIODevice* createDevice (const String& deviceName) = 0;
|
||||
virtual AudioIODevice* createDevice (const String& outputDeviceName,
|
||||
const String& inputDeviceName) = 0;
|
||||
|
||||
//==============================================================================
|
||||
struct DeviceSetupDetails
|
||||
{
|
||||
AudioDeviceManager* manager;
|
||||
int minNumInputChannels, maxNumInputChannels;
|
||||
int minNumOutputChannels, maxNumOutputChannels;
|
||||
bool useStereoPairs;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Destructor. */
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -35,7 +35,7 @@
|
|||
#include "../controls/juce_ComboBox.h"
|
||||
#include "../controls/juce_ListBox.h"
|
||||
#include "../../../audio/devices/juce_AudioDeviceManager.h"
|
||||
class AudioDeviceSelectorComponentListBox;
|
||||
class MidiInputSelectorComponentListBox;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
|
|
@ -89,24 +89,24 @@ public:
|
|||
/** @internal */
|
||||
void changeListenerCallback (void*);
|
||||
|
||||
//==============================================================================
|
||||
/** Called by the device-specific displays to create a little level meter that
|
||||
just displays the current total input levels from the given device manager.
|
||||
*/
|
||||
static Component* createSimpleLevelMeterComponent (AudioDeviceManager* managerToDisplay);
|
||||
|
||||
//==============================================================================
|
||||
juce_UseDebuggingNewOperator
|
||||
|
||||
private:
|
||||
AudioDeviceManager& deviceManager;
|
||||
ComboBox* audioDeviceDropDown;
|
||||
ComboBox* deviceTypeDropDown;
|
||||
Label* deviceTypeDropDownLabel;
|
||||
Component* audioDeviceSettingsComp;
|
||||
String audioDeviceSettingsCompType;
|
||||
const int minOutputChannels, maxOutputChannels, minInputChannels, maxInputChannels;
|
||||
|
||||
ComboBox* sampleRateDropDown;
|
||||
AudioDeviceSelectorComponentListBox* inputChansBox;
|
||||
Label* inputsLabel;
|
||||
AudioDeviceSelectorComponentListBox* outputChansBox;
|
||||
Label* outputsLabel;
|
||||
Label* sampleRateLabel;
|
||||
ComboBox* bufferSizeDropDown;
|
||||
Label* bufferSizeLabel;
|
||||
Button* launchUIButton;
|
||||
AudioDeviceSelectorComponentListBox* midiInputsList;
|
||||
MidiInputSelectorComponentListBox* midiInputsList;
|
||||
Label* midiInputsLabel;
|
||||
ComboBox* midiOutputSelector;
|
||||
Label* midiOutputLabel;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue