@@ -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<JucerApplication*> (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() | |||
@@ -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 <int> 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 <int deviceIndex> | |||
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<GUID> 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 <DSoundAudioIODevice*> (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 <GUID> outputGuids, inputGuids; | |||
private: | |||
bool hasScanned; | |||
BOOL outputEnumProc (LPGUID lpGUID, String desc) | |||
static BOOL enumProc (LPGUID lpGUID, String desc, StringArray& names, Array<GUID>& 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<DSoundDeviceList*> (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<DSoundDeviceList*> (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 <DSoundAudioIODevice*> (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); | |||
@@ -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 | |||
@@ -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() | |||
{ | |||
@@ -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. | |||
@@ -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 <int> 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 <int deviceIndex> | |||
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) | |||
{ | |||
@@ -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<GUID> 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 <DSoundAudioIODevice*> (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 <GUID> outputGuids, inputGuids; | |||
private: | |||
bool hasScanned; | |||
//============================================================================== | |||
BOOL outputEnumProc (LPGUID lpGUID, String desc) | |||
static BOOL enumProc (LPGUID lpGUID, String desc, StringArray& names, Array<GUID>& 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<DSoundDeviceList*> (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<DSoundDeviceList*> (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 <DSoundAudioIODevice*> (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() | |||
{ | |||
@@ -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 |
@@ -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); | |||