From dbe5768527268b4734dca9df1bd76ff348207ec0 Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Fri, 24 Jun 2011 11:43:38 +0100 Subject: [PATCH] Added device detection for DirectSound. New method addToDesktop() for ResizableWindow. --- .../Source/Application/jucer_MainWindow.cpp | 12 +- juce_amalgamated.cpp | 423 ++++++++---------- juce_amalgamated.h | 3 + .../windows/juce_ResizableWindow.cpp | 7 +- .../components/windows/juce_ResizableWindow.h | 3 + src/native/windows/juce_win32_ASIO.cpp | 138 ++---- src/native/windows/juce_win32_DirectSound.cpp | 233 +++++----- src/native/windows/juce_win32_Messaging.cpp | 33 ++ src/native/windows/juce_win32_WASAPI.cpp | 23 +- 9 files changed, 395 insertions(+), 480 deletions(-) diff --git a/extras/Introjucer/Source/Application/jucer_MainWindow.cpp b/extras/Introjucer/Source/Application/jucer_MainWindow.cpp index eeac652f1e..9d2f6e880b 100644 --- a/extras/Introjucer/Source/Application/jucer_MainWindow.cpp +++ b/extras/Introjucer/Source/Application/jucer_MainWindow.cpp @@ -37,15 +37,16 @@ ApplicationCommandManager* commandManager = nullptr; MainWindow::MainWindow() : DocumentWindow (JUCEApplication::getInstance()->getApplicationName(), Colour::greyLevel (0.6f), - DocumentWindow::allButtons) + DocumentWindow::allButtons, + false) { setUsingNativeTitleBar (true); setContentOwned (new ProjectContentComponent(), false); -#if ! JUCE_MAC + #if ! JUCE_MAC JucerApplication* app = static_cast (JUCEApplication::getInstance()); setMenuBar (app->menuModel); -#endif + #endif setResizable (true, false); @@ -77,6 +78,11 @@ MainWindow::MainWindow() //getPeer()->setCurrentRenderingEngine (0); getLookAndFeel().setColour (ColourSelector::backgroundColourId, Colours::transparentBlack); + + setVisible (true); + addToDesktop(); + + getContentComponent()->grabKeyboardFocus(); } MainWindow::~MainWindow() diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 533135fdc8..37a1e453a1 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -80492,7 +80492,7 @@ void ResizableWindow::initialise (const bool shouldAddToDesktop) lastNonFullScreenPos.setBounds (50, 50, 256, 256); if (shouldAddToDesktop) - Component::addToDesktop (ResizableWindow::getDesktopWindowStyleFlags()); + addToDesktop(); } int ResizableWindow::getDesktopWindowStyleFlags() const @@ -80505,6 +80505,11 @@ int ResizableWindow::getDesktopWindowStyleFlags() const return styleFlags; } +void ResizableWindow::addToDesktop() +{ + Component::addToDesktop (ResizableWindow::getDesktopWindowStyleFlags()); +} + void ResizableWindow::clearContentComponent() { if (ownsContentComponent) @@ -247265,6 +247270,38 @@ void MessageManager::doPlatformSpecificShutdown() OleUninitialize(); } +class DeviceChangeDetector // (Used by various audio classes) +{ +public: + DeviceChangeDetector (const wchar_t* const name) + : messageWindow (name, (WNDPROC) deviceChangeEventCallback) + { + SetWindowLongPtr (messageWindow.getHWND(), GWLP_USERDATA, (LONG_PTR) this); + } + + virtual ~DeviceChangeDetector() {} + +protected: + virtual void systemDeviceChanged() = 0; + +private: + HiddenMessageWindow messageWindow; + + static LRESULT CALLBACK deviceChangeEventCallback (HWND h, const UINT message, + const WPARAM wParam, const LPARAM lParam) + { + if (message == WM_DEVICECHANGE + && (wParam == 0x8000 /*DBT_DEVICEARRIVAL*/ + || wParam == 0x8004 /*DBT_DEVICEREMOVECOMPLETE*/ + || wParam == 0x0007 /*DBT_DEVNODES_CHANGED*/)) + { + ((DeviceChangeDetector*) GetWindowLongPtr (h, GWLP_USERDATA))->systemDeviceChanged(); + } + + return DefWindowProc (h, message, wParam, lParam); + } +}; + #endif /*** End of inlined file: juce_win32_Messaging.cpp ***/ @@ -256845,8 +256882,6 @@ namespace ASIODebugging class ASIOAudioIODevice; static ASIOAudioIODevice* volatile currentASIODev[3] = { 0 }; -static const int maxASIOChannels = 160; - class JUCE_API ASIOAudioIODevice : public AudioIODevice, private Timer { @@ -257141,30 +257176,7 @@ public: const int totalBuffers = numActiveInputChans + numActiveOutputChans; - callbacks.sampleRateDidChange = &sampleRateChangedCallback; - - if (currentASIODev[0] == this) - { - callbacks.bufferSwitch = &bufferSwitchCallback0; - callbacks.asioMessage = &asioMessagesCallback0; - callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback0; - } - else if (currentASIODev[1] == this) - { - callbacks.bufferSwitch = &bufferSwitchCallback1; - callbacks.asioMessage = &asioMessagesCallback1; - callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback1; - } - else if (currentASIODev[2] == this) - { - callbacks.bufferSwitch = &bufferSwitchCallback2; - callbacks.asioMessage = &asioMessagesCallback2; - callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback2; - } - else - { - jassertfalse; - } + setCallbackFunctions(); log ("disposing buffers"); err = asioObject->disposeBuffers(); @@ -257197,7 +257209,7 @@ public: Array types; currentBitDepth = 16; - for (i = 0; i < jmin ((int) totalNumInputChans, maxASIOChannels); ++i) + for (i = 0; i < jmin ((int) totalNumInputChans, (int) maxASIOChannels); ++i) { if (inputChannels[i]) { @@ -257224,7 +257236,7 @@ public: jassert (numActiveInputChans == n); n = 0; - for (i = 0; i < jmin ((int) totalNumOutputChans, maxASIOChannels); ++i) + for (i = 0; i < jmin ((int) totalNumOutputChans, (int) maxASIOChannels); ++i) { if (outputChannels[i]) { @@ -257518,6 +257530,8 @@ private: AudioIODeviceCallback* volatile currentCallback; CriticalSection callbackLock; + enum { maxASIOChannels = 160 }; + ASIOBufferInfo bufferInfos [maxASIOChannels]; float* inBuffers [maxASIOChannels]; float* outBuffers [maxASIOChannels]; @@ -257749,30 +257763,7 @@ private: ++numChans; } - callbacks.sampleRateDidChange = &sampleRateChangedCallback; - - if (currentASIODev[0] == this) - { - callbacks.bufferSwitch = &bufferSwitchCallback0; - callbacks.asioMessage = &asioMessagesCallback0; - callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback0; - } - else if (currentASIODev[1] == this) - { - callbacks.bufferSwitch = &bufferSwitchCallback1; - callbacks.asioMessage = &asioMessagesCallback1; - callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback1; - } - else if (currentASIODev[2] == this) - { - callbacks.bufferSwitch = &bufferSwitchCallback2; - callbacks.asioMessage = &asioMessagesCallback2; - callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback2; - } - else - { - jassertfalse; - } + setCallbackFunctions(); log ("creating buffers (dummy): " + String (numChans) + ", " + String ((int) preferredSize)); @@ -258028,64 +258019,47 @@ private: asioObject->outputReady(); } - static ASIOTime* JUCE_ASIOCALLBACK bufferSwitchTimeInfoCallback0 (ASIOTime*, long index, long) - { - if (currentASIODev[0] != nullptr) - currentASIODev[0]->callback (index); - - return nullptr; - } - - static ASIOTime* JUCE_ASIOCALLBACK bufferSwitchTimeInfoCallback1 (ASIOTime*, long index, long) + template + struct ASIOCallbackFunctions { - if (currentASIODev[1] != nullptr) - currentASIODev[1]->callback (index); - - return nullptr; - } - - static ASIOTime* JUCE_ASIOCALLBACK bufferSwitchTimeInfoCallback2 (ASIOTime*, long index, long) - { - if (currentASIODev[2] != nullptr) - currentASIODev[2]->callback (index); - - return nullptr; - } + static ASIOTime* JUCE_ASIOCALLBACK bufferSwitchTimeInfoCallback (ASIOTime*, long index, long) + { + if (currentASIODev[deviceIndex] != nullptr) + currentASIODev[deviceIndex]->callback (index); - static void JUCE_ASIOCALLBACK bufferSwitchCallback0 (long index, long) - { - if (currentASIODev[0] != nullptr) - currentASIODev[0]->callback (index); - } + return nullptr; + } - static void JUCE_ASIOCALLBACK bufferSwitchCallback1 (long index, long) - { - if (currentASIODev[1] != nullptr) - currentASIODev[1]->callback (index); - } + static void JUCE_ASIOCALLBACK bufferSwitchCallback (long index, long) + { + if (currentASIODev[deviceIndex] != nullptr) + currentASIODev[deviceIndex]->callback (index); + } - static void JUCE_ASIOCALLBACK bufferSwitchCallback2 (long index, long) - { - if (currentASIODev[2] != nullptr) - currentASIODev[2]->callback (index); - } + static long JUCE_ASIOCALLBACK asioMessagesCallback (long selector, long value, void*, double*) + { + return ASIOAudioIODevice::asioMessagesCallback (selector, value, deviceIndex); + } - static long JUCE_ASIOCALLBACK asioMessagesCallback0 (long selector, long value, void*, double*) - { - return asioMessagesCallback (selector, value, 0); - } + static void setCallbacks (ASIOCallbacks& callbacks) + { + callbacks.bufferSwitch = &bufferSwitchCallback; + callbacks.asioMessage = &asioMessagesCallback; + callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback; + } + }; - static long JUCE_ASIOCALLBACK asioMessagesCallback1 (long selector, long value, void*, double*) + void setCallbackFunctions() { - return asioMessagesCallback (selector, value, 1); - } + callbacks.sampleRateDidChange = &sampleRateChangedCallback; - static long JUCE_ASIOCALLBACK asioMessagesCallback2 (long selector, long value, void*, double*) - { - return asioMessagesCallback (selector, value, 2); + if (currentASIODev[0] == this) ASIOCallbackFunctions<0>::setCallbacks (callbacks); + else if (currentASIODev[1] == this) ASIOCallbackFunctions<1>::setCallbacks (callbacks); + else if (currentASIODev[2] == this) ASIOCallbackFunctions<2>::setCallbacks (callbacks); + else jassertfalse; } - static long JUCE_ASIOCALLBACK asioMessagesCallback (long selector, long value, const int deviceIndex) + static long asioMessagesCallback (long selector, long value, const int deviceIndex) { switch (selector) { @@ -258805,7 +258779,7 @@ namespace class DSoundInternalOutChannel { public: - DSoundInternalOutChannel (const String& name_, LPGUID guid_, int rate, + DSoundInternalOutChannel (const String& name_, const GUID& guid_, int rate, int bufferSize, float* left, float* right) : bitDepth (16), name (name_), guid (guid_), sampleRate (rate), bufferSizeSamples (bufferSize), leftBuffer (left), rightBuffer (right), @@ -258854,7 +258828,7 @@ public: HRESULT hr = E_NOINTERFACE; if (dsDirectSoundCreate != 0) - hr = dsDirectSoundCreate (guid, &pDirectSound, 0); + hr = dsDirectSoundCreate (&guid, &pDirectSound, 0); if (hr == S_OK) { @@ -259093,7 +259067,7 @@ public: private: String name; - LPGUID guid; + GUID guid; int sampleRate, bufferSizeSamples; float* leftBuffer; float* rightBuffer; @@ -259115,7 +259089,7 @@ private: struct DSoundInternalInChannel { public: - DSoundInternalInChannel (const String& name_, LPGUID guid_, int rate, + DSoundInternalInChannel (const String& name_, const GUID& guid_, int rate, int bufferSize, float* left, float* right) : bitDepth (16), name (name_), guid (guid_), sampleRate (rate), bufferSizeSamples (bufferSize), leftBuffer (left), rightBuffer (right), @@ -259173,7 +259147,7 @@ public: HRESULT hr = E_NOINTERFACE; if (dsDirectSoundCaptureCreate != 0) - hr = dsDirectSoundCaptureCreate (guid, &pDirectSoundCapture, 0); + hr = dsDirectSoundCaptureCreate (&guid, &pDirectSoundCapture, 0); logError (hr); @@ -259349,7 +259323,7 @@ public: private: String name; - LPGUID guid; + GUID guid; int sampleRate, bufferSizeSamples; float* leftBuffer; float* rightBuffer; @@ -259668,23 +259642,16 @@ public: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DSoundAudioIODevice); }; -class DSoundAudioIODeviceType : public AudioIODeviceType +struct DSoundDeviceList { -public: - DSoundAudioIODeviceType() - : AudioIODeviceType ("DirectSound"), - hasScanned (false) - { - initialiseDSoundFunctions(); - } + StringArray outputDeviceNames, inputDeviceNames; + Array outputGuids, inputGuids; - void scanForDevices() + void scan() { - hasScanned = true; - outputDeviceNames.clear(); - outputGuids.clear(); inputDeviceNames.clear(); + outputGuids.clear(); inputGuids.clear(); if (dsDirectSoundEnumerateW != 0) @@ -259694,57 +259661,16 @@ public: } } - StringArray getDeviceNames (bool wantInputNames) const - { - jassert (hasScanned); // need to call scanForDevices() before doing this - - return wantInputNames ? inputDeviceNames - : outputDeviceNames; - } - - int getDefaultDeviceIndex (bool /*forInput*/) const + bool operator!= (const DSoundDeviceList& other) const noexcept { - jassert (hasScanned); // need to call scanForDevices() before doing this - return 0; + return outputDeviceNames != other.outputDeviceNames + || inputDeviceNames != other.inputDeviceNames + || outputGuids != other.outputGuids + || inputGuids != other.inputGuids; } - int getIndexOfDevice (AudioIODevice* device, bool asInput) const - { - jassert (hasScanned); // need to call scanForDevices() before doing this - - DSoundAudioIODevice* const d = dynamic_cast (device); - if (d == 0) - return -1; - - return asInput ? d->inputDeviceIndex - : d->outputDeviceIndex; - } - - bool hasSeparateInputsAndOutputs() const { return true; } - - AudioIODevice* createDevice (const String& outputDeviceName, - const String& inputDeviceName) - { - jassert (hasScanned); // need to call scanForDevices() before doing this - - const int outputIndex = outputDeviceNames.indexOf (outputDeviceName); - const int inputIndex = inputDeviceNames.indexOf (inputDeviceName); - - if (outputIndex >= 0 || inputIndex >= 0) - return new DSoundAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName - : inputDeviceName, - outputIndex, inputIndex); - - return nullptr; - } - - StringArray outputDeviceNames, inputDeviceNames; - OwnedArray outputGuids, inputGuids; - private: - bool hasScanned; - - BOOL outputEnumProc (LPGUID lpGUID, String desc) + static BOOL enumProc (LPGUID lpGUID, String desc, StringArray& names, Array& guids) { desc = desc.trim(); @@ -259753,68 +259679,28 @@ private: const String origDesc (desc); int n = 2; - while (outputDeviceNames.contains (desc)) + while (names.contains (desc)) desc = origDesc + " (" + String (n++) + ")"; - outputDeviceNames.add (desc); - - if (lpGUID != 0) - outputGuids.add (new GUID (*lpGUID)); - else - outputGuids.add (nullptr); + names.add (desc); + guids.add (lpGUID != nullptr ? *lpGUID : GUID()); } return TRUE; } - static BOOL CALLBACK outputEnumProcW (LPGUID lpGUID, LPCWSTR description, LPCWSTR, LPVOID object) - { - return ((DSoundAudioIODeviceType*) object) - ->outputEnumProc (lpGUID, String (description)); - } + BOOL outputEnumProc (LPGUID guid, LPCWSTR desc) { return enumProc (guid, desc, outputDeviceNames, outputGuids); } + BOOL inputEnumProc (LPGUID guid, LPCWSTR desc) { return enumProc (guid, desc, inputDeviceNames, inputGuids); } - static BOOL CALLBACK outputEnumProcA (LPGUID lpGUID, LPCTSTR description, LPCTSTR, LPVOID object) + static BOOL CALLBACK outputEnumProcW (LPGUID lpGUID, LPCWSTR description, LPCWSTR, LPVOID object) { - return ((DSoundAudioIODeviceType*) object) - ->outputEnumProc (lpGUID, String (description)); - } - - BOOL CALLBACK inputEnumProc (LPGUID lpGUID, String desc) - { - desc = desc.trim(); - - if (desc.isNotEmpty()) - { - const String origDesc (desc); - - int n = 2; - while (inputDeviceNames.contains (desc)) - desc = origDesc + " (" + String (n++) + ")"; - - inputDeviceNames.add (desc); - - if (lpGUID != 0) - inputGuids.add (new GUID (*lpGUID)); - else - inputGuids.add (nullptr); - } - - return TRUE; + return static_cast (object)->outputEnumProc (lpGUID, description); } static BOOL CALLBACK inputEnumProcW (LPGUID lpGUID, LPCWSTR description, LPCWSTR, LPVOID object) { - return ((DSoundAudioIODeviceType*) object) - ->inputEnumProc (lpGUID, String (description)); + return static_cast (object)->inputEnumProc (lpGUID, description); } - - static BOOL CALLBACK inputEnumProcA (LPGUID lpGUID, LPCTSTR description, LPCTSTR, LPVOID object) - { - return ((DSoundAudioIODeviceType*) object) - ->inputEnumProc (lpGUID, String (description)); - } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DSoundAudioIODeviceType); }; String DSoundAudioIODevice::openDevice (const BigInteger& inputChannels, @@ -259831,8 +259717,8 @@ String DSoundAudioIODevice::openDevice (const BigInteger& inputChannels, bufferSizeSamples = bufferSizeSamples_ & ~7; - DSoundAudioIODeviceType dlh; - dlh.scanForDevices(); + DSoundDeviceList dlh; + dlh.scan(); enabledInputs = inputChannels; enabledInputs.setRange (inChannels.size(), @@ -259945,6 +259831,88 @@ String DSoundAudioIODevice::openDevice (const BigInteger& inputChannels, return error; } +class DSoundAudioIODeviceType : public AudioIODeviceType, + private DeviceChangeDetector +{ +public: + DSoundAudioIODeviceType() + : AudioIODeviceType ("DirectSound"), + DeviceChangeDetector (L"DirectSound"), + hasScanned (false) + { + initialiseDSoundFunctions(); + } + + void scanForDevices() + { + hasScanned = true; + deviceList.scan(); + } + + StringArray getDeviceNames (bool wantInputNames) const + { + jassert (hasScanned); // need to call scanForDevices() before doing this + + return wantInputNames ? deviceList.inputDeviceNames + : deviceList.outputDeviceNames; + } + + int getDefaultDeviceIndex (bool /*forInput*/) const + { + jassert (hasScanned); // need to call scanForDevices() before doing this + return 0; + } + + int getIndexOfDevice (AudioIODevice* device, bool asInput) const + { + jassert (hasScanned); // need to call scanForDevices() before doing this + + DSoundAudioIODevice* const d = dynamic_cast (device); + if (d == 0) + return -1; + + return asInput ? d->inputDeviceIndex + : d->outputDeviceIndex; + } + + bool hasSeparateInputsAndOutputs() const { return true; } + + AudioIODevice* createDevice (const String& outputDeviceName, + const String& inputDeviceName) + { + jassert (hasScanned); // need to call scanForDevices() before doing this + + const int outputIndex = deviceList.outputDeviceNames.indexOf (outputDeviceName); + const int inputIndex = deviceList.inputDeviceNames.indexOf (inputDeviceName); + + if (outputIndex >= 0 || inputIndex >= 0) + return new DSoundAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName + : inputDeviceName, + outputIndex, inputIndex); + + return nullptr; + } + +private: + + DSoundDeviceList deviceList; + bool hasScanned; + + void systemDeviceChanged() + { + DSoundDeviceList newList; + newList.scan(); + + if (newList != deviceList) + { + deviceList = newList; + callDeviceChangeListeners(); + } + } + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DSoundAudioIODeviceType); +}; + AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_DirectSound() { return new DSoundAudioIODeviceType(); @@ -260879,15 +260847,15 @@ private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WASAPIAudioIODevice); }; -class WASAPIAudioIODeviceType : public AudioIODeviceType +class WASAPIAudioIODeviceType : public AudioIODeviceType, + private DeviceChangeDetector { public: WASAPIAudioIODeviceType() : AudioIODeviceType ("Windows Audio"), - deviceChangeCatcher (_T("Windows Audio"), (WNDPROC) deviceChangeEventCallback), + DeviceChangeDetector (L"Windows Audio"), hasScanned (false) { - SetWindowLongPtr (deviceChangeCatcher.getHWND(), GWLP_USERDATA, (LONG_PTR) this); } void scanForDevices() @@ -260957,7 +260925,6 @@ public: StringArray inputDeviceNames, inputDeviceIds; private: - HiddenMessageWindow deviceChangeCatcher; bool hasScanned; static String getDefaultEndpoint (IMMDeviceEnumerator* const enumerator, const bool forCapture) @@ -261045,21 +261012,7 @@ private: outputDeviceNames.appendNumbersToDuplicates (false, false); } - static LRESULT CALLBACK deviceChangeEventCallback (HWND h, const UINT message, - const WPARAM wParam, const LPARAM lParam) - { - if (message == WM_DEVICECHANGE - && (wParam == 0x8000 /*DBT_DEVICEARRIVAL*/ - || wParam == 0x8004 /*DBT_DEVICEREMOVECOMPLETE*/ - || wParam == 0x0007 /*DBT_DEVNODES_CHANGED*/)) - { - ((WASAPIAudioIODeviceType*) GetWindowLongPtr (h, GWLP_USERDATA))->handleDeviceChange(); - } - - return DefWindowProc (h, message, wParam, lParam); - } - - void handleDeviceChange() + void systemDeviceChanged() { StringArray newOutNames, newInNames, newOutIds, newInIds; scan (newOutNames, newInNames, newOutIds, newInIds); diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 37412a9dec..d3b8a50de3 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -57521,6 +57521,9 @@ public: */ void setMinimised (bool shouldMinimise); + /** Adds the window to the desktop using the default flags. */ + void addToDesktop(); + /** Returns a string which encodes the window's current size and position. This string will encapsulate the window's size, position, and whether it's diff --git a/src/gui/components/windows/juce_ResizableWindow.cpp b/src/gui/components/windows/juce_ResizableWindow.cpp index c97026fbcf..4335fef10f 100644 --- a/src/gui/components/windows/juce_ResizableWindow.cpp +++ b/src/gui/components/windows/juce_ResizableWindow.cpp @@ -90,7 +90,7 @@ void ResizableWindow::initialise (const bool shouldAddToDesktop) lastNonFullScreenPos.setBounds (50, 50, 256, 256); if (shouldAddToDesktop) - Component::addToDesktop (ResizableWindow::getDesktopWindowStyleFlags()); + addToDesktop(); } int ResizableWindow::getDesktopWindowStyleFlags() const @@ -103,6 +103,11 @@ int ResizableWindow::getDesktopWindowStyleFlags() const return styleFlags; } +void ResizableWindow::addToDesktop() +{ + Component::addToDesktop (ResizableWindow::getDesktopWindowStyleFlags()); +} + //============================================================================== void ResizableWindow::clearContentComponent() { diff --git a/src/gui/components/windows/juce_ResizableWindow.h b/src/gui/components/windows/juce_ResizableWindow.h index 3b5267b63e..547be4861f 100644 --- a/src/gui/components/windows/juce_ResizableWindow.h +++ b/src/gui/components/windows/juce_ResizableWindow.h @@ -200,6 +200,9 @@ public: */ void setMinimised (bool shouldMinimise); + /** Adds the window to the desktop using the default flags. */ + void addToDesktop(); + //============================================================================== /** Returns a string which encodes the window's current size and position. diff --git a/src/native/windows/juce_win32_ASIO.cpp b/src/native/windows/juce_win32_ASIO.cpp index ff797a7bb5..46502a2b62 100644 --- a/src/native/windows/juce_win32_ASIO.cpp +++ b/src/native/windows/juce_win32_ASIO.cpp @@ -75,8 +75,6 @@ namespace ASIODebugging class ASIOAudioIODevice; static ASIOAudioIODevice* volatile currentASIODev[3] = { 0 }; -static const int maxASIOChannels = 160; - //============================================================================== class JUCE_API ASIOAudioIODevice : public AudioIODevice, @@ -373,30 +371,7 @@ public: const int totalBuffers = numActiveInputChans + numActiveOutputChans; - callbacks.sampleRateDidChange = &sampleRateChangedCallback; - - if (currentASIODev[0] == this) - { - callbacks.bufferSwitch = &bufferSwitchCallback0; - callbacks.asioMessage = &asioMessagesCallback0; - callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback0; - } - else if (currentASIODev[1] == this) - { - callbacks.bufferSwitch = &bufferSwitchCallback1; - callbacks.asioMessage = &asioMessagesCallback1; - callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback1; - } - else if (currentASIODev[2] == this) - { - callbacks.bufferSwitch = &bufferSwitchCallback2; - callbacks.asioMessage = &asioMessagesCallback2; - callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback2; - } - else - { - jassertfalse; - } + setCallbackFunctions(); log ("disposing buffers"); err = asioObject->disposeBuffers(); @@ -429,7 +404,7 @@ public: Array types; currentBitDepth = 16; - for (i = 0; i < jmin ((int) totalNumInputChans, maxASIOChannels); ++i) + for (i = 0; i < jmin ((int) totalNumInputChans, (int) maxASIOChannels); ++i) { if (inputChannels[i]) { @@ -456,7 +431,7 @@ public: jassert (numActiveInputChans == n); n = 0; - for (i = 0; i < jmin ((int) totalNumOutputChans, maxASIOChannels); ++i) + for (i = 0; i < jmin ((int) totalNumOutputChans, (int) maxASIOChannels); ++i) { if (outputChannels[i]) { @@ -750,6 +725,8 @@ private: AudioIODeviceCallback* volatile currentCallback; CriticalSection callbackLock; + enum { maxASIOChannels = 160 }; + ASIOBufferInfo bufferInfos [maxASIOChannels]; float* inBuffers [maxASIOChannels]; float* outBuffers [maxASIOChannels]; @@ -982,31 +959,7 @@ private: ++numChans; } - - callbacks.sampleRateDidChange = &sampleRateChangedCallback; - - if (currentASIODev[0] == this) - { - callbacks.bufferSwitch = &bufferSwitchCallback0; - callbacks.asioMessage = &asioMessagesCallback0; - callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback0; - } - else if (currentASIODev[1] == this) - { - callbacks.bufferSwitch = &bufferSwitchCallback1; - callbacks.asioMessage = &asioMessagesCallback1; - callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback1; - } - else if (currentASIODev[2] == this) - { - callbacks.bufferSwitch = &bufferSwitchCallback2; - callbacks.asioMessage = &asioMessagesCallback2; - callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback2; - } - else - { - jassertfalse; - } + setCallbackFunctions(); log ("creating buffers (dummy): " + String (numChans) + ", " + String ((int) preferredSize)); @@ -1264,65 +1217,48 @@ private: } //============================================================================== - static ASIOTime* JUCE_ASIOCALLBACK bufferSwitchTimeInfoCallback0 (ASIOTime*, long index, long) - { - if (currentASIODev[0] != nullptr) - currentASIODev[0]->callback (index); - - return nullptr; - } - - static ASIOTime* JUCE_ASIOCALLBACK bufferSwitchTimeInfoCallback1 (ASIOTime*, long index, long) + template + struct ASIOCallbackFunctions { - if (currentASIODev[1] != nullptr) - currentASIODev[1]->callback (index); - - return nullptr; - } - - static ASIOTime* JUCE_ASIOCALLBACK bufferSwitchTimeInfoCallback2 (ASIOTime*, long index, long) - { - if (currentASIODev[2] != nullptr) - currentASIODev[2]->callback (index); - - return nullptr; - } + static ASIOTime* JUCE_ASIOCALLBACK bufferSwitchTimeInfoCallback (ASIOTime*, long index, long) + { + if (currentASIODev[deviceIndex] != nullptr) + currentASIODev[deviceIndex]->callback (index); - static void JUCE_ASIOCALLBACK bufferSwitchCallback0 (long index, long) - { - if (currentASIODev[0] != nullptr) - currentASIODev[0]->callback (index); - } + return nullptr; + } - static void JUCE_ASIOCALLBACK bufferSwitchCallback1 (long index, long) - { - if (currentASIODev[1] != nullptr) - currentASIODev[1]->callback (index); - } + static void JUCE_ASIOCALLBACK bufferSwitchCallback (long index, long) + { + if (currentASIODev[deviceIndex] != nullptr) + currentASIODev[deviceIndex]->callback (index); + } - static void JUCE_ASIOCALLBACK bufferSwitchCallback2 (long index, long) - { - if (currentASIODev[2] != nullptr) - currentASIODev[2]->callback (index); - } + static long JUCE_ASIOCALLBACK asioMessagesCallback (long selector, long value, void*, double*) + { + return ASIOAudioIODevice::asioMessagesCallback (selector, value, deviceIndex); + } - static long JUCE_ASIOCALLBACK asioMessagesCallback0 (long selector, long value, void*, double*) - { - return asioMessagesCallback (selector, value, 0); - } + static void setCallbacks (ASIOCallbacks& callbacks) + { + callbacks.bufferSwitch = &bufferSwitchCallback; + callbacks.asioMessage = &asioMessagesCallback; + callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback; + } + }; - static long JUCE_ASIOCALLBACK asioMessagesCallback1 (long selector, long value, void*, double*) + void setCallbackFunctions() { - return asioMessagesCallback (selector, value, 1); - } + callbacks.sampleRateDidChange = &sampleRateChangedCallback; - static long JUCE_ASIOCALLBACK asioMessagesCallback2 (long selector, long value, void*, double*) - { - return asioMessagesCallback (selector, value, 2); + if (currentASIODev[0] == this) ASIOCallbackFunctions<0>::setCallbacks (callbacks); + else if (currentASIODev[1] == this) ASIOCallbackFunctions<1>::setCallbacks (callbacks); + else if (currentASIODev[2] == this) ASIOCallbackFunctions<2>::setCallbacks (callbacks); + else jassertfalse; } //============================================================================== - static long JUCE_ASIOCALLBACK asioMessagesCallback (long selector, long value, const int deviceIndex) + static long asioMessagesCallback (long selector, long value, const int deviceIndex) { switch (selector) { diff --git a/src/native/windows/juce_win32_DirectSound.cpp b/src/native/windows/juce_win32_DirectSound.cpp index 9bb3ff2c0e..d8e1ebda9d 100644 --- a/src/native/windows/juce_win32_DirectSound.cpp +++ b/src/native/windows/juce_win32_DirectSound.cpp @@ -228,7 +228,7 @@ namespace class DSoundInternalOutChannel { public: - DSoundInternalOutChannel (const String& name_, LPGUID guid_, int rate, + DSoundInternalOutChannel (const String& name_, const GUID& guid_, int rate, int bufferSize, float* left, float* right) : bitDepth (16), name (name_), guid (guid_), sampleRate (rate), bufferSizeSamples (bufferSize), leftBuffer (left), rightBuffer (right), @@ -277,7 +277,7 @@ public: HRESULT hr = E_NOINTERFACE; if (dsDirectSoundCreate != 0) - hr = dsDirectSoundCreate (guid, &pDirectSound, 0); + hr = dsDirectSoundCreate (&guid, &pDirectSound, 0); if (hr == S_OK) { @@ -516,7 +516,7 @@ public: private: String name; - LPGUID guid; + GUID guid; int sampleRate, bufferSizeSamples; float* leftBuffer; float* rightBuffer; @@ -539,7 +539,7 @@ private: struct DSoundInternalInChannel { public: - DSoundInternalInChannel (const String& name_, LPGUID guid_, int rate, + DSoundInternalInChannel (const String& name_, const GUID& guid_, int rate, int bufferSize, float* left, float* right) : bitDepth (16), name (name_), guid (guid_), sampleRate (rate), bufferSizeSamples (bufferSize), leftBuffer (left), rightBuffer (right), @@ -597,7 +597,7 @@ public: HRESULT hr = E_NOINTERFACE; if (dsDirectSoundCaptureCreate != 0) - hr = dsDirectSoundCaptureCreate (guid, &pDirectSoundCapture, 0); + hr = dsDirectSoundCaptureCreate (&guid, &pDirectSoundCapture, 0); logError (hr); @@ -773,7 +773,7 @@ public: private: String name; - LPGUID guid; + GUID guid; int sampleRate, bufferSizeSamples; float* leftBuffer; float* rightBuffer; @@ -1094,26 +1094,17 @@ public: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DSoundAudioIODevice); }; - //============================================================================== -class DSoundAudioIODeviceType : public AudioIODeviceType +struct DSoundDeviceList { -public: - DSoundAudioIODeviceType() - : AudioIODeviceType ("DirectSound"), - hasScanned (false) - { - initialiseDSoundFunctions(); - } + StringArray outputDeviceNames, inputDeviceNames; + Array outputGuids, inputGuids; - //============================================================================== - void scanForDevices() + void scan() { - hasScanned = true; - outputDeviceNames.clear(); - outputGuids.clear(); inputDeviceNames.clear(); + outputGuids.clear(); inputGuids.clear(); if (dsDirectSoundEnumerateW != 0) @@ -1123,59 +1114,16 @@ public: } } - StringArray getDeviceNames (bool wantInputNames) const - { - jassert (hasScanned); // need to call scanForDevices() before doing this - - return wantInputNames ? inputDeviceNames - : outputDeviceNames; - } - - int getDefaultDeviceIndex (bool /*forInput*/) const - { - jassert (hasScanned); // need to call scanForDevices() before doing this - return 0; - } - - int getIndexOfDevice (AudioIODevice* device, bool asInput) const + bool operator!= (const DSoundDeviceList& other) const noexcept { - jassert (hasScanned); // need to call scanForDevices() before doing this - - DSoundAudioIODevice* const d = dynamic_cast (device); - if (d == 0) - return -1; - - return asInput ? d->inputDeviceIndex - : d->outputDeviceIndex; + return outputDeviceNames != other.outputDeviceNames + || inputDeviceNames != other.inputDeviceNames + || outputGuids != other.outputGuids + || inputGuids != other.inputGuids; } - bool hasSeparateInputsAndOutputs() const { return true; } - - AudioIODevice* createDevice (const String& outputDeviceName, - const String& inputDeviceName) - { - jassert (hasScanned); // need to call scanForDevices() before doing this - - const int outputIndex = outputDeviceNames.indexOf (outputDeviceName); - const int inputIndex = inputDeviceNames.indexOf (inputDeviceName); - - if (outputIndex >= 0 || inputIndex >= 0) - return new DSoundAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName - : inputDeviceName, - outputIndex, inputIndex); - - return nullptr; - } - - //============================================================================== - StringArray outputDeviceNames, inputDeviceNames; - OwnedArray outputGuids, inputGuids; - private: - bool hasScanned; - - //============================================================================== - BOOL outputEnumProc (LPGUID lpGUID, String desc) + static BOOL enumProc (LPGUID lpGUID, String desc, StringArray& names, Array& guids) { desc = desc.trim(); @@ -1184,70 +1132,28 @@ private: const String origDesc (desc); int n = 2; - while (outputDeviceNames.contains (desc)) + while (names.contains (desc)) desc = origDesc + " (" + String (n++) + ")"; - outputDeviceNames.add (desc); - - if (lpGUID != 0) - outputGuids.add (new GUID (*lpGUID)); - else - outputGuids.add (nullptr); + names.add (desc); + guids.add (lpGUID != nullptr ? *lpGUID : GUID()); } return TRUE; } - static BOOL CALLBACK outputEnumProcW (LPGUID lpGUID, LPCWSTR description, LPCWSTR, LPVOID object) - { - return ((DSoundAudioIODeviceType*) object) - ->outputEnumProc (lpGUID, String (description)); - } - - static BOOL CALLBACK outputEnumProcA (LPGUID lpGUID, LPCTSTR description, LPCTSTR, LPVOID object) - { - return ((DSoundAudioIODeviceType*) object) - ->outputEnumProc (lpGUID, String (description)); - } + BOOL outputEnumProc (LPGUID guid, LPCWSTR desc) { return enumProc (guid, desc, outputDeviceNames, outputGuids); } + BOOL inputEnumProc (LPGUID guid, LPCWSTR desc) { return enumProc (guid, desc, inputDeviceNames, inputGuids); } - //============================================================================== - BOOL CALLBACK inputEnumProc (LPGUID lpGUID, String desc) + static BOOL CALLBACK outputEnumProcW (LPGUID lpGUID, LPCWSTR description, LPCWSTR, LPVOID object) { - desc = desc.trim(); - - if (desc.isNotEmpty()) - { - const String origDesc (desc); - - int n = 2; - while (inputDeviceNames.contains (desc)) - desc = origDesc + " (" + String (n++) + ")"; - - inputDeviceNames.add (desc); - - if (lpGUID != 0) - inputGuids.add (new GUID (*lpGUID)); - else - inputGuids.add (nullptr); - } - - return TRUE; + return static_cast (object)->outputEnumProc (lpGUID, description); } static BOOL CALLBACK inputEnumProcW (LPGUID lpGUID, LPCWSTR description, LPCWSTR, LPVOID object) { - return ((DSoundAudioIODeviceType*) object) - ->inputEnumProc (lpGUID, String (description)); - } - - static BOOL CALLBACK inputEnumProcA (LPGUID lpGUID, LPCTSTR description, LPCTSTR, LPVOID object) - { - return ((DSoundAudioIODeviceType*) object) - ->inputEnumProc (lpGUID, String (description)); + return static_cast (object)->inputEnumProc (lpGUID, description); } - - //============================================================================== - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DSoundAudioIODeviceType); }; //============================================================================== @@ -1265,8 +1171,8 @@ String DSoundAudioIODevice::openDevice (const BigInteger& inputChannels, bufferSizeSamples = bufferSizeSamples_ & ~7; - DSoundAudioIODeviceType dlh; - dlh.scanForDevices(); + DSoundDeviceList dlh; + dlh.scan(); enabledInputs = inputChannels; enabledInputs.setRange (inChannels.size(), @@ -1379,6 +1285,91 @@ String DSoundAudioIODevice::openDevice (const BigInteger& inputChannels, return error; } +//============================================================================== +class DSoundAudioIODeviceType : public AudioIODeviceType, + private DeviceChangeDetector +{ +public: + DSoundAudioIODeviceType() + : AudioIODeviceType ("DirectSound"), + DeviceChangeDetector (L"DirectSound"), + hasScanned (false) + { + initialiseDSoundFunctions(); + } + + //============================================================================== + void scanForDevices() + { + hasScanned = true; + deviceList.scan(); + } + + StringArray getDeviceNames (bool wantInputNames) const + { + jassert (hasScanned); // need to call scanForDevices() before doing this + + return wantInputNames ? deviceList.inputDeviceNames + : deviceList.outputDeviceNames; + } + + int getDefaultDeviceIndex (bool /*forInput*/) const + { + jassert (hasScanned); // need to call scanForDevices() before doing this + return 0; + } + + int getIndexOfDevice (AudioIODevice* device, bool asInput) const + { + jassert (hasScanned); // need to call scanForDevices() before doing this + + DSoundAudioIODevice* const d = dynamic_cast (device); + if (d == 0) + return -1; + + return asInput ? d->inputDeviceIndex + : d->outputDeviceIndex; + } + + bool hasSeparateInputsAndOutputs() const { return true; } + + AudioIODevice* createDevice (const String& outputDeviceName, + const String& inputDeviceName) + { + jassert (hasScanned); // need to call scanForDevices() before doing this + + const int outputIndex = deviceList.outputDeviceNames.indexOf (outputDeviceName); + const int inputIndex = deviceList.inputDeviceNames.indexOf (inputDeviceName); + + if (outputIndex >= 0 || inputIndex >= 0) + return new DSoundAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName + : inputDeviceName, + outputIndex, inputIndex); + + return nullptr; + } + +private: + //============================================================================== + DSoundDeviceList deviceList; + bool hasScanned; + + void systemDeviceChanged() + { + DSoundDeviceList newList; + newList.scan(); + + if (newList != deviceList) + { + deviceList = newList; + callDeviceChangeListeners(); + } + } + + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DSoundAudioIODeviceType); +}; + //============================================================================== AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_DirectSound() { diff --git a/src/native/windows/juce_win32_Messaging.cpp b/src/native/windows/juce_win32_Messaging.cpp index 45a5f109af..5b237f40de 100644 --- a/src/native/windows/juce_win32_Messaging.cpp +++ b/src/native/windows/juce_win32_Messaging.cpp @@ -344,4 +344,37 @@ void MessageManager::doPlatformSpecificShutdown() OleUninitialize(); } +//============================================================================== +class DeviceChangeDetector // (Used by various audio classes) +{ +public: + DeviceChangeDetector (const wchar_t* const name) + : messageWindow (name, (WNDPROC) deviceChangeEventCallback) + { + SetWindowLongPtr (messageWindow.getHWND(), GWLP_USERDATA, (LONG_PTR) this); + } + + virtual ~DeviceChangeDetector() {} + +protected: + virtual void systemDeviceChanged() = 0; + +private: + HiddenMessageWindow messageWindow; + + static LRESULT CALLBACK deviceChangeEventCallback (HWND h, const UINT message, + const WPARAM wParam, const LPARAM lParam) + { + if (message == WM_DEVICECHANGE + && (wParam == 0x8000 /*DBT_DEVICEARRIVAL*/ + || wParam == 0x8004 /*DBT_DEVICEREMOVECOMPLETE*/ + || wParam == 0x0007 /*DBT_DEVNODES_CHANGED*/)) + { + ((DeviceChangeDetector*) GetWindowLongPtr (h, GWLP_USERDATA))->systemDeviceChanged(); + } + + return DefWindowProc (h, message, wParam, lParam); + } +}; + #endif diff --git a/src/native/windows/juce_win32_WASAPI.cpp b/src/native/windows/juce_win32_WASAPI.cpp index 2cd4d09187..68c65d164f 100644 --- a/src/native/windows/juce_win32_WASAPI.cpp +++ b/src/native/windows/juce_win32_WASAPI.cpp @@ -958,15 +958,15 @@ private: //============================================================================== -class WASAPIAudioIODeviceType : public AudioIODeviceType +class WASAPIAudioIODeviceType : public AudioIODeviceType, + private DeviceChangeDetector { public: WASAPIAudioIODeviceType() : AudioIODeviceType ("Windows Audio"), - deviceChangeCatcher (_T("Windows Audio"), (WNDPROC) deviceChangeEventCallback), + DeviceChangeDetector (L"Windows Audio"), hasScanned (false) { - SetWindowLongPtr (deviceChangeCatcher.getHWND(), GWLP_USERDATA, (LONG_PTR) this); } //============================================================================== @@ -1038,7 +1038,6 @@ public: StringArray inputDeviceNames, inputDeviceIds; private: - HiddenMessageWindow deviceChangeCatcher; bool hasScanned; //============================================================================== @@ -1129,21 +1128,7 @@ private: } //============================================================================== - static LRESULT CALLBACK deviceChangeEventCallback (HWND h, const UINT message, - const WPARAM wParam, const LPARAM lParam) - { - if (message == WM_DEVICECHANGE - && (wParam == 0x8000 /*DBT_DEVICEARRIVAL*/ - || wParam == 0x8004 /*DBT_DEVICEREMOVECOMPLETE*/ - || wParam == 0x0007 /*DBT_DEVNODES_CHANGED*/)) - { - ((WASAPIAudioIODeviceType*) GetWindowLongPtr (h, GWLP_USERDATA))->handleDeviceChange(); - } - - return DefWindowProc (h, message, wParam, lParam); - } - - void handleDeviceChange() + void systemDeviceChanged() { StringArray newOutNames, newInNames, newOutIds, newInIds; scan (newOutNames, newInNames, newOutIds, newInIds);