OpenShot Audio Library | OpenShotAudio  0.3.0
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 
23 namespace juce
24 {
25 
26 bool 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 
38 bool AudioDeviceManager::AudioDeviceSetup::operator!= (const AudioDeviceManager::AudioDeviceSetup& other) const
39 {
40  return ! operator== (other);
41 }
42 
43 //==============================================================================
44 class AudioDeviceManager::CallbackHandler : public AudioIODeviceCallback,
45  public MidiInputCallback,
46  public AudioIODeviceType::Listener
47 {
48 public:
49  CallbackHandler (AudioDeviceManager& adm) noexcept : owner (adm) {}
50 
51 private:
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 //==============================================================================
100 void AudioDeviceManager::createDeviceTypesIfNeeded()
101 {
102  if (availableDeviceTypes.size() == 0)
103  {
105  createAudioDeviceTypes (types);
106 
107  for (auto* t : types)
108  addAudioDeviceType (std::unique_ptr<AudioIODeviceType> (t));
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 
123 void AudioDeviceManager::audioDeviceListChanged()
124 {
125  if (currentAudioDevice != nullptr)
126  {
127  auto isCurrentDeviceStillAvailable = [&]
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 //==============================================================================
161 static void addIfNotNull (OwnedArray<AudioIODeviceType>& list, AudioIODeviceType* const device)
162 {
163  if (device != nullptr)
164  list.add (device);
165 }
166 
168 {
169  addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI (false));
170  addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI (true));
181 }
182 
183 void 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 
212 static 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 //==============================================================================
222 String AudioDeviceManager::initialise (const int numInputChannelsNeeded,
223  const int numOutputChannelsNeeded,
224  const XmlElement* const xml,
225  const bool selectDefaultDeviceOnFailure,
226  const String& preferredDefaultDeviceName,
227  const AudioDeviceSetup* preferredSetupOptions)
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 
242 String AudioDeviceManager::initialiseDefault (const String& preferredDefaultDeviceName,
243  const AudioDeviceSetup* preferredSetupOptions)
244 {
245  AudioDeviceSetup setup;
246 
247  if (preferredSetupOptions != nullptr)
248  {
249  setup = *preferredSetupOptions;
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 
279 String 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 
389  int numOutputChannelsNeeded)
390 {
391  lastExplicitSettings.reset();
392 
393  return initialise (numInputChannelsNeeded, numOutputChannelsNeeded,
394  nullptr, false, {}, nullptr);
395 }
396 
397 void 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 
409 std::unique_ptr<XmlElement> AudioDeviceManager::createStateXml() const
410 {
411  if (lastExplicitSettings != nullptr)
412  return std::make_unique<XmlElement> (*lastExplicitSettings);
413 
414  return {};
415 }
416 
417 //==============================================================================
418 void 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 
431 AudioIODeviceType* 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 
442 AudioIODeviceType* 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 
455 {
456  return currentSetup;
457 }
458 
460 {
461  setup = currentSetup;
462 }
463 
464 void AudioDeviceManager::deleteCurrentDevice()
465 {
466  currentAudioDevice.reset();
467  currentSetup.inputDeviceName.clear();
468  currentSetup.outputDeviceName.clear();
469 }
470 
471 void AudioDeviceManager::setCurrentAudioDeviceType (const String& type, bool treatAsChosenDevice)
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 
490  setAudioDeviceSetup (s, treatAsChosenDevice);
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 
507 static 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 
527  bool treatAsChosenDevice)
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 
541  if (treatAsChosenDevice)
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  {
591  if (treatAsChosenDevice)
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 
620  if (treatAsChosenDevice)
621  updateXml();
622  }
623  else
624  {
625  deleteCurrentDevice();
626  }
627 
628  return error;
629 }
630 
631 double 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 
661 int 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 
671 void 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 
705 void 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 
786  needsDeinitialising = needsDeinitialising && callbacks.contains (callbackToRemove);
787  callbacks.removeFirstMatchingValue (callbackToRemove);
788  }
789 
790  if (needsDeinitialising)
791  callbackToRemove->audioDeviceStopped();
792  }
793 }
794 
795 void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelData,
796  int numInputChannels,
797  float** outputChannelData,
798  int numOutputChannels,
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,
813  outputChannelData, numOutputChannels, numSamples);
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 
853 void 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 
868 void 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 
880 void 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 //==============================================================================
894 void 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 {
929  removeMidiInputDeviceCallback (identifier, callbackToAdd);
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 
952 void 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  {
969  Array<AudioIODeviceCallback*> oldCallbacks;
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 //==============================================================================
1005 AudioDeviceManager::LevelMeter::LevelMeter() noexcept : level() {}
1006 
1007 void 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 
1043 double 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
1095 void AudioDeviceManager::setMidiInputEnabled (const String& name, const bool enabled)
1096 {
1097  for (auto& device : MidiInput::getAvailableDevices())
1098  {
1099  if (device.name == name)
1100  {
1101  setMidiInputDeviceEnabled (device.identifier, enabled);
1102  return;
1103  }
1104  }
1105 }
1106 
1108 {
1109  for (auto& device : MidiInput::getAvailableDevices())
1110  if (device.name == name)
1111  return isMidiInputDeviceEnabled (device.identifier);
1112 
1113  return false;
1114 }
1115 
1117 {
1118  if (name.isEmpty())
1119  {
1120  addMidiInputDeviceCallback ({}, callbackToAdd);
1121  }
1122  else
1123  {
1124  for (auto& device : MidiInput::getAvailableDevices())
1125  {
1126  if (device.name == name)
1127  {
1128  addMidiInputDeviceCallback (device.identifier, callbackToAdd);
1129  return;
1130  }
1131  }
1132  }
1133 }
1134 
1136 {
1137  for (auto& device : MidiInput::getAvailableDevices())
1138  {
1139  if (device.name == name)
1140  {
1141  removeMidiInputDeviceCallback (device.identifier, callbackToRemove);
1142  return;
1143  }
1144  }
1145 }
1146 
1148 {
1149  for (auto& device : MidiOutput::getAvailableDevices())
1150  {
1151  if (device.name == name)
1152  {
1153  setDefaultMidiOutputDevice (device.identifier);
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
int size() const noexcept
Definition: juce_Array.h:215
void remove(int indexToRemove)
Definition: juce_Array.h:767
void add(const ElementType &newElement)
Definition: juce_Array.h:418
ElementType & getReference(int index) noexcept
Definition: juce_Array.h:267
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 void audioDeviceAboutToStart(AudioIODevice *device)=0
virtual void audioDeviceStopped()=0
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
virtual void scanForDevices()=0
static AudioIODeviceType * createAudioIODeviceType_Bela()
virtual AudioIODevice * createDevice(const String &outputDeviceName, const String &inputDeviceName)=0
const String & getTypeName() const noexcept
static AudioIODeviceType * createAudioIODeviceType_ALSA()
static AudioIODeviceType * createAudioIODeviceType_iOSAudio()
String toString(int base, int minimumNumCharacters=1) const
bool isZero() const noexcept
int countNumberOfSetBits() const noexcept
static std::unique_ptr< MidiInput > openDevice(const String &deviceIdentifier, MidiInputCallback *callback)
static Array< MidiDeviceInfo > getAvailableDevices()
String getIdentifier() const noexcept
bool isActiveSense() const noexcept
static Array< MidiDeviceInfo > getAvailableDevices()
static std::unique_ptr< MidiOutput > openDevice(const String &deviceIdentifier)
String trim() const
bool isEmpty() const noexcept
Definition: juce_String.h:296
void clear() noexcept
bool isNotEmpty() const noexcept
Definition: juce_String.h:302
static void JUCE_CALLTYPE sleep(int milliseconds)
bool hasTagName(StringRef possibleTagName) const noexcept