26 bool AudioDeviceManager::AudioDeviceSetup::operator== (
const AudioDeviceManager::AudioDeviceSetup& other)
const 38 bool AudioDeviceManager::AudioDeviceSetup::operator!= (
const AudioDeviceManager::AudioDeviceSetup& other)
const 40 return ! operator== (other);
44 class AudioDeviceManager::CallbackHandler :
public AudioIODeviceCallback,
45 public MidiInputCallback,
46 public AudioIODeviceType::Listener
52 void audioDeviceIOCallback (
const float** ins,
int numIns,
float** outs,
int numOuts,
int numSamples)
override 54 owner.audioDeviceIOCallbackInt (ins, numIns, outs, numOuts, numSamples);
57 void audioDeviceAboutToStart (AudioIODevice* device)
override 59 owner.audioDeviceAboutToStartInt (device);
62 void audioDeviceStopped()
override 64 owner.audioDeviceStoppedInt();
67 void audioDeviceError (
const String& message)
override 69 owner.audioDeviceErrorInt (message);
72 void handleIncomingMidiMessage (MidiInput* source,
const MidiMessage& message)
override 74 owner.handleIncomingMidiMessageInt (source, message);
77 void audioDeviceListChanged()
override 79 owner.audioDeviceListChanged();
84 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CallbackHandler)
90 callbackHandler.reset (
new CallbackHandler (*
this));
95 currentAudioDevice.reset();
96 defaultMidiOutput.reset();
100 void AudioDeviceManager::createDeviceTypesIfNeeded()
102 if (availableDeviceTypes.size() == 0)
107 for (
auto* t : types)
112 if (
auto* first = availableDeviceTypes.getFirst())
113 currentDeviceType = first->getTypeName();
119 scanDevicesIfNeeded();
120 return availableDeviceTypes;
123 void AudioDeviceManager::audioDeviceListChanged()
125 if (currentAudioDevice !=
nullptr)
127 auto isCurrentDeviceStillAvailable = [&]
129 for (
auto* dt : availableDeviceTypes)
130 if (currentAudioDevice->getTypeName() == dt->getTypeName())
131 for (
auto& dn : dt->getDeviceNames())
132 if (currentAudioDevice->getName() == dn)
138 if (! isCurrentDeviceStillAvailable())
143 initialiseFromXML (*e,
true, preferredDeviceName, ¤tSetup);
145 initialiseDefault (preferredDeviceName, ¤tSetup);
148 if (currentAudioDevice !=
nullptr)
150 currentSetup.sampleRate = currentAudioDevice->getCurrentSampleRate();
151 currentSetup.bufferSize = currentAudioDevice->getCurrentBufferSizeSamples();
152 currentSetup.inputChannels = currentAudioDevice->getActiveInputChannels();
153 currentSetup.outputChannels = currentAudioDevice->getActiveOutputChannels();
163 if (device !=
nullptr)
185 if (newDeviceType !=
nullptr)
187 jassert (lastDeviceTypeConfigs.size() == availableDeviceTypes.size());
189 availableDeviceTypes.add (newDeviceType.release());
192 availableDeviceTypes.getLast()->addListener (callbackHandler.get());
198 if (deviceTypeToRemove !=
nullptr)
200 jassert (lastDeviceTypeConfigs.size() == availableDeviceTypes.size());
202 auto index = availableDeviceTypes.indexOf (deviceTypeToRemove);
204 if (
auto removed = std::unique_ptr<AudioIODeviceType> (availableDeviceTypes.removeAndReturn (index)))
206 removed->removeListener (callbackHandler.get());
207 lastDeviceTypeConfigs.remove (index,
true);
215 if (deviceName.trim().equalsIgnoreCase (name.
trim()))
223 const int numOutputChannelsNeeded,
225 const bool selectDefaultDeviceOnFailure,
226 const String& preferredDefaultDeviceName,
229 scanDevicesIfNeeded();
231 numInputChansNeeded = numInputChannelsNeeded;
232 numOutputChansNeeded = numOutputChannelsNeeded;
233 preferredDeviceName = preferredDefaultDeviceName;
235 if (xml !=
nullptr && xml->
hasTagName (
"DEVICESETUP"))
236 return initialiseFromXML (*xml, selectDefaultDeviceOnFailure,
237 preferredDeviceName, preferredSetupOptions);
239 return initialiseDefault (preferredDeviceName, preferredSetupOptions);
242 String AudioDeviceManager::initialiseDefault (
const String& preferredDefaultDeviceName,
247 if (preferredSetupOptions !=
nullptr)
249 setup = *preferredSetupOptions;
251 else if (preferredDefaultDeviceName.
isNotEmpty())
253 for (
auto* type : availableDeviceTypes)
257 if (out.matchesWildcard (preferredDefaultDeviceName,
true))
266 if (in.matchesWildcard (preferredDefaultDeviceName,
true))
275 insertDefaultDeviceNames (setup);
280 bool selectDefaultDeviceOnFailure,
281 const String& preferredDefaultDeviceName,
284 lastExplicitSettings.reset (
new XmlElement (xml));
289 if (preferredSetupOptions !=
nullptr)
290 setup = *preferredSetupOptions;
305 if (findType (currentDeviceType) ==
nullptr)
309 else if (
auto* firstType = availableDeviceTypes.getFirst())
310 currentDeviceType = firstType->getTypeName();
324 if (error.
isNotEmpty() && selectDefaultDeviceOnFailure)
325 error =
initialise (numInputChansNeeded, numOutputChansNeeded,
nullptr,
false, preferredDefaultDeviceName);
327 midiDeviceInfosFromXml.
clear();
328 enabledMidiInputs.clear();
330 forEachXmlChildElementWithTagName (xml, c,
"MIDIINPUT")
331 midiDeviceInfosFromXml.add ({ c->getStringAttribute (
"name"), c->getStringAttribute (
"identifier") });
335 for (
auto& device : available)
336 if (device.identifier == identifier)
344 for (
auto& device : available)
345 if (device.name == name)
346 return device.identifier;
353 for (
auto& info : midiDeviceInfosFromXml)
355 if (isIdentifierAvailable (inputs, info.identifier))
361 auto identifier = getUpdatedIdentifierForName (inputs, info.name);
363 if (identifier.isNotEmpty())
373 if (isIdentifierAvailable (outputs, defaultOutputDeviceInfo.identifier))
379 auto identifier = getUpdatedIdentifierForName (outputs, defaultOutputDeviceInfo.name);
381 if (identifier.isNotEmpty())
389 int numOutputChannelsNeeded)
391 lastExplicitSettings.reset();
393 return initialise (numInputChannelsNeeded, numOutputChannelsNeeded,
394 nullptr,
false, {},
nullptr);
397 void AudioDeviceManager::insertDefaultDeviceNames (
AudioDeviceSetup& setup)
const 411 if (lastExplicitSettings !=
nullptr)
412 return std::make_unique<XmlElement> (*lastExplicitSettings);
418 void AudioDeviceManager::scanDevicesIfNeeded()
420 if (listNeedsScanning)
422 listNeedsScanning =
false;
424 createDeviceTypesIfNeeded();
426 for (
auto* type : availableDeviceTypes)
433 scanDevicesIfNeeded();
435 for (
auto* type : availableDeviceTypes)
444 scanDevicesIfNeeded();
446 for (
auto* type : availableDeviceTypes)
447 if ((inputName.
isNotEmpty() && deviceListContains (type,
true, inputName))
448 || (outputName.
isNotEmpty() && deviceListContains (type,
false, outputName)))
461 setup = currentSetup;
464 void AudioDeviceManager::deleteCurrentDevice()
466 currentAudioDevice.reset();
468 currentSetup.outputDeviceName.clear();
473 for (
int i = 0; i < availableDeviceTypes.size(); ++i)
475 if (availableDeviceTypes.getUnchecked(i)->getTypeName() == type
476 && currentDeviceType != type)
478 if (currentAudioDevice !=
nullptr)
485 currentDeviceType = type;
488 insertDefaultDeviceNames (s);
500 for (
auto* type : availableDeviceTypes)
504 return availableDeviceTypes.getFirst();
509 auto updateChannels = [](
const String& deviceName,
BigInteger& channels,
int defaultNumChannels)
515 else if (defaultNumChannels != -1)
518 channels.setRange (0, defaultNumChannels,
true);
527 bool treatAsChosenDevice)
529 jassert (&newSetup != ¤tSetup);
531 if (newSetup != currentSetup)
533 else if (currentAudioDevice !=
nullptr)
539 deleteCurrentDevice();
541 if (treatAsChosenDevice)
553 || currentAudioDevice ==
nullptr)
555 deleteCurrentDevice();
556 scanDevicesIfNeeded();
568 if (currentAudioDevice ==
nullptr)
569 error =
"Can't open the audio device!\n\n" 570 "This may be because another application is currently using the same device - " 571 "if so, you should close any other applications and try again!";
573 error = currentAudioDevice->getLastError();
577 deleteCurrentDevice();
582 currentSetup = newSetup;
585 if (! currentSetup.useDefaultOutputChannels) numOutputChansNeeded = currentSetup.outputChannels.countNumberOfSetBits();
587 updateSetupChannels (currentSetup, numInputChansNeeded, numOutputChansNeeded);
589 if (currentSetup.inputChannels.isZero() && currentSetup.outputChannels.isZero())
591 if (treatAsChosenDevice)
597 currentSetup.sampleRate = chooseBestSampleRate (currentSetup.sampleRate);
598 currentSetup.bufferSize = chooseBestBufferSize (currentSetup.bufferSize);
600 error = currentAudioDevice->open (currentSetup.inputChannels,
601 currentSetup.outputChannels,
602 currentSetup.sampleRate,
603 currentSetup.bufferSize);
607 currentDeviceType = currentAudioDevice->getTypeName();
609 currentAudioDevice->start (callbackHandler.get());
611 currentSetup.sampleRate = currentAudioDevice->getCurrentSampleRate();
612 currentSetup.bufferSize = currentAudioDevice->getCurrentBufferSizeSamples();
613 currentSetup.inputChannels = currentAudioDevice->getActiveInputChannels();
614 currentSetup.outputChannels = currentAudioDevice->getActiveOutputChannels();
616 for (
int i = 0; i < availableDeviceTypes.size(); ++i)
617 if (availableDeviceTypes.getUnchecked (i)->getTypeName() == currentDeviceType)
618 *(lastDeviceTypeConfigs.getUnchecked (i)) = currentSetup;
620 if (treatAsChosenDevice)
625 deleteCurrentDevice();
631 double AudioDeviceManager::chooseBestSampleRate (
double rate)
const 633 jassert (currentAudioDevice !=
nullptr);
635 auto rates = currentAudioDevice->getAvailableSampleRates();
637 if (rate > 0 && rates.contains (rate))
640 rate = currentAudioDevice->getCurrentSampleRate();
642 if (rate > 0 && rates.contains (rate))
645 double lowestAbove44 = 0.0;
647 for (
int i = rates.size(); --i >= 0;)
651 if (sr >= 44100.0 && (lowestAbove44 < 1.0 || sr < lowestAbove44))
655 if (lowestAbove44 > 0.0)
656 return lowestAbove44;
661 int AudioDeviceManager::chooseBestBufferSize (
int bufferSize)
const 663 jassert (currentAudioDevice !=
nullptr);
665 if (bufferSize > 0 && currentAudioDevice->getAvailableBufferSizes().contains (bufferSize))
668 return currentAudioDevice->getDefaultBufferSize();
671 void AudioDeviceManager::stopDevice()
673 if (currentAudioDevice !=
nullptr)
674 currentAudioDevice->stop();
682 currentAudioDevice.reset();
683 loadMeasurer.reset();
688 if (currentAudioDevice ==
nullptr)
690 if (currentSetup.inputDeviceName.isEmpty()
691 && currentSetup.outputDeviceName.isEmpty())
705 void AudioDeviceManager::updateXml()
707 lastExplicitSettings.reset (
new XmlElement (
"DEVICESETUP"));
709 lastExplicitSettings->setAttribute (
"deviceType", currentDeviceType);
710 lastExplicitSettings->setAttribute (
"audioOutputDeviceName", currentSetup.outputDeviceName);
711 lastExplicitSettings->setAttribute (
"audioInputDeviceName", currentSetup.inputDeviceName);
713 if (currentAudioDevice !=
nullptr)
715 lastExplicitSettings->setAttribute (
"audioDeviceRate", currentAudioDevice->getCurrentSampleRate());
717 if (currentAudioDevice->getDefaultBufferSize() != currentAudioDevice->getCurrentBufferSizeSamples())
718 lastExplicitSettings->setAttribute (
"audioDeviceBufferSize", currentAudioDevice->getCurrentBufferSizeSamples());
720 if (! currentSetup.useDefaultInputChannels)
721 lastExplicitSettings->setAttribute (
"audioDeviceInChans", currentSetup.inputChannels.toString (2));
723 if (! currentSetup.useDefaultOutputChannels)
724 lastExplicitSettings->setAttribute (
"audioDeviceOutChans", currentSetup.outputChannels.toString (2));
727 for (
auto& input : enabledMidiInputs)
729 auto* child = lastExplicitSettings->createNewChildElement (
"MIDIINPUT");
731 child->setAttribute (
"name", input->getName());
732 child->setAttribute (
"identifier", input->getIdentifier());
735 if (midiDeviceInfosFromXml.size() > 0)
741 for (
auto& d : midiDeviceInfosFromXml)
743 if (! availableMidiDevices.contains (d))
745 auto* child = lastExplicitSettings->createNewChildElement (
"MIDIINPUT");
747 child->setAttribute (
"name", d.name);
748 child->setAttribute (
"identifier", d.identifier);
755 lastExplicitSettings->setAttribute (
"defaultMidiOutput", defaultMidiOutputDeviceInfo.name);
756 lastExplicitSettings->setAttribute (
"defaultMidiOutputDevice", defaultMidiOutputDeviceInfo.identifier);
766 if (callbacks.contains (newCallback))
770 if (currentAudioDevice !=
nullptr && newCallback !=
nullptr)
774 callbacks.add (newCallback);
779 if (callbackToRemove !=
nullptr)
781 bool needsDeinitialising = currentAudioDevice !=
nullptr;
786 needsDeinitialising = needsDeinitialising && callbacks.contains (callbackToRemove);
787 callbacks.removeFirstMatchingValue (callbackToRemove);
790 if (needsDeinitialising)
795 void AudioDeviceManager::audioDeviceIOCallbackInt (
const float** inputChannelData,
796 int numInputChannels,
797 float** outputChannelData,
798 int numOutputChannels,
803 inputLevelGetter->updateLevel (inputChannelData, numInputChannels, numSamples);
804 outputLevelGetter->updateLevel (const_cast<const float**> (outputChannelData), numOutputChannels, numSamples);
806 if (callbacks.size() > 0)
810 tempBuffer.setSize (jmax (1, numOutputChannels), jmax (1, numSamples),
false,
false,
true);
812 callbacks.getUnchecked(0)->audioDeviceIOCallback (inputChannelData, numInputChannels,
813 outputChannelData, numOutputChannels, numSamples);
815 auto** tempChans = tempBuffer.getArrayOfWritePointers();
817 for (
int i = callbacks.size(); --i > 0;)
819 callbacks.getUnchecked(i)->audioDeviceIOCallback (inputChannelData, numInputChannels,
820 tempChans, numOutputChannels, numSamples);
822 for (
int chan = 0; chan < numOutputChannels; ++chan)
824 if (
auto* src = tempChans [chan])
825 if (
auto* dst = outputChannelData [chan])
826 for (
int j = 0; j < numSamples; ++j)
833 for (
int i = 0; i < numOutputChannels; ++i)
834 zeromem (outputChannelData[i], (
size_t) numSamples *
sizeof (
float));
837 if (testSound !=
nullptr)
839 auto numSamps = jmin (numSamples, testSound->getNumSamples() - testSoundPosition);
840 auto* src = testSound->getReadPointer (0, testSoundPosition);
842 for (
int i = 0; i < numOutputChannels; ++i)
843 for (
int j = 0; j < numSamps; ++j)
844 outputChannelData [i][j] += src[j];
846 testSoundPosition += numSamps;
848 if (testSoundPosition >= testSound->getNumSamples())
853 void AudioDeviceManager::audioDeviceAboutToStartInt (
AudioIODevice*
const device)
861 for (
int i = callbacks.size(); --i >= 0;)
862 callbacks.getUnchecked(i)->audioDeviceAboutToStart (device);
868 void AudioDeviceManager::audioDeviceStoppedInt()
874 loadMeasurer.reset();
876 for (
int i = callbacks.size(); --i >= 0;)
877 callbacks.getUnchecked(i)->audioDeviceStopped();
880 void AudioDeviceManager::audioDeviceErrorInt (
const String& message)
884 for (
int i = callbacks.size(); --i >= 0;)
885 callbacks.getUnchecked(i)->audioDeviceError (message);
890 return loadMeasurer.getLoadAsProportion();
902 enabledMidiInputs.push_back (std::move (midiIn));
903 enabledMidiInputs.back()->start();
908 auto removePredicate = [identifier] (
const std::unique_ptr<MidiInput>& in) {
return in->getIdentifier() == identifier; };
909 enabledMidiInputs.erase (std::remove_if (std::begin (enabledMidiInputs), std::end (enabledMidiInputs), removePredicate),
910 std::end (enabledMidiInputs));
920 for (
auto& mi : enabledMidiInputs)
921 if (mi->getIdentifier() == identifier)
934 midiCallbacks.add ({ identifier, callbackToAdd });
940 for (
int i = midiCallbacks.size(); --i >= 0;)
942 auto& mc = midiCallbacks.getReference (i);
944 if (mc.callback == callbackToRemove && mc.deviceIdentifier == identifier)
947 midiCallbacks.remove (i);
952 void AudioDeviceManager::handleIncomingMidiMessageInt (
MidiInput* source,
const MidiMessage& message)
958 for (
auto& mc : midiCallbacks)
959 if (mc.deviceIdentifier.isEmpty() || mc.deviceIdentifier == source->
getIdentifier())
960 mc.callback->handleIncomingMidiMessage (source, message);
967 if (defaultMidiOutputDeviceInfo.identifier != identifier)
976 if (currentAudioDevice !=
nullptr)
977 for (
int i = oldCallbacks.
size(); --i >= 0;)
980 defaultMidiOutput.reset();
985 if (defaultMidiOutput !=
nullptr)
986 defaultMidiOutputDeviceInfo = defaultMidiOutput->getDeviceInfo();
988 defaultMidiOutputDeviceInfo = {};
990 if (currentAudioDevice !=
nullptr)
991 for (
auto* c : oldCallbacks)
992 c->audioDeviceAboutToStart (currentAudioDevice.get());
996 oldCallbacks.swapWith (callbacks);
1005 AudioDeviceManager::LevelMeter::LevelMeter() noexcept : level() {}
1007 void AudioDeviceManager::LevelMeter::updateLevel (
const float*
const* channelData,
int numChannels,
int numSamples) noexcept
1009 if (getReferenceCount() <= 1)
1012 auto localLevel = level.get();
1014 if (numChannels > 0)
1016 for (
int j = 0; j < numSamples; ++j)
1020 for (
int i = 0; i < numChannels; ++i)
1021 s += std::abs (channelData[i][j]);
1023 s /= (float) numChannels;
1025 const float decayFactor = 0.99992f;
1029 else if (localLevel > 0.001f)
1030 localLevel *= decayFactor;
1043 double AudioDeviceManager::LevelMeter::getCurrentLevel()
const noexcept
1045 jassert (getReferenceCount() > 1);
1052 std::unique_ptr<AudioBuffer<float>> oldSound;
1056 std::swap (oldSound, testSound);
1060 testSoundPosition = 0;
1062 if (currentAudioDevice !=
nullptr)
1064 auto sampleRate = currentAudioDevice->getCurrentSampleRate();
1067 double frequency = 440.0;
1068 float amplitude = 0.5f;
1072 std::unique_ptr<AudioBuffer<float>> newSound (
new AudioBuffer<float> (1, soundLength));
1074 for (
int i = 0; i < soundLength; ++i)
1075 newSound->setSample (0, i, amplitude * (
float) std::sin (i * phasePerSample));
1077 newSound->applyGainRamp (0, 0, soundLength / 10, 0.0f, 1.0f);
1078 newSound->applyGainRamp (0, soundLength - soundLength / 4, soundLength / 4, 1.0f, 0.0f);
1082 std::swap (testSound, newSound);
1089 auto deviceXRuns = (currentAudioDevice !=
nullptr ? currentAudioDevice->getXRunCount() : -1);
1090 return jmax (0, deviceXRuns) + loadMeasurer.getXRunCount();
1099 if (device.
name == name)
1110 if (device.
name == name)
1126 if (device.
name == name)
1139 if (device.
name == name)
1151 if (device.
name == name)
void addAudioCallback(AudioIODeviceCallback *newCallback)
String initialiseWithDefaultDevices(int numInputChannelsNeeded, int numOutputChannelsNeeded)
BigInteger outputChannels
bool isMidiInputDeviceEnabled(const String &deviceIdentifier) const
void removeAudioDeviceType(AudioIODeviceType *deviceTypeToRemove)
bool hasTagName(StringRef possibleTagName) const noexcept
void addMidiInputDeviceCallback(const String &deviceIdentifier, MidiInputCallback *callback)
void removeMidiInputDeviceCallback(const String &deviceIdentifier, MidiInputCallback *callback)
bool isNotEmpty() const noexcept
void swapWith(OtherArrayType &otherArray) noexcept
virtual void audioDeviceAboutToStart(AudioIODevice *device)=0
static AudioIODeviceType * createAudioIODeviceType_iOSAudio()
void setMidiInputDeviceEnabled(const String &deviceIdentifier, bool enabled)
void parseString(StringRef text, int base)
String setAudioDeviceSetup(const AudioDeviceSetup &newSetup, bool treatAsChosenDevice)
static AudioIODeviceType * createAudioIODeviceType_Oboe()
static AudioIODeviceType * createAudioIODeviceType_CoreAudio()
~AudioDeviceManager() override
int getIntAttribute(StringRef attributeName, int defaultReturnValue=0) const
static AudioIODeviceType * createAudioIODeviceType_OpenSLES()
bool hasAttribute(StringRef attributeName) const noexcept
ElementType getUnchecked(int index) const
String initialise(int numInputChannelsNeeded, int numOutputChannelsNeeded, const XmlElement *savedState, bool selectDefaultDeviceOnFailure, const String &preferredDefaultDeviceName=String(), const AudioDeviceSetup *preferredSetupOptions=nullptr)
std::unique_ptr< XmlElement > createStateXml() const
AudioDeviceSetup getAudioDeviceSetup() const
static AudioIODeviceType * createAudioIODeviceType_ASIO()
static AudioIODeviceType * createAudioIODeviceType_Bela()
virtual StringArray getDeviceNames(bool wantInputNames=false) const =0
AudioIODeviceType * getCurrentDeviceTypeObject() const
bool useDefaultOutputChannels
int getXRunCount() const noexcept
void addAudioDeviceType(std::unique_ptr< AudioIODeviceType > newDeviceType)
bool useDefaultInputChannels
static std::unique_ptr< MidiOutput > openDevice(const String &deviceIdentifier)
double getDoubleAttribute(StringRef attributeName, double defaultReturnValue=0.0) const
void setCurrentAudioDeviceType(const String &type, bool treatAsChosenDevice)
static AudioIODeviceType * createAudioIODeviceType_JACK()
virtual double getCurrentSampleRate()=0
static AudioIODeviceType * createAudioIODeviceType_DirectSound()
static AudioIODeviceType * createAudioIODeviceType_WASAPI(bool exclusiveMode)
virtual int getCurrentBufferSizeSamples()=0
void setMidiInputEnabled(const String &, bool)
virtual int getDefaultDeviceIndex(bool forInput) const =0
void removeAudioCallback(AudioIODeviceCallback *callback)
virtual AudioIODevice * createDevice(const String &outputDeviceName, const String &inputDeviceName)=0
int size() const noexcept
static AudioIODeviceType * createAudioIODeviceType_Android()
virtual void audioDeviceStopped()=0
bool isEmpty() const noexcept
const String & getStringAttribute(StringRef attributeName) const noexcept
const OwnedArray< AudioIODeviceType > & getAvailableDeviceTypes()
ObjectClass * add(ObjectClass *newObject)
bool isActiveSense() const noexcept
void setDefaultMidiOutputDevice(const String &deviceIdentifier)
static Array< MidiDeviceInfo > getAvailableDevices()
static void JUCE_CALLTYPE sleep(int milliseconds)
void setDefaultMidiOutput(const String &)
bool isMidiInputEnabled(const String &) const
virtual void createAudioDeviceTypes(OwnedArray< AudioIODeviceType > &types)
int countNumberOfSetBits() const noexcept
const String & getTypeName() const noexcept
void addMidiInputCallback(const String &, MidiInputCallback *)
void restartLastAudioDevice()
void removeMidiInputCallback(const String &, MidiInputCallback *)
virtual void scanForDevices()=0
double getCpuUsage() const
static AudioIODeviceType * createAudioIODeviceType_ALSA()