Browse Source

Added device detection for DirectSound. New method addToDesktop() for ResizableWindow.

tags/2021-05-28
Julian Storer 14 years ago
parent
commit
dbe5768527
9 changed files with 395 additions and 480 deletions
  1. +9
    -3
      extras/Introjucer/Source/Application/jucer_MainWindow.cpp
  2. +188
    -235
      juce_amalgamated.cpp
  3. +3
    -0
      juce_amalgamated.h
  4. +6
    -1
      src/gui/components/windows/juce_ResizableWindow.cpp
  5. +3
    -0
      src/gui/components/windows/juce_ResizableWindow.h
  6. +37
    -101
      src/native/windows/juce_win32_ASIO.cpp
  7. +112
    -121
      src/native/windows/juce_win32_DirectSound.cpp
  8. +33
    -0
      src/native/windows/juce_win32_Messaging.cpp
  9. +4
    -19
      src/native/windows/juce_win32_WASAPI.cpp

+ 9
- 3
extras/Introjucer/Source/Application/jucer_MainWindow.cpp View File

@@ -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()


+ 188
- 235
juce_amalgamated.cpp View File

@@ -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);


+ 3
- 0
juce_amalgamated.h View File

@@ -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


+ 6
- 1
src/gui/components/windows/juce_ResizableWindow.cpp View File

@@ -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()
{


+ 3
- 0
src/gui/components/windows/juce_ResizableWindow.h View File

@@ -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.


+ 37
- 101
src/native/windows/juce_win32_ASIO.cpp View File

@@ -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)
{


+ 112
- 121
src/native/windows/juce_win32_DirectSound.cpp View File

@@ -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()
{


+ 33
- 0
src/native/windows/juce_win32_Messaging.cpp View File

@@ -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

+ 4
- 19
src/native/windows/juce_win32_WASAPI.cpp View File

@@ -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);


Loading…
Cancel
Save