1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-02-04 03:40:07 +00:00

Refactored midi input code to allow unlimited syex length + partial sysex callbacks on win32. Fixed a few problems with menu bars, Quicktime, AudioUnits. Modernised some old win32 file chooser code. Tweaked some window border rendering.

This commit is contained in:
Julian Storer 2010-10-08 14:52:23 +01:00
parent 9168728a7e
commit d508109296
27 changed files with 1339 additions and 1376 deletions

View file

@ -911,6 +911,7 @@
1C4E5F07F277AE37C71EA547 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_linux_NativeCode.cpp; path = ../../src/native/juce_linux_NativeCode.cpp; sourceTree = SOURCE_ROOT; };
3BC24CC03A2F940A615FE935 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = juce_mac_NativeCode.mm; path = ../../src/native/juce_mac_NativeCode.mm; sourceTree = SOURCE_ROOT; };
9DFCF3F7BB734C8AABD83D8D = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_NativeCode.cpp; path = ../../src/native/juce_win32_NativeCode.cpp; sourceTree = SOURCE_ROOT; };
213F0A7BF38AF6AB34414A45 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_MidiDataConcatenator.h; path = ../../src/native/common/juce_MidiDataConcatenator.h; sourceTree = SOURCE_ROOT; };
21B2342B75097AB93CFF7E97 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_posix_NamedPipe.cpp; path = ../../src/native/common/juce_posix_NamedPipe.cpp; sourceTree = SOURCE_ROOT; };
2C48BB1A286C6A63174E5798 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_posix_SharedCode.h; path = ../../src/native/common/juce_posix_SharedCode.h; sourceTree = SOURCE_ROOT; };
7A51D8B81F390A4CABF25C73 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_linux_Audio.cpp; path = ../../src/native/linux/juce_linux_Audio.cpp; sourceTree = SOURCE_ROOT; };
@ -1686,6 +1687,7 @@
13FBF71BD76A08C8971C6351,
177636E4EEEBBB139F934897 ); name = io; sourceTree = "<group>"; };
DDB94A7300C3D1F2E9E51C47 = { isa = PBXGroup; children = (
213F0A7BF38AF6AB34414A45,
21B2342B75097AB93CFF7E97,
2C48BB1A286C6A63174E5798 ); name = common; sourceTree = "<group>"; };
1004A23965A4DB0FCC441ED3 = { isa = PBXGroup; children = (

View file

@ -837,6 +837,7 @@
<File RelativePath="..\..\src\native\juce_mac_NativeCode.mm"/>
<File RelativePath="..\..\src\native\juce_win32_NativeCode.cpp"/>
<Filter Name="common">
<File RelativePath="..\..\src\native\common\juce_MidiDataConcatenator.h"/>
<File RelativePath="..\..\src\native\common\juce_posix_NamedPipe.cpp"/>
<File RelativePath="..\..\src\native\common\juce_posix_SharedCode.h"/>
</Filter>

View file

@ -837,6 +837,7 @@
<File RelativePath="..\..\src\native\juce_mac_NativeCode.mm"/>
<File RelativePath="..\..\src\native\juce_win32_NativeCode.cpp"/>
<Filter Name="common">
<File RelativePath="..\..\src\native\common\juce_MidiDataConcatenator.h"/>
<File RelativePath="..\..\src\native\common\juce_posix_NamedPipe.cpp"/>
<File RelativePath="..\..\src\native\common\juce_posix_SharedCode.h"/>
</Filter>

View file

@ -839,6 +839,7 @@
<File RelativePath="..\..\src\native\juce_mac_NativeCode.mm"/>
<File RelativePath="..\..\src\native\juce_win32_NativeCode.cpp"/>
<Filter Name="common">
<File RelativePath="..\..\src\native\common\juce_MidiDataConcatenator.h"/>
<File RelativePath="..\..\src\native\common\juce_posix_NamedPipe.cpp"/>
<File RelativePath="..\..\src\native\common\juce_posix_SharedCode.h"/>
</Filter>

View file

@ -737,6 +737,7 @@
<ClInclude Include="..\..\src\io\streams\juce_MemoryOutputStream.h"/>
<ClInclude Include="..\..\src\io\streams\juce_OutputStream.h"/>
<ClInclude Include="..\..\src\io\streams\juce_SubregionStream.h"/>
<ClInclude Include="..\..\src\native\common\juce_MidiDataConcatenator.h"/>
<ClInclude Include="..\..\src\native\common\juce_posix_SharedCode.h"/>
<ClInclude Include="..\..\src\native\linux\juce_linux_NativeIncludes.h"/>
<ClInclude Include="..\..\src\native\mac\juce_mac_CarbonViewWrapperComponent.h"/>

View file

@ -2133,6 +2133,9 @@
<ClInclude Include="..\..\src\io\streams\juce_SubregionStream.h">
<Filter>Juce\Source\io\streams</Filter>
</ClInclude>
<ClInclude Include="..\..\src\native\common\juce_MidiDataConcatenator.h">
<Filter>Juce\Source\native\common</Filter>
</ClInclude>
<ClInclude Include="..\..\src\native\common\juce_posix_SharedCode.h">
<Filter>Juce\Source\native\common</Filter>
</ClInclude>

View file

@ -911,6 +911,7 @@
1C4E5F07F277AE37C71EA547 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_linux_NativeCode.cpp; path = ../../src/native/juce_linux_NativeCode.cpp; sourceTree = SOURCE_ROOT; };
3BC24CC03A2F940A615FE935 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = juce_mac_NativeCode.mm; path = ../../src/native/juce_mac_NativeCode.mm; sourceTree = SOURCE_ROOT; };
9DFCF3F7BB734C8AABD83D8D = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_NativeCode.cpp; path = ../../src/native/juce_win32_NativeCode.cpp; sourceTree = SOURCE_ROOT; };
213F0A7BF38AF6AB34414A45 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_MidiDataConcatenator.h; path = ../../src/native/common/juce_MidiDataConcatenator.h; sourceTree = SOURCE_ROOT; };
21B2342B75097AB93CFF7E97 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_posix_NamedPipe.cpp; path = ../../src/native/common/juce_posix_NamedPipe.cpp; sourceTree = SOURCE_ROOT; };
2C48BB1A286C6A63174E5798 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_posix_SharedCode.h; path = ../../src/native/common/juce_posix_SharedCode.h; sourceTree = SOURCE_ROOT; };
7A51D8B81F390A4CABF25C73 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_linux_Audio.cpp; path = ../../src/native/linux/juce_linux_Audio.cpp; sourceTree = SOURCE_ROOT; };
@ -1686,6 +1687,7 @@
13FBF71BD76A08C8971C6351,
177636E4EEEBBB139F934897 ); name = io; sourceTree = "<group>"; };
DDB94A7300C3D1F2E9E51C47 = { isa = PBXGroup; children = (
213F0A7BF38AF6AB34414A45,
21B2342B75097AB93CFF7E97,
2C48BB1A286C6A63174E5798 ); name = common; sourceTree = "<group>"; };
1004A23965A4DB0FCC441ED3 = { isa = PBXGroup; children = (

View file

@ -1253,6 +1253,8 @@
<FILE id="z5G75xgix" name="juce_win32_NativeCode.cpp" compile="1" resource="0"
file="src/native/juce_win32_NativeCode.cpp"/>
<GROUP id="yPi7BU95s" name="common">
<FILE id="2wc3bGX" name="juce_MidiDataConcatenator.h" compile="0" resource="0"
file="src/native/common/juce_MidiDataConcatenator.h"/>
<FILE id="n92kYqkP1" name="juce_posix_NamedPipe.cpp" compile="1" resource="0"
file="src/native/common/juce_posix_NamedPipe.cpp"/>
<FILE id="H4ShC0AEe" name="juce_posix_SharedCode.h" compile="0" resource="0"

View file

@ -99,7 +99,7 @@ public:
<< ", " << pixFormat->accumulationBufferBlueBits
<< ", " << pixFormat->accumulationBufferAlphaBits
<< "), full-scene AA="
<< pixFormat->fullSceneAntiAliasingNumSamples;
<< (int) pixFormat->fullSceneAntiAliasingNumSamples;
Logger::outputDebugString (formatDescription);
}

View file

@ -1347,13 +1347,15 @@ public:
"*",
useNativeVersion);
if (fc.browseForFileToOpen())
if (fc.browseForMultipleFilesToOpen())
{
File chosenFile = fc.getResult();
String chosen;
for (int i = 0; i < fc.getResults().size(); ++i)
chosen << fc.getResults().getReference(i).getFullPathName() << "\n";
AlertWindow::showMessageBox (AlertWindow::InfoIcon,
"File Chooser...",
"You picked: " + chosenFile.getFullPathName());
"You picked: " + chosen);
}
}
else if (result == 124)
@ -1366,13 +1368,15 @@ public:
"*.jpg;*.jpeg;*.png;*.gif",
useNativeVersion);
if (fc.browseForFileToOpen (&imagePreview))
if (fc.browseForMultipleFilesToOpen (&imagePreview))
{
File chosenFile = fc.getResult();
String chosen;
for (int i = 0; i < fc.getResults().size(); ++i)
chosen << fc.getResults().getReference(i).getFullPathName() << "\n";
AlertWindow::showMessageBox (AlertWindow::InfoIcon,
"File Chooser...",
"You picked: " + chosenFile.getFullPathName());
"You picked: " + chosen);
}
}
else if (result == 122)

File diff suppressed because it is too large Load diff

View file

@ -64,7 +64,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 52
#define JUCE_BUILDNUMBER 73
#define JUCE_BUILDNUMBER 74
/** Current Juce version number.
@ -25726,6 +25726,9 @@ public:
/** Returns the sum of the left and right gaps. */
int getLeftAndRight() const throw() { return left + right; }
/** Returns true if this border has no thickness along any edge. */
bool isEmpty() const throw() { return left + right + top + bottom == 0; }
/** Changes the top gap. */
void setTop (int newTopGap) throw();
@ -38574,6 +38577,18 @@ public:
*/
double getCurrentInputLevel() const;
/** Returns the a lock that can be used to synchronise access to the audio callback.
Obviously while this is locked, you're blocking the audio thread from running, so
it must only be used for very brief periods when absolutely necessary.
*/
CriticalSection& getAudioCallbackLock() throw() { return audioCallbackLock; }
/** Returns the a lock that can be used to synchronise access to the midi callback.
Obviously while this is locked, you're blocking the midi system from running, so
it must only be used for very brief periods when absolutely necessary.
*/
CriticalSection& getMidiCallbackLock() throw() { return midiCallbackLock; }
juce_UseDebuggingNewOperator
private:

View file

@ -256,7 +256,7 @@ public:
}
}
int framesToDo = bufferList->mBuffers[0].mDataByteSize / inputStreamDesc.mBytesPerFrame;
int framesToDo = jmin (numSamples, bufferList->mBuffers[0].mDataByteSize / inputStreamDesc.mBytesPerFrame);
bufferList->mBuffers[0].mDataByteSize = inputStreamDesc.mBytesPerFrame * framesToDo;
UInt32 outFlags = 0;
@ -268,8 +268,8 @@ public:
break;
}
lastSampleRead = startSampleInFile + actualNumFrames * samplesPerFrame;
const int samplesReceived = actualNumFrames * samplesPerFrame;
lastSampleRead = startSampleInFile + actualNumFrames;
const int samplesReceived = actualNumFrames;
for (int j = numDestChannels; --j >= 0;)
{

View file

@ -429,6 +429,18 @@ public:
*/
double getCurrentInputLevel() const;
/** Returns the a lock that can be used to synchronise access to the audio callback.
Obviously while this is locked, you're blocking the audio thread from running, so
it must only be used for very brief periods when absolutely necessary.
*/
CriticalSection& getAudioCallbackLock() throw() { return audioCallbackLock; }
/** Returns the a lock that can be used to synchronise access to the midi callback.
Obviously while this is locked, you're blocking the midi system from running, so
it must only be used for very brief periods when absolutely necessary.
*/
CriticalSection& getMidiCallbackLock() throw() { return midiCallbackLock; }
//==============================================================================
juce_UseDebuggingNewOperator

View file

@ -199,6 +199,8 @@ public:
//==============================================================================
~AudioUnitPluginInstance();
void initialise();
//==============================================================================
// AudioPluginInstance methods:
@ -273,7 +275,7 @@ private:
String pluginName, manufacturer, version;
String fileOrIdentifier;
CriticalSection lock;
bool initialised, wantsMidiMessages, wasPlaying;
bool wantsMidiMessages, wasPlaying, prepared;
HeapBlock <AudioBufferList> outputBufferList;
AudioTimeStamp timeStamp;
@ -284,7 +286,8 @@ private:
//==============================================================================
bool getComponentDescFromFile (const String& fileOrIdentifier);
void initialise();
void setPluginCallbacks();
void getParameterListFromPlugin();
//==============================================================================
OSStatus renderGetInput (AudioUnitRenderActionFlags* ioActionFlags,
@ -348,16 +351,49 @@ private:
0, supportedChannels, &supportedChannelsSize) == noErr
&& supportedChannelsSize > 0)
{
int explicitNumIns = 0;
int explicitNumOuts = 0;
int maximumNumIns = 0;
int maximumNumOuts = 0;
for (int i = 0; i < supportedChannelsSize / sizeof (AUChannelInfo); ++i)
{
numIns = jmax (numIns, (int) supportedChannels[i].inChannels);
numOuts = jmax (numOuts, (int) supportedChannels[i].outChannels);
const int inChannels = (int) supportedChannels[i].inChannels;
const int outChannels = (int) supportedChannels[i].outChannels;
if (inChannels < 0)
maximumNumIns = jmin (maximumNumIns, inChannels);
else
explicitNumIns = jmax (explicitNumIns, inChannels);
if (outChannels < 0)
maximumNumOuts = jmin (maximumNumOuts, outChannels);
else
explicitNumOuts = jmax (explicitNumOuts, outChannels);
}
if ((maximumNumIns == -1 && maximumNumOuts == -1) // (special meaning: any number of ins/outs, as long as they match)
|| (maximumNumIns == -2 && maximumNumOuts == -1) // (special meaning: any number of ins/outs, even if they don't match)
|| (maximumNumIns == -1 && maximumNumOuts == -2))
{
numIns = numOuts = 2;
}
else
{
numIns = explicitNumIns;
numOuts = explicitNumOuts;
if (maximumNumIns == -1 || (maximumNumIns < 0 && explicitNumIns <= -maximumNumIns))
numIns = 2;
if (maximumNumOuts == -1 || (maximumNumOuts < 0 && explicitNumOuts <= -maximumNumOuts))
numOuts = 2;
}
}
else
{
// (this really means the plugin will take any number of ins/outs as long
// as they are the same)
// (this really means the plugin will take any number of ins/outs as long
// as they are the same)
numIns = numOuts = 2;
}
}
@ -371,8 +407,7 @@ private:
//==============================================================================
AudioUnitPluginInstance::AudioUnitPluginInstance (const String& fileOrIdentifier)
: fileOrIdentifier (fileOrIdentifier),
initialised (false),
wantsMidiMessages (false),
wantsMidiMessages (false), wasPlaying (false), prepared (false),
audioUnit (0),
currentBuffer (0)
{
@ -498,13 +533,20 @@ bool AudioUnitPluginInstance::getComponentDescFromFile (const String& fileOrIden
//==============================================================================
void AudioUnitPluginInstance::initialise()
{
if (initialised || audioUnit == 0)
return;
getParameterListFromPlugin();
setPluginCallbacks();
log ("Initialising AU: " + pluginName);
int numIns, numOuts;
getNumChannels (numIns, numOuts);
setPlayConfigDetails (numIns, numOuts, 0, 0);
setLatencySamples (0);
}
void AudioUnitPluginInstance::getParameterListFromPlugin()
{
parameterIds.clear();
if (audioUnit != 0)
{
UInt32 paramListSize = 0;
AudioUnitGetProperty (audioUnit, kAudioUnitProperty_ParameterList, kAudioUnitScope_Global,
@ -518,36 +560,34 @@ void AudioUnitPluginInstance::initialise()
0, &parameterIds.getReference(0), &paramListSize);
}
}
}
void AudioUnitPluginInstance::setPluginCallbacks()
{
if (audioUnit != 0)
{
AURenderCallbackStruct info;
zerostruct (info);
info.inputProcRefCon = this;
info.inputProc = renderGetInputCallback;
{
AURenderCallbackStruct info;
zerostruct (info);
info.inputProcRefCon = this;
info.inputProc = renderGetInputCallback;
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input,
0, &info, sizeof (info));
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input,
0, &info, sizeof (info));
}
{
HostCallbackInfo info;
zerostruct (info);
info.hostUserData = this;
info.beatAndTempoProc = getBeatAndTempoCallback;
info.musicalTimeLocationProc = getMusicalTimeLocationCallback;
info.transportStateProc = getTransportStateCallback;
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_HostCallbacks, kAudioUnitScope_Global,
0, &info, sizeof (info));
}
}
{
HostCallbackInfo info;
zerostruct (info);
info.hostUserData = this;
info.beatAndTempoProc = getBeatAndTempoCallback;
info.musicalTimeLocationProc = getMusicalTimeLocationCallback;
info.transportStateProc = getTransportStateCallback;
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_HostCallbacks, kAudioUnitScope_Global,
0, &info, sizeof (info));
}
int numIns, numOuts;
getNumChannels (numIns, numOuts);
setPlayConfigDetails (numIns, numOuts, 0, 0);
initialised = AudioUnitInitialize (audioUnit) == noErr;
setLatencySamples (0);
}
@ -557,6 +597,8 @@ void AudioUnitPluginInstance::prepareToPlay (double sampleRate_,
{
if (audioUnit != 0)
{
releaseResources();
Float64 sampleRateIn = 0, sampleRateOut = 0;
UInt32 sampleRateSize = sizeof (sampleRateIn);
AudioUnitGetProperty (audioUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Input, 0, &sampleRateIn, &sampleRateSize);
@ -564,25 +606,13 @@ void AudioUnitPluginInstance::prepareToPlay (double sampleRate_,
if (sampleRateIn != sampleRate_ || sampleRateOut != sampleRate_)
{
if (initialised)
{
AudioUnitUninitialize (audioUnit);
initialised = false;
}
Float64 sr = sampleRate_;
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Input, 0, &sr, sizeof (Float64));
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, &sr, sizeof (Float64));
}
}
initialise();
if (initialised)
{
int numIns, numOuts;
getNumChannels (numIns, numOuts);
setPlayConfigDetails (numIns, numOuts, sampleRate_, samplesPerBlockExpected);
Float64 latencySecs = 0.0;
@ -596,24 +626,26 @@ void AudioUnitPluginInstance::prepareToPlay (double sampleRate_,
AudioUnitReset (audioUnit, kAudioUnitScope_Output, 0);
AudioUnitReset (audioUnit, kAudioUnitScope_Global, 0);
AudioStreamBasicDescription stream;
zerostruct (stream);
stream.mSampleRate = sampleRate_;
stream.mFormatID = kAudioFormatLinearPCM;
stream.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved;
stream.mFramesPerPacket = 1;
stream.mBytesPerPacket = 4;
stream.mBytesPerFrame = 4;
stream.mBitsPerChannel = 32;
stream.mChannelsPerFrame = numIns;
{
AudioStreamBasicDescription stream;
zerostruct (stream);
stream.mSampleRate = sampleRate_;
stream.mFormatID = kAudioFormatLinearPCM;
stream.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved;
stream.mFramesPerPacket = 1;
stream.mBytesPerPacket = 4;
stream.mBytesPerFrame = 4;
stream.mBitsPerChannel = 32;
stream.mChannelsPerFrame = numIns;
OSStatus err = AudioUnitSetProperty (audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
0, &stream, sizeof (stream));
OSStatus err = AudioUnitSetProperty (audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
0, &stream, sizeof (stream));
stream.mChannelsPerFrame = numOuts;
stream.mChannelsPerFrame = numOuts;
err = AudioUnitSetProperty (audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
0, &stream, sizeof (stream));
err = AudioUnitSetProperty (audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
0, &stream, sizeof (stream));
}
outputBufferList.calloc (sizeof (AudioBufferList) + sizeof (AudioBuffer) * (numOuts + 1), 1);
outputBufferList->mNumberBuffers = numOuts;
@ -628,19 +660,24 @@ void AudioUnitPluginInstance::prepareToPlay (double sampleRate_,
currentBuffer = 0;
wasPlaying = false;
prepared = (AudioUnitInitialize (audioUnit) == noErr);
}
}
void AudioUnitPluginInstance::releaseResources()
{
if (initialised)
if (prepared)
{
AudioUnitUninitialize (audioUnit);
AudioUnitReset (audioUnit, kAudioUnitScope_Input, 0);
AudioUnitReset (audioUnit, kAudioUnitScope_Output, 0);
AudioUnitReset (audioUnit, kAudioUnitScope_Global, 0);
outputBufferList.free();
currentBuffer = 0;
prepared = false;
}
}
@ -678,7 +715,7 @@ void AudioUnitPluginInstance::processBlock (AudioSampleBuffer& buffer,
{
const int numSamples = buffer.getNumSamples();
if (initialised)
if (prepared)
{
AudioUnitRenderActionFlags flags = 0;
@ -718,7 +755,7 @@ void AudioUnitPluginInstance::processBlock (AudioSampleBuffer& buffer,
}
else
{
// Not initialised, so just bypass..
// Plugin not working correctly, so just bypass..
for (int i = getNumInputChannels(); i < getNumOutputChannels(); ++i)
buffer.clear (i, 0, buffer.getNumSamples());
}
@ -898,6 +935,8 @@ private:
UInt32 dataSize = 0;
Boolean isWritable = false;
AudioUnitInitialize (plugin.audioUnit);
if (AudioUnitGetPropertyInfo (plugin.audioUnit, kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global,
0, &dataSize, &isWritable) == noErr
&& dataSize != 0

View file

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

View file

@ -1745,9 +1745,25 @@ void LookAndFeel::drawCornerResizer (Graphics& g,
}
}
void LookAndFeel::drawResizableFrame (Graphics&, int /*w*/, int /*h*/,
const BorderSize& /*borders*/)
void LookAndFeel::drawResizableFrame (Graphics& g, int w, int h, const BorderSize& border)
{
if (! border.isEmpty())
{
const Rectangle<int> fullSize (0, 0, w, h);
const Rectangle<int> centreArea (border.subtractedFrom (fullSize));
g.saveState();
g.excludeClipRegion (centreArea);
g.setColour (Colour (0x50000000));
g.drawRect (fullSize);
g.setColour (Colour (0x19000000));
g.drawRect (centreArea.expanded (1, 1));
g.restoreState();
}
}
//==============================================================================
@ -1757,17 +1773,9 @@ void LookAndFeel::fillResizableWindowBackground (Graphics& g, int /*w*/, int /*h
g.fillAll (window.getBackgroundColour());
}
void LookAndFeel::drawResizableWindowBorder (Graphics& g, int w, int h,
const BorderSize& border, ResizableWindow&)
void LookAndFeel::drawResizableWindowBorder (Graphics&, int /*w*/, int /*h*/,
const BorderSize& /*border*/, ResizableWindow&)
{
g.setColour (Colour (0x80000000));
g.drawRect (0, 0, w, h);
g.setColour (Colour (0x19000000));
g.drawRect (border.getLeft() - 1,
border.getTop() - 1,
w + 2 - border.getLeftAndRight(),
h + 2 - border.getTopAndBottom());
}
void LookAndFeel::drawDocumentWindowTitleBar (DocumentWindow& window,

View file

@ -235,9 +235,7 @@ void MenuBarComponent::handleCommandMessage (int commandId)
{
const Point<int> mousePos (getMouseXYRelative());
updateItemUnderMouse (mousePos.getX(), mousePos.getY());
if (! isCurrentlyBlockedByAnotherModalComponent())
setOpenItem (-1);
setOpenItem (-1);
if (commandId != 0 && model != 0)
model->menuItemSelected (commandId, topLevelIndexClicked);

View file

@ -82,6 +82,9 @@ public:
/** Returns the sum of the left and right gaps. */
int getLeftAndRight() const throw() { return left + right; }
/** Returns true if this border has no thickness along any edge. */
bool isEmpty() const throw() { return left + right + top + bottom == 0; }
//==============================================================================
/** Changes the top gap. */
void setTop (int newTopGap) throw();

View file

@ -0,0 +1,148 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-10 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/
#ifndef __JUCE_MIDIDATACONCATENATOR_JUCEHEADER__
#define __JUCE_MIDIDATACONCATENATOR_JUCEHEADER__
//==============================================================================
/**
Helper class that takes chunks of incoming midi bytes, packages them into
messages, and dispatches them to a midi callback.
*/
class MidiDataConcatenator
{
public:
//==============================================================================
MidiDataConcatenator (const int initialBufferSize)
: pendingData (initialBufferSize),
pendingBytes (0), pendingDataTime (0)
{
}
void reset()
{
pendingBytes = 0;
pendingDataTime = 0;
}
void pushMidiData (const void* data, int numBytes, double time,
MidiInput* input, MidiInputCallback& callback)
{
const uint8* d = static_cast <const uint8*> (data);
while (numBytes > 0)
{
if (pendingBytes > 0 || d[0] == 0xf0)
{
processSysex (d, numBytes, time, input, callback);
}
else
{
int used = 0;
const MidiMessage m (d, numBytes, used, 0, time);
if (used <= 0)
{
jassertfalse; // malformed midi message
break;
}
callback.handleIncomingMidiMessage (input, m);
numBytes -= used;
d += used;
}
}
}
private:
void processSysex (const uint8*& d, int& numBytes, double time,
MidiInput* input, MidiInputCallback& callback)
{
if (*d == 0xf0)
{
pendingBytes = 0;
pendingDataTime = time;
}
pendingData.ensureSize (pendingBytes + numBytes, false);
uint8* totalMessage = static_cast<uint8*> (pendingData.getData());
uint8* dest = totalMessage + pendingBytes;
do
{
if (pendingBytes > 0 && *d >= 0x80)
{
if (*d >= 0xfa || *d == 0xf8)
{
callback.handleIncomingMidiMessage (input, MidiMessage (*d, time));
++d;
--numBytes;
}
else
{
if (*d == 0xf7)
{
*dest++ = *d++;
pendingBytes++;
--numBytes;
}
break;
}
}
else
{
*dest++ = *d++;
pendingBytes++;
--numBytes;
}
}
while (numBytes > 0);
if (pendingBytes > 0)
{
if (totalMessage [pendingBytes - 1] == 0xf7)
{
callback.handleIncomingMidiMessage (input, MidiMessage (totalMessage, pendingBytes, pendingDataTime));
pendingBytes = 0;
}
else
{
callback.handlePartialSysexMessage (input, totalMessage, pendingBytes, pendingDataTime);
}
}
}
MemoryBlock pendingData;
int pendingBytes;
double pendingDataTime;
MidiDataConcatenator (const MidiDataConcatenator&);
MidiDataConcatenator& operator= (const MidiDataConcatenator&);
};
#endif // __JUCE_MIDIDATACONCATENATOR_JUCEHEADER__

View file

@ -85,6 +85,7 @@ BEGIN_JUCE_NAMESPACE
#include "../audio/devices/juce_AudioIODeviceType.h"
#include "../audio/devices/juce_MidiOutput.h"
#include "../audio/devices/juce_MidiInput.h"
#include "common/juce_MidiDataConcatenator.h"
#undef Point
//==============================================================================

View file

@ -83,6 +83,7 @@ BEGIN_JUCE_NAMESPACE
#include "../audio/devices/juce_AudioIODeviceType.h"
#include "../audio/devices/juce_MidiOutput.h"
#include "../audio/devices/juce_MidiInput.h"
#include "common/juce_MidiDataConcatenator.h"
//==============================================================================
#define JUCE_INCLUDED_FILE 1

View file

@ -214,130 +214,75 @@ namespace CoreMidiHelpers
MIDIEndpointDispose (endPoint);
}
void send (const MIDIPacketList* const packets)
{
if (port != 0)
MIDISend (port, endPoint, packets);
else
MIDIReceived (endPoint, packets);
}
MIDIPortRef port;
MIDIEndpointRef endPoint;
};
//==============================================================================
class MidiPortAndCallback;
static CriticalSection callbackLock;
static Array<MidiPortAndCallback*> activeCallbacks;
class MidiPortAndCallback
{
public:
MidiInput* input;
MidiPortAndEndpoint* portAndEndpoint;
MidiInputCallback* callback;
MemoryBlock pendingData;
int pendingBytes;
double pendingDataTime;
bool active;
void processSysex (const uint8*& d, int& size, const double time)
MidiPortAndCallback (MidiInputCallback& callback_)
: input (0), active (false), callback (callback_), concatenator (2048)
{
if (*d == 0xf0)
}
~MidiPortAndCallback()
{
active = false;
{
pendingBytes = 0;
pendingDataTime = time;
const ScopedLock sl (callbackLock);
activeCallbacks.removeValue (this);
}
pendingData.ensureSize (pendingBytes + size, false);
uint8* totalMessage = (uint8*) pendingData.getData();
if (portAndEndpoint != 0 && portAndEndpoint->port != 0)
CHECK_ERROR (MIDIPortDisconnectSource (portAndEndpoint->port, portAndEndpoint->endPoint));
}
uint8* dest = totalMessage + pendingBytes;
void handlePackets (const MIDIPacketList* const pktlist)
{
const double time = Time::getMillisecondCounterHiRes() * 0.001;
while (size > 0)
const ScopedLock sl (callbackLock);
if (activeCallbacks.contains (this) && active)
{
if (pendingBytes > 0 && *d >= 0x80)
const MIDIPacket* packet = &pktlist->packet[0];
for (unsigned int i = 0; i < pktlist->numPackets; ++i)
{
if (*d >= 0xfa || *d == 0xf8)
{
callback->handleIncomingMidiMessage (input, MidiMessage (*d, time));
++d;
--size;
}
else
{
if (*d == 0xf7)
{
*dest++ = *d++;
pendingBytes++;
--size;
}
concatenator.pushMidiData (packet->data, (int) packet->length, time,
input, callback);
break;
}
packet = MIDIPacketNext (packet);
}
else
{
*dest++ = *d++;
pendingBytes++;
--size;
}
}
if (totalMessage [pendingBytes - 1] == 0xf7)
{
callback->handleIncomingMidiMessage (input, MidiMessage (totalMessage, pendingBytes, pendingDataTime));
pendingBytes = 0;
}
else
{
callback->handlePartialSysexMessage (input, totalMessage, pendingBytes, pendingDataTime);
}
}
MidiInput* input;
ScopedPointer<MidiPortAndEndpoint> portAndEndpoint;
volatile bool active;
private:
MidiInputCallback& callback;
MidiDataConcatenator concatenator;
};
static CriticalSection callbackLock;
static Array<void*> activeCallbacks;
static void midiInputProc (const MIDIPacketList* pktlist,
void* readProcRefCon,
void* /*srcConnRefCon*/)
static void midiInputProc (const MIDIPacketList* pktlist, void* readProcRefCon, void* /*srcConnRefCon*/)
{
double time = Time::getMillisecondCounterHiRes() * 0.001;
const double originalTime = time;
MidiPortAndCallback* const mpc = (MidiPortAndCallback*) readProcRefCon;
const ScopedLock sl (CoreMidiHelpers::callbackLock);
if (CoreMidiHelpers::activeCallbacks.contains (mpc) && mpc->active)
{
const MIDIPacket* packet = &pktlist->packet[0];
for (unsigned int i = 0; i < pktlist->numPackets; ++i)
{
const uint8* d = (const uint8*) (packet->data);
int size = packet->length;
while (size > 0)
{
time = originalTime;
if (mpc->pendingBytes > 0 || d[0] == 0xf0)
{
mpc->processSysex (d, size, time);
}
else
{
int used = 0;
const MidiMessage m (d, size, used, 0, time);
if (used <= 0)
{
jassertfalse; // malformed midi message
break;
}
else
{
mpc->callback->handleIncomingMidiMessage (mpc->input, m);
}
size -= used;
d += used;
}
}
packet = MIDIPacketNext (packet);
}
}
static_cast <MidiPortAndCallback*> (readProcRefCon)->handlePackets (pktlist);
}
}
@ -462,10 +407,7 @@ void MidiOutput::sendMessageNow (const MidiMessage& message)
p = MIDIPacketNext (p);
}
if (mpe->port != 0)
MIDISend (mpe->port, mpe->endPoint, packets);
else
MIDIReceived (mpe->endPoint, packets);
mpe->send (packets);
}
else
{
@ -475,10 +417,7 @@ void MidiOutput::sendMessageNow (const MidiMessage& message)
packets.packet[0].length = message.getRawDataSize();
*(int*) (packets.packet[0].data) = *(const int*) message.getRawData();
if (mpe->port != 0)
MIDISend (mpe->port, mpe->endPoint, &packets);
else
MIDIReceived (mpe->endPoint, &packets);
mpe->send (&packets);
}
}
@ -517,8 +456,10 @@ int MidiInput::getDefaultDeviceIndex()
MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback)
{
jassert (callback != 0);
using namespace CoreMidiHelpers;
MidiInput* mi = 0;
MidiInput* newInput = 0;
if (((unsigned int) index) < (unsigned int) MIDIGetNumberOfSources())
{
@ -526,31 +467,26 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback)
if (endPoint != 0)
{
CFStringRef pname;
CFStringRef name;
if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname)))
if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &name)))
{
MIDIClientRef client = getGlobalMidiClient();
if (client != 0)
{
MIDIPortRef port;
ScopedPointer <MidiPortAndCallback> mpc (new MidiPortAndCallback (*callback));
ScopedPointer <MidiPortAndCallback> mpc (new MidiPortAndCallback());
mpc->active = false;
if (CHECK_ERROR (MIDIInputPortCreate (client, pname, midiInputProc, mpc, &port)))
if (CHECK_ERROR (MIDIInputPortCreate (client, name, midiInputProc, mpc, &port)))
{
if (CHECK_ERROR (MIDIPortConnectSource (port, endPoint, 0)))
{
mpc->portAndEndpoint = new MidiPortAndEndpoint (port, endPoint);
mpc->callback = callback;
mpc->pendingBytes = 0;
mpc->pendingData.ensureSize (128);
mi = new MidiInput (getDevices() [index]);
mpc->input = mi;
mi->internal = mpc;
newInput = new MidiInput (getDevices() [index]);
mpc->input = newInput;
newInput->internal = mpc;
const ScopedLock sl (callbackLock);
activeCallbacks.add (mpc.release());
@ -563,22 +499,24 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback)
}
}
CFRelease (pname);
CFRelease (name);
}
}
return mi;
return newInput;
}
MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallback* callback)
{
jassert (callback != 0);
using namespace CoreMidiHelpers;
MidiInput* mi = 0;
MIDIClientRef client = getGlobalMidiClient();
if (client != 0)
{
ScopedPointer <MidiPortAndCallback> mpc (new MidiPortAndCallback());
ScopedPointer <MidiPortAndCallback> mpc (new MidiPortAndCallback (*callback));
mpc->active = false;
MIDIEndpointRef endPoint;
@ -586,9 +524,6 @@ MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallba
if (CHECK_ERROR (MIDIDestinationCreate (client, name, midiInputProc, mpc, &endPoint)))
{
mpc->portAndEndpoint = new MidiPortAndEndpoint (0, endPoint);
mpc->callback = callback;
mpc->pendingBytes = 0;
mpc->pendingData.ensureSize (128);
mi = new MidiInput (deviceName);
mpc->input = mi;
@ -611,21 +546,7 @@ MidiInput::MidiInput (const String& name_)
MidiInput::~MidiInput()
{
using namespace CoreMidiHelpers;
MidiPortAndCallback* const mpc = static_cast<MidiPortAndCallback*> (internal);
mpc->active = false;
{
const ScopedLock sl (callbackLock);
activeCallbacks.removeValue (mpc);
}
if (mpc->portAndEndpoint->port != 0)
CHECK_ERROR (MIDIPortDisconnectSource (mpc->portAndEndpoint->port, mpc->portAndEndpoint->endPoint));
delete mpc->portAndEndpoint;
delete mpc;
delete static_cast<CoreMidiHelpers::MidiPortAndCallback*> (internal);
}
void MidiInput::start()

View file

@ -78,11 +78,7 @@ public:
{
const Point<int> pos (owner->relativePositionToOtherComponent (topComp, Point<int>()));
NSRect r;
r.origin.x = (float) pos.getX();
r.origin.y = (float) pos.getY();
r.size.width = (float) owner->getWidth();
r.size.height = (float) owner->getHeight();
NSRect r = NSMakeRect ((float) pos.getX(), (float) pos.getY(), (float) owner->getWidth(), (float) owner->getHeight());
r.origin.y = [[view superview] frame].size.height - (r.origin.y + r.size.height);
[view setFrame: r];

View file

@ -871,11 +871,7 @@ NSViewComponentPeer::NSViewComponentPeer (Component* const component_,
#endif
recursiveToFrontCall (false)
{
NSRect r;
r.origin.x = 0;
r.origin.y = 0;
r.size.width = (float) component->getWidth();
r.size.height = (float) component->getHeight();
NSRect r = NSMakeRect (0, 0, (float) component->getWidth(),(float) component->getHeight());
view = [[JuceNSView alloc] initWithOwner: this withFrame: r];
[view setPostsFrameChangedNotifications: YES];
@ -999,14 +995,8 @@ void NSViewComponentPeer::setSize (int w, int h)
void NSViewComponentPeer::setBounds (int x, int y, int w, int h, bool isNowFullScreen)
{
fullScreen = isNowFullScreen;
w = jmax (0, w);
h = jmax (0, h);
NSRect r;
r.origin.x = (float) x;
r.origin.y = (float) y;
r.size.width = (float) w;
r.size.height = (float) h;
NSRect r = NSMakeRect ((float) x, (float) y, (float) jmax (0, w), (float) jmax (0, h));
if (isSharedWindow)
{

View file

@ -29,14 +29,8 @@
//==============================================================================
void juce_setWindowStyleBit (HWND h, const int styleType, const int feature, const bool bitIsSet) throw();
namespace FileChooserHelpers
{
static const void* defaultDirPath = 0;
static String returnedString; // need this to get non-existent pathnames from the directory chooser
static Component* currentExtraFileWin = 0;
static bool areThereAnyAlwaysOnTopWindows()
{
for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;)
@ -50,64 +44,67 @@ namespace FileChooserHelpers
return false;
}
static int CALLBACK browseCallbackProc (HWND hWnd, UINT msg, LPARAM lParam, LPARAM /*lpData*/)
struct FileChooserCallbackInfo
{
String initialPath;
String returnedString; // need this to get non-existent pathnames from the directory chooser
ScopedPointer<Component> customComponent;
};
static int CALLBACK browseCallbackProc (HWND hWnd, UINT msg, LPARAM lParam, LPARAM lpData)
{
FileChooserCallbackInfo* info = (FileChooserCallbackInfo*) lpData;
if (msg == BFFM_INITIALIZED)
SendMessage (hWnd, BFFM_SETSELECTIONW, TRUE, (LPARAM) defaultDirPath);
SendMessage (hWnd, BFFM_SETSELECTIONW, TRUE, (LPARAM) static_cast <const WCHAR*> (info->initialPath));
else if (msg == BFFM_VALIDATEFAILEDW)
returnedString = (LPCWSTR) lParam;
info->returnedString = (LPCWSTR) lParam;
else if (msg == BFFM_VALIDATEFAILEDA)
returnedString = (const char*) lParam;
info->returnedString = (const char*) lParam;
return 0;
}
static UINT_PTR CALLBACK openCallback (HWND hdlg, UINT uiMsg, WPARAM /*wParam*/, LPARAM lParam)
{
if (currentExtraFileWin != 0)
if (uiMsg == WM_INITDIALOG)
{
if (uiMsg == WM_INITDIALOG)
Component* customComp = ((FileChooserCallbackInfo*) (((OPENFILENAMEW*) lParam)->lCustData))->customComponent;
HWND dialogH = GetParent (hdlg);
jassert (dialogH != 0);
if (dialogH == 0)
dialogH = hdlg;
RECT r, cr;
GetWindowRect (dialogH, &r);
GetClientRect (dialogH, &cr);
SetWindowPos (dialogH, 0,
r.left, r.top,
customComp->getWidth() + jmax (150, (int) (r.right - r.left)),
jmax (150, (int) (r.bottom - r.top)),
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER);
customComp->setBounds (cr.right, cr.top, customComp->getWidth(), cr.bottom - cr.top);
customComp->addToDesktop (0, dialogH);
}
else if (uiMsg == WM_NOTIFY)
{
LPOFNOTIFY ofn = (LPOFNOTIFY) lParam;
if (ofn->hdr.code == CDN_SELCHANGE)
{
HWND dialogH = GetParent (hdlg);
jassert (dialogH != 0);
if (dialogH == 0)
dialogH = hdlg;
FileChooserCallbackInfo* info = (FileChooserCallbackInfo*) ofn->lpOFN->lCustData;
FilePreviewComponent* comp = static_cast<FilePreviewComponent*> (info->customComponent->getChildComponent(0));
RECT r, cr;
GetWindowRect (dialogH, &r);
GetClientRect (dialogH, &cr);
SetWindowPos (dialogH, 0,
r.left, r.top,
currentExtraFileWin->getWidth() + jmax (150, (int) (r.right - r.left)),
jmax (150, (int) (r.bottom - r.top)),
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER);
currentExtraFileWin->setBounds (cr.right, cr.top, currentExtraFileWin->getWidth(), cr.bottom - cr.top);
currentExtraFileWin->getChildComponent(0)->setBounds (0, 0, currentExtraFileWin->getWidth(), currentExtraFileWin->getHeight());
SetParent ((HWND) currentExtraFileWin->getWindowHandle(), (HWND) dialogH);
juce_setWindowStyleBit ((HWND)currentExtraFileWin->getWindowHandle(), GWL_STYLE, WS_CHILD, (dialogH != 0));
juce_setWindowStyleBit ((HWND)currentExtraFileWin->getWindowHandle(), GWL_STYLE, WS_POPUP, (dialogH == 0));
}
else if (uiMsg == WM_NOTIFY)
{
LPOFNOTIFY ofn = (LPOFNOTIFY) lParam;
if (ofn->hdr.code == CDN_SELCHANGE)
if (comp != 0)
{
FilePreviewComponent* comp = (FilePreviewComponent*) currentExtraFileWin->getChildComponent(0);
WCHAR path [MAX_PATH * 2];
zerostruct (path);
CommDlg_OpenSave_GetFilePath (GetParent (hdlg), (LPARAM) &path, MAX_PATH);
if (comp != 0)
{
TCHAR path [MAX_PATH * 2];
path[0] = 0;
CommDlg_OpenSave_GetFilePath (GetParent (hdlg), (LPARAM) &path, MAX_PATH);
const String fn ((const WCHAR*) path);
comp->selectedFileChanged (File (fn));
}
comp->selectedFileChanged (File (path));
}
}
}
@ -115,17 +112,15 @@ namespace FileChooserHelpers
return 0;
}
class FPComponentHolder : public Component
class CustomComponentHolder : public Component
{
public:
FPComponentHolder()
CustomComponentHolder (Component* customComp)
{
setVisible (true);
setOpaque (true);
}
~FPComponentHolder()
{
addAndMakeVisible (customComp);
setSize (jlimit (20, 800, customComp->getWidth()), customComp->getHeight());
}
void paint (Graphics& g)
@ -133,203 +128,157 @@ namespace FileChooserHelpers
g.fillAll (Colours::lightgrey);
}
void resized()
{
if (getNumChildComponents() > 0)
getChildComponent(0)->setBounds (getLocalBounds());
}
juce_UseDebuggingNewOperator
private:
FPComponentHolder (const FPComponentHolder&);
FPComponentHolder& operator= (const FPComponentHolder&);
CustomComponentHolder (const CustomComponentHolder&);
CustomComponentHolder& operator= (const CustomComponentHolder&);
};
}
//==============================================================================
void FileChooser::showPlatformDialog (Array<File>& results,
const String& title,
const File& currentFileOrDirectory,
const String& filter,
bool selectsDirectory,
bool /*selectsFiles*/,
bool isSaveDialogue,
bool warnAboutOverwritingExistingFiles,
bool selectMultipleFiles,
FilePreviewComponent* extraInfoComponent)
void FileChooser::showPlatformDialog (Array<File>& results, const String& title, const File& currentFileOrDirectory,
const String& filter, bool selectsDirectory, bool /*selectsFiles*/,
bool isSaveDialogue, bool warnAboutOverwritingExistingFiles,
bool selectMultipleFiles, FilePreviewComponent* extraInfoComponent)
{
using namespace FileChooserHelpers;
const int numCharsAvailable = 32768;
MemoryBlock filenameSpace ((numCharsAvailable + 1) * sizeof (WCHAR), true);
WCHAR* const fname = (WCHAR*) filenameSpace.getData();
int fnameIdx = 0;
JUCE_TRY
HeapBlock<WCHAR> files;
const int charsAvailableForResult = 32768;
files.calloc (charsAvailableForResult + 1);
int filenameOffset = 0;
FileChooserCallbackInfo info;
// use a modal window as the parent for this dialog box
// to block input from other app windows
Component parentWindow (String::empty);
const Rectangle<int> mainMon (Desktop::getInstance().getMainMonitorArea());
parentWindow.setBounds (mainMon.getX() + mainMon.getWidth() / 4,
mainMon.getY() + mainMon.getHeight() / 4,
0, 0);
parentWindow.setOpaque (true);
parentWindow.setAlwaysOnTop (areThereAnyAlwaysOnTopWindows());
parentWindow.addToDesktop (0);
if (extraInfoComponent == 0)
parentWindow.enterModalState();
if (currentFileOrDirectory.isDirectory())
{
// use a modal window as the parent for this dialog box
// to block input from other app windows
const Rectangle<int> mainMon (Desktop::getInstance().getMainMonitorArea());
info.initialPath = currentFileOrDirectory.getFullPathName();
}
else
{
currentFileOrDirectory.getFileName().copyToUnicode (files, charsAvailableForResult);
info.initialPath = currentFileOrDirectory.getParentDirectory().getFullPathName();
}
Component w (String::empty);
w.setBounds (mainMon.getX() + mainMon.getWidth() / 4,
mainMon.getY() + mainMon.getHeight() / 4,
0, 0);
w.setOpaque (true);
w.setAlwaysOnTop (areThereAnyAlwaysOnTopWindows());
w.addToDesktop (0);
if (selectsDirectory)
{
BROWSEINFO bi;
zerostruct (bi);
if (extraInfoComponent == 0)
w.enterModalState();
bi.hwndOwner = (HWND) parentWindow.getWindowHandle();
bi.pszDisplayName = files;
bi.lpszTitle = title;
bi.lParam = (LPARAM) &info;
bi.lpfn = browseCallbackProc;
#ifdef BIF_USENEWUI
bi.ulFlags = BIF_USENEWUI | BIF_VALIDATE;
#else
bi.ulFlags = 0x50;
#endif
String initialDir;
LPITEMIDLIST list = SHBrowseForFolder (&bi);
if (currentFileOrDirectory.isDirectory())
if (! SHGetPathFromIDListW (list, files))
{
initialDir = currentFileOrDirectory.getFullPathName();
}
else
{
currentFileOrDirectory.getFileName().copyToUnicode (fname, numCharsAvailable);
initialDir = currentFileOrDirectory.getParentDirectory().getFullPathName();
files[0] = 0;
info.returnedString = String::empty;
}
if (currentExtraFileWin->isValidComponent())
LPMALLOC al;
if (list != 0 && SUCCEEDED (SHGetMalloc (&al)))
al->Free (list);
if (info.returnedString.isNotEmpty())
{
jassertfalse;
results.add (File (String (files)).getSiblingFile (info.returnedString));
return;
}
if (selectsDirectory)
{
LPITEMIDLIST list = 0;
filenameSpace.fillWith (0);
{
BROWSEINFO bi;
zerostruct (bi);
bi.hwndOwner = (HWND) w.getWindowHandle();
bi.pszDisplayName = fname;
bi.lpszTitle = title;
bi.lpfn = browseCallbackProc;
#ifdef BIF_USENEWUI
bi.ulFlags = BIF_USENEWUI | BIF_VALIDATE;
#else
bi.ulFlags = 0x50;
#endif
defaultDirPath = (const WCHAR*) initialDir;
list = SHBrowseForFolder (&bi);
if (! SHGetPathFromIDListW (list, fname))
{
fname[0] = 0;
returnedString = String::empty;
}
}
LPMALLOC al;
if (list != 0 && SUCCEEDED (SHGetMalloc (&al)))
al->Free (list);
defaultDirPath = 0;
if (returnedString.isNotEmpty())
{
const String stringFName (fname);
results.add (File (stringFName).getSiblingFile (returnedString));
returnedString = String::empty;
return;
}
}
else
{
DWORD flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR | OFN_HIDEREADONLY;
if (warnAboutOverwritingExistingFiles)
flags |= OFN_OVERWRITEPROMPT;
if (selectMultipleFiles)
flags |= OFN_ALLOWMULTISELECT;
if (extraInfoComponent != 0)
{
flags |= OFN_ENABLEHOOK;
currentExtraFileWin = new FPComponentHolder();
currentExtraFileWin->addAndMakeVisible (extraInfoComponent);
currentExtraFileWin->setSize (jlimit (20, 800, extraInfoComponent->getWidth()),
extraInfoComponent->getHeight());
currentExtraFileWin->addToDesktop (0);
currentExtraFileWin->enterModalState();
}
{
WCHAR filters [1024];
zeromem (filters, sizeof (filters));
filter.copyToUnicode (filters, 1024);
filter.copyToUnicode (filters + filter.length() + 1,
1022 - filter.length());
OPENFILENAMEW of;
zerostruct (of);
#ifdef OPENFILENAME_SIZE_VERSION_400W
of.lStructSize = OPENFILENAME_SIZE_VERSION_400W;
#else
of.lStructSize = sizeof (of);
#endif
of.hwndOwner = (HWND) w.getWindowHandle();
of.lpstrFilter = filters;
of.nFilterIndex = 1;
of.lpstrFile = fname;
of.nMaxFile = numCharsAvailable;
of.lpstrInitialDir = initialDir;
of.lpstrTitle = title;
of.Flags = flags;
if (extraInfoComponent != 0)
of.lpfnHook = &openCallback;
if (isSaveDialogue)
{
if (! GetSaveFileName (&of))
fname[0] = 0;
else
fnameIdx = of.nFileOffset;
}
else
{
if (! GetOpenFileName (&of))
fname[0] = 0;
else
fnameIdx = of.nFileOffset;
}
}
}
}
#if JUCE_CATCH_UNHANDLED_EXCEPTIONS
catch (...)
else
{
fname[0] = 0;
DWORD flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR | OFN_HIDEREADONLY;
if (warnAboutOverwritingExistingFiles)
flags |= OFN_OVERWRITEPROMPT;
if (selectMultipleFiles)
flags |= OFN_ALLOWMULTISELECT;
if (extraInfoComponent != 0)
{
flags |= OFN_ENABLEHOOK;
info.customComponent = new CustomComponentHolder (extraInfoComponent);
info.customComponent->enterModalState();
}
WCHAR filters [1024];
zerostruct (filters);
filter.copyToUnicode (filters, 1024);
filter.copyToUnicode (filters + filter.length() + 1, 1022 - filter.length());
OPENFILENAMEW of;
zerostruct (of);
#ifdef OPENFILENAME_SIZE_VERSION_400W
of.lStructSize = OPENFILENAME_SIZE_VERSION_400W;
#else
of.lStructSize = sizeof (of);
#endif
of.hwndOwner = (HWND) parentWindow.getWindowHandle();
of.lpstrFilter = filters;
of.nFilterIndex = 1;
of.lpstrFile = files;
of.nMaxFile = charsAvailableForResult;
of.lpstrInitialDir = info.initialPath;
of.lpstrTitle = title;
of.Flags = flags;
of.lCustData = (LPARAM) &info;
if (extraInfoComponent != 0)
of.lpfnHook = &openCallback;
if (! (isSaveDialogue ? GetSaveFileName (&of)
: GetOpenFileName (&of)))
return;
filenameOffset = of.nFileOffset;
}
#endif
deleteAndZero (currentExtraFileWin);
const WCHAR* const files = fname;
if (selectMultipleFiles && fnameIdx > 0 && files [fnameIdx - 1] == 0)
if (selectMultipleFiles && filenameOffset > 0 && files [filenameOffset - 1] == 0)
{
const WCHAR* filename = files + fnameIdx;
const WCHAR* filename = files + filenameOffset;
while (*filename != 0)
{
const String filepath (String (files) + "\\" + String (filename));
results.add (File (filepath));
results.add (File (String (files) + "\\" + String (filename)));
filename += CharacterFunctions::length (filename) + 1;
}
}
else if (files[0] != 0)
{
results.add (File (files));
results.add (File (String (files)));
}
}

View file

@ -27,31 +27,24 @@
// compiled on its own).
#if JUCE_INCLUDED_FILE
//==============================================================================
class MidiInThread : public Thread
class MidiInCollector
{
public:
//==============================================================================
MidiInThread (MidiInput* const input_,
MidiInputCallback* const callback_)
: Thread ("Juce Midi"),
deviceHandle (0),
MidiInCollector (MidiInput* const input_,
MidiInputCallback& callback_)
: deviceHandle (0),
input (input_),
callback (callback_),
concatenator (4096),
isStarted (false),
startTime (0)
{
pending.ensureSize ((int) defaultBufferSize);
}
for (int i = (int) numInHeaders; --i >= 0;)
{
zeromem (&hdr[i], sizeof (MIDIHDR));
hdr[i].lpData = inData[i];
hdr[i].dwBufferLength = (int) inBufferSize;
}
};
~MidiInThread()
~MidiInCollector()
{
stop();
@ -69,89 +62,21 @@ public:
}
//==============================================================================
void handle (const uint32 message, const uint32 timeStamp)
void handleMessage (const uint32 message, const uint32 timeStamp)
{
const int byte = message & 0xff;
if (byte < 0x80)
return;
const int time = timeStampToMs (timeStamp);
if ((message & 0xff) >= 0x80 && isStarted)
{
const ScopedLock sl (lock);
pending.addEvent (&message, 3, time);
concatenator.pushMidiData (&message, 3, convertTimeStamp (timeStamp), input, callback);
writeFinishedBlocks();
}
notify();
}
void handleSysEx (MIDIHDR* const hdr, const uint32 timeStamp)
{
const int time = timeStampToMs (timeStamp);
const int num = hdr->dwBytesRecorded;
if (num > 0)
if (isStarted)
{
{
const ScopedLock sl (lock);
pending.addEvent (hdr->lpData, num, time);
}
notify();
}
}
void writeBlock (const int i)
{
hdr[i].dwBytesRecorded = 0;
MMRESULT res = midiInPrepareHeader (deviceHandle, &hdr[i], sizeof (MIDIHDR));
jassert (res == MMSYSERR_NOERROR);
res = midiInAddBuffer (deviceHandle, &hdr[i], sizeof (MIDIHDR));
jassert (res == MMSYSERR_NOERROR);
}
void run()
{
MidiBuffer newEvents;
newEvents.ensureSize ((int) defaultBufferSize);
while (! threadShouldExit())
{
for (int i = 0; i < (int) numInHeaders; ++i)
{
if ((hdr[i].dwFlags & WHDR_DONE) != 0)
{
MMRESULT res = midiInUnprepareHeader (deviceHandle, &hdr[i], sizeof (MIDIHDR));
(void) res;
jassert (res == MMSYSERR_NOERROR);
writeBlock (i);
}
}
newEvents.clear(); // (resets it without freeing allocated storage)
{
const ScopedLock sl (lock);
newEvents.swapWith (pending);
}
//xxx needs to figure out if blocks are broken up or not
if (newEvents.isEmpty())
{
wait (500);
}
else
{
MidiMessage message (0xf4, 0.0);
int time;
for (MidiBuffer::Iterator i (newEvents); i.getNextEvent (message, time);)
{
message.setTimeStamp (time * 0.001);
callback->handleIncomingMidiMessage (input, message);
}
}
concatenator.pushMidiData (hdr->lpData, hdr->dwBytesRecorded, convertTimeStamp (timeStamp), input, callback);
writeFinishedBlocks();
}
}
@ -160,23 +85,22 @@ public:
jassert (deviceHandle != 0);
if (deviceHandle != 0 && ! isStarted)
{
stop();
activeMidiCollectors.addIfNotAlreadyThere (this);
activeMidiThreads.addIfNotAlreadyThere (this);
int i;
for (i = 0; i < (int) numInHeaders; ++i)
writeBlock (i);
for (int i = 0; i < (int) numHeaders; ++i)
headers[i].write (deviceHandle);
startTime = Time::getMillisecondCounter();
MMRESULT res = midiInStart (deviceHandle);
jassert (res == MMSYSERR_NOERROR);
if (res == MMSYSERR_NOERROR)
{
concatenator.reset();
isStarted = true;
pending.clear();
startThread (6);
}
else
{
unprepareAllHeaders();
}
}
}
@ -185,42 +109,25 @@ public:
{
if (isStarted)
{
stopThread (5000);
isStarted = false;
midiInReset (deviceHandle);
midiInStop (deviceHandle);
activeMidiThreads.removeValue (this);
{ const ScopedLock sl (lock); }
for (int i = (int) numInHeaders; --i >= 0;)
{
if ((hdr[i].dwFlags & WHDR_DONE) != 0)
{
int c = 10;
while (--c >= 0 && midiInUnprepareHeader (deviceHandle, &hdr[i], sizeof (MIDIHDR)) == MIDIERR_STILLPLAYING)
Sleep (20);
jassert (c >= 0);
}
}
isStarted = false;
pending.clear();
activeMidiCollectors.removeValue (this);
unprepareAllHeaders();
concatenator.reset();
}
}
static void CALLBACK midiInCallback (HMIDIIN, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR midiMessage, DWORD_PTR timeStamp)
{
MidiInThread* const thread = reinterpret_cast <MidiInThread*> (dwInstance);
MidiInCollector* const collector = reinterpret_cast <MidiInCollector*> (dwInstance);
if (thread != 0 && activeMidiThreads.contains (thread))
if (activeMidiCollectors.contains (collector))
{
if (uMsg == MIM_DATA)
thread->handle ((uint32) midiMessage, (uint32) timeStamp);
collector->handleMessage ((uint32) midiMessage, (uint32) timeStamp);
else if (uMsg == MIM_LONGDATA)
thread->handleSysEx ((MIDIHDR*) midiMessage, (uint32) timeStamp);
collector->handleSysEx ((MIDIHDR*) midiMessage, (uint32) timeStamp);
}
}
@ -229,24 +136,77 @@ public:
HMIDIIN deviceHandle;
private:
static Array <void*, CriticalSection> activeMidiThreads;
static Array <MidiInCollector*, CriticalSection> activeMidiCollectors;
MidiInput* input;
MidiInputCallback* callback;
bool isStarted;
MidiInputCallback& callback;
MidiDataConcatenator concatenator;
bool volatile isStarted;
uint32 startTime;
CriticalSection lock;
enum { defaultBufferSize = 8192,
numInHeaders = 32,
inBufferSize = 256 };
class MidiHeader
{
public:
MidiHeader()
{
zerostruct (hdr);
hdr.lpData = data;
hdr.dwBufferLength = numElementsInArray (data);
}
MIDIHDR hdr [(int) numInHeaders];
char inData [(int) numInHeaders] [(int) inBufferSize];
void write (HMIDIIN deviceHandle)
{
hdr.dwBytesRecorded = 0;
MMRESULT res = midiInPrepareHeader (deviceHandle, &hdr, sizeof (hdr));
res = midiInAddBuffer (deviceHandle, &hdr, sizeof (hdr));
}
MidiBuffer pending;
void writeIfFinished (HMIDIIN deviceHandle)
{
if ((hdr.dwFlags & WHDR_DONE) != 0)
{
MMRESULT res = midiInUnprepareHeader (deviceHandle, &hdr, sizeof (hdr));
(void) res;
write (deviceHandle);
}
}
int timeStampToMs (uint32 timeStamp)
void unprepare (HMIDIIN deviceHandle)
{
if ((hdr.dwFlags & WHDR_DONE) != 0)
{
int c = 10;
while (--c >= 0 && midiInUnprepareHeader (deviceHandle, &hdr, sizeof (hdr)) == MIDIERR_STILLPLAYING)
Thread::sleep (20);
jassert (c >= 0);
}
}
private:
MIDIHDR hdr;
char data [256];
MidiHeader (const MidiHeader&);
MidiHeader& operator= (const MidiHeader&);
};
enum { numHeaders = 32 };
MidiHeader headers [numHeaders];
void writeFinishedBlocks()
{
for (int i = 0; i < (int) numHeaders; ++i)
headers[i].writeIfFinished (deviceHandle);
}
void unprepareAllHeaders()
{
for (int i = 0; i < (int) numHeaders; ++i)
headers[i].unprepare (deviceHandle);
}
double convertTimeStamp (uint32 timeStamp)
{
timeStamp += startTime;
@ -259,14 +219,14 @@ private:
timeStamp = now;
}
return (int) timeStamp;
return timeStamp * 0.001;
}
MidiInThread (const MidiInThread&);
MidiInThread& operator= (const MidiInThread&);
MidiInCollector (const MidiInCollector&);
MidiInCollector& operator= (const MidiInCollector&);
};
Array <void*, CriticalSection> MidiInThread::activeMidiThreads;
Array <MidiInCollector*, CriticalSection> MidiInCollector::activeMidiCollectors;
//==============================================================================
@ -322,18 +282,18 @@ MidiInput* MidiInput::openDevice (const int index, MidiInputCallback* const call
}
ScopedPointer <MidiInput> in (new MidiInput (name));
ScopedPointer <MidiInThread> thread (new MidiInThread (in, callback));
ScopedPointer <MidiInCollector> collector (new MidiInCollector (in, *callback));
HMIDIIN h;
HRESULT err = midiInOpen (&h, deviceId,
(DWORD_PTR) &MidiInThread::midiInCallback,
(DWORD_PTR) (MidiInThread*) thread,
(DWORD_PTR) &MidiInCollector::midiInCallback,
(DWORD_PTR) (MidiInCollector*) collector,
CALLBACK_FUNCTION);
if (err == MMSYSERR_NOERROR)
{
thread->deviceHandle = h;
in->internal = thread.release();
collector->deviceHandle = h;
in->internal = collector.release();
return in.release();
}
@ -348,17 +308,17 @@ MidiInput::MidiInput (const String& name_)
MidiInput::~MidiInput()
{
delete static_cast <MidiInThread*> (internal);
delete static_cast <MidiInCollector*> (internal);
}
void MidiInput::start()
{
static_cast <MidiInThread*> (internal)->start();
static_cast <MidiInCollector*> (internal)->start();
}
void MidiInput::stop()
{
static_cast <MidiInThread*> (internal)->stop();
static_cast <MidiInCollector*> (internal)->stop();
}