Browse Source

Update to latest juce

tags/2018-04-16
falkTX 11 years ago
parent
commit
300096b8ef
99 changed files with 1417 additions and 826 deletions
  1. +1
    -1
      libs/juce/source/modules/juce_audio_basics/effects/juce_Reverb.h
  2. +13
    -12
      libs/juce/source/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp
  3. +12
    -12
      libs/juce/source/modules/juce_audio_basics/midi/juce_MidiMessageSequence.h
  4. +12
    -10
      libs/juce/source/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp
  5. +19
    -24
      libs/juce/source/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h
  6. +6
    -13
      libs/juce/source/modules/juce_audio_devices/audio_io/juce_AudioIODevice.cpp
  7. +5
    -0
      libs/juce/source/modules/juce_audio_devices/audio_io/juce_AudioIODevice.h
  8. +1
    -1
      libs/juce/source/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h
  9. +1
    -0
      libs/juce/source/modules/juce_audio_devices/juce_audio_devices.cpp
  10. +43
    -24
      libs/juce/source/modules/juce_audio_devices/native/juce_android_OpenSL.cpp
  11. +28
    -44
      libs/juce/source/modules/juce_audio_devices/native/juce_ios_Audio.cpp
  12. +28
    -3
      libs/juce/source/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp
  13. +2
    -2
      libs/juce/source/modules/juce_audio_formats/codecs/juce_AiffAudioFormat.cpp
  14. +250
    -172
      libs/juce/source/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h
  15. +2
    -1
      libs/juce/source/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp
  16. +73
    -59
      libs/juce/source/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp
  17. +1
    -1
      libs/juce/source/modules/juce_audio_processors/format/juce_AudioPluginFormat.h
  18. +1
    -1
      libs/juce/source/modules/juce_audio_processors/format/juce_AudioPluginFormatManager.h
  19. +1
    -1
      libs/juce/source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.h
  20. +3
    -3
      libs/juce/source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm
  21. +54
    -27
      libs/juce/source/modules/juce_audio_processors/format_types/juce_VST3Common.h
  22. +361
    -62
      libs/juce/source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp
  23. +2
    -4
      libs/juce/source/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp
  24. +1
    -5
      libs/juce/source/modules/juce_audio_processors/processors/juce_AudioProcessor.h
  25. +3
    -3
      libs/juce/source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h
  26. +26
    -15
      libs/juce/source/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp
  27. +7
    -11
      libs/juce/source/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp
  28. +2
    -2
      libs/juce/source/modules/juce_audio_utils/gui/juce_AudioThumbnail.cpp
  29. +1
    -1
      libs/juce/source/modules/juce_core/containers/juce_AbstractFifo.cpp
  30. +1
    -1
      libs/juce/source/modules/juce_core/containers/juce_Array.h
  31. +1
    -1
      libs/juce/source/modules/juce_core/containers/juce_DynamicObject.cpp
  32. +1
    -1
      libs/juce/source/modules/juce_core/containers/juce_DynamicObject.h
  33. +8
    -0
      libs/juce/source/modules/juce_core/files/juce_File.h
  34. +12
    -23
      libs/juce/source/modules/juce_core/files/juce_FileInputStream.cpp
  35. +9
    -9
      libs/juce/source/modules/juce_core/files/juce_FileInputStream.h
  36. +1
    -1
      libs/juce/source/modules/juce_core/javascript/juce_Javascript.cpp
  37. +1
    -1
      libs/juce/source/modules/juce_core/memory/juce_SharedResourcePointer.h
  38. +8
    -3
      libs/juce/source/modules/juce_core/native/java/JuceAppActivity.java
  39. +13
    -2
      libs/juce/source/modules/juce_core/native/juce_android_SystemStats.cpp
  40. +4
    -1
      libs/juce/source/modules/juce_core/native/juce_linux_Network.cpp
  41. +1
    -1
      libs/juce/source/modules/juce_core/native/juce_linux_SystemStats.cpp
  42. +9
    -4
      libs/juce/source/modules/juce_core/native/juce_mac_Network.mm
  43. +1
    -1
      libs/juce/source/modules/juce_core/native/juce_mac_SystemStats.mm
  44. +10
    -7
      libs/juce/source/modules/juce_core/native/juce_posix_SharedCode.h
  45. +23
    -1
      libs/juce/source/modules/juce_core/native/juce_win32_Files.cpp
  46. +11
    -5
      libs/juce/source/modules/juce_core/native/juce_win32_Network.cpp
  47. +11
    -3
      libs/juce/source/modules/juce_core/native/juce_win32_SystemStats.cpp
  48. +2
    -3
      libs/juce/source/modules/juce_core/network/juce_URL.cpp
  49. +3
    -1
      libs/juce/source/modules/juce_core/system/juce_SystemStats.h
  50. +1
    -1
      libs/juce/source/modules/juce_core/system/juce_TargetPlatform.h
  51. +4
    -4
      libs/juce/source/modules/juce_core/text/juce_LocalisedStrings.cpp
  52. +4
    -4
      libs/juce/source/modules/juce_core/text/juce_LocalisedStrings.h
  53. +3
    -2
      libs/juce/source/modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp
  54. +2
    -1
      libs/juce/source/modules/juce_data_structures/app_properties/juce_PropertiesFile.h
  55. +11
    -83
      libs/juce/source/modules/juce_data_structures/values/juce_Value.cpp
  56. +8
    -5
      libs/juce/source/modules/juce_data_structures/values/juce_Value.h
  57. +2
    -2
      libs/juce/source/modules/juce_events/broadcasters/juce_AsyncUpdater.h
  58. +1
    -1
      libs/juce/source/modules/juce_events/native/juce_win32_Messaging.cpp
  59. +5
    -5
      libs/juce/source/modules/juce_graphics/contexts/juce_GraphicsContext.cpp
  60. +6
    -1
      libs/juce/source/modules/juce_graphics/fonts/juce_CustomTypeface.h
  61. +4
    -4
      libs/juce/source/modules/juce_graphics/fonts/juce_Font.h
  62. +12
    -12
      libs/juce/source/modules/juce_graphics/geometry/juce_Path.cpp
  63. +6
    -2
      libs/juce/source/modules/juce_graphics/geometry/juce_Path.h
  64. +38
    -2
      libs/juce/source/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm
  65. +12
    -2
      libs/juce/source/modules/juce_graphics/native/juce_mac_Fonts.mm
  66. +2
    -2
      libs/juce/source/modules/juce_gui_basics/commands/juce_ApplicationCommandTarget.cpp
  67. +1
    -1
      libs/juce/source/modules/juce_gui_basics/commands/juce_ApplicationCommandTarget.h
  68. +3
    -3
      libs/juce/source/modules/juce_gui_basics/components/juce_Component.cpp
  69. +11
    -0
      libs/juce/source/modules/juce_gui_basics/components/juce_ModalComponentManager.cpp
  70. +5
    -0
      libs/juce/source/modules/juce_gui_basics/components/juce_ModalComponentManager.h
  71. +5
    -0
      libs/juce/source/modules/juce_gui_basics/drawables/juce_SVGParser.cpp
  72. +1
    -1
      libs/juce/source/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.cpp
  73. +7
    -0
      libs/juce/source/modules/juce_gui_basics/filebrowser/juce_FilenameComponent.cpp
  74. +2
    -0
      libs/juce/source/modules/juce_gui_basics/filebrowser/juce_FilenameComponent.h
  75. +17
    -0
      libs/juce/source/modules/juce_gui_basics/keyboard/juce_TextInputTarget.h
  76. +6
    -9
      libs/juce/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp
  77. +2
    -2
      libs/juce/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V3.cpp
  78. +2
    -2
      libs/juce/source/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp
  79. +20
    -4
      libs/juce/source/modules/juce_gui_basics/native/juce_android_Windowing.cpp
  80. +23
    -6
      libs/juce/source/modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm
  81. +1
    -1
      libs/juce/source/modules/juce_gui_basics/native/juce_ios_Windowing.mm
  82. +5
    -3
      libs/juce/source/modules/juce_gui_basics/native/juce_linux_Windowing.cpp
  83. +2
    -3
      libs/juce/source/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm
  84. +10
    -5
      libs/juce/source/modules/juce_gui_basics/native/juce_win32_Windowing.cpp
  85. +1
    -1
      libs/juce/source/modules/juce_gui_basics/properties/juce_ChoicePropertyComponent.cpp
  86. +1
    -1
      libs/juce/source/modules/juce_gui_basics/properties/juce_ChoicePropertyComponent.h
  87. +12
    -7
      libs/juce/source/modules/juce_gui_basics/widgets/juce_ComboBox.cpp
  88. +2
    -0
      libs/juce/source/modules/juce_gui_basics/widgets/juce_ComboBox.h
  89. +13
    -8
      libs/juce/source/modules/juce_gui_basics/widgets/juce_Label.cpp
  90. +14
    -15
      libs/juce/source/modules/juce_gui_basics/widgets/juce_Label.h
  91. +1
    -1
      libs/juce/source/modules/juce_gui_basics/widgets/juce_TableHeaderComponent.cpp
  92. +1
    -1
      libs/juce/source/modules/juce_gui_basics/widgets/juce_TextEditor.cpp
  93. +3
    -0
      libs/juce/source/modules/juce_gui_basics/widgets/juce_TextEditor.h
  94. +1
    -1
      libs/juce/source/modules/juce_gui_basics/windows/juce_ComponentPeer.h
  95. +31
    -31
      libs/juce/source/modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp
  96. +1
    -1
      libs/juce/source/modules/juce_gui_basics/windows/juce_TopLevelWindow.h
  97. +1
    -1
      libs/juce/source/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp
  98. +1
    -1
      libs/juce/source/modules/juce_gui_extra/documents/juce_FileBasedDocument.cpp
  99. +1
    -1
      libs/juce/source/modules/juce_gui_extra/misc/juce_LiveConstantEditor.h

+ 1
- 1
libs/juce/source/modules/juce_audio_basics/effects/juce_Reverb.h View File

@@ -181,7 +181,7 @@ public:
for (int j = 0; j < numAllPasses; ++j) // run the allpass filters in series
output = allPass[0][j].process (output);
samples[i] = output * wet1 + input * dry;
samples[i] = output * wet1 + samples[i] * dry;
}
}


+ 13
- 12
libs/juce/source/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp View File

@@ -29,6 +29,7 @@ MidiMessageSequence::MidiMessageSequence()
MidiMessageSequence::MidiMessageSequence (const MidiMessageSequence& other)
{
list.addCopiesOf (other.list);
updateMatchedPairs();
}
MidiMessageSequence& MidiMessageSequence::operator= (const MidiMessageSequence& other)
@@ -52,17 +53,17 @@ void MidiMessageSequence::clear()
list.clear();
}
int MidiMessageSequence::getNumEvents() const
int MidiMessageSequence::getNumEvents() const noexcept
{
return list.size();
}
MidiMessageSequence::MidiEventHolder* MidiMessageSequence::getEventPointer (const int index) const
MidiMessageSequence::MidiEventHolder* MidiMessageSequence::getEventPointer (const int index) const noexcept
{
return list [index];
}
double MidiMessageSequence::getTimeOfMatchingKeyUp (const int index) const
double MidiMessageSequence::getTimeOfMatchingKeyUp (const int index) const noexcept
{
if (const MidiEventHolder* const meh = list [index])
if (meh->noteOffObject != nullptr)
@@ -71,7 +72,7 @@ double MidiMessageSequence::getTimeOfMatchingKeyUp (const int index) const
return 0.0;
}
int MidiMessageSequence::getIndexOfMatchingKeyUp (const int index) const
int MidiMessageSequence::getIndexOfMatchingKeyUp (const int index) const noexcept
{
if (const MidiEventHolder* const meh = list [index])
return list.indexOf (meh->noteOffObject);
@@ -79,12 +80,12 @@ int MidiMessageSequence::getIndexOfMatchingKeyUp (const int index) const
return -1;
}
int MidiMessageSequence::getIndexOf (MidiEventHolder* const event) const
int MidiMessageSequence::getIndexOf (MidiEventHolder* const event) const noexcept
{
return list.indexOf (event);
}
int MidiMessageSequence::getNextIndexAtTime (const double timeStamp) const
int MidiMessageSequence::getNextIndexAtTime (const double timeStamp) const noexcept
{
const int numEvents = list.size();
@@ -97,17 +98,17 @@ int MidiMessageSequence::getNextIndexAtTime (const double timeStamp) const
}
//==============================================================================
double MidiMessageSequence::getStartTime() const
double MidiMessageSequence::getStartTime() const noexcept
{
return getEventTime (0);
}
double MidiMessageSequence::getEndTime() const
double MidiMessageSequence::getEndTime() const noexcept
{
return getEventTime (list.size() - 1);
}
double MidiMessageSequence::getEventTime (const int index) const
double MidiMessageSequence::getEventTime (const int index) const noexcept
{
if (const MidiEventHolder* const meh = list [index])
return meh->message.getTimeStamp();
@@ -181,13 +182,13 @@ void MidiMessageSequence::addSequence (const MidiMessageSequence& other,
}
//==============================================================================
void MidiMessageSequence::sort()
void MidiMessageSequence::sort() noexcept
{
MidiMessageSequenceSorter sorter;
list.sort (sorter, true);
}
void MidiMessageSequence::updateMatchedPairs()
void MidiMessageSequence::updateMatchedPairs() noexcept
{
for (int i = 0; i < list.size(); ++i)
{
@@ -226,7 +227,7 @@ void MidiMessageSequence::updateMatchedPairs()
}
}
void MidiMessageSequence::addTimeToMessages (const double delta)
void MidiMessageSequence::addTimeToMessages (const double delta) noexcept
{
for (int i = list.size(); --i >= 0;)
{


+ 12
- 12
libs/juce/source/modules/juce_audio_basics/midi/juce_MidiMessageSequence.h View File

@@ -91,47 +91,47 @@ public:
void clear();
/** Returns the number of events in the sequence. */
int getNumEvents() const;
int getNumEvents() const noexcept;
/** Returns a pointer to one of the events. */
MidiEventHolder* getEventPointer (int index) const;
MidiEventHolder* getEventPointer (int index) const noexcept;
/** Returns the time of the note-up that matches the note-on at this index.
If the event at this index isn't a note-on, it'll just return 0.
@see MidiMessageSequence::MidiEventHolder::noteOffObject
*/
double getTimeOfMatchingKeyUp (int index) const;
double getTimeOfMatchingKeyUp (int index) const noexcept;
/** Returns the index of the note-up that matches the note-on at this index.
If the event at this index isn't a note-on, it'll just return -1.
@see MidiMessageSequence::MidiEventHolder::noteOffObject
*/
int getIndexOfMatchingKeyUp (int index) const;
int getIndexOfMatchingKeyUp (int index) const noexcept;
/** Returns the index of an event. */
int getIndexOf (MidiEventHolder* event) const;
int getIndexOf (MidiEventHolder* event) const noexcept;
/** Returns the index of the first event on or after the given timestamp.
If the time is beyond the end of the sequence, this will return the
number of events.
*/
int getNextIndexAtTime (double timeStamp) const;
int getNextIndexAtTime (double timeStamp) const noexcept;
//==============================================================================
/** Returns the timestamp of the first event in the sequence.
@see getEndTime
*/
double getStartTime() const;
double getStartTime() const noexcept;
/** Returns the timestamp of the last event in the sequence.
@see getStartTime
*/
double getEndTime() const;
double getEndTime() const noexcept;
/** Returns the timestamp of the event at a given index.
If the index is out-of-range, this will return 0.0
*/
double getEventTime (int index) const;
double getEventTime (int index) const noexcept;
//==============================================================================
/** Inserts a midi message into the sequence.
@@ -185,13 +185,13 @@ public:
will scan the list and make sure all the note-offs in the MidiEventHolder
structures are pointing at the correct ones.
*/
void updateMatchedPairs();
void updateMatchedPairs() noexcept;
/** Forces a sort of the sequence.
You may need to call this if you've manually modified the timestamps of some
events such that the overall order now needs updating.
*/
void sort();
void sort() noexcept;
//==============================================================================
/** Copies all the messages for a particular midi channel to another sequence.
@@ -224,7 +224,7 @@ public:
/** Adds an offset to the timestamps of all events in the sequence.
@param deltaTime the amount to add to each timestamp.
*/
void addTimeToMessages (double deltaTime);
void addTimeToMessages (double deltaTime) noexcept;
//==============================================================================
/** Scans through the sequence to determine the state of any midi controllers at


+ 12
- 10
libs/juce/source/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp View File

@@ -859,8 +859,11 @@ void AudioDeviceManager::addMidiInputCallback (const String& name, MidiInputCall
if (name.isEmpty() || isMidiInputEnabled (name))
{
const ScopedLock sl (midiCallbackLock);
midiCallbacks.add (callbackToAdd);
midiCallbackDevices.add (name);
MidiCallbackInfo mc;
mc.deviceName = name;
mc.callback = callbackToAdd;
midiCallbacks.add (mc);
}
}
@@ -868,11 +871,12 @@ void AudioDeviceManager::removeMidiInputCallback (const String& name, MidiInputC
{
for (int i = midiCallbacks.size(); --i >= 0;)
{
if (midiCallbackDevices[i] == name && midiCallbacks.getUnchecked(i) == callbackToRemove)
const MidiCallbackInfo& mc = midiCallbacks.getReference(i);
if (mc.callback == callbackToRemove && mc.deviceName == name)
{
const ScopedLock sl (midiCallbackLock);
midiCallbacks.remove (i);
midiCallbackDevices.remove (i);
}
}
}
@@ -881,16 +885,14 @@ void AudioDeviceManager::handleIncomingMidiMessageInt (MidiInput* source, const
{
if (! message.isActiveSense())
{
const bool isDefaultSource = (source == nullptr || source == enabledMidiInputs.getFirst());
const ScopedLock sl (midiCallbackLock);
for (int i = midiCallbackDevices.size(); --i >= 0;)
for (int i = 0; i < midiCallbacks.size(); ++i)
{
const String name (midiCallbackDevices[i]);
const MidiCallbackInfo& mc = midiCallbacks.getReference(i);
if ((isDefaultSource && name.isEmpty()) || (name.isNotEmpty() && name == source->getName()))
midiCallbacks.getUnchecked(i)->handleIncomingMidiMessage (source, message);
if (mc.deviceName.isEmpty() || mc.deviceName == source->getName())
mc.callback->handleIncomingMidiMessage (source, message);
}
}
}


+ 19
- 24
libs/juce/source/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h View File

@@ -209,10 +209,9 @@ public:
//==============================================================================
/** Returns the current device properties that are in use.
@see setAudioDeviceSetup
*/
void getAudioDeviceSetup (AudioDeviceSetup& setup);
void getAudioDeviceSetup (AudioDeviceSetup& result);
/** Changes the current device or its settings.
@@ -261,9 +260,7 @@ public:
void setCurrentAudioDeviceType (const String& type,
bool treatAsChosenDevice);
/** Closes the currently-open device.
You can call restartLastAudioDevice() later to reopen it in the same state
that it was just in.
*/
@@ -305,8 +302,8 @@ public:
//==============================================================================
/** Returns the average proportion of available CPU being spent inside the audio callbacks.
Returns a value between 0 and 1.0
@returns A value between 0 and 1.0 to indicate the approximate proportion of CPU
time spent in the callbacks.
*/
double getCpuUsage() const;
@@ -333,16 +330,16 @@ public:
void setMidiInputEnabled (const String& midiInputDeviceName, bool enabled);
/** Returns true if a given midi input device is being used.
@see setMidiInputEnabled
*/
bool isMidiInputEnabled (const String& midiInputDeviceName) const;
/** Registers a listener for callbacks when midi events arrive from a midi input.
The device name can be empty to indicate that it wants events from whatever the
current "default" device is. Or it can be the name of one of the midi input devices
(see MidiInput::getDevices() for the names).
The device name can be empty to indicate that it wants to receive all incoming
events from all the enabled MIDI inputs. Or it can be the name of one of the
MIDI input devices if it just wants the events from that device. (see
MidiInput::getDevices() for the list of device names).
Only devices which are enabled (see the setMidiInputEnabled() method) will have their
events forwarded on to listeners.
@@ -350,8 +347,7 @@ public:
void addMidiInputCallback (const String& midiInputDeviceName,
MidiInputCallback* callback);
/** Removes a listener that was previously registered with addMidiInputCallback().
*/
/** Removes a listener that was previously registered with addMidiInputCallback(). */
void removeMidiInputCallback (const String& midiInputDeviceName,
MidiInputCallback* callback);
@@ -371,22 +367,17 @@ public:
void setDefaultMidiOutput (const String& deviceName);
/** Returns the name of the default midi output.
@see setDefaultMidiOutput, getDefaultMidiOutput
*/
String getDefaultMidiOutputName() const { return defaultMidiOutputName; }
const String& getDefaultMidiOutputName() const noexcept { return defaultMidiOutputName; }
/** Returns the current default midi output device.
If no device has been selected, or the device can't be opened, this will
return 0.
If no device has been selected, or the device can't be opened, this will return nullptr.
@see getDefaultMidiOutputName
*/
MidiOutput* getDefaultMidiOutput() const noexcept { return defaultMidiOutput; }
/** Returns a list of the types of device supported.
*/
/** Returns a list of the types of device supported. */
const OwnedArray<AudioIODeviceType>& getAvailableDeviceTypes();
//==============================================================================
@@ -429,9 +420,7 @@ public:
void enableInputLevelMeasurement (bool enableMeasurement);
/** Returns the current input level.
To use this, you must first enable it by calling enableInputLevelMeasurement().
See enableInputLevelMeasurement() for more info.
*/
double getCurrentInputLevel() const;
@@ -468,10 +457,16 @@ private:
int testSoundPosition;
AudioSampleBuffer tempBuffer;
struct MidiCallbackInfo
{
String deviceName;
MidiInputCallback* callback;
};
StringArray midiInsFromXml;
OwnedArray<MidiInput> enabledMidiInputs;
Array<MidiInputCallback*> midiCallbacks;
StringArray midiCallbackDevices;
Array<MidiCallbackInfo> midiCallbacks;
String defaultMidiOutputName;
ScopedPointer<MidiOutput> defaultMidiOutput;
CriticalSection audioCallbackLock, midiCallbackLock;


+ 6
- 13
libs/juce/source/modules/juce_audio_devices/audio_io/juce_AudioIODevice.cpp View File

@@ -22,20 +22,16 @@
==============================================================================
*/
AudioIODevice::AudioIODevice (const String& deviceName, const String& typeName_)
: name (deviceName),
typeName (typeName_)
AudioIODevice::AudioIODevice (const String& deviceName, const String& deviceTypeName)
: name (deviceName), typeName (deviceTypeName)
{
}
AudioIODevice::~AudioIODevice()
{
}
AudioIODevice::~AudioIODevice() {}
bool AudioIODevice::hasControlPanel() const
{
return false;
}
void AudioIODeviceCallback::audioDeviceError (const String&) {}
bool AudioIODevice::setAudioPreprocessingEnabled (bool) { return false; }
bool AudioIODevice::hasControlPanel() const { return false; }
bool AudioIODevice::showControlPanel()
{
@@ -43,6 +39,3 @@ bool AudioIODevice::showControlPanel()
// their hasControlPanel() method.
return false;
}
//==============================================================================
void AudioIODeviceCallback::audioDeviceError (const String&) {}

+ 5
- 0
libs/juce/source/modules/juce_audio_devices/audio_io/juce_AudioIODevice.h View File

@@ -289,6 +289,11 @@ public:
*/
virtual bool showControlPanel();
/** On devices which support it, this allows automatic gain control or other
mic processing to be disabled.
If the device doesn't support this operation, it'll return false.
*/
virtual bool setAudioPreprocessingEnabled (bool shouldBeEnabled);
//==============================================================================
protected:


+ 1
- 1
libs/juce/source/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h View File

@@ -34,7 +34,7 @@
method. Each of the objects returned can then be used to list the available
devices of that type. E.g.
@code
OwnedArray <AudioIODeviceType> types;
OwnedArray<AudioIODeviceType> types;
myAudioDeviceManager.createAudioDeviceTypes (types);
for (int i = 0; i < types.size(); ++i)


+ 1
- 0
libs/juce/source/modules/juce_audio_devices/juce_audio_devices.cpp View File

@@ -125,6 +125,7 @@
#if JUCE_USE_ANDROID_OPENSLES
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#include <SLES/OpenSLES_AndroidConfiguration.h>
#endif
#endif


+ 43
- 24
libs/juce/source/modules/juce_audio_devices/native/juce_android_OpenSL.cpp View File

@@ -80,7 +80,7 @@ public:
Array<double> getAvailableSampleRates() override
{
static const double rates[] = { 8000.0, 16000.0, 32000.0, 44100.0, 48000.0 };
static const double rates[] = { 8000.0, 16000.0, 32000.0, 44100.0, 48000.0 };
return Array<double> (rates, numElementsInArray (rates));
}
@@ -165,29 +165,9 @@ public:
oldCallback->audioDeviceStopped();
}
void run() override
bool setAudioPreprocessingEnabled (bool enable) override
{
if (recorder != nullptr) recorder->start();
if (player != nullptr) player->start();
while (! threadShouldExit())
{
if (player != nullptr) player->writeBuffer (outputBuffer, *this);
if (recorder != nullptr) recorder->readNextBlock (inputBuffer, *this);
const ScopedLock sl (callbackLock);
if (callback != nullptr)
{
callback->audioDeviceIOCallback (numInputChannels > 0 ? inputBuffer.getArrayOfReadPointers() : nullptr, numInputChannels,
numOutputChannels > 0 ? outputBuffer.getArrayOfWritePointers() : nullptr, numOutputChannels,
actualBufferSize);
}
else
{
outputBuffer.clear();
}
}
return recorder != nullptr && recorder->setAudioPreprocessingEnabled (enable);
}
private:
@@ -212,6 +192,31 @@ private:
return oldCallback;
}
void run() override
{
if (recorder != nullptr) recorder->start();
if (player != nullptr) player->start();
while (! threadShouldExit())
{
if (player != nullptr) player->writeBuffer (outputBuffer, *this);
if (recorder != nullptr) recorder->readNextBlock (inputBuffer, *this);
const ScopedLock sl (callbackLock);
if (callback != nullptr)
{
callback->audioDeviceIOCallback (numInputChannels > 0 ? inputBuffer.getArrayOfReadPointers() : nullptr, numInputChannels,
numOutputChannels > 0 ? outputBuffer.getArrayOfWritePointers() : nullptr, numOutputChannels,
actualBufferSize);
}
else
{
outputBuffer.clear();
}
}
}
//==================================================================================================
struct Engine
{
@@ -230,6 +235,7 @@ private:
SL_IID_ANDROIDSIMPLEBUFFERQUEUE = (SLInterfaceID*) library.getFunction ("SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
SL_IID_PLAY = (SLInterfaceID*) library.getFunction ("SL_IID_PLAY");
SL_IID_RECORD = (SLInterfaceID*) library.getFunction ("SL_IID_RECORD");
SL_IID_ANDROIDCONFIGURATION = (SLInterfaceID*) library.getFunction ("SL_IID_ANDROIDCONFIGURATION");
check ((*engineObject)->Realize (engineObject, SL_BOOLEAN_FALSE));
check ((*engineObject)->GetInterface (engineObject, *SL_IID_ENGINE, &engineInterface));
@@ -271,6 +277,7 @@ private:
SLInterfaceID* SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
SLInterfaceID* SL_IID_PLAY;
SLInterfaceID* SL_IID_RECORD;
SLInterfaceID* SL_IID_ANDROIDCONFIGURATION;
private:
DynamicLibrary library;
@@ -434,7 +441,8 @@ private:
struct Recorder
{
Recorder (int numChannels, int sampleRate, Engine& engine)
: recorderObject (nullptr), recorderRecord (nullptr), recorderBufferQueue (nullptr),
: recorderObject (nullptr), recorderRecord (nullptr),
recorderBufferQueue (nullptr), configObject (nullptr),
bufferList (numChannels)
{
jassert (numChannels == 1); // STEREO doesn't always work!!
@@ -466,6 +474,7 @@ private:
{
check ((*recorderObject)->GetInterface (recorderObject, *engine.SL_IID_RECORD, &recorderRecord));
check ((*recorderObject)->GetInterface (recorderObject, *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &recorderBufferQueue));
check ((*recorderObject)->GetInterface (recorderObject, *engine.SL_IID_ANDROIDCONFIGURATION, &configObject));
check ((*recorderBufferQueue)->RegisterCallback (recorderBufferQueue, staticCallback, this));
check ((*recorderRecord)->SetRecordState (recorderRecord, SL_RECORDSTATE_STOPPED));
@@ -532,10 +541,20 @@ private:
}
}
bool setAudioPreprocessingEnabled (bool enable)
{
SLuint32 mode = enable ? SL_ANDROID_RECORDING_PRESET_GENERIC
: SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
return configObject != nullptr
&& check ((*configObject)->SetConfiguration (configObject, SL_ANDROID_KEY_RECORDING_PRESET, &mode, sizeof (mode)));
}
private:
SLObjectItf recorderObject;
SLRecordItf recorderRecord;
SLAndroidSimpleBufferQueueItf recorderBufferQueue;
SLAndroidConfigurationItf configObject;
BufferList bufferList;


+ 28
- 44
libs/juce/source/modules/juce_audio_devices/native/juce_ios_Audio.cpp View File

@@ -67,7 +67,12 @@ public:
return s;
}
Array<double> getAvailableSampleRates() override { return sampleRates; }
Array<double> getAvailableSampleRates() override
{
// can't find a good way to actually ask the device for which of these it supports..
static const double rates[] = { 8000.0, 16000.0, 22050.0, 32000.0, 44100.0, 48000.0 };
return Array<double> (rates, numElementsInArray (rates));
}
Array<int> getAvailableBufferSizes() override
{
@@ -79,7 +84,7 @@ public:
return r;
}
int getDefaultBufferSize() override { return 1024; }
int getDefaultBufferSize() override { return 1024; }
String open (const BigInteger& inputChannelsWanted,
const BigInteger& outputChannelsWanted,
@@ -117,10 +122,9 @@ public:
AudioSessionAddPropertyListener (kAudioSessionProperty_AudioRouteChange, routingChangedStatic, this);
fixAudioRouteIfSetToReceiver();
updateDeviceInfo();
setSessionFloat64Property (kAudioSessionProperty_PreferredHardwareSampleRate, targetSampleRate);
updateSampleRates();
updateDeviceInfo();
setSessionFloat32Property (kAudioSessionProperty_PreferredHardwareIOBufferDuration, preferredBufferSize / sampleRate);
updateCurrentBufferSize();
@@ -162,8 +166,15 @@ public:
BigInteger getActiveOutputChannels() const override { return activeOutputChans; }
BigInteger getActiveInputChannels() const override { return activeInputChans; }
int getOutputLatencyInSamples() override { return 0; } //xxx
int getInputLatencyInSamples() override { return 0; } //xxx
int getOutputLatencyInSamples() override { return getLatency (kAudioSessionProperty_CurrentHardwareOutputLatency); }
int getInputLatencyInSamples() override { return getLatency (kAudioSessionProperty_CurrentHardwareInputLatency); }
int getLatency (AudioSessionPropertyID propID)
{
Float32 latency = 0;
getSessionProperty (propID, latency);
return roundToInt (latency * getCurrentSampleRate());
}
void start (AudioIODeviceCallback* newCallback) override
{
@@ -197,11 +208,16 @@ public:
bool isPlaying() override { return isRunning && callback != nullptr; }
String getLastError() override { return lastError; }
bool setAudioPreprocessingEnabled (bool enable) override
{
return setSessionUInt32Property (kAudioSessionProperty_Mode, enable ? kAudioSessionMode_Default
: kAudioSessionMode_Measurement);
}
private:
//==================================================================================================
CriticalSection callbackLock;
Float64 sampleRate;
Array<Float64> sampleRates;
int numInputChannels, numOutputChannels;
int preferredBufferSize, actualBufferSize;
bool isRunning;
@@ -322,38 +338,6 @@ private:
getSessionProperty (kAudioSessionProperty_AudioInputAvailable, audioInputIsAvailable);
}
void updateSampleRates()
{
getSessionProperty (kAudioSessionProperty_CurrentHardwareSampleRate, sampleRate);
sampleRates.clear();
sampleRates.add (sampleRate);
const int commonSampleRates[] = { 8000, 16000, 22050, 32000, 44100, 48000 };
for (int i = 0; i < numElementsInArray (commonSampleRates); ++i)
{
Float64 rate = (Float64) commonSampleRates[i];
if (rate != sampleRate)
{
setSessionFloat64Property (kAudioSessionProperty_PreferredHardwareSampleRate, rate);
Float64 actualSampleRate = 0.0;
getSessionProperty (kAudioSessionProperty_CurrentHardwareSampleRate, actualSampleRate);
if (actualSampleRate == rate)
sampleRates.add (actualSampleRate);
}
}
DefaultElementComparator<Float64> comparator;
sampleRates.sort (comparator);
setSessionFloat64Property (kAudioSessionProperty_PreferredHardwareSampleRate, sampleRate);
getSessionProperty (kAudioSessionProperty_CurrentHardwareSampleRate, sampleRate);
}
void updateCurrentBufferSize()
{
Float32 bufferDuration = sampleRate > 0 ? (Float32) (preferredBufferSize / sampleRate) : 0.0f;
@@ -455,12 +439,12 @@ private:
static OSStatus processStatic (void* client, AudioUnitRenderActionFlags* flags, const AudioTimeStamp* time,
UInt32 /*busNumber*/, UInt32 numFrames, AudioBufferList* data)
{
return static_cast <iOSAudioIODevice*> (client)->process (flags, time, numFrames, data);
return static_cast<iOSAudioIODevice*> (client)->process (flags, time, numFrames, data);
}
static void routingChangedStatic (void* client, AudioSessionPropertyID, UInt32 /*inDataSize*/, const void* propertyValue)
{
static_cast <iOSAudioIODevice*> (client)->routingChanged (propertyValue);
static_cast<iOSAudioIODevice*> (client)->routingChanged (propertyValue);
}
//==================================================================================================
@@ -552,9 +536,9 @@ private:
return AudioSessionGetProperty (propID, &valueSize, &result);
}
static void setSessionUInt32Property (AudioSessionPropertyID propID, UInt32 v) noexcept { AudioSessionSetProperty (propID, sizeof (v), &v); }
static void setSessionFloat32Property (AudioSessionPropertyID propID, Float32 v) noexcept { AudioSessionSetProperty (propID, sizeof (v), &v); }
static void setSessionFloat64Property (AudioSessionPropertyID propID, Float64 v) noexcept { AudioSessionSetProperty (propID, sizeof (v), &v); }
static bool setSessionUInt32Property (AudioSessionPropertyID propID, UInt32 v) noexcept { AudioSessionSetProperty (propID, sizeof (v), &v) == kAudioSessionNoError; }
static bool setSessionFloat32Property (AudioSessionPropertyID propID, Float32 v) noexcept { AudioSessionSetProperty (propID, sizeof (v), &v) == kAudioSessionNoError; }
static bool setSessionFloat64Property (AudioSessionPropertyID propID, Float64 v) noexcept { AudioSessionSetProperty (propID, sizeof (v), &v) == kAudioSessionNoError; }
JUCE_DECLARE_NON_COPYABLE (iOSAudioIODevice)
};


+ 28
- 3
libs/juce/source/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp View File

@@ -144,6 +144,7 @@ public:
: owner (d),
inputLatency (0),
outputLatency (0),
bitDepth (32),
callback (nullptr),
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
audioProcID (0),
@@ -352,6 +353,22 @@ public:
return (int) lat;
}
int getBitDepthFromDevice (AudioObjectPropertyScope scope) const
{
AudioObjectPropertyAddress pa;
pa.mElement = kAudioObjectPropertyElementMaster;
pa.mSelector = kAudioStreamPropertyPhysicalFormat;
pa.mScope = scope;
AudioStreamBasicDescription asbd;
UInt32 size = sizeof (asbd);
if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, &asbd)))
return (int) asbd.mBitsPerChannel;
return 0;
}
void updateDetailsFromDevice()
{
stopTimer();
@@ -392,6 +409,13 @@ public:
StringArray newInNames (getChannelInfo (true, newInChans));
StringArray newOutNames (getChannelInfo (false, newOutChans));
const int inputBitDepth = getBitDepthFromDevice (kAudioDevicePropertyScopeInput);
const int outputBitDepth = getBitDepthFromDevice (kAudioDevicePropertyScopeOutput);
bitDepth = jmax (inputBitDepth, outputBitDepth);
if (bitDepth <= 0)
bitDepth = 32;
// after getting the new values, lock + apply them
const ScopedLock sl (callbackLock);
@@ -728,6 +752,7 @@ public:
//==============================================================================
CoreAudioIODevice& owner;
int inputLatency, outputLatency;
int bitDepth;
BigInteger activeInputChans, activeOutputChans;
StringArray inChanNames, outChanNames;
Array<double> sampleRates;
@@ -886,7 +911,7 @@ public:
Array<int> getAvailableBufferSizes() override { return internal->bufferSizes; }
double getCurrentSampleRate() override { return internal->getSampleRate(); }
int getCurrentBitDepth() override { return 32; } // no way to find out, so just assume it's high..
int getCurrentBitDepth() override { return internal->bitDepth; }
int getCurrentBufferSizeSamples() override { return internal->getBufferSize(); }
int getDefaultBufferSize() override
@@ -1387,7 +1412,7 @@ private:
d.done = (d.numInputChans == 0);
}
for (int tries = 3;;)
for (int tries = 5;;)
{
bool anyRemaining = false;
@@ -1434,7 +1459,7 @@ private:
d.done = (d.numOutputChans == 0);
}
for (int tries = 3;;)
for (int tries = 5;;)
{
bool anyRemaining = false;


+ 2
- 2
libs/juce/source/modules/juce_audio_formats/codecs/juce_AiffAudioFormat.cpp View File

@@ -888,13 +888,13 @@ AiffAudioFormat::~AiffAudioFormat()
Array<int> AiffAudioFormat::getPossibleSampleRates()
{
const int rates[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, 0 };
return Array <int> (rates);
return Array<int> (rates);
}
Array<int> AiffAudioFormat::getPossibleBitDepths()
{
const int depths[] = { 8, 16, 24, 0 };
return Array <int> (depths);
return Array<int> (depths);
}
bool AiffAudioFormat::canDoStereo() { return true; }


+ 250
- 172
libs/juce/source/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h View File

@@ -29,161 +29,77 @@ extern AudioProcessor* JUCE_CALLTYPE createPluginFilter();
//==============================================================================
/**
A class that can be used to run a simple standalone application containing your filter.
An object that creates and plays a standalone instance of an AudioProcessor.
Just create one of these objects in your JUCEApplicationBase::initialise() method, and
let it do its work. It will create your filter object using the same createPluginFilter() function
that the other plugin wrappers use.
The object will create your processor using the same createPluginFilter()
function that the other plugin wrappers use, and will run it through the
computer's audio/MIDI devices using AudioDeviceManager and AudioProcessorPlayer.
*/
class StandaloneFilterWindow : public DocumentWindow,
public ButtonListener // (can't use Button::Listener due to idiotic VC2005 bug)
class StandalonePluginHolder
{
public:
//==============================================================================
/** Creates a window with a given title and colour.
/** Creates an instance of the default plugin.
The settings object can be a PropertySet that the class should use to
store its settings - the object that is passed-in will be owned by this
class and deleted automatically when no longer needed. (It can also be null)
*/
StandaloneFilterWindow (const String& title,
Colour backgroundColour,
PropertySet* settingsToUse)
: DocumentWindow (title, backgroundColour, DocumentWindow::minimiseButton | DocumentWindow::closeButton),
settings (settingsToUse),
optionsButton ("options")
StandalonePluginHolder (PropertySet* settingsToUse)
: settings (settingsToUse)
{
setTitleBarButtonsRequired (DocumentWindow::minimiseButton | DocumentWindow::closeButton, false);
Component::addAndMakeVisible (optionsButton);
optionsButton.addListener (this);
optionsButton.setTriggeredOnMouseDown (true);
createFilter();
if (filter == nullptr)
{
jassertfalse // Your filter didn't create correctly! In a standalone app that's not too great.
JUCEApplicationBase::quit();
}
filter->setPlayConfigDetails (JucePlugin_MaxNumInputChannels,
JucePlugin_MaxNumOutputChannels,
44100, 512);
deviceManager = new AudioDeviceManager();
deviceManager->addAudioCallback (&player);
deviceManager->addMidiInputCallback (String::empty, &player);
player.setProcessor (filter);
ScopedPointer<XmlElement> savedState;
if (settings != nullptr)
savedState = settings->getXmlValue ("audioSetup");
deviceManager->initialise (filter->getNumInputChannels(),
filter->getNumOutputChannels(),
savedState,
true);
if (settings != nullptr)
{
MemoryBlock data;
if (data.fromBase64Encoding (settings->getValue ("filterState"))
&& data.getSize() > 0)
{
filter->setStateInformation (data.getData(), (int) data.getSize());
}
}
setContentOwned (filter->createEditorIfNeeded(), true);
if (settings != nullptr)
{
const int x = settings->getIntValue ("windowX", -100);
const int y = settings->getIntValue ("windowY", -100);
if (x != -100 && y != -100)
setBoundsConstrained (juce::Rectangle<int> (x, y, getWidth(), getHeight()));
else
centreWithSize (getWidth(), getHeight());
}
else
{
centreWithSize (getWidth(), getHeight());
}
createPlugin();
setupAudioDevices();
reloadPluginState();
startPlaying();
}
~StandaloneFilterWindow()
~StandalonePluginHolder()
{
if (settings != nullptr)
{
settings->setValue ("windowX", getX());
settings->setValue ("windowY", getY());
if (deviceManager != nullptr)
{
ScopedPointer<XmlElement> xml (deviceManager->createStateXml());
settings->setValue ("audioSetup", xml);
}
}
deviceManager->removeMidiInputCallback (String::empty, &player);
deviceManager->removeAudioCallback (&player);
deviceManager = nullptr;
if (settings != nullptr && filter != nullptr)
{
MemoryBlock data;
filter->getStateInformation (data);
settings->setValue ("filterState", data.toBase64Encoding());
}
deleteFilter();
deletePlugin();
shutDownAudioDevices();
}
//==============================================================================
AudioProcessor* getAudioProcessor() const noexcept { return filter; }
AudioDeviceManager* getDeviceManager() const noexcept { return deviceManager; }
void createFilter()
void createPlugin()
{
AudioProcessor::setTypeOfNextNewPlugin (AudioProcessor::wrapperType_Standalone);
filter = createPluginFilter();
processor = createPluginFilter();
jassert (processor != nullptr); // Your createPluginFilter() function must return a valid object!
AudioProcessor::setTypeOfNextNewPlugin (AudioProcessor::wrapperType_Undefined);
processor->setPlayConfigDetails (JucePlugin_MaxNumInputChannels,
JucePlugin_MaxNumOutputChannels,
44100, 512);
}
/** Deletes and re-creates the filter and its UI. */
void resetFilter()
void deletePlugin()
{
deleteFilter();
createFilter();
if (filter != nullptr)
{
if (deviceManager != nullptr)
player.setProcessor (filter);
stopPlaying();
processor = nullptr;
}
setContentOwned (filter->createEditorIfNeeded(), true);
}
static String getFilePatterns (const String& fileSuffix)
{
if (fileSuffix.isEmpty())
return String();
if (settings != nullptr)
settings->removeValue ("filterState");
return (fileSuffix.startsWithChar ('.') ? "*" : "*.") + fileSuffix;
}
/** Pops up a dialog letting the user save the filter's state to a file. */
void saveState()
//==============================================================================
/** Pops up a dialog letting the user save the processor's state to a file. */
void askUserToSaveState (const String& fileSuffix = String())
{
FileChooser fc (TRANS("Save current state"),
settings != nullptr ? File (settings->getValue ("lastStateFile"))
: File::nonexistent);
: File::getSpecialLocation (File::userDocumentsDirectory),
getFilePatterns (fileSuffix));
if (fc.browseForFileToSave (true))
{
MemoryBlock data;
filter->getStateInformation (data);
processor->getStateInformation (data);
if (! fc.getResult().replaceWithData (data.getData(), data.getSize()))
{
@@ -194,12 +110,13 @@ public:
}
}
/** Pops up a dialog letting the user re-load the filter's state from a file. */
void loadState()
/** Pops up a dialog letting the user re-load the processor's state from a file. */
void askUserToLoadState (const String& fileSuffix = String())
{
FileChooser fc (TRANS("Load a saved state"),
settings != nullptr ? File (settings->getValue ("lastStateFile"))
: File::nonexistent);
: File::getSpecialLocation (File::userDocumentsDirectory),
getFilePatterns (fileSuffix));
if (fc.browseForFileToOpen())
{
@@ -207,7 +124,7 @@ public:
if (fc.getResult().loadFileAsData (data))
{
filter->setStateInformation (data.getData(), (int) data.getSize());
processor->setStateInformation (data.getData(), (int) data.getSize());
}
else
{
@@ -218,20 +135,33 @@ public:
}
}
/** Shows the audio properties dialog box modally. */
virtual void showAudioSettingsDialog()
//==============================================================================
void startPlaying()
{
player.setProcessor (processor);
}
void stopPlaying()
{
player.setProcessor (nullptr);
}
//==============================================================================
/** Shows an audio properties dialog box modally. */
void showAudioSettingsDialog()
{
DialogWindow::LaunchOptions o;
o.content.setOwned (new AudioDeviceSelectorComponent (*deviceManager,
filter->getNumInputChannels(),
filter->getNumInputChannels(),
filter->getNumOutputChannels(),
filter->getNumOutputChannels(),
true, false, true, false));
o.content.setOwned (new AudioDeviceSelectorComponent (deviceManager,
processor->getNumInputChannels(),
processor->getNumInputChannels(),
processor->getNumOutputChannels(),
processor->getNumOutputChannels(),
true, false,
true, false));
o.content->setSize (500, 450);
o.dialogTitle = TRANS("Audio Settings");
o.dialogBackgroundColour = Colours::lightgrey;
o.dialogBackgroundColour = Colour (0xfff0f0f0);
o.escapeKeyTriggersCloseButton = true;
o.useNativeTitleBar = true;
o.resizable = false;
@@ -239,66 +169,214 @@ public:
o.launchAsync();
}
//==============================================================================
/** @internal */
void closeButtonPressed() override
void saveAudioDeviceState()
{
JUCEApplicationBase::quit();
if (settings != nullptr)
{
ScopedPointer<XmlElement> xml (deviceManager.createStateXml());
settings->setValue ("audioSetup", xml);
}
}
/** @internal */
void buttonClicked (Button*) override
void reloadAudioDeviceState()
{
if (filter != nullptr)
ScopedPointer<XmlElement> savedState;
if (settings != nullptr)
savedState = settings->getXmlValue ("audioSetup");
deviceManager.initialise (processor->getNumInputChannels(),
processor->getNumOutputChannels(),
savedState,
true);
}
//==============================================================================
void savePluginState()
{
if (settings != nullptr && processor != nullptr)
{
PopupMenu m;
m.addItem (1, TRANS("Audio Settings..."));
m.addSeparator();
m.addItem (2, TRANS("Save current state..."));
m.addItem (3, TRANS("Load a saved state..."));
m.addSeparator();
m.addItem (4, TRANS("Reset to default state"));
switch (m.showAt (&optionsButton))
{
case 1: showAudioSettingsDialog(); break;
case 2: saveState(); break;
case 3: loadState(); break;
case 4: resetFilter(); break;
default: break;
}
MemoryBlock data;
processor->getStateInformation (data);
settings->setValue ("filterState", data.toBase64Encoding());
}
}
/** @internal */
void resized() override
void reloadPluginState()
{
DocumentWindow::resized();
optionsButton.setBounds (8, 6, 60, getTitleBarHeight() - 8);
if (settings != nullptr)
{
MemoryBlock data;
if (data.fromBase64Encoding (settings->getValue ("filterState")) && data.getSize() > 0)
processor->setStateInformation (data.getData(), (int) data.getSize());
}
}
private:
//==============================================================================
ScopedPointer<PropertySet> settings;
ScopedPointer<AudioProcessor> filter;
ScopedPointer<AudioDeviceManager> deviceManager;
ScopedPointer<AudioProcessor> processor;
AudioDeviceManager deviceManager;
AudioProcessorPlayer player;
TextButton optionsButton;
void deleteFilter()
private:
void setupAudioDevices()
{
player.setProcessor (nullptr);
deviceManager.addAudioCallback (&player);
deviceManager.addMidiInputCallback (String::empty, &player);
reloadAudioDeviceState();
}
void shutDownAudioDevices()
{
saveAudioDeviceState();
deviceManager.removeMidiInputCallback (String::empty, &player);
deviceManager.removeAudioCallback (&player);
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StandalonePluginHolder)
};
//==============================================================================
/**
A class that can be used to run a simple standalone application containing your filter.
Just create one of these objects in your JUCEApplicationBase::initialise() method, and
let it do its work. It will create your filter object using the same createPluginFilter() function
that the other plugin wrappers use.
*/
class StandaloneFilterWindow : public DocumentWindow,
public ButtonListener // (can't use Button::Listener due to VC2005 bug)
{
public:
//==============================================================================
/** Creates a window with a given title and colour.
The settings object can be a PropertySet that the class should use to
store its settings - the object that is passed-in will be owned by this
class and deleted automatically when no longer needed. (It can also be null)
*/
StandaloneFilterWindow (const String& title,
Colour backgroundColour,
PropertySet* settingsToUse)
: DocumentWindow (title, backgroundColour, DocumentWindow::minimiseButton | DocumentWindow::closeButton),
optionsButton ("options")
{
setTitleBarButtonsRequired (DocumentWindow::minimiseButton | DocumentWindow::closeButton, false);
if (filter != nullptr && getContentComponent() != nullptr)
Component::addAndMakeVisible (optionsButton);
optionsButton.addListener (this);
optionsButton.setTriggeredOnMouseDown (true);
pluginHolder = new StandalonePluginHolder (settingsToUse);
createEditorComp();
if (PropertySet* props = pluginHolder->settings)
{
filter->editorBeingDeleted (dynamic_cast <AudioProcessorEditor*> (getContentComponent()));
const int x = props->getIntValue ("windowX", -100);
const int y = props->getIntValue ("windowY", -100);
if (x != -100 && y != -100)
setBoundsConstrained (juce::Rectangle<int> (x, y, getWidth(), getHeight()));
else
centreWithSize (getWidth(), getHeight());
}
else
{
centreWithSize (getWidth(), getHeight());
}
}
~StandaloneFilterWindow()
{
if (PropertySet* props = pluginHolder->settings)
{
props->setValue ("windowX", getX());
props->setValue ("windowY", getY());
}
pluginHolder->stopPlaying();
deleteEditorComp();
pluginHolder = nullptr;
}
//==============================================================================
AudioProcessor* getAudioProcessor() const noexcept { return pluginHolder->processor; }
AudioDeviceManager& getDeviceManager() const noexcept { return pluginHolder->deviceManager; }
void createEditorComp()
{
setContentOwned (getAudioProcessor()->createEditorIfNeeded(), true);
}
void deleteEditorComp()
{
if (AudioProcessorEditor* ed = dynamic_cast<AudioProcessorEditor*> (getContentComponent()))
{
pluginHolder->processor->editorBeingDeleted (ed);
clearContentComponent();
}
}
filter = nullptr;
/** Deletes and re-creates the plugin, resetting it to its default state. */
void resetToDefaultState()
{
pluginHolder->stopPlaying();
deleteEditorComp();
pluginHolder->deletePlugin();
if (PropertySet* props = pluginHolder->settings)
props->removeValue ("filterState");
pluginHolder->createPlugin();
createEditorComp();
pluginHolder->startPlaying();
}
//==============================================================================
void closeButtonPressed() override
{
JUCEApplicationBase::quit();
}
void buttonClicked (Button*) override
{
PopupMenu m;
m.addItem (1, TRANS("Audio Settings..."));
m.addSeparator();
m.addItem (2, TRANS("Save current state..."));
m.addItem (3, TRANS("Load a saved state..."));
m.addSeparator();
m.addItem (4, TRANS("Reset to default state"));
switch (m.showAt (&optionsButton))
{
case 1: pluginHolder->showAudioSettingsDialog(); break;
case 2: pluginHolder->askUserToSaveState(); break;
case 3: pluginHolder->askUserToLoadState(); break;
case 4: resetToDefaultState(); break;
default: break;
}
}
void resized() override
{
DocumentWindow::resized();
optionsButton.setBounds (8, 6, 60, getTitleBarHeight() - 8);
}
ScopedPointer<StandalonePluginHolder> pluginHolder;
private:
//==============================================================================
TextButton optionsButton;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StandaloneFilterWindow)
};
#endif // JUCE_STANDALONEFILTERWINDOW_H_INCLUDED

+ 2
- 1
libs/juce/source/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp View File

@@ -1052,7 +1052,8 @@ public:
Timer::callPendingTimersSynchronously();
for (int i = ComponentPeer::getNumPeers(); --i >= 0;)
ComponentPeer::getPeer (i)->performAnyPendingRepaintsNow();
if (ComponentPeer* p = ComponentPeer::getPeer(i))
p->performAnyPendingRepaintsNow();
recursionCheck = false;
}


+ 73
- 59
libs/juce/source/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp View File

@@ -279,9 +279,9 @@ public:
}
//==============================================================================
void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int index) override { beginEdit ((Steinberg::uint32) index); }
void audioProcessorParameterChanged (AudioProcessor*, int index, float newValue) override { performEdit ((Steinberg::uint32) index, (double) newValue); }
void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int index) override { endEdit ((Steinberg::uint32) index); }
void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int index) override { beginEdit ((Vst::ParamID) index); }
void audioProcessorParameterChanged (AudioProcessor*, int index, float newValue) override { performEdit ((Vst::ParamID) index, (double) newValue); }
void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int index) override { endEdit ((Vst::ParamID) index); }
void audioProcessorChanged (AudioProcessor*) override
{
@@ -788,60 +788,66 @@ public:
(int) htonl (bank->content.data.size)));
}
void loadVST3PresetFile (const char* data, int size)
bool loadVST3PresetFile (const char* data, int size)
{
// At offset 4 there's a little-endian version number which seems to typically be 1
// At offset 8 there's 32 bytes the SDK calls "ASCII-encoded class id"
const int chunkListOffset = (int) ByteOrder::littleEndianInt (data + 40);
const char* const chunkList = data + chunkListOffset;
jassert (memcmp (chunkList, "List", 4) == 0);
const int entryCount = (int) ByteOrder::littleEndianInt (chunkList + 4);
jassert (entryCount > 0);
if (size < 48)
return false;
for (int i = 0; i < entryCount; ++i)
{
const char* const entry = chunkList + 8 + 20 * i;
// At offset 4 there's a little-endian version number which seems to typically be 1
// At offset 8 there's 32 bytes the SDK calls "ASCII-encoded class id"
const int chunkListOffset = (int) ByteOrder::littleEndianInt (data + 40);
jassert (memcmp (data + chunkListOffset, "List", 4) == 0);
const int entryCount = (int) ByteOrder::littleEndianInt (data + chunkListOffset + 4);
jassert (entryCount > 0);
if (memcmp (entry, "Comp", 4) == 0)
{
// "Comp" entries seem to contain the data.
juce::uint64 chunkOffset = ByteOrder::littleEndianInt64 (entry + 4);
juce::uint64 chunkSize = ByteOrder::littleEndianInt64 (entry + 12);
for (int i = 0; i < entryCount; ++i)
{
const int entryOffset = chunkListOffset + 8 + 20 * i;
#if JUCE_32BIT
jassert (chunkOffset <= (juce::uint64) 0xffffffff);
#endif
jassert (chunkSize <= 0x7fffffff);
if (entryOffset + 20 > size)
return false;
loadVST2VstWBlock (data + chunkOffset, (int) chunkSize);
}
}
}
if (memcmp (data + entryOffset, "Comp", 4) == 0)
{
// "Comp" entries seem to contain the data.
juce::uint64 chunkOffset = ByteOrder::littleEndianInt64 (data + entryOffset + 4);
juce::uint64 chunkSize = ByteOrder::littleEndianInt64 (data + entryOffset + 12);
bool loadVST2CompatibleState (const char* data, int size)
{
if (size < 4)
return false;
if ('VstW' == htonl (*(juce::int32*) data))
{
loadVST2VstWBlock (data, size);
return true;
}
if (memcmp (data, "VST3", 4) == 0)
{
// In Cubase 5, when loading VST3 .vstpreset files,
// we get the whole content of the files to load.
// In Cubase 7 we get just the contents within and
// we go directly to the loadVST2VstW codepath instead.
loadVST3PresetFile (data, size);
return true;
}
return false;
}
if (chunkOffset + chunkSize > size)
{
jassertfalse;
return false;
}
loadVST2VstWBlock (data + chunkOffset, (int) chunkSize);
}
}
return true;
}
bool loadVST2CompatibleState (const char* data, int size)
{
if (size < 4)
return false;
if (htonl (*(juce::int32*) data) == 'VstW')
{
loadVST2VstWBlock (data, size);
return true;
}
if (memcmp (data, "VST3", 4) == 0)
{
// In Cubase 5, when loading VST3 .vstpreset files,
// we get the whole content of the files to load.
// In Cubase 7 we get just the contents within and
// we go directly to the loadVST2VstW codepath instead.
return loadVST3PresetFile (data, size);
}
return false;
}
#endif
bool loadStateData (const void* data, int size)
@@ -885,14 +891,12 @@ public:
for (;;)
{
Steinberg::int32 bytesRead = 0;
const Steinberg::tresult status = state->read (buffer, (Steinberg::int32) bytesPerBlock, &bytesRead);
if (state->read (buffer, (Steinberg::int32) bytesPerBlock, &bytesRead) == kResultTrue && bytesRead > 0)
{
allData.write (buffer, bytesRead);
continue;
}
if (bytesRead <= 0 || (status != kResultTrue && ! getHostType().isWavelab()))
break;
break;
allData.write (buffer, bytesRead);
}
}
@@ -1099,10 +1103,12 @@ public:
Steinberg::int32 counter = 0;
FOREACH_CAST (IPtr<Vst::Bus>, Vst::AudioBus, bus, list)
{
if (counter < numBusses)
bus->setArrangement (arrangement[counter]);
counter++;
}
ENDFOR
return kResultTrue;
@@ -1114,6 +1120,8 @@ public:
tresult PLUGIN_API setBusArrangements (Vst::SpeakerArrangement* inputs, Steinberg::int32 numIns,
Vst::SpeakerArrangement* outputs, Steinberg::int32 numOuts) override
{
(void) inputs; (void) outputs;
#if JucePlugin_MaxNumInputChannels > 0
if (setBusArrangementFor (audioInputs, inputs, numIns) != kResultTrue)
return kResultFalse;
@@ -1238,8 +1246,8 @@ public:
const int numMidiEventsComingIn = midiBuffer.getNumEvents();
#endif
const int numInputChans = data.inputs != nullptr ? (int) data.inputs[0].numChannels : 0;
const int numOutputChans = data.outputs != nullptr ? (int) data.outputs[0].numChannels : 0;
const int numInputChans = (data.inputs != nullptr && data.inputs[0].channelBuffers32 != nullptr) ? (int) data.inputs[0].numChannels : 0;
const int numOutputChans = (data.outputs != nullptr && data.outputs[0].channelBuffers32 != nullptr) ? (int) data.outputs[0].numChannels : 0;
int totalChans = 0;
@@ -1255,7 +1263,13 @@ public:
++totalChans;
}
AudioSampleBuffer buffer (channelList.getRawDataPointer(), totalChans, (int) data.numSamples);
AudioSampleBuffer buffer;
if (totalChans != 0)
buffer.setDataToReferTo (channelList.getRawDataPointer(), totalChans, (int) data.numSamples);
else if (getHostType().isWavelab()
&& pluginInstance->getNumInputChannels() + pluginInstance->getNumOutputChannels() > 0)
return kResultFalse;
{
const ScopedLock sl (pluginInstance->getCallbackLock());


+ 1
- 1
libs/juce/source/modules/juce_audio_processors/format/juce_AudioPluginFormat.h View File

@@ -54,7 +54,7 @@ public:
(e.g. VST shells) can use a single DLL to create a set of different plugin
subtypes, so in that case, each subtype is returned as a separate object.
*/
virtual void findAllTypesForFile (OwnedArray <PluginDescription>& results,
virtual void findAllTypesForFile (OwnedArray<PluginDescription>& results,
const String& fileOrIdentifier) = 0;
/** Tries to recreate a type from a previously generated PluginDescription.


+ 1
- 1
libs/juce/source/modules/juce_audio_processors/format/juce_AudioPluginFormatManager.h View File

@@ -89,7 +89,7 @@ public:
private:
//==============================================================================
OwnedArray <AudioPluginFormat> formats;
OwnedArray<AudioPluginFormat> formats;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginFormatManager)
};


+ 1
- 1
libs/juce/source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.h View File

@@ -37,7 +37,7 @@ public:
//==============================================================================
String getName() const override { return "AudioUnit"; }
void findAllTypesForFile (OwnedArray <PluginDescription>&, const String& fileOrIdentifier) override;
void findAllTypesForFile (OwnedArray<PluginDescription>&, const String& fileOrIdentifier) override;
AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc, double, int) override;
bool fileMightContainThisPluginType (const String& fileOrIdentifier) override;
String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) override;


+ 3
- 3
libs/juce/source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm View File

@@ -138,7 +138,7 @@ namespace AudioUnitFormatHelpers
fileOrIdentifier.lastIndexOfChar ('/')) + 1));
StringArray tokens;
tokens.addTokens (s, ",", String());
tokens.addTokens (s, ",", StringRef());
tokens.removeEmptyStrings();
if (tokens.size() == 3)
@@ -915,7 +915,7 @@ private:
bool automatable;
};
OwnedArray <ParamInfo> parameters;
OwnedArray<ParamInfo> parameters;
MidiDataConcatenator midiConcatenator;
CriticalSection midiInLock;
@@ -1600,7 +1600,7 @@ AudioUnitPluginFormat::~AudioUnitPluginFormat()
{
}
void AudioUnitPluginFormat::findAllTypesForFile (OwnedArray <PluginDescription>& results,
void AudioUnitPluginFormat::findAllTypesForFile (OwnedArray<PluginDescription>& results,
const String& fileOrIdentifier)
{
if (! fileMightContainThisPluginType (fileOrIdentifier))


+ 54
- 27
libs/juce/source/modules/juce_audio_processors/format_types/juce_VST3Common.h View File

@@ -85,6 +85,18 @@ static Steinberg::Vst::TChar* toString (const juce::String& source) noexcept
//==============================================================================
static Steinberg::Vst::SpeakerArrangement getArrangementForBus (Steinberg::Vst::IAudioProcessor* processor,
bool isInput, int busIndex)
{
Steinberg::Vst::SpeakerArrangement arrangement = Steinberg::Vst::SpeakerArr::kEmpty;
if (processor != nullptr)
processor->getBusArrangement (isInput ? Steinberg::Vst::kInput : Steinberg::Vst::kOutput,
(Steinberg::int32) busIndex, arrangement);
return arrangement;
}
/** For the sake of simplicity, there can only be 1 arrangement type per channel count.
i.e.: 4 channels == k31Cine OR k40Cine
*/
@@ -126,9 +138,9 @@ class ComSmartPtr
{
public:
ComSmartPtr() noexcept : source (nullptr) {}
ComSmartPtr (ObjectType* object) noexcept : source (object) { if (source != nullptr) source->addRef(); }
ComSmartPtr (const ComSmartPtr& other) noexcept : source (other.source) { if (source != nullptr) source->addRef(); }
~ComSmartPtr() { if (source != nullptr) source->release(); }
ComSmartPtr (ObjectType* object, bool autoAddRef = true) noexcept : source (object) { if (source != nullptr && autoAddRef) source->addRef(); }
ComSmartPtr (const ComSmartPtr& other) noexcept : source (other.source) { if (source != nullptr) source->addRef(); }
~ComSmartPtr() { if (source != nullptr) source->release(); }
operator ObjectType*() const noexcept { return source; }
ObjectType* get() const noexcept { return source; }
@@ -341,7 +353,7 @@ namespace VST3BufferExchange
Bus& bus,
AudioSampleBuffer& buffer,
int numChannels, int channelStartOffset,
int sampleOffset = 0) noexcept
int sampleOffset = 0)
{
const int channelEnd = numChannels + channelStartOffset;
jassert (channelEnd >= 0 && channelEnd <= buffer.getNumChannels());
@@ -356,37 +368,52 @@ namespace VST3BufferExchange
vstBuffers.silenceFlags = 0;
}
static void mapBufferToBusses (Array<Steinberg::Vst::AudioBusBuffers>& result,
Steinberg::Vst::IAudioProcessor& processor,
BusMap& busMapToUse,
bool isInput, int numBusses,
AudioSampleBuffer& source)
static void mapArrangementToBusses (int& channelIndexOffset, int index,
Array<Steinberg::Vst::AudioBusBuffers>& result,
BusMap& busMapToUse, Steinberg::Vst::SpeakerArrangement arrangement,
AudioSampleBuffer& source)
{
int channelIndexOffset = 0;
const int numChansForBus = BigInteger ((juce::int64) arrangement).countNumberOfSetBits();
for (int i = 0; i < numBusses; ++i)
if (index >= result.size())
result.add (Steinberg::Vst::AudioBusBuffers());
if (index >= busMapToUse.size())
busMapToUse.add (Bus());
if (numChansForBus > 0)
{
Steinberg::Vst::SpeakerArrangement arrangement = 0;
processor.getBusArrangement (isInput ? Steinberg::Vst::kInput : Steinberg::Vst::kOutput,
(Steinberg::int32) i, arrangement);
associateBufferTo (result.getReference (index),
busMapToUse.getReference (index),
source, numChansForBus, channelIndexOffset);
}
const int numChansForBus = BigInteger ((juce::int64) arrangement).countNumberOfSetBits();
channelIndexOffset += numChansForBus;
}
if (i >= result.size())
result.add (Steinberg::Vst::AudioBusBuffers());
static void mapBufferToBusses (Array<Steinberg::Vst::AudioBusBuffers>& result, BusMap& busMapToUse,
const Array<Steinberg::Vst::SpeakerArrangement>& arrangements,
AudioSampleBuffer& source)
{
int channelIndexOffset = 0;
if (i >= busMapToUse.size())
busMapToUse.add (Bus());
for (int i = 0; i < arrangements.size(); ++i)
mapArrangementToBusses (channelIndexOffset, i, result, busMapToUse,
arrangements.getUnchecked (i), source);
}
if (numChansForBus > 0)
{
associateBufferTo (result.getReference (i),
busMapToUse.getReference (i),
source, numChansForBus, channelIndexOffset);
}
static void mapBufferToBusses (Array<Steinberg::Vst::AudioBusBuffers>& result,
Steinberg::Vst::IAudioProcessor& processor,
BusMap& busMapToUse, bool isInput, int numBusses,
AudioSampleBuffer& source)
{
int channelIndexOffset = 0;
channelIndexOffset += numChansForBus;
}
for (int i = 0; i < numBusses; ++i)
mapArrangementToBusses (channelIndexOffset, i,
result, busMapToUse,
getArrangementForBus (&processor, isInput, i),
source);
}
}


+ 361
- 62
libs/juce/source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp View File

@@ -31,6 +31,7 @@
#define JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY 1
#endif
#include <map>
#include "juce_VST3Headers.h"
#undef JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY
@@ -111,6 +112,7 @@ static void createPluginDescription (PluginDescription& description,
description.lastFileModTime = pluginFile.getLastModificationTime();
description.manufacturerName = company;
description.name = name;
description.descriptiveName = name;
description.pluginFormatName = "VST3";
description.numInputChannels = numInputs;
description.numOutputChannels = numOutputs;
@@ -378,32 +380,70 @@ public:
FUnknown* getFUnknown() { return static_cast<Vst::IComponentHandler*> (this); }
static bool hasFlag (Steinberg::int32 source, Steinberg::int32 flag) noexcept
{
return (source & flag) == flag;
}
//==============================================================================
tresult PLUGIN_API beginEdit (Vst::ParamID) override
tresult PLUGIN_API beginEdit (Vst::ParamID paramID) override
{
// XXX todo..
return kResultFalse;
const int index = getIndexOfParamID (paramID);
if (index < 0)
return kResultFalse;
owner->beginParameterChangeGesture (index);
return kResultTrue;
}
tresult PLUGIN_API performEdit (Vst::ParamID id, Vst::ParamValue valueNormalized) override
tresult PLUGIN_API performEdit (Vst::ParamID paramID, Vst::ParamValue valueNormalized) override
{
if (owner != nullptr)
return owner->editController->setParamNormalized (id, valueNormalized);
const int index = getIndexOfParamID (paramID);
return kResultFalse;
if (index < 0)
return kResultFalse;
owner->sendParamChangeMessageToListeners (index, (float) valueNormalized);
return owner->editController->setParamNormalized (paramID, valueNormalized);
}
tresult PLUGIN_API endEdit (Vst::ParamID) override
tresult PLUGIN_API endEdit (Vst::ParamID paramID) override
{
// XXX todo..
return kResultFalse;
const int index = getIndexOfParamID (paramID);
if (index < 0)
return kResultFalse;
owner->endParameterChangeGesture (index);
return kResultTrue;
}
tresult PLUGIN_API restartComponent (Steinberg::int32) override
tresult PLUGIN_API restartComponent (Steinberg::int32 flags) override
{
if (owner != nullptr)
{
owner->reset();
if (hasFlag (flags, Vst::kReloadComponent))
owner->reset();
if (hasFlag (flags, Vst::kIoChanged))
{
double sampleRate = owner->getSampleRate();
int numSamples = owner->getBlockSize();
if (sampleRate <= 8000.0)
sampleRate = 44100.0;
if (numSamples <= 0)
numSamples = 1024;
owner->prepareToPlay (owner->getSampleRate(), owner->getBlockSize());
}
if (hasFlag (flags, Vst::kLatencyChanged))
if (owner->processor != nullptr)
owner->setLatencySamples (jmax (0, (int) owner->processor->getLatencySamples()));
owner->updateHostDisplay();
return kResultTrue;
}
@@ -437,9 +477,171 @@ public:
return kResultFalse;
}
//==============================================================================
class ContextMenu : public Vst::IContextMenu
{
public:
ContextMenu (VST3PluginInstance& pluginInstance) : owner (pluginInstance) {}
virtual ~ContextMenu() {}
JUCE_DECLARE_VST3_COM_REF_METHODS
JUCE_DECLARE_VST3_COM_QUERY_METHODS
Steinberg::int32 PLUGIN_API getItemCount() override { return (Steinberg::int32) items.size(); }
tresult PLUGIN_API addItem (const Item& item, IContextMenuTarget* target) override
{
jassert (target != nullptr);
ItemAndTarget newItem;
newItem.item = item;
newItem.target = target;
items.add (newItem);
return kResultOk;
}
tresult PLUGIN_API removeItem (const Item& toRemove, IContextMenuTarget* target) override
{
for (int i = items.size(); --i >= 0;)
{
ItemAndTarget& item = items.getReference(i);
if (item.item.tag == toRemove.tag && item.target == target)
items.remove (i);
}
return kResultOk;
}
tresult PLUGIN_API getItem (Steinberg::int32 tag, Item& result, IContextMenuTarget** target) override
{
for (int i = 0; i < items.size(); ++i)
{
const ItemAndTarget& item = items.getReference(i);
if (item.item.tag == tag)
{
result = item.item;
if (target != nullptr)
*target = item.target;
return kResultTrue;
}
}
zerostruct (result);
return kResultFalse;
}
tresult PLUGIN_API popup (Steinberg::UCoord x, Steinberg::UCoord y) override
{
Array<const Item*> subItemStack;
OwnedArray<PopupMenu> menuStack;
PopupMenu* topLevelMenu = menuStack.add (new PopupMenu());
for (int i = 0; i < items.size(); ++i)
{
const Item& item = items.getReference (i).item;
PopupMenu* menuToUse = menuStack.getLast();
if (hasFlag (item.flags, Item::kIsGroupStart & ~Item::kIsDisabled))
{
subItemStack.add (&item);
menuStack.add (new PopupMenu());
}
else if (hasFlag (item.flags, Item::kIsGroupEnd))
{
if (const Item* subItem = subItemStack.getLast())
{
if (PopupMenu* m = menuStack [menuStack.size() - 2])
m->addSubMenu (toString (subItem->name), *menuToUse,
! hasFlag (subItem->flags, Item::kIsDisabled),
nullptr,
hasFlag (subItem->flags, Item::kIsChecked));
menuStack.removeLast (1);
subItemStack.removeLast (1);
}
}
else if (hasFlag (item.flags, Item::kIsSeparator))
{
menuToUse->addSeparator();
}
else
{
menuToUse->addItem (item.tag != 0 ? (int) item.tag : (int) zeroTagReplacement,
toString (item.name),
! hasFlag (item.flags, Item::kIsDisabled),
hasFlag (item.flags, Item::kIsChecked));
}
}
PopupMenu::Options options;
if (AudioProcessorEditor* ed = owner.getActiveEditor())
options = options.withTargetScreenArea (ed->getScreenBounds().translated ((int) x, (int) y).withSize (1, 1));
#if JUCE_MODAL_LOOPS_PERMITTED
// Unfortunately, Steinberg's docs explicitly say this should be modal..
handleResult (topLevelMenu->showMenu (options));
#else
topLevelMenu->showMenuAsync (options, ModalCallbackFunction::create (menuFinished, ComSmartPtr<ContextMenu> (this)));
#endif
return kResultOk;
}
#if ! JUCE_MODAL_LOOPS_PERMITTED
static void menuFinished (int modalResult, ComSmartPtr<ContextMenu> menu) { menu->handleResult (modalResult); }
#endif
private:
enum { zeroTagReplacement = 0x7fffffff };
Atomic<int> refCount;
VST3PluginInstance& owner;
struct ItemAndTarget
{
Item item;
ComSmartPtr<IContextMenuTarget> target;
};
Array<ItemAndTarget> items;
void handleResult (int result)
{
if (result == 0)
return;
if (result == zeroTagReplacement)
result = 0;
for (int i = 0; i < items.size(); ++i)
{
const ItemAndTarget& item = items.getReference(i);
if ((int) item.item.tag == result)
{
if (item.target != nullptr)
item.target->executeMenuItem ((Steinberg::int32) result);
break;
}
}
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ContextMenu)
};
Vst::IContextMenu* PLUGIN_API createContextMenu (IPlugView*, const Vst::ParamID*) override
{
jassertfalse;
if (owner != nullptr)
return new ContextMenu (*owner);
return nullptr;
}
@@ -549,9 +751,42 @@ public:
private:
//==============================================================================
Atomic<int32> refCount;
VST3PluginInstance* const owner;
Atomic<int> refCount;
String appName;
VST3PluginInstance* owner;
typedef std::map<Vst::ParamID, int> ParamMapType;
ParamMapType paramToIndexMap;
int getIndexOfParamID (Vst::ParamID paramID)
{
if (owner == nullptr || owner->editController == nullptr)
return -1;
int result = getMappedParamID (paramID);
if (result < 0)
{
const int numParams = owner->editController->getParameterCount();
for (int i = 0; i < numParams; ++i)
{
Vst::ParameterInfo paramInfo;
owner->editController->getParameterInfo (i, paramInfo);
paramToIndexMap[paramInfo.id] = i;
}
result = getMappedParamID (paramID);
}
return result;
}
int getMappedParamID (Vst::ParamID paramID)
{
const ParamMapType::iterator it (paramToIndexMap.find (paramID));
return it != paramToIndexMap.end() ? it->second : -1;
}
//==============================================================================
class Message : public Vst::IMessage
@@ -577,9 +812,9 @@ private:
JUCE_DECLARE_VST3_COM_REF_METHODS
JUCE_DECLARE_VST3_COM_QUERY_METHODS
FIDString PLUGIN_API getMessageID() { return messageId.toRawUTF8(); }
void PLUGIN_API setMessageID (FIDString id) { messageId = toString (id); }
Vst::IAttributeList* PLUGIN_API getAttributes() { return attributeList; }
FIDString PLUGIN_API getMessageID() override { return messageId.toRawUTF8(); }
void PLUGIN_API setMessageID (FIDString id) override { messageId = toString (id); }
Vst::IAttributeList* PLUGIN_API getAttributes() override { return attributeList; }
var value;
@@ -587,7 +822,7 @@ private:
VST3HostContext& owner;
ComSmartPtr<Vst::IAttributeList> attributeList;
String messageId;
Atomic<int32> refCount;
Atomic<int> refCount;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Message)
};
@@ -715,7 +950,7 @@ private:
private:
VST3HostContext* owner;
Atomic<int32> refCount;
Atomic<int> refCount;
//==============================================================================
template<typename Type>
@@ -1195,7 +1430,8 @@ public:
VST3PluginWindow (AudioProcessor* owner, IPlugView* pluginView)
: AudioProcessorEditor (owner),
ComponentMovementWatcher (this),
view (pluginView),
refCount (1),
view (pluginView, false),
pluginHandle (nullptr),
recursiveResize (false)
{
@@ -1266,20 +1502,32 @@ public:
{
rect.right = (Steinberg::int32) getWidth();
rect.bottom = (Steinberg::int32) getHeight();
view->checkSizeConstraint (&rect);
setSize ((int) rect.getWidth(), (int) rect.getHeight());
#if JUCE_WINDOWS
SetWindowPos (pluginHandle, 0,
pos.x, pos.y, rect.getWidth(), rect.getHeight(),
isVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW);
#elif JUCE_MAC
dummyComponent.setBounds (getLocalBounds());
#endif
view->onSize (&rect);
}
else
{
warnOnFailure (view->getSize (&rect));
}
#if JUCE_WINDOWS
SetWindowPos (pluginHandle, 0,
pos.x, pos.y, rect.getWidth(), rect.getHeight(),
isVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW);
#elif JUCE_MAC
dummyComponent.setBounds (0, 0, (int) rect.getWidth(), (int) rect.getHeight());
#endif
#if JUCE_WINDOWS
SetWindowPos (pluginHandle, 0,
pos.x, pos.y, rect.getWidth(), rect.getHeight(),
isVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW);
#elif JUCE_MAC
dummyComponent.setBounds (0, 0, (int) rect.getWidth(), (int) rect.getHeight());
#endif
}
// Some plugins don't update their cursor correctly when mousing out the window
Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate();
@@ -1364,7 +1612,7 @@ private:
if (peer != nullptr)
pluginHandle = (HandleFormat) peer->getNativeHandle();
#elif JUCE_MAC
dummyComponent.setBounds (getBounds().withZeroOrigin());
dummyComponent.setBounds (getLocalBounds());
addAndMakeVisible (dummyComponent);
pluginHandle = (NSView*) dummyComponent.getView();
jassert (pluginHandle != nil);
@@ -1391,7 +1639,8 @@ public:
midiInputs (new MidiEventList()),
midiOutputs (new MidiEventList()),
isComponentInitialised (false),
isControllerInitialised (false)
isControllerInitialised (false),
isActive (false)
{
host = new VST3HostContext (this);
}
@@ -1413,7 +1662,6 @@ public:
if (isControllerInitialised) editController->terminate();
if (isComponentInitialised) component->terminate();
//Deletion order appears to matter:
componentConnection = nullptr;
editControllerConnection = nullptr;
unitData = nullptr;
@@ -1425,6 +1673,8 @@ public:
editController2 = nullptr;
editController = nullptr;
component = nullptr;
host = nullptr;
module = nullptr;
}
bool initialise()
@@ -1478,8 +1728,27 @@ public:
return module != nullptr ? module->name : String::empty;
}
void repopulateArrangements()
{
inputArrangements.clearQuick();
outputArrangements.clearQuick();
// NB: Some plugins need a valid arrangement despite specifying 0 for their I/O busses
for (int i = 0; i < jmax (1, numInputAudioBusses); ++i)
inputArrangements.add (getArrangementForBus (processor, true, i));
for (int i = 0; i < jmax (1, numOutputAudioBusses); ++i)
outputArrangements.add (getArrangementForBus (processor, false, i));
}
void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock) override
{
// Avoid redundantly calling things like setActive, which can be a heavy-duty call for some plugins:
if (isActive
&& getSampleRate() == sampleRate
&& getBlockSize() == estimatedSamplesPerBlock)
return;
using namespace Vst;
ProcessSetup setup;
@@ -1495,20 +1764,25 @@ public:
editController->setComponentHandler (host);
Array<SpeakerArrangement> inArrangements, outArrangements;
if (inputArrangements.size() <= 0 || outputArrangements.size() <= 0)
repopulateArrangements();
for (int i = 0; i < numInputAudioBusses; ++i)
inArrangements.add (getArrangementForNumChannels (jmax (0, (int) getBusInfo (true, true, i).channelCount)));
warnOnFailure (processor->setBusArrangements (inputArrangements.getRawDataPointer(), numInputAudioBusses,
outputArrangements.getRawDataPointer(), numOutputAudioBusses));
for (int i = 0; i < numOutputAudioBusses; ++i)
outArrangements.add (getArrangementForNumChannels (jmax (0, (int) getBusInfo (false, true, i).channelCount)));
// Update the num. busses in case the configuration has been modified by the plugin. (May affect number of channels!):
const int newNumInputAudioBusses = getNumSingleDirectionBussesFor (component, true, true);
const int newNumOutputAudioBusses = getNumSingleDirectionBussesFor (component, false, true);
warnOnFailure (processor->setBusArrangements (inArrangements.getRawDataPointer(), numInputAudioBusses,
outArrangements.getRawDataPointer(), numOutputAudioBusses));
// Repopulate arrangements if the number of busses have changed:
if (numInputAudioBusses != newNumInputAudioBusses
|| numOutputAudioBusses != newNumOutputAudioBusses)
{
numInputAudioBusses = newNumInputAudioBusses;
numOutputAudioBusses = newNumOutputAudioBusses;
// Update the num. busses in case the configuration has been modified by the plugin. (May affect number of channels!):
numInputAudioBusses = getNumSingleDirectionBussesFor (component, true, true);
numOutputAudioBusses = getNumSingleDirectionBussesFor (component, false, true);
repopulateArrangements();
}
// Needed for having the same sample rate in processBlock(); some plugins need this!
setPlayConfigDetails (getNumSingleDirectionChannelsFor (component, true, true),
@@ -1517,21 +1791,30 @@ public:
setStateForAllBusses (true);
setLatencySamples (jmax (0, (int) processor->getLatencySamples()));
warnOnFailure (component->setActive (true));
warnOnFailure (processor->setProcessing (true));
isActive = true;
}
void releaseResources() override
{
if (! isActive)
return; // Avoids redundantly calling things like setActive
JUCE_TRY
{
isActive = false;
setStateForAllBusses (false);
if (processor != nullptr)
processor->setProcessing (false);
warnOnFailure (processor->setProcessing (false));
if (component != nullptr)
component->setActive (false);
warnOnFailure (component->setActive (false));
}
JUCE_CATCH_ALL_ASSERT
}
@@ -1540,7 +1823,8 @@ public:
{
using namespace Vst;
if (processor != nullptr
if (isActive
&& processor != nullptr
&& processor->canProcessSampleSize (kSample32) == kResultTrue)
{
const int numSamples = buffer.getNumSamples();
@@ -1612,15 +1896,22 @@ public:
//==============================================================================
bool silenceInProducesSilenceOut() const override
{
return processor == nullptr;
if (processor != nullptr)
return processor->getTailSamples() == Vst::kNoTail;
return true;
}
/** May return a negative value as a means of informing us that the plugin has "infinite tail," or 0 for "no tail." */
double getTailLengthSeconds() const override
{
if (processor != nullptr)
return (double) jmin ((int) jmax ((Steinberg::uint32) 0, processor->getTailSamples()), 0x7fffffff)
* getSampleRate();
{
const double sampleRate = getSampleRate();
if (sampleRate > 0.0)
return jlimit (0, 0x7fffffff, (int) processor->getTailSamples()) / sampleRate;
}
return 0.0;
}
@@ -1640,7 +1931,7 @@ public:
if (getActiveEditor() != nullptr)
return true;
ComSmartPtr<IPlugView> view (tryCreatingView());
ComSmartPtr<IPlugView> view (tryCreatingView(), false);
return view != nullptr;
}
@@ -1706,6 +1997,16 @@ public:
return toString (result);
}
//==============================================================================
void reset() override
{
if (component != nullptr)
{
component->setActive (false);
component->setActive (true);
}
}
//==============================================================================
void getStateInformation (MemoryBlock& destData) override
{
@@ -1785,6 +2086,7 @@ private:
as very poorly specified by the Steinberg SDK
*/
int numInputAudioBusses, numOutputAudioBusses;
Array<Vst::SpeakerArrangement> inputArrangements, outputArrangements; // Caching to improve performance and to avoid possible non-thread-safe calls to getBusArrangements().
VST3BufferExchange::BusMap inputBusMap, outputBusMap;
Array<Vst::AudioBusBuffers> inputBusses, outputBusses;
@@ -1829,21 +2131,21 @@ private:
JUCE_DECLARE_VST3_COM_REF_METHODS
JUCE_DECLARE_VST3_COM_QUERY_METHODS
Steinberg::int32 PLUGIN_API getParameterCount() { return 0; }
Steinberg::int32 PLUGIN_API getParameterCount() override { return 0; }
Vst::IParamValueQueue* PLUGIN_API getParameterData (Steinberg::int32)
Vst::IParamValueQueue* PLUGIN_API getParameterData (Steinberg::int32) override
{
return nullptr;
}
Vst::IParamValueQueue* PLUGIN_API addParameterData (const Vst::ParamID&, Steinberg::int32& index)
Vst::IParamValueQueue* PLUGIN_API addParameterData (const Vst::ParamID&, Steinberg::int32& index) override
{
index = 0;
return nullptr;
}
private:
Atomic<int32> refCount;
Atomic<int> refCount;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParameterChangeList)
};
@@ -1851,7 +2153,7 @@ private:
ComSmartPtr<ParameterChangeList> inputParameterChanges, outputParameterChanges;
ComSmartPtr<MidiEventList> midiInputs, midiOutputs;
Vst::ProcessContext timingInfo; //< Only use this in processBlock()!
bool isComponentInitialised, isControllerInitialised;
bool isComponentInitialised, isControllerInitialised, isActive;
//==============================================================================
bool fetchComponentAndController (IPluginFactory* factory, const Steinberg::int32 numClasses)
@@ -2031,11 +2333,11 @@ private:
Vst::BusInfo getBusInfo (bool forInput, bool forAudio, int index = 0) const
{
Vst::BusInfo busInfo;
busInfo.mediaType = forAudio ? Vst::kAudio : Vst::kEvent;
busInfo.direction = forInput ? Vst::kInput : Vst::kOutput;
component->getBusInfo (forAudio ? Vst::kAudio : Vst::kEvent,
forInput ? Vst::kInput : Vst::kOutput,
component->getBusInfo (busInfo.mediaType, busInfo.direction,
(Steinberg::int32) index, busInfo);
return busInfo;
}
@@ -2056,11 +2358,8 @@ private:
{
using namespace VST3BufferExchange;
mapBufferToBusses (inputBusses, *processor, inputBusMap,
true, numInputAudioBusses, buffer);
mapBufferToBusses (outputBusses, *processor, outputBusMap,
false, numOutputAudioBusses, buffer);
mapBufferToBusses (inputBusses, inputBusMap, inputArrangements, buffer);
mapBufferToBusses (outputBusses, outputBusMap, outputArrangements, buffer);
destination.inputs = inputBusses.getRawDataPointer();
destination.outputs = outputBusses.getRawDataPointer();


+ 2
- 4
libs/juce/source/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp View File

@@ -1285,7 +1285,8 @@ public:
handleUpdateNowIfNeeded();
for (int i = ComponentPeer::getNumPeers(); --i >= 0;)
ComponentPeer::getPeer(i)->performAnyPendingRepaintsNow();
if (ComponentPeer* p = ComponentPeer::getPeer(i))
p->performAnyPendingRepaintsNow();
}
break;
@@ -2317,10 +2318,8 @@ private:
{
if (isOpen)
{
#if ! (JUCE_MAC && JUCE_SUPPORT_CARBON)
JUCE_VST_LOG ("Closing VST UI: " + plugin.getName());
isOpen = false;
dispatch (effEditClose, 0, 0, 0, 0);
stopTimer();
@@ -2336,7 +2335,6 @@ private:
pluginWindow = 0;
pluginProc = 0;
#endif
#endif
}
}


+ 1
- 5
libs/juce/source/modules/juce_audio_processors/processors/juce_AudioProcessor.h View File

@@ -44,11 +44,7 @@ class JUCE_API AudioProcessor
{
protected:
//==============================================================================
/** Constructor.
You can also do your initialisation tasks in the initialiseFilterInfo()
call, which will be made after this object has been created.
*/
/** Constructor. */
AudioProcessor();
public:


+ 3
- 3
libs/juce/source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h View File

@@ -388,11 +388,11 @@ public:
private:
//==============================================================================
ReferenceCountedArray <Node> nodes;
OwnedArray <Connection> connections;
ReferenceCountedArray<Node> nodes;
OwnedArray<Connection> connections;
uint32 lastNodeId;
AudioSampleBuffer renderingBuffers;
OwnedArray <MidiBuffer> midiBuffers;
OwnedArray<MidiBuffer> midiBuffers;
Array<void*> renderingOps;
friend class AudioGraphIOProcessor;


+ 26
- 15
libs/juce/source/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp View File

@@ -27,12 +27,12 @@ class ProcessorParameterPropertyComp : public PropertyComponent,
private Timer
{
public:
ProcessorParameterPropertyComp (const String& name, AudioProcessor& p, const int index_)
ProcessorParameterPropertyComp (const String& name, AudioProcessor& p, int paramIndex)
: PropertyComponent (name),
owner (p),
index (index_),
index (paramIndex),
paramHasChanged (false),
slider (p, index_)
slider (p, paramIndex)
{
startTimer (100);
addAndMakeVisible (slider);
@@ -44,15 +44,19 @@ public:
owner.removeListener (this);
}
void refresh()
void refresh() override
{
paramHasChanged = false;
slider.setValue (owner.getParameter (index), dontSendNotification);
if (slider.getThumbBeingDragged() < 0)
slider.setValue (owner.getParameter (index), dontSendNotification);
slider.updateText();
}
void audioProcessorChanged (AudioProcessor*) {}
void audioProcessorChanged (AudioProcessor*) override {}
void audioProcessorParameterChanged (AudioProcessor*, int parameterIndex, float)
void audioProcessorParameterChanged (AudioProcessor*, int parameterIndex, float) override
{
if (parameterIndex == index)
paramHasChanged = true;
@@ -76,27 +80,34 @@ private:
class ParamSlider : public Slider
{
public:
ParamSlider (AudioProcessor& p, const int index_)
: owner (p),
index (index_)
ParamSlider (AudioProcessor& p, int paramIndex) : owner (p), index (paramIndex)
{
setRange (0.0, 1.0, 0.0);
const int steps = owner.getParameterNumSteps (index);
if (steps > 1 && steps < 0x7fffffff)
setRange (0.0, 1.0, 1.0 / (steps - 1.0));
else
setRange (0.0, 1.0);
setSliderStyle (Slider::LinearBar);
setTextBoxIsEditable (false);
setScrollWheelEnabled (false);
setScrollWheelEnabled (true);
}
void valueChanged()
void valueChanged() override
{
const float newVal = (float) getValue();
if (owner.getParameter (index) != newVal)
{
owner.setParameterNotifyingHost (index, newVal);
updateText();
}
}
String getTextFromValue (double /*value*/)
String getTextFromValue (double /*value*/) override
{
return owner.getParameterText (index);
return owner.getParameterText (index) + " " + owner.getParameterLabel (index).trimEnd();
}
private:


+ 7
- 11
libs/juce/source/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp View File

@@ -75,11 +75,10 @@ class AudioDeviceSelectorComponent::MidiInputSelectorComponentListBox : public
private ListBoxModel
{
public:
MidiInputSelectorComponentListBox (AudioDeviceManager& dm,
const String& noItemsMessage_)
MidiInputSelectorComponentListBox (AudioDeviceManager& dm, const String& noItems)
: ListBox (String::empty, nullptr),
deviceManager (dm),
noItemsMessage (noItemsMessage_)
noItemsMessage (noItems)
{
items = MidiInput::getDevices();
@@ -87,15 +86,12 @@ public:
setOutlineThickness (1);
}
int getNumRows()
int getNumRows() override
{
return items.size();
}
void paintListBoxItem (int row,
Graphics& g,
int width, int height,
bool rowIsSelected)
void paintListBoxItem (int row, Graphics& g, int width, int height, bool rowIsSelected) override
{
if (isPositiveAndBelow (row, items.size()))
{
@@ -118,7 +114,7 @@ public:
}
}
void listBoxItemClicked (int row, const MouseEvent& e)
void listBoxItemClicked (int row, const MouseEvent& e) override
{
selectRow (row);
@@ -126,12 +122,12 @@ public:
flipEnablement (row);
}
void listBoxItemDoubleClicked (int row, const MouseEvent&)
void listBoxItemDoubleClicked (int row, const MouseEvent&) override
{
flipEnablement (row);
}
void returnKeyPressed (int row)
void returnKeyPressed (int row) override
{
flipEnablement (row);
}


+ 2
- 2
libs/juce/source/modules/juce_audio_utils/gui/juce_AudioThumbnail.cpp View File

@@ -342,7 +342,7 @@ public:
}
private:
Array <MinMaxValue> data;
Array<MinMaxValue> data;
int peakLevel;
void ensureSize (const int thumbSamples)
@@ -414,7 +414,7 @@ public:
}
private:
Array <MinMaxValue> data;
Array<MinMaxValue> data;
double cachedStart, cachedTimePerPixel;
int numChannelsCached, numSamplesCached;
bool cacheNeedsRefilling;


+ 1
- 1
libs/juce/source/modules/juce_core/containers/juce_AbstractFifo.cpp View File

@@ -35,7 +35,7 @@ AbstractFifo::AbstractFifo (const int capacity) noexcept
AbstractFifo::~AbstractFifo() {}
int AbstractFifo::getTotalSize() const noexcept { return bufferSize; }
int AbstractFifo::getFreeSpace() const noexcept { return bufferSize - getNumReady(); }
int AbstractFifo::getFreeSpace() const noexcept { return bufferSize - getNumReady() - 1; }
int AbstractFifo::getNumReady() const noexcept
{


+ 1
- 1
libs/juce/source/modules/juce_core/containers/juce_Array.h View File

@@ -42,7 +42,7 @@
- it must be able to be relocated in memory by a memcpy without this causing any problems - so
objects whose functionality relies on external pointers or references to themselves can not be used.
You can of course have an array of pointers to any kind of object, e.g. Array <MyClass*>, but if
You can of course have an array of pointers to any kind of object, e.g. Array<MyClass*>, but if
you do this, the array doesn't take any ownership of the objects - see the OwnedArray class or the
ReferenceCountedArray class for more powerful ways of holding lists of objects.


+ 1
- 1
libs/juce/source/modules/juce_core/containers/juce_DynamicObject.cpp View File

@@ -31,7 +31,7 @@ DynamicObject::DynamicObject()
}
DynamicObject::DynamicObject (const DynamicObject& other)
: properties (other.properties)
: ReferenceCountedObject(), properties (other.properties)
{
}


+ 1
- 1
libs/juce/source/modules/juce_core/containers/juce_DynamicObject.h View File

@@ -58,7 +58,7 @@ public:
virtual bool hasProperty (const Identifier& propertyName) const;
/** Returns a named property.
This returns a void if no such property exists.
This returns var::null if no such property exists.
*/
virtual var getProperty (const Identifier& propertyName) const;


+ 8
- 0
libs/juce/source/modules/juce_core/files/juce_File.h View File

@@ -361,6 +361,14 @@ public:
*/
File getLinkedTarget() const;
/** Returns a unique identifier for the file, if one is available.
Depending on the OS and file-system, this may be a unix inode number or
a win32 file identifier, or 0 if it fails to find one. The number will
be unique on the filesystem, but not globally.
*/
uint64 getFileIdentifier() const;
//==============================================================================
/** Returns the last modification time of this file.


+ 12
- 23
libs/juce/source/modules/juce_core/files/juce_FileInputStream.cpp View File

@@ -28,40 +28,33 @@
int64 juce_fileSetPosition (void* handle, int64 pos);
//==============================================================================
FileInputStream::FileInputStream (const File& f)
: file (f),
fileHandle (nullptr),
currentPosition (0),
status (Result::ok()),
needToSeek (true)
status (Result::ok())
{
openHandle();
}
FileInputStream::~FileInputStream()
{
closeHandle();
}
//==============================================================================
int64 FileInputStream::getTotalLength()
{
// You should always check that a stream opened successfully before using it!
jassert (openedOk());
return file.getSize();
}
int FileInputStream::read (void* buffer, int bytesToRead)
{
// You should always check that a stream opened successfully before using it!
jassert (openedOk());
jassert (buffer != nullptr && bytesToRead >= 0);
if (needToSeek)
{
if (juce_fileSetPosition (fileHandle, currentPosition) < 0)
return 0;
needToSeek = false;
}
// The buffer should never be null, and a negative size is probably a
// sign that something is broken!
jassert (buffer != nullptr && bytesToRead >= 0);
const size_t num = readInternal (buffer, (size_t) bytesToRead);
currentPosition += num;
@@ -81,15 +74,11 @@ int64 FileInputStream::getPosition()
bool FileInputStream::setPosition (int64 pos)
{
// You should always check that a stream opened successfully before using it!
jassert (openedOk());
if (pos != currentPosition)
{
pos = jlimit ((int64) 0, getTotalLength(), pos);
needToSeek |= (currentPosition != pos);
currentPosition = pos;
}
currentPosition = juce_fileSetPosition (fileHandle, pos);
return true;
return currentPosition == pos;
}

+ 9
- 9
libs/juce/source/modules/juce_core/files/juce_FileInputStream.h View File

@@ -40,10 +40,11 @@ class JUCE_API FileInputStream : public InputStream
{
public:
//==============================================================================
/** Creates a FileInputStream.
/** Creates a FileInputStream to read from the given file.
@param fileToRead the file to read from - if the file can't be accessed for some
reason, then the stream will just contain no data
After creating a FileInputStream, you should use openedOk() or failedToOpen()
to make sure that it's OK before trying to read from it! If it failed, you
can call getStatus() to get more error information.
*/
explicit FileInputStream (const File& fileToRead);
@@ -73,24 +74,23 @@ public:
//==============================================================================
int64 getTotalLength() override;
int read (void* destBuffer, int maxBytesToRead) override;
int read (void*, int) override;
bool isExhausted() override;
int64 getPosition() override;
bool setPosition (int64 pos) override;
bool setPosition (int64) override;
private:
//==============================================================================
File file;
const File file;
void* fileHandle;
int64 currentPosition;
Result status;
bool needToSeek;
void openHandle();
void closeHandle();
size_t readInternal (void* buffer, size_t numBytes);
size_t readInternal (void*, size_t);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileInputStream)
};
#endif // JUCE_FILEINPUTSTREAM_H_INCLUDED

+ 1
- 1
libs/juce/source/modules/juce_core/javascript/juce_Javascript.cpp View File

@@ -768,7 +768,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
{
FunctionObject() noexcept {}
FunctionObject (const FunctionObject& other) : functionCode (other.functionCode)
FunctionObject (const FunctionObject& other) : DynamicObject(), functionCode (other.functionCode)
{
ExpressionTreeBuilder tb (functionCode);
tb.parseFunctionParamsAndBody (*this);


+ 1
- 1
libs/juce/source/modules/juce_core/memory/juce_SharedResourcePointer.h View File

@@ -139,7 +139,7 @@ private:
static SharedObjectHolder& getSharedObjectHolder() noexcept
{
static char holder [sizeof (SharedObjectHolder)] = { 0 };
static void* holder [(sizeof (SharedObjectHolder) + sizeof(void*) - 1) / sizeof(void*)] = { 0 };
return *reinterpret_cast<SharedObjectHolder*> (holder);
}


+ 8
- 3
libs/juce/source/modules/juce_core/native/java/JuceAppActivity.java View File

@@ -399,16 +399,21 @@ public final class JuceAppActivity extends Activity
private native void handleKeyDown (long host, int keycode, int textchar);
private native void handleKeyUp (long host, int keycode, int textchar);
public void showKeyboard (boolean shouldShow)
public void showKeyboard (String type)
{
InputMethodManager imm = (InputMethodManager) getSystemService (Context.INPUT_METHOD_SERVICE);
if (imm != null)
{
if (shouldShow)
imm.showSoftInput (this, InputMethodManager.SHOW_FORCED);
if (type.length() > 0)
{
imm.showSoftInput (this, android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT);
imm.setInputMethod (getWindowToken(), type);
}
else
{
imm.hideSoftInputFromWindow (getWindowToken(), 0);
}
}
}


+ 13
- 2
libs/juce/source/modules/juce_core/native/juce_android_SystemStats.cpp View File

@@ -179,6 +179,16 @@ namespace AndroidStatsHelpers
JuceAppActivity.getLocaleValue,
isRegion)));
}
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD)
DECLARE_JNI_CLASS (BuildClass, "android/os/Build");
#undef JNI_CLASS_MEMBERS
String getAndroidOsBuildValue (const char* fieldName)
{
return juceString (LocalRef<jstring> ((jstring) getEnv()->GetStaticObjectField (
BuildClass, getEnv()->GetStaticFieldID (BuildClass, fieldName, "Ljava/lang/String;"))));
}
}
//==============================================================================
@@ -194,7 +204,8 @@ String SystemStats::getOperatingSystemName()
String SystemStats::getDeviceDescription()
{
return String::empty;
return AndroidStatsHelpers::getAndroidOsBuildValue ("MODEL")
+ "-" + AndroidStatsHelpers::getAndroidOsBuildValue ("SERIAL");
}
bool SystemStats::isOperatingSystem64Bit()
@@ -262,7 +273,7 @@ String SystemStats::getComputerName()
String SystemStats::getUserLanguage() { return AndroidStatsHelpers::getLocaleValue (false); }
String SystemStats::getUserRegion() { return AndroidStatsHelpers::getLocaleValue (true); }
String SystemStats::getDisplayLanguage() { return getUserLanguage(); }
String SystemStats::getDisplayLanguage() { return getUserLanguage() + "-" + getUserRegion(); }
//==============================================================================
void CPUInformation::initialise() noexcept


+ 4
- 1
libs/juce/source/modules/juce_core/native/juce_linux_Network.cpp View File

@@ -46,7 +46,10 @@ void MACAddress::findAllAddresses (Array<MACAddress>& result)
&& (ifr.ifr_flags & IFF_LOOPBACK) == 0
&& ioctl (s, SIOCGIFHWADDR, &ifr) == 0)
{
result.addIfNotAlreadyThere (MACAddress ((const uint8*) ifr.ifr_hwaddr.sa_data));
MACAddress ma ((const uint8*) ifr.ifr_hwaddr.sa_data);
if (! ma.isNull())
result.addIfNotAlreadyThere (ma);
}
}


+ 1
- 1
libs/juce/source/modules/juce_core/native/juce_linux_SystemStats.cpp View File

@@ -139,7 +139,7 @@ static String getLocaleValue (nl_item key)
String SystemStats::getUserLanguage() { return getLocaleValue (_NL_IDENTIFICATION_LANGUAGE); }
String SystemStats::getUserRegion() { return getLocaleValue (_NL_IDENTIFICATION_TERRITORY); }
String SystemStats::getDisplayLanguage() { return getUserLanguage(); }
String SystemStats::getDisplayLanguage() { return getUserLanguage() + "-" + getUserRegion(); }
//==============================================================================
void CPUInformation::initialise() noexcept


+ 9
- 4
libs/juce/source/modules/juce_core/native/juce_mac_Network.mm View File

@@ -39,12 +39,17 @@ void MACAddress::findAllAddresses (Array<MACAddress>& result)
{
const sockaddr_dl* const sadd = (const sockaddr_dl*) cursor->ifa_addr;
#ifndef IFT_ETHER
#define IFT_ETHER 6
#endif
#ifndef IFT_ETHER
enum { IFT_ETHER = 6 };
#endif
if (sadd->sdl_type == IFT_ETHER)
result.addIfNotAlreadyThere (MACAddress (((const uint8*) sadd->sdl_data) + sadd->sdl_nlen));
{
MACAddress ma (MACAddress (((const uint8*) sadd->sdl_data) + sadd->sdl_nlen));
if (! ma.isNull())
result.addIfNotAlreadyThere (ma);
}
}
}


+ 1
- 1
libs/juce/source/modules/juce_core/native/juce_mac_SystemStats.mm View File

@@ -124,7 +124,7 @@ SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
return iOS;
#else
StringArray parts;
parts.addTokens (getOSXVersion(), ".", String());
parts.addTokens (getOSXVersion(), ".", StringRef());
jassert (parts[0].getIntValue() == 10);
const int major = parts[1].getIntValue();


+ 10
- 7
libs/juce/source/modules/juce_core/native/juce_posix_SharedCode.h View File

@@ -280,6 +280,12 @@ int64 File::getSize() const
return juce_stat (fullPath, info) ? info.st_size : 0;
}
uint64 File::getFileIdentifier() const
{
juce_statStruct info;
return juce_stat (fullPath, info) ? (uint64) info.st_ino : 0;
}
//==============================================================================
bool File::hasWriteAccess() const
{
@@ -391,13 +397,10 @@ void FileInputStream::openHandle()
status = getResultForErrno();
}
void FileInputStream::closeHandle()
FileInputStream::~FileInputStream()
{
if (fileHandle != 0)
{
close (getFD (fileHandle));
fileHandle = 0;
}
}
size_t FileInputStream::readInternal (void* const buffer, const size_t numBytes)
@@ -1017,12 +1020,12 @@ public:
// we're the child process..
close (pipeHandles[0]); // close the read handle
if ((streamFlags | wantStdOut) != 0)
if ((streamFlags & wantStdOut) != 0)
dup2 (pipeHandles[1], 1); // turns the pipe into stdout
else
close (STDOUT_FILENO);
if ((streamFlags | wantStdErr) != 0)
if ((streamFlags & wantStdErr) != 0)
dup2 (pipeHandles[1], 2);
else
close (STDERR_FILENO);
@@ -1210,7 +1213,7 @@ private:
{
mach_timebase_info_data_t timebase;
(void) mach_timebase_info (&timebase);
delta = (((uint64_t) (millis * 1000000.0)) * timebase.numer) / timebase.denom;
delta = (((uint64_t) (millis * 1000000.0)) * timebase.denom) / timebase.numer;
time = mach_absolute_time();
}


+ 23
- 1
libs/juce/source/modules/juce_core/native/juce_win32_Files.cpp View File

@@ -234,7 +234,7 @@ void FileInputStream::openHandle()
status = WindowsFileHelpers::getResultForLastError();
}
void FileInputStream::closeHandle()
FileInputStream::~FileInputStream()
{
CloseHandle ((HANDLE) fileHandle);
}
@@ -474,6 +474,28 @@ int64 File::getVolumeTotalSize() const
return WindowsFileHelpers::getDiskSpaceInfo (getFullPathName(), true);
}
uint64 File::getFileIdentifier() const
{
uint64 result = 0;
HANDLE h = CreateFile (getFullPathName().toWideCharPointer(),
GENERIC_READ, FILE_SHARE_READ, nullptr,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
if (h != INVALID_HANDLE_VALUE)
{
BY_HANDLE_FILE_INFORMATION info;
zerostruct (info);
if (GetFileInformationByHandle (h, &info))
result = (((uint64) info.nFileIndexHigh) << 32) | info.nFileIndexLow;
CloseHandle (h);
}
return result;
}
//==============================================================================
bool File::isOnCDRomDrive() const
{


+ 11
- 5
libs/juce/source/modules/juce_core/native/juce_win32_Network.cpp View File

@@ -287,7 +287,7 @@ private:
if (bytesToDo > 0
&& ! InternetWriteFile (request,
static_cast <const char*> (postData.getData()) + bytesSent,
static_cast<const char*> (postData.getData()) + bytesSent,
(DWORD) bytesToDo, &bytesDone))
{
break;
@@ -342,7 +342,13 @@ struct GetAdaptersInfoHelper
namespace MACAddressHelpers
{
void getViaGetAdaptersInfo (Array<MACAddress>& result)
static void addAddress (Array<MACAddress>& result, const MACAddress& ma)
{
if (! ma.isNull())
result.addIfNotAlreadyThere (ma);
}
static void getViaGetAdaptersInfo (Array<MACAddress>& result)
{
GetAdaptersInfoHelper gah;
@@ -350,11 +356,11 @@ namespace MACAddressHelpers
{
for (PIP_ADAPTER_INFO adapter = gah.adapterInfo; adapter != nullptr; adapter = adapter->Next)
if (adapter->AddressLength >= 6)
result.addIfNotAlreadyThere (MACAddress (adapter->Address));
addAddress (result, MACAddress (adapter->Address));
}
}
void getViaNetBios (Array<MACAddress>& result)
static void getViaNetBios (Array<MACAddress>& result)
{
DynamicLibrary dll ("netapi32.dll");
JUCE_LOAD_WINAPI_FUNCTION (dll, Netbios, NetbiosCall, UCHAR, (PNCB))
@@ -396,7 +402,7 @@ namespace MACAddressHelpers
ncb.ncb_length = sizeof (ASTAT);
if (NetbiosCall (&ncb) == 0 && astat.adapt.adapter_type == 0xfe)
result.addIfNotAlreadyThere (MACAddress (astat.adapt.adapter_address));
addAddress (result, MACAddress (astat.adapt.adapter_address));
}
}
}


+ 11
- 3
libs/juce/source/modules/juce_core/native/juce_win32_SystemStats.cpp View File

@@ -428,8 +428,16 @@ String SystemStats::getDisplayLanguage()
DynamicLibrary dll ("kernel32.dll");
JUCE_LOAD_WINAPI_FUNCTION (dll, GetUserDefaultUILanguage, getUserDefaultUILanguage, LANGID, (void))
if (getUserDefaultUILanguage != nullptr)
return getLocaleValue (MAKELCID (getUserDefaultUILanguage(), SORT_DEFAULT), LOCALE_SISO639LANGNAME, "en");
if (getUserDefaultUILanguage == nullptr)
return "en";
return "en";
const DWORD langID = MAKELCID (getUserDefaultUILanguage(), SORT_DEFAULT);
String mainLang (getLocaleValue (langID, LOCALE_SISO639LANGNAME, "en"));
String region (getLocaleValue (langID, LOCALE_SISO3166CTRYNAME, nullptr));
if (region.isNotEmpty())
mainLang << '-' << region;
return mainLang;
}

+ 2
- 3
libs/juce/source/modules/juce_core/network/juce_URL.cpp View File

@@ -241,8 +241,6 @@ void URL::createHeadersAndPostData (String& headers, MemoryBlock& headersAndPost
{
MemoryOutputStream data (headersAndPostData, false);
data << URLHelpers::getMangledParameters (*this);
if (filesToUpload.size() > 0)
{
// (this doesn't currently support mixing custom post-data with uploads..)
@@ -285,7 +283,8 @@ void URL::createHeadersAndPostData (String& headers, MemoryBlock& headersAndPost
}
else
{
data << postData;
data << URLHelpers::getMangledParameters (*this)
<< postData;
// if the user-supplied headers didn't contain a content-type, add one now..
if (! headers.containsIgnoreCase ("Content-Type"))


+ 3
- 1
libs/juce/source/modules/juce_core/system/juce_SystemStats.h View File

@@ -118,7 +118,9 @@ public:
static String getUserRegion();
/** Returns the user's display language.
The return value is a 2 or 3 letter language code (ISO 639-1 or ISO 639-2)
The return value is a 2 or 3 letter language code (ISO 639-1 or ISO 639-2).
Note that depending on the OS and region, this may also be followed by a dash
and a sub-region code, e.g "en-GB"
*/
static String getDisplayLanguage();


+ 1
- 1
libs/juce/source/modules/juce_core/system/juce_TargetPlatform.h View File

@@ -161,7 +161,7 @@
#define JUCE_32BIT 1
#endif
#ifdef __arm__
#if defined (__arm__) || defined (__arm64__)
#define JUCE_ARM 1
#elif __MMX__ || __SSE__ || __amd64__
#define JUCE_INTEL 1


+ 4
- 4
libs/juce/source/modules/juce_core/text/juce_LocalisedStrings.cpp View File

@@ -194,11 +194,11 @@ LocalisedStrings* LocalisedStrings::getCurrentMappings()
String LocalisedStrings::translateWithCurrentMappings (const String& text) { return juce::translate (text); }
String LocalisedStrings::translateWithCurrentMappings (const char* text) { return juce::translate (text); }
String translate (const String& text) { return juce::translate (text, text); }
String translate (const char* text) { return juce::translate (String (text)); }
String translate (CharPointer_UTF8 text) { return juce::translate (String (text)); }
JUCE_API String translate (const String& text) { return juce::translate (text, text); }
JUCE_API String translate (const char* text) { return juce::translate (String (text)); }
JUCE_API String translate (CharPointer_UTF8 text) { return juce::translate (String (text)); }
String translate (const String& text, const String& resultIfNotFound)
JUCE_API String translate (const String& text, const String& resultIfNotFound)
{
const SpinLock::ScopedLockType sl (currentMappingsLock);


+ 4
- 4
libs/juce/source/modules/juce_core/text/juce_LocalisedStrings.h View File

@@ -226,22 +226,22 @@ private:
/** Uses the LocalisedStrings class to translate the given string literal.
@see LocalisedStrings
*/
String translate (const String& stringLiteral);
JUCE_API String translate (const String& stringLiteral);
/** Uses the LocalisedStrings class to translate the given string literal.
@see LocalisedStrings
*/
String translate (const char* stringLiteral);
JUCE_API String translate (const char* stringLiteral);
/** Uses the LocalisedStrings class to translate the given string literal.
@see LocalisedStrings
*/
String translate (CharPointer_UTF8 stringLiteral);
JUCE_API String translate (CharPointer_UTF8 stringLiteral);
/** Uses the LocalisedStrings class to translate the given string literal.
@see LocalisedStrings
*/
String translate (const String& stringLiteral, const String& resultIfNotFound);
JUCE_API String translate (const String& stringLiteral, const String& resultIfNotFound);
#endif // JUCE_LOCALISEDSTRINGS_H_INCLUDED

+ 3
- 2
libs/juce/source/modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp View File

@@ -53,7 +53,7 @@ File PropertiesFile::Options::getDefaultFile() const
File dir (commonToAllUsers ? "/Library/"
: "~/Library/");
if (osxLibrarySubFolder != "Preferences" && osxLibrarySubFolder != "Application Support")
if (osxLibrarySubFolder != "Preferences" && ! osxLibrarySubFolder.startsWith ("Application Support"))
{
/* The PropertiesFile class always used to put its settings files in "Library/Preferences", but Apple
have changed their advice, and now stipulate that settings should go in "Library/Application Support".
@@ -61,7 +61,8 @@ File PropertiesFile::Options::getDefaultFile() const
Because older apps would be broken by a silent change in this class's behaviour, you must now
explicitly set the osxLibrarySubFolder value to indicate which path you want to use.
In newer apps, you should always set this to "Application Support".
In newer apps, you should always set this to "Application Support"
or "Application Support/YourSubFolderName".
If your app needs to load settings files that were created by older versions of juce and
you want to maintain backwards-compatibility, then you can set this to "Preferences".


+ 2
- 1
libs/juce/source/modules/juce_data_structures/app_properties/juce_PropertiesFile.h View File

@@ -85,7 +85,8 @@ public:
Because older apps would be broken by a silent change in this class's behaviour, you must now
explicitly set the osxLibrarySubFolder value to indicate which path you want to use.
In newer apps, you should always set this to "Application Support".
In newer apps, you should always set this to "Application Support" or
"Application Support/YourSubFolderName".
If your app needs to load settings files that were created by older versions of juce and
you want to maintain backwards-compatibility, then you can set this to "Preferences".


+ 11
- 83
libs/juce/source/modules/juce_data_structures/values/juce_Value.cpp View File

@@ -22,76 +22,18 @@
==============================================================================
*/
class SharedValueSourceUpdater : public ReferenceCountedObject,
private AsyncUpdater
{
public:
SharedValueSourceUpdater() : sourcesBeingIterated (nullptr) {}
~SharedValueSourceUpdater() { masterReference.clear(); }
void update (Value::ValueSource* const source)
{
sourcesNeedingAnUpdate.add (source);
if (sourcesBeingIterated == nullptr)
triggerAsyncUpdate();
}
void valueDeleted (Value::ValueSource* const source)
{
sourcesNeedingAnUpdate.removeValue (source);
if (sourcesBeingIterated != nullptr)
sourcesBeingIterated->removeValue (source);
}
WeakReference<SharedValueSourceUpdater>::Master masterReference;
private:
typedef SortedSet<Value::ValueSource*> SourceSet;
SourceSet sourcesNeedingAnUpdate;
SourceSet* sourcesBeingIterated;
void handleAsyncUpdate() override
{
const ReferenceCountedObjectPtr<SharedValueSourceUpdater> localRef (this);
{
const ScopedValueSetter<SourceSet*> inside (sourcesBeingIterated, nullptr, nullptr);
int maxLoops = 10;
while (sourcesNeedingAnUpdate.size() > 0)
{
if (--maxLoops == 0)
{
triggerAsyncUpdate();
break;
}
SourceSet sources;
sources.swapWith (sourcesNeedingAnUpdate);
sourcesBeingIterated = &sources;
for (int i = sources.size(); --i >= 0;)
if (i < sources.size())
sources.getUnchecked(i)->sendChangeMessage (true);
}
}
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SharedValueSourceUpdater)
};
static WeakReference<SharedValueSourceUpdater> sharedUpdater;
Value::ValueSource::ValueSource()
{
}
Value::ValueSource::~ValueSource()
{
if (asyncUpdater != nullptr)
static_cast <SharedValueSourceUpdater*> (asyncUpdater.get())->valueDeleted (this);
cancelPendingUpdate();
}
void Value::ValueSource::handleAsyncUpdate()
{
sendChangeMessage (true);
}
void Value::ValueSource::sendChangeMessage (const bool synchronous)
@@ -103,7 +45,8 @@ void Value::ValueSource::sendChangeMessage (const bool synchronous)
if (synchronous)
{
const ReferenceCountedObjectPtr<ValueSource> localRef (this);
asyncUpdater = nullptr;
cancelPendingUpdate();
for (int i = numListeners; --i >= 0;)
if (Value* const v = valuesWithListeners[i])
@@ -111,22 +54,7 @@ void Value::ValueSource::sendChangeMessage (const bool synchronous)
}
else
{
SharedValueSourceUpdater* updater = static_cast <SharedValueSourceUpdater*> (asyncUpdater.get());
if (updater == nullptr)
{
if (sharedUpdater == nullptr)
{
asyncUpdater = updater = new SharedValueSourceUpdater();
sharedUpdater = updater;
}
else
{
asyncUpdater = updater = sharedUpdater.get();
}
}
updater->update (this);
triggerAsyncUpdate();
}
}
}
@@ -195,13 +123,13 @@ Value& Value::operator= (const Value& other)
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
Value::Value (Value&& other) noexcept
: value (static_cast <ReferenceCountedObjectPtr <ValueSource>&&> (other.value))
: value (static_cast<ReferenceCountedObjectPtr<ValueSource>&&> (other.value))
{
}
Value& Value::operator= (Value&& other) noexcept
{
value = static_cast <ReferenceCountedObjectPtr <ValueSource>&&> (other.value);
value = static_cast<ReferenceCountedObjectPtr<ValueSource>&&> (other.value);
return *this;
}
#endif


+ 8
- 5
libs/juce/source/modules/juce_data_structures/values/juce_Value.h View File

@@ -167,7 +167,8 @@ public:
of a ValueSource object. If you're feeling adventurous, you can create your own custom
ValueSource classes to allow Value objects to represent your own custom data items.
*/
class JUCE_API ValueSource : public SingleThreadedReferenceCountedObject
class JUCE_API ValueSource : public ReferenceCountedObject,
private AsyncUpdater
{
public:
ValueSource();
@@ -192,8 +193,10 @@ public:
protected:
//==============================================================================
friend class Value;
SortedSet <Value*> valuesWithListeners;
ReferenceCountedObjectPtr<ReferenceCountedObject> asyncUpdater;
SortedSet<Value*> valuesWithListeners;
private:
void handleAsyncUpdate() override;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValueSource)
};
@@ -210,8 +213,8 @@ public:
private:
//==============================================================================
friend class ValueSource;
ReferenceCountedObjectPtr <ValueSource> value;
ListenerList <Listener> listeners;
ReferenceCountedObjectPtr<ValueSource> value;
ListenerList<Listener> listeners;
void callListeners();


+ 2
- 2
libs/juce/source/modules/juce_events/broadcasters/juce_AsyncUpdater.h View File

@@ -68,8 +68,8 @@ public:
callback happens, this will cancel the handleAsyncUpdate() callback.
Note that this method simply cancels the next callback - if a callback is already
in progress on a different thread, this won't block until it finishes, so there's
no guarantee that the callback isn't still running when you return from
in progress on a different thread, this won't block until the callback finishes, so
there's no guarantee that the callback isn't still running when the method returns.
*/
void cancelPendingUpdate() noexcept;


+ 1
- 1
libs/juce/source/modules/juce_events/native/juce_win32_Messaging.cpp View File

@@ -100,7 +100,7 @@ bool MessageManager::dispatchNextMessageOnSystemQueue (const bool returnIfNoPend
using namespace WindowsMessageHelpers;
MSG m;
if (returnIfNoPendingMessages && ! PeekMessage (&m, (HWND) 0, 0, 0, 0))
if (returnIfNoPendingMessages && ! PeekMessage (&m, (HWND) 0, 0, 0, PM_NOREMOVE))
return false;
if (GetMessage (&m, (HWND) 0, 0, 0) >= 0)


+ 5
- 5
libs/juce/source/modules/juce_graphics/contexts/juce_GraphicsContext.cpp View File

@@ -438,14 +438,14 @@ void Graphics::drawRect (Rectangle<float> r, const float lineThickness) const
//==============================================================================
void Graphics::fillEllipse (const Rectangle<float>& area) const
{
fillEllipse (area.getX(), area.getY(), area.getWidth(), area.getHeight());
Path p;
p.addEllipse (area);
fillPath (p);
}
void Graphics::fillEllipse (float x, float y, float width, float height) const
void Graphics::fillEllipse (float x, float y, float w, float h) const
{
Path p;
p.addEllipse (x, y, width, height);
fillPath (p);
fillEllipse (Rectangle<float> (x, y, w, h));
}
void Graphics::drawEllipse (float x, float y, float width, float height, float lineThickness) const


+ 6
- 1
libs/juce/source/modules/juce_graphics/fonts/juce_CustomTypeface.h View File

@@ -52,6 +52,11 @@ public:
/** Loads a typeface from a previously saved stream.
The stream must have been created by writeToStream().
NOTE! Since this class was written, support was added for loading real font files from
memory, so for most people, using Typeface::createSystemTypefaceFor() to load a real font
is more appropriate than using this class to store it in a proprietary format.
@see writeToStream
*/
explicit CustomTypeface (InputStream& serialisedTypefaceStream);
@@ -116,7 +121,7 @@ public:
NOTE! Since this class was written, support was added for loading real font files from
memory, so for most people, using Typeface::createSystemTypefaceFor() to load a real font
is more appropriate than using this class to store it in a proprietory format.
is more appropriate than using this class to store it in a proprietary format.
*/
bool writeToStream (OutputStream& outputStream);


+ 4
- 4
libs/juce/source/modules/juce_graphics/fonts/juce_Font.h View File

@@ -169,7 +169,7 @@ public:
*/
static const String& getDefaultSansSerifFontName();
/** Returns a typeface font family that represents the default sans-serif font.
/** Returns a typeface font family that represents the default serif font.
Note that this method just returns a generic placeholder string that means "the default
serif font" - it's not the actual font family of this font.
@@ -178,7 +178,7 @@ public:
*/
static const String& getDefaultSerifFontName();
/** Returns a typeface font family that represents the default sans-serif font.
/** Returns a typeface font family that represents the default monospaced font.
Note that this method just returns a generic placeholder string that means "the default
monospaced font" - it's not the actual font family of this font.
@@ -187,10 +187,10 @@ public:
*/
static const String& getDefaultMonospacedFontName();
/** Returns a typeface font style that represents the default sans-serif font.
/** Returns a font style name that represents the default style.
Note that this method just returns a generic placeholder string that means "the default
font style" - it's not the actual font style of this font.
font style" - it's not the actual name of the font style of any particular font.
@see setTypefaceStyle
*/


+ 12
- 12
libs/juce/source/modules/juce_graphics/geometry/juce_Path.cpp View File

@@ -436,9 +436,7 @@ void Path::addRectangle (const float x, const float y,
data.elements [numElements++] = closeSubPathMarker;
}
void Path::addRoundedRectangle (const float x, const float y,
const float w, const float h,
float csx, float csy)
void Path::addRoundedRectangle (float x, float y, float w, float h, float csx, float csy)
{
addRoundedRectangle (x, y, w, h, csx, csy, true, true, true, true);
}
@@ -498,9 +496,7 @@ void Path::addRoundedRectangle (const float x, const float y, const float w, con
closeSubPath();
}
void Path::addRoundedRectangle (const float x, const float y,
const float w, const float h,
float cs)
void Path::addRoundedRectangle (float x, float y, float w, float h, float cs)
{
addRoundedRectangle (x, y, w, h, cs, cs);
}
@@ -527,15 +523,19 @@ void Path::addQuadrilateral (const float x1, const float y1,
closeSubPath();
}
void Path::addEllipse (const float x, const float y,
const float w, const float h)
void Path::addEllipse (float x, float y, float w, float h)
{
const float hw = w * 0.5f;
addEllipse (Rectangle<float> (x, y, w, h));
}
void Path::addEllipse (Rectangle<float> area)
{
const float hw = area.getWidth() * 0.5f;
const float hw55 = hw * 0.55f;
const float hh = h * 0.5f;
const float hh = area.getHeight() * 0.5f;
const float hh55 = hh * 0.55f;
const float cx = x + hw;
const float cy = y + hh;
const float cx = area.getX() + hw;
const float cy = area.getY() + hh;
startNewSubPath (cx, cy - hh);
cubicTo (cx + hw55, cy - hh, cx + hw, cy - hh55, cx + hw, cy);


+ 6
- 2
libs/juce/source/modules/juce_graphics/geometry/juce_Path.h View File

@@ -391,13 +391,17 @@ public:
float x4, float y4);
/** Adds an ellipse to the path.
The shape is added as a new sub-path. (Any currently open paths will be left open).
@see addArc
*/
void addEllipse (float x, float y, float width, float height);
/** Adds an ellipse to the path.
The shape is added as a new sub-path. (Any currently open paths will be left open).
@see addArc
*/
void addEllipse (Rectangle<float> area);
/** Adds an elliptical arc to the current path.
Note that when specifying the start and end angles, the curve will be drawn either clockwise


+ 38
- 2
libs/juce/source/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm View File

@@ -29,7 +29,7 @@ class CoreGraphicsImage : public ImagePixelData
{
public:
CoreGraphicsImage (const Image::PixelFormat format, const int w, const int h, const bool clearImage)
: ImagePixelData (format, w, h)
: ImagePixelData (format, w, h), cachedImageRef (0)
{
pixelStride = format == Image::RGB ? 3 : ((format == Image::ARGB) ? 4 : 1);
lineStride = (pixelStride * jmax (1, width) + 3) & ~3;
@@ -47,11 +47,13 @@ public:
~CoreGraphicsImage()
{
freeCachedImageRef();
CGContextRelease (context);
}
LowLevelGraphicsContext* createLowLevelContext() override
{
freeCachedImageRef();
sendDataChangeMessage();
return new CoreGraphicsContext (context, height, 1.0f);
}
@@ -64,7 +66,10 @@ public:
bitmap.pixelStride = pixelStride;
if (mode != Image::BitmapData::readOnly)
{
freeCachedImageRef();
sendDataChangeMessage();
}
}
ImagePixelData* clone() override
@@ -77,6 +82,27 @@ public:
ImageType* createType() const override { return new NativeImageType(); }
//==============================================================================
static CGImageRef getCachedImageRef (const Image& juceImage, CGColorSpaceRef colourSpace)
{
CoreGraphicsImage* const cgim = dynamic_cast<CoreGraphicsImage*> (juceImage.getPixelData());
if (cgim != nullptr && cgim->cachedImageRef != 0)
{
CGImageRetain (cgim->cachedImageRef);
return cgim->cachedImageRef;
}
CGImageRef ref = createImage (juceImage, colourSpace, false);
if (cgim != nullptr)
{
CGImageRetain (ref);
cgim->cachedImageRef = ref;
}
return ref;
}
static CGImageRef createImage (const Image& juceImage, CGColorSpaceRef colourSpace, const bool mustOutliveSource)
{
const Image::BitmapData srcData (juceImage, Image::BitmapData::readOnly);
@@ -106,10 +132,20 @@ public:
//==============================================================================
CGContextRef context;
CGImageRef cachedImageRef;
HeapBlock<uint8> imageData;
int pixelStride, lineStride;
private:
void freeCachedImageRef()
{
if (cachedImageRef != 0)
{
CGImageRelease (cachedImageRef);
cachedImageRef = 0;
}
}
static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format)
{
#if JUCE_BIG_ENDIAN
@@ -454,7 +490,7 @@ void CoreGraphicsContext::drawImage (const Image& sourceImage, const AffineTrans
{
const int iw = sourceImage.getWidth();
const int ih = sourceImage.getHeight();
CGImageRef image = CoreGraphicsImage::createImage (sourceImage, rgbColourSpace, false);
CGImageRef image = CoreGraphicsImage::getCachedImageRef (sourceImage, rgbColourSpace);
CGContextSaveGState (context);
CGContextSetAlpha (context, state->fillType.getOpacity());


+ 12
- 2
libs/juce/source/modules/juce_graphics/native/juce_mac_Fonts.mm View File

@@ -1280,15 +1280,25 @@ Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
}
#if JUCE_CORETEXT_AVAILABLE
static bool containsNoMemoryTypefaces (const AttributedString& text)
static bool canAllTypefacesBeUsedInLayout (const AttributedString& text)
{
const int numCharacterAttributes = text.getNumAttributes();
for (int i = 0; i < numCharacterAttributes; ++i)
{
if (const Font* const f = text.getAttribute (i)->getFont())
{
if (OSXTypeface* tf = dynamic_cast<OSXTypeface*> (f->getTypeface()))
{
if (tf->isMemoryFont)
return false;
}
else if (dynamic_cast<CustomTypeface*> (f->getTypeface()) != nullptr)
{
return false;
}
}
}
return true;
}
@@ -1299,7 +1309,7 @@ bool TextLayout::createNativeLayout (const AttributedString& text)
#if JUCE_CORETEXT_AVAILABLE
// Seems to be an unfathomable bug in CoreText which prevents the layout working with
// typefaces that were loaded from memory, so have to fallback if we hit any of those..
if (containsNoMemoryTypefaces (text))
if (canAllTypefacesBeUsedInLayout (text))
{
CoreTextTypeLayout::createLayout (*this, text);
return true;


+ 2
- 2
libs/juce/source/modules/juce_gui_basics/commands/juce_ApplicationCommandTarget.cpp View File

@@ -91,7 +91,7 @@ ApplicationCommandTarget* ApplicationCommandTarget::getTargetForCommand (const C
while (target != nullptr)
{
Array <CommandID> commandIDs;
Array<CommandID> commandIDs;
target->getAllCommands (commandIDs);
if (commandIDs.contains (commandID))
@@ -113,7 +113,7 @@ ApplicationCommandTarget* ApplicationCommandTarget::getTargetForCommand (const C
if (target != nullptr)
{
Array <CommandID> commandIDs;
Array<CommandID> commandIDs;
target->getAllCommands (commandIDs);
if (commandIDs.contains (commandID))


+ 1
- 1
libs/juce/source/modules/juce_gui_basics/commands/juce_ApplicationCommandTarget.h View File

@@ -134,7 +134,7 @@ public:
Your target should add all the command IDs that it handles to the array that is
passed-in.
*/
virtual void getAllCommands (Array <CommandID>& commands) = 0;
virtual void getAllCommands (Array<CommandID>& commands) = 0;
/** This must provide details about one of the commands that this target can perform.


+ 3
- 3
libs/juce/source/modules/juce_gui_basics/components/juce_Component.cpp View File

@@ -659,7 +659,7 @@ void Component::addToDesktop (int styleWanted, void* nativeWindowToAttachTo)
bool wasFullscreen = false;
bool wasMinimised = false;
ComponentBoundsConstrainer* currentConstainer = nullptr;
ComponentBoundsConstrainer* currentConstrainer = nullptr;
Rectangle<int> oldNonFullScreenBounds;
int oldRenderingEngine = -1;
@@ -669,7 +669,7 @@ void Component::addToDesktop (int styleWanted, void* nativeWindowToAttachTo)
wasFullscreen = peer->isFullScreen();
wasMinimised = peer->isMinimised();
currentConstainer = peer->getConstrainer();
currentConstrainer = peer->getConstrainer();
oldNonFullScreenBounds = peer->getNonFullScreenBounds();
oldRenderingEngine = peer->getCurrentRenderingEngine();
@@ -720,7 +720,7 @@ void Component::addToDesktop (int styleWanted, void* nativeWindowToAttachTo)
peer->setAlwaysOnTop (true);
#endif
peer->setConstrainer (currentConstainer);
peer->setConstrainer (currentConstrainer);
repaint();
internalHierarchyChanged();


+ 11
- 0
libs/juce/source/modules/juce_gui_basics/components/juce_ModalComponentManager.cpp View File

@@ -234,6 +234,17 @@ void ModalComponentManager::bringModalComponentsToFront (bool topOneShouldGrabFo
}
}
bool ModalComponentManager::cancelAllModalComponents()
{
const int numModal = getNumModalComponents();
for (int i = numModal; --i >= 0;)
if (Component* const c = getModalComponent(i))
c->exitModalState (0);
return numModal > 0;
}
#if JUCE_MODAL_LOOPS_PERMITTED
class ModalComponentManager::ReturnValueRetriever : public ModalComponentManager::Callback
{


+ 5
- 0
libs/juce/source/modules/juce_gui_basics/components/juce_ModalComponentManager.h View File

@@ -107,6 +107,11 @@ public:
/** Brings any modal components to the front. */
void bringModalComponentsToFront (bool topOneShouldGrabFocus = true);
/** Calls exitModalState (0) on any components that are currently modal.
@returns true if any components were modal; false if nothing needed cancelling
*/
bool cancelAllModalComponents();
#if JUCE_MODAL_LOOPS_PERMITTED
/** Runs the event loop until the currently topmost modal component is dismissed, and
returns the exit code for that component.


+ 5
- 0
libs/juce/source/modules/juce_gui_basics/drawables/juce_SVGParser.cpp View File

@@ -349,6 +349,11 @@ public:
if (! carryOn)
break;
}
// paths that finish back at their start position often seem to be
// left without a 'z', so need to be closed explicitly..
if (path.getCurrentPosition() == subpathStart)
path.closeSubPath();
}
private:


+ 1
- 1
libs/juce/source/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.cpp View File

@@ -203,7 +203,7 @@ void FileChooserDialogBox::okButtonPressed()
{
AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
TRANS("File already exists"),
TRANS("There's already a file called: FLMN")
TRANS("There's already a file called: FLNM")
.replace ("FLNM", content->chooserComponent.getSelectedFile(0).getFullPathName())
+ "\n\n"
+ TRANS("Are you sure you want to overwrite it?"),


+ 7
- 0
libs/juce/source/modules/juce_gui_basics/filebrowser/juce_FilenameComponent.cpp View File

@@ -68,6 +68,13 @@ void FilenameComponent::resized()
getLookAndFeel().layoutFilenameComponent (*this, &filenameBox, browseButton);
}
KeyboardFocusTraverser* FilenameComponent::createFocusTraverser()
{
// This prevents the sub-components from grabbing focus if the
// FilenameComponent has been set to refuse focus.
return getWantsKeyboardFocus() ? Component::createFocusTraverser() : nullptr;
}
void FilenameComponent::setBrowseButtonText (const String& newBrowseButtonText)
{
browseButtonText = newBrowseButtonText;


+ 2
- 0
libs/juce/source/modules/juce_gui_basics/filebrowser/juce_FilenameComponent.h View File

@@ -205,6 +205,8 @@ public:
void fileDragEnter (const StringArray&, int, int) override;
/** @internal */
void fileDragExit (const StringArray&) override;
/** @internal */
KeyboardFocusTraverser* createFocusTraverser() override;
private:
//==============================================================================


+ 17
- 0
libs/juce/source/modules/juce_gui_basics/keyboard/juce_TextInputTarget.h View File

@@ -71,6 +71,23 @@ public:
/** Returns the position of the caret, relative to the component's origin. */
virtual Rectangle<int> getCaretRectangle() = 0;
/** A set of possible on-screen keyboard types, for use in the
getKeyboardType() method.
*/
enum VirtualKeyboardType
{
textKeyboard = 0,
numericKeyboard,
urlKeyboard,
emailAddressKeyboard,
phoneNumberKeyboard
};
/** Returns the target's preference for the type of keyboard that would be most appropriate.
This may be ignored, depending on the capabilities of the OS.
*/
virtual VirtualKeyboardType getKeyboardType() { return textKeyboard; }
};


+ 6
- 9
libs/juce/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp View File

@@ -452,8 +452,7 @@ void LookAndFeel_V2::drawAlertBox (Graphics& g, AlertWindow& alert,
colour = alert.getAlertType() == AlertWindow::InfoIcon ? (uint32) 0x605555ff : (uint32) 0x40b69900;
character = alert.getAlertType() == AlertWindow::InfoIcon ? 'i' : '?';
icon.addEllipse ((float) iconRect.getX(), (float) iconRect.getY(),
(float) iconRect.getWidth(), (float) iconRect.getHeight());
icon.addEllipse (iconRect.toFloat());
}
GlyphArrangement ga;
@@ -1183,13 +1182,11 @@ void LookAndFeel_V2::drawLabel (Graphics& g, Label& label)
g.setColour (label.findColour (Label::textColourId).withMultipliedAlpha (alpha));
g.setFont (font);
g.drawFittedText (label.getText(),
label.getHorizontalBorderSize(),
label.getVerticalBorderSize(),
label.getWidth() - 2 * label.getHorizontalBorderSize(),
label.getHeight() - 2 * label.getVerticalBorderSize(),
label.getJustificationType(),
jmax (1, (int) (label.getHeight() / font.getHeight())),
Rectangle<int> textArea (label.getBorderSize().subtractedFrom (label.getLocalBounds()));
g.drawFittedText (label.getText(), textArea, label.getJustificationType(),
jmax (1, (int) (textArea.getHeight() / font.getHeight())),
label.getMinimumHorizontalScale());
g.setColour (label.findColour (Label::outlineColourId).withMultipliedAlpha (alpha));


+ 2
- 2
libs/juce/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V3.cpp View File

@@ -30,8 +30,8 @@ LookAndFeel_V3::LookAndFeel_V3()
setColour (TextButton::buttonColourId, textButtonColour);
setColour (ComboBox::buttonColourId, textButtonColour);
setColour (TextEditor::outlineColourId, Colours::transparentBlack);
setColour (TabbedButtonBar::tabOutlineColourId, Colour (0xff999999));
setColour (TabbedComponent::outlineColourId, Colour (0xff999999));
setColour (TabbedButtonBar::tabOutlineColourId, Colour (0x66000000));
setColour (TabbedComponent::outlineColourId, Colour (0x66000000));
setColour (Slider::trackColourId, Colour (0xbbffffff));
setColour (Slider::thumbColourId, Colour (0xffddddff));
setColour (BubbleComponent::backgroundColourId, Colour (0xeeeeeedd));


+ 2
- 2
libs/juce/source/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp View File

@@ -102,9 +102,9 @@ public:
//==============================================================================
#if JUCE_DUMP_MOUSE_EVENTS
#define JUCE_MOUSE_EVENT_DBG(desc) DBG ("Mouse " desc << " #" << source.getIndex() \
#define JUCE_MOUSE_EVENT_DBG(desc) DBG ("Mouse " << desc << " #" << index \
<< ": " << screenPosToLocalPos (comp, screenPos).toString() \
<< " - Comp: " << String::toHexString ((int) &comp));
<< " - Comp: " << String::toHexString ((pointer_sized_int) &comp));
#else
#define JUCE_MOUSE_EVENT_DBG(desc)
#endif


+ 20
- 4
libs/juce/source/modules/juce_gui_basics/native/juce_android_Windowing.cpp View File

@@ -91,7 +91,7 @@ DECLARE_JNI_CLASS (CanvasMinimal, "android/graphics/Canvas");
METHOD (hasFocus, "hasFocus", "()Z") \
METHOD (invalidate, "invalidate", "(IIII)V") \
METHOD (containsPoint, "containsPoint", "(II)Z") \
METHOD (showKeyboard, "showKeyboard", "(Z)V") \
METHOD (showKeyboard, "showKeyboard", "(Ljava/lang/String;)V") \
METHOD (createGLView, "createGLView", "()L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$OpenGLView;") \
DECLARE_JNI_CLASS (ComponentPeerView, JUCE_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView");
@@ -378,14 +378,30 @@ public:
handleFocusLoss();
}
void textInputRequired (const Point<int>&) override
static const char* getVirtualKeyboardType (TextInputTarget::VirtualKeyboardType type) noexcept
{
view.callVoidMethod (ComponentPeerView.showKeyboard, true);
switch (type)
{
case TextInputTarget::textKeyboard: return "text";
case TextInputTarget::numericKeyboard: return "number";
case TextInputTarget::urlKeyboard: return "textUri";
case TextInputTarget::emailAddressKeyboard: return "textEmailAddress";
case TextInputTarget::phoneNumberKeyboard: return "phone";
default: jassertfalse; break;
}
return "text";
}
void textInputRequired (Point<int>, TextInputTarget& target) override
{
view.callVoidMethod (ComponentPeerView.showKeyboard,
javaString (getVirtualKeyboardType (target.getKeyboardType())).get());
}
void dismissPendingTextInput() override
{
view.callVoidMethod (ComponentPeerView.showKeyboard, false);
view.callVoidMethod (ComponentPeerView.showKeyboard, javaString ("").get());
}
//==============================================================================


+ 23
- 6
libs/juce/source/modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm View File

@@ -168,7 +168,7 @@ public:
void viewFocusLoss();
bool isFocused() const override;
void grabFocus() override;
void textInputRequired (const Point<int>&) override;
void textInputRequired (Point<int>, TextInputTarget&) override;
BOOL textViewReplaceCharacters (Range<int>, const String&);
void updateHiddenTextContent (TextInputTarget*);
@@ -702,10 +702,7 @@ void UIViewComponentPeer::toFront (bool makeActiveWindow)
void UIViewComponentPeer::toBehind (ComponentPeer* other)
{
UIViewComponentPeer* const otherPeer = dynamic_cast <UIViewComponentPeer*> (other);
jassert (otherPeer != nullptr); // wrong type of window?
if (otherPeer != nullptr)
if (UIViewComponentPeer* const otherPeer = dynamic_cast<UIViewComponentPeer*> (other))
{
if (isSharedWindow)
{
@@ -716,6 +713,10 @@ void UIViewComponentPeer::toBehind (ComponentPeer* other)
// don't know how to do this
}
}
else
{
jassertfalse; // wrong type of window?
}
}
void UIViewComponentPeer::setIcon (const Image& /*newIcon*/)
@@ -828,12 +829,28 @@ void UIViewComponentPeer::grabFocus()
}
}
void UIViewComponentPeer::textInputRequired (const Point<int>&)
void UIViewComponentPeer::textInputRequired (Point<int>, TextInputTarget&)
{
}
static UIKeyboardType getUIKeyboardType (TextInputTarget::VirtualKeyboardType type) noexcept
{
switch (type)
{
case TextInputTarget::textKeyboard: return UIKeyboardTypeAlphabet;
case TextInputTarget::numericKeyboard: return UIKeyboardTypeNumbersAndPunctuation;
case TextInputTarget::urlKeyboard: return UIKeyboardTypeURL;
case TextInputTarget::emailAddressKeyboard: return UIKeyboardTypeEmailAddress;
case TextInputTarget::phoneNumberKeyboard: return UIKeyboardTypePhonePad;
default: jassertfalse; break;
}
return UIKeyboardTypeDefault;
}
void UIViewComponentPeer::updateHiddenTextContent (TextInputTarget* target)
{
view->hiddenTextView.keyboardType = getUIKeyboardType (target->getKeyboardType());
view->hiddenTextView.text = juceStringToNS (target->getTextInRange (Range<int> (0, target->getHighlightedRegion().getStart())));
view->hiddenTextView.selectedRange = NSMakeRange (target->getHighlightedRegion().getStart(), 0);
}


+ 1
- 1
libs/juce/source/modules/juce_gui_basics/native/juce_ios_Windowing.mm View File

@@ -189,7 +189,7 @@ private:
- (void) alertView: (UIAlertView*) alertView clickedButtonAtIndex: (NSInteger) buttonIndex
{
owner->buttonClicked (buttonIndex);
owner->buttonClicked ((int) buttonIndex);
alertView.hidden = true;
}


+ 5
- 3
libs/juce/source/modules/juce_gui_basics/native/juce_linux_Windowing.cpp View File

@@ -1217,7 +1217,7 @@ public:
}
}
void textInputRequired (const Point<int>&) override {}
void textInputRequired (Point<int>, TextInputTarget&) override {}
void repaint (const Rectangle<int>& area) override
{
@@ -1327,6 +1327,7 @@ public:
default:
#if JUCE_USE_XSHM
if (XSHMHelpers::isShmAvailable())
{
ScopedXLock xlock;
if (event.xany.type == XShmGetEventBase (display))
@@ -1902,7 +1903,8 @@ private:
for (const Rectangle<int>* i = originalRepaintRegion.begin(), * const e = originalRepaintRegion.end(); i != e; ++i)
{
#if JUCE_USE_XSHM
++shmPaintsPending;
if (XSHMHelpers::isShmAvailable())
++shmPaintsPending;
#endif
static_cast<XBitmapImage*> (image.getPixelData())
@@ -3045,7 +3047,7 @@ void Desktop::Displays::findDisplays (float masterScale)
screens[j].height) * masterScale;
d.isMain = (index == 0);
d.scale = masterScale;
d.dpi = getDisplayDPI (index);
d.dpi = getDisplayDPI (0); // (all screens share the same DPI)
displays.add (d);
}


+ 2
- 3
libs/juce/source/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm View File

@@ -1136,8 +1136,7 @@ public:
bool isFocused() const override
{
return isSharedWindow ? this == currentlyFocusedPeer
: [window isKeyWindow];
return this == currentlyFocusedPeer;
}
void grabFocus() override
@@ -1151,7 +1150,7 @@ public:
}
}
void textInputRequired (const Point<int>&) override {}
void textInputRequired (Point<int>, TextInputTarget&) override {}
//==============================================================================
void repaint (const Rectangle<int>& area) override


+ 10
- 5
libs/juce/source/modules/juce_gui_basics/native/juce_win32_Windowing.cpp View File

@@ -877,7 +877,7 @@ public:
shouldDeactivateTitleBar = oldDeactivate;
}
void textInputRequired (const Point<int>&) override
void textInputRequired (Point<int>, TextInputTarget&) override
{
if (! hasCreatedCaret)
{
@@ -902,10 +902,15 @@ public:
void performAnyPendingRepaintsNow() override
{
MSG m;
if (component.isVisible()
&& (PeekMessage (&m, hwnd, WM_PAINT, WM_PAINT, PM_REMOVE) || isUsingUpdateLayeredWindow()))
handlePaintMessage();
if (component.isVisible())
{
WeakReference<Component> localRef (&component);
MSG m;
if (isUsingUpdateLayeredWindow() || PeekMessage (&m, hwnd, WM_PAINT, WM_PAINT, PM_REMOVE))
if (localRef != nullptr) // (the PeekMessage call can dispatch messages, which may delete this comp)
handlePaintMessage();
}
}
//==============================================================================


+ 1
- 1
libs/juce/source/modules/juce_gui_basics/properties/juce_ChoicePropertyComponent.cpp View File

@@ -74,7 +74,7 @@ ChoicePropertyComponent::ChoicePropertyComponent (const String& name)
ChoicePropertyComponent::ChoicePropertyComponent (const Value& valueToControl,
const String& name,
const StringArray& choiceList,
const Array <var>& correspondingValues)
const Array<var>& correspondingValues)
: PropertyComponent (name),
choices (choiceList),
isCustomClass (false)


+ 1
- 1
libs/juce/source/modules/juce_gui_basics/properties/juce_ChoicePropertyComponent.h View File

@@ -70,7 +70,7 @@ public:
ChoicePropertyComponent (const Value& valueToControl,
const String& propertyName,
const StringArray& choices,
const Array <var>& correspondingValues);
const Array<var>& correspondingValues);
/** Destructor. */
~ChoicePropertyComponent();


+ 12
- 7
libs/juce/source/modules/juce_gui_basics/widgets/juce_ComboBox.cpp View File

@@ -49,7 +49,7 @@ ComboBox::ComboBox (const String& name)
noChoicesMessage (TRANS("(no choices)"))
{
setRepaintsOnMouseActivity (true);
ComboBox::lookAndFeelChanged();
lookAndFeelChanged();
currentId.addListener (this);
}
@@ -410,12 +410,22 @@ void ComboBox::enablementChanged()
repaint();
}
void ComboBox::colourChanged()
{
lookAndFeelChanged();
}
void ComboBox::parentHierarchyChanged()
{
lookAndFeelChanged();
}
void ComboBox::lookAndFeelChanged()
{
repaint();
{
ScopedPointer <Label> newLabel (getLookAndFeel().createComboBoxTextBox (*this));
ScopedPointer<Label> newLabel (getLookAndFeel().createComboBoxTextBox (*this));
jassert (newLabel != nullptr);
if (label != nullptr)
@@ -446,11 +456,6 @@ void ComboBox::lookAndFeelChanged()
resized();
}
void ComboBox::colourChanged()
{
lookAndFeelChanged();
}
//==============================================================================
bool ComboBox::keyPressed (const KeyPress& key)
{


+ 2
- 0
libs/juce/source/modules/juce_gui_basics/widgets/juce_ComboBox.h View File

@@ -393,6 +393,8 @@ public:
bool keyPressed (const KeyPress&) override;
/** @internal */
void valueChanged (Value&) override;
/** @internal */
void parentHierarchyChanged() override;
// These methods' bool parameters have changed: see their new method signatures.
JUCE_DEPRECATED (void clear (bool));


+ 13
- 8
libs/juce/source/modules/juce_gui_basics/widgets/juce_Label.cpp View File

@@ -28,8 +28,7 @@ Label::Label (const String& name, const String& labelText)
lastTextValue (labelText),
font (15.0f),
justification (Justification::centredLeft),
horizontalBorderSize (5),
verticalBorderSize (1),
border (1, 5, 1, 5),
minimumHorizontalScale (0.7f),
editSingleClick (false),
editDoubleClick (false),
@@ -123,12 +122,11 @@ void Label::setJustificationType (Justification newJustification)
}
}
void Label::setBorderSize (int h, int v)
void Label::setBorderSize (BorderSize<int> newBorder)
{
if (horizontalBorderSize != h || verticalBorderSize != v)
if (border != newBorder)
{
horizontalBorderSize = h;
verticalBorderSize = v;
border = newBorder;
repaint();
}
}
@@ -191,7 +189,12 @@ void Label::componentVisibilityChanged (Component& component)
//==============================================================================
void Label::textWasEdited() {}
void Label::textWasChanged() {}
void Label::editorShown (TextEditor*) {}
void Label::editorShown (TextEditor* textEditor)
{
Component::BailOutChecker checker (this);
listeners.callChecked (checker, &LabelListener::editorShown, this, *textEditor);
}
void Label::editorAboutToBeHidden (TextEditor*)
{
@@ -325,7 +328,7 @@ void Label::mouseDoubleClick (const MouseEvent& e)
void Label::resized()
{
if (editor != nullptr)
editor->setBoundsInset (BorderSize<int> (0));
editor->setBounds (getLocalBounds());
}
void Label::focusGained (FocusChangeType cause)
@@ -446,3 +449,5 @@ void Label::textEditorFocusLost (TextEditor& ed)
{
textEditorTextChanged (ed);
}
void Label::Listener::editorShown (Label*, TextEditor&) {}

+ 14
- 15
libs/juce/source/modules/juce_gui_basics/widgets/juce_Label.h View File

@@ -74,7 +74,7 @@ public:
You can call Value::referTo() on this object to make the label read and control
a Value object that you supply.
*/
Value& getTextValue() { return textValue; }
Value& getTextValue() noexcept { return textValue; }
//==============================================================================
/** Changes the font to use to draw the text.
@@ -109,25 +109,21 @@ public:
//==============================================================================
/** Sets the style of justification to be used for positioning the text.
(The default is Justification::centredLeft)
*/
void setJustificationType (Justification justification);
/** Returns the type of justification, as set in setJustificationType(). */
Justification getJustificationType() const noexcept { return justification; }
Justification getJustificationType() const noexcept { return justification; }
/** Changes the gap that is left between the edge of the component and the text.
/** Changes the border that is left between the edge of the component and the text.
By default there's a small gap left at the sides of the component to allow for
the drawing of the border, but you can change this if necessary.
*/
void setBorderSize (int horizontalBorder, int verticalBorder);
/** Returns the size of the horizontal gap being left around the text. */
int getHorizontalBorderSize() const noexcept { return horizontalBorderSize; }
void setBorderSize (BorderSize<int> newBorderSize);
/** Returns the size of the vertical gap being left around the text. */
int getVerticalBorderSize() const noexcept { return verticalBorderSize; }
/** Returns the size of the border to be left around the text. */
BorderSize<int> getBorderSize() const noexcept { return border; }
/** Makes this label "stick to" another component.
@@ -152,16 +148,17 @@ public:
Returns false if the label is above the other component. This is only relevent if
attachToComponent() has been called.
*/
bool isAttachedOnLeft() const noexcept { return leftOfOwnerComp; }
bool isAttachedOnLeft() const noexcept { return leftOfOwnerComp; }
/** Specifies the minimum amount that the font can be squashed horizantally before it starts
/** Specifies the minimum amount that the font can be squashed horizontally before it starts
using ellipsis.
@see Graphics::drawFittedText
*/
void setMinimumHorizontalScale (float newScale);
float getMinimumHorizontalScale() const noexcept { return minimumHorizontalScale; }
/** Specifies the amount that the font can be squashed horizontally. */
float getMinimumHorizontalScale() const noexcept { return minimumHorizontalScale; }
//==============================================================================
/**
@@ -182,6 +179,9 @@ public:
/** Called when a Label's text has changed. */
virtual void labelTextChanged (Label* labelThatHasChanged) = 0;
/** Called when a Label goes into editing mode and displays a TextEditor. */
virtual void editorShown (Label*, TextEditor& textEditorShown);
};
/** Registers a listener that will be called when the label's text changes. */
@@ -228,7 +228,6 @@ public:
bool isEditable() const noexcept { return editSingleClick || editDoubleClick; }
/** Makes the editor appear as if the label had been clicked by the user.
@see textWasEdited, setEditable
*/
void showEditor();
@@ -327,7 +326,7 @@ private:
ScopedPointer<TextEditor> editor;
ListenerList<Listener> listeners;
WeakReference<Component> ownerComponent;
int horizontalBorderSize, verticalBorderSize;
BorderSize<int> border;
float minimumHorizontalScale;
bool editSingleClick;
bool editDoubleClick;


+ 1
- 1
libs/juce/source/modules/juce_gui_basics/widgets/juce_TableHeaderComponent.cpp View File

@@ -623,7 +623,7 @@ void TableHeaderComponent::mouseDrag (const MouseEvent& e)
minWidthOnRight += columns.getUnchecked (i)->minimumWidth;
const Rectangle<int> currentPos (getColumnPosition (getIndexOfColumnId (columnIdBeingResized, true)));
w = jmax (ci->minimumWidth, jmin (w, getWidth() - minWidthOnRight - currentPos.getX()));
w = jmax (ci->minimumWidth, jmin (w, lastDeliberateWidth - minWidthOnRight - currentPos.getX()));
}
setColumnWidth (columnIdBeingResized, w);


+ 1
- 1
libs/juce/source/modules/juce_gui_basics/widgets/juce_TextEditor.cpp View File

@@ -2059,7 +2059,7 @@ void TextEditor::focusGained (FocusChangeType)
if (ComponentPeer* const peer = getPeer())
if (! isReadOnly())
peer->textInputRequired (peer->globalToLocal (getScreenPosition()));
peer->textInputRequired (peer->globalToLocal (getScreenPosition()), *this);
}
void TextEditor::focusLost (FocusChangeType)


+ 3
- 0
libs/juce/source/modules/juce_gui_basics/widgets/juce_TextEditor.h View File

@@ -568,6 +568,9 @@ public:
*/
void setInputFilter (InputFilter* newFilter, bool takeOwnership);
/** Returns the current InputFilter, as set by setInputFilter(). */
InputFilter* getInputFilter() const noexcept { return inputFilter; }
/** Sets limits on the characters that can be entered.
This is just a shortcut that passes an instance of the LengthAndCharacterRestriction
class to setInputFilter().


+ 1
- 1
libs/juce/source/modules/juce_gui_basics/windows/juce_ComponentPeer.h View File

@@ -276,7 +276,7 @@ public:
This may cause things like a virtual on-screen keyboard to appear, depending
on the OS.
*/
virtual void textInputRequired (const Point<int>& position) = 0;
virtual void textInputRequired (Point<int> position, TextInputTarget&) = 0;
/** If there's some kind of OS input-method in progress, this should dismiss it. */
virtual void dismissPendingTextInput();


+ 31
- 31
libs/juce/source/modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp View File

@@ -27,7 +27,6 @@ class TopLevelWindowManager : private Timer,
private DeletedAtShutdown
{
public:
//==============================================================================
TopLevelWindowManager() : currentActive (nullptr)
{
}
@@ -48,33 +47,15 @@ public:
{
startTimer (jmin (1731, getTimerInterval() * 2));
TopLevelWindow* active = nullptr;
TopLevelWindow* newActive = findCurrentlyActiveWindow();
if (Process::isForegroundProcess())
{
active = currentActive;
Component* const c = Component::getCurrentlyFocusedComponent();
TopLevelWindow* tlw = dynamic_cast <TopLevelWindow*> (c);
if (tlw == nullptr && c != nullptr)
tlw = c->findParentComponentOfClass<TopLevelWindow>();
if (tlw != nullptr)
active = tlw;
}
if (active != currentActive)
if (newActive != currentActive)
{
currentActive = active;
currentActive = newActive;
for (int i = windows.size(); --i >= 0;)
{
TopLevelWindow* const tlw = windows.getUnchecked (i);
tlw->setWindowActive (isWindowActive (tlw));
i = jmin (i, windows.size() - 1);
}
if (TopLevelWindow* tlw = windows[i])
tlw->setWindowActive (isWindowActive (tlw));
Desktop::getInstance().triggerFocusCallback();
}
@@ -101,7 +82,7 @@ public:
deleteInstance();
}
Array <TopLevelWindow*> windows;
Array<TopLevelWindow*> windows;
private:
TopLevelWindow* currentActive;
@@ -119,6 +100,26 @@ private:
&& tlw->isShowing();
}
TopLevelWindow* findCurrentlyActiveWindow() const
{
if (Process::isForegroundProcess())
{
Component* const focusedComp = Component::getCurrentlyFocusedComponent();
TopLevelWindow* w = dynamic_cast<TopLevelWindow*> (focusedComp);
if (w == nullptr && focusedComp != nullptr)
w = focusedComp->findParentComponentOfClass<TopLevelWindow>();
if (w == nullptr)
w = currentActive;
if (w != nullptr && w->isShowing())
return w;
}
return nullptr;
}
JUCE_DECLARE_NON_COPYABLE (TopLevelWindowManager)
};
@@ -187,12 +188,11 @@ bool TopLevelWindow::isUsingNativeTitleBar() const noexcept
void TopLevelWindow::visibilityChanged()
{
if (isShowing()
&& (getPeer()->getStyleFlags() & (ComponentPeer::windowIsTemporary
| ComponentPeer::windowIgnoresKeyPresses)) == 0)
{
toFront (true);
}
if (isShowing())
if (ComponentPeer* p = getPeer())
if ((p->getStyleFlags() & (ComponentPeer::windowIsTemporary
| ComponentPeer::windowIgnoresKeyPresses)) == 0)
toFront (true);
}
void TopLevelWindow::parentHierarchyChanged()


+ 1
- 1
libs/juce/source/modules/juce_gui_basics/windows/juce_TopLevelWindow.h View File

@@ -155,7 +155,7 @@ private:
bool useDropShadow, useNativeTitleBar, isCurrentlyActive;
ScopedPointer<DropShadower> shadower;
void setWindowActive (bool isNowActive);
void setWindowActive (bool);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TopLevelWindow)
};


+ 1
- 1
libs/juce/source/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp View File

@@ -1645,7 +1645,7 @@ void CodeEditorComponent::State::restoreState (CodeEditorComponent& editor) cons
CodeEditorComponent::State::State (const String& s)
{
StringArray tokens;
tokens.addTokens (s, ":", String::empty);
tokens.addTokens (s, ":", StringRef());
lastTopLine = tokens[0].getIntValue();
lastCaretPos = tokens[1].getIntValue();


+ 1
- 1
libs/juce/source/modules/juce_gui_extra/documents/juce_FileBasedDocument.cpp View File

@@ -119,7 +119,7 @@ static bool askToOverwriteFile (const File& newFile)
{
return AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
TRANS("File already exists"),
TRANS("There's already a file called: FLMN")
TRANS("There's already a file called: FLNM")
.replace ("FLNM", newFile.getFullPathName())
+ "\n\n"
+ TRANS("Are you sure you want to overwrite it?"),


+ 1
- 1
libs/juce/source/modules/juce_gui_extra/misc/juce_LiveConstantEditor.h View File

@@ -288,7 +288,7 @@ namespace LiveConstantEditor
@endcode
*/
#define JUCE_LIVE_CONSTANT(initialValue) \
(LiveConstantEditor::getValue (__FILE__, __LINE__ - 1, initialValue))
(juce::LiveConstantEditor::getValue (__FILE__, __LINE__ - 1, initialValue))
#else
#define JUCE_LIVE_CONSTANT(initialValue) \
(initialValue)


Loading…
Cancel
Save