Browse Source

Tweaks to fake mouse-move behaviour. Improvements to WASAPI performance. AudioFormatManager is no longer a singleton - just create your own instance and use it instead.

tags/2021-05-28
Julian Storer 15 years ago
parent
commit
4d6b2daa93
13 changed files with 293 additions and 331 deletions
  1. +1
    -0
      extras/the jucer/build/mac/Jucer.xcodeproj/project.pbxproj
  2. +120
    -152
      juce_amalgamated.cpp
  3. +26
    -12
      juce_amalgamated.h
  4. +10
    -16
      src/audio/audio_file_formats/juce_AudioFormatManager.cpp
  5. +0
    -2
      src/audio/audio_file_formats/juce_AudioFormatManager.h
  6. +3
    -2
      src/audio/audio_file_formats/juce_AudioThumbnail.cpp
  7. +1
    -1
      src/core/juce_StandardHeader.h
  8. +12
    -57
      src/gui/components/juce_Component.cpp
  9. +5
    -8
      src/gui/components/juce_Component.h
  10. +48
    -4
      src/gui/components/juce_Desktop.cpp
  11. +18
    -0
      src/gui/components/juce_Desktop.h
  12. +1
    -1
      src/gui/components/mouse/juce_MouseInputSource.h
  13. +48
    -76
      src/native/windows/juce_win32_WASAPI.cpp

+ 1
- 0
extras/the jucer/build/mac/Jucer.xcodeproj/project.pbxproj View File

@@ -524,6 +524,7 @@
buildSettings = {
COPY_PHASE_STRIP = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "$(HOME)/Applications";
PRODUCT_NAME = Jucer;


+ 120
- 152
juce_amalgamated.cpp View File

@@ -21718,20 +21718,15 @@ AudioFormatManager::AudioFormatManager()

AudioFormatManager::~AudioFormatManager()
{
clearFormats();
clearSingletonInstance();
}

juce_ImplementSingleton (AudioFormatManager);

void AudioFormatManager::registerFormat (AudioFormat* newFormat,
const bool makeThisTheDefaultFormat)
void AudioFormatManager::registerFormat (AudioFormat* newFormat, const bool makeThisTheDefaultFormat)
{
jassert (newFormat != 0);

if (newFormat != 0)
{
#if JUCE_DEBUG
#if JUCE_DEBUG
for (int i = getNumKnownFormats(); --i >= 0;)
{
if (getKnownFormat (i)->getFormatName() == newFormat->getFormatName())
@@ -21739,7 +21734,7 @@ void AudioFormatManager::registerFormat (AudioFormat* newFormat,
jassertfalse; // trying to add the same format twice!
}
}
#endif
#endif

if (makeThisTheDefaultFormat)
defaultFormatIndex = getNumKnownFormats();
@@ -21750,21 +21745,21 @@ void AudioFormatManager::registerFormat (AudioFormat* newFormat,

void AudioFormatManager::registerBasicFormats()
{
#if JUCE_MAC
#if JUCE_MAC
registerFormat (new AiffAudioFormat(), true);
registerFormat (new WavAudioFormat(), false);
#else
#else
registerFormat (new WavAudioFormat(), true);
registerFormat (new AiffAudioFormat(), false);
#endif
#endif

#if JUCE_USE_FLAC
#if JUCE_USE_FLAC
registerFormat (new FlacAudioFormat(), false);
#endif
#endif

#if JUCE_USE_OGGVORBIS
#if JUCE_USE_OGGVORBIS
registerFormat (new OggVorbisAudioFormat(), false);
#endif
#endif
}

void AudioFormatManager::clearFormats()
@@ -22298,9 +22293,10 @@ public:
for (int w = clip.getWidth(); --w >= 0;)
{
if (cacheData->isNonZero())
g.drawVerticalLine (x++, jmax (midY - cacheData->maxValue * vscale - 0.3f, topY),
jmin (midY - cacheData->minValue * vscale + 0.3f, bottomY));
g.drawVerticalLine (x, jmax (midY - cacheData->maxValue * vscale - 0.3f, topY),
jmin (midY - cacheData->minValue * vscale + 0.3f, bottomY));

++x;
++cacheData;
}
}
@@ -41995,57 +41991,6 @@ void Component::internalMouseExit (MouseInputSource& source, const Point<int>& r
}
}

class InternalDragRepeater : public Timer
{
public:
InternalDragRepeater()
{}

~InternalDragRepeater()
{
clearSingletonInstance();
}

juce_DeclareSingleton_SingleThreaded_Minimal (InternalDragRepeater)

void timerCallback()
{
Desktop& desktop = Desktop::getInstance();
int numMiceDown = 0;

for (int i = desktop.getNumMouseSources(); --i >= 0;)
{
MouseInputSource* const source = desktop.getMouseSource(i);
if (source->isDragging())
{
source->triggerFakeMove();
++numMiceDown;
}
}

if (numMiceDown == 0)
deleteInstance();
}

private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InternalDragRepeater);
};

juce_ImplementSingleton_SingleThreaded (InternalDragRepeater)

void Component::beginDragAutoRepeat (const int interval)
{
if (interval > 0)
{
if (InternalDragRepeater::getInstance()->getTimerInterval() != interval)
InternalDragRepeater::getInstance()->startTimer (interval);
}
else
{
InternalDragRepeater::deleteInstance();
}
}

void Component::internalMouseDown (MouseInputSource& source, const Point<int>& relativePos, const Time& time)
{
Desktop& desktop = Desktop::getInstance();
@@ -42254,7 +42199,15 @@ void Component::internalMouseWheel (MouseInputSource& source, const Point<int>&

void Component::sendFakeMouseMove() const
{
Desktop::getInstance().getMainMouseSource().triggerFakeMove();
MouseInputSource& mainMouse = Desktop::getInstance().getMainMouseSource();

if (! mainMouse.isDragging())
mainMouse.triggerFakeMove();
}

void Component::beginDragAutoRepeat (const int interval)
{
Desktop::getInstance().beginDragAutoRepeat (interval);
}

void Component::broughtToFront()
@@ -42682,10 +42635,10 @@ ComponentPeer* Component::getPeer() const
{
if (flags.hasHeavyweightPeerFlag)
return ComponentPeer::getPeerFor (this);
else if (parentComponent_ != 0)
return parentComponent_->getPeer();
else
else if (parentComponent_ == 0)
return 0;

return parentComponent_->getPeer();
}

Component::BailOutChecker::BailOutChecker (Component* const component1, Component* const component2_)
@@ -42756,11 +42709,10 @@ extern void juce_updateMultiMonitorInfo (Array <Rectangle<int> >& monitorCoords,

void Desktop::refreshMonitorSizes()
{
const Array <Rectangle<int> > oldClipped (monitorCoordsClipped);
const Array <Rectangle<int> > oldUnclipped (monitorCoordsUnclipped);
Array <Rectangle<int> > oldClipped, oldUnclipped;
oldClipped.swapWithArray (monitorCoordsClipped);
oldUnclipped.swapWithArray (monitorCoordsUnclipped);

monitorCoordsClipped.clear();
monitorCoordsUnclipped.clear();
juce_updateMultiMonitorInfo (monitorCoordsClipped, true);
juce_updateMultiMonitorInfo (monitorCoordsUnclipped, false);
jassert (monitorCoordsClipped.size() == monitorCoordsUnclipped.size());
@@ -42939,6 +42891,50 @@ MouseInputSource* Desktop::getDraggingMouseSource (int index) const throw()
return 0;
}

class MouseDragAutoRepeater : public Timer
{
public:
MouseDragAutoRepeater() {}

void timerCallback()
{
Desktop& desktop = Desktop::getInstance();
int numMiceDown = 0;

for (int i = desktop.getNumMouseSources(); --i >= 0;)
{
MouseInputSource* const source = desktop.getMouseSource(i);
if (source->isDragging())
{
source->triggerFakeMove();
++numMiceDown;
}
}

if (numMiceDown == 0)
desktop.beginDragAutoRepeat (0);
}

private:
JUCE_DECLARE_NON_COPYABLE (MouseDragAutoRepeater);
};

void Desktop::beginDragAutoRepeat (const int interval)
{
if (interval > 0)
{
if (dragRepeater == 0)
dragRepeater = new MouseDragAutoRepeater();

if (dragRepeater->getTimerInterval() != interval)
dragRepeater->startTimer (interval);
}
else
{
dragRepeater = 0;
}
}

void Desktop::addFocusChangeListener (FocusChangeListener* const listener)
{
focusListeners.add (listener);
@@ -251648,7 +251644,7 @@ AudioIODeviceType* juce_createAudioIODeviceType_DirectSound()
#if JUCE_INCLUDED_FILE && JUCE_WASAPI

#ifndef WASAPI_ENABLE_LOGGING
#define WASAPI_ENABLE_LOGGING 1
#define WASAPI_ENABLE_LOGGING 0
#endif

namespace WasapiClasses
@@ -251969,7 +251965,8 @@ public:
reservoirCapacity = 16384;
reservoir.setSize (actualNumChannels * reservoirCapacity * sizeof (float));
return openClient (newSampleRate, newChannels)
&& (numChannels == 0 || check (client->GetService (__uuidof (IAudioCaptureClient), (void**) captureClient.resetAndGetPointerAddress())));
&& (numChannels == 0 || check (client->GetService (__uuidof (IAudioCaptureClient),
(void**) captureClient.resetAndGetPointerAddress())));
}

void close()
@@ -251979,18 +251976,19 @@ public:
reservoir.setSize (0);
}

void updateFormat (bool isFloat)
template <class SourceType>
void updateFormatWithType (SourceType*)
{
typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> NativeType;
converter = new AudioData::ConverterInstance <AudioData::Pointer <SourceType, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, NativeType> (actualNumChannels, 1);
}

if (isFloat)
converter = new AudioData::ConverterInstance <AudioData::Pointer <AudioData::Float32, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, NativeType> (actualNumChannels, 1);
else if (bytesPerSample == 4)
converter = new AudioData::ConverterInstance <AudioData::Pointer <AudioData::Int32, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, NativeType> (actualNumChannels, 1);
else if (bytesPerSample == 3)
converter = new AudioData::ConverterInstance <AudioData::Pointer <AudioData::Int24, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, NativeType> (actualNumChannels, 1);
else
converter = new AudioData::ConverterInstance <AudioData::Pointer <AudioData::Int16, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, NativeType> (actualNumChannels, 1);
void updateFormat (bool isFloat)
{
if (isFloat) updateFormatWithType ((AudioData::Float32*) 0);
else if (bytesPerSample == 4) updateFormatWithType ((AudioData::Int32*) 0);
else if (bytesPerSample == 3) updateFormatWithType ((AudioData::Int24*) 0);
else updateFormatWithType ((AudioData::Int16*) 0);
}

void copyBuffers (float** destBuffers, int numDestBuffers, int bufferSize, Thread& thread)
@@ -252011,7 +252009,7 @@ public:

bufferSize -= samplesToDo;
offset += samplesToDo;
reservoirSize -= samplesToDo;
reservoirSize = 0;
}
else
{
@@ -252021,14 +252019,14 @@ public:

if (packetLength == 0)
{
if (thread.threadShouldExit())
if (thread.threadShouldExit()
|| WaitForSingleObject (clientEvent, 1000) == WAIT_TIMEOUT)
break;

Thread::sleep (1);
continue;
}

uint8* inputData = 0;
uint8* inputData;
UINT32 numSamplesAvailable;
DWORD flags;

@@ -252089,18 +252087,19 @@ public:
renderClient = 0;
}

void updateFormat (bool isFloat)
template <class DestType>
void updateFormatWithType (DestType*)
{
typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> NativeType;
converter = new AudioData::ConverterInstance <NativeType, AudioData::Pointer <DestType, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, actualNumChannels);
}

if (isFloat)
converter = new AudioData::ConverterInstance <NativeType, AudioData::Pointer <AudioData::Float32, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, actualNumChannels);
else if (bytesPerSample == 4)
converter = new AudioData::ConverterInstance <NativeType, AudioData::Pointer <AudioData::Int32, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, actualNumChannels);
else if (bytesPerSample == 3)
converter = new AudioData::ConverterInstance <NativeType, AudioData::Pointer <AudioData::Int24, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, actualNumChannels);
else
converter = new AudioData::ConverterInstance <NativeType, AudioData::Pointer <AudioData::Int16, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, actualNumChannels);
void updateFormat (bool isFloat)
{
if (isFloat) updateFormatWithType ((AudioData::Float32*) 0);
else if (bytesPerSample == 4) updateFormatWithType ((AudioData::Int32*) 0);
else if (bytesPerSample == 3) updateFormatWithType ((AudioData::Int24*) 0);
else updateFormatWithType ((AudioData::Int16*) 0);
}

void copyBuffers (const float** const srcBuffers, const int numSrcBuffers, int bufferSize, Thread& thread)
@@ -252121,10 +252120,10 @@ public:

if (samplesToDo <= 0)
{
if (thread.threadShouldExit())
if (thread.threadShouldExit()
|| WaitForSingleObject (clientEvent, 1000) == WAIT_TIMEOUT)
break;

Thread::sleep (0);
continue;
}

@@ -252288,11 +252287,8 @@ public:
return lastError;
}

if (inputDevice != 0)
ResetEvent (inputDevice->clientEvent);

if (outputDevice != 0)
ResetEvent (outputDevice->clientEvent);
if (inputDevice != 0) ResetEvent (inputDevice->clientEvent);
if (outputDevice != 0) ResetEvent (outputDevice->clientEvent);

startThread (8);
Thread::sleep (5);
@@ -252318,20 +252314,15 @@ public:
void close()
{
stop();
signalThreadShouldExit();

if (inputDevice != 0)
SetEvent (inputDevice->clientEvent);

if (outputDevice != 0)
SetEvent (outputDevice->clientEvent);
if (inputDevice != 0) SetEvent (inputDevice->clientEvent);
if (outputDevice != 0) SetEvent (outputDevice->clientEvent);

stopThread (5000);

if (inputDevice != 0)
inputDevice->close();

if (outputDevice != 0)
outputDevice->close();
if (inputDevice != 0) inputDevice->close();
if (outputDevice != 0) outputDevice->close();

isOpen_ = false;
}
@@ -252377,13 +252368,13 @@ public:
void setMMThreadPriority()
{
DynamicLibraryLoader dll ("avrt.dll");
DynamicLibraryImport (AvSetMmThreadCharacteristics, avSetMmThreadCharacteristics, HANDLE, dll, (LPCTSTR, LPDWORD))
DynamicLibraryImport (AvSetMmThreadCharacteristicsW, avSetMmThreadCharacteristics, HANDLE, dll, (LPCWSTR, LPDWORD))
DynamicLibraryImport (AvSetMmThreadPriority, avSetMmThreadPriority, HANDLE, dll, (HANDLE, AVRT_PRIORITY))

if (avSetMmThreadCharacteristics != 0 && avSetMmThreadPriority != 0)
{
DWORD dummy = 0;
HANDLE h = avSetMmThreadCharacteristics (_T("Pro Audio"), &dummy);
HANDLE h = avSetMmThreadCharacteristics (L"Pro Audio", &dummy);

if (h != 0)
avSetMmThreadPriority (h, AVRT_PRIORITY_NORMAL);
@@ -252396,13 +252387,6 @@ public:

const int bufferSize = currentBufferSizeSamples;

HANDLE events[2];
int numEvents = 0;
if (inputDevice != 0)
events [numEvents++] = inputDevice->clientEvent;
if (outputDevice != 0)
events [numEvents++] = outputDevice->clientEvent;

const int numInputBuffers = getActiveInputChannels().countNumberOfSetBits();
const int numOutputBuffers = getActiveOutputChannels().countNumberOfSetBits();

@@ -252414,44 +252398,28 @@ public:

while (! threadShouldExit())
{
const DWORD result = useExclusiveMode ? (inputDevice != 0 ? WaitForSingleObject (inputDevice->clientEvent, 1000) : S_OK)
: WaitForMultipleObjects (numEvents, events, true, 1000);
if (result == WAIT_TIMEOUT)
continue;

if (threadShouldExit())
break;

if (inputDevice != 0)
{
inputDevice->copyBuffers (inputBuffers, numInputBuffers, bufferSize, *this);

// Make the callback..
if (threadShouldExit())
break;
}

JUCE_TRY
{
const ScopedLock sl (startStopLock);

if (isStarted)
{
JUCE_TRY
{
callback->audioDeviceIOCallback ((const float**) inputBuffers,
numInputBuffers,
outputBuffers,
numOutputBuffers,
bufferSize);
}
JUCE_CATCH_EXCEPTION
}
callback->audioDeviceIOCallback (const_cast <const float**> (inputBuffers), numInputBuffers,
outputBuffers, numOutputBuffers, bufferSize);
else
{
outs.clear();
}
}

if (useExclusiveMode && WaitForSingleObject (outputDevice->clientEvent, 1000) == WAIT_TIMEOUT)
continue;
JUCE_CATCH_EXCEPTION

if (outputDevice != 0)
outputDevice->copyBuffers ((const float**) outputBuffers, numOutputBuffers, bufferSize, *this);
outputDevice->copyBuffers (const_cast <const float**> (outputBuffers), numOutputBuffers, bufferSize, *this);
}
}



+ 26
- 12
juce_amalgamated.h View File

@@ -64,7 +64,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 52
#define JUCE_BUILDNUMBER 104
#define JUCE_BUILDNUMBER 105

/** Current Juce version number.

@@ -27535,24 +27535,21 @@ public:
float wheelIncrementY);

/** Ensures that a non-stop stream of mouse-drag events will be sent during the
next mouse-drag operation.
current mouse-drag operation.

This allows you to make sure that mouseDrag() events sent continuously, even
This allows you to make sure that mouseDrag() events are sent continuously, even
when the mouse isn't moving. This can be useful for things like auto-scrolling
components when the mouse is near an edge.

Call this method during a mouseDown() or mouseDrag() callback, specifying the
minimum interval between consecutive mouse drag callbacks. The callbacks
will continue until the mouse is released, and then the interval will be reset,
so you need to make sure it's called every time you begin a drag event. If it
is called when the mouse isn't actually being pressed, it will apply to the next
mouse-drag operation that happens.

so you need to make sure it's called every time you begin a drag event.
Passing an interval of 0 or less will cancel the auto-repeat.

@see mouseDrag
@see mouseDrag, Desktop::beginDragAutoRepeat
*/
static void beginDragAutoRepeat (int millisecondIntervalBetweenCallbacks);
static void beginDragAutoRepeat (int millisecondsBetweenCallbacks);

/** Causes automatic repaints when the mouse enters or exits this component.

@@ -29591,6 +29588,23 @@ public:
*/
MouseInputSource* getDraggingMouseSource (int index) const throw();

/** Ensures that a non-stop stream of mouse-drag events will be sent during the
current mouse-drag operation.

This allows you to make sure that mouseDrag() events are sent continuously, even
when the mouse isn't moving. This can be useful for things like auto-scrolling
components when the mouse is near an edge.

Call this method during a mouseDown() or mouseDrag() callback, specifying the
minimum interval between consecutive mouse drag callbacks. The callbacks
will continue until the mouse is released, and then the interval will be reset,
so you need to make sure it's called every time you begin a drag event.
Passing an interval of 0 or less will cancel the auto-repeat.

@see mouseDrag
*/
void beginDragAutoRepeat (int millisecondsBetweenCallbacks);

/** In a tablet device which can be turned around, this is used to inidicate the orientation. */
enum DisplayOrientation
{
@@ -29654,6 +29668,8 @@ private:
int mouseClickCounter;
void incrementMouseClickCounter() throw();

ScopedPointer<Timer> dragRepeater;

Component* kioskModeComponent;
Rectangle<int> kioskComponentOriginalBounds;

@@ -32425,8 +32441,6 @@ public:
/** Destructor. */
~AudioFormatManager();

juce_DeclareSingleton (AudioFormatManager, false);

/** Adds a format to the manager's list of available file types.

The object passed-in will be deleted by this object, so don't keep a pointer
@@ -56680,7 +56694,7 @@ public:
/** Returns the component that was last known to be under this pointer. */
Component* getComponentUnderMouse() const;

/** Tells the device to dispatch a mouse-move event.
/** Tells the device to dispatch a mouse-move or mouse-drag event.
This is asynchronous - the event will occur on the message thread.
*/
void triggerFakeMove() const;


+ 10
- 16
src/audio/audio_file_formats/juce_AudioFormatManager.cpp View File

@@ -44,22 +44,16 @@ AudioFormatManager::AudioFormatManager()
AudioFormatManager::~AudioFormatManager()
{
clearFormats();
clearSingletonInstance();
}
juce_ImplementSingleton (AudioFormatManager);
//==============================================================================
void AudioFormatManager::registerFormat (AudioFormat* newFormat,
const bool makeThisTheDefaultFormat)
void AudioFormatManager::registerFormat (AudioFormat* newFormat, const bool makeThisTheDefaultFormat)
{
jassert (newFormat != 0);
if (newFormat != 0)
{
#if JUCE_DEBUG
#if JUCE_DEBUG
for (int i = getNumKnownFormats(); --i >= 0;)
{
if (getKnownFormat (i)->getFormatName() == newFormat->getFormatName())
@@ -67,7 +61,7 @@ void AudioFormatManager::registerFormat (AudioFormat* newFormat,
jassertfalse; // trying to add the same format twice!
}
}
#endif
#endif
if (makeThisTheDefaultFormat)
defaultFormatIndex = getNumKnownFormats();
@@ -78,21 +72,21 @@ void AudioFormatManager::registerFormat (AudioFormat* newFormat,
void AudioFormatManager::registerBasicFormats()
{
#if JUCE_MAC
#if JUCE_MAC
registerFormat (new AiffAudioFormat(), true);
registerFormat (new WavAudioFormat(), false);
#else
#else
registerFormat (new WavAudioFormat(), true);
registerFormat (new AiffAudioFormat(), false);
#endif
#endif
#if JUCE_USE_FLAC
#if JUCE_USE_FLAC
registerFormat (new FlacAudioFormat(), false);
#endif
#endif
#if JUCE_USE_OGGVORBIS
#if JUCE_USE_OGGVORBIS
registerFormat (new OggVorbisAudioFormat(), false);
#endif
#endif
}
void AudioFormatManager::clearFormats()


+ 0
- 2
src/audio/audio_file_formats/juce_AudioFormatManager.h View File

@@ -56,8 +56,6 @@ public:
/** Destructor. */
~AudioFormatManager();
juce_DeclareSingleton (AudioFormatManager, false);
//==============================================================================
/** Adds a format to the manager's list of available file types.


+ 3
- 2
src/audio/audio_file_formats/juce_AudioThumbnail.cpp View File

@@ -370,9 +370,10 @@ public:
for (int w = clip.getWidth(); --w >= 0;)
{
if (cacheData->isNonZero())
g.drawVerticalLine (x++, jmax (midY - cacheData->maxValue * vscale - 0.3f, topY),
jmin (midY - cacheData->minValue * vscale + 0.3f, bottomY));
g.drawVerticalLine (x, jmax (midY - cacheData->maxValue * vscale - 0.3f, topY),
jmin (midY - cacheData->minValue * vscale + 0.3f, bottomY));
++x;
++cacheData;
}
}


+ 1
- 1
src/core/juce_StandardHeader.h View File

@@ -33,7 +33,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 52
#define JUCE_BUILDNUMBER 104
#define JUCE_BUILDNUMBER 105
/** Current Juce version number.


+ 12
- 57
src/gui/components/juce_Component.cpp View File

@@ -2296,59 +2296,6 @@ void Component::internalMouseExit (MouseInputSource& source, const Point<int>& r
}
}
//==============================================================================
class InternalDragRepeater : public Timer
{
public:
InternalDragRepeater()
{}
~InternalDragRepeater()
{
clearSingletonInstance();
}
juce_DeclareSingleton_SingleThreaded_Minimal (InternalDragRepeater)
void timerCallback()
{
Desktop& desktop = Desktop::getInstance();
int numMiceDown = 0;
for (int i = desktop.getNumMouseSources(); --i >= 0;)
{
MouseInputSource* const source = desktop.getMouseSource(i);
if (source->isDragging())
{
source->triggerFakeMove();
++numMiceDown;
}
}
if (numMiceDown == 0)
deleteInstance();
}
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InternalDragRepeater);
};
juce_ImplementSingleton_SingleThreaded (InternalDragRepeater)
void Component::beginDragAutoRepeat (const int interval)
{
if (interval > 0)
{
if (InternalDragRepeater::getInstance()->getTimerInterval() != interval)
InternalDragRepeater::getInstance()->startTimer (interval);
}
else
{
InternalDragRepeater::deleteInstance();
}
}
//==============================================================================
void Component::internalMouseDown (MouseInputSource& source, const Point<int>& relativePos, const Time& time)
{
@@ -2559,7 +2506,15 @@ void Component::internalMouseWheel (MouseInputSource& source, const Point<int>&
void Component::sendFakeMouseMove() const
{
Desktop::getInstance().getMainMouseSource().triggerFakeMove();
MouseInputSource& mainMouse = Desktop::getInstance().getMainMouseSource();
if (! mainMouse.isDragging())
mainMouse.triggerFakeMove();
}
void Component::beginDragAutoRepeat (const int interval)
{
Desktop::getInstance().beginDragAutoRepeat (interval);
}
void Component::broughtToFront()
@@ -2993,10 +2948,10 @@ ComponentPeer* Component::getPeer() const
{
if (flags.hasHeavyweightPeerFlag)
return ComponentPeer::getPeerFor (this);
else if (parentComponent_ != 0)
return parentComponent_->getPeer();
else
else if (parentComponent_ == 0)
return 0;
return parentComponent_->getPeer();
}
//==============================================================================


+ 5
- 8
src/gui/components/juce_Component.h View File

@@ -1514,24 +1514,21 @@ public:
//==============================================================================
/** Ensures that a non-stop stream of mouse-drag events will be sent during the
next mouse-drag operation.
current mouse-drag operation.
This allows you to make sure that mouseDrag() events sent continuously, even
This allows you to make sure that mouseDrag() events are sent continuously, even
when the mouse isn't moving. This can be useful for things like auto-scrolling
components when the mouse is near an edge.
Call this method during a mouseDown() or mouseDrag() callback, specifying the
minimum interval between consecutive mouse drag callbacks. The callbacks
will continue until the mouse is released, and then the interval will be reset,
so you need to make sure it's called every time you begin a drag event. If it
is called when the mouse isn't actually being pressed, it will apply to the next
mouse-drag operation that happens.
so you need to make sure it's called every time you begin a drag event.
Passing an interval of 0 or less will cancel the auto-repeat.
@see mouseDrag
@see mouseDrag, Desktop::beginDragAutoRepeat
*/
static void beginDragAutoRepeat (int millisecondIntervalBetweenCallbacks);
static void beginDragAutoRepeat (int millisecondsBetweenCallbacks);
/** Causes automatic repaints when the mouse enters or exits this component.


+ 48
- 4
src/gui/components/juce_Desktop.cpp View File

@@ -70,11 +70,10 @@ extern void juce_updateMultiMonitorInfo (Array <Rectangle<int> >& monitorCoords,
void Desktop::refreshMonitorSizes()
{
const Array <Rectangle<int> > oldClipped (monitorCoordsClipped);
const Array <Rectangle<int> > oldUnclipped (monitorCoordsUnclipped);
Array <Rectangle<int> > oldClipped, oldUnclipped;
oldClipped.swapWithArray (monitorCoordsClipped);
oldUnclipped.swapWithArray (monitorCoordsUnclipped);
monitorCoordsClipped.clear();
monitorCoordsUnclipped.clear();
juce_updateMultiMonitorInfo (monitorCoordsClipped, true);
juce_updateMultiMonitorInfo (monitorCoordsUnclipped, false);
jassert (monitorCoordsClipped.size() == monitorCoordsUnclipped.size());
@@ -256,6 +255,51 @@ MouseInputSource* Desktop::getDraggingMouseSource (int index) const throw()
return 0;
}
//==============================================================================
class MouseDragAutoRepeater : public Timer
{
public:
MouseDragAutoRepeater() {}
void timerCallback()
{
Desktop& desktop = Desktop::getInstance();
int numMiceDown = 0;
for (int i = desktop.getNumMouseSources(); --i >= 0;)
{
MouseInputSource* const source = desktop.getMouseSource(i);
if (source->isDragging())
{
source->triggerFakeMove();
++numMiceDown;
}
}
if (numMiceDown == 0)
desktop.beginDragAutoRepeat (0);
}
private:
JUCE_DECLARE_NON_COPYABLE (MouseDragAutoRepeater);
};
void Desktop::beginDragAutoRepeat (const int interval)
{
if (interval > 0)
{
if (dragRepeater == 0)
dragRepeater = new MouseDragAutoRepeater();
if (dragRepeater->getTimerInterval() != interval)
dragRepeater->startTimer (interval);
}
else
{
dragRepeater = 0;
}
}
//==============================================================================
void Desktop::addFocusChangeListener (FocusChangeListener* const listener)
{


+ 18
- 0
src/gui/components/juce_Desktop.h View File

@@ -281,6 +281,22 @@ public:
*/
MouseInputSource* getDraggingMouseSource (int index) const throw();
/** Ensures that a non-stop stream of mouse-drag events will be sent during the
current mouse-drag operation.
This allows you to make sure that mouseDrag() events are sent continuously, even
when the mouse isn't moving. This can be useful for things like auto-scrolling
components when the mouse is near an edge.
Call this method during a mouseDown() or mouseDrag() callback, specifying the
minimum interval between consecutive mouse drag callbacks. The callbacks
will continue until the mouse is released, and then the interval will be reset,
so you need to make sure it's called every time you begin a drag event.
Passing an interval of 0 or less will cancel the auto-repeat.
@see mouseDrag
*/
void beginDragAutoRepeat (int millisecondsBetweenCallbacks);
//==============================================================================
/** In a tablet device which can be turned around, this is used to inidicate the orientation. */
@@ -347,6 +363,8 @@ private:
int mouseClickCounter;
void incrementMouseClickCounter() throw();
ScopedPointer<Timer> dragRepeater;
Component* kioskModeComponent;
Rectangle<int> kioskComponentOriginalBounds;


+ 1
- 1
src/gui/components/mouse/juce_MouseInputSource.h View File

@@ -109,7 +109,7 @@ public:
/** Returns the component that was last known to be under this pointer. */
Component* getComponentUnderMouse() const;
/** Tells the device to dispatch a mouse-move event.
/** Tells the device to dispatch a mouse-move or mouse-drag event.
This is asynchronous - the event will occur on the message thread.
*/
void triggerFakeMove() const;


+ 48
- 76
src/native/windows/juce_win32_WASAPI.cpp View File

@@ -28,7 +28,7 @@
#if JUCE_INCLUDED_FILE && JUCE_WASAPI
#ifndef WASAPI_ENABLE_LOGGING
#define WASAPI_ENABLE_LOGGING 1
#define WASAPI_ENABLE_LOGGING 0
#endif
//==============================================================================
@@ -353,7 +353,8 @@ public:
reservoirCapacity = 16384;
reservoir.setSize (actualNumChannels * reservoirCapacity * sizeof (float));
return openClient (newSampleRate, newChannels)
&& (numChannels == 0 || check (client->GetService (__uuidof (IAudioCaptureClient), (void**) captureClient.resetAndGetPointerAddress())));
&& (numChannels == 0 || check (client->GetService (__uuidof (IAudioCaptureClient),
(void**) captureClient.resetAndGetPointerAddress())));
}
void close()
@@ -363,18 +364,19 @@ public:
reservoir.setSize (0);
}
void updateFormat (bool isFloat)
template <class SourceType>
void updateFormatWithType (SourceType*)
{
typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> NativeType;
converter = new AudioData::ConverterInstance <AudioData::Pointer <SourceType, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, NativeType> (actualNumChannels, 1);
}
if (isFloat)
converter = new AudioData::ConverterInstance <AudioData::Pointer <AudioData::Float32, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, NativeType> (actualNumChannels, 1);
else if (bytesPerSample == 4)
converter = new AudioData::ConverterInstance <AudioData::Pointer <AudioData::Int32, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, NativeType> (actualNumChannels, 1);
else if (bytesPerSample == 3)
converter = new AudioData::ConverterInstance <AudioData::Pointer <AudioData::Int24, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, NativeType> (actualNumChannels, 1);
else
converter = new AudioData::ConverterInstance <AudioData::Pointer <AudioData::Int16, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, NativeType> (actualNumChannels, 1);
void updateFormat (bool isFloat)
{
if (isFloat) updateFormatWithType ((AudioData::Float32*) 0);
else if (bytesPerSample == 4) updateFormatWithType ((AudioData::Int32*) 0);
else if (bytesPerSample == 3) updateFormatWithType ((AudioData::Int24*) 0);
else updateFormatWithType ((AudioData::Int16*) 0);
}
void copyBuffers (float** destBuffers, int numDestBuffers, int bufferSize, Thread& thread)
@@ -395,7 +397,7 @@ public:
bufferSize -= samplesToDo;
offset += samplesToDo;
reservoirSize -= samplesToDo;
reservoirSize = 0;
}
else
{
@@ -405,14 +407,14 @@ public:
if (packetLength == 0)
{
if (thread.threadShouldExit())
if (thread.threadShouldExit()
|| WaitForSingleObject (clientEvent, 1000) == WAIT_TIMEOUT)
break;
Thread::sleep (1);
continue;
}
uint8* inputData = 0;
uint8* inputData;
UINT32 numSamplesAvailable;
DWORD flags;
@@ -474,18 +476,19 @@ public:
renderClient = 0;
}
void updateFormat (bool isFloat)
template <class DestType>
void updateFormatWithType (DestType*)
{
typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> NativeType;
converter = new AudioData::ConverterInstance <NativeType, AudioData::Pointer <DestType, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, actualNumChannels);
}
if (isFloat)
converter = new AudioData::ConverterInstance <NativeType, AudioData::Pointer <AudioData::Float32, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, actualNumChannels);
else if (bytesPerSample == 4)
converter = new AudioData::ConverterInstance <NativeType, AudioData::Pointer <AudioData::Int32, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, actualNumChannels);
else if (bytesPerSample == 3)
converter = new AudioData::ConverterInstance <NativeType, AudioData::Pointer <AudioData::Int24, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, actualNumChannels);
else
converter = new AudioData::ConverterInstance <NativeType, AudioData::Pointer <AudioData::Int16, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, actualNumChannels);
void updateFormat (bool isFloat)
{
if (isFloat) updateFormatWithType ((AudioData::Float32*) 0);
else if (bytesPerSample == 4) updateFormatWithType ((AudioData::Int32*) 0);
else if (bytesPerSample == 3) updateFormatWithType ((AudioData::Int24*) 0);
else updateFormatWithType ((AudioData::Int16*) 0);
}
void copyBuffers (const float** const srcBuffers, const int numSrcBuffers, int bufferSize, Thread& thread)
@@ -506,10 +509,10 @@ public:
if (samplesToDo <= 0)
{
if (thread.threadShouldExit())
if (thread.threadShouldExit()
|| WaitForSingleObject (clientEvent, 1000) == WAIT_TIMEOUT)
break;
Thread::sleep (0);
continue;
}
@@ -675,11 +678,8 @@ public:
return lastError;
}
if (inputDevice != 0)
ResetEvent (inputDevice->clientEvent);
if (outputDevice != 0)
ResetEvent (outputDevice->clientEvent);
if (inputDevice != 0) ResetEvent (inputDevice->clientEvent);
if (outputDevice != 0) ResetEvent (outputDevice->clientEvent);
startThread (8);
Thread::sleep (5);
@@ -705,20 +705,15 @@ public:
void close()
{
stop();
signalThreadShouldExit();
if (inputDevice != 0)
SetEvent (inputDevice->clientEvent);
if (outputDevice != 0)
SetEvent (outputDevice->clientEvent);
if (inputDevice != 0) SetEvent (inputDevice->clientEvent);
if (outputDevice != 0) SetEvent (outputDevice->clientEvent);
stopThread (5000);
if (inputDevice != 0)
inputDevice->close();
if (outputDevice != 0)
outputDevice->close();
if (inputDevice != 0) inputDevice->close();
if (outputDevice != 0) outputDevice->close();
isOpen_ = false;
}
@@ -764,13 +759,13 @@ public:
void setMMThreadPriority()
{
DynamicLibraryLoader dll ("avrt.dll");
DynamicLibraryImport (AvSetMmThreadCharacteristics, avSetMmThreadCharacteristics, HANDLE, dll, (LPCTSTR, LPDWORD))
DynamicLibraryImport (AvSetMmThreadCharacteristicsW, avSetMmThreadCharacteristics, HANDLE, dll, (LPCWSTR, LPDWORD))
DynamicLibraryImport (AvSetMmThreadPriority, avSetMmThreadPriority, HANDLE, dll, (HANDLE, AVRT_PRIORITY))
if (avSetMmThreadCharacteristics != 0 && avSetMmThreadPriority != 0)
{
DWORD dummy = 0;
HANDLE h = avSetMmThreadCharacteristics (_T("Pro Audio"), &dummy);
HANDLE h = avSetMmThreadCharacteristics (L"Pro Audio", &dummy);
if (h != 0)
avSetMmThreadPriority (h, AVRT_PRIORITY_NORMAL);
@@ -783,13 +778,6 @@ public:
const int bufferSize = currentBufferSizeSamples;
HANDLE events[2];
int numEvents = 0;
if (inputDevice != 0)
events [numEvents++] = inputDevice->clientEvent;
if (outputDevice != 0)
events [numEvents++] = outputDevice->clientEvent;
const int numInputBuffers = getActiveInputChannels().countNumberOfSetBits();
const int numOutputBuffers = getActiveOutputChannels().countNumberOfSetBits();
@@ -801,44 +789,28 @@ public:
while (! threadShouldExit())
{
const DWORD result = useExclusiveMode ? (inputDevice != 0 ? WaitForSingleObject (inputDevice->clientEvent, 1000) : S_OK)
: WaitForMultipleObjects (numEvents, events, true, 1000);
if (result == WAIT_TIMEOUT)
continue;
if (threadShouldExit())
break;
if (inputDevice != 0)
{
inputDevice->copyBuffers (inputBuffers, numInputBuffers, bufferSize, *this);
// Make the callback..
if (threadShouldExit())
break;
}
JUCE_TRY
{
const ScopedLock sl (startStopLock);
if (isStarted)
{
JUCE_TRY
{
callback->audioDeviceIOCallback ((const float**) inputBuffers,
numInputBuffers,
outputBuffers,
numOutputBuffers,
bufferSize);
}
JUCE_CATCH_EXCEPTION
}
callback->audioDeviceIOCallback (const_cast <const float**> (inputBuffers), numInputBuffers,
outputBuffers, numOutputBuffers, bufferSize);
else
{
outs.clear();
}
}
if (useExclusiveMode && WaitForSingleObject (outputDevice->clientEvent, 1000) == WAIT_TIMEOUT)
continue;
JUCE_CATCH_EXCEPTION
if (outputDevice != 0)
outputDevice->copyBuffers ((const float**) outputBuffers, numOutputBuffers, bufferSize, *this);
outputDevice->copyBuffers (const_cast <const float**> (outputBuffers), numOutputBuffers, bufferSize, *this);
}
}


Loading…
Cancel
Save