OpenShot Audio Library | OpenShotAudio 0.3.2
Loading...
Searching...
No Matches
juce_AudioDeviceManager.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2017 - ROLI Ltd.
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26bool AudioDeviceManager::AudioDeviceSetup::operator== (const AudioDeviceManager::AudioDeviceSetup& other) const
27{
28 return outputDeviceName == other.outputDeviceName
29 && inputDeviceName == other.inputDeviceName
30 && sampleRate == other.sampleRate
31 && bufferSize == other.bufferSize
32 && inputChannels == other.inputChannels
33 && useDefaultInputChannels == other.useDefaultInputChannels
34 && outputChannels == other.outputChannels
35 && useDefaultOutputChannels == other.useDefaultOutputChannels;
36}
37
38bool AudioDeviceManager::AudioDeviceSetup::operator!= (const AudioDeviceManager::AudioDeviceSetup& other) const
39{
40 return ! operator== (other);
41}
42
43//==============================================================================
44class AudioDeviceManager::CallbackHandler : public AudioIODeviceCallback,
45 public MidiInputCallback,
46 public AudioIODeviceType::Listener
47{
48public:
49 CallbackHandler (AudioDeviceManager& adm) noexcept : owner (adm) {}
50
51private:
52 void audioDeviceIOCallback (const float** ins, int numIns, float** outs, int numOuts, int numSamples) override
53 {
54 owner.audioDeviceIOCallbackInt (ins, numIns, outs, numOuts, numSamples);
55 }
56
57 void audioDeviceAboutToStart (AudioIODevice* device) override
58 {
59 owner.audioDeviceAboutToStartInt (device);
60 }
61
62 void audioDeviceStopped() override
63 {
64 owner.audioDeviceStoppedInt();
65 }
66
67 void audioDeviceError (const String& message) override
68 {
69 owner.audioDeviceErrorInt (message);
70 }
71
72 void handleIncomingMidiMessage (MidiInput* source, const MidiMessage& message) override
73 {
74 owner.handleIncomingMidiMessageInt (source, message);
75 }
76
77 void audioDeviceListChanged() override
78 {
79 owner.audioDeviceListChanged();
80 }
81
82 AudioDeviceManager& owner;
83
84 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CallbackHandler)
85};
86
87//==============================================================================
89{
90 callbackHandler.reset (new CallbackHandler (*this));
91}
92
94{
95 currentAudioDevice.reset();
96 defaultMidiOutput.reset();
97}
98
99//==============================================================================
100void AudioDeviceManager::createDeviceTypesIfNeeded()
101{
102 if (availableDeviceTypes.size() == 0)
103 {
106
107 for (auto* t : types)
109
110 types.clear (false);
111
112 if (auto* first = availableDeviceTypes.getFirst())
113 currentDeviceType = first->getTypeName();
114 }
115}
116
118{
119 scanDevicesIfNeeded();
120 return availableDeviceTypes;
121}
122
123void AudioDeviceManager::audioDeviceListChanged()
124{
125 if (currentAudioDevice != nullptr)
126 {
128 {
129 for (auto* dt : availableDeviceTypes)
130 if (currentAudioDevice->getTypeName() == dt->getTypeName())
131 for (auto& dn : dt->getDeviceNames())
132 if (currentAudioDevice->getName() == dn)
133 return true;
134
135 return false;
136 };
137
138 if (! isCurrentDeviceStillAvailable())
139 {
141
142 if (auto e = createStateXml())
143 initialiseFromXML (*e, true, preferredDeviceName, &currentSetup);
144 else
145 initialiseDefault (preferredDeviceName, &currentSetup);
146 }
147
148 if (currentAudioDevice != nullptr)
149 {
150 currentSetup.sampleRate = currentAudioDevice->getCurrentSampleRate();
151 currentSetup.bufferSize = currentAudioDevice->getCurrentBufferSizeSamples();
152 currentSetup.inputChannels = currentAudioDevice->getActiveInputChannels();
153 currentSetup.outputChannels = currentAudioDevice->getActiveOutputChannels();
154 }
155 }
156
158}
159
160//==============================================================================
161static void addIfNotNull (OwnedArray<AudioIODeviceType>& list, AudioIODeviceType* const device)
162{
163 if (device != nullptr)
164 list.add (device);
165}
166
182
183void AudioDeviceManager::addAudioDeviceType (std::unique_ptr<AudioIODeviceType> newDeviceType)
184{
185 if (newDeviceType != nullptr)
186 {
187 jassert (lastDeviceTypeConfigs.size() == availableDeviceTypes.size());
188
189 availableDeviceTypes.add (newDeviceType.release());
190 lastDeviceTypeConfigs.add (new AudioDeviceSetup());
191
192 availableDeviceTypes.getLast()->addListener (callbackHandler.get());
193 }
194}
195
197{
198 if (deviceTypeToRemove != nullptr)
199 {
200 jassert (lastDeviceTypeConfigs.size() == availableDeviceTypes.size());
201
202 auto index = availableDeviceTypes.indexOf (deviceTypeToRemove);
203
204 if (auto removed = std::unique_ptr<AudioIODeviceType> (availableDeviceTypes.removeAndReturn (index)))
205 {
206 removed->removeListener (callbackHandler.get());
207 lastDeviceTypeConfigs.remove (index, true);
208 }
209 }
210}
211
212static bool deviceListContains (AudioIODeviceType* type, bool isInput, const String& name)
213{
214 for (auto& deviceName : type->getDeviceNames (isInput))
215 if (deviceName.trim().equalsIgnoreCase (name.trim()))
216 return true;
217
218 return false;
219}
220
221//==============================================================================
223 const int numOutputChannelsNeeded,
224 const XmlElement* const xml,
228{
229 scanDevicesIfNeeded();
230
231 numInputChansNeeded = numInputChannelsNeeded;
232 numOutputChansNeeded = numOutputChannelsNeeded;
233 preferredDeviceName = preferredDefaultDeviceName;
234
235 if (xml != nullptr && xml->hasTagName ("DEVICESETUP"))
236 return initialiseFromXML (*xml, selectDefaultDeviceOnFailure,
237 preferredDeviceName, preferredSetupOptions);
238
239 return initialiseDefault (preferredDeviceName, preferredSetupOptions);
240}
241
242String AudioDeviceManager::initialiseDefault (const String& preferredDefaultDeviceName,
243 const AudioDeviceSetup* preferredSetupOptions)
244{
245 AudioDeviceSetup setup;
246
247 if (preferredSetupOptions != nullptr)
248 {
250 }
251 else if (preferredDefaultDeviceName.isNotEmpty())
252 {
253 for (auto* type : availableDeviceTypes)
254 {
255 for (auto& out : type->getDeviceNames (false))
256 {
257 if (out.matchesWildcard (preferredDefaultDeviceName, true))
258 {
259 setup.outputDeviceName = out;
260 break;
261 }
262 }
263
264 for (auto& in : type->getDeviceNames (true))
265 {
266 if (in.matchesWildcard (preferredDefaultDeviceName, true))
267 {
268 setup.inputDeviceName = in;
269 break;
270 }
271 }
272 }
273 }
274
275 insertDefaultDeviceNames (setup);
276 return setAudioDeviceSetup (setup, false);
277}
278
279String AudioDeviceManager::initialiseFromXML (const XmlElement& xml,
280 bool selectDefaultDeviceOnFailure,
281 const String& preferredDefaultDeviceName,
282 const AudioDeviceSetup* preferredSetupOptions)
283{
284 lastExplicitSettings.reset (new XmlElement (xml));
285
286 String error;
287 AudioDeviceSetup setup;
288
289 if (preferredSetupOptions != nullptr)
290 setup = *preferredSetupOptions;
291
292 if (xml.getStringAttribute ("audioDeviceName").isNotEmpty())
293 {
294 setup.inputDeviceName = setup.outputDeviceName
295 = xml.getStringAttribute ("audioDeviceName");
296 }
297 else
298 {
299 setup.inputDeviceName = xml.getStringAttribute ("audioInputDeviceName");
300 setup.outputDeviceName = xml.getStringAttribute ("audioOutputDeviceName");
301 }
302
303 currentDeviceType = xml.getStringAttribute ("deviceType");
304
305 if (findType (currentDeviceType) == nullptr)
306 {
307 if (auto* type = findType (setup.inputDeviceName, setup.outputDeviceName))
308 currentDeviceType = type->getTypeName();
309 else if (auto* firstType = availableDeviceTypes.getFirst())
310 currentDeviceType = firstType->getTypeName();
311 }
312
313 setup.bufferSize = xml.getIntAttribute ("audioDeviceBufferSize", setup.bufferSize);
314 setup.sampleRate = xml.getDoubleAttribute ("audioDeviceRate", setup.sampleRate);
315
316 setup.inputChannels .parseString (xml.getStringAttribute ("audioDeviceInChans", "11"), 2);
317 setup.outputChannels.parseString (xml.getStringAttribute ("audioDeviceOutChans", "11"), 2);
318
319 setup.useDefaultInputChannels = ! xml.hasAttribute ("audioDeviceInChans");
320 setup.useDefaultOutputChannels = ! xml.hasAttribute ("audioDeviceOutChans");
321
322 error = setAudioDeviceSetup (setup, true);
323
324 if (error.isNotEmpty() && selectDefaultDeviceOnFailure)
325 error = initialise (numInputChansNeeded, numOutputChansNeeded, nullptr, false, preferredDefaultDeviceName);
326
327 midiDeviceInfosFromXml.clear();
328 enabledMidiInputs.clear();
329
330 forEachXmlChildElementWithTagName (xml, c, "MIDIINPUT")
331 midiDeviceInfosFromXml.add ({ c->getStringAttribute ("name"), c->getStringAttribute ("identifier") });
332
333 auto isIdentifierAvailable = [] (const Array<MidiDeviceInfo>& available, const String& identifier)
334 {
335 for (auto& device : available)
336 if (device.identifier == identifier)
337 return true;
338
339 return false;
340 };
341
342 auto getUpdatedIdentifierForName = [&] (const Array<MidiDeviceInfo>& available, const String& name) -> String
343 {
344 for (auto& device : available)
345 if (device.name == name)
346 return device.identifier;
347
348 return {};
349 };
350
351 auto inputs = MidiInput::getAvailableDevices();
352
353 for (auto& info : midiDeviceInfosFromXml)
354 {
355 if (isIdentifierAvailable (inputs, info.identifier))
356 {
357 setMidiInputDeviceEnabled (info.identifier, true);
358 }
359 else
360 {
361 auto identifier = getUpdatedIdentifierForName (inputs, info.name);
362
363 if (identifier.isNotEmpty())
364 setMidiInputDeviceEnabled (identifier, true);
365 }
366 }
367
368 MidiDeviceInfo defaultOutputDeviceInfo (xml.getStringAttribute ("defaultMidiOutput"),
369 xml.getStringAttribute ("defaultMidiOutputDevice"));
370
371 auto outputs = MidiOutput::getAvailableDevices();
372
373 if (isIdentifierAvailable (outputs, defaultOutputDeviceInfo.identifier))
374 {
375 setDefaultMidiOutputDevice (defaultOutputDeviceInfo.identifier);
376 }
377 else
378 {
379 auto identifier = getUpdatedIdentifierForName (outputs, defaultOutputDeviceInfo.name);
380
381 if (identifier.isNotEmpty())
382 setDefaultMidiOutputDevice (identifier);
383 }
384
385 return error;
386}
387
390{
391 lastExplicitSettings.reset();
392
394 nullptr, false, {}, nullptr);
395}
396
397void AudioDeviceManager::insertDefaultDeviceNames (AudioDeviceSetup& setup) const
398{
399 if (auto* type = getCurrentDeviceTypeObject())
400 {
401 if (numOutputChansNeeded > 0 && setup.outputDeviceName.isEmpty())
402 setup.outputDeviceName = type->getDeviceNames (false) [type->getDefaultDeviceIndex (false)];
403
404 if (numInputChansNeeded > 0 && setup.inputDeviceName.isEmpty())
405 setup.inputDeviceName = type->getDeviceNames (true) [type->getDefaultDeviceIndex (true)];
406 }
407}
408
409std::unique_ptr<XmlElement> AudioDeviceManager::createStateXml() const
410{
411 if (lastExplicitSettings != nullptr)
412 return std::make_unique<XmlElement> (*lastExplicitSettings);
413
414 return {};
415}
416
417//==============================================================================
418void AudioDeviceManager::scanDevicesIfNeeded()
419{
420 if (listNeedsScanning)
421 {
422 listNeedsScanning = false;
423
424 createDeviceTypesIfNeeded();
425
426 for (auto* type : availableDeviceTypes)
427 type->scanForDevices();
428 }
429}
430
431AudioIODeviceType* AudioDeviceManager::findType (const String& typeName)
432{
433 scanDevicesIfNeeded();
434
435 for (auto* type : availableDeviceTypes)
436 if (type->getTypeName() == typeName)
437 return type;
438
439 return {};
440}
441
442AudioIODeviceType* AudioDeviceManager::findType (const String& inputName, const String& outputName)
443{
444 scanDevicesIfNeeded();
445
446 for (auto* type : availableDeviceTypes)
447 if ((inputName.isNotEmpty() && deviceListContains (type, true, inputName))
448 || (outputName.isNotEmpty() && deviceListContains (type, false, outputName)))
449 return type;
450
451 return {};
452}
453
458
460{
461 setup = currentSetup;
462}
463
464void AudioDeviceManager::deleteCurrentDevice()
465{
466 currentAudioDevice.reset();
467 currentSetup.inputDeviceName.clear();
468 currentSetup.outputDeviceName.clear();
469}
470
472{
473 for (int i = 0; i < availableDeviceTypes.size(); ++i)
474 {
475 if (availableDeviceTypes.getUnchecked(i)->getTypeName() == type
476 && currentDeviceType != type)
477 {
478 if (currentAudioDevice != nullptr)
479 {
481 Thread::sleep (1500); // allow a moment for OS devices to sort themselves out, to help
482 // avoid things like DirectSound/ASIO clashes
483 }
484
485 currentDeviceType = type;
486
487 AudioDeviceSetup s (*lastDeviceTypeConfigs.getUnchecked(i));
488 insertDefaultDeviceNames (s);
489
491
493 break;
494 }
495 }
496}
497
499{
500 for (auto* type : availableDeviceTypes)
501 if (type->getTypeName() == currentDeviceType)
502 return type;
503
504 return availableDeviceTypes.getFirst();
505}
506
507static void updateSetupChannels (AudioDeviceManager::AudioDeviceSetup& setup, int defaultNumIns, int defaultNumOuts)
508{
509 auto updateChannels = [](const String& deviceName, BigInteger& channels, int defaultNumChannels)
510 {
511 if (deviceName.isEmpty())
512 {
513 channels.clear();
514 }
515 else if (defaultNumChannels != -1)
516 {
517 channels.clear();
518 channels.setRange (0, defaultNumChannels, true);
519 }
520 };
521
522 updateChannels (setup.inputDeviceName, setup.inputChannels, setup.useDefaultInputChannels ? defaultNumIns : -1);
523 updateChannels (setup.outputDeviceName, setup.outputChannels, setup.useDefaultOutputChannels ? defaultNumOuts : -1);
524}
525
528{
529 jassert (&newSetup != &currentSetup); // this will have no effect
530
531 if (newSetup != currentSetup)
533 else if (currentAudioDevice != nullptr)
534 return {};
535
536 if (getCurrentDeviceTypeObject() == nullptr
537 || (newSetup.inputDeviceName.isEmpty() && newSetup.outputDeviceName.isEmpty()))
538 {
539 deleteCurrentDevice();
540
542 updateXml();
543
544 return {};
545 }
546
547 stopDevice();
548
549 String error;
550
551 if (currentSetup.inputDeviceName != newSetup.inputDeviceName
552 || currentSetup.outputDeviceName != newSetup.outputDeviceName
553 || currentAudioDevice == nullptr)
554 {
555 deleteCurrentDevice();
556 scanDevicesIfNeeded();
557
558 auto* type = getCurrentDeviceTypeObject();
559
560 if (newSetup.outputDeviceName.isNotEmpty() && ! deviceListContains (type, false, newSetup.outputDeviceName))
561 return "No such device: " + newSetup.outputDeviceName;
562
563 if (newSetup.inputDeviceName.isNotEmpty() && ! deviceListContains (type, true, newSetup.inputDeviceName))
564 return "No such device: " + newSetup.inputDeviceName;
565
566 currentAudioDevice.reset (type->createDevice (newSetup.outputDeviceName, newSetup.inputDeviceName));
567
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!";
572 else
573 error = currentAudioDevice->getLastError();
574
575 if (error.isNotEmpty())
576 {
577 deleteCurrentDevice();
578 return error;
579 }
580 }
581
582 currentSetup = newSetup;
583
584 if (! currentSetup.useDefaultInputChannels) numInputChansNeeded = currentSetup.inputChannels.countNumberOfSetBits();
585 if (! currentSetup.useDefaultOutputChannels) numOutputChansNeeded = currentSetup.outputChannels.countNumberOfSetBits();
586
587 updateSetupChannels (currentSetup, numInputChansNeeded, numOutputChansNeeded);
588
589 if (currentSetup.inputChannels.isZero() && currentSetup.outputChannels.isZero())
590 {
592 updateXml();
593
594 return {};
595 }
596
597 currentSetup.sampleRate = chooseBestSampleRate (currentSetup.sampleRate);
598 currentSetup.bufferSize = chooseBestBufferSize (currentSetup.bufferSize);
599
600 error = currentAudioDevice->open (currentSetup.inputChannels,
601 currentSetup.outputChannels,
602 currentSetup.sampleRate,
603 currentSetup.bufferSize);
604
605 if (error.isEmpty())
606 {
607 currentDeviceType = currentAudioDevice->getTypeName();
608
609 currentAudioDevice->start (callbackHandler.get());
610
611 currentSetup.sampleRate = currentAudioDevice->getCurrentSampleRate();
612 currentSetup.bufferSize = currentAudioDevice->getCurrentBufferSizeSamples();
613 currentSetup.inputChannels = currentAudioDevice->getActiveInputChannels();
614 currentSetup.outputChannels = currentAudioDevice->getActiveOutputChannels();
615
616 for (int i = 0; i < availableDeviceTypes.size(); ++i)
617 if (availableDeviceTypes.getUnchecked (i)->getTypeName() == currentDeviceType)
618 *(lastDeviceTypeConfigs.getUnchecked (i)) = currentSetup;
619
621 updateXml();
622 }
623 else
624 {
625 deleteCurrentDevice();
626 }
627
628 return error;
629}
630
631double AudioDeviceManager::chooseBestSampleRate (double rate) const
632{
633 jassert (currentAudioDevice != nullptr);
634
635 auto rates = currentAudioDevice->getAvailableSampleRates();
636
637 if (rate > 0 && rates.contains (rate))
638 return rate;
639
640 rate = currentAudioDevice->getCurrentSampleRate();
641
642 if (rate > 0 && rates.contains (rate))
643 return rate;
644
645 double lowestAbove44 = 0.0;
646
647 for (int i = rates.size(); --i >= 0;)
648 {
649 auto sr = rates[i];
650
651 if (sr >= 44100.0 && (lowestAbove44 < 1.0 || sr < lowestAbove44))
652 lowestAbove44 = sr;
653 }
654
655 if (lowestAbove44 > 0.0)
656 return lowestAbove44;
657
658 return rates[0];
659}
660
661int AudioDeviceManager::chooseBestBufferSize (int bufferSize) const
662{
663 jassert (currentAudioDevice != nullptr);
664
665 if (bufferSize > 0 && currentAudioDevice->getAvailableBufferSizes().contains (bufferSize))
666 return bufferSize;
667
668 return currentAudioDevice->getDefaultBufferSize();
669}
670
671void AudioDeviceManager::stopDevice()
672{
673 if (currentAudioDevice != nullptr)
674 currentAudioDevice->stop();
675
676 testSound.reset();
677}
678
680{
681 stopDevice();
682 currentAudioDevice.reset();
683 loadMeasurer.reset();
684}
685
687{
688 if (currentAudioDevice == nullptr)
689 {
690 if (currentSetup.inputDeviceName.isEmpty()
691 && currentSetup.outputDeviceName.isEmpty())
692 {
693 // This method will only reload the last device that was running
694 // before closeAudioDevice() was called - you need to actually open
695 // one first, with setAudioDevice().
696 jassertfalse;
697 return;
698 }
699
700 AudioDeviceSetup s (currentSetup);
701 setAudioDeviceSetup (s, false);
702 }
703}
704
705void AudioDeviceManager::updateXml()
706{
707 lastExplicitSettings.reset (new XmlElement ("DEVICESETUP"));
708
709 lastExplicitSettings->setAttribute ("deviceType", currentDeviceType);
710 lastExplicitSettings->setAttribute ("audioOutputDeviceName", currentSetup.outputDeviceName);
711 lastExplicitSettings->setAttribute ("audioInputDeviceName", currentSetup.inputDeviceName);
712
713 if (currentAudioDevice != nullptr)
714 {
715 lastExplicitSettings->setAttribute ("audioDeviceRate", currentAudioDevice->getCurrentSampleRate());
716
717 if (currentAudioDevice->getDefaultBufferSize() != currentAudioDevice->getCurrentBufferSizeSamples())
718 lastExplicitSettings->setAttribute ("audioDeviceBufferSize", currentAudioDevice->getCurrentBufferSizeSamples());
719
720 if (! currentSetup.useDefaultInputChannels)
721 lastExplicitSettings->setAttribute ("audioDeviceInChans", currentSetup.inputChannels.toString (2));
722
723 if (! currentSetup.useDefaultOutputChannels)
724 lastExplicitSettings->setAttribute ("audioDeviceOutChans", currentSetup.outputChannels.toString (2));
725 }
726
727 for (auto& input : enabledMidiInputs)
728 {
729 auto* child = lastExplicitSettings->createNewChildElement ("MIDIINPUT");
730
731 child->setAttribute ("name", input->getName());
732 child->setAttribute ("identifier", input->getIdentifier());
733 }
734
735 if (midiDeviceInfosFromXml.size() > 0)
736 {
737 // Add any midi devices that have been enabled before, but which aren't currently
738 // open because the device has been disconnected.
739 auto availableMidiDevices = MidiInput::getAvailableDevices();
740
741 for (auto& d : midiDeviceInfosFromXml)
742 {
743 if (! availableMidiDevices.contains (d))
744 {
745 auto* child = lastExplicitSettings->createNewChildElement ("MIDIINPUT");
746
747 child->setAttribute ("name", d.name);
748 child->setAttribute ("identifier", d.identifier);
749 }
750 }
751 }
752
753 if (defaultMidiOutputDeviceInfo != MidiDeviceInfo())
754 {
755 lastExplicitSettings->setAttribute ("defaultMidiOutput", defaultMidiOutputDeviceInfo.name);
756 lastExplicitSettings->setAttribute ("defaultMidiOutputDevice", defaultMidiOutputDeviceInfo.identifier);
757 }
758}
759
760//==============================================================================
762{
763 {
764 const ScopedLock sl (audioCallbackLock);
765
766 if (callbacks.contains (newCallback))
767 return;
768 }
769
770 if (currentAudioDevice != nullptr && newCallback != nullptr)
771 newCallback->audioDeviceAboutToStart (currentAudioDevice.get());
772
773 const ScopedLock sl (audioCallbackLock);
774 callbacks.add (newCallback);
775}
776
778{
779 if (callbackToRemove != nullptr)
780 {
781 bool needsDeinitialising = currentAudioDevice != nullptr;
782
783 {
784 const ScopedLock sl (audioCallbackLock);
785
788 }
789
791 callbackToRemove->audioDeviceStopped();
792 }
793}
794
795void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelData,
797 float** outputChannelData,
799 int numSamples)
800{
801 const ScopedLock sl (audioCallbackLock);
802
803 inputLevelGetter->updateLevel (inputChannelData, numInputChannels, numSamples);
804 outputLevelGetter->updateLevel (const_cast<const float**> (outputChannelData), numOutputChannels, numSamples);
805
806 if (callbacks.size() > 0)
807 {
808 AudioProcessLoadMeasurer::ScopedTimer timer (loadMeasurer);
809
810 tempBuffer.setSize (jmax (1, numOutputChannels), jmax (1, numSamples), false, false, true);
811
812 callbacks.getUnchecked(0)->audioDeviceIOCallback (inputChannelData, numInputChannels,
814
815 auto** tempChans = tempBuffer.getArrayOfWritePointers();
816
817 for (int i = callbacks.size(); --i > 0;)
818 {
819 callbacks.getUnchecked(i)->audioDeviceIOCallback (inputChannelData, numInputChannels,
820 tempChans, numOutputChannels, numSamples);
821
822 for (int chan = 0; chan < numOutputChannels; ++chan)
823 {
824 if (auto* src = tempChans [chan])
825 if (auto* dst = outputChannelData [chan])
826 for (int j = 0; j < numSamples; ++j)
827 dst[j] += src[j];
828 }
829 }
830 }
831 else
832 {
833 for (int i = 0; i < numOutputChannels; ++i)
834 zeromem (outputChannelData[i], (size_t) numSamples * sizeof (float));
835 }
836
837 if (testSound != nullptr)
838 {
839 auto numSamps = jmin (numSamples, testSound->getNumSamples() - testSoundPosition);
840 auto* src = testSound->getReadPointer (0, testSoundPosition);
841
842 for (int i = 0; i < numOutputChannels; ++i)
843 for (int j = 0; j < numSamps; ++j)
844 outputChannelData [i][j] += src[j];
845
846 testSoundPosition += numSamps;
847
848 if (testSoundPosition >= testSound->getNumSamples())
849 testSound.reset();
850 }
851}
852
853void AudioDeviceManager::audioDeviceAboutToStartInt (AudioIODevice* const device)
854{
855 loadMeasurer.reset (device->getCurrentSampleRate(),
856 device->getCurrentBufferSizeSamples());
857
858 {
859 const ScopedLock sl (audioCallbackLock);
860
861 for (int i = callbacks.size(); --i >= 0;)
862 callbacks.getUnchecked(i)->audioDeviceAboutToStart (device);
863 }
864
866}
867
868void AudioDeviceManager::audioDeviceStoppedInt()
869{
871
872 const ScopedLock sl (audioCallbackLock);
873
874 loadMeasurer.reset();
875
876 for (int i = callbacks.size(); --i >= 0;)
877 callbacks.getUnchecked(i)->audioDeviceStopped();
878}
879
880void AudioDeviceManager::audioDeviceErrorInt (const String& message)
881{
882 const ScopedLock sl (audioCallbackLock);
883
884 for (int i = callbacks.size(); --i >= 0;)
885 callbacks.getUnchecked(i)->audioDeviceError (message);
886}
887
889{
890 return loadMeasurer.getLoadAsProportion();
891}
892
893//==============================================================================
894void AudioDeviceManager::setMidiInputDeviceEnabled (const String& identifier, bool enabled)
895{
896 if (enabled != isMidiInputDeviceEnabled (identifier))
897 {
898 if (enabled)
899 {
900 if (auto midiIn = MidiInput::openDevice (identifier, callbackHandler.get()))
901 {
902 enabledMidiInputs.push_back (std::move (midiIn));
903 enabledMidiInputs.back()->start();
904 }
905 }
906 else
907 {
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));
911 }
912
913 updateXml();
915 }
916}
917
919{
920 for (auto& mi : enabledMidiInputs)
921 if (mi->getIdentifier() == identifier)
922 return true;
923
924 return false;
925}
926
928{
930
931 if (identifier.isEmpty() || isMidiInputDeviceEnabled (identifier))
932 {
933 const ScopedLock sl (midiCallbackLock);
934 midiCallbacks.add ({ identifier, callbackToAdd });
935 }
936}
937
939{
940 for (int i = midiCallbacks.size(); --i >= 0;)
941 {
942 auto& mc = midiCallbacks.getReference (i);
943
944 if (mc.callback == callbackToRemove && mc.deviceIdentifier == identifier)
945 {
946 const ScopedLock sl (midiCallbackLock);
947 midiCallbacks.remove (i);
948 }
949 }
950}
951
952void AudioDeviceManager::handleIncomingMidiMessageInt (MidiInput* source, const MidiMessage& message)
953{
954 if (! message.isActiveSense())
955 {
956 const ScopedLock sl (midiCallbackLock);
957
958 for (auto& mc : midiCallbacks)
959 if (mc.deviceIdentifier.isEmpty() || mc.deviceIdentifier == source->getIdentifier())
960 mc.callback->handleIncomingMidiMessage (source, message);
961 }
962}
963
964//==============================================================================
966{
967 if (defaultMidiOutputDeviceInfo.identifier != identifier)
968 {
970
971 {
972 const ScopedLock sl (audioCallbackLock);
973 oldCallbacks.swapWith (callbacks);
974 }
975
976 if (currentAudioDevice != nullptr)
977 for (int i = oldCallbacks.size(); --i >= 0;)
978 oldCallbacks.getUnchecked (i)->audioDeviceStopped();
979
980 defaultMidiOutput.reset();
981
982 if (identifier.isNotEmpty())
983 defaultMidiOutput = MidiOutput::openDevice (identifier);
984
985 if (defaultMidiOutput != nullptr)
986 defaultMidiOutputDeviceInfo = defaultMidiOutput->getDeviceInfo();
987 else
988 defaultMidiOutputDeviceInfo = {};
989
990 if (currentAudioDevice != nullptr)
991 for (auto* c : oldCallbacks)
992 c->audioDeviceAboutToStart (currentAudioDevice.get());
993
994 {
995 const ScopedLock sl (audioCallbackLock);
996 oldCallbacks.swapWith (callbacks);
997 }
998
999 updateXml();
1001 }
1002}
1003
1004//==============================================================================
1005AudioDeviceManager::LevelMeter::LevelMeter() noexcept : level() {}
1006
1007void AudioDeviceManager::LevelMeter::updateLevel (const float* const* channelData, int numChannels, int numSamples) noexcept
1008{
1009 if (getReferenceCount() <= 1)
1010 return;
1011
1012 auto localLevel = level.get();
1013
1014 if (numChannels > 0)
1015 {
1016 for (int j = 0; j < numSamples; ++j)
1017 {
1018 float s = 0;
1019
1020 for (int i = 0; i < numChannels; ++i)
1021 s += std::abs (channelData[i][j]);
1022
1023 s /= (float) numChannels;
1024
1025 const float decayFactor = 0.99992f;
1026
1027 if (s > localLevel)
1028 localLevel = s;
1029 else if (localLevel > 0.001f)
1030 localLevel *= decayFactor;
1031 else
1032 localLevel = 0;
1033 }
1034 }
1035 else
1036 {
1037 localLevel = 0;
1038 }
1039
1040 level = localLevel;
1041}
1042
1043double AudioDeviceManager::LevelMeter::getCurrentLevel() const noexcept
1044{
1045 jassert (getReferenceCount() > 1);
1046 return level.get();
1047}
1048
1050{
1051 { // cunningly nested to swap, unlock and delete in that order.
1052 std::unique_ptr<AudioBuffer<float>> oldSound;
1053
1054 {
1055 const ScopedLock sl (audioCallbackLock);
1056 std::swap (oldSound, testSound);
1057 }
1058 }
1059
1060 testSoundPosition = 0;
1061
1062 if (currentAudioDevice != nullptr)
1063 {
1064 auto sampleRate = currentAudioDevice->getCurrentSampleRate();
1065 auto soundLength = (int) sampleRate;
1066
1067 double frequency = 440.0;
1068 float amplitude = 0.5f;
1069
1070 auto phasePerSample = MathConstants<double>::twoPi / (sampleRate / frequency);
1071
1072 std::unique_ptr<AudioBuffer<float>> newSound (new AudioBuffer<float> (1, soundLength));
1073
1074 for (int i = 0; i < soundLength; ++i)
1075 newSound->setSample (0, i, amplitude * (float) std::sin (i * phasePerSample));
1076
1077 newSound->applyGainRamp (0, 0, soundLength / 10, 0.0f, 1.0f);
1078 newSound->applyGainRamp (0, soundLength - soundLength / 4, soundLength / 4, 1.0f, 0.0f);
1079
1080 {
1081 const ScopedLock sl (audioCallbackLock);
1082 std::swap (testSound, newSound);
1083 }
1084 }
1085}
1086
1088{
1089 auto deviceXRuns = (currentAudioDevice != nullptr ? currentAudioDevice->getXRunCount() : -1);
1090 return jmax (0, deviceXRuns) + loadMeasurer.getXRunCount();
1091}
1092
1093//==============================================================================
1094// Deprecated
1095void AudioDeviceManager::setMidiInputEnabled (const String& name, const bool enabled)
1096{
1098 {
1099 if (device.name == name)
1100 {
1101 setMidiInputDeviceEnabled (device.identifier, enabled);
1102 return;
1103 }
1104 }
1105}
1106
1108{
1110 if (device.name == name)
1111 return isMidiInputDeviceEnabled (device.identifier);
1112
1113 return false;
1114}
1115
1117{
1118 if (name.isEmpty())
1119 {
1121 }
1122 else
1123 {
1125 {
1126 if (device.name == name)
1127 {
1129 return;
1130 }
1131 }
1132 }
1133}
1134
1136{
1138 {
1139 if (device.name == name)
1140 {
1142 return;
1143 }
1144 }
1145}
1146
1148{
1150 {
1151 if (device.name == name)
1152 {
1154 return;
1155 }
1156 }
1157}
1158
1159} // namespace juce
void swapWith(OtherArrayType &otherArray) noexcept
Definition juce_Array.h:621
ElementType getUnchecked(int index) const
Definition juce_Array.h:252
bool isEmpty() const noexcept
Definition juce_Array.h:222
int size() const noexcept
Definition juce_Array.h:215
void removeFirstMatchingValue(ParameterType valueToRemove)
Definition juce_Array.h:834
void remove(int indexToRemove)
Definition juce_Array.h:767
ElementType getFirst() const noexcept
Definition juce_Array.h:290
int indexOf(ParameterType elementToLookFor) const
Definition juce_Array.h:382
void add(const ElementType &newElement)
Definition juce_Array.h:418
ElementType removeAndReturn(int indexToRemove)
Definition juce_Array.h:785
bool contains(ParameterType elementToLookFor) const
Definition juce_Array.h:400
void clear()
Definition juce_Array.h:188
ElementType & getReference(int index) noexcept
Definition juce_Array.h:267
ElementType getLast() const noexcept
Definition juce_Array.h:300
void setSize(int newNumChannels, int newNumSamples, bool keepExistingContent=false, bool clearExtraSpace=false, bool avoidReallocating=false)
Type ** getArrayOfWritePointers() noexcept
bool isMidiInputDeviceEnabled(const String &deviceIdentifier) const
void removeAudioDeviceType(AudioIODeviceType *deviceTypeToRemove)
AudioDeviceSetup getAudioDeviceSetup() const
void removeMidiInputDeviceCallback(const String &deviceIdentifier, MidiInputCallback *callback)
AudioIODeviceType * getCurrentDeviceTypeObject() const
String setAudioDeviceSetup(const AudioDeviceSetup &newSetup, bool treatAsChosenDevice)
void removeMidiInputCallback(const String &, MidiInputCallback *)
bool isMidiInputEnabled(const String &) const
virtual void createAudioDeviceTypes(OwnedArray< AudioIODeviceType > &types)
void setMidiInputEnabled(const String &, bool)
void setDefaultMidiOutputDevice(const String &deviceIdentifier)
void setMidiInputDeviceEnabled(const String &deviceIdentifier, bool enabled)
void setDefaultMidiOutput(const String &)
void addMidiInputCallback(const String &, MidiInputCallback *)
void addMidiInputDeviceCallback(const String &deviceIdentifier, MidiInputCallback *callback)
void setCurrentAudioDeviceType(const String &type, bool treatAsChosenDevice)
const OwnedArray< AudioIODeviceType > & getAvailableDeviceTypes()
String initialise(int numInputChannelsNeeded, int numOutputChannelsNeeded, const XmlElement *savedState, bool selectDefaultDeviceOnFailure, const String &preferredDefaultDeviceName=String(), const AudioDeviceSetup *preferredSetupOptions=nullptr)
void addAudioCallback(AudioIODeviceCallback *newCallback)
String initialiseWithDefaultDevices(int numInputChannelsNeeded, int numOutputChannelsNeeded)
void removeAudioCallback(AudioIODeviceCallback *callback)
void addAudioDeviceType(std::unique_ptr< AudioIODeviceType > newDeviceType)
std::unique_ptr< XmlElement > createStateXml() const
virtual int getDefaultDeviceIndex(bool forInput) const =0
static AudioIODeviceType * createAudioIODeviceType_ASIO()
static AudioIODeviceType * createAudioIODeviceType_Oboe()
static AudioIODeviceType * createAudioIODeviceType_JACK()
static AudioIODeviceType * createAudioIODeviceType_DirectSound()
static AudioIODeviceType * createAudioIODeviceType_Android()
static AudioIODeviceType * createAudioIODeviceType_OpenSLES()
static AudioIODeviceType * createAudioIODeviceType_WASAPI(bool exclusiveMode)
static AudioIODeviceType * createAudioIODeviceType_CoreAudio()
virtual StringArray getDeviceNames(bool wantInputNames=false) const =0
const String & getTypeName() const noexcept
static AudioIODeviceType * createAudioIODeviceType_Bela()
static AudioIODeviceType * createAudioIODeviceType_ALSA()
virtual AudioIODevice * createDevice(const String &outputDeviceName, const String &inputDeviceName)=0
static AudioIODeviceType * createAudioIODeviceType_iOSAudio()
String toString(int base, int minimumNumCharacters=1) const
bool isZero() const noexcept
int countNumberOfSetBits() const noexcept
static Array< MidiDeviceInfo > getAvailableDevices()
static std::unique_ptr< MidiInput > openDevice(const String &deviceIdentifier, MidiInputCallback *callback)
bool isActiveSense() const noexcept
static std::unique_ptr< MidiOutput > openDevice(const String &deviceIdentifier)
static Array< MidiDeviceInfo > getAvailableDevices()
bool isEmpty() const noexcept
void clear() noexcept
bool isNotEmpty() const noexcept
static void JUCE_CALLTYPE sleep(int milliseconds)
bool hasTagName(StringRef possibleTagName) const noexcept