diff --git a/Builds/MacOSX/Dexed.xcodeproj/project.pbxproj b/Builds/MacOSX/Dexed.xcodeproj/project.pbxproj index ba6efd2..4472db1 100644 --- a/Builds/MacOSX/Dexed.xcodeproj/project.pbxproj +++ b/Builds/MacOSX/Dexed.xcodeproj/project.pbxproj @@ -58,6 +58,8 @@ E293B9570C97E4BAD129D4A2 = { isa = PBXBuildFile; fileRef = FE39DD2B654DF778D919D554; }; A6E2908774D7F669F21B1874 = { isa = PBXBuildFile; fileRef = C7C6039A52C3EE370CA9E73A; }; B82FDEB3E53C9455BC6A5DAE = { isa = PBXBuildFile; fileRef = EAA5D8078BCC042BDF94C77A; settings = {COMPILER_FLAGS = "-w"; }; }; + 52C0C94470D90310AF2F8433 = { isa = PBXBuildFile; fileRef = D0178A36F6E46F92111E4883; }; + 13F8BF7C26D50908163425CF = { isa = PBXBuildFile; fileRef = 01EF232D8B427B8CE38127C2; }; 00C044DBB8BA1AF35CBC42E6 = { isa = PBXBuildFile; fileRef = D6C6FCBA5ECA257959BFE674; }; E8D9A2B640A87FE92D2DA887 = { isa = PBXBuildFile; fileRef = F6F950B6ABB40B62AE4C0B78; }; 001A2BCC899370ADC99A8F3A = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_FileChooser.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_FileChooser.h"; sourceTree = "SOURCE_ROOT"; }; @@ -65,6 +67,7 @@ 00FDFD1ABE59B4CEF74BF5A3 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = env.cc; path = ../../Source/msfa/env.cc; sourceTree = "SOURCE_ROOT"; }; 015FE0A32C2B3FDA879FAB57 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_DragAndDropContainer.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/mouse/juce_DragAndDropContainer.h"; sourceTree = "SOURCE_ROOT"; }; 018D0FB9E97B68D2EB3E3F72 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = PluginEditor.cpp; path = ../../Source/PluginEditor.cpp; sourceTree = "SOURCE_ROOT"; }; + 01EF232D8B427B8CE38127C2 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_VST3_Wrapper.mm"; path = "../../JuceLibraryCode/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.mm"; sourceTree = "SOURCE_ROOT"; }; 02139A14E2732DE36631414F = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_TableHeaderComponent.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/widgets/juce_TableHeaderComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; 0236A082C107280C1505021A = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ImageConvolutionKernel.h"; path = "../../JuceLibraryCode/modules/juce_graphics/images/juce_ImageConvolutionKernel.h"; sourceTree = "SOURCE_ROOT"; }; 02E962E65624D43B0906B0C6 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_PerformanceCounter.cpp"; path = "../../JuceLibraryCode/modules/juce_core/time/juce_PerformanceCounter.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -84,6 +87,7 @@ 06C4DD7797E7526DB1B47AE5 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_IPAddress.cpp"; path = "../../JuceLibraryCode/modules/juce_core/network/juce_IPAddress.cpp"; sourceTree = "SOURCE_ROOT"; }; 07037505B34930CDA76B04A5 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_StretchableObjectResizer.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/layout/juce_StretchableObjectResizer.cpp"; sourceTree = "SOURCE_ROOT"; }; 0707C87B401DC983E3FF4263 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MathsFunctions.h"; path = "../../JuceLibraryCode/modules/juce_core/maths/juce_MathsFunctions.h"; sourceTree = "SOURCE_ROOT"; }; + 07333A7932C6B7538F4DF21F = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_VST3Headers.h"; path = "../../JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3Headers.h"; sourceTree = "SOURCE_ROOT"; }; 0733471B6DA02299D2C9590A = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_StringArray.cpp"; path = "../../JuceLibraryCode/modules/juce_core/text/juce_StringArray.cpp"; sourceTree = "SOURCE_ROOT"; }; 075BB641199B15A84856DE6E = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_SliderPropertyComponent.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/properties/juce_SliderPropertyComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; 076C4F22CCC47AFEAC2D0C68 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_LuaCodeTokeniser.h"; path = "../../JuceLibraryCode/modules/juce_gui_extra/code_editor/juce_LuaCodeTokeniser.h"; sourceTree = "SOURCE_ROOT"; }; @@ -127,6 +131,7 @@ 170F06D00B2197E66300D558 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_TextPropertyComponent.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/properties/juce_TextPropertyComponent.h"; sourceTree = "SOURCE_ROOT"; }; 1754400A2E372510CB25043F = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_TopLevelWindow.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/windows/juce_TopLevelWindow.h"; sourceTree = "SOURCE_ROOT"; }; 1756BAFDC82F5E69704BEAFE = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ComponentMovementWatcher.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/layout/juce_ComponentMovementWatcher.cpp"; sourceTree = "SOURCE_ROOT"; }; + 17A328AD02B5D7DA362E1D5D = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ConnectedChildProcess.cpp"; path = "../../JuceLibraryCode/modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp"; sourceTree = "SOURCE_ROOT"; }; 17C3024C2A1EE03BC0ED9C96 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_mac_Windowing.mm"; path = "../../JuceLibraryCode/modules/juce_gui_basics/native/juce_mac_Windowing.mm"; sourceTree = "SOURCE_ROOT"; }; 17ED00953353016B7E7492B0 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ApplicationCommandInfo.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/commands/juce_ApplicationCommandInfo.cpp"; sourceTree = "SOURCE_ROOT"; }; 18AD1662D33E576F96C30A6A = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_TopLevelWindow.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -197,6 +202,7 @@ 2B455841042E415B99DEE263 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_SpinLock.h"; path = "../../JuceLibraryCode/modules/juce_core/threads/juce_SpinLock.h"; sourceTree = "SOURCE_ROOT"; }; 2BAC9F6B6869D1E85C51540B = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Expression.h"; path = "../../JuceLibraryCode/modules/juce_core/maths/juce_Expression.h"; sourceTree = "SOURCE_ROOT"; }; 2BEBDED2BACDEEEE975583F3 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_StringPool.h"; path = "../../JuceLibraryCode/modules/juce_core/text/juce_StringPool.h"; sourceTree = "SOURCE_ROOT"; }; + 2C65FDA74486C92DF5EA5C87 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_FileFilter.h"; path = "../../JuceLibraryCode/modules/juce_core/files/juce_FileFilter.h"; sourceTree = "SOURCE_ROOT"; }; 2CA19470CA427333F8CAC0A5 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ImagePreviewComponent.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_ImagePreviewComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; 2CB4C73C121FCDEF65CBAC79 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_mac_MainMenu.mm"; path = "../../JuceLibraryCode/modules/juce_gui_basics/native/juce_mac_MainMenu.mm"; sourceTree = "SOURCE_ROOT"; }; 2D26E2304C0F6FC633936014 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = lfo.cc; path = ../../Source/msfa/lfo.cc; sourceTree = "SOURCE_ROOT"; }; @@ -235,7 +241,6 @@ 3444F7C54161FEB1F844619E = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_IPAddress.h"; path = "../../JuceLibraryCode/modules/juce_core/network/juce_IPAddress.h"; sourceTree = "SOURCE_ROOT"; }; 346937AF08405CC63D570161 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_FileBasedDocument.h"; path = "../../JuceLibraryCode/modules/juce_gui_extra/documents/juce_FileBasedDocument.h"; sourceTree = "SOURCE_ROOT"; }; 349B7AFA001B78E62A9AFABB = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_KeyListener.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/keyboard/juce_KeyListener.cpp"; sourceTree = "SOURCE_ROOT"; }; - 35865817C4ED48DCD346B5D9 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_WildcardFileFilter.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_WildcardFileFilter.cpp"; sourceTree = "SOURCE_ROOT"; }; 35892C1EF9CEA7C1F1C9109F = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_TabbedComponent.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/layout/juce_TabbedComponent.h"; sourceTree = "SOURCE_ROOT"; }; 3597896505C601CE1FFE1158 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ApplicationCommandManager.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.h"; sourceTree = "SOURCE_ROOT"; }; 35F80132DF4DC3669B44BD4A = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_LowLevelGraphicsPostScriptRenderer.h"; path = "../../JuceLibraryCode/modules/juce_graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.h"; sourceTree = "SOURCE_ROOT"; }; @@ -270,6 +275,7 @@ 4051235A3DA7534A8E1286F0 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ComponentDragger.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/mouse/juce_ComponentDragger.h"; sourceTree = "SOURCE_ROOT"; }; 40ACF762CE264F32184C4F7D = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_HighResolutionTimer.cpp"; path = "../../JuceLibraryCode/modules/juce_core/threads/juce_HighResolutionTimer.cpp"; sourceTree = "SOURCE_ROOT"; }; 40D83B00A8BBE334104EB694 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_RectangleList.h"; path = "../../JuceLibraryCode/modules/juce_graphics/geometry/juce_RectangleList.h"; sourceTree = "SOURCE_ROOT"; }; + 40DCD07DB4B1D9FBB9D47BE5 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ConnectedChildProcess.h"; path = "../../JuceLibraryCode/modules/juce_events/interprocess/juce_ConnectedChildProcess.h"; sourceTree = "SOURCE_ROOT"; }; 413E92912A2C8CACB46AFD3B = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_SliderPropertyComponent.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/properties/juce_SliderPropertyComponent.h"; sourceTree = "SOURCE_ROOT"; }; 4166468539A5F6E92A7A153E = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ReferenceCountedArray.h"; path = "../../JuceLibraryCode/modules/juce_core/containers/juce_ReferenceCountedArray.h"; sourceTree = "SOURCE_ROOT"; }; 41700CC92AEEF157D3B53BA2 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Drawable.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/drawables/juce_Drawable.h"; sourceTree = "SOURCE_ROOT"; }; @@ -297,7 +303,6 @@ 462B768DFC2129F54233D51D = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_StretchableLayoutResizerBar.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/layout/juce_StretchableLayoutResizerBar.h"; sourceTree = "SOURCE_ROOT"; }; 46908987EEFC3623A53A95C2 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_LagrangeInterpolator.cpp"; path = "../../JuceLibraryCode/modules/juce_audio_basics/effects/juce_LagrangeInterpolator.cpp"; sourceTree = "SOURCE_ROOT"; }; 46969E6B78BC89383358DCDA = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_XMLCodeTokeniser.h"; path = "../../JuceLibraryCode/modules/juce_gui_extra/code_editor/juce_XMLCodeTokeniser.h"; sourceTree = "SOURCE_ROOT"; }; - 46B8FB88F2949700DD70A821 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_WildcardFileFilter.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_WildcardFileFilter.h"; sourceTree = "SOURCE_ROOT"; }; 46C20298CCB469481F5C8D36 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MouseInactivityDetector.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/mouse/juce_MouseInactivityDetector.h"; sourceTree = "SOURCE_ROOT"; }; 4710CA869326390AF0CE2A0B = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ResizableEdgeComponent.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/layout/juce_ResizableEdgeComponent.h"; sourceTree = "SOURCE_ROOT"; }; 47168956BF1BAC3FCBD55BB8 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_posix_NamedPipe.cpp"; path = "../../JuceLibraryCode/modules/juce_core/native/juce_posix_NamedPipe.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -446,7 +451,6 @@ 7936BBAA586387B2FAFB958B = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = PluginData.cpp; path = ../../Source/PluginData.cpp; sourceTree = "SOURCE_ROOT"; }; 7A0FB6545BA2E344A1F45EA5 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Decibels.h"; path = "../../JuceLibraryCode/modules/juce_audio_basics/effects/juce_Decibels.h"; sourceTree = "SOURCE_ROOT"; }; 7A26D67672786E0663369D49 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_IIRFilterAudioSource.cpp"; path = "../../JuceLibraryCode/modules/juce_audio_basics/sources/juce_IIRFilterAudioSource.cpp"; sourceTree = "SOURCE_ROOT"; }; - 7A38190CB0652B0EBA02100C = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_FileFilter.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_FileFilter.cpp"; sourceTree = "SOURCE_ROOT"; }; 7A739B1B4B833A4668904CA6 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ReferenceCountedObject.h"; path = "../../JuceLibraryCode/modules/juce_core/memory/juce_ReferenceCountedObject.h"; sourceTree = "SOURCE_ROOT"; }; 7A854175B4E6D35ABB7D4E45 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_URL.h"; path = "../../JuceLibraryCode/modules/juce_core/network/juce_URL.h"; sourceTree = "SOURCE_ROOT"; }; 7A905E3EE096DAA1D7BA7ABD = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_TabbedButtonBar.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/layout/juce_TabbedButtonBar.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -456,8 +460,10 @@ 7C2634F55C78A3822A661CE2 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_XmlElement.cpp"; path = "../../JuceLibraryCode/modules/juce_core/xml/juce_XmlElement.cpp"; sourceTree = "SOURCE_ROOT"; }; 7CDDAFACA226D14742566EE3 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_StringPairArray.cpp"; path = "../../JuceLibraryCode/modules/juce_core/text/juce_StringPairArray.cpp"; sourceTree = "SOURCE_ROOT"; }; 7D5E3634F29C83FE1216E5EC = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_DragAndDropContainer.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/mouse/juce_DragAndDropContainer.cpp"; sourceTree = "SOURCE_ROOT"; }; + 7DC83451FCA10947AC92EBBC = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_VST3Common.h"; path = "../../JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3Common.h"; sourceTree = "SOURCE_ROOT"; }; 7E68BB771E88E0A2A323D365 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_CPlusPlusCodeTokeniser.h"; path = "../../JuceLibraryCode/modules/juce_gui_extra/code_editor/juce_CPlusPlusCodeTokeniser.h"; sourceTree = "SOURCE_ROOT"; }; 7EC7AB8D0C164E19F70A4D8C = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ModifierKeys.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/keyboard/juce_ModifierKeys.h"; sourceTree = "SOURCE_ROOT"; }; + 7ECA74A2FC82F26715446C70 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_FileFilter.cpp"; path = "../../JuceLibraryCode/modules/juce_core/files/juce_FileFilter.cpp"; sourceTree = "SOURCE_ROOT"; }; 7F081876B753390FC305329F = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_Thread.cpp"; path = "../../JuceLibraryCode/modules/juce_core/threads/juce_Thread.cpp"; sourceTree = "SOURCE_ROOT"; }; 7F0B06EA0B38D4555CFEBA61 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MemoryBlock.h"; path = "../../JuceLibraryCode/modules/juce_core/memory/juce_MemoryBlock.h"; sourceTree = "SOURCE_ROOT"; }; 7F63546442D6681E7AA27CB8 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_KeyPress.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/keyboard/juce_KeyPress.h"; sourceTree = "SOURCE_ROOT"; }; @@ -467,6 +473,7 @@ 80153220EFB623D6F205FD1B = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_MenuBarComponent.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/menus/juce_MenuBarComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; 8141C52E88E3E82A0A226FAD = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_KeyPress.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/keyboard/juce_KeyPress.cpp"; sourceTree = "SOURCE_ROOT"; }; 817CC81F50861DAEEFB2043A = { isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; }; + 829D2BFEB85DC3589FEBB868 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_WildcardFileFilter.cpp"; path = "../../JuceLibraryCode/modules/juce_core/files/juce_WildcardFileFilter.cpp"; sourceTree = "SOURCE_ROOT"; }; 8312A52619B88D3763F6B493 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_LookAndFeel_V3.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V3.cpp"; sourceTree = "SOURCE_ROOT"; }; 834F3F9FC2FE9564FF95243D = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_win32_Fonts.cpp"; path = "../../JuceLibraryCode/modules/juce_graphics/native/juce_win32_Fonts.cpp"; sourceTree = "SOURCE_ROOT"; }; 838E63F5800CA577B92EF6AE = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = OperatorEditor.cpp; path = ../../Source/OperatorEditor.cpp; sourceTree = "SOURCE_ROOT"; }; @@ -710,10 +717,10 @@ CF348935D8F88A548C0FB249 = { isa = PBXFileReference; lastKnownFileType = file; name = "juce_module_info"; path = "../../../JUCE/modules/juce_events/juce_module_info"; sourceTree = "SOURCE_ROOT"; }; CFFA7532FAFF5655253878FE = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_Threads.cpp"; path = "../../JuceLibraryCode/modules/juce_core/native/juce_android_Threads.cpp"; sourceTree = "SOURCE_ROOT"; }; D0096F2804DF0875565D0051 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioDataConverters.h"; path = "../../JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h"; sourceTree = "SOURCE_ROOT"; }; + D0178A36F6E46F92111E4883 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_VST3_Wrapper.cpp"; path = "../../JuceLibraryCode/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp"; sourceTree = "SOURCE_ROOT"; }; D1353A684AD92A6A9FAFBB1B = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_DynamicObject.cpp"; path = "../../JuceLibraryCode/modules/juce_core/containers/juce_DynamicObject.cpp"; sourceTree = "SOURCE_ROOT"; }; D154251B66BF13E992D3D06A = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_SystemTrayIconComponent.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_extra/misc/juce_SystemTrayIconComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; D17049595AD1C1353337817D = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ImageConvolutionKernel.cpp"; path = "../../JuceLibraryCode/modules/juce_graphics/images/juce_ImageConvolutionKernel.cpp"; sourceTree = "SOURCE_ROOT"; }; - D1BA8296F20CACB8F81B7316 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_FileFilter.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_FileFilter.h"; sourceTree = "SOURCE_ROOT"; }; D1BEED433BFC4AA10346BE1C = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_FileSearchPath.cpp"; path = "../../JuceLibraryCode/modules/juce_core/files/juce_FileSearchPath.cpp"; sourceTree = "SOURCE_ROOT"; }; D25566BCBFE5CCA4E425E6A7 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Variant.h"; path = "../../JuceLibraryCode/modules/juce_core/containers/juce_Variant.h"; sourceTree = "SOURCE_ROOT"; }; D2E57CCA4E6F6DBE2953744C = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ComponentBoundsConstrainer.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/layout/juce_ComponentBoundsConstrainer.h"; sourceTree = "SOURCE_ROOT"; }; @@ -864,6 +871,7 @@ FF46344F53B1AE5119D163D5 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_CarbonVisibility.h"; path = "../../JuceLibraryCode/modules/juce_audio_plugin_client/utility/juce_CarbonVisibility.h"; sourceTree = "SOURCE_ROOT"; }; FF5B77AA3517B4637F862BD3 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_RelativeCoordinatePositioner.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativeCoordinatePositioner.cpp"; sourceTree = "SOURCE_ROOT"; }; FF6607118B29435E76806DFA = { isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Dexed.component; sourceTree = "BUILT_PRODUCTS_DIR"; }; + FF973BD60572C077A148D3AB = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_WildcardFileFilter.h"; path = "../../JuceLibraryCode/modules/juce_core/files/juce_WildcardFileFilter.h"; sourceTree = "SOURCE_ROOT"; }; F472964B0FFEE5615B72CE3D = { isa = PBXGroup; children = ( 15B75D829C40872D542A38B8 ); name = Resources; sourceTree = ""; }; BDC5059F1563FD8DD69AD324 = { isa = PBXGroup; children = ( @@ -978,10 +986,13 @@ B794B15ADD462305846C5903 = { isa = PBXGroup; children = ( D6C6FCBA5ECA257959BFE674, F6F950B6ABB40B62AE4C0B78 ); name = VST; sourceTree = ""; }; - 85A5C17AC07E3A6A3F2EDA18 = { isa = PBXGroup; children = ( + FA8A91020A6EDA9A5DDF8D4A = { isa = PBXGroup; children = ( + D0178A36F6E46F92111E4883, + 01EF232D8B427B8CE38127C2 ); name = VST3; sourceTree = ""; }; + C6FD96042B8BCA45D8185D2F = { isa = PBXGroup; children = ( 505852570B48EB3F18076B03, 3254CAE4C282C4432214B016 ); name = AAX; sourceTree = ""; }; - 87B177FB46D381DF5C97583E = { isa = PBXGroup; children = ( + 0FB9E2767E5705CC99B13E68 = { isa = PBXGroup; children = ( FF46344F53B1AE5119D163D5, C33C134DA87CD13FAF7BC5A1, 477946525F6F1BE9135A3101, @@ -993,8 +1004,9 @@ D53856B782944C7AA8FC0B1E, 9302146DD804F9CBF819DE20, B794B15ADD462305846C5903, - 85A5C17AC07E3A6A3F2EDA18, - 87B177FB46D381DF5C97583E, + FA8A91020A6EDA9A5DDF8D4A, + C6FD96042B8BCA45D8185D2F, + 0FB9E2767E5705CC99B13E68, EF6B42F9461A962D9D91EFEA, 4E1C775897B0A2C2F9E2CB44 ); name = "juce_audio_plugin_client"; sourceTree = ""; }; 2BB71E1725728DD1B293B270 = { isa = PBXGroup; children = ( @@ -1021,6 +1033,8 @@ 78934C6C88D2B35DEF15BAB8, 6E8FC799E88893F8CD15BB71, B4AA6DED570BD1D3E701BA49, + 7DC83451FCA10947AC92EBBC, + 07333A7932C6B7538F4DF21F, 3F15C4289E956EA0447392BD, 153D4DE95D01307F844AA15B, 83DC5A4F730ECA567FADFC3E, @@ -1160,6 +1174,8 @@ 4D488219CE9D736D69F6EF59, 39423D67EFB8E7CEEF5FFAA9, 95B7D6B36478C5A2977ADD4C, + 7ECA74A2FC82F26715446C70, + 2C65FDA74486C92DF5EA5C87, D409BECBAD7CDC3DE48EFA2F, 418C5A909668054B5140BDA9, B446CB8C1ED8823EA2F33E30, @@ -1168,7 +1184,9 @@ 3BB7B60AE87F68C10DBEE118, F5E56D366A88F772BE998AED, 4370F9713D43E71621F2AA2A, - F0E8BE4931D56987065FE1C1 ); name = files; sourceTree = ""; }; + F0E8BE4931D56987065FE1C1, + 829D2BFEB85DC3589FEBB868, + FF973BD60572C077A148D3AB ); name = files; sourceTree = ""; }; F71D9B3CC8688C2E11360EA4 = { isa = PBXGroup; children = ( 06C4DD7797E7526DB1B47AE5, 3444F7C54161FEB1F844619E, @@ -1329,6 +1347,8 @@ 29FCF15A6F116C0A823A186D, ECB0C2120DE11AE690DB987B ); name = broadcasters; sourceTree = ""; }; 9ACE3BB033DC986A0A577EE8 = { isa = PBXGroup; children = ( + 17A328AD02B5D7DA362E1D5D, + 40DCD07DB4B1D9FBB9D47BE5, 88DEE0054A9328954E19EECA, F4EA09FAC67FDDA4D2E1D151, EACE6ED62F30C9222D91ACB2, @@ -1669,8 +1689,6 @@ 001A2BCC899370ADC99A8F3A, 3223ECE0332620D3B03E301A, E44EB5B165F16ABE2DFB809D, - 7A38190CB0652B0EBA02100C, - D1BA8296F20CACB8F81B7316, 25F88A5C788D9CF7301569EB, 8C4A3CBB322357AF0CA3C2CD, 9E0A95AA535CE6ABE66D9A30, @@ -1681,9 +1699,7 @@ BA9FFDC7BCC2D364014E1280, E8A7578ED10948AB49EE2997, 2CA19470CA427333F8CAC0A5, - 27077B2F6AA5ED05FAF0B5D8, - 35865817C4ED48DCD346B5D9, - 46B8FB88F2949700DD70A821 ); name = filebrowser; sourceTree = ""; }; + 27077B2F6AA5ED05FAF0B5D8 ); name = filebrowser; sourceTree = ""; }; D20A63B1C4DF64E9DA6C9CE8 = { isa = PBXGroup; children = ( 041EA7D542B0EBF7213B9BA2, 17ED00953353016B7E7492B0, @@ -1836,6 +1852,8 @@ FE39DD2B654DF778D919D554, C7C6039A52C3EE370CA9E73A, EAA5D8078BCC042BDF94C77A, + D0178A36F6E46F92111E4883, + 01EF232D8B427B8CE38127C2, D6C6FCBA5ECA257959BFE674, F6F950B6ABB40B62AE4C0B78, 8F32EF92B0A18751EC39A79B ); name = "Juce Library Code"; sourceTree = ""; }; @@ -1991,6 +2009,8 @@ DDD1E74DE1AC7E6493AF04CA, A6E2908774D7F669F21B1874, B82FDEB3E53C9455BC6A5DAE, + 52C0C94470D90310AF2F8433, + 13F8BF7C26D50908163425CF, 00C044DBB8BA1AF35CBC42E6, E8D9A2B640A87FE92D2DA887 ); runOnlyForDeploymentPostprocessing = 0; }; 06D721A024B3596A28AB8EC1 = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( diff --git a/Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate b/Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate index 8a60573..d017439 100644 Binary files a/Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate and b/Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Builds/VisualStudio2012/Dexed.vcxproj b/Builds/VisualStudio2012/Dexed.vcxproj index e01b429..91f6f40 100644 --- a/Builds/VisualStudio2012/Dexed.vcxproj +++ b/Builds/VisualStudio2012/Dexed.vcxproj @@ -223,6 +223,9 @@ true + + true + true @@ -367,6 +370,9 @@ true + + true + true @@ -379,6 +385,9 @@ true + + true + true @@ -544,6 +553,9 @@ true + + true + true @@ -961,9 +973,6 @@ true - - true - true @@ -979,9 +988,6 @@ true - - true - true @@ -1119,6 +1125,7 @@ StdCall + @@ -1187,6 +1194,8 @@ + + @@ -1268,11 +1277,13 @@ + + @@ -1332,6 +1343,7 @@ + @@ -1488,14 +1500,12 @@ - - diff --git a/Builds/VisualStudio2012/Dexed.vcxproj.filters b/Builds/VisualStudio2012/Dexed.vcxproj.filters index f2259fd..c8f175a 100644 --- a/Builds/VisualStudio2012/Dexed.vcxproj.filters +++ b/Builds/VisualStudio2012/Dexed.vcxproj.filters @@ -47,6 +47,9 @@ {AF5F4789-D607-BFD8-D853-09473C27449C} + + {22689F25-8C5C-52CF-09E4-4308D1521B9B} + {F0C10808-8C36-BCD0-D25F-523774B0ADA2} @@ -403,6 +406,12 @@ Juce Modules\juce_audio_plugin_client\VST + + Juce Modules\juce_audio_plugin_client\VST3 + + + Juce Modules\juce_audio_plugin_client\VST3 + Juce Modules\juce_audio_plugin_client\AAX @@ -553,6 +562,9 @@ Juce Modules\juce_core\files + + Juce Modules\juce_core\files + Juce Modules\juce_core\files @@ -565,6 +577,9 @@ Juce Modules\juce_core\files + + Juce Modules\juce_core\files + Juce Modules\juce_core\network @@ -745,6 +760,9 @@ Juce Modules\juce_events\broadcasters + + Juce Modules\juce_events\interprocess + Juce Modules\juce_events\interprocess @@ -1174,9 +1192,6 @@ Juce Modules\juce_gui_basics\filebrowser - - Juce Modules\juce_gui_basics\filebrowser - Juce Modules\juce_gui_basics\filebrowser @@ -1192,9 +1207,6 @@ Juce Modules\juce_gui_basics\filebrowser - - Juce Modules\juce_gui_basics\filebrowser - Juce Modules\juce_gui_basics\commands @@ -1393,6 +1405,9 @@ Juce Library Code + + Juce Library Code + Juce Library Code @@ -1593,6 +1608,12 @@ Juce Modules\juce_audio_processors\format_types + + Juce Modules\juce_audio_processors\format_types + + + Juce Modules\juce_audio_processors\format_types + Juce Modules\juce_audio_processors\format_types @@ -1836,6 +1857,9 @@ Juce Modules\juce_core\files + + Juce Modules\juce_core\files + Juce Modules\juce_core\files @@ -1851,6 +1875,9 @@ Juce Modules\juce_core\files + + Juce Modules\juce_core\files + Juce Modules\juce_core\network @@ -2028,6 +2055,9 @@ Juce Modules\juce_events\broadcasters + + Juce Modules\juce_events\interprocess + Juce Modules\juce_events\interprocess @@ -2496,9 +2526,6 @@ Juce Modules\juce_gui_basics\filebrowser - - Juce Modules\juce_gui_basics\filebrowser - Juce Modules\juce_gui_basics\filebrowser @@ -2517,9 +2544,6 @@ Juce Modules\juce_gui_basics\filebrowser - - Juce Modules\juce_gui_basics\filebrowser - Juce Modules\juce_gui_basics\commands diff --git a/Builds/VisualStudio2013/Dexed.vcxproj b/Builds/VisualStudio2013/Dexed.vcxproj index c74725b..9ea2c96 100644 --- a/Builds/VisualStudio2013/Dexed.vcxproj +++ b/Builds/VisualStudio2013/Dexed.vcxproj @@ -223,6 +223,9 @@ true + + true + true @@ -367,6 +370,9 @@ true + + true + true @@ -379,6 +385,9 @@ true + + true + true @@ -544,6 +553,9 @@ true + + true + true @@ -961,9 +973,6 @@ true - - true - true @@ -979,9 +988,6 @@ true - - true - true @@ -1119,6 +1125,7 @@ StdCall + @@ -1187,6 +1194,8 @@ + + @@ -1268,11 +1277,13 @@ + + @@ -1332,6 +1343,7 @@ + @@ -1488,14 +1500,12 @@ - - diff --git a/Builds/VisualStudio2013/Dexed.vcxproj.filters b/Builds/VisualStudio2013/Dexed.vcxproj.filters index 56f2fec..0a1b4b5 100644 --- a/Builds/VisualStudio2013/Dexed.vcxproj.filters +++ b/Builds/VisualStudio2013/Dexed.vcxproj.filters @@ -47,6 +47,9 @@ {AF5F4789-D607-BFD8-D853-09473C27449C} + + {22689F25-8C5C-52CF-09E4-4308D1521B9B} + {F0C10808-8C36-BCD0-D25F-523774B0ADA2} @@ -403,6 +406,12 @@ Juce Modules\juce_audio_plugin_client\VST + + Juce Modules\juce_audio_plugin_client\VST3 + + + Juce Modules\juce_audio_plugin_client\VST3 + Juce Modules\juce_audio_plugin_client\AAX @@ -553,6 +562,9 @@ Juce Modules\juce_core\files + + Juce Modules\juce_core\files + Juce Modules\juce_core\files @@ -565,6 +577,9 @@ Juce Modules\juce_core\files + + Juce Modules\juce_core\files + Juce Modules\juce_core\network @@ -745,6 +760,9 @@ Juce Modules\juce_events\broadcasters + + Juce Modules\juce_events\interprocess + Juce Modules\juce_events\interprocess @@ -1174,9 +1192,6 @@ Juce Modules\juce_gui_basics\filebrowser - - Juce Modules\juce_gui_basics\filebrowser - Juce Modules\juce_gui_basics\filebrowser @@ -1192,9 +1207,6 @@ Juce Modules\juce_gui_basics\filebrowser - - Juce Modules\juce_gui_basics\filebrowser - Juce Modules\juce_gui_basics\commands @@ -1393,6 +1405,9 @@ Juce Library Code + + Juce Library Code + Juce Library Code @@ -1593,6 +1608,12 @@ Juce Modules\juce_audio_processors\format_types + + Juce Modules\juce_audio_processors\format_types + + + Juce Modules\juce_audio_processors\format_types + Juce Modules\juce_audio_processors\format_types @@ -1836,6 +1857,9 @@ Juce Modules\juce_core\files + + Juce Modules\juce_core\files + Juce Modules\juce_core\files @@ -1851,6 +1875,9 @@ Juce Modules\juce_core\files + + Juce Modules\juce_core\files + Juce Modules\juce_core\network @@ -2028,6 +2055,9 @@ Juce Modules\juce_events\broadcasters + + Juce Modules\juce_events\interprocess + Juce Modules\juce_events\interprocess @@ -2496,9 +2526,6 @@ Juce Modules\juce_gui_basics\filebrowser - - Juce Modules\juce_gui_basics\filebrowser - Juce Modules\juce_gui_basics\filebrowser @@ -2517,9 +2544,6 @@ Juce Modules\juce_gui_basics\filebrowser - - Juce Modules\juce_gui_basics\filebrowser - Juce Modules\juce_gui_basics\commands diff --git a/JuceLibraryCode/modules/juce_audio_basics/juce_module_info b/JuceLibraryCode/modules/juce_audio_basics/juce_module_info index acdd765..b5f46c9 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/juce_module_info +++ b/JuceLibraryCode/modules/juce_audio_basics/juce_module_info @@ -1,7 +1,7 @@ { "id": "juce_audio_basics", "name": "JUCE audio and midi data classes", - "version": "3.0.1", + "version": "3.0.3", "description": "Classes for audio buffer manipulation, midi message handling, synthesis, etc", "website": "http://www.juce.com/juce", "license": "GPL/Commercial", diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.cpp b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.cpp index c111404..6f6c374 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.cpp @@ -155,7 +155,7 @@ MidiMessage::MidiMessage (const MidiMessage& other, const double newTimeStamp) MidiMessage::MidiMessage (const void* srcData, int sz, int& numBytesUsed, const uint8 lastStatusByte, double t) : timeStamp (t) { - const uint8* src = static_cast (srcData); + const uint8* src = static_cast (srcData); unsigned int byte = (unsigned int) *src; if (byte < 0x80) @@ -658,6 +658,36 @@ String MidiMessage::getTextFromTextMetaEvent() const CharPointer_UTF8 (textData + getMetaEventLength())); } +MidiMessage MidiMessage::textMetaEvent (int type, StringRef text) +{ + jassert (type > 0 && type < 16) + + MidiMessage result; + + const size_t textSize = text.text.sizeInBytes() - 1; + + uint8 header[8]; + size_t n = sizeof (header); + + header[--n] = (uint8) (textSize & 0x7f); + + for (size_t i = textSize; (i >>= 7) != 0;) + header[--n] = (uint8) ((i & 0x7f) | 0x80); + + header[--n] = (uint8) type; + header[--n] = 0xff; + + const size_t headerLen = sizeof (header) - n; + + uint8* const dest = result.allocateSpace ((int) (headerLen + textSize)); + result.size = (int) (headerLen + textSize); + + memcpy (dest, header + n, headerLen); + memcpy (dest + headerLen, text.text.getAddress(), textSize); + + return result; +} + bool MidiMessage::isTrackNameEvent() const noexcept { const uint8* data = getRawData(); return (data[1] == 3) && (*data == 0xff); } bool MidiMessage::isTempoMetaEvent() const noexcept { const uint8* data = getRawData(); return (data[1] == 81) && (*data == 0xff); } bool MidiMessage::isMidiChannelMetaEvent() const noexcept { const uint8* data = getRawData(); return (data[1] == 0x20) && (*data == 0xff) && (data[2] == 1); } @@ -941,6 +971,11 @@ double MidiMessage::getMidiNoteInHertz (int noteNumber, const double frequencyOf return frequencyOfA * pow (2.0, (noteNumber - 69) / 12.0); } +bool MidiMessage::isMidiNoteBlack (int noteNumber) noexcept +{ + return ((1 << (noteNumber % 12)) & 0x054a) != 0; +} + const char* MidiMessage::getGMInstrumentName (const int n) { static const char* names[] = diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.h b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.h index c775883..4694c55 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.h +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.h @@ -168,9 +168,7 @@ public: bool isForChannel (int channelNumber) const noexcept; /** Changes the message's midi channel. - This won't do anything for non-channel messages like sysexes. - @param newChannelNumber the channel number to change it to, in the range 1 to 16 */ void setChannel (int newChannelNumber) noexcept; @@ -181,17 +179,13 @@ public: bool isSysEx() const noexcept; /** Returns a pointer to the sysex data inside the message. - If this event isn't a sysex event, it'll return 0. - @see getSysExDataSize */ const uint8* getSysExData() const noexcept; /** Returns the size of the sysex data. - This value excludes the 0xf0 header byte and the 0xf7 at the end. - @see getSysExData */ int getSysExDataSize() const noexcept; @@ -252,15 +246,12 @@ public: bool isNoteOnOrOff() const noexcept; /** Returns the midi note number for note-on and note-off messages. - If the message isn't a note-on or off, the value returned is undefined. - @see isNoteOff, getMidiNoteName, getMidiNoteInHertz, setNoteNumber */ int getNoteNumber() const noexcept; /** Changes the midi note number of a note-on or note-off message. - If the message isn't a note on or off, this will do nothing. */ void setNoteNumber (int newNoteNumber) noexcept; @@ -320,16 +311,12 @@ public: //============================================================================== /** Returns true if the message is a program (patch) change message. - @see getProgramChangeNumber, getGMInstrumentName */ bool isProgramChange() const noexcept; /** Returns the new program number of a program change message. - - If the message isn't a program change, the value returned will be - nonsense. - + If the message isn't a program change, the value returned is undefined. @see isProgramChange, getGMInstrumentName */ int getProgramChangeNumber() const noexcept; @@ -344,7 +331,6 @@ public: //============================================================================== /** Returns true if the message is a pitch-wheel move. - @see getPitchWheelValue, pitchWheel */ bool isPitchWheel() const noexcept; @@ -433,7 +419,6 @@ public: /** Returns the controller number of a controller message. The name of the controller can be looked up using the getControllerName() method. - Note that the value returned is invalid for messages that aren't controller changes. @see isController, getControllerName, getControllerValue @@ -443,7 +428,6 @@ public: /** Returns the controller value from a controller message. A value 0 to 127 is returned to indicate the new controller position. - Note that the value returned is invalid for messages that aren't controller changes. @see isController, getControllerNumber @@ -467,13 +451,11 @@ public: int value) noexcept; /** Checks whether this message is an all-notes-off message. - @see allNotesOff */ bool isAllNotesOff() const noexcept; /** Checks whether this message is an all-sound-off message. - @see allSoundOff */ bool isAllSoundOff() const noexcept; @@ -520,13 +502,11 @@ public: int getMetaEventType() const noexcept; /** Returns a pointer to the data in a meta-event. - @see isMetaEvent, getMetaEventLength */ const uint8* getMetaEventData() const noexcept; /** Returns the length of the data for a meta-event. - @see isMetaEvent, getMetaEventData */ int getMetaEventLength() const noexcept; @@ -539,29 +519,28 @@ public: bool isEndOfTrackMetaEvent() const noexcept; /** Creates an end-of-track meta-event. - @see isEndOfTrackMetaEvent */ static MidiMessage endOfTrack() noexcept; /** Returns true if this is an 'track name' meta-event. - You can use the getTextFromTextMetaEvent() method to get the track's name. */ bool isTrackNameEvent() const noexcept; /** Returns true if this is a 'text' meta-event. - @see getTextFromTextMetaEvent */ bool isTextMetaEvent() const noexcept; /** Returns the text from a text meta-event. - @see isTextMetaEvent */ String getTextFromTextMetaEvent() const; + /** Creates a text meta-event. */ + static MidiMessage textMetaEvent (int type, StringRef text); + //============================================================================== /** Returns true if this is a 'tempo' meta-event. @see getTempoMetaEventTickLength, getTempoSecondsPerQuarterNote @@ -660,7 +639,6 @@ public: //============================================================================== /** Returns true if this is a midi start event. - @see midiStart */ bool isMidiStart() const noexcept; @@ -669,7 +647,6 @@ public: static MidiMessage midiStart() noexcept; /** Returns true if this is a midi continue event. - @see midiContinue */ bool isMidiContinue() const noexcept; @@ -678,7 +655,6 @@ public: static MidiMessage midiContinue() noexcept; /** Returns true if this is a midi stop event. - @see midiStop */ bool isMidiStop() const noexcept; @@ -687,7 +663,6 @@ public: static MidiMessage midiStop() noexcept; /** Returns true if this is a midi clock event. - @see midiClock, songPositionPointer */ bool isMidiClock() const noexcept; @@ -696,13 +671,11 @@ public: static MidiMessage midiClock() noexcept; /** Returns true if this is a song-position-pointer message. - @see getSongPositionPointerMidiBeat, songPositionPointer */ bool isSongPositionPointer() const noexcept; /** Returns the midi beat-number of a song-position-pointer message. - @see isSongPositionPointer, songPositionPointer */ int getSongPositionPointerMidiBeat() const noexcept; @@ -719,23 +692,18 @@ public: //============================================================================== /** Returns true if this is a quarter-frame midi timecode message. - @see quarterFrame, getQuarterFrameSequenceNumber, getQuarterFrameValue */ bool isQuarterFrame() const noexcept; /** Returns the sequence number of a quarter-frame midi timecode message. - This will be a value between 0 and 7. - @see isQuarterFrame, getQuarterFrameValue, quarterFrame */ int getQuarterFrameSequenceNumber() const noexcept; /** Returns the value from a quarter-frame message. - - This will be the lower nybble of the message's data-byte, a value - between 0 and 15 + This will be the lower nybble of the message's data-byte, a value between 0 and 15 */ int getQuarterFrameValue() const noexcept; @@ -747,7 +715,6 @@ public: static MidiMessage quarterFrame (int sequenceNumber, int value) noexcept; /** SMPTE timecode types. - Used by the getFullFrameParameters() and fullFrame() methods. */ enum SmpteTimecodeType @@ -758,8 +725,7 @@ public: fps30 = 3 }; - /** Returns true if this is a full-frame midi timecode message. - */ + /** Returns true if this is a full-frame midi timecode message. */ bool isFullFrame() const noexcept; /** Extracts the timecode information from a full-frame midi timecode message. @@ -773,8 +739,7 @@ public: int& frames, SmpteTimecodeType& timecodeType) const noexcept; - /** Creates a full-frame MTC message. - */ + /** Creates a full-frame MTC message. */ static MidiMessage fullFrame (int hours, int minutes, int seconds, @@ -799,7 +764,6 @@ public: }; /** Checks whether this is an MMC message. - If it is, you can use the getMidiMachineControlCommand() to find out its type. */ bool isMidiMachineControlMessage() const noexcept; @@ -889,6 +853,9 @@ public: */ static double getMidiNoteInHertz (int noteNumber, const double frequencyOfA = 440.0) noexcept; + /** Returns true if the given midi note number is a black key. */ + static bool isMidiNoteBlack (int noteNumber) noexcept; + /** Returns the standard name of a GM instrument, or nullptr if unknown for this index. @param midiInstrumentNumber the program number 0 to 127 diff --git a/JuceLibraryCode/modules/juce_audio_devices/juce_module_info b/JuceLibraryCode/modules/juce_audio_devices/juce_module_info index 5afbb4e..b50181f 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/juce_module_info +++ b/JuceLibraryCode/modules/juce_audio_devices/juce_module_info @@ -1,7 +1,7 @@ { "id": "juce_audio_devices", "name": "JUCE audio and midi I/O device classes", - "version": "3.0.1", + "version": "3.0.3", "description": "Classes to play and record from audio and midi i/o devices.", "website": "http://www.juce.com/juce", "license": "GPL/Commercial", diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_ios_Audio.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_ios_Audio.cpp index a5a1b31..f20ea44 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_ios_Audio.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_ios_Audio.cpp @@ -122,7 +122,7 @@ public: setSessionFloat64Property (kAudioSessionProperty_PreferredHardwareSampleRate, targetSampleRate); updateSampleRates(); - setSessionFloat64Property (kAudioSessionProperty_PreferredHardwareIOBufferDuration, preferredBufferSize / sampleRate); + setSessionFloat32Property (kAudioSessionProperty_PreferredHardwareIOBufferDuration, preferredBufferSize / sampleRate); updateCurrentBufferSize(); prepareFloatBuffers (actualBufferSize); @@ -553,6 +553,7 @@ private: } 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); } JUCE_DECLARE_NON_COPYABLE (iOSAudioIODevice) diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp index 799207c..74e7a6c 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp @@ -185,15 +185,12 @@ public: const int tempBufSize = bufferSize + 4; audioBuffer.calloc ((size_t) ((numInputChans + numOutputChans) * tempBufSize)); - tempInputBuffers.calloc ((size_t) numInputChans + 2); + tempInputBuffers.calloc ((size_t) numInputChans + 2); tempOutputBuffers.calloc ((size_t) numOutputChans + 2); int count = 0; - for (int i = 0; i < numInputChans; ++i) - tempInputBuffers[i] = audioBuffer + count++ * tempBufSize; - - for (int i = 0; i < numOutputChans; ++i) - tempOutputBuffers[i] = audioBuffer + count++ * tempBufSize; + for (int i = 0; i < numInputChans; ++i) tempInputBuffers[i] = audioBuffer + count++ * tempBufSize; + for (int i = 0; i < numOutputChans; ++i) tempOutputBuffers[i] = audioBuffer + count++ * tempBufSize; } struct CallbackDetailsForChannel @@ -234,24 +231,15 @@ public: NSString* nameNSString = nil; size = sizeof (nameNSString); - #if JUCE_CLANG - // Very irritating that AudioDeviceGetProperty is marked as deprecated, since - // there seems to be no replacement way of getting the channel names. - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wdeprecated-declarations" - #endif + pa.mSelector = kAudioObjectPropertyElementName; + pa.mElement = chanNum + 1; - if (AudioDeviceGetProperty (deviceID, chanNum + 1, input, kAudioDevicePropertyChannelNameCFString, - &size, &nameNSString) == noErr) + if (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, &nameNSString) == noErr) { name = nsStringToJuce (nameNSString); [nameNSString release]; } - #if JUCE_CLANG - #pragma clang diagnostic pop - #endif - if ((input ? activeInputChans : activeOutputChans) [chanNum]) { CallbackDetailsForChannel info = { i, (int) j, (int) b.mNumberChannels }; @@ -283,7 +271,7 @@ public: if (OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, nullptr, &size))) { - HeapBlock ranges; + HeapBlock ranges; ranges.calloc (size, 1); if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, ranges))) @@ -322,7 +310,7 @@ public: if (OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, nullptr, &size))) { - HeapBlock ranges; + HeapBlock ranges; ranges.calloc (size, 1); if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, ranges))) @@ -424,7 +412,7 @@ public: StringArray getSources (bool input) { StringArray s; - HeapBlock types; + HeapBlock types; const int num = getAllDataSourcesForDevice (deviceID, types); for (int i = 0; i < num; ++i) @@ -466,7 +454,7 @@ public: { if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, ¤tSourceID))) { - HeapBlock types; + HeapBlock types; const int num = getAllDataSourcesForDevice (deviceID, types); for (int i = 0; i < num; ++i) @@ -487,7 +475,7 @@ public: { if (deviceID != 0) { - HeapBlock types; + HeapBlock types; const int num = getAllDataSourcesForDevice (deviceID, types); if (isPositiveAndBelow (index, num)) @@ -1049,12 +1037,12 @@ public: devices.clear(); } - void addDevice (AudioIODevice* device) + void addDevice (AudioIODevice* device, bool useInputs, bool useOutputs) { jassert (device != nullptr); jassert (! isOpen()); jassert (! device->isOpen()); - devices.add (new DeviceWrapper (*this, device)); + devices.add (new DeviceWrapper (*this, device, useInputs, useOutputs)); } Array getDevices() const @@ -1072,8 +1060,7 @@ public: StringArray names; for (int i = 0; i < devices.size(); ++i) - names.addArray (devices.getUnchecked(i)->device->getOutputChannelNames()); - + names.addArray (devices.getUnchecked(i)->getOutputChannelNames()); names.appendNumbersToDuplicates (false, true); return names; @@ -1084,7 +1071,7 @@ public: StringArray names; for (int i = 0; i < devices.size(); ++i) - names.addArray (devices.getUnchecked(i)->device->getInputChannelNames()); + names.addArray (devices.getUnchecked(i)->getInputChannelNames()); names.appendNumbersToDuplicates (false, true); return names; @@ -1181,8 +1168,8 @@ public: BigInteger ins (inputChannels >> totalInputChanIndex); BigInteger outs (outputChannels >> totalOutputChanIndex); - int numIns = d.device->getInputChannelNames().size(); - int numOuts = d.device->getOutputChannelNames().size(); + int numIns = d.getInputChannelNames().size(); + int numOuts = d.getOutputChannelNames().size(); totalInputChanIndex += numIns; totalOutputChanIndex += numOuts; @@ -1225,9 +1212,13 @@ public: for (int i = 0; i < devices.size(); ++i) { - const int numChans = devices.getUnchecked(i)->device->getOutputChannelNames().size(); - chans |= (devices.getUnchecked(i)->device->getActiveOutputChannels() << start); - start += numChans; + const int numChans = devices.getUnchecked(i)->getOutputChannelNames().size(); + + if (numChans > 0) + { + chans |= (devices.getUnchecked(i)->device->getActiveOutputChannels() << start); + start += numChans; + } } return chans; @@ -1240,9 +1231,13 @@ public: for (int i = 0; i < devices.size(); ++i) { - const int numChans = devices.getUnchecked(i)->device->getInputChannelNames().size(); - chans |= (devices.getUnchecked(i)->device->getActiveInputChannels() << start); - start += numChans; + const int numChans = devices.getUnchecked(i)->getInputChannelNames().size(); + + if (numChans > 0) + { + chans |= (devices.getUnchecked(i)->device->getActiveInputChannels() << start); + start += numChans; + } } return chans; @@ -1469,8 +1464,9 @@ private: //============================================================================== struct DeviceWrapper : private AudioIODeviceCallback { - DeviceWrapper (AudioIODeviceCombiner& cd, AudioIODevice* d) + DeviceWrapper (AudioIODeviceCombiner& cd, AudioIODevice* d, bool useIns, bool useOuts) : owner (cd), device (d), inputIndex (0), outputIndex (0), + useInputs (useIns), useOutputs (useOuts), inputFifo (32), outputFifo (32), done (false) { } @@ -1490,10 +1486,12 @@ private: inputFifo.reset(); outputFifo.reset(); - String err (device->open (inputChannels, outputChannels, sampleRate, bufferSize)); + String err (device->open (useInputs ? inputChannels : BigInteger(), + useOutputs ? outputChannels : BigInteger(), + sampleRate, bufferSize)); - numInputChans = device->getActiveInputChannels().countNumberOfSetBits(); - numOutputChans = device->getActiveOutputChannels().countNumberOfSetBits(); + numInputChans = useInputs ? device->getActiveInputChannels().countNumberOfSetBits() : 0; + numOutputChans = useOutputs ? device->getActiveOutputChannels().countNumberOfSetBits() : 0; inputIndex = channelIndex; outputIndex = channelIndex + numInputChans; @@ -1518,6 +1516,9 @@ private: outputFifo.reset(); } + StringArray getOutputChannelNames() const { return useOutputs ? device->getOutputChannelNames() : StringArray(); } + StringArray getInputChannelNames() const { return useInputs ? device->getInputChannelNames() : StringArray(); } + bool isInputReady (int numSamples) const noexcept { return numInputChans == 0 || inputFifo.getNumReady() >= numSamples; @@ -1655,6 +1656,7 @@ private: AudioIODeviceCombiner& owner; ScopedPointer device; int inputIndex, numInputChans, outputIndex, numOutputChans; + bool useInputs, useOutputs; AbstractFifo inputFifo, outputFifo; bool done; @@ -1850,8 +1852,8 @@ public: if (out == nullptr) return in.release(); ScopedPointer combo (new AudioIODeviceCombiner (combinedName)); - combo->addDevice (in.release()); - combo->addDevice (out.release()); + combo->addDevice (in.release(), true, false); + combo->addDevice (out.release(), false, true); return combo.release(); } @@ -1874,7 +1876,7 @@ private: if (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, nullptr, &size) == noErr) { - HeapBlock bufList; + HeapBlock bufList; bufList.calloc (size, 1); if (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, bufList) == noErr) diff --git a/JuceLibraryCode/modules/juce_audio_formats/juce_module_info b/JuceLibraryCode/modules/juce_audio_formats/juce_module_info index b37705e..640afc9 100644 --- a/JuceLibraryCode/modules/juce_audio_formats/juce_module_info +++ b/JuceLibraryCode/modules/juce_audio_formats/juce_module_info @@ -1,7 +1,7 @@ { "id": "juce_audio_formats", "name": "JUCE audio file format codecs", - "version": "3.0.1", + "version": "3.0.3", "description": "Classes for reading and writing various audio file formats.", "website": "http://www.juce.com/juce", "license": "GPL/Commercial", diff --git a/JuceLibraryCode/modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp b/JuceLibraryCode/modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp index ee4b90f..a392166 100644 --- a/JuceLibraryCode/modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp +++ b/JuceLibraryCode/modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp @@ -124,8 +124,7 @@ struct AAXClasses case 6: return AAX_eStemFormat_5_1; case 7: return AAX_eStemFormat_7_0_DTS; case 8: return AAX_eStemFormat_7_1_DTS; - - default: jassertfalse; break; // hmm - not a valid number of chans.. + default: jassertfalse; break; } return AAX_eStemFormat_None; @@ -139,17 +138,45 @@ struct AAXClasses case AAX_eStemFormat_Mono: return 1; case AAX_eStemFormat_Stereo: return 2; case AAX_eStemFormat_LCR: return 3; + case AAX_eStemFormat_LCRS: case AAX_eStemFormat_Quad: return 4; case AAX_eStemFormat_5_0: return 5; - case AAX_eStemFormat_5_1: return 6; + case AAX_eStemFormat_5_1: + case AAX_eStemFormat_6_0: return 6; + case AAX_eStemFormat_6_1: + case AAX_eStemFormat_7_0_SDDS: case AAX_eStemFormat_7_0_DTS: return 7; + case AAX_eStemFormat_7_1_SDDS: case AAX_eStemFormat_7_1_DTS: return 8; - default: jassertfalse; break; // hmm - not a valid number of chans.. + default: jassertfalse; break; } return 0; } + static const char* getSpeakerArrangementString (AAX_EStemFormat format) noexcept + { + switch (format) + { + case AAX_eStemFormat_Mono: return "M"; + case AAX_eStemFormat_Stereo: return "L R"; + case AAX_eStemFormat_LCR: return "L C R"; + case AAX_eStemFormat_LCRS: return "L C R S"; + case AAX_eStemFormat_Quad: return "L R Ls Rs"; + case AAX_eStemFormat_5_0: return "L C R Ls Rs"; + case AAX_eStemFormat_5_1: return "L C R Ls Rs LFE"; + case AAX_eStemFormat_6_0: return "L C R Ls Cs Rs"; + case AAX_eStemFormat_6_1: return "L C R Ls Cs Rs LFE"; + case AAX_eStemFormat_7_0_SDDS: return "L Lc C Rc R Ls Rs"; + case AAX_eStemFormat_7_1_SDDS: return "L Lc C Rc R Ls Rs LFE"; + case AAX_eStemFormat_7_0_DTS: return "L C R Lss Rss Lsr Rsr"; + case AAX_eStemFormat_7_1_DTS: return "L C R Lss Rss Lsr Rsr LFE"; + default: break; + } + + return nullptr; + } + //============================================================================== struct JUCELibraryRefCount { @@ -743,6 +770,9 @@ struct AAXClasses midiBuffer.clear(); + (void) midiNodeIn; + (void) midiNodesOut; + #if JucePlugin_WantsMidiInput { AAX_CMidiStream* const midiStream = midiNodeIn->GetNodeBuffer(); @@ -852,6 +882,9 @@ struct AAXClasses AudioProcessor& audioProcessor = getPluginInstance(); + audioProcessor.setSpeakerArrangement (getSpeakerArrangementString (inputStemFormat), + getSpeakerArrangementString (outputStemFormat)); + audioProcessor.setPlayConfigDetails (numberOfInputChannels, numberOfOutputChannels, sampleRate, lastBufferSize); audioProcessor.prepareToPlay (sampleRate, lastBufferSize); @@ -928,6 +961,7 @@ struct AAXClasses // This value needs to match the RTAS wrapper's Type ID, so that // the host knows that the RTAS/AAX plugins are equivalent. properties->AddProperty (AAX_eProperty_PlugInID_Native, 'jcaa' + channelConfigIndex); + properties->AddProperty (AAX_eProperty_PlugInID_AudioSuite, 'jyaa' + channelConfigIndex); check (desc.AddProcessProc_Native (algorithmProcessCallback, properties)); } diff --git a/JuceLibraryCode/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm b/JuceLibraryCode/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm index b1d9ec2..0e51b82 100644 --- a/JuceLibraryCode/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm +++ b/JuceLibraryCode/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm @@ -535,7 +535,7 @@ public: #if BUILD_AU_CARBON_UI int GetNumCustomUIComponents() override { - return PluginHostType().isDigitalPerformer() ? 0 : 1; + return getHostType().isDigitalPerformer() ? 0 : 1; } void GetUIComponentDescs (ComponentDescription* inDescArray) override @@ -947,6 +947,7 @@ public: incomingEvents.addEvent (data, 3, (int) inStartFrame); return noErr; #else + (void) nStatus; (void) inChannel; (void) inData1; (void) inData2; (void) inStartFrame; return kAudioUnitErr_PropertyNotInUse; #endif } @@ -958,6 +959,7 @@ public: incomingEvents.addEvent (inData, (int) inLength, 0); return noErr; #else + (void) inData; (void) inLength; return kAudioUnitErr_PropertyNotInUse; #endif } @@ -1093,7 +1095,7 @@ public: bool keyPressed (const KeyPress&) override { - if (PluginHostType().isAbletonLive()) + if (getHostType().isAbletonLive()) { static NSTimeInterval lastEventTime = 0; // check we're not recursively sending the same event NSTimeInterval eventTime = [[NSApp currentEvent] timestamp]; diff --git a/JuceLibraryCode/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h b/JuceLibraryCode/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h index 6dfcf87..00976ef 100644 --- a/JuceLibraryCode/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h +++ b/JuceLibraryCode/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h @@ -105,7 +105,7 @@ public: const int y = settings->getIntValue ("windowY", -100); if (x != -100 && y != -100) - setBoundsConstrained (Rectangle (x, y, getWidth(), getHeight())); + setBoundsConstrained (juce::Rectangle (x, y, getWidth(), getHeight())); else centreWithSize (getWidth(), getHeight()); } diff --git a/JuceLibraryCode/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp b/JuceLibraryCode/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp index b38206d..719e056 100644 --- a/JuceLibraryCode/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp +++ b/JuceLibraryCode/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp @@ -111,11 +111,11 @@ namespace juce { #if JUCE_MAC extern void initialiseMac(); - extern void* attachComponentToWindowRef (Component*, void* windowRef); - extern void detachComponentFromWindowRef (Component*, void* nsWindow); - extern void setNativeHostWindowSize (void* nsWindow, Component*, int newWidth, int newHeight); - extern void checkWindowVisibility (void* nsWindow, Component*); - extern bool forwardCurrentKeyEventToHost (Component*); + extern void* attachComponentToWindowRef (Component*, void* parent, bool isNSView); + extern void detachComponentFromWindowRef (Component*, void* window, bool isNSView); + extern void setNativeHostWindowSize (void* window, Component*, int newWidth, int newHeight, bool isNSView); + extern void checkWindowVisibility (void* window, Component*, bool isNSView); + extern bool forwardCurrentKeyEventToHost (Component*, bool isNSView); #if ! JUCE_64BIT extern void updateEditorCompBounds (Component*); #endif @@ -283,6 +283,11 @@ public: hasShutdown (false), firstProcessCallback (true), shouldDeleteEditor (false), + #if JUCE_64BIT + useNSView (true), + #else + useNSView (false), + #endif processTempBuffer (1, 1), hostWindow (0) { @@ -366,61 +371,70 @@ public: } //============================================================================== - bool getEffectName (char* name) + bool getEffectName (char* name) override { String (JucePlugin_Name).copyToUTF8 (name, 64); return true; } - bool getVendorString (char* text) + bool getVendorString (char* text) override { String (JucePlugin_Manufacturer).copyToUTF8 (text, 64); return true; } - bool getProductString (char* text) { return getEffectName (text); } - VstInt32 getVendorVersion() { return convertHexVersionToDecimal (JucePlugin_VersionCode); } - VstPlugCategory getPlugCategory() { return JucePlugin_VSTCategory; } - bool keysRequired() { return (JucePlugin_EditorRequiresKeyboardFocus) != 0; } + bool getProductString (char* text) override { return getEffectName (text); } + VstInt32 getVendorVersion() override { return convertHexVersionToDecimal (JucePlugin_VersionCode); } + VstPlugCategory getPlugCategory() override { return JucePlugin_VSTCategory; } + bool keysRequired() { return (JucePlugin_EditorRequiresKeyboardFocus) != 0; } - VstInt32 canDo (char* text) + VstInt32 canDo (char* text) override { - VstInt32 result = 0; - if (strcmp (text, "receiveVstEvents") == 0 - || strcmp (text, "receiveVstMidiEvent") == 0 - || strcmp (text, "receiveVstMidiEvents") == 0) + || strcmp (text, "receiveVstMidiEvent") == 0 + || strcmp (text, "receiveVstMidiEvents") == 0) { #if JucePlugin_WantsMidiInput - result = 1; + return 1; #else - result = -1; + return -1; #endif } - else if (strcmp (text, "sendVstEvents") == 0 - || strcmp (text, "sendVstMidiEvent") == 0 - || strcmp (text, "sendVstMidiEvents") == 0) + + if (strcmp (text, "sendVstEvents") == 0 + || strcmp (text, "sendVstMidiEvent") == 0 + || strcmp (text, "sendVstMidiEvents") == 0) { #if JucePlugin_ProducesMidiOutput - result = 1; + return 1; #else - result = -1; + return -1; #endif } - else if (strcmp (text, "receiveVstTimeInfo") == 0 - || strcmp (text, "conformsToWindowRules") == 0 - || strcmp (text, "bypass") == 0) + + if (strcmp (text, "receiveVstTimeInfo") == 0 + || strcmp (text, "conformsToWindowRules") == 0 + || strcmp (text, "bypass") == 0) { - result = 1; + return 1; } - else if (strcmp (text, "openCloseAnyThread") == 0) + + if (strcmp (text, "openCloseAnyThread") == 0) { // This tells Wavelab to use the UI thread to invoke open/close, // like all other hosts do. - result = -1; + return -1; + } + + #if JUCE_MAC + if (strcmp (text, "hasCockosViewAsConfig") == 0) + { + useNSView = true; + return 0xbeef0000; } + #endif - return result; + return 0; } bool getInputProperties (VstInt32 index, VstPinProperties* properties) @@ -485,6 +499,7 @@ public: VSTMidiEventList::addEventsToMidiBuffer (events, midiEvents); return 1; #else + (void) events; return 0; #endif } @@ -1014,7 +1029,7 @@ public: #if JUCE_MAC if (hostWindow != 0) - checkWindowVisibility (hostWindow, editorComp); + checkWindowVisibility (hostWindow, editorComp, useNSView); #endif tryMasterIdle(); @@ -1107,7 +1122,7 @@ public: #if JUCE_MAC if (hostWindow != 0) { - detachComponentFromWindowRef (editorComp, hostWindow); + detachComponentFromWindowRef (editorComp, hostWindow, useNSView); hostWindow = 0; } #endif @@ -1164,7 +1179,7 @@ public: Window editorWnd = (Window) editorComp->getWindowHandle(); XReparentWindow (display, editorWnd, hostWindow, 0, 0); #else - hostWindow = attachComponentToWindowRef (editorComp, ptr); + hostWindow = attachComponentToWindowRef (editorComp, ptr, useNSView); #endif editorComp->setVisible (true); @@ -1210,7 +1225,7 @@ public: { // some hosts don't support the sizeWindow call, so do it manually.. #if JUCE_MAC - setNativeHostWindowSize (hostWindow, editorComp, newWidth, newHeight); + setNativeHostWindowSize (hostWindow, editorComp, newWidth, newHeight, useNSView); #elif JUCE_LINUX // (Currently, all linux hosts support sizeWindow, so this should never need to happen) @@ -1266,12 +1281,6 @@ public: } } - static PluginHostType& getHostType() - { - static PluginHostType hostType; - return hostType; - } - //============================================================================== // A component to hold the AudioProcessorEditor, and cope with some housekeeping // chores when it changes or repaints. @@ -1323,7 +1332,7 @@ public: { // If we have an unused keypress, move the key-focus to a host window // and re-inject the event.. - return forwardCurrentKeyEventToHost (this); + return forwardCurrentKeyEventToHost (this, wrapper.useNSView); } #endif @@ -1338,7 +1347,8 @@ public: editor->setBounds (getLocalBounds()); #if JUCE_MAC && ! JUCE_64BIT - updateEditorCompBounds (this); + if (! wrapper.useNSView) + updateEditorCompBounds (this); #endif } @@ -1349,8 +1359,9 @@ public: const int cw = child->getWidth(); const int ch = child->getHeight(); - #if JUCE_MAC && JUCE_64BIT - setTopLeftPosition (0, getHeight() - ch); + #if JUCE_MAC + if (wrapper.useNSView) + setTopLeftPosition (0, getHeight() - ch); #endif wrapper.resizeHostWindow (cw, ch); @@ -1405,7 +1416,8 @@ private: VSTMidiEventList outgoingEvents; VstSpeakerArrangementType speakerIn, speakerOut; int numInChans, numOutChans; - bool isProcessing, isBypassed, hasShutdown, firstProcessCallback, shouldDeleteEditor; + bool isProcessing, isBypassed, hasShutdown, firstProcessCallback; + bool shouldDeleteEditor, useNSView; HeapBlock channels; Array tempChannels; // see note in processReplacing() AudioSampleBuffer processTempBuffer; diff --git a/JuceLibraryCode/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.mm b/JuceLibraryCode/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.mm index b56cd23..8f22ef8 100644 --- a/JuceLibraryCode/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.mm +++ b/JuceLibraryCode/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.mm @@ -28,7 +28,7 @@ #include "../utility/juce_CheckSettingMacros.h" -#if JucePlugin_Build_VST +#if JucePlugin_Build_VST || JucePlugin_Build_VST3 #define JUCE_MAC_WINDOW_VISIBITY_BODGE 1 @@ -77,13 +77,82 @@ void initialiseMac() #endif } -void* attachComponentToWindowRef (Component* comp, void* windowRef); -void* attachComponentToWindowRef (Component* comp, void* windowRef) +void* attachComponentToWindowRef (Component* comp, void* parentWindowOrView, bool isNSView); +void* attachComponentToWindowRef (Component* comp, void* parentWindowOrView, bool isNSView) { JUCE_AUTORELEASEPOOL { - #if JUCE_64BIT - NSView* parentView = (NSView*) windowRef; + #if ! JUCE_64BIT + if (! isNSView) + { + NSWindow* hostWindow = [[NSWindow alloc] initWithWindowRef: parentWindowOrView]; + [hostWindow retain]; + [hostWindow setCanHide: YES]; + [hostWindow setReleasedWhenClosed: YES]; + + HIViewRef parentView = 0; + + WindowAttributes attributes; + GetWindowAttributes ((WindowRef) parentWindowOrView, &attributes); + if ((attributes & kWindowCompositingAttribute) != 0) + { + HIViewRef root = HIViewGetRoot ((WindowRef) parentWindowOrView); + HIViewFindByID (root, kHIViewWindowContentID, &parentView); + + if (parentView == 0) + parentView = root; + } + else + { + GetRootControl ((WindowRef) parentWindowOrView, (ControlRef*) &parentView); + + if (parentView == 0) + CreateRootControl ((WindowRef) parentWindowOrView, (ControlRef*) &parentView); + } + + // It seems that the only way to successfully position our overlaid window is by putting a dummy + // HIView into the host's carbon window, and then catching events to see when it gets repositioned + HIViewRef dummyView = 0; + HIImageViewCreate (0, &dummyView); + HIRect r = { {0, 0}, { (float) comp->getWidth(), (float) comp->getHeight()} }; + HIViewSetFrame (dummyView, &r); + HIViewAddSubview (parentView, dummyView); + comp->getProperties().set ("dummyViewRef", String::toHexString ((pointer_sized_int) (void*) dummyView)); + + EventHandlerRef ref; + const EventTypeSpec kControlBoundsChangedEvent = { kEventClassControl, kEventControlBoundsChanged }; + InstallEventHandler (GetControlEventTarget (dummyView), NewEventHandlerUPP (viewBoundsChangedEvent), 1, &kControlBoundsChangedEvent, (void*) comp, &ref); + comp->getProperties().set ("boundsEventRef", String::toHexString ((pointer_sized_int) (void*) ref)); + + updateEditorCompBounds (comp); + + #if ! JucePlugin_EditorRequiresKeyboardFocus + comp->addToDesktop (ComponentPeer::windowIsTemporary | ComponentPeer::windowIgnoresKeyPresses); + #else + comp->addToDesktop (ComponentPeer::windowIsTemporary); + #endif + + comp->setVisible (true); + comp->toFront (false); + + NSView* pluginView = (NSView*) comp->getWindowHandle(); + NSWindow* pluginWindow = [pluginView window]; + [pluginWindow setExcludedFromWindowsMenu: YES]; + [pluginWindow setCanHide: YES]; + + [hostWindow addChildWindow: pluginWindow + ordered: NSWindowAbove]; + [hostWindow orderFront: nil]; + [pluginWindow orderFront: nil]; + + attachWindowHidingHooks (comp, (WindowRef) parentWindowOrView, hostWindow); + + return hostWindow; + } + #endif + + (void) isNSView; + NSView* parentView = (NSView*) parentWindowOrView; #if JucePlugin_EditorRequiresKeyboardFocus comp->addToDesktop (0, parentView); @@ -100,162 +169,125 @@ void* attachComponentToWindowRef (Component* comp, void* windowRef) [[parentView window] setAcceptsMouseMovedEvents: YES]; return parentView; - #else - NSWindow* hostWindow = [[NSWindow alloc] initWithWindowRef: windowRef]; - [hostWindow retain]; - [hostWindow setCanHide: YES]; - [hostWindow setReleasedWhenClosed: YES]; - - HIViewRef parentView = 0; - - WindowAttributes attributes; - GetWindowAttributes ((WindowRef) windowRef, &attributes); - if ((attributes & kWindowCompositingAttribute) != 0) - { - HIViewRef root = HIViewGetRoot ((WindowRef) windowRef); - HIViewFindByID (root, kHIViewWindowContentID, &parentView); - - if (parentView == 0) - parentView = root; - } - else - { - GetRootControl ((WindowRef) windowRef, (ControlRef*) &parentView); - - if (parentView == 0) - CreateRootControl ((WindowRef) windowRef, (ControlRef*) &parentView); - } - - // It seems that the only way to successfully position our overlaid window is by putting a dummy - // HIView into the host's carbon window, and then catching events to see when it gets repositioned - HIViewRef dummyView = 0; - HIImageViewCreate (0, &dummyView); - HIRect r = { {0, 0}, { (float) comp->getWidth(), (float) comp->getHeight()} }; - HIViewSetFrame (dummyView, &r); - HIViewAddSubview (parentView, dummyView); - comp->getProperties().set ("dummyViewRef", String::toHexString ((pointer_sized_int) (void*) dummyView)); - - EventHandlerRef ref; - const EventTypeSpec kControlBoundsChangedEvent = { kEventClassControl, kEventControlBoundsChanged }; - InstallEventHandler (GetControlEventTarget (dummyView), NewEventHandlerUPP (viewBoundsChangedEvent), 1, &kControlBoundsChangedEvent, (void*) comp, &ref); - comp->getProperties().set ("boundsEventRef", String::toHexString ((pointer_sized_int) (void*) ref)); - - updateEditorCompBounds (comp); - - #if ! JucePlugin_EditorRequiresKeyboardFocus - comp->addToDesktop (ComponentPeer::windowIsTemporary | ComponentPeer::windowIgnoresKeyPresses); - #else - comp->addToDesktop (ComponentPeer::windowIsTemporary); - #endif - - comp->setVisible (true); - comp->toFront (false); - - NSView* pluginView = (NSView*) comp->getWindowHandle(); - NSWindow* pluginWindow = [pluginView window]; - [pluginWindow setExcludedFromWindowsMenu: YES]; - [pluginWindow setCanHide: YES]; - - [hostWindow addChildWindow: pluginWindow - ordered: NSWindowAbove]; - [hostWindow orderFront: nil]; - [pluginWindow orderFront: nil]; - - attachWindowHidingHooks (comp, (WindowRef) windowRef, hostWindow); - - return hostWindow; - #endif } } -void detachComponentFromWindowRef (Component* comp, void* nsWindow); -void detachComponentFromWindowRef (Component* comp, void* nsWindow) +void detachComponentFromWindowRef (Component* comp, void* window, bool isNSView); +void detachComponentFromWindowRef (Component* comp, void* window, bool isNSView) { JUCE_AUTORELEASEPOOL { - #if JUCE_64BIT - comp->removeFromDesktop(); - #else - EventHandlerRef ref = (EventHandlerRef) (void*) (pointer_sized_int) - comp->getProperties() ["boundsEventRef"].toString().getHexValue64(); - RemoveEventHandler (ref); + #if ! JUCE_64BIT + if (! isNSView) + { + EventHandlerRef ref = (EventHandlerRef) (void*) (pointer_sized_int) + comp->getProperties() ["boundsEventRef"].toString().getHexValue64(); + RemoveEventHandler (ref); - removeWindowHidingHooks (comp); + removeWindowHidingHooks (comp); - HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int) - comp->getProperties() ["dummyViewRef"].toString().getHexValue64(); + HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int) + comp->getProperties() ["dummyViewRef"].toString().getHexValue64(); - if (HIViewIsValid (dummyView)) - CFRelease (dummyView); + if (HIViewIsValid (dummyView)) + CFRelease (dummyView); - NSWindow* hostWindow = (NSWindow*) nsWindow; - NSView* pluginView = (NSView*) comp->getWindowHandle(); - NSWindow* pluginWindow = [pluginView window]; + NSWindow* hostWindow = (NSWindow*) window; + NSView* pluginView = (NSView*) comp->getWindowHandle(); + NSWindow* pluginWindow = [pluginView window]; - [hostWindow removeChildWindow: pluginWindow]; - comp->removeFromDesktop(); + [pluginView retain]; + [hostWindow removeChildWindow: pluginWindow]; + [pluginWindow close]; + comp->removeFromDesktop(); + [pluginView release]; - [hostWindow release]; + [hostWindow release]; - // The event loop needs to be run between closing the window and deleting the plugin, - // presumably to let the cocoa objects get tidied up. Leaving out this line causes crashes - // in Live and Reaper when you delete the plugin with its window open. - // (Doing it this way rather than using a single longer timout means that we can guarantee - // how many messages will be dispatched, which seems to be vital in Reaper) - for (int i = 20; --i >= 0;) - MessageManager::getInstance()->runDispatchLoopUntil (1); + static bool needToRunMessageLoop = ! getHostType().isReaper(); + + // The event loop needs to be run between closing the window and deleting the plugin, + // presumably to let the cocoa objects get tidied up. Leaving out this line causes crashes + // in Live when you delete the plugin with its window open. + // (Doing it this way rather than using a single longer timout means that we can guarantee + // how many messages will be dispatched, which seems to be vital in Reaper) + if (needToRunMessageLoop) + for (int i = 20; --i >= 0;) + MessageManager::getInstance()->runDispatchLoopUntil (1); + + return; + } #endif + + (void) isNSView; + comp->removeFromDesktop(); } } -void setNativeHostWindowSize (void* nsWindow, Component* component, int newWidth, int newHeight); -void setNativeHostWindowSize (void* nsWindow, Component* component, int newWidth, int newHeight) +void setNativeHostWindowSize (void* window, Component* component, int newWidth, int newHeight, bool isNSView); +void setNativeHostWindowSize (void* window, Component* component, int newWidth, int newHeight, bool isNSView) { JUCE_AUTORELEASEPOOL { - #if JUCE_64BIT - if (NSView* hostView = (NSView*) nsWindow) + #if ! JUCE_64BIT + if (! isNSView) { - // xxx is this necessary, or do the hosts detect a change in the child view and do this automatically? - [hostView setFrameSize: NSMakeSize ([hostView frame].size.width + (newWidth - component->getWidth()), - [hostView frame].size.height + (newHeight - component->getHeight()))]; + if (HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int) + component->getProperties() ["dummyViewRef"].toString().getHexValue64()) + { + HIRect frameRect; + HIViewGetFrame (dummyView, &frameRect); + frameRect.size.width = newWidth; + frameRect.size.height = newHeight; + HIViewSetFrame (dummyView, &frameRect); + } + + return; } - #else - (void) nsWindow; + #endif + + (void) isNSView; - if (HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int) - component->getProperties() ["dummyViewRef"].toString().getHexValue64()) + if (NSView* hostView = (NSView*) window) { - HIRect frameRect; - HIViewGetFrame (dummyView, &frameRect); - frameRect.size.width = newWidth; - frameRect.size.height = newHeight; - HIViewSetFrame (dummyView, &frameRect); + const int dx = newWidth - component->getWidth(); + const int dy = newHeight - component->getHeight(); + + NSRect r = [hostView frame]; + r.size.width += dx; + r.size.height += dy; + r.origin.y -= dy; + [hostView setFrame: r]; } - #endif } } -void checkWindowVisibility (void* nsWindow, Component* comp); -void checkWindowVisibility (void* nsWindow, Component* comp) +void checkWindowVisibility (void* window, Component* comp, bool isNSView); +void checkWindowVisibility (void* window, Component* comp, bool isNSView) { + (void) window; (void) comp; (void) isNSView; + #if ! JUCE_64BIT - comp->setVisible ([((NSWindow*) nsWindow) isVisible]); + if (! isNSView) + comp->setVisible ([((NSWindow*) window) isVisible]); #endif } -bool forwardCurrentKeyEventToHost (Component* comp); -bool forwardCurrentKeyEventToHost (Component* comp) +bool forwardCurrentKeyEventToHost (Component* comp, bool isNSView); +bool forwardCurrentKeyEventToHost (Component* comp, bool isNSView) { - #if JUCE_64BIT - (void) comp; - return false; - #else - NSWindow* win = [(NSView*) comp->getWindowHandle() window]; - [[win parentWindow] makeKeyWindow]; - repostCurrentNSEvent(); - return true; + #if ! JUCE_64BIT + if (! isNSView) + { + NSWindow* win = [(NSView*) comp->getWindowHandle() window]; + [[win parentWindow] makeKeyWindow]; + repostCurrentNSEvent(); + return true; + } #endif + + (void) comp; (void) isNSView; + return false; } } // (juce namespace) diff --git a/JuceLibraryCode/modules/juce_audio_plugin_client/juce_module_info b/JuceLibraryCode/modules/juce_audio_plugin_client/juce_module_info index 12bd247..cd95a31 100644 --- a/JuceLibraryCode/modules/juce_audio_plugin_client/juce_module_info +++ b/JuceLibraryCode/modules/juce_audio_plugin_client/juce_module_info @@ -1,8 +1,8 @@ { "id": "juce_audio_plugin_client", "name": "JUCE audio plugin wrapper classes", - "version": "3.0.1", - "description": "Classes for building VST, RTAS and AU plugins.", + "version": "3.0.3", + "description": "Classes for building VST, VST3, RTAS, AAX and AU plugins.", "website": "http://www.juce.com/juce", "license": "GPL/Commercial", @@ -14,6 +14,8 @@ "compile": [ { "file": "VST/juce_VST_Wrapper.cpp" }, { "file": "VST/juce_VST_Wrapper.mm", "target": "xcode" }, + { "file": "VST3/juce_VST3_Wrapper.cpp" }, + { "file": "VST3/juce_VST3_Wrapper.mm", "target": "xcode" }, { "file": "RTAS/juce_RTAS_DigiCode1.cpp", "warnings": "disabled", "stdcall": "1", "target": "xcode, msvc" }, { "file": "RTAS/juce_RTAS_DigiCode2.cpp", "warnings": "disabled", "stdcall": "1", "target": "xcode, msvc" }, { "file": "RTAS/juce_RTAS_DigiCode3.cpp", "warnings": "disabled", "stdcall": "1", "target": "xcode, msvc" }, @@ -36,6 +38,7 @@ "RTAS/*.mm", "RTAS/*.h", "VST/*", + "VST3/*", "AAX/*", "utility/*" ] diff --git a/JuceLibraryCode/modules/juce_audio_plugin_client/utility/juce_CheckSettingMacros.h b/JuceLibraryCode/modules/juce_audio_plugin_client/utility/juce_CheckSettingMacros.h index 7474655..b3f51b5 100644 --- a/JuceLibraryCode/modules/juce_audio_plugin_client/utility/juce_CheckSettingMacros.h +++ b/JuceLibraryCode/modules/juce_audio_plugin_client/utility/juce_CheckSettingMacros.h @@ -25,7 +25,8 @@ // The following checks should cause a compile error if you've forgotten to // define all your plugin settings properly.. -#if ! (JucePlugin_Build_VST || JucePlugin_Build_AU || JucePlugin_Build_RTAS || JucePlugin_Build_AAX \ +#if ! (JucePlugin_Build_VST || JucePlugin_Build_VST3 \ + || JucePlugin_Build_AU || JucePlugin_Build_RTAS || JucePlugin_Build_AAX \ || JucePlugin_Build_Standalone || JucePlugin_Build_LV2) #error "You need to enable at least one plugin format!" #endif @@ -75,11 +76,16 @@ #endif //============================================================================== -#if _WIN64 || (__LP64__ && (defined(__APPLE_CPP__) || defined(__APPLE_CC__))) +#if _WIN64 || (__LP64__ && (defined (__APPLE_CPP__) || defined (__APPLE_CC__))) #undef JucePlugin_Build_RTAS #define JucePlugin_Build_RTAS 0 #endif +#if ! (defined (_MSC_VER) || defined (__APPLE_CPP__) || defined (__APPLE_CC__)) + #undef JucePlugin_Build_VST3 + #define JucePlugin_Build_VST3 0 +#endif + //============================================================================== #if JucePlugin_Build_RTAS && _MSC_VER && ! defined (JucePlugin_WinBag_path) #error "You need to define the JucePlugin_WinBag_path value!" diff --git a/JuceLibraryCode/modules/juce_audio_plugin_client/utility/juce_IncludeModuleHeaders.h b/JuceLibraryCode/modules/juce_audio_plugin_client/utility/juce_IncludeModuleHeaders.h index 8e62206..32d06d7 100644 --- a/JuceLibraryCode/modules/juce_audio_plugin_client/utility/juce_IncludeModuleHeaders.h +++ b/JuceLibraryCode/modules/juce_audio_plugin_client/utility/juce_IncludeModuleHeaders.h @@ -26,14 +26,21 @@ using namespace juce; -#if JUCE_MAC && ! DOXYGEN - #define Point juce::Point - #define Component juce::Component - - namespace juce - { - void repostCurrentNSEvent(); - } -#endif +namespace juce +{ + #if JUCE_MAC && ! DOXYGEN + #define Point juce::Point + #define Component juce::Component + + void repostCurrentNSEvent(); + #endif + + //============================================================================== + inline const PluginHostType& getHostType() + { + static PluginHostType hostType; + return hostType; + } +} extern AudioProcessor* JUCE_CALLTYPE createPluginFilterOfType (AudioProcessor::WrapperType); diff --git a/JuceLibraryCode/modules/juce_audio_plugin_client/utility/juce_PluginHostType.h b/JuceLibraryCode/modules/juce_audio_plugin_client/utility/juce_PluginHostType.h index 1f020c5..c321fc1 100644 --- a/JuceLibraryCode/modules/juce_audio_plugin_client/utility/juce_PluginHostType.h +++ b/JuceLibraryCode/modules/juce_audio_plugin_client/utility/juce_PluginHostType.h @@ -39,14 +39,19 @@ public: AbletonLive7, AbletonLive8, AbletonLiveGeneric, + AdobeAudition, AdobePremierePro, AppleLogic, + Ardour, CakewalkSonar8, CakewalkSonarGeneric, DigidesignProTools, + DigitalPerformer, + FruityLoops, + MagixSamplitude, + MergingPyramix, + MuseReceptorGeneric, Reaper, - Tracktion3, - TracktionGeneric, SteinbergCubase4, SteinbergCubase5, SteinbergCubase5Bridged, @@ -62,13 +67,11 @@ public: SteinbergWavelab7, SteinbergWavelab8, SteinbergWavelabGeneric, - MuseReceptorGeneric, - MagixSamplitude, - FruityLoops, - WaveBurner, - DigitalPerformer, + SteinbergTestHost, StudioOne, - MergingPyramix, + Tracktion3, + TracktionGeneric, + WaveBurner, VBVSTScanner }; @@ -76,25 +79,28 @@ public: //============================================================================== bool isAbletonLive() const noexcept { return type == AbletonLive6 || type == AbletonLive7 || type == AbletonLive8 || type == AbletonLiveGeneric; } - bool isNuendo() const noexcept { return type == SteinbergNuendo3 || type == SteinbergNuendo4 || type == SteinbergNuendo5 || type == SteinbergNuendoGeneric; } + bool isAdobeAudition() const noexcept { return type == AdobeAudition; } + bool isArdour() const noexcept { return type == Ardour; } + bool isDigitalPerformer() const noexcept { return type == DigitalPerformer; } bool isCubase() const noexcept { return type == SteinbergCubase4 || type == SteinbergCubase5 || type == SteinbergCubase5Bridged || type == SteinbergCubase6 || type == SteinbergCubase7 || type == SteinbergCubaseGeneric; } bool isCubaseBridged() const noexcept { return type == SteinbergCubase5Bridged; } - bool isSteinberg() const noexcept { return isCubase() || isNuendo() || isWavelab(); } - bool isTracktion() const noexcept { return type == Tracktion3 || type == TracktionGeneric; } - bool isSonar() const noexcept { return type == CakewalkSonar8 || type == CakewalkSonarGeneric; } - bool isWavelab() const noexcept { return isWavelabLegacy() || type == SteinbergWavelab7 || type == SteinbergWavelab8 || type == SteinbergWavelabGeneric; } - bool isWavelabLegacy() const noexcept { return type == SteinbergWavelab5 || type == SteinbergWavelab6; } - bool isPremiere() const noexcept { return type == AdobePremierePro; } bool isLogic() const noexcept { return type == AppleLogic; } - bool isReceptor() const noexcept { return type == MuseReceptorGeneric; } - bool isSamplitude() const noexcept { return type == MagixSamplitude; } bool isFruityLoops() const noexcept { return type == FruityLoops; } - bool isWaveBurner() const noexcept { return type == WaveBurner; } - bool isDigitalPerformer() const noexcept { return type == DigitalPerformer; } + bool isNuendo() const noexcept { return type == SteinbergNuendo3 || type == SteinbergNuendo4 || type == SteinbergNuendo5 || type == SteinbergNuendoGeneric; } + bool isPremiere() const noexcept { return type == AdobePremierePro; } + bool isPyramix() const noexcept { return type == MergingPyramix; } + bool isReceptor() const noexcept { return type == MuseReceptorGeneric; } bool isReaper() const noexcept { return type == Reaper; } + bool isSamplitude() const noexcept { return type == MagixSamplitude; } + bool isSonar() const noexcept { return type == CakewalkSonar8 || type == CakewalkSonarGeneric; } + bool isSteinbergTestHost() const noexcept{ return type == SteinbergTestHost; } + bool isSteinberg() const noexcept { return isCubase() || isNuendo() || isWavelab() || isSteinbergTestHost(); } bool isStudioOne() const noexcept { return type == StudioOne; } - bool isPyramix() const noexcept { return type == MergingPyramix; } + bool isTracktion() const noexcept { return type == Tracktion3 || type == TracktionGeneric; } bool isVBVSTScanner() const noexcept { return type == VBVSTScanner; } + bool isWaveBurner() const noexcept { return type == WaveBurner; } + bool isWavelab() const noexcept { return isWavelabLegacy() || type == SteinbergWavelab7 || type == SteinbergWavelab8 || type == SteinbergWavelabGeneric; } + bool isWavelabLegacy() const noexcept { return type == SteinbergWavelab5 || type == SteinbergWavelab6; } //============================================================================== const char* getHostDescription() const noexcept @@ -105,14 +111,18 @@ public: case AbletonLive7: return "Ableton Live 7"; case AbletonLive8: return "Ableton Live 8"; case AbletonLiveGeneric: return "Ableton Live"; + case AdobeAudition: return "Adobe Audition"; case AdobePremierePro: return "Adobe Premiere"; case AppleLogic: return "Apple Logic"; case CakewalkSonar8: return "Cakewalk Sonar 8"; case CakewalkSonarGeneric: return "Cakewalk Sonar"; case DigidesignProTools: return "ProTools"; + case DigitalPerformer: return "DigitalPerformer"; + case FruityLoops: return "FruityLoops"; + case MagixSamplitude: return "Magix Samplitude"; + case MergingPyramix: return "Pyramix"; + case MuseReceptorGeneric: return "Muse Receptor"; case Reaper: return "Reaper"; - case Tracktion3: return "Tracktion 3"; - case TracktionGeneric: return "Tracktion"; case SteinbergCubase4: return "Steinberg Cubase 4"; case SteinbergCubase5: return "Steinberg Cubase 5"; case SteinbergCubase5Bridged: return "Steinberg Cubase 5 Bridged"; @@ -128,14 +138,12 @@ public: case SteinbergWavelab7: return "Steinberg Wavelab 7"; case SteinbergWavelab8: return "Steinberg Wavelab 8"; case SteinbergWavelabGeneric: return "Steinberg Wavelab"; - case MuseReceptorGeneric: return "Muse Receptor"; - case MagixSamplitude: return "Magix Samplitude"; - case FruityLoops: return "FruityLoops"; - case WaveBurner: return "WaveBurner"; - case DigitalPerformer: return "DigitalPerformer"; + case SteinbergTestHost: return "Steinberg TestHost"; case StudioOne: return "Studio One"; - case MergingPyramix: return "Pyramix"; + case Tracktion3: return "Tracktion 3"; + case TracktionGeneric: return "Tracktion"; case VBVSTScanner: return "VBVSTScanner"; + case WaveBurner: return "WaveBurner"; default: break; } @@ -155,7 +163,7 @@ private: const String hostPath (getHostPath()); const String hostFilename (File (hostPath).getFileName()); - #if JUCE_MAC + #if JUCE_MAC if (hostPath.containsIgnoreCase ("Live 6.")) return AbletonLive6; if (hostPath.containsIgnoreCase ("Live 7.")) return AbletonLive7; if (hostPath.containsIgnoreCase ("Live 8.")) return AbletonLive8; @@ -182,11 +190,12 @@ private: if (hostPath.containsIgnoreCase ("Tracktion 3")) return Tracktion3; if (hostFilename.containsIgnoreCase ("Tracktion")) return TracktionGeneric; - #elif JUCE_WINDOWS + #elif JUCE_WINDOWS if (hostFilename.containsIgnoreCase ("Live 6.")) return AbletonLive6; if (hostFilename.containsIgnoreCase ("Live 7.")) return AbletonLive7; if (hostFilename.containsIgnoreCase ("Live 8.")) return AbletonLive8; if (hostFilename.containsIgnoreCase ("Live ")) return AbletonLiveGeneric; + if (hostFilename.containsIgnoreCase ("Audition")) return AdobeAudition; if (hostFilename.containsIgnoreCase ("Adobe Premiere")) return AdobePremierePro; if (hostFilename.containsIgnoreCase ("ProTools")) return DigidesignProTools; if (hostPath.containsIgnoreCase ("SONAR 8")) return CakewalkSonar8; @@ -207,6 +216,7 @@ private: if (hostPath.containsIgnoreCase ("Wavelab 8")) return SteinbergWavelab8; if (hostPath.containsIgnoreCase ("Nuendo")) return SteinbergNuendoGeneric; if (hostFilename.containsIgnoreCase ("Wavelab")) return SteinbergWavelabGeneric; + if (hostFilename.containsIgnoreCase ("TestHost")) return SteinbergTestHost; if (hostFilename.containsIgnoreCase ("rm-host")) return MuseReceptorGeneric; if (hostFilename.startsWith ("FL")) return FruityLoops; if (hostPath.containsIgnoreCase ("Studio One")) return StudioOne; @@ -216,7 +226,8 @@ private: if (hostFilename.startsWithIgnoreCase ("Sam")) return MagixSamplitude; #elif JUCE_LINUX - jassertfalse // not yet done! + if (hostFilename.containsIgnoreCase ("Ardour")) return Ardour; + #else #error #endif diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm index 375b2e7..cf2efcb 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm @@ -478,8 +478,8 @@ public: resetBusses(); - prepared = (AudioUnitInitialize (audioUnit) == noErr); - jassert (prepared); + jassert (! prepared); + initialiseAudioUnit(); } } @@ -499,6 +499,14 @@ public: incomingMidi.clear(); } + bool initialiseAudioUnit() + { + if (! prepared) + prepared = (AudioUnitInitialize (audioUnit) == noErr); + + return prepared; + } + void resetBusses() { for (int i = 0; i < numInputBusses; ++i) AudioUnitReset (audioUnit, kAudioUnitScope_Input, i); @@ -653,8 +661,13 @@ public: void sendAllParametersChangedEvents() { - for (int i = 0; i < parameters.size(); ++i) - sendParameterChangeEvent (i); + jassert (audioUnit != nullptr); + + AudioUnitParameter param; + param.mAudioUnit = audioUnit; + param.mParameterID = kAUParameterListener_AnyParameter; + + AUParameterListenerNotify (nullptr, nullptr, ¶m); } const String getParameterName (int index) override @@ -799,10 +812,14 @@ public: if (propertyList != 0) { + initialiseAudioUnit(); + AudioUnitSetProperty (audioUnit, kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, 0, &propertyList, sizeof (propertyList)); sendAllParametersChangedEvents(); + + CFRelease (propertyList); } } @@ -1295,8 +1312,7 @@ private: }; //============================================================================== -class AudioUnitPluginWindowCocoa : public AudioProcessorEditor, - public Timer +class AudioUnitPluginWindowCocoa : public AudioProcessorEditor { public: AudioUnitPluginWindowCocoa (AudioUnitPluginInstance& p, bool createGenericViewIfNeeded) @@ -1335,30 +1351,25 @@ public: wrapper.setSize (getWidth(), getHeight()); } - void timerCallback() override - { - wrapper.resizeToFitView(); - startTimer (jmin (713, getTimerInterval() + 51)); - } - void childBoundsChanged (Component*) override { setSize (wrapper.getWidth(), wrapper.getHeight()); - startTimer (70); } private: AudioUnitPluginInstance& plugin; - NSViewComponent wrapper; + + AutoResizingNSViewComponent wrapper; bool createView (const bool createGenericViewIfNeeded) { + if (! plugin.initialiseAudioUnit()) + return false; + NSView* pluginView = nil; UInt32 dataSize = 0; Boolean isWritable = false; - AudioUnitInitialize (plugin.audioUnit); - if (AudioUnitGetPropertyInfo (plugin.audioUnit, kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global, 0, &dataSize, &isWritable) == noErr && dataSize != 0 @@ -1410,10 +1421,7 @@ private: wrapper.setView (pluginView); if (pluginView != nil) - { - timerCallback(); - startTimer (70); - } + wrapper.resizeToFitView(); return pluginView != nil; } @@ -1528,16 +1536,10 @@ private: Float32Point pos = { 0, 0 }; Float32Point size = { 250, 200 }; - HIViewRef pluginView = 0; - AudioUnitCarbonViewCreate (carbonView, - owner.getAudioUnit(), - windowRef, - rootView, - &pos, - &size, - (ControlRef*) &pluginView); + AudioUnitCarbonViewCreate (carbonView, owner.getAudioUnit(), windowRef, rootView, + &pos, &size, (ControlRef*) &pluginView); return pluginView; } diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp index d162906..55361fc 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp @@ -26,96 +26,20 @@ } // namespace juce -// Wow, those VST guys really don't worry too much about compiler warnings. -#if JUCE_MSVC - #pragma warning (disable: 4505) - #pragma warning (push, 0) - #pragma warning (disable: 4702) -#elif JUCE_CLANG - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wnon-virtual-dtor" - #pragma clang diagnostic ignored "-Wreorder" - #pragma clang diagnostic ignored "-Wunsequenced" - #pragma clang diagnostic ignored "-Wint-to-pointer-cast" - #pragma clang diagnostic ignored "-Wunused-parameter" - #pragma clang diagnostic ignored "-Wconversion" - #pragma clang diagnostic ignored "-Woverloaded-virtual" - #pragma clang diagnostic ignored "-Wshadow" +#if JucePlugin_Build_VST3 + #undef JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY + #define JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY 1 #endif -/* These files come with the Steinberg VST3 SDK - to get them, you'll need to - visit the Steinberg website and agree to whatever is currently required to - get them. +#include "juce_VST3Headers.h" - Then, you'll need to make sure your include path contains your "VST SDK3" - directory (or whatever you've named it on your machine). The introjucer has - a special box for setting this path. -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if JUCE_MSVC - #pragma warning (pop) -#elif JUCE_CLANG - #pragma clang diagnostic pop -#endif - -#undef ASSERT -#undef WARNING -#undef PRINTSYSERROR -#undef DEBUGSTR -#undef DBPRT0 -#undef DBPRT1 -#undef DBPRT2 -#undef DBPRT3 -#undef DBPRT4 -#undef DBPRT5 -#undef calloc -#undef free -#undef malloc -#undef realloc -#undef NEW -#undef NEWVEC -#undef VERIFY -#undef VERIFY_IS -#undef VERIFY_NOT -#undef META_CREATE_FUNC -#undef CLASS_CREATE_FUNC -#undef SINGLE_CREATE_FUNC -#undef _META_CLASS -#undef _META_CLASS_IFACE -#undef _META_CLASS_SINGLE -#undef META_CLASS -#undef META_CLASS_IFACE -#undef META_CLASS_SINGLE -#undef OBJ_METHODS -#undef SINGLETON -#undef QUERY_INTERFACE +#undef JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY namespace juce { +#include "juce_VST3Common.h" + using namespace Steinberg; //============================================================================== @@ -157,71 +81,6 @@ static int warnOnFailure (int result) #define warnOnFailure(x) x #endif -//============================================================================== -template -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(); } - - operator ObjectType*() const noexcept { return source; } - ObjectType* get() const noexcept { return source; } - ObjectType& operator*() const noexcept { return *source; } - ObjectType* operator->() const noexcept { return source; } - - ComSmartPtr& operator= (const ComSmartPtr& other) { return operator= (other.source); } - - ComSmartPtr& operator= (ObjectType* const newObjectToTakePossessionOf) - { - ComSmartPtr p (newObjectToTakePossessionOf); - std::swap (p.source, source); - return *this; - } - - bool operator== (ObjectType* const other) noexcept { return source == other; } - bool operator!= (ObjectType* const other) noexcept { return source != other; } - - bool loadFrom (FUnknown* o) - { - *this = nullptr; - return o != nullptr && o->queryInterface (ObjectType::iid, (void**) &source) == kResultOk; - } - - bool loadFrom (IPluginFactory* factory, const TUID& uuid) - { - jassert (factory != nullptr); - *this = nullptr; - return factory->createInstance (uuid, ObjectType::iid, (void**) &source) == kResultOk; - } - -private: - ObjectType* source; -}; - -//============================================================================== -#define JUCE_DECLARE_VST3_COM_REF_METHODS \ - Steinberg::uint32 JUCE_CALLTYPE addRef() { return (Steinberg::uint32) ++refCount; } \ - Steinberg::uint32 JUCE_CALLTYPE release() { const int r = --refCount; if (r == 0) delete this; return (Steinberg::uint32) r; } - -#define JUCE_DECLARE_VST3_COM_QUERY_METHODS \ - tresult PLUGIN_API JUCE_CALLTYPE queryInterface (const TUID, void** obj) \ - {\ - jassertfalse; \ - *obj = nullptr; \ - return kNotImplemented; \ - } - -//============================================================================== -static String toString (const char8* string) noexcept { return String (string); } -static String toString (const char16* string) noexcept { return String (CharPointer_UTF16 ((CharPointer_UTF16::CharType*) string)); } - -// NB: The casts are handled by a Steinberg::UString operator -static String toString (const UString128& string) noexcept { return toString (static_cast (string)); } -static String toString (const UString256& string) noexcept { return toString (static_cast (string)); } - //============================================================================== static int getHashForTUID (const TUID& tuid) noexcept { @@ -299,9 +158,10 @@ static int getNumSingleDirectionChannelsFor (Vst::IComponent* component, return numChannels; } -static void activateAllBussesOfType (Vst::IComponent* component, - bool activateInputs, - bool activateAudioChannels) +static void setStateForAllBussesOfType (Vst::IComponent* component, + bool state, + bool activateInputs, + bool activateAudioChannels) { jassert (component != nullptr); @@ -310,7 +170,7 @@ static void activateAllBussesOfType (Vst::IComponent* component, const Steinberg::int32 numBuses = component->getBusCount (mediaType, direction); for (Steinberg::int32 i = numBuses; --i >= 0;) - warnOnFailure (component->activateBus (mediaType, direction, i, true)); + warnOnFailure (component->activateBus (mediaType, direction, i, state)); } //============================================================================== @@ -457,42 +317,6 @@ static Vst::SpeakerArrangement getSpeakerArrangementFrom (const String& string) return Vst::SpeakerArr::getSpeakerArrangementFromString (string.toUTF8()); } -/** - @note There can only be 1 arrangement per channel count. (i.e.: 4 channels == k31Cine OR k40Cine) -*/ -static void fillWithCorrespondingSpeakerArrangements (Array& destination, - int numChannels) -{ - using namespace Vst::SpeakerArr; - - destination.clearQuick(); - - if (numChannels <= 0) - { - destination.add (kEmpty); - return; - } - - /* - The order of the arrangement checks must be descending, since most plugins test for - the first arrangement to match their number of specified channels. - */ - if (numChannels >= 14) destination.add (k131); - if (numChannels >= 13) destination.add (k130); - if (numChannels >= 12) destination.add (k111); - if (numChannels >= 11) destination.add (k101); - if (numChannels >= 10) destination.add (k91); - if (numChannels >= 9) destination.add (k90); - if (numChannels >= 8) destination.add (k71CineFullFront); - if (numChannels >= 7) destination.add (k61Cine); - if (numChannels >= 6) destination.add (k51); - if (numChannels >= 5) destination.add (k50); - if (numChannels >= 4) destination.add (k31Cine); - if (numChannels >= 3) destination.add (k30Cine); - if (numChannels >= 2) destination.add (kStereo); - if (numChannels >= 1) destination.add (kMono); -} - //============================================================================== static StringArray getPluginEffectCategories() { @@ -528,170 +352,6 @@ static StringArray getPluginInstrumentCategories() return StringArray (categories); } -//============================================================================== -class MidiEventList : public Vst::IEventList -{ -public: - MidiEventList() {} - virtual ~MidiEventList() {} - - JUCE_DECLARE_VST3_COM_REF_METHODS - JUCE_DECLARE_VST3_COM_QUERY_METHODS - - //============================================================================== - void clear() - { - events.clearQuick(); - } - - Steinberg::int32 PLUGIN_API getEventCount() override - { - return (Steinberg::int32) events.size(); - } - - // NB: This has to cope with out-of-range indexes from some plugins. - tresult PLUGIN_API getEvent (Steinberg::int32 index, Vst::Event& e) override - { - if (isPositiveAndBelow ((int) index, events.size())) - { - e = events.getReference ((int) index); - return kResultTrue; - } - - return kResultFalse; - } - - tresult PLUGIN_API addEvent (Vst::Event& e) override - { - events.add (e); - return kResultTrue; - } - - //============================================================================== - static void toMidiBuffer (MidiBuffer& result, Vst::IEventList& eventList) - { - using namespace Vst; - - for (Steinberg::int32 i = 0; i < eventList.getEventCount(); ++i) - { - Event e; - - if (eventList.getEvent (i, e) == kResultOk) - { - switch (e.type) - { - case Event::kNoteOnEvent: - result.addEvent (MidiMessage::noteOn (createSafeChannel (e.noteOn.channel), - createSafeNote (e.noteOn.pitch), - (uint8) denormaliseToMidiValue (e.noteOn.velocity)), - e.sampleOffset); - break; - - case Event::kNoteOffEvent: - result.addEvent (MidiMessage::noteOff (createSafeChannel (e.noteOff.channel), - createSafeNote (e.noteOff.pitch), - (uint8) denormaliseToMidiValue (e.noteOff.velocity)), - e.sampleOffset); - break; - - case Event::kPolyPressureEvent: - result.addEvent (MidiMessage::aftertouchChange (createSafeChannel (e.polyPressure.channel), - createSafeNote (e.polyPressure.pitch), - denormaliseToMidiValue (e.polyPressure.pressure)), - e.sampleOffset); - break; - - case Event::kDataEvent: - result.addEvent (MidiMessage::createSysExMessage (e.data.bytes, e.data.size), - e.sampleOffset); - break; - - default: - break; - } - } - } - } - - static void toEventList (Vst::IEventList& result, MidiBuffer& midiBuffer) - { - using namespace Vst; - - MidiBuffer::Iterator iterator (midiBuffer); - MidiMessage msg; - int midiEventPosition = 0; - - enum { maxNumEvents = 2048 }; // Steinberg's Host Checker states no more than 2048 events are allowed at once - int numEvents = 0; - - while (iterator.getNextEvent (msg, midiEventPosition)) - { - if (++numEvents > maxNumEvents) - break; - - Event e = { 0 }; - - if (msg.isNoteOn()) - { - e.type = Event::kNoteOnEvent; - e.noteOn.channel = createSafeChannel (msg.getChannel()); - e.noteOn.pitch = createSafeNote (msg.getNoteNumber()); - e.noteOn.velocity = normaliseMidiValue (msg.getVelocity()); - e.noteOn.length = 0; - e.noteOn.tuning = 0.0f; - e.noteOn.noteId = -1; - } - else if (msg.isNoteOff()) - { - e.type = Event::kNoteOffEvent; - e.noteOff.channel = createSafeChannel (msg.getChannel()); - e.noteOff.pitch = createSafeNote (msg.getNoteNumber()); - e.noteOff.velocity = normaliseMidiValue (msg.getVelocity()); - e.noteOff.tuning = 0.0f; - e.noteOff.noteId = -1; - } - else if (msg.isSysEx()) - { - e.type = Event::kDataEvent; - e.data.bytes = msg.getSysExData(); - e.data.size = msg.getSysExDataSize(); - e.data.type = DataEvent::kMidiSysEx; - } - else if (msg.isAftertouch()) - { - e.type = Event::kPolyPressureEvent; - e.polyPressure.channel = createSafeChannel (msg.getChannel()); - e.polyPressure.pitch = createSafeNote (msg.getNoteNumber()); - e.polyPressure.pressure = normaliseMidiValue (msg.getAfterTouchValue()); - } - else - { - continue; - } - - e.busIndex = 0; - e.sampleOffset = midiEventPosition; - - result.addEvent (e); - } - } - -private: - Array events; - Atomic refCount; - - static Steinberg::int16 createSafeChannel (int channel) noexcept { return (Steinberg::int16) jlimit (0, 15, channel - 1); } - static int createSafeChannel (Steinberg::int16 channel) noexcept { return (int) jlimit (1, 16, channel + 1); } - - static Steinberg::int16 createSafeNote (int note) noexcept { return (Steinberg::int16) jlimit (0, 127, note); } - static int createSafeNote (Steinberg::int16 note) noexcept { return jlimit (0, 127, (int) note); } - - static float normaliseMidiValue (int value) noexcept { return jlimit (0.0f, 1.0f, (float) value / 127.0f); } - static int denormaliseToMidiValue (float value) noexcept { return roundToInt (jlimit (0.0f, 127.0f, value * 127.0f)); } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiEventList) -}; - //============================================================================== class VST3PluginInstance; @@ -753,7 +413,6 @@ public: //============================================================================== tresult PLUGIN_API setDirty (TBool) override { - jassertfalse; return kResultFalse; } @@ -873,14 +532,6 @@ public: return kResultOk; } - #define TEST_FOR_AND_RETURN_IF_VALID(ClassType) \ - if (doIdsMatch (iid, ClassType::iid)) \ - { \ - addRef(); \ - *obj = dynamic_cast (this); \ - return kResultOk; \ - } - TEST_FOR_AND_RETURN_IF_VALID (Vst::IComponentHandler) TEST_FOR_AND_RETURN_IF_VALID (Vst::IComponentHandler2) TEST_FOR_AND_RETURN_IF_VALID (Vst::IComponentHandler3) @@ -888,7 +539,6 @@ public: TEST_FOR_AND_RETURN_IF_VALID (Vst::IHostApplication) TEST_FOR_AND_RETURN_IF_VALID (Vst::IParamValueQueue) TEST_FOR_AND_RETURN_IF_VALID (Vst::IUnitHandler) - #undef TEST_FOR_AND_RETURN_IF_VALID *obj = nullptr; return kNotImplemented; @@ -1139,6 +789,7 @@ public: Result result (Result::ok()); const Steinberg::int32 numClasses = factory->countClasses(); + for (Steinberg::int32 i = 0; i < numClasses; ++i) { PClassInfo info; @@ -1174,7 +825,7 @@ public: foundNames.add (name); - int numInputs = 0, numOutputs = 0; + PluginDescription desc; { ComSmartPtr component; @@ -1183,8 +834,11 @@ public: { if (component->initialize (vst3HostContext->getFUnknown()) == kResultOk) { - numInputs = getNumSingleDirectionChannelsFor (component, true, true); - numOutputs = getNumSingleDirectionChannelsFor (component, false, true); + const int numInputs = getNumSingleDirectionChannelsFor (component, true, true); + const int numOutputs = getNumSingleDirectionChannelsFor (component, false, true); + + createPluginDescription (desc, file, companyName, name, + info, info2, infoW, numInputs, numOutputs); component->terminate(); } @@ -1193,13 +847,12 @@ public: jassertfalse; } } + else + { + jassertfalse; + } } - PluginDescription desc; - - createPluginDescription (desc, file, companyName, name, - info, info2, infoW, numInputs, numOutputs); - result = performOnDescription (desc); if (result.failed()) @@ -1265,6 +918,7 @@ private: struct DLLHandle { DLLHandle (const String& modulePath) + : factory (nullptr) { if (modulePath.trim().isNotEmpty()) open (modulePath); @@ -1278,6 +932,7 @@ struct DLLHandle if (ExitModuleFn exitFn = (ExitModuleFn) getFunction ("ExitDll")) exitFn(); + releaseFactory(); library.close(); #else @@ -1286,6 +941,8 @@ struct DLLHandle if (ExitModuleFn exitFn = (ExitModuleFn) getFunction ("bundleExit")) exitFn(); + releaseFactory(); + CFRelease (bundleRef); bundleRef = nullptr; } @@ -1303,12 +960,22 @@ struct DLLHandle #endif } + /** @note The factory should begin with a refCount of 1, + so don't increment the reference count + (ie: don't use a ComSmartPtr in here)! + Its lifetime will be handled by this DllHandle, + when such will be destroyed. + + @see releaseFactory + */ IPluginFactory* JUCE_CALLTYPE getPluginFactory() { - if (GetFactoryProc proc = (GetFactoryProc) getFunction ("GetPluginFactory")) - return proc(); + if (factory == nullptr) + if (GetFactoryProc proc = (GetFactoryProc) getFunction ("GetPluginFactory")) + factory = proc(); - return nullptr; + jassert (factory != nullptr); // The plugin NEEDS to provide a factory to be able to be called a VST3! + return factory; } void* getFunction (const char* functionName) @@ -1327,6 +994,14 @@ struct DLLHandle } private: + IPluginFactory* factory; + + void releaseFactory() + { + if (factory != nullptr) + factory->release(); + } + #if JUCE_WINDOWS DynamicLibrary library; @@ -1364,9 +1039,9 @@ private: bundleRef = CFBundleCreate (kCFAllocatorDefault, url); CFRelease (url); - if (bundleRef != 0) + if (bundleRef != nullptr) { - CFErrorRef error = 0; + CFErrorRef error = nullptr; if (CFBundleLoadExecutableAndReturnError (bundleRef, &error)) { @@ -1383,7 +1058,7 @@ private: } } - if (error != 0) + if (error != nullptr) { if (CFStringRef failureMessage = CFErrorCopyFailureReason (error)) { @@ -1395,7 +1070,7 @@ private: } CFRelease (bundleRef); - bundleRef = 0; + bundleRef = nullptr; } } @@ -1443,6 +1118,7 @@ public: return result.wasOk(); } + jassertfalse; return false; } @@ -1493,15 +1169,18 @@ private: ComSmartPtr pluginFactory (dllHandle->getPluginFactory()); - ComSmartPtr host (new VST3HostContext (nullptr)); - MatchingDescriptionFinder finder (host, pluginFactory, description); + if (pluginFactory != nullptr) + { + ComSmartPtr host (new VST3HostContext (nullptr)); + MatchingDescriptionFinder finder (host, pluginFactory, description); - const Result result (finder.findDescriptionsAndPerform (f)); + const Result result (finder.findDescriptionsAndPerform (f)); - if (result.getErrorMessage() == MatchingDescriptionFinder::getSuccessString()) - { - name = description.name; - return true; + if (result.getErrorMessage() == MatchingDescriptionFinder::getSuccessString()) + { + name = description.name; + return true; + } } return false; @@ -1527,11 +1206,11 @@ public: setOpaque (true); setVisible (true); + view->setFrame (this); + ViewRect rect; warnOnFailure (view->getSize (&rect)); resizeWithRect (*this, rect); - - view->setFrame (this); // Done after to avoid recursive calls from plugins... } ~VST3PluginWindow() @@ -1541,8 +1220,9 @@ public: #if JUCE_MAC dummyComponent.setView (nullptr); - [pluginHandle release]; #endif + + view = nullptr; } JUCE_DECLARE_VST3_COM_REF_METHODS @@ -1604,7 +1284,8 @@ public: dummyComponent.setBounds (0, 0, (int) rect.getWidth(), (int) rect.getHeight()); #endif - Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate(); // Some plugins don't update their cursor correctly when mousing out the window + // Some plugins don't update their cursor correctly when mousing out the window + Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate(); recursiveResize = false; } @@ -1655,20 +1336,20 @@ private: ScopedPointer peer; typedef HWND HandleFormat; #elif JUCE_MAC - NSViewComponent dummyComponent; + AutoResizingNSViewComponentWithParent dummyComponent; typedef NSView* HandleFormat; #else Component dummyComponent; typedef void* HandleFormat; #endif - HandleFormat pluginHandle; //< Don't delete this + HandleFormat pluginHandle; bool recursiveResize; //============================================================================== static void resizeWithRect (Component& comp, const ViewRect& rect) { - comp.setBounds (rect.left, rect.top, + comp.setBounds ((int) rect.left, (int) rect.top, jmax (10, std::abs ((int) rect.getWidth())), jmax (10, std::abs ((int) rect.getHeight()))); } @@ -1688,17 +1369,12 @@ private: #elif JUCE_MAC dummyComponent.setBounds (getBounds().withZeroOrigin()); addAndMakeVisible (dummyComponent); - pluginHandle = [[NSView alloc] init]; - dummyComponent.setView (pluginHandle); + pluginHandle = (NSView*) dummyComponent.getView(); + jassert (pluginHandle != nil); #endif if (pluginHandle != nullptr) - view->attached (pluginHandle, - #if JUCE_WINDOWS - kPlatformTypeHWND); - #else - kPlatformTypeNSView); - #endif + warnOnFailure (view->attached (pluginHandle, defaultVST3WindowType)); } } @@ -1713,7 +1389,6 @@ public: : module (handle), numInputAudioBusses (0), numOutputAudioBusses (0), - resultBuffer (1, 1), inputParameterChanges (new ParameterChangeList()), outputParameterChanges (new ParameterChangeList()), midiInputs (new MidiEventList()), @@ -1741,6 +1416,16 @@ public: if (isControllerInitialised) editController->terminate(); if (isComponentInitialised) component->terminate(); + //Deletion order appears to matter: + componentConnection = nullptr; + editControllerConnection = nullptr; + unitData = nullptr; + unitInfo = nullptr; + programListData = nullptr; + componentHandler2 = nullptr; + componentHandler = nullptr; + processor = nullptr; + editController2 = nullptr; editController = nullptr; component = nullptr; } @@ -1763,8 +1448,8 @@ public: if (! fetchComponentAndController (factory, factory->countClasses())) return false; - if (warnOnFailure (editController->initialize (host->getFUnknown())) != kResultTrue) - return false; + // (May return an error if the plugin combines the IComponent and IEditController implementations) + editController->initialize (host->getFUnknown()); isControllerInitialised = true; editController->setComponentHandler (host); @@ -1796,62 +1481,6 @@ public: return module != nullptr ? module->name : String::empty; } - typedef Array > BusMap; - - /** Assigns a series of AudioSampleBuffer's channels to an AudioBusBuffers' - - @warning For speed, does not check the channel count and offsets - according to the AudioSampleBuffer - */ - void associateBufferTo (Vst::AudioBusBuffers& vstBuffers, - BusMap& busMap, - const AudioSampleBuffer& buffer, - int numChannels, int channelStartOffset, - int sampleOffset = 0) noexcept - { - const int channelEnd = numChannels + channelStartOffset; - jassert (channelEnd >= 0 && channelEnd <= buffer.getNumChannels()); - - busMap.add (Array()); - Array& chans = busMap.getReference (busMap.size() - 1); - - for (int i = channelStartOffset; i < channelEnd; ++i) - chans.add (buffer.getSampleData (i, sampleOffset)); - - vstBuffers.channelBuffers32 = chans.getRawDataPointer(); - vstBuffers.numChannels = numChannels; - vstBuffers.silenceFlags = 0; - } - - void mapAudioSampleBufferToBusses (Array& result, - AudioSampleBuffer& source, - int numBusses, bool isInput) - { - result.clearQuick(); - - BusMap& busMapToUse = isInput ? inputBusMap : outputBusMap; - busMapToUse.clearQuick(); - - int channelIndexOffset = 0; - - for (int i = 0; i < numBusses; ++i) - { - Vst::SpeakerArrangement arrangement = 0; - processor->getBusArrangement (isInput ? Vst::kInput : Vst::kOutput, - (Steinberg::int32) i, arrangement); - - const int numChansForBus = BigInteger ((int64) arrangement).countNumberOfSetBits(); - - result.add (Vst::AudioBusBuffers()); - - associateBufferTo (result.getReference (i), busMapToUse, source, - BigInteger ((int64) arrangement).countNumberOfSetBits(), - channelIndexOffset); - - channelIndexOffset += numChansForBus; - } - } - void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock) override { using namespace Vst; @@ -1868,8 +1497,6 @@ public: setup.sampleRate = sampleRate; setup.processMode = isNonRealtime() ? kOffline : kRealtime; - resultBuffer.setSize (numOutputs, estimatedSamplesPerBlock, false, true, true); - warnOnFailure (processor->setupProcessing (setup)); if (! isComponentInitialised) @@ -1877,8 +1504,7 @@ public: editController->setComponentHandler (host); - warnOnFailure (component->setActive (true)); - warnOnFailure (processor->setProcessing (true)); + setStateForAllBusses (true); Array inArrangements, outArrangements; @@ -1887,13 +1513,16 @@ public: warnOnFailure (processor->setBusArrangements (inArrangements.getRawDataPointer(), numInputAudioBusses, outArrangements.getRawDataPointer(), numOutputAudioBusses)); + + warnOnFailure (component->setActive (true)); + warnOnFailure (processor->setProcessing (true)); } void releaseResources() override { JUCE_TRY { - resultBuffer.setSize (1, 1, false, true, true); + setStateForAllBusses (false); if (processor != nullptr) processor->setProcessing (false); @@ -1996,10 +1625,7 @@ public: //============================================================================== AudioProcessorEditor* createEditor() override { - if (view == nullptr) - view = tryCreatingView(); - - if (view != nullptr) + if (IPlugView* view = tryCreatingView()) return new VST3PluginWindow (this, view); return nullptr; @@ -2007,9 +1633,7 @@ public: bool hasEditor() const override { - if (view == nullptr) - view = tryCreatingView(); - + ComSmartPtr view (tryCreatingView()); //N.B.: Must use a ComSmartPtr to not delete the view from the plugin permanently! return view != nullptr; } @@ -2123,11 +1747,11 @@ public: (void) sizeInBytes; } - ComSmartPtr editController; - private: //============================================================================== VST3ModuleHandle::Ptr module; + + friend VST3HostContext; ComSmartPtr host; // Information objects: @@ -2137,26 +1761,24 @@ private: ScopedPointer infoW; // Rudimentary interfaces: - ComSmartPtr processor; ComSmartPtr component; + ComSmartPtr editController; + ComSmartPtr editController2; + ComSmartPtr processor; ComSmartPtr componentHandler; ComSmartPtr componentHandler2; - ComSmartPtr editController2; ComSmartPtr unitInfo; - ComSmartPtr programListData; ComSmartPtr unitData; + ComSmartPtr programListData; ComSmartPtr componentConnection; ComSmartPtr editControllerConnection; - mutable ComSmartPtr view; - /** The number of IO busses MUST match that of the plugin, even if there aren't enough channels to process, as very poorly specified by the Steinberg SDK */ int numInputAudioBusses, numOutputAudioBusses; - AudioSampleBuffer resultBuffer; - BusMap inputBusMap, outputBusMap; + VST3BufferExchange::BusMap inputBusMap, outputBusMap; Array inputBusses, outputBusses; //============================================================================== @@ -2370,12 +1992,17 @@ private: if (componentHandler2 == nullptr) componentHandler2.loadFrom (editController); } + void setStateForAllBusses (bool newState) + { + setStateForAllBussesOfType (component, newState, true, true); // Activate/deactivate audio inputs + setStateForAllBussesOfType (component, newState, false, true); // Activate/deactivate audio outputs + setStateForAllBussesOfType (component, newState, true, false); // Activate/deactivate MIDI inputs + setStateForAllBussesOfType (component, newState, false, false); // Activate/deactivate MIDI outputs + } + void setupIO() { - activateAllBussesOfType (component, true, true); // Activate audio inputs - activateAllBussesOfType (component, false, true); // Activate audio outputs - activateAllBussesOfType (component, true, false); // Activate MIDI inputs - activateAllBussesOfType (component, false, false); // Activate MIDI outputs + setStateForAllBusses (true); Vst::ProcessSetup setup; setup.symbolicSampleSize = Vst::kSample32; @@ -2406,15 +2033,13 @@ private: } //============================================================================== - ComSmartPtr tryCreatingView() const + /** @note An IPlugView, when first created, should start with a ref-count of 1! */ + IPlugView* tryCreatingView() const { - ComSmartPtr v (editController->createView (Vst::ViewType::kEditor)); - - if (v == nullptr) - v = editController->createView (nullptr); + IPlugView* v = editController->createView (Vst::ViewType::kEditor); - if (v == nullptr) - v.loadFrom (editController); + if (v == nullptr) v = editController->createView (nullptr); + if (v == nullptr) editController->queryInterface (IPlugView::iid, (void**) &v); return v; } @@ -2422,10 +2047,13 @@ private: //============================================================================== void associateTo (Vst::ProcessData& destination, AudioSampleBuffer& buffer) { - resultBuffer.clear(); + using namespace VST3BufferExchange; + + mapBufferToBusses (inputBusses, *processor, inputBusMap, + true, numInputAudioBusses, buffer); - mapAudioSampleBufferToBusses (inputBusses, buffer, numInputAudioBusses, true); - mapAudioSampleBufferToBusses (outputBusses, resultBuffer, numOutputAudioBusses, false); + mapBufferToBusses (outputBusses, *processor, outputBusMap, + false, numOutputAudioBusses, buffer); destination.inputs = inputBusses.getRawDataPointer(); destination.outputs = outputBusses.getRawDataPointer(); @@ -2512,7 +2140,7 @@ AudioPluginInstance* VST3PluginFormat::createInstanceFromDescription (const Plug bool VST3PluginFormat::fileMightContainThisPluginType (const String& fileOrIdentifier) { - const File f (fileOrIdentifier); + const File f (File::createFileWithoutCheckingPath (fileOrIdentifier)); return f.hasFileExtension (".vst3") #if JUCE_MAC @@ -2573,7 +2201,7 @@ FileSearchPath VST3PluginFormat::getDefaultLocationsToSearch() const String programFiles (File::getSpecialLocation (File::globalApplicationsDirectory).getFullPathName()); return FileSearchPath (programFiles + "\\Common Files\\VST3"); #elif JUCE_MAC - return FileSearchPath ("~/Library/Audio/Plug-Ins/VST3;/Library/Audio/Plug-Ins/VST3"); + return FileSearchPath ("/Library/Audio/Plug-Ins/VST3;~/Library/Audio/Plug-Ins/VST3"); #else return FileSearchPath(); #endif diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp index dec1a37..3d29db0 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp @@ -718,6 +718,7 @@ public: VSTPluginInstance (const ModuleHandle::Ptr& module_) : effect (nullptr), module (module_), + usesCocoaNSView (false), name (module_->pluginName), wantsMidiMessages (false), initialised (false), @@ -839,7 +840,7 @@ public: jassert (MessageManager::getInstance()->isThisTheMessageThread()); #endif - JUCE_VST_LOG ("Initialising VST: " + module->pluginName); + JUCE_VST_LOG ("Initialising VST: " + module->pluginName + " (" + getVersion() + ")"); initialised = true; setPlayConfigDetails (effect->numInputs, effect->numOutputs, @@ -871,6 +872,10 @@ public: wantsMidiMessages = dispatch (effCanDo, 0, 0, (void*) "receiveVstMidiEvent", 0) > 0; + #if JUCE_MAC && JUCE_SUPPORT_CARBON + usesCocoaNSView = (dispatch (effCanDo, 0, 0, (void*) "hasCockosViewAsConfig", 0) & 0xffff0000) == 0xbeef0000; + #endif + setLatencySamples (effect->initialDelay); } @@ -1659,6 +1664,7 @@ public: ModuleHandle::Ptr module; ScopedPointer extraFunctions; + bool usesCocoaNSView; private: String name; @@ -1898,7 +1904,6 @@ class VSTPluginWindow : public AudioProcessorEditor, public Timer { public: - //============================================================================== VSTPluginWindow (VSTPluginInstance& plug) : AudioProcessorEditor (&plug), #if ! JUCE_MAC @@ -1912,18 +1917,20 @@ public: alreadyInside (false) { #if JUCE_WINDOWS - sizeCheckCount = 0; pluginHWND = 0; + sizeCheckCount = 0; + #elif JUCE_LINUX pluginWindow = None; pluginProc = None; - #elif JUCE_MAC && JUCE_SUPPORT_CARBON - addAndMakeVisible (innerWrapper = new InnerWrapperComponent (*this)); + #elif JUCE_MAC - addAndMakeVisible (innerWrapper = new NSViewComponent()); - NSView* innerView = [[NSView alloc] init]; - innerWrapper->setView (innerView); - [innerView release]; + #if JUCE_SUPPORT_CARBON + if (! plug.usesCocoaNSView) + addAndMakeVisible (carbonWrapper = new CarbonWrapperComponent (*this)); + else + #endif + addAndMakeVisible (cocoaWrapper = new AutoResizingNSViewComponentWithParent()); #endif activeVSTWindows.add (this); @@ -1938,7 +1945,10 @@ public: closePluginWindow(); #if JUCE_MAC - innerWrapper = nullptr; + #if JUCE_SUPPORT_CARBON + carbonWrapper = nullptr; + #endif + cocoaWrapper = nullptr; #endif activeVSTWindows.removeFirstMatchingValue (this); @@ -1993,20 +2003,28 @@ public: } #endif - #if JUCE_MAC && ! JUCE_SUPPORT_CARBON + #if JUCE_MAC void visibilityChanged() override { - if (isVisible()) - openPluginWindow(); - else - closePluginWindow(); + if (cocoaWrapper != nullptr) + { + if (isVisible()) + openPluginWindow ((NSView*) cocoaWrapper->getView()); + else + closePluginWindow(); + } } void childBoundsChanged (Component*) override { - if (innerWrapper != nullptr) - setSize (innerWrapper->getWidth(), - innerWrapper->getHeight()); + if (cocoaWrapper != nullptr) + { + int w = cocoaWrapper->getWidth(); + int h = cocoaWrapper->getHeight(); + + if (w != getWidth() || h != getHeight()) + setSize (w, h); + } } #endif @@ -2138,15 +2156,8 @@ private: //============================================================================== #if JUCE_MAC - #if JUCE_SUPPORT_CARBON - void openPluginWindow (WindowRef parentWindow) - { - #else - void openPluginWindow() + void openPluginWindow (void* parentWindow) { - NSView* parentWindow = (NSView*) innerWrapper->getView(); - #endif - if (isOpen || parentWindow == 0) return; @@ -2358,9 +2369,9 @@ private: { for (int i = activeVSTWindows.size(); --i >= 0;) { - const VSTPluginWindow* const w = activeVSTWindows.getUnchecked (i); + Component::SafePointer w (activeVSTWindows[i]); - if (w->pluginHWND == hW) + if (w != nullptr && w->pluginHWND == hW) { if (message == WM_CHAR || message == WM_KEYDOWN @@ -2373,9 +2384,10 @@ private: message, wParam, lParam); } - return CallWindowProc ((WNDPROC) w->originalWndProc, - (HWND) w->pluginHWND, - message, wParam, lParam); + if (w != nullptr) // (may have been deleted in SendMessage callback) + return CallWindowProc ((WNDPROC) w->originalWndProc, + (HWND) w->pluginHWND, + message, wParam, lParam); } } @@ -2500,17 +2512,17 @@ private: //============================================================================== #if JUCE_MAC #if JUCE_SUPPORT_CARBON - class InnerWrapperComponent : public CarbonViewWrapperComponent + class CarbonWrapperComponent : public CarbonViewWrapperComponent { public: - InnerWrapperComponent (VSTPluginWindow& w) + CarbonWrapperComponent (VSTPluginWindow& w) : owner (w), alreadyInside (false) { keepPluginWindowWhenHidden = w.shouldAvoidDeletingWindow(); setRepaintsChildHIViewWhenCreated (w.shouldRepaintCarbonWindowWhenCreated()); } - ~InnerWrapperComponent() + ~CarbonWrapperComponent() { deleteWindow(); } @@ -2574,20 +2586,24 @@ private: VSTPluginWindow& owner; bool alreadyInside; - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InnerWrapperComponent) + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CarbonWrapperComponent) }; - friend class InnerWrapperComponent; - ScopedPointer innerWrapper; - - #else - ScopedPointer innerWrapper; + friend class CarbonWrapperComponent; + ScopedPointer carbonWrapper; #endif + ScopedPointer cocoaWrapper; + void resized() override { - if (innerWrapper != nullptr) - innerWrapper->setSize (getWidth(), getHeight()); + #if JUCE_SUPPORT_CARBON + if (carbonWrapper != nullptr) + carbonWrapper->setSize (getWidth(), getHeight()); + #endif + + if (cocoaWrapper != nullptr) + cocoaWrapper->setSize (getWidth(), getHeight()); } #endif @@ -2637,7 +2653,7 @@ static VSTPluginInstance* createAndUpdateDesc (VSTPluginFormat& format, PluginDe return nullptr; } -void VSTPluginFormat::findAllTypesForFile (OwnedArray & results, +void VSTPluginFormat::findAllTypesForFile (OwnedArray& results, const String& fileOrIdentifier) { if (! fileMightContainThisPluginType (fileOrIdentifier)) @@ -2671,14 +2687,17 @@ void VSTPluginFormat::findAllTypesForFile (OwnedArray & resul break; desc.uid = uid; + desc.name = shellEffectName; + + aboutToScanVSTShellPlugin (desc); ScopedPointer shellInstance (createAndUpdateDesc (*this, desc)); if (shellInstance != nullptr) { jassert (desc.uid == uid); - desc.name = shellEffectName; desc.hasSharedContainer = true; + desc.name = shellEffectName; if (! arrayContainsPlugin (results, desc)) results.add (new PluginDescription (desc)); @@ -2724,7 +2743,7 @@ AudioPluginInstance* VSTPluginFormat::createInstanceFromDescription (const Plugi bool VSTPluginFormat::fileMightContainThisPluginType (const String& fileOrIdentifier) { - const File f (fileOrIdentifier); + const File f (File::createFileWithoutCheckingPath (fileOrIdentifier)); #if JUCE_MAC if (f.isDirectory() && f.hasFileExtension (".vst")) @@ -2881,4 +2900,6 @@ VSTPluginFormat::VstIntPtr JUCE_CALLTYPE VSTPluginFormat::dispatcher (AudioPlugi return 0; } +void VSTPluginFormat::aboutToScanVSTShellPlugin (const PluginDescription&) {} + #endif diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.h index 0c38b80..4e4b744 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.h @@ -96,6 +96,13 @@ public: FileSearchPath getDefaultLocationsToSearch() override; bool canScanForPlugins() const override { return true; } + /** Can be overridden to receive a callback when each member of a shell plugin is about to be + tested during a call to findAllTypesForFile(). + Only the name and uid members of the PluginDescription are guaranteed to be valid when + this is called. + */ + virtual void aboutToScanVSTShellPlugin (const PluginDescription&); + private: void recursiveFileSearch (StringArray&, const File&, bool recursive); diff --git a/JuceLibraryCode/modules/juce_audio_processors/juce_audio_processors.cpp b/JuceLibraryCode/modules/juce_audio_processors/juce_audio_processors.cpp index f3fc57e..78d3387 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/juce_audio_processors.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/juce_audio_processors.cpp @@ -57,6 +57,11 @@ #undef KeyPress #endif +#if ! JUCE_WINDOWS && ! JUCE_MAC + #undef JUCE_PLUGINHOST_VST3 + #define JUCE_PLUGINHOST_VST3 0 +#endif + //============================================================================== namespace juce { @@ -71,6 +76,68 @@ static inline bool arrayContainsPlugin (const OwnedArray& lis return false; } +#if JUCE_MAC +//============================================================================== +struct AutoResizingNSViewComponent : public NSViewComponent, + private AsyncUpdater +{ + AutoResizingNSViewComponent() : recursive (false) {} + + void childBoundsChanged (Component*) override + { + if (recursive) + { + triggerAsyncUpdate(); + } + else + { + recursive = true; + resizeToFitView(); + recursive = true; + } + } + + void handleAsyncUpdate() override { resizeToFitView(); } + + bool recursive; +}; + +//============================================================================== +struct AutoResizingNSViewComponentWithParent : public AutoResizingNSViewComponent, + private Timer +{ + AutoResizingNSViewComponentWithParent() + { + NSView* v = [[NSView alloc] init]; + setView (v); + [v release]; + + startTimer (100); + } + + void timerCallback() override + { + if (NSView* parent = (NSView*) getView()) + { + if ([[parent subviews] count] > 0) + { + if (NSView* child = [[parent subviews] objectAtIndex: 0]) + { + NSRect f = [parent frame]; + NSSize newSize = [child frame].size; + + if (f.size.width != newSize.width || f.size.height != newSize.height) + { + f.size = newSize; + [parent setFrame: f]; + } + } + } + } + } +}; +#endif + #if JUCE_CLANG #pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif diff --git a/JuceLibraryCode/modules/juce_audio_processors/juce_audio_processors.h b/JuceLibraryCode/modules/juce_audio_processors/juce_audio_processors.h index 78dc79f..3854d2a 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/juce_audio_processors.h +++ b/JuceLibraryCode/modules/juce_audio_processors/juce_audio_processors.h @@ -44,7 +44,7 @@ Enables the VST3 audio plugin hosting classes. This requires the Steinberg VST3 SDK to be installed on your machine. - @see VSTPluginFormat, VVST3PluginFormat, AudioPluginFormat, AudioPluginFormatManager, JUCE_PLUGINHOST_VST, JUCE_PLUGINHOST_AU + @see VSTPluginFormat, VST3PluginFormat, AudioPluginFormat, AudioPluginFormatManager, JUCE_PLUGINHOST_VST, JUCE_PLUGINHOST_AU */ #ifndef JUCE_PLUGINHOST_VST3 #define JUCE_PLUGINHOST_VST3 0 @@ -60,7 +60,7 @@ #endif #if ! (JUCE_PLUGINHOST_AU || JUCE_PLUGINHOST_VST || JUCE_PLUGINHOST_VST3) -// #error "You need to set either the JUCE_PLUGINHOST_AU anr/or JUCE_PLUGINHOST_VST flags if you're using this module!" +// #error "You need to set either the JUCE_PLUGINHOST_AU and/or JUCE_PLUGINHOST_VST and/or JUCE_PLUGINHOST_VST3 flags if you're using this module!" #endif #if ! (defined (JUCE_SUPPORT_CARBON) || JUCE_64BIT) diff --git a/JuceLibraryCode/modules/juce_audio_processors/juce_module_info b/JuceLibraryCode/modules/juce_audio_processors/juce_module_info index 34124f6..1230c9c 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/juce_module_info +++ b/JuceLibraryCode/modules/juce_audio_processors/juce_module_info @@ -1,7 +1,7 @@ { "id": "juce_audio_processors", "name": "JUCE audio plugin hosting classes", - "version": "3.0.1", + "version": "3.0.3", "description": "Classes for loading and playing VST, AU, or internally-generated audio processors.", "website": "http://www.juce.com/juce", "license": "GPL/Commercial", diff --git a/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessor.h b/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessor.h index 24d0d02..e54b84a 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessor.h +++ b/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessor.h @@ -609,6 +609,7 @@ public: { wrapperType_Undefined = 0, wrapperType_VST, + wrapperType_VST3, wrapperType_AudioUnit, wrapperType_RTAS, wrapperType_AAX, diff --git a/JuceLibraryCode/modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp b/JuceLibraryCode/modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp index 2ea3c98..afbf23e 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp @@ -202,6 +202,14 @@ void KnownPluginList::scanAndAddDragAndDroppedFiles (AudioPluginFormatManager& f } } } + + scanFinished(); +} + +void KnownPluginList::scanFinished() +{ + if (scanner != nullptr) + scanner->scanFinished(); } const StringArray& KnownPluginList::getBlacklistedFiles() const @@ -280,10 +288,16 @@ void KnownPluginList::sort (const SortMethod method, bool forwards) { if (method != defaultOrder) { + Array oldOrder, newOrder; + oldOrder.addArray (types); + PluginSorter sorter (method, forwards); types.sort (sorter, true); - sendChangeMessage(); + newOrder.addArray (types); + + if (oldOrder != newOrder) + sendChangeMessage(); } } @@ -523,3 +537,13 @@ int KnownPluginList::getIndexChosenByMenu (const int menuResultCode) const //============================================================================== KnownPluginList::CustomScanner::CustomScanner() {} KnownPluginList::CustomScanner::~CustomScanner() {} + +void KnownPluginList::CustomScanner::scanFinished() {} + +bool KnownPluginList::CustomScanner::shouldExit() const noexcept +{ + if (ThreadPoolJob* job = ThreadPoolJob::getCurrentThreadPoolJob()) + return job->shouldExit(); + + return false; +} diff --git a/JuceLibraryCode/modules/juce_audio_processors/scanning/juce_KnownPluginList.h b/JuceLibraryCode/modules/juce_audio_processors/scanning/juce_KnownPluginList.h index 5f60643..3c8df25 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/scanning/juce_KnownPluginList.h +++ b/JuceLibraryCode/modules/juce_audio_processors/scanning/juce_KnownPluginList.h @@ -97,6 +97,9 @@ public: OwnedArray & typesFound, AudioPluginFormat& formatToUse); + /** Tells a custom scanner that a scan has finished, and it can release any resources. */ + void scanFinished(); + /** Returns true if the specified file is already known about and if it hasn't been modified since our entry was created. */ @@ -170,8 +173,8 @@ public: struct PluginTree { String folder; /**< The name of this folder in the tree */ - OwnedArray subFolders; - Array plugins; + OwnedArray subFolders; + Array plugins; }; /** Creates a PluginTree object containing all the known plugins. */ @@ -190,9 +193,21 @@ public: virtual bool findPluginTypesFor (AudioPluginFormat& format, OwnedArray & result, const String& fileOrIdentifier) = 0; + + /** Called when a scan has finished, to allow clean-up of resources. */ + virtual void scanFinished(); + + /** Returns true if the current scan should be abandoned. + Any blocking methods should check this value repeatedly and return if + if becomes true. + */ + bool shouldExit() const noexcept; }; - void setCustomScanner (CustomScanner* scanner); + /** Supplies a custom scanner to be used in future scans. + The KnownPluginList will take ownership of the object passed in. + */ + void setCustomScanner (CustomScanner*); private: //============================================================================== diff --git a/JuceLibraryCode/modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.cpp b/JuceLibraryCode/modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.cpp index 5502f00..a7beea7 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.cpp @@ -63,6 +63,7 @@ PluginDirectoryScanner::PluginDirectoryScanner (KnownPluginList& listToAddTo, PluginDirectoryScanner::~PluginDirectoryScanner() { + list.scanFinished(); } //============================================================================== diff --git a/JuceLibraryCode/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp b/JuceLibraryCode/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp index 8112277..a0c2388 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp @@ -83,9 +83,9 @@ public: } } - void deleteKeyPressed (int lastRowSelected) override + void deleteKeyPressed (int) override { - removePluginItem (list, lastRowSelected); + owner.removeSelected(); } void sortOrderChanged (int newSortColumnId, bool isForwards) override @@ -152,6 +152,7 @@ PluginListComponent::PluginListComponent (AudioPluginFormatManager& manager, Kno table.setHeaderHeight (22); table.setRowHeight (20); table.setModel (tableModel); + table.setMultipleSelectionEnabled (true); addAndMakeVisible (table); addAndMakeVisible (optionsButton); @@ -161,6 +162,7 @@ PluginListComponent::PluginListComponent (AudioPluginFormatManager& manager, Kno setSize (400, 600); list.addChangeListener (this); updateList(); + table.getHeader().reSortTable(); PluginDirectoryScanner::applyBlacklistingsFromDeadMansPedal (list, deadMansPedalFile); deadMansPedalFile.deleteFile(); @@ -195,6 +197,7 @@ void PluginListComponent::resized() void PluginListComponent::changeListenerCallback (ChangeBroadcaster*) { + table.getHeader().reSortTable(); updateList(); } @@ -208,7 +211,7 @@ void PluginListComponent::removeSelected() { const SparseSet selected (table.getSelectedRows()); - for (int i = list.getNumTypes(); --i >= 0;) + for (int i = table.getNumRows(); --i >= 0;) if (selected.contains (i)) TableModel::removePluginItem (list, i); } diff --git a/JuceLibraryCode/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp b/JuceLibraryCode/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp index db22b5d..64801fc 100644 --- a/JuceLibraryCode/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp +++ b/JuceLibraryCode/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp @@ -40,12 +40,19 @@ public: void timerCallback() override { - const float newLevel = (float) manager.getCurrentInputLevel(); + if (isShowing()) + { + const float newLevel = (float) manager.getCurrentInputLevel(); - if (std::abs (level - newLevel) > 0.005f) + if (std::abs (level - newLevel) > 0.005f) + { + level = newLevel; + repaint(); + } + } + else { - level = newLevel; - repaint(); + level = 0; } } diff --git a/JuceLibraryCode/modules/juce_audio_utils/gui/juce_AudioThumbnail.cpp b/JuceLibraryCode/modules/juce_audio_utils/gui/juce_AudioThumbnail.cpp index 43d32f6..0745d09 100644 --- a/JuceLibraryCode/modules/juce_audio_utils/gui/juce_AudioThumbnail.cpp +++ b/JuceLibraryCode/modules/juce_audio_utils/gui/juce_AudioThumbnail.cpp @@ -461,15 +461,20 @@ private: if (sample >= 0) { if (sample >= levelData->lengthInSamples) - break; - - levelData->getLevels (sample, jmax (1, nextSample - sample), levels); + { + for (int chan = 0; chan < numChannelsCached; ++chan) + *getData (chan, i) = MinMaxValue(); + } + else + { + levelData->getLevels (sample, jmax (1, nextSample - sample), levels); - const int totalChans = jmin (levels.size() / 2, numChannelsCached); + const int totalChans = jmin (levels.size() / 2, numChannelsCached); - for (int chan = 0; chan < totalChans; ++chan) - getData (chan, i)->setFloat (levels.getUnchecked (chan * 2), - levels.getUnchecked (chan * 2 + 1)); + for (int chan = 0; chan < totalChans; ++chan) + getData (chan, i)->setFloat (levels.getUnchecked (chan * 2), + levels.getUnchecked (chan * 2 + 1)); + } } startTime += timePerPixel; diff --git a/JuceLibraryCode/modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.cpp b/JuceLibraryCode/modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.cpp index 490ce90..2cfe71f 100644 --- a/JuceLibraryCode/modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.cpp +++ b/JuceLibraryCode/modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.cpp @@ -152,10 +152,9 @@ void MidiKeyboardComponent::setLowestVisibleKeyFloat (float noteNumber) firstKey = noteNumber; if (hasMoved) - { sendChangeMessage(); - resized(); - } + + resized(); } } @@ -212,19 +211,11 @@ void MidiKeyboardComponent::getKeyPosition (int midiNoteNumber, const float keyW 5.0f, 6 - blackNoteWidth * 0.3f, 6.0f }; - static const float widths[] = { 1.0f, blackNoteWidth, - 1.0f, blackNoteWidth, - 1.0f, - 1.0f, blackNoteWidth, - 1.0f, blackNoteWidth, - 1.0f, blackNoteWidth, - 1.0f }; - const int octave = midiNoteNumber / 12; const int note = midiNoteNumber % 12; x = roundToInt (octave * 7.0f * keyWidth_ + notePos [note] * keyWidth_); - w = roundToInt (widths [note] * keyWidth_); + w = roundToInt (MidiMessage::isMidiNoteBlack (note) ? blackNoteWidth * keyWidth_ : keyWidth_); } void MidiKeyboardComponent::getKeyPos (int midiNoteNumber, int& x, int& w) const @@ -261,6 +252,12 @@ int MidiKeyboardComponent::getKeyStartPosition (const int midiNoteNumber) const return x; } +int MidiKeyboardComponent::getNoteAtPosition (Point p) +{ + float v; + return xyToNote (p, v); +} + const uint8 MidiKeyboardComponent::whiteNotes[] = { 0, 2, 4, 5, 7, 9, 11 }; const uint8 MidiKeyboardComponent::blackNotes[] = { 1, 3, 6, 8, 10 }; @@ -383,13 +380,13 @@ void MidiKeyboardComponent::paint (Graphics& g) else y2 = 5.0f; - g.setGradientFill (ColourGradient (Colours::black.withAlpha (0.3f), x1, y1, - Colours::transparentBlack, x2, y2, false)); - int x, w; getKeyPos (rangeEnd, x, w); x += w; + const Colour shadowCol (findColour (shadowColourId)); + g.setGradientFill (ColourGradient (shadowCol, x1, y1, shadowCol.withAlpha (0.0f), x2, y2, false)); + switch (orientation) { case horizontalKeyboard: g.fillRect (0, 0, x, 5); break; @@ -458,14 +455,13 @@ void MidiKeyboardComponent::drawWhiteNote (int midiNoteNumber, g.setColour (textColour); g.setFont (Font (jmin (12.0f, keyWidth * 0.9f)).withHorizontalScale (0.8f)); - Justification justification (Justification::centredBottom); - - if (orientation == verticalKeyboardFacingLeft) - justification = Justification::centredLeft; - else if (orientation == verticalKeyboardFacingRight) - justification = Justification::centredRight; - - g.drawFittedText (text, x + 2, y + 2, w - 4, h - 4, justification, 1); + switch (orientation) + { + case horizontalKeyboard: g.drawFittedText (text, x + 1, y, w - 1, h - 2, Justification::centredBottom, 1); break; + case verticalKeyboardFacingLeft: g.drawFittedText (text, x + 2, y + 2, w - 4, h - 4, Justification::centredLeft, 1); break; + case verticalKeyboardFacingRight: g.drawFittedText (text, x + 2, y + 2, w - 4, h - 4, Justification::centredRight, 1); break; + default: break; + } } g.setColour (lineColour); @@ -531,7 +527,7 @@ void MidiKeyboardComponent::setOctaveForMiddleC (const int octaveNum) String MidiKeyboardComponent::getWhiteNoteText (const int midiNoteNumber) { - if (keyWidth > 14.0f && midiNoteNumber % 12 == 0) + if (keyWidth > 11.0f && midiNoteNumber % 12 == 0) return MidiMessage::getMidiNoteName (midiNoteNumber, true, true, octaveNumForMiddleC); return String::empty; @@ -594,31 +590,29 @@ void MidiKeyboardComponent::resized() } } - const bool showScrollButtons = canScroll && (((int) firstKey) > rangeStart || kx2 > w + xOffset * 2); - - scrollDown->setVisible (showScrollButtons); - scrollUp->setVisible (showScrollButtons); + scrollDown->setVisible (canScroll && firstKey > (float) rangeStart); xOffset = 0; - if (showScrollButtons) + if (canScroll) { const int scrollButtonW = jmin (12, w / 2); + Rectangle r (getLocalBounds()); if (orientation == horizontalKeyboard) { - scrollDown->setBounds (0, 0, scrollButtonW, getHeight()); - scrollUp->setBounds (getWidth() - scrollButtonW, 0, scrollButtonW, getHeight()); + scrollDown->setBounds (r.removeFromLeft (scrollButtonW)); + scrollUp ->setBounds (r.removeFromRight (scrollButtonW)); } else if (orientation == verticalKeyboardFacingLeft) { - scrollDown->setBounds (0, 0, getWidth(), scrollButtonW); - scrollUp->setBounds (0, getHeight() - scrollButtonW, getWidth(), scrollButtonW); + scrollDown->setBounds (r.removeFromTop (scrollButtonW)); + scrollUp ->setBounds (r.removeFromBottom (scrollButtonW)); } else { - scrollDown->setBounds (0, getHeight() - scrollButtonW, getWidth(), scrollButtonW); - scrollUp->setBounds (0, 0, getWidth(), scrollButtonW); + scrollDown->setBounds (r.removeFromBottom (scrollButtonW)); + scrollUp ->setBounds (r.removeFromTop (scrollButtonW)); } int endOfLastKey, kw; @@ -626,7 +620,7 @@ void MidiKeyboardComponent::resized() endOfLastKey += kw; float mousePositionVelocity; - const int spaceAvailable = w - scrollButtonW * 2; + const int spaceAvailable = w; const int lastStartKey = remappedXYToNote (Point (endOfLastKey - spaceAvailable, 0), mousePositionVelocity) + 1; if (lastStartKey >= 0 && ((int) firstKey) > lastStartKey) @@ -636,14 +630,16 @@ void MidiKeyboardComponent::resized() } int newOffset = 0; - getKeyPos (((int) firstKey), newOffset, kw); - xOffset = newOffset - scrollButtonW; + getKeyPos ((int) firstKey, newOffset, kw); + xOffset = newOffset; } else { firstKey = (float) rangeStart; } + getKeyPos (rangeEnd, kx2, kw2); + scrollUp->setVisible (canScroll && kx2 > w); repaint(); } } diff --git a/JuceLibraryCode/modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.h b/JuceLibraryCode/modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.h index 987d742..c53890c 100644 --- a/JuceLibraryCode/modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.h +++ b/JuceLibraryCode/modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.h @@ -52,7 +52,6 @@ class JUCE_API MidiKeyboardComponent : public Component, public: //============================================================================== /** The direction of the keyboard. - @see setOrientation */ enum Orientation @@ -97,7 +96,6 @@ public: void setMidiChannel (int midiChannelNumber); /** Returns the midi channel that the keyboard is using for midi messages. - @see setMidiChannel */ int getMidiChannel() const noexcept { return midiChannel; } @@ -117,7 +115,6 @@ public: void setMidiChannelsToDisplay (int midiChannelMask); /** Returns the current set of midi channels represented by the component. - This is the value that was set with setMidiChannelsToDisplay(). */ int getMidiChannelsToDisplay() const noexcept { return midiInChannelMask; } @@ -169,7 +166,6 @@ public: int getLowestVisibleKey() const noexcept { return (int) firstKey; } /** Returns the length of the black notes. - This will be their vertical or horizontal length, depending on the keyboard's orientation. */ int getBlackNoteLength() const noexcept { return blackNoteLength; } @@ -196,7 +192,8 @@ public: keyDownOverlayColourId = 0x1005004, /**< This colour will be overlaid on the normal note colour. */ textLabelColourId = 0x1005005, upDownButtonBackgroundColourId = 0x1005006, - upDownButtonArrowColourId = 0x1005007 + upDownButtonArrowColourId = 0x1005007, + shadowColourId = 0x1005008 }; /** Returns the position within the component of the left-hand edge of a key. @@ -206,6 +203,9 @@ public: */ int getKeyStartPosition (int midiNoteNumber) const; + /** Returns the key at a given coordinate. */ + int getNoteAtPosition (Point position); + //============================================================================== /** Deletes all key-mappings. @see setKeyPressForNote @@ -319,9 +319,7 @@ protected: const Colour& noteFillColour); /** Allows text to be drawn on the white notes. - By default this is used to label the C in each octave, but could be used for other things. - @see setOctaveForMiddleC */ virtual String getWhiteNoteText (const int midiNoteNumber); diff --git a/JuceLibraryCode/modules/juce_audio_utils/juce_module_info b/JuceLibraryCode/modules/juce_audio_utils/juce_module_info index 59269d2..3156631 100644 --- a/JuceLibraryCode/modules/juce_audio_utils/juce_module_info +++ b/JuceLibraryCode/modules/juce_audio_utils/juce_module_info @@ -1,7 +1,7 @@ { "id": "juce_audio_utils", "name": "JUCE extra audio utility classes", - "version": "3.0.1", + "version": "3.0.3", "description": "Classes for audio-related GUI and miscellaneous tasks.", "website": "http://www.juce.com/juce", "license": "GPL/Commercial", diff --git a/JuceLibraryCode/modules/juce_audio_utils/players/juce_AudioProcessorPlayer.cpp b/JuceLibraryCode/modules/juce_audio_utils/players/juce_AudioProcessorPlayer.cpp index b3cc31d..18e1410 100644 --- a/JuceLibraryCode/modules/juce_audio_utils/players/juce_AudioProcessorPlayer.cpp +++ b/JuceLibraryCode/modules/juce_audio_utils/players/juce_AudioProcessorPlayer.cpp @@ -45,9 +45,7 @@ void AudioProcessorPlayer::setProcessor (AudioProcessor* const processorToPlay) { if (processorToPlay != nullptr && sampleRate > 0 && blockSize > 0) { - processorToPlay->setPlayConfigDetails (numInputChans, numOutputChans, - sampleRate, blockSize); - + processorToPlay->setPlayConfigDetails (numInputChans, numOutputChans, sampleRate, blockSize); processorToPlay->prepareToPlay (sampleRate, blockSize); } @@ -120,22 +118,23 @@ void AudioProcessorPlayer::audioDeviceIOCallback (const float** const inputChann AudioSampleBuffer buffer (channels, totalNumChans, numSamples); - const ScopedLock sl (lock); - - if (processor != nullptr) { - const ScopedLock sl2 (processor->getCallbackLock()); + const ScopedLock sl (lock); - if (processor->isSuspended()) + if (processor != nullptr) { - for (int i = 0; i < numOutputChannels; ++i) - zeromem (outputChannelData[i], sizeof (float) * (size_t) numSamples); - } - else - { - processor->processBlock (buffer, incomingMidi); + const ScopedLock sl2 (processor->getCallbackLock()); + + if (! processor->isSuspended()) + { + processor->processBlock (buffer, incomingMidi); + return; + } } } + + for (int i = 0; i < numOutputChannels; ++i) + FloatVectorOperations::clear (outputChannelData[i], numSamples); } void AudioProcessorPlayer::audioDeviceAboutToStart (AudioIODevice* const device) diff --git a/JuceLibraryCode/modules/juce_audio_utils/players/juce_AudioProcessorPlayer.h b/JuceLibraryCode/modules/juce_audio_utils/players/juce_AudioProcessorPlayer.h index df0600a..418ceff 100644 --- a/JuceLibraryCode/modules/juce_audio_utils/players/juce_AudioProcessorPlayer.h +++ b/JuceLibraryCode/modules/juce_audio_utils/players/juce_AudioProcessorPlayer.h @@ -52,27 +52,22 @@ public: /** Sets the processor that should be played. The processor that is passed in will not be deleted or owned by this object. - To stop anything playing, pass in 0 to this method. + To stop anything playing, pass a nullptr to this method. */ void setProcessor (AudioProcessor* processorToPlay); - /** Returns the current audio processor that is being played. - */ - AudioProcessor* getCurrentProcessor() const { return processor; } + /** Returns the current audio processor that is being played. */ + AudioProcessor* getCurrentProcessor() const noexcept { return processor; } /** Returns a midi message collector that you can pass midi messages to if you want them to be injected into the midi stream that is being sent to the processor. */ - MidiMessageCollector& getMidiMessageCollector() { return messageCollector; } + MidiMessageCollector& getMidiMessageCollector() noexcept { return messageCollector; } //============================================================================== /** @internal */ - void audioDeviceIOCallback (const float** inputChannelData, - int totalNumInputChannels, - float** outputChannelData, - int totalNumOutputChannels, - int numSamples) override; + void audioDeviceIOCallback (const float**, int, float**, int, int) override; /** @internal */ void audioDeviceAboutToStart (AudioIODevice*) override; /** @internal */ diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_Array.h b/JuceLibraryCode/modules/juce_core/containers/juce_Array.h index e258b68..8c0f592 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_Array.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_Array.h @@ -40,7 +40,7 @@ do so, the class must fulfil these requirements: - it must have a copy constructor and assignment operator - 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 be used. + 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 , but if you do this, the array doesn't take any ownership of the objects - see the OwnedArray class or the @@ -143,6 +143,7 @@ public: Array& operator= (Array&& other) noexcept { const ScopedLockType lock (getLock()); + deleteAllElements(); data = static_cast&&> (other.data); numUsed = other.numUsed; other.numUsed = 0; diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_DynamicObject.cpp b/JuceLibraryCode/modules/juce_core/containers/juce_DynamicObject.cpp index 69d9bf9..439a263 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_DynamicObject.cpp +++ b/JuceLibraryCode/modules/juce_core/containers/juce_DynamicObject.cpp @@ -30,6 +30,11 @@ DynamicObject::DynamicObject() { } +DynamicObject::DynamicObject (const DynamicObject& other) + : properties (other.properties) +{ +} + DynamicObject::~DynamicObject() { } @@ -78,12 +83,9 @@ void DynamicObject::clear() properties.clear(); } -DynamicObject::Ptr DynamicObject::clone() +void DynamicObject::cloneAllProperties() { - DynamicObject* newCopy = new DynamicObject(); - newCopy->properties = properties; - - for (LinkedListPointer* i = &(newCopy->properties.values);;) + for (LinkedListPointer* i = &(properties.values);;) { if (NamedValueSet::NamedValue* const v = i->get()) { @@ -93,8 +95,13 @@ DynamicObject::Ptr DynamicObject::clone() else break; } +} - return newCopy; +DynamicObject::Ptr DynamicObject::clone() +{ + Ptr d (new DynamicObject (*this)); + d->cloneAllProperties(); + return d; } void DynamicObject::writeAsJSON (OutputStream& out, const int indentLevel, const bool allOnOneLine) diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_DynamicObject.h b/JuceLibraryCode/modules/juce_core/containers/juce_DynamicObject.h index e6d547d..b2ba93a 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_DynamicObject.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_DynamicObject.h @@ -46,9 +46,8 @@ class JUCE_API DynamicObject : public ReferenceCountedObject public: //============================================================================== DynamicObject(); - - /** Destructor. */ - virtual ~DynamicObject(); + DynamicObject (const DynamicObject&); + ~DynamicObject(); typedef ReferenceCountedObjectPtr Ptr; @@ -104,6 +103,9 @@ public: /** Returns the NamedValueSet that holds the object's properties. */ NamedValueSet& getProperties() noexcept { return properties; } + /** Calls var::clone() on all the properties that this object contains. */ + void cloneAllProperties(); + //============================================================================== /** Returns a clone of this object. The default implementation of this method just returns a new DynamicObject diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_HashMap.h b/JuceLibraryCode/modules/juce_core/containers/juce_HashMap.h index a109421..e663d32 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_HashMap.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_HashMap.h @@ -60,7 +60,7 @@ struct DefaultHashFunctions @code struct MyHashGenerator { - int generateHash (MyKeyType key, int upperLimit) + int generateHash (MyKeyType key, int upperLimit) const { // The function must return a value 0 <= x < upperLimit return someFunctionOfMyKeyType (key) % upperLimit; diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_NamedValueSet.cpp b/JuceLibraryCode/modules/juce_core/containers/juce_NamedValueSet.cpp index 5ea71a5..0d866b1 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_NamedValueSet.cpp +++ b/JuceLibraryCode/modules/juce_core/containers/juce_NamedValueSet.cpp @@ -30,7 +30,7 @@ NamedValueSet::NamedValue::NamedValue() noexcept { } -inline NamedValueSet::NamedValue::NamedValue (const Identifier n, const var& v) +inline NamedValueSet::NamedValue::NamedValue (Identifier n, const var& v) : name (n), value (v) { } @@ -49,22 +49,22 @@ NamedValueSet::NamedValue& NamedValueSet::NamedValue::operator= (const NamedValu #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS NamedValueSet::NamedValue::NamedValue (NamedValue&& other) noexcept - : nextListItem (static_cast &&> (other.nextListItem)), - name (static_cast (other.name)), - value (static_cast (other.value)) + : nextListItem (static_cast&&> (other.nextListItem)), + name (static_cast (other.name)), + value (static_cast (other.value)) { } -inline NamedValueSet::NamedValue::NamedValue (const Identifier n, var&& v) - : name (n), value (static_cast (v)) +inline NamedValueSet::NamedValue::NamedValue (Identifier n, var&& v) + : name (n), value (static_cast (v)) { } NamedValueSet::NamedValue& NamedValueSet::NamedValue::operator= (NamedValue&& other) noexcept { - nextListItem = static_cast &&> (other.nextListItem); - name = static_cast (other.name); - value = static_cast (other.value); + nextListItem = static_cast&&> (other.nextListItem); + name = static_cast (other.name); + value = static_cast (other.value); return *this; } #endif @@ -141,7 +141,7 @@ int NamedValueSet::size() const noexcept return values.size(); } -const var& NamedValueSet::operator[] (const Identifier name) const +const var& NamedValueSet::operator[] (Identifier name) const { for (NamedValue* i = values; i != nullptr; i = i->nextListItem) if (i->name == name) @@ -150,7 +150,7 @@ const var& NamedValueSet::operator[] (const Identifier name) const return var::null; } -var NamedValueSet::getWithDefault (const Identifier name, const var& defaultReturnValue) const +var NamedValueSet::getWithDefault (Identifier name, const var& defaultReturnValue) const { if (const var* const v = getVarPointer (name)) return *v; @@ -158,7 +158,7 @@ var NamedValueSet::getWithDefault (const Identifier name, const var& defaultRetu return defaultReturnValue; } -var* NamedValueSet::getVarPointer (const Identifier name) const noexcept +var* NamedValueSet::getVarPointer (Identifier name) const noexcept { for (NamedValue* i = values; i != nullptr; i = i->nextListItem) if (i->name == name) @@ -168,7 +168,7 @@ var* NamedValueSet::getVarPointer (const Identifier name) const noexcept } #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS -bool NamedValueSet::set (const Identifier name, var&& newValue) +bool NamedValueSet::set (Identifier name, var&& newValue) { LinkedListPointer* i = &values; @@ -193,7 +193,7 @@ bool NamedValueSet::set (const Identifier name, var&& newValue) } #endif -bool NamedValueSet::set (const Identifier name, const var& newValue) +bool NamedValueSet::set (Identifier name, const var& newValue) { LinkedListPointer* i = &values; @@ -217,12 +217,27 @@ bool NamedValueSet::set (const Identifier name, const var& newValue) return true; } -bool NamedValueSet::contains (const Identifier name) const +bool NamedValueSet::contains (Identifier name) const { return getVarPointer (name) != nullptr; } -bool NamedValueSet::remove (const Identifier name) +int NamedValueSet::indexOf (Identifier name) const noexcept +{ + int index = 0; + + for (NamedValue* i = values; i != nullptr; i = i->nextListItem) + { + if (i->name == name) + return index; + + ++index; + } + + return -1; +} + +bool NamedValueSet::remove (Identifier name) { LinkedListPointer* i = &values; @@ -245,7 +260,7 @@ bool NamedValueSet::remove (const Identifier name) return false; } -const Identifier NamedValueSet::getName (const int index) const +Identifier NamedValueSet::getName (const int index) const { const NamedValue* const v = values[index]; jassert (v != nullptr); @@ -268,7 +283,7 @@ void NamedValueSet::setFromXmlAttributes (const XmlElement& xml) for (int i = 0; i < numAtts; ++i) { - const String& name = xml.getAttributeName (i); + const String& name = xml.getAttributeName (i); const String& value = xml.getAttributeValue (i); if (name.startsWith ("base64:")) diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_NamedValueSet.h b/JuceLibraryCode/modules/juce_core/containers/juce_NamedValueSet.h index d649847..6043e2a 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_NamedValueSet.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_NamedValueSet.h @@ -43,21 +43,21 @@ public: NamedValueSet() noexcept; /** Creates a copy of another set. */ - NamedValueSet (const NamedValueSet& other); + NamedValueSet (const NamedValueSet&); /** Replaces this set with a copy of another set. */ - NamedValueSet& operator= (const NamedValueSet& other); + NamedValueSet& operator= (const NamedValueSet&); #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS - NamedValueSet (NamedValueSet&& other) noexcept; - NamedValueSet& operator= (NamedValueSet&& other) noexcept; + NamedValueSet (NamedValueSet&&) noexcept; + NamedValueSet& operator= (NamedValueSet&&) noexcept; #endif /** Destructor. */ ~NamedValueSet(); - bool operator== (const NamedValueSet& other) const; - bool operator!= (const NamedValueSet& other) const; + bool operator== (const NamedValueSet&) const; + bool operator!= (const NamedValueSet&) const; //============================================================================== /** Returns the total number of values that the set contains. */ @@ -67,46 +67,49 @@ public: If the name isn't found, this will return a void variant. @see getProperty */ - const var& operator[] (const Identifier name) const; + const var& operator[] (Identifier name) const; /** Tries to return the named value, but if no such value is found, this will instead return the supplied default value. */ - var getWithDefault (const Identifier name, const var& defaultReturnValue) const; + var getWithDefault (Identifier name, const var& defaultReturnValue) const; /** Changes or adds a named value. @returns true if a value was changed or added; false if the value was already set the the value passed-in. */ - bool set (const Identifier name, const var& newValue); + bool set (Identifier name, const var& newValue); #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS /** Changes or adds a named value. @returns true if a value was changed or added; false if the value was already set the the value passed-in. */ - bool set (const Identifier name, var&& newValue); + bool set (Identifier name, var&& newValue); #endif /** Returns true if the set contains an item with the specified name. */ - bool contains (const Identifier name) const; + bool contains (Identifier name) const; /** Removes a value from the set. @returns true if a value was removed; false if there was no value with the name that was given. */ - bool remove (const Identifier name); + bool remove (Identifier name); /** Returns the name of the value at a given index. The index must be between 0 and size() - 1. */ - const Identifier getName (int index) const; + Identifier getName (int index) const; /** Returns the value of the item at a given index. The index must be between 0 and size() - 1. */ const var& getValueAt (int index) const; + /** Returns the index of the given name, or -1 if it's not found. */ + int indexOf (Identifier name) const noexcept; + /** Removes all values. */ void clear(); @@ -117,7 +120,7 @@ public: Do not use this method unless you really need access to the internal var object for some reason - for normal reading and writing always prefer operator[]() and set(). */ - var* getVarPointer (const Identifier name) const noexcept; + var* getVarPointer (Identifier name) const noexcept; //============================================================================== /** Sets properties to the values of all of an XML element's attributes. */ @@ -135,14 +138,14 @@ private: public: NamedValue() noexcept; NamedValue (const NamedValue&); - NamedValue (const Identifier name, const var& value); + NamedValue (Identifier, const var&); NamedValue& operator= (const NamedValue&); #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS NamedValue (NamedValue&&) noexcept; - NamedValue (const Identifier name, var&& value); + NamedValue (Identifier, var&&); NamedValue& operator= (NamedValue&&) noexcept; #endif - bool operator== (const NamedValue& other) const noexcept; + bool operator== (const NamedValue&) const noexcept; LinkedListPointer nextListItem; Identifier name; diff --git a/JuceLibraryCode/modules/juce_core/files/juce_DirectoryIterator.h b/JuceLibraryCode/modules/juce_core/files/juce_DirectoryIterator.h index b297c5e..3ca2265 100644 --- a/JuceLibraryCode/modules/juce_core/files/juce_DirectoryIterator.h +++ b/JuceLibraryCode/modules/juce_core/files/juce_DirectoryIterator.h @@ -32,16 +32,16 @@ //============================================================================== /** - Searches through a the files in a directory, returning each file that is found. + Searches through the files in a directory, returning each file that is found. A DirectoryIterator will search through a directory and its subdirectories using a wildcard filepattern match. - If you may be finding a large number of files, this is better than - using File::findChildFiles() because it doesn't block while it finds them - all, and this is more memory-efficient. + If you may be scanning a large number of files, it's usually smarter to use this + class than File::findChildFiles() because it allows you to stop at any time, rather + than having to wait for the entire scan to finish before getting the results. - It can also guess how far it's got using a wildly inaccurate algorithm. + It also provides an estimate of its progress, using a (highly inaccurate!) algorithm. */ class JUCE_API DirectoryIterator { diff --git a/JuceLibraryCode/modules/juce_core/files/juce_FileSearchPath.h b/JuceLibraryCode/modules/juce_core/files/juce_FileSearchPath.h index fcd0693..51baf2e 100644 --- a/JuceLibraryCode/modules/juce_core/files/juce_FileSearchPath.h +++ b/JuceLibraryCode/modules/juce_core/files/juce_FileSearchPath.h @@ -101,7 +101,7 @@ public: /** Merges another search path into this one. This will remove any duplicate directories. */ - void addPath (const FileSearchPath& other); + void addPath (const FileSearchPath&); /** Removes any directories that are actually subdirectories of one of the other directories in the search path. diff --git a/JuceLibraryCode/modules/juce_core/javascript/juce_JSON.cpp b/JuceLibraryCode/modules/juce_core/javascript/juce_JSON.cpp index 8aa8192..ebf2e47 100644 --- a/JuceLibraryCode/modules/juce_core/javascript/juce_JSON.cpp +++ b/JuceLibraryCode/modules/juce_core/javascript/juce_JSON.cpp @@ -100,7 +100,6 @@ public: return Result::ok(); } -private: static Result parseAny (String::CharPointerType& t, var& result) { t = t.findEndOfWhitespace(); @@ -160,6 +159,7 @@ private: return createFail ("Syntax error", &t); } +private: static Result createFail (const char* const message, const String::CharPointerType* location = nullptr) { String m (message); @@ -460,51 +460,6 @@ public: out << ']'; } -/* static void writeObject (OutputStream& out, DynamicObject& object, - const int indentLevel, const bool allOnOneLine) - { - NamedValueSet& props = object.getProperties(); - - out << '{'; - if (! allOnOneLine) - out << newLine; - - LinkedListPointer* i = &(props.values); - - for (;;) - { - NamedValueSet::NamedValue* const v = i->get(); - - if (v == nullptr) - break; - - if (! allOnOneLine) - writeSpaces (out, indentLevel + indentSize); - - out << '"'; - writeString (out, v->name); - out << "\": "; - write (out, v->value, indentLevel + indentSize, allOnOneLine); - - if (v->nextListItem.get() != nullptr) - { - if (allOnOneLine) - out << ", "; - else - out << ',' << newLine; - } - else if (! allOnOneLine) - out << newLine; - - i = &(v->nextListItem); - } - - if (! allOnOneLine) - writeSpaces (out, indentLevel); - - out << '}'; - }*/ - enum { indentSize = 2 }; }; @@ -513,7 +468,17 @@ var JSON::parse (const String& text) { var result; - if (! JSONParser::parseObjectOrArray (text.getCharPointer(), result)) + if (! parse (text, result)) + result = var(); + + return result; +} + +var JSON::fromString (StringRef text) +{ + var result; + + if (! JSONParser::parseAny (text.text, result)) result = var(); return result; diff --git a/JuceLibraryCode/modules/juce_core/javascript/juce_JSON.h b/JuceLibraryCode/modules/juce_core/javascript/juce_JSON.h index c0dc505..7fb17ee 100644 --- a/JuceLibraryCode/modules/juce_core/javascript/juce_JSON.h +++ b/JuceLibraryCode/modules/juce_core/javascript/juce_JSON.h @@ -53,6 +53,10 @@ public: If you're not interested in the error message, you can use one of the other shortcut parse methods, which simply return a var::null if the parsing fails. + + Note that this will only parse valid JSON, which means that the item given must + be either an object or an array definition. If you want to also be able to parse + any kind of primitive JSON object, use the fromString() method. */ static Result parse (const String& text, var& parsedResult); @@ -60,6 +64,10 @@ public: If the parsing fails, this simply returns var::null - if you need to find out more detail about the parse error, use the alternative parse() method which returns a Result. + + Note that this will only parse valid JSON, which means that the item given must + be either an object or an array definition. If you want to also be able to parse + any kind of primitive JSON object, use the fromString() method. */ static var parse (const String& text); @@ -94,6 +102,13 @@ public: static String toString (const var& objectToFormat, bool allOnOneLine = false); + /** Parses a string that was created with the toString() method. + This is slightly different to the parse() methods because they will reject primitive + values and only accept array or object definitions, whereas this method will handle + either. + */ + static var fromString (StringRef); + /** Writes a JSON-formatted representation of the var object to the given stream. If allOnOneLine is true, the result will be compacted into a single line of text with no carriage-returns. If false, it will be laid-out in a more human-readable format. @@ -106,7 +121,7 @@ public: /** Returns a version of a string with any extended characters escaped. */ static String escapeString (StringRef); - /** Parses a quoted string in JSON format, returning the un-escaped result in the + /** Parses a quoted string-literal in JSON format, returning the un-escaped result in the result parameter, and an error message in case the content was illegal. This advances the text parameter, leaving it positioned after the closing quote. */ diff --git a/JuceLibraryCode/modules/juce_core/juce_core.cpp b/JuceLibraryCode/modules/juce_core/juce_core.cpp index 2fca180..be6b6eb 100644 --- a/JuceLibraryCode/modules/juce_core/juce_core.cpp +++ b/JuceLibraryCode/modules/juce_core/juce_core.cpp @@ -151,7 +151,6 @@ namespace juce #include "text/juce_StringPairArray.cpp" #include "text/juce_StringPool.cpp" #include "text/juce_TextDiff.cpp" -#include "threads/juce_ChildProcess.cpp" #include "threads/juce_ReadWriteLock.cpp" #include "threads/juce_Thread.cpp" #include "threads/juce_ThreadPool.cpp" @@ -165,6 +164,8 @@ namespace juce #include "zip/juce_GZIPDecompressorInputStream.cpp" #include "zip/juce_GZIPCompressorOutputStream.cpp" #include "zip/juce_ZipFile.cpp" +#include "files/juce_FileFilter.cpp" +#include "files/juce_WildcardFileFilter.cpp" //============================================================================== #if JUCE_MAC || JUCE_IOS @@ -216,6 +217,7 @@ namespace juce #endif +#include "threads/juce_ChildProcess.cpp" #include "threads/juce_HighResolutionTimer.cpp" } diff --git a/JuceLibraryCode/modules/juce_core/juce_core.h b/JuceLibraryCode/modules/juce_core/juce_core.h index 1355b44..953c6ad 100644 --- a/JuceLibraryCode/modules/juce_core/juce_core.h +++ b/JuceLibraryCode/modules/juce_core/juce_core.h @@ -232,6 +232,8 @@ extern JUCE_API void JUCE_CALLTYPE logAssertion (const char* file, int line) noe #include "files/juce_FileSearchPath.h" #include "files/juce_MemoryMappedFile.h" #include "files/juce_TemporaryFile.h" +#include "files/juce_FileFilter.h" +#include "files/juce_WildcardFileFilter.h" #include "streams/juce_FileInputSource.h" #include "logging/juce_FileLogger.h" #include "javascript/juce_JSON.h" diff --git a/JuceLibraryCode/modules/juce_core/juce_module_info b/JuceLibraryCode/modules/juce_core/juce_module_info index d6cb11d..32f4a47 100644 --- a/JuceLibraryCode/modules/juce_core/juce_module_info +++ b/JuceLibraryCode/modules/juce_core/juce_module_info @@ -1,7 +1,7 @@ { "id": "juce_core", "name": "JUCE core classes", - "version": "3.0.1", + "version": "3.0.3", "description": "The essential set of basic JUCE classes, as required by all the other JUCE modules. Includes text, container, memory, threading and i/o functionality.", "website": "http://www.juce.com/juce", "license": "ISC Permissive", diff --git a/JuceLibraryCode/modules/juce_core/maths/juce_BigInteger.h b/JuceLibraryCode/modules/juce_core/maths/juce_BigInteger.h index c212cfd..4c6c25c 100644 --- a/JuceLibraryCode/modules/juce_core/maths/juce_BigInteger.h +++ b/JuceLibraryCode/modules/juce_core/maths/juce_BigInteger.h @@ -65,11 +65,11 @@ public: BigInteger (int64 value); /** Creates a copy of another BigInteger. */ - BigInteger (const BigInteger& other); + BigInteger (const BigInteger&); #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS - BigInteger (BigInteger&& other) noexcept; - BigInteger& operator= (BigInteger&& other) noexcept; + BigInteger (BigInteger&&) noexcept; + BigInteger& operator= (BigInteger&&) noexcept; #endif /** Destructor. */ @@ -77,10 +77,10 @@ public: //============================================================================== /** Copies another BigInteger onto this one. */ - BigInteger& operator= (const BigInteger& other); + BigInteger& operator= (const BigInteger&); /** Swaps the internal contents of this with another object. */ - void swapWith (BigInteger& other) noexcept; + void swapWith (BigInteger&) noexcept; //============================================================================== /** Returns the value of a specified bit in the number. @@ -183,14 +183,14 @@ public: //============================================================================== // All the standard arithmetic ops... - BigInteger& operator+= (const BigInteger& other); - BigInteger& operator-= (const BigInteger& other); - BigInteger& operator*= (const BigInteger& other); - BigInteger& operator/= (const BigInteger& other); - BigInteger& operator|= (const BigInteger& other); - BigInteger& operator&= (const BigInteger& other); - BigInteger& operator^= (const BigInteger& other); - BigInteger& operator%= (const BigInteger& other); + BigInteger& operator+= (const BigInteger&); + BigInteger& operator-= (const BigInteger&); + BigInteger& operator*= (const BigInteger&); + BigInteger& operator/= (const BigInteger&); + BigInteger& operator|= (const BigInteger&); + BigInteger& operator&= (const BigInteger&); + BigInteger& operator^= (const BigInteger&); + BigInteger& operator%= (const BigInteger&); BigInteger& operator<<= (int numBitsToShift); BigInteger& operator>>= (int numBitsToShift); BigInteger& operator++(); @@ -199,23 +199,23 @@ public: BigInteger operator-- (int); BigInteger operator-() const; - BigInteger operator+ (const BigInteger& other) const; - BigInteger operator- (const BigInteger& other) const; - BigInteger operator* (const BigInteger& other) const; - BigInteger operator/ (const BigInteger& other) const; - BigInteger operator| (const BigInteger& other) const; - BigInteger operator& (const BigInteger& other) const; - BigInteger operator^ (const BigInteger& other) const; - BigInteger operator% (const BigInteger& other) const; + BigInteger operator+ (const BigInteger&) const; + BigInteger operator- (const BigInteger&) const; + BigInteger operator* (const BigInteger&) const; + BigInteger operator/ (const BigInteger&) const; + BigInteger operator| (const BigInteger&) const; + BigInteger operator& (const BigInteger&) const; + BigInteger operator^ (const BigInteger&) const; + BigInteger operator% (const BigInteger&) const; BigInteger operator<< (int numBitsToShift) const; BigInteger operator>> (int numBitsToShift) const; - bool operator== (const BigInteger& other) const noexcept; - bool operator!= (const BigInteger& other) const noexcept; - bool operator< (const BigInteger& other) const noexcept; - bool operator<= (const BigInteger& other) const noexcept; - bool operator> (const BigInteger& other) const noexcept; - bool operator>= (const BigInteger& other) const noexcept; + bool operator== (const BigInteger&) const noexcept; + bool operator!= (const BigInteger&) const noexcept; + bool operator< (const BigInteger&) const noexcept; + bool operator<= (const BigInteger&) const noexcept; + bool operator> (const BigInteger&) const noexcept; + bool operator>= (const BigInteger&) const noexcept; //============================================================================== /** Does a signed comparison of two BigIntegers. @@ -243,8 +243,7 @@ public: */ void divideBy (const BigInteger& divisor, BigInteger& remainder); - /** Returns the largest value that will divide both this value and the one passed-in. - */ + /** Returns the largest value that will divide both this value and the one passed-in. */ BigInteger findGreatestCommonDivisor (BigInteger other) const; /** Performs a combined exponent and modulo operation. @@ -310,12 +309,12 @@ public: private: //============================================================================== - HeapBlock values; + HeapBlock values; size_t numValues; int highestBit; bool negative; - void ensureSize (size_t numVals); + void ensureSize (size_t); void shiftLeft (int bits, int startBit); void shiftRight (int bits, int startBit); diff --git a/JuceLibraryCode/modules/juce_core/maths/juce_Expression.cpp b/JuceLibraryCode/modules/juce_core/maths/juce_Expression.cpp index 9734446..a18effa 100644 --- a/JuceLibraryCode/modules/juce_core/maths/juce_Expression.cpp +++ b/JuceLibraryCode/modules/juce_core/maths/juce_Expression.cpp @@ -188,12 +188,10 @@ struct Expression::Helpers if (input != left && input != right) return TermPtr(); - const Term* const dest = findDestinationFor (topLevelTerm, this); - - if (dest == nullptr) - return new Constant (overallTarget, false); + if (const Term* const dest = findDestinationFor (topLevelTerm, this)) + return dest->createTermToEvaluateInput (scope, this, overallTarget, topLevelTerm); - return dest->createTermToEvaluateInput (scope, this, overallTarget, topLevelTerm); + return new Constant (overallTarget, false); } }; diff --git a/JuceLibraryCode/modules/juce_core/maths/juce_Expression.h b/JuceLibraryCode/modules/juce_core/maths/juce_Expression.h index e6443c8..8939129 100644 --- a/JuceLibraryCode/modules/juce_core/maths/juce_Expression.h +++ b/JuceLibraryCode/modules/juce_core/maths/juce_Expression.h @@ -59,14 +59,14 @@ public: explicit Expression (double constant); /** Creates a copy of an expression. */ - Expression (const Expression& other); + Expression (const Expression&); /** Copies another expression. */ - Expression& operator= (const Expression& other); + Expression& operator= (const Expression&); #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS - Expression (Expression&& other) noexcept; - Expression& operator= (Expression&& other) noexcept; + Expression (Expression&&) noexcept; + Expression& operator= (Expression&&) noexcept; #endif /** Creates an expression by parsing a string. @@ -78,14 +78,14 @@ public: /** Returns a string version of the expression. */ String toString() const; - /** Returns an expression which is an addtion operation of two existing expressions. */ - Expression operator+ (const Expression& other) const; + /** Returns an expression which is an addition operation of two existing expressions. */ + Expression operator+ (const Expression&) const; /** Returns an expression which is a subtraction operation of two existing expressions. */ - Expression operator- (const Expression& other) const; + Expression operator- (const Expression&) const; /** Returns an expression which is a multiplication operation of two existing expressions. */ - Expression operator* (const Expression& other) const; + Expression operator* (const Expression&) const; /** Returns an expression which is a division operation of two existing expressions. */ - Expression operator/ (const Expression& other) const; + Expression operator/ (const Expression&) const; /** Returns an expression which performs a negation operation on an existing expression. */ Expression operator-() const; diff --git a/JuceLibraryCode/modules/juce_core/native/juce_android_Network.cpp b/JuceLibraryCode/modules/juce_core/native/juce_android_Network.cpp index c551eda..40478d4 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_android_Network.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_android_Network.cpp @@ -87,6 +87,10 @@ public: LocalRef responseHeaderBuffer (env->NewObject (StringBuffer, StringBuffer.constructor)); + // Annoyingly, the android HTTP functions will choke on this call if you try to do it on the message + // thread. You'll need to move your networking code to a background thread to keep it happy.. + jassert (Thread::getCurrentThread() != nullptr); + stream = GlobalRef (env->CallStaticObjectMethod (JuceAppActivity, JuceAppActivity.createHTTPStream, javaString (address).get(), diff --git a/JuceLibraryCode/modules/juce_core/native/juce_posix_NamedPipe.cpp b/JuceLibraryCode/modules/juce_core/native/juce_posix_NamedPipe.cpp index c97f881..d0c0b09 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_posix_NamedPipe.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_posix_NamedPipe.cpp @@ -194,7 +194,12 @@ bool NamedPipe::openInternal (const String& pipeName, const bool createPipe) pimpl = new Pimpl (File::getSpecialLocation (File::tempDirectory) .getChildFile (File::createLegalFileName (pipeName)).getFullPathName(), createPipe); #else - pimpl = new Pimpl ("/tmp/" + File::createLegalFileName (pipeName), createPipe); + String file (pipeName); + + if (! File::isAbsolutePath (file)) + file = "/tmp/" + File::createLegalFileName (file); + + pimpl = new Pimpl (file, createPipe); #endif if (createPipe && ! pimpl->createFifos()) diff --git a/JuceLibraryCode/modules/juce_core/native/juce_posix_SharedCode.h b/JuceLibraryCode/modules/juce_core/native/juce_posix_SharedCode.h index 46d2382..402662a 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_posix_SharedCode.h +++ b/JuceLibraryCode/modules/juce_core/native/juce_posix_SharedCode.h @@ -1053,7 +1053,7 @@ public: close (pipeHandle); } - bool isRunning() const + bool isRunning() const noexcept { if (childPID != 0) { @@ -1065,7 +1065,7 @@ public: return false; } - int read (void* const dest, const int numBytes) + int read (void* const dest, const int numBytes) noexcept { jassert (dest != nullptr); @@ -1082,11 +1082,25 @@ public: return 0; } - bool killProcess() const + bool killProcess() const noexcept { return ::kill (childPID, SIGKILL) == 0; } + uint32 getExitCode() const noexcept + { + if (childPID != 0) + { + int childState = 0; + const int pid = waitpid (childPID, &childState, WNOHANG); + + if (pid >= 0 && WIFEXITED (childState)) + return WEXITSTATUS (childState); + } + + return 0; + } + int childPID; private: @@ -1114,21 +1128,6 @@ bool ChildProcess::start (const StringArray& args, int streamFlags) return activeProcess != nullptr; } -bool ChildProcess::isRunning() const -{ - return activeProcess != nullptr && activeProcess->isRunning(); -} - -int ChildProcess::readProcessOutput (void* dest, int numBytes) -{ - return activeProcess != nullptr ? activeProcess->read (dest, numBytes) : 0; -} - -bool ChildProcess::kill() -{ - return activeProcess == nullptr || activeProcess->killProcess(); -} - //============================================================================== struct HighResolutionTimer::Pimpl { diff --git a/JuceLibraryCode/modules/juce_core/native/juce_win32_Threads.cpp b/JuceLibraryCode/modules/juce_core/native/juce_win32_Threads.cpp index d6de0f8..4537bce 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_win32_Threads.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_win32_Threads.cpp @@ -482,12 +482,12 @@ public: CloseHandle (writePipe); } - bool isRunning() const + bool isRunning() const noexcept { return WaitForSingleObject (processInfo.hProcess, 0) != WAIT_OBJECT_0; } - int read (void* dest, int numNeeded) const + int read (void* dest, int numNeeded) const noexcept { int total = 0; @@ -522,11 +522,18 @@ public: return total; } - bool killProcess() const + bool killProcess() const noexcept { return TerminateProcess (processInfo.hProcess, 0) != FALSE; } + uint32 getExitCode() const noexcept + { + DWORD exitCode = 0; + GetExitCodeProcess (processInfo.hProcess, &exitCode); + return (uint32) exitCode; + } + bool ok; private: @@ -551,21 +558,6 @@ bool ChildProcess::start (const StringArray& args, int streamFlags) return start (args.joinIntoString (" "), streamFlags); } -bool ChildProcess::isRunning() const -{ - return activeProcess != nullptr && activeProcess->isRunning(); -} - -int ChildProcess::readProcessOutput (void* dest, int numBytes) -{ - return activeProcess != nullptr ? activeProcess->read (dest, numBytes) : 0; -} - -bool ChildProcess::kill() -{ - return activeProcess == nullptr || activeProcess->killProcess(); -} - //============================================================================== struct HighResolutionTimer::Pimpl { diff --git a/JuceLibraryCode/modules/juce_core/network/juce_MACAddress.h b/JuceLibraryCode/modules/juce_core/network/juce_MACAddress.h index 0fa9d9d..6356131 100644 --- a/JuceLibraryCode/modules/juce_core/network/juce_MACAddress.h +++ b/JuceLibraryCode/modules/juce_core/network/juce_MACAddress.h @@ -51,10 +51,10 @@ public: MACAddress(); /** Creates a copy of another address. */ - MACAddress (const MACAddress& other); + MACAddress (const MACAddress&); /** Creates a copy of another address. */ - MACAddress& operator= (const MACAddress& other); + MACAddress& operator= (const MACAddress&); /** Creates an address from 6 bytes. */ explicit MACAddress (const uint8 bytes[6]); @@ -75,8 +75,8 @@ public: /** Returns true if this address is null (00-00-00-00-00-00). */ bool isNull() const noexcept; - bool operator== (const MACAddress& other) const noexcept; - bool operator!= (const MACAddress& other) const noexcept; + bool operator== (const MACAddress&) const noexcept; + bool operator!= (const MACAddress&) const noexcept; //============================================================================== private: diff --git a/JuceLibraryCode/modules/juce_core/streams/juce_OutputStream.cpp b/JuceLibraryCode/modules/juce_core/streams/juce_OutputStream.cpp index 47c2f06..7c6d0bd 100644 --- a/JuceLibraryCode/modules/juce_core/streams/juce_OutputStream.cpp +++ b/JuceLibraryCode/modules/juce_core/streams/juce_OutputStream.cpp @@ -174,12 +174,16 @@ bool OutputStream::writeDoubleBigEndian (double value) bool OutputStream::writeString (const String& text) { + #if (JUCE_STRING_UTF_TYPE == 8) + return write (text.toRawUTF8(), text.getNumBytesAsUTF8() + 1); + #else // (This avoids using toUTF8() to prevent the memory bloat that it would leave behind // if lots of large, persistent strings were to be written to streams). const size_t numBytes = text.getNumBytesAsUTF8() + 1; HeapBlock temp (numBytes); text.copyToUTF8 (temp, numBytes); return write (temp, numBytes); + #endif } bool OutputStream::writeText (const String& text, const bool asUTF16, diff --git a/JuceLibraryCode/modules/juce_core/system/juce_StandardHeader.h b/JuceLibraryCode/modules/juce_core/system/juce_StandardHeader.h index 12e332a..c9d06ac 100644 --- a/JuceLibraryCode/modules/juce_core/system/juce_StandardHeader.h +++ b/JuceLibraryCode/modules/juce_core/system/juce_StandardHeader.h @@ -36,7 +36,7 @@ */ #define JUCE_MAJOR_VERSION 3 #define JUCE_MINOR_VERSION 0 -#define JUCE_BUILDNUMBER 1 +#define JUCE_BUILDNUMBER 3 /** Current Juce version number. diff --git a/JuceLibraryCode/modules/juce_core/text/juce_CharPointer_UTF8.h b/JuceLibraryCode/modules/juce_core/text/juce_CharPointer_UTF8.h index d03c2a0..78d9a97 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_CharPointer_UTF8.h +++ b/JuceLibraryCode/modules/juce_core/text/juce_CharPointer_UTF8.h @@ -171,11 +171,12 @@ public: while (--numExtraValues >= 0) { - const uint32 nextByte = (uint32) (uint8) *data++; + const uint32 nextByte = (uint32) (uint8) *data; if ((nextByte & 0xc0) != 0x80) break; + ++data; n <<= 6; n |= (nextByte & 0x3f); } @@ -248,16 +249,8 @@ public: if ((n & 0x80) != 0) { - uint32 bit = 0x40; - - while ((n & bit) != 0) - { + while ((*d & 0xc0) == 0x80) ++d; - bit >>= 1; - - if (bit == 0) - break; // illegal utf-8 sequence - } } else if (n == 0) break; diff --git a/JuceLibraryCode/modules/juce_core/text/juce_LocalisedStrings.cpp b/JuceLibraryCode/modules/juce_core/text/juce_LocalisedStrings.cpp index 1d70e4e..4563a8a 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_LocalisedStrings.cpp +++ b/JuceLibraryCode/modules/juce_core/text/juce_LocalisedStrings.cpp @@ -36,6 +36,21 @@ LocalisedStrings::LocalisedStrings (const File& fileToLoad, bool ignoreCase) loadFromText (fileToLoad.loadFileAsString(), ignoreCase); } +LocalisedStrings::LocalisedStrings (const LocalisedStrings& other) + : languageName (other.languageName), countryCodes (other.countryCodes), + translations (other.translations), fallback (createCopyIfNotNull (other.fallback.get())) +{ +} + +LocalisedStrings& LocalisedStrings::operator= (const LocalisedStrings& other) +{ + languageName = other.languageName; + countryCodes = other.countryCodes; + translations = other.translations; + fallback = createCopyIfNotNull (other.fallback.get()); + return *this; +} + LocalisedStrings::~LocalisedStrings() { } diff --git a/JuceLibraryCode/modules/juce_core/text/juce_LocalisedStrings.h b/JuceLibraryCode/modules/juce_core/text/juce_LocalisedStrings.h index acf1da8..e8f70f7 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_LocalisedStrings.h +++ b/JuceLibraryCode/modules/juce_core/text/juce_LocalisedStrings.h @@ -82,16 +82,17 @@ public: When you create one of these, you can call setCurrentMappings() to make it the set of mappings that the system's using. */ - LocalisedStrings (const String& fileContents, - bool ignoreCaseOfKeys); + LocalisedStrings (const String& fileContents, bool ignoreCaseOfKeys); /** Creates a set of translations from a file. When you create one of these, you can call setCurrentMappings() to make it the set of mappings that the system's using. */ - LocalisedStrings (const File& fileToLoad, - bool ignoreCaseOfKeys); + LocalisedStrings (const File& fileToLoad, bool ignoreCaseOfKeys); + + LocalisedStrings (const LocalisedStrings&); + LocalisedStrings& operator= (const LocalisedStrings&); /** Destructor. */ ~LocalisedStrings(); @@ -100,7 +101,7 @@ public: /** Selects the current set of mappings to be used by the system. The object you pass in will be automatically deleted when no longer needed, so - don't keep a pointer to it. You can also pass in zero to remove the current + don't keep a pointer to it. You can also pass in nullptr to remove the current mappings. See also the TRANS() macro, which uses the current set to do its translation. @@ -195,6 +196,7 @@ private: StringArray countryCodes; StringPairArray translations; ScopedPointer fallback; + friend struct ContainerDeletePolicy; void loadFromText (const String&, bool ignoreCase); diff --git a/JuceLibraryCode/modules/juce_core/text/juce_String.cpp b/JuceLibraryCode/modules/juce_core/text/juce_String.cpp index d9f8fea..66d2773 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_String.cpp +++ b/JuceLibraryCode/modules/juce_core/text/juce_String.cpp @@ -313,6 +313,10 @@ String::String (const char* const t) you use UTF-8 with escape characters in your source code to represent extended characters, because there's no other way to represent these strings in a way that isn't dependent on the compiler, source code editor and platform. + + Note that the Introjucer has a handy string literal generator utility that will convert + any unicode string to a valid C++ string literal, creating ascii escape sequences that will + work in any compiler. */ jassert (t == nullptr || CharPointer_ASCII::isValidString (t, std::numeric_limits::max())); } @@ -332,6 +336,10 @@ String::String (const char* const t, const size_t maxChars) you use UTF-8 with escape characters in your source code to represent extended characters, because there's no other way to represent these strings in a way that isn't dependent on the compiler, source code editor and platform. + + Note that the Introjucer has a handy string literal generator utility that will convert + any unicode string to a valid C++ string literal, creating ascii escape sequences that will + work in any compiler. */ jassert (t == nullptr || CharPointer_ASCII::isValidString (t, (int) maxChars)); } diff --git a/JuceLibraryCode/modules/juce_core/text/juce_String.h b/JuceLibraryCode/modules/juce_core/text/juce_String.h index febe6ee..7b1c17b 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_String.h +++ b/JuceLibraryCode/modules/juce_core/text/juce_String.h @@ -84,7 +84,7 @@ public: because there's no other way to represent unicode strings in a way that isn't dependent on the compiler, source code editor and platform. - This will use up the the first maxChars characters of the string (or less if the string + This will use up to the first maxChars characters of the string (or less if the string is actually shorter). */ String (const char* text, size_t maxChars); @@ -1294,6 +1294,8 @@ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, long number); /** Appends a decimal number at the end of a string. */ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, int64 number); /** Appends a decimal number at the end of a string. */ +JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, uint64 number); +/** Appends a decimal number at the end of a string. */ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, float number); /** Appends a decimal number at the end of a string. */ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, double number); diff --git a/JuceLibraryCode/modules/juce_core/threads/juce_ChildProcess.cpp b/JuceLibraryCode/modules/juce_core/threads/juce_ChildProcess.cpp index 7edab2a..4566b13 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_ChildProcess.cpp +++ b/JuceLibraryCode/modules/juce_core/threads/juce_ChildProcess.cpp @@ -29,6 +29,26 @@ ChildProcess::ChildProcess() {} ChildProcess::~ChildProcess() {} +bool ChildProcess::isRunning() const +{ + return activeProcess != nullptr && activeProcess->isRunning(); +} + +int ChildProcess::readProcessOutput (void* dest, int numBytes) +{ + return activeProcess != nullptr ? activeProcess->read (dest, numBytes) : 0; +} + +bool ChildProcess::kill() +{ + return activeProcess == nullptr || activeProcess->killProcess(); +} + +uint32 ChildProcess::getExitCode() const +{ + return activeProcess != nullptr ? activeProcess->getExitCode() : 0; +} + bool ChildProcess::waitForProcessToFinish (const int timeoutMs) const { const uint32 timeoutTime = Time::getMillisecondCounter() + (uint32) timeoutMs; diff --git a/JuceLibraryCode/modules/juce_core/threads/juce_ChildProcess.h b/JuceLibraryCode/modules/juce_core/threads/juce_ChildProcess.h index c5a245f..0adcb57 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_ChildProcess.h +++ b/JuceLibraryCode/modules/juce_core/threads/juce_ChildProcess.h @@ -97,6 +97,9 @@ public: /** Blocks until the process is no longer running. */ bool waitForProcessToFinish (int timeoutMs) const; + /** If the process has finished, this returns its exit code. */ + uint32 getExitCode() const; + /** Attempts to kill the child process. Returns true if it succeeded. Trying to read from the process after calling this may result in undefined behaviour. diff --git a/JuceLibraryCode/modules/juce_core/threads/juce_CriticalSection.h b/JuceLibraryCode/modules/juce_core/threads/juce_CriticalSection.h index 7889b35..60e61dd 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_CriticalSection.h +++ b/JuceLibraryCode/modules/juce_core/threads/juce_CriticalSection.h @@ -38,6 +38,10 @@ one of these is by using RAII in the form of a local ScopedLock object - have a look through the codebase for many examples of how to do this. + In almost all cases you'll want to declare your CriticalSection as a member variable. + Occasionally you may want to declare one as a static variable, but in that case the usual + C++ static object order-of-construction warnings should be heeded. + @see ScopedLock, ScopedTryLock, ScopedUnlock, SpinLock, ReadWriteLock, Thread, InterProcessLock */ class JUCE_API CriticalSection @@ -157,21 +161,27 @@ private: /** Automatically locks and unlocks a CriticalSection object. - Use one of these as a local variable to provide RAII-based locking of a CriticalSection. + You can use a ScopedLock as a local variable to provide RAII-based locking of a CriticalSection. e.g. @code - CriticalSection myCriticalSection; - - for (;;) + struct MyObject { - const ScopedLock myScopedLock (myCriticalSection); - // myCriticalSection is now locked + CriticalSection objectLock; + + // assuming that this example function will be called by multiple threads + void foo() + { + const ScopedLock myScopedLock (objectLock); + + // objectLock is now locked.. - ...do some stuff... + ...do some thread-safe work here... - // myCriticalSection gets unlocked here. - } + // ..and objectLock gets unlocked here, as myScopedLock goes out of + // scope at the end of the block + } + }; @endcode @see CriticalSection, ScopedUnlock @@ -189,29 +199,29 @@ typedef CriticalSection::ScopedLockType ScopedLock; e.g. @code - CriticalSection myCriticalSection; - - for (;;) + struct MyObject { - const ScopedLock myScopedLock (myCriticalSection); - // myCriticalSection is now locked - - ... do some stuff with it locked .. + CriticalSection objectLock; - while (xyz) + void foo() { - ... do some stuff with it locked .. + { + const ScopedLock myScopedLock (objectLock); - const ScopedUnlock unlocker (myCriticalSection); + // objectLock is now locked.. - // myCriticalSection is now unlocked for the remainder of this block, - // and re-locked at the end. + { + ScopedUnlock myUnlocker (objectLock); - ...do some stuff with it unlocked ... - } + // ..and now unlocked.. + } + + // ..and now locked again.. + } - // myCriticalSection gets unlocked here. - } + // ..and finally unlocked. + } + }; @endcode @see CriticalSection, ScopedLock @@ -225,26 +235,27 @@ typedef CriticalSection::ScopedUnlockType ScopedUnlock; Use one of these as a local variable to control access to a CriticalSection. e.g. @code - CriticalSection myCriticalSection; - for (;;) + struct MyObject { - const ScopedTryLock myScopedTryLock (myCriticalSection); + CriticalSection objectLock; - // Unlike using a ScopedLock, this may fail to actually get the lock, so you - // should test this with the isLocked() method before doing your thread-unsafe - // action.. - if (myScopedTryLock.isLocked()) + void foo() { - ...do some stuff... + const ScopedTryLock myScopedTryLock (objectLock); + + // Unlike using a ScopedLock, this may fail to actually get the lock, so you + // must call the isLocked() method before making any assumptions.. + if (myScopedTryLock.isLocked()) + { + ...safely do some work... + } + else + { + // If we get here, then our attempt at locking failed because another thread had already locked it.. + } } - else - { - ..our attempt at locking failed because another thread had already locked it.. - } - - // myCriticalSection gets unlocked here (if it was locked) - } + }; @endcode @see CriticalSection::tryEnter, ScopedLock, ScopedUnlock, ScopedReadLock diff --git a/JuceLibraryCode/modules/juce_core/threads/juce_Thread.cpp b/JuceLibraryCode/modules/juce_core/threads/juce_Thread.cpp index 70318dc..3d1ff0a 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_Thread.cpp +++ b/JuceLibraryCode/modules/juce_core/threads/juce_Thread.cpp @@ -221,7 +221,7 @@ bool Thread::setPriority (const int newPriority) const ScopedLock sl (startStopLock); - if (setThreadPriority (threadHandle, newPriority)) + if ((! isThreadRunning()) || setThreadPriority (threadHandle, newPriority)) { threadPriority = newPriority; return true; diff --git a/JuceLibraryCode/modules/juce_core/threads/juce_ThreadPool.cpp b/JuceLibraryCode/modules/juce_core/threads/juce_ThreadPool.cpp index 257572a..e6b0b9f 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_ThreadPool.cpp +++ b/JuceLibraryCode/modules/juce_core/threads/juce_ThreadPool.cpp @@ -26,12 +26,31 @@ ============================================================================== */ +class ThreadPool::ThreadPoolThread : public Thread +{ +public: + ThreadPoolThread (ThreadPool& p) + : Thread ("Pool"), currentJob (nullptr), pool (p) + { + } + + void run() override + { + while (! threadShouldExit()) + if (! pool.runNextJob (*this)) + wait (500); + } + + ThreadPoolJob* volatile currentJob; + ThreadPool& pool; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ThreadPoolThread) +}; + +//============================================================================== ThreadPoolJob::ThreadPoolJob (const String& name) - : jobName (name), - pool (nullptr), - shouldStop (false), - isActive (false), - shouldBeDeleted (false) + : jobName (name), pool (nullptr), + shouldStop (false), isActive (false), shouldBeDeleted (false) { } @@ -57,30 +76,13 @@ void ThreadPoolJob::signalJobShouldExit() shouldStop = true; } -//============================================================================== -class ThreadPool::ThreadPoolThread : public Thread +ThreadPoolJob* ThreadPoolJob::getCurrentThreadPoolJob() { -public: - ThreadPoolThread (ThreadPool& pool_) - : Thread ("Pool"), - pool (pool_) - { - } - - void run() override - { - while (! threadShouldExit()) - { - if (! pool.runNextJob()) - wait (500); - } - } + if (ThreadPool::ThreadPoolThread* t = dynamic_cast (Thread::getCurrentThread())) + return t->currentJob; -private: - ThreadPool& pool; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ThreadPoolThread) -}; + return nullptr; +} //============================================================================== ThreadPool::ThreadPool (const int numThreads) @@ -164,8 +166,7 @@ bool ThreadPool::isJobRunning (const ThreadPoolJob* const job) const return jobs.contains (const_cast (job)) && job->isActive; } -bool ThreadPool::waitForJobToFinish (const ThreadPoolJob* const job, - const int timeOutMs) const +bool ThreadPool::waitForJobToFinish (const ThreadPoolJob* const job, const int timeOutMs) const { if (job != nullptr) { @@ -215,7 +216,7 @@ bool ThreadPool::removeJob (ThreadPoolJob* const job, } bool ThreadPool::removeAllJobs (const bool interruptRunningJobs, const int timeOutMs, - ThreadPool::JobSelector* selectedJobsToRemove) + ThreadPool::JobSelector* const selectedJobsToRemove) { Array jobsToWaitFor; @@ -328,46 +329,49 @@ ThreadPoolJob* ThreadPool::pickNextJobToRun() return nullptr; } -bool ThreadPool::runNextJob() +bool ThreadPool::runNextJob (ThreadPoolThread& thread) { - ThreadPoolJob* const job = pickNextJobToRun(); - - if (job == nullptr) - return false; - - ThreadPoolJob::JobStatus result = ThreadPoolJob::jobHasFinished; - - JUCE_TRY + if (ThreadPoolJob* const job = pickNextJobToRun()) { - result = job->runJob(); - } - JUCE_CATCH_ALL_ASSERT + ThreadPoolJob::JobStatus result = ThreadPoolJob::jobHasFinished; + thread.currentJob = job; - OwnedArray deletionList; + JUCE_TRY + { + result = job->runJob(); + } + JUCE_CATCH_ALL_ASSERT - { - const ScopedLock sl (lock); + thread.currentJob = nullptr; + + OwnedArray deletionList; - if (jobs.contains (job)) { - job->isActive = false; + const ScopedLock sl (lock); - if (result != ThreadPoolJob::jobNeedsRunningAgain || job->shouldStop) + if (jobs.contains (job)) { - jobs.removeFirstMatchingValue (job); - addToDeleteList (deletionList, job); + job->isActive = false; - jobFinishedSignal.signal(); - } - else - { - // move the job to the end of the queue if it wants another go - jobs.move (jobs.indexOf (job), -1); + if (result != ThreadPoolJob::jobNeedsRunningAgain || job->shouldStop) + { + jobs.removeFirstMatchingValue (job); + addToDeleteList (deletionList, job); + + jobFinishedSignal.signal(); + } + else + { + // move the job to the end of the queue if it wants another go + jobs.move (jobs.indexOf (job), -1); + } } } + + return true; } - return true; + return false; } void ThreadPool::addToDeleteList (OwnedArray& deletionList, ThreadPoolJob* const job) const diff --git a/JuceLibraryCode/modules/juce_core/threads/juce_ThreadPool.h b/JuceLibraryCode/modules/juce_core/threads/juce_ThreadPool.h index ed820e8..3d5f762 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_ThreadPool.h +++ b/JuceLibraryCode/modules/juce_core/threads/juce_ThreadPool.h @@ -119,6 +119,12 @@ public: */ void signalJobShouldExit(); + //============================================================================== + /** If the calling thread is being invoked inside a runJob() method, this will + return the ThreadPoolJob that it belongs to. + */ + static ThreadPoolJob* getCurrentThreadPoolJob(); + //============================================================================== private: friend class ThreadPool; @@ -290,6 +296,7 @@ private: Array jobs; class ThreadPoolThread; + friend class ThreadPoolJob; friend class ThreadPoolThread; friend struct ContainerDeletePolicy; OwnedArray threads; @@ -297,7 +304,7 @@ private: CriticalSection lock; WaitableEvent jobFinishedSignal; - bool runNextJob(); + bool runNextJob (ThreadPoolThread&); ThreadPoolJob* pickNextJobToRun(); void addToDeleteList (OwnedArray&, ThreadPoolJob*) const; void createThreads (int numThreads); diff --git a/JuceLibraryCode/modules/juce_core/time/juce_Time.cpp b/JuceLibraryCode/modules/juce_core/time/juce_Time.cpp index 6903683..959275b 100644 --- a/JuceLibraryCode/modules/juce_core/time/juce_Time.cpp +++ b/JuceLibraryCode/modules/juce_core/time/juce_Time.cpp @@ -110,7 +110,7 @@ namespace TimeHelpers const size_t numChars = wcsftime (buffer, bufferSize - 1, format.toUTF32(), tm); #endif - if (numChars > 0) + if (numChars > 0 || format.isEmpty()) return String (StringType (buffer), StringType (buffer) + (int) numChars); } diff --git a/JuceLibraryCode/modules/juce_core/xml/juce_XmlDocument.cpp b/JuceLibraryCode/modules/juce_core/xml/juce_XmlDocument.cpp index 6243d3e..3ccebd0 100644 --- a/JuceLibraryCode/modules/juce_core/xml/juce_XmlDocument.cpp +++ b/JuceLibraryCode/modules/juce_core/xml/juce_XmlDocument.cpp @@ -371,8 +371,8 @@ void XmlDocument::readQuotedString (String& result) } else if (character == 0) { - outOfData = true; setLastError ("unmatched quotes", false); + outOfData = true; break; } @@ -432,7 +432,7 @@ XmlElement* XmlDocument::readNextElement (const bool alsoParseSubElements) ++input; if (alsoParseSubElements) - readChildElements (node); + readChildElements (*node); break; } @@ -487,9 +487,9 @@ XmlElement* XmlDocument::readNextElement (const bool alsoParseSubElements) return node; } -void XmlDocument::readChildElements (XmlElement* parent) +void XmlDocument::readChildElements (XmlElement& parent) { - LinkedListPointer::Appender childAppender (parent->firstChildElement); + LinkedListPointer::Appender childAppender (parent.firstChildElement); for (;;) { @@ -563,7 +563,25 @@ void XmlDocument::readChildElements (XmlElement* parent) const juce_wchar c = *input; if (c == '<') + { + if (input[1] == '!' && input[2] == '-' && input[3] == '-') + { + input += 4; + const int closeComment = input.indexOf (CharPointer_ASCII ("-->")); + + if (closeComment < 0) + { + setLastError ("unterminated comment", false); + outOfData = true; + return; + } + + input += closeComment + 3; + continue; + } + break; + } if (c == 0) { diff --git a/JuceLibraryCode/modules/juce_core/xml/juce_XmlDocument.h b/JuceLibraryCode/modules/juce_core/xml/juce_XmlDocument.h index 582c23f..d2a5b49 100644 --- a/JuceLibraryCode/modules/juce_core/xml/juce_XmlDocument.h +++ b/JuceLibraryCode/modules/juce_core/xml/juce_XmlDocument.h @@ -156,23 +156,23 @@ private: String lastError, dtdText; StringArray tokenisedDTD; bool needToLoadDTD, ignoreEmptyTextElements; - ScopedPointer inputSource; + ScopedPointer inputSource; XmlElement* parseDocumentElement (String::CharPointerType, bool outer); - void setLastError (const String& desc, bool carryOn); + void setLastError (const String&, bool carryOn); bool parseHeader(); bool parseDTD(); void skipNextWhiteSpace(); juce_wchar readNextChar() noexcept; XmlElement* readNextElement (bool alsoParseSubElements); - void readChildElements (XmlElement* parent); - void readQuotedString (String& result); - void readEntity (String& result); - - String getFileContents (const String& filename) const; - String expandEntity (const String& entity); - String expandExternalEntity (const String& entity); - String getParameterEntity (const String& entity); + void readChildElements (XmlElement&); + void readQuotedString (String&); + void readEntity (String&); + + String getFileContents (const String&) const; + String expandEntity (const String&); + String expandExternalEntity (const String&); + String getParameterEntity (const String&); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XmlDocument) }; diff --git a/JuceLibraryCode/modules/juce_core/xml/juce_XmlElement.cpp b/JuceLibraryCode/modules/juce_core/xml/juce_XmlElement.cpp index 0a0a725..886c98d 100644 --- a/JuceLibraryCode/modules/juce_core/xml/juce_XmlElement.cpp +++ b/JuceLibraryCode/modules/juce_core/xml/juce_XmlElement.cpp @@ -55,7 +55,7 @@ XmlElement::XmlElement (const String& tag) noexcept jassert (tag.containsNonWhitespaceChars()) // The tag can't contain spaces or other characters that would create invalid XML! - jassert (! tag.containsAnyOf (" <>/&")); + jassert (! tag.containsAnyOf (" <>/&(){}")); } XmlElement::XmlElement (int /*dummy*/) noexcept diff --git a/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp b/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp index 3c1c0d4..f20b144 100644 --- a/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp +++ b/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp @@ -215,18 +215,18 @@ bool PropertiesFile::loadAsXml() bool PropertiesFile::saveAsXml() { XmlElement doc (PropertyFileConstants::fileTag); + const StringPairArray& props = getAllProperties(); - for (int i = 0; i < getAllProperties().size(); ++i) + for (int i = 0; i < props.size(); ++i) { XmlElement* const e = doc.createNewChildElement (PropertyFileConstants::valueTag); - e->setAttribute (PropertyFileConstants::nameAttribute, getAllProperties().getAllKeys() [i]); + e->setAttribute (PropertyFileConstants::nameAttribute, props.getAllKeys() [i]); // if the value seems to contain xml, store it as such.. - if (XmlElement* const childElement = XmlDocument::parse (getAllProperties().getAllValues() [i])) + if (XmlElement* const childElement = XmlDocument::parse (props.getAllValues() [i])) e->addChildElement (childElement); else - e->setAttribute (PropertyFileConstants::valueAttribute, - getAllProperties().getAllValues() [i]); + e->setAttribute (PropertyFileConstants::valueAttribute, props.getAllValues() [i]); } ProcessScopedLock pl (createProcessLock()); @@ -311,14 +311,17 @@ bool PropertiesFile::saveAsBinary() out->writeInt (PropertyFileConstants::magicNumber); } - const int numProperties = getAllProperties().size(); + const StringPairArray& props = getAllProperties(); + const int numProperties = props.size(); + const StringArray& keys = props.getAllKeys(); + const StringArray& values = props.getAllValues(); out->writeInt (numProperties); for (int i = 0; i < numProperties; ++i) { - out->writeString (getAllProperties().getAllKeys() [i]); - out->writeString (getAllProperties().getAllValues() [i]); + out->writeString (keys[i]); + out->writeString (values[i]); } out = nullptr; diff --git a/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_PropertiesFile.h b/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_PropertiesFile.h index fd09c8c..dc8929a 100644 --- a/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_PropertiesFile.h +++ b/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_PropertiesFile.h @@ -57,7 +57,7 @@ public: struct JUCE_API Options { /** Creates an empty Options structure. - You'll need to fill-in the data memebers appropriately before using this structure. + You'll need to fill-in the data members appropriately before using this structure. */ Options(); diff --git a/JuceLibraryCode/modules/juce_data_structures/juce_module_info b/JuceLibraryCode/modules/juce_data_structures/juce_module_info index 7ba39c4..853ae59 100644 --- a/JuceLibraryCode/modules/juce_data_structures/juce_module_info +++ b/JuceLibraryCode/modules/juce_data_structures/juce_module_info @@ -1,7 +1,7 @@ { "id": "juce_data_structures", "name": "JUCE data model helper classes", - "version": "3.0.1", + "version": "3.0.3", "description": "Classes for undo/redo management, and smart data structures.", "website": "http://www.juce.com/juce", "license": "GPL/Commercial", diff --git a/JuceLibraryCode/modules/juce_events/broadcasters/juce_ActionBroadcaster.h b/JuceLibraryCode/modules/juce_events/broadcasters/juce_ActionBroadcaster.h index ec72733..8052bed 100644 --- a/JuceLibraryCode/modules/juce_events/broadcasters/juce_ActionBroadcaster.h +++ b/JuceLibraryCode/modules/juce_events/broadcasters/juce_ActionBroadcaster.h @@ -73,7 +73,7 @@ private: class ActionMessage; friend class ActionMessage; - SortedSet actionListeners; + SortedSet actionListeners; CriticalSection actionListenerLock; JUCE_DECLARE_NON_COPYABLE (ActionBroadcaster) diff --git a/JuceLibraryCode/modules/juce_events/broadcasters/juce_ActionListener.h b/JuceLibraryCode/modules/juce_events/broadcasters/juce_ActionListener.h index 200f606..12257f9 100644 --- a/JuceLibraryCode/modules/juce_events/broadcasters/juce_ActionListener.h +++ b/JuceLibraryCode/modules/juce_events/broadcasters/juce_ActionListener.h @@ -28,10 +28,7 @@ //============================================================================== /** - Receives callbacks to indicate that some kind of event has occurred. - - Used by various classes, e.g. buttons when they are pressed, to tell listeners - about something that's happened. + Interface class for delivery of events that are sent by an ActionBroadcaster. @see ActionBroadcaster, ChangeListener */ diff --git a/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnection.cpp b/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnection.cpp index e22ff5b..b1b72f7 100644 --- a/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnection.cpp +++ b/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnection.cpp @@ -22,14 +22,27 @@ ============================================================================== */ +struct InterprocessConnection::ConnectionThread : public Thread +{ + ConnectionThread (InterprocessConnection& c) : Thread ("JUCE IPC"), owner (c) {} + + void run() override { owner.runThread(); } + +private: + InterprocessConnection& owner; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ConnectionThread); +}; + +//============================================================================== InterprocessConnection::InterprocessConnection (const bool callbacksOnMessageThread, const uint32 magicMessageHeaderNumber) - : Thread ("Juce IPC connection"), - callbackConnectionState (false), + : callbackConnectionState (false), useMessageThread (callbacksOnMessageThread), magicMessageHeader (magicMessageHeaderNumber), pipeReceiveMessageTimeout (-1) { + thread = new ConnectionThread (*this); } InterprocessConnection::~InterprocessConnection() @@ -37,9 +50,9 @@ InterprocessConnection::~InterprocessConnection() callbackConnectionState = false; disconnect(); masterReference.clear(); + thread = nullptr; } - //============================================================================== bool InterprocessConnection::connectToSocket (const String& hostName, const int portNumber, @@ -53,7 +66,7 @@ bool InterprocessConnection::connectToSocket (const String& hostName, if (socket->connect (hostName, portNumber, timeOutMillisecs)) { connectionMadeInt(); - startThread(); + thread->startThread(); return true; } else @@ -99,7 +112,7 @@ bool InterprocessConnection::createPipe (const String& pipeName, const int timeo void InterprocessConnection::disconnect() { - signalThreadShouldExit(); + thread->signalThreadShouldExit(); { const ScopedLock sl (pipeAndSocketLock); @@ -107,7 +120,7 @@ void InterprocessConnection::disconnect() if (pipe != nullptr) pipe->close(); } - stopThread (4000); + thread->stopThread (4000); deletePipeAndSocket(); connectionLostInt(); } @@ -125,7 +138,7 @@ bool InterprocessConnection::isConnected() const return ((socket != nullptr && socket->isConnected()) || (pipe != nullptr && pipe->isOpen())) - && isThreadRunning(); + && thread->isThreadRunning(); } String InterprocessConnection::getConnectedHostName() const @@ -173,7 +186,7 @@ void InterprocessConnection::initialiseWithSocket (StreamingSocket* newSocket) jassert (socket == nullptr && pipe == nullptr); socket = newSocket; connectionMadeInt(); - startThread(); + thread->startThread(); } void InterprocessConnection::initialiseWithPipe (NamedPipe* newPipe) @@ -181,7 +194,7 @@ void InterprocessConnection::initialiseWithPipe (NamedPipe* newPipe) jassert (socket == nullptr && pipe == nullptr); pipe = newPipe; connectionMadeInt(); - startThread(); + thread->startThread(); } //============================================================================== @@ -279,7 +292,7 @@ bool InterprocessConnection::readNextMessageInt() while (bytesInMessage > 0) { - if (threadShouldExit()) + if (thread->threadShouldExit()) return false; const int numThisTime = jmin (bytesInMessage, 65536); @@ -311,9 +324,9 @@ bool InterprocessConnection::readNextMessageInt() return true; } -void InterprocessConnection::run() +void InterprocessConnection::runThread() { - while (! threadShouldExit()) + while (! thread->threadShouldExit()) { if (socket != nullptr) { @@ -328,7 +341,7 @@ void InterprocessConnection::run() if (ready == 0) { - wait (1); + thread->wait (1); continue; } } @@ -346,7 +359,7 @@ void InterprocessConnection::run() break; } - if (threadShouldExit() || ! readNextMessageInt()) + if (thread->threadShouldExit() || ! readNextMessageInt()) break; } } diff --git a/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnection.h b/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnection.h index 25aa502..8f21a29 100644 --- a/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnection.h +++ b/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnection.h @@ -47,7 +47,7 @@ class MemoryBlock; @see InterprocessConnectionServer, Socket, NamedPipe */ -class JUCE_API InterprocessConnection : private Thread +class JUCE_API InterprocessConnection { public: //============================================================================== @@ -71,7 +71,7 @@ public: uint32 magicMessageHeaderNumber = 0xf2b49e2c); /** Destructor. */ - ~InterprocessConnection(); + virtual ~InterprocessConnection(); //============================================================================== /** Tries to connect this object to a socket. @@ -195,7 +195,12 @@ private: void connectionLostInt(); void deliverDataInt (const MemoryBlock&); bool readNextMessageInt(); - void run() override; + + struct ConnectionThread; + friend struct ConnectionThread; + friend struct ContainerDeletePolicy; + ScopedPointer thread; + void runThread(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InterprocessConnection) }; diff --git a/JuceLibraryCode/modules/juce_events/juce_events.cpp b/JuceLibraryCode/modules/juce_events/juce_events.cpp index aa11627..2110d0a 100644 --- a/JuceLibraryCode/modules/juce_events/juce_events.cpp +++ b/JuceLibraryCode/modules/juce_events/juce_events.cpp @@ -73,6 +73,7 @@ namespace juce #include "timers/juce_Timer.cpp" #include "interprocess/juce_InterprocessConnection.cpp" #include "interprocess/juce_InterprocessConnectionServer.cpp" +#include "interprocess/juce_ConnectedChildProcess.cpp" //============================================================================== #if JUCE_MAC diff --git a/JuceLibraryCode/modules/juce_events/juce_events.h b/JuceLibraryCode/modules/juce_events/juce_events.h index 799adc0..02f7c63 100644 --- a/JuceLibraryCode/modules/juce_events/juce_events.h +++ b/JuceLibraryCode/modules/juce_events/juce_events.h @@ -49,6 +49,7 @@ namespace juce #include "timers/juce_MultiTimer.h" #include "interprocess/juce_InterprocessConnection.h" #include "interprocess/juce_InterprocessConnectionServer.h" +#include "interprocess/juce_ConnectedChildProcess.h" #include "native/juce_ScopedXLock.h" } diff --git a/JuceLibraryCode/modules/juce_events/juce_module_info b/JuceLibraryCode/modules/juce_events/juce_module_info index cb3c7f2..a537935 100644 --- a/JuceLibraryCode/modules/juce_events/juce_module_info +++ b/JuceLibraryCode/modules/juce_events/juce_module_info @@ -1,7 +1,7 @@ { "id": "juce_events", "name": "JUCE message and event handling classes", - "version": "3.0.1", + "version": "3.0.3", "description": "Classes for running an application's main event loop and sending/receiving messages, timers, etc.", "website": "http://www.juce.com/juce", "license": "GPL/Commercial", diff --git a/JuceLibraryCode/modules/juce_graphics/colour/juce_Colour.cpp b/JuceLibraryCode/modules/juce_graphics/colour/juce_Colour.cpp index d2095cc..0646287 100644 --- a/JuceLibraryCode/modules/juce_graphics/colour/juce_Colour.cpp +++ b/JuceLibraryCode/modules/juce_graphics/colour/juce_Colour.cpp @@ -26,7 +26,7 @@ namespace ColourHelpers { static uint8 floatToUInt8 (const float n) noexcept { - return n <= 0.0f ? 0 : (n >= 1.0f ? 255 : (uint8) (n * 255.0f)); + return n <= 0.0f ? 0 : (n >= 1.0f ? 255 : static_cast (n * 255.996f)); } // This is an adjusted brightness value, based on the way the human diff --git a/JuceLibraryCode/modules/juce_graphics/colour/juce_ColourGradient.h b/JuceLibraryCode/modules/juce_graphics/colour/juce_ColourGradient.h index ad499ce..73e6631 100644 --- a/JuceLibraryCode/modules/juce_graphics/colour/juce_ColourGradient.h +++ b/JuceLibraryCode/modules/juce_graphics/colour/juce_ColourGradient.h @@ -151,8 +151,8 @@ public: */ bool isRadial; - bool operator== (const ColourGradient& other) const noexcept; - bool operator!= (const ColourGradient& other) const noexcept; + bool operator== (const ColourGradient&) const noexcept; + bool operator!= (const ColourGradient&) const noexcept; private: @@ -165,14 +165,14 @@ private: : position (pos), colour (col) {} - bool operator== (const ColourPoint& other) const noexcept; - bool operator!= (const ColourPoint& other) const noexcept; + bool operator== (const ColourPoint&) const noexcept; + bool operator!= (const ColourPoint&) const noexcept; double position; Colour colour; }; - Array colours; + Array colours; JUCE_LEAK_DETECTOR (ColourGradient) }; diff --git a/JuceLibraryCode/modules/juce_graphics/colour/juce_FillType.h b/JuceLibraryCode/modules/juce_graphics/colour/juce_FillType.h index 714b204..19401d6 100644 --- a/JuceLibraryCode/modules/juce_graphics/colour/juce_FillType.h +++ b/JuceLibraryCode/modules/juce_graphics/colour/juce_FillType.h @@ -59,14 +59,14 @@ public: FillType (const Image& image, const AffineTransform& transform) noexcept; /** Creates a copy of another FillType. */ - FillType (const FillType& other); + FillType (const FillType&); /** Makes a copy of another FillType. */ - FillType& operator= (const FillType& other); + FillType& operator= (const FillType&); #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS - FillType (FillType&& other) noexcept; - FillType& operator= (FillType&& other) noexcept; + FillType (FillType&&) noexcept; + FillType& operator= (FillType&&) noexcept; #endif /** Destructor. */ @@ -138,8 +138,8 @@ public: AffineTransform transform; //============================================================================== - bool operator== (const FillType& other) const; - bool operator!= (const FillType& other) const; + bool operator== (const FillType&) const; + bool operator!= (const FillType&) const; private: JUCE_LEAK_DETECTOR (FillType) diff --git a/JuceLibraryCode/modules/juce_graphics/contexts/juce_GraphicsContext.cpp b/JuceLibraryCode/modules/juce_graphics/contexts/juce_GraphicsContext.cpp index e43cf79..3442b1d 100644 --- a/JuceLibraryCode/modules/juce_graphics/contexts/juce_GraphicsContext.cpp +++ b/JuceLibraryCode/modules/juce_graphics/contexts/juce_GraphicsContext.cpp @@ -281,28 +281,30 @@ void Graphics::drawMultiLineText (const String& text, const int startX, } } -void Graphics::drawText (const String& text, const Rectangle& area, - Justification justificationType, - const bool useEllipsesIfTooBig) const +void Graphics::drawText (const String& text, const Rectangle& area, + Justification justificationType, bool useEllipsesIfTooBig) const { - if (text.isNotEmpty() && context.clipRegionIntersects (area)) + if (text.isNotEmpty() && context.clipRegionIntersects (area.getSmallestIntegerContainer())) { GlyphArrangement arr; - arr.addCurtailedLineOfText (context.getFont(), text, - 0.0f, 0.0f, (float) area.getWidth(), - useEllipsesIfTooBig); + arr.addCurtailedLineOfText (context.getFont(), text, 0.0f, 0.0f, + area.getWidth(), useEllipsesIfTooBig); arr.justifyGlyphs (0, arr.getNumGlyphs(), - (float) area.getX(), (float) area.getY(), - (float) area.getWidth(), (float) area.getHeight(), + area.getX(), area.getY(), area.getWidth(), area.getHeight(), justificationType); arr.draw (*this); } } +void Graphics::drawText (const String& text, const Rectangle& area, + Justification justificationType, bool useEllipsesIfTooBig) const +{ + drawText (text, area.toFloat(), justificationType, useEllipsesIfTooBig); +} + void Graphics::drawText (const String& text, const int x, const int y, const int width, const int height, - Justification justificationType, - const bool useEllipsesIfTooBig) const + Justification justificationType, const bool useEllipsesIfTooBig) const { drawText (text, Rectangle (x, y, width, height), justificationType, useEllipsesIfTooBig); } diff --git a/JuceLibraryCode/modules/juce_graphics/contexts/juce_GraphicsContext.h b/JuceLibraryCode/modules/juce_graphics/contexts/juce_GraphicsContext.h index 221cfcb..d59bcd2 100644 --- a/JuceLibraryCode/modules/juce_graphics/contexts/juce_GraphicsContext.h +++ b/JuceLibraryCode/modules/juce_graphics/contexts/juce_GraphicsContext.h @@ -174,6 +174,20 @@ public: Justification justificationType, bool useEllipsesIfTooBig) const; + /** Draws a line of text within a specified rectangle. + + The text will be positioned within the rectangle based on the justification + flags passed-in. If the string is too long to fit inside the rectangle, it will + either be truncated or will have ellipsis added to its end (if the useEllipsesIfTooBig + flag is true). + + @see drawSingleLineText, drawFittedText, drawMultiLineText, GlyphArrangement::addJustifiedText + */ + void drawText (const String& text, + const Rectangle& area, + Justification justificationType, + bool useEllipsesIfTooBig) const; + /** Tries to draw a text string inside a given space. This does its best to make the given text readable within the specified rectangle, diff --git a/JuceLibraryCode/modules/juce_graphics/fonts/juce_CustomTypeface.cpp b/JuceLibraryCode/modules/juce_graphics/fonts/juce_CustomTypeface.cpp index c9d6e8d..a2adb04 100644 --- a/JuceLibraryCode/modules/juce_graphics/fonts/juce_CustomTypeface.cpp +++ b/JuceLibraryCode/modules/juce_graphics/fonts/juce_CustomTypeface.cpp @@ -385,7 +385,7 @@ bool CustomTypeface::getOutlineForGlyph (int glyphNumber, Path& path) return false; } -EdgeTable* CustomTypeface::getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform) +EdgeTable* CustomTypeface::getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform, float fontHeight) { if (const GlyphInfo* const glyph = findGlyph ((juce_wchar) glyphNumber, true)) { @@ -399,7 +399,7 @@ EdgeTable* CustomTypeface::getEdgeTableForGlyph (int glyphNumber, const AffineTr const Typeface::Ptr fallbackTypeface (getFallbackTypeface()); if (fallbackTypeface != nullptr && fallbackTypeface != this) - return fallbackTypeface->getEdgeTableForGlyph (glyphNumber, transform); + return fallbackTypeface->getEdgeTableForGlyph (glyphNumber, transform, fontHeight); } return nullptr; diff --git a/JuceLibraryCode/modules/juce_graphics/fonts/juce_CustomTypeface.h b/JuceLibraryCode/modules/juce_graphics/fonts/juce_CustomTypeface.h index 8e7e020..fa1bb79 100644 --- a/JuceLibraryCode/modules/juce_graphics/fonts/juce_CustomTypeface.h +++ b/JuceLibraryCode/modules/juce_graphics/fonts/juce_CustomTypeface.h @@ -119,7 +119,7 @@ public: float getStringWidth (const String&) override; void getGlyphPositions (const String&, Array & glyphs, Array& xOffsets) override; bool getOutlineForGlyph (int glyphNumber, Path&) override; - EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform&) override; + EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform&, float fontHeight) override; protected: //============================================================================== diff --git a/JuceLibraryCode/modules/juce_graphics/fonts/juce_GlyphArrangement.h b/JuceLibraryCode/modules/juce_graphics/fonts/juce_GlyphArrangement.h index 62b40b9..f11894d 100644 --- a/JuceLibraryCode/modules/juce_graphics/fonts/juce_GlyphArrangement.h +++ b/JuceLibraryCode/modules/juce_graphics/fonts/juce_GlyphArrangement.h @@ -44,8 +44,8 @@ public: PositionedGlyph (const Font& font, juce_wchar character, int glyphNumber, float anchorX, float baselineY, float width, bool isWhitespace); - PositionedGlyph (const PositionedGlyph& other); - PositionedGlyph& operator= (const PositionedGlyph& other); + PositionedGlyph (const PositionedGlyph&); + PositionedGlyph& operator= (const PositionedGlyph&); ~PositionedGlyph(); /** Returns the character the glyph represents. */ @@ -209,10 +209,10 @@ public: float minimumHorizontalScale = 0.7f); /** Appends another glyph arrangement to this one. */ - void addGlyphArrangement (const GlyphArrangement& other); + void addGlyphArrangement (const GlyphArrangement&); /** Appends a custom glyph to the arrangement. */ - void addGlyph (const PositionedGlyph& glyph); + void addGlyph (const PositionedGlyph&); //============================================================================== /** Draws this glyph arrangement to a graphics context. diff --git a/JuceLibraryCode/modules/juce_graphics/fonts/juce_Typeface.cpp b/JuceLibraryCode/modules/juce_graphics/fonts/juce_Typeface.cpp index 032ee31..4eda6b0 100644 --- a/JuceLibraryCode/modules/juce_graphics/fonts/juce_Typeface.cpp +++ b/JuceLibraryCode/modules/juce_graphics/fonts/juce_Typeface.cpp @@ -101,8 +101,8 @@ struct FontStyleHelpers }; //============================================================================== -Typeface::Typeface (const String& name_, const String& style_) noexcept - : name (name_), style (style_) +Typeface::Typeface (const String& faceName, const String& styleName) noexcept + : name (faceName), style (styleName) { } @@ -116,13 +116,145 @@ Typeface::Ptr Typeface::getFallbackTypeface() return fallbackFont.getTypeface(); } -EdgeTable* Typeface::getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform) +EdgeTable* Typeface::getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform, float fontHeight) { Path path; if (getOutlineForGlyph (glyphNumber, path) && ! path.isEmpty()) + { + applyVerticalHintingTransform (fontHeight, path); + return new EdgeTable (path.getBoundsTransformed (transform).getSmallestIntegerContainer().expanded (1, 0), path, transform); + } return nullptr; } + +//============================================================================== +struct Typeface::HintingParams +{ + HintingParams (Typeface& t) + : cachedSize (0), top (0), middle (0), bottom (0) + { + Font font (&t); + font = font.withHeight ((float) standardHeight); + + top = getAverageY (font, "BDEFPRTZOQ", true); + middle = getAverageY (font, "acegmnopqrsuvwxy", true); + bottom = getAverageY (font, "BDELZOC", false); + } + + void applyVerticalHintingTransform (float fontSize, Path& path) + { + if (cachedSize != fontSize) + { + cachedSize = fontSize; + cachedScale = Scaling (top, middle, bottom, fontSize); + } + + if (bottom < top + 3.0f / fontSize) + return; + + Path result; + + for (Path::Iterator i (path); i.next();) + { + switch (i.elementType) + { + case Path::Iterator::startNewSubPath: result.startNewSubPath (i.x1, cachedScale.apply (i.y1)); break; + case Path::Iterator::lineTo: result.lineTo (i.x1, cachedScale.apply (i.y1)); break; + case Path::Iterator::quadraticTo: result.quadraticTo (i.x1, cachedScale.apply (i.y1), + i.x2, cachedScale.apply (i.y2)); break; + case Path::Iterator::cubicTo: result.cubicTo (i.x1, cachedScale.apply (i.y1), + i.x2, cachedScale.apply (i.y2), + i.x3, cachedScale.apply (i.y3)); break; + case Path::Iterator::closePath: result.closeSubPath(); break; + default: jassertfalse; break; + } + } + + result.swapWithPath (path); + } + +private: + struct Scaling + { + Scaling() noexcept : middle(), upperScale(), upperOffset(), lowerScale(), lowerOffset() {} + + Scaling (float t, float m, float b, float fontSize) noexcept : middle (m) + { + const float newT = std::floor (fontSize * t + 0.5f) / fontSize; + const float newB = std::floor (fontSize * b + 0.5f) / fontSize; + const float newM = std::floor (fontSize * m + 0.3f) / fontSize; // this is slightly biased so that lower-case letters + // are more likely to become taller than shorter. + upperScale = jlimit (0.9f, 1.1f, (newM - newT) / (m - t)); + lowerScale = jlimit (0.9f, 1.1f, (newB - newM) / (b - m)); + + upperOffset = newM - m * upperScale; + lowerOffset = newB - b * lowerScale; + } + + float apply (float y) const noexcept + { + return y < middle ? (y * upperScale + upperOffset) + : (y * lowerScale + lowerOffset); + } + + float middle, upperScale, upperOffset, lowerScale, lowerOffset; + }; + + float cachedSize; + Scaling cachedScale; + + static float getAverageY (const Font& font, const char* chars, bool getTop) + { + GlyphArrangement ga; + ga.addLineOfText (font, chars, 0, 0); + + Array y; + DefaultElementComparator sorter; + + for (int i = 0; i < ga.getNumGlyphs(); ++i) + { + Path p; + ga.getGlyph (i).createPath (p); + Rectangle bounds (p.getBounds()); + + if (! p.isEmpty()) + y.addSorted (sorter, getTop ? bounds.getY() : bounds.getBottom()); + } + + float median = y[y.size() / 2]; + + float total = 0; + int num = 0; + + for (int i = 0; i < y.size(); ++i) + { + if (std::abs (median - y.getUnchecked(i)) < 0.05f * (float) standardHeight) + { + total += y.getUnchecked(i); + ++num; + } + } + + return num < 4 ? 0.0f : total / (num * (float) standardHeight); + } + + enum { standardHeight = 100 }; + float top, middle, bottom; +}; + +void Typeface::applyVerticalHintingTransform (float fontSize, Path& path) +{ + if (fontSize > 3.0f && fontSize < 25.0f) + { + ScopedLock sl (hintingLock); + + if (hintingParams == nullptr) + hintingParams = new HintingParams (*this); + + return hintingParams->applyVerticalHintingTransform (fontSize, path); + } +} diff --git a/JuceLibraryCode/modules/juce_graphics/fonts/juce_Typeface.h b/JuceLibraryCode/modules/juce_graphics/fonts/juce_Typeface.h index 9c2ae31..a392fb7 100644 --- a/JuceLibraryCode/modules/juce_graphics/fonts/juce_Typeface.h +++ b/JuceLibraryCode/modules/juce_graphics/fonts/juce_Typeface.h @@ -117,7 +117,7 @@ public: virtual bool getOutlineForGlyph (int glyphNumber, Path& path) = 0; /** Returns a new EdgeTable that contains the path for the givem glyph, with the specified transform applied. */ - virtual EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform); + virtual EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform, float fontHeight); /** Returns true if the typeface uses hinting. */ virtual bool isHinted() const { return false; } @@ -134,6 +134,12 @@ public: */ static void scanFolderForFonts (const File& folder); + /** Makes an attempt at performing a good overall distortion that will scale a font of + the given size to align vertically with the pixel grid. The path should be an unscaled + (i.e. normalised to height of 1.0) path for a glyph. + */ + void applyVerticalHintingTransform (float fontHeight, Path& path); + protected: //============================================================================== String name, style; @@ -143,6 +149,11 @@ protected: static Ptr getFallbackTypeface(); private: + struct HintingParams; + friend struct ContainerDeletePolicy; + ScopedPointer hintingParams; + CriticalSection hintingLock; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Typeface) }; diff --git a/JuceLibraryCode/modules/juce_graphics/geometry/juce_EdgeTable.h b/JuceLibraryCode/modules/juce_graphics/geometry/juce_EdgeTable.h index 8500d07..d8b6d66 100644 --- a/JuceLibraryCode/modules/juce_graphics/geometry/juce_EdgeTable.h +++ b/JuceLibraryCode/modules/juce_graphics/geometry/juce_EdgeTable.h @@ -62,10 +62,10 @@ public: explicit EdgeTable (const Rectangle& rectangleToAdd); /** Creates a copy of another edge table. */ - EdgeTable (const EdgeTable& other); + EdgeTable (const EdgeTable&); /** Copies from another edge table. */ - EdgeTable& operator= (const EdgeTable& other); + EdgeTable& operator= (const EdgeTable&); /** Destructor. */ ~EdgeTable(); @@ -73,7 +73,7 @@ public: //============================================================================== void clipToRectangle (const Rectangle& r); void excludeRectangle (const Rectangle& r); - void clipToEdgeTable (const EdgeTable& other); + void clipToEdgeTable (const EdgeTable&); void clipLineToMask (int x, int y, const uint8* mask, int maskStride, int numPixels); bool isEmpty() noexcept; const Rectangle& getMaximumBounds() const noexcept { return bounds; } diff --git a/JuceLibraryCode/modules/juce_graphics/geometry/juce_Path.h b/JuceLibraryCode/modules/juce_graphics/geometry/juce_Path.h index b17e704..f94da19 100644 --- a/JuceLibraryCode/modules/juce_graphics/geometry/juce_Path.h +++ b/JuceLibraryCode/modules/juce_graphics/geometry/juce_Path.h @@ -67,21 +67,21 @@ public: Path(); /** Creates a copy of another path. */ - Path (const Path& other); + Path (const Path&); /** Destructor. */ ~Path(); /** Copies this path from another one. */ - Path& operator= (const Path& other); + Path& operator= (const Path&); #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS - Path (Path&& other) noexcept; - Path& operator= (Path&& other) noexcept; + Path (Path&&) noexcept; + Path& operator= (Path&&) noexcept; #endif - bool operator== (const Path& other) const noexcept; - bool operator!= (const Path& other) const noexcept; + bool operator== (const Path&) const noexcept; + bool operator!= (const Path&) const noexcept; //============================================================================== /** Returns true if the path doesn't contain any lines or curves. */ @@ -558,7 +558,7 @@ public: The internal data of the two paths is swapped over, so this is much faster than copying it to a temp variable and back. */ - void swapWithPath (Path& other) noexcept; + void swapWithPath (Path&) noexcept; //============================================================================== /** Applies a 2D transform to all the vertices in the path. diff --git a/JuceLibraryCode/modules/juce_graphics/geometry/juce_PathStrokeType.cpp b/JuceLibraryCode/modules/juce_graphics/geometry/juce_PathStrokeType.cpp index 3e5e373..bdac333 100644 --- a/JuceLibraryCode/modules/juce_graphics/geometry/juce_PathStrokeType.cpp +++ b/JuceLibraryCode/modules/juce_graphics/geometry/juce_PathStrokeType.cpp @@ -22,12 +22,13 @@ ============================================================================== */ -PathStrokeType::PathStrokeType (const float strokeThickness, - const JointStyle jointStyle_, - const EndCapStyle endStyle_) noexcept - : thickness (strokeThickness), - jointStyle (jointStyle_), - endStyle (endStyle_) +PathStrokeType::PathStrokeType (float strokeThickness) noexcept + : thickness (strokeThickness), jointStyle (mitered), endStyle (butt) +{ +} + +PathStrokeType::PathStrokeType (float strokeThickness, JointStyle joint, EndCapStyle end) noexcept + : thickness (strokeThickness), jointStyle (joint), endStyle (end) { } diff --git a/JuceLibraryCode/modules/juce_graphics/geometry/juce_PathStrokeType.h b/JuceLibraryCode/modules/juce_graphics/geometry/juce_PathStrokeType.h index 60bb464..6374741 100644 --- a/JuceLibraryCode/modules/juce_graphics/geometry/juce_PathStrokeType.h +++ b/JuceLibraryCode/modules/juce_graphics/geometry/juce_PathStrokeType.h @@ -63,6 +63,9 @@ public: }; //============================================================================== + /** Creates a stroke type with a given line-width, and default joint/end styles. */ + explicit PathStrokeType (float strokeThickness) noexcept; + /** Creates a stroke type. @param strokeThickness the width of the line to use @@ -70,14 +73,14 @@ public: @param endStyle the type of end-caps to use for the ends of open paths. */ PathStrokeType (float strokeThickness, - JointStyle jointStyle = mitered, + JointStyle jointStyle, EndCapStyle endStyle = butt) noexcept; - /** Createes a copy of another stroke type. */ - PathStrokeType (const PathStrokeType& other) noexcept; + /** Creates a copy of another stroke type. */ + PathStrokeType (const PathStrokeType&) noexcept; /** Copies another stroke onto this one. */ - PathStrokeType& operator= (const PathStrokeType& other) noexcept; + PathStrokeType& operator= (const PathStrokeType&) noexcept; /** Destructor. */ ~PathStrokeType() noexcept; @@ -184,10 +187,10 @@ public: //============================================================================== /** Compares the stroke thickness, joint and end styles of two stroke types. */ - bool operator== (const PathStrokeType& other) const noexcept; + bool operator== (const PathStrokeType&) const noexcept; /** Compares the stroke thickness, joint and end styles of two stroke types. */ - bool operator!= (const PathStrokeType& other) const noexcept; + bool operator!= (const PathStrokeType&) const noexcept; private: //============================================================================== diff --git a/JuceLibraryCode/modules/juce_graphics/geometry/juce_Point.h b/JuceLibraryCode/modules/juce_graphics/geometry/juce_Point.h index 3df567b..ffe80fe 100644 --- a/JuceLibraryCode/modules/juce_graphics/geometry/juce_Point.h +++ b/JuceLibraryCode/modules/juce_graphics/geometry/juce_Point.h @@ -151,7 +151,8 @@ public: */ FloatType getAngleToPoint (Point other) const noexcept { - return static_cast (std::atan2 (other.x - x, y - other.y)); + return static_cast (std::atan2 (static_cast (other.x - x), + static_cast (y - other.y))); } /** Returns the point that would be reached by rotating this point clockwise @@ -169,8 +170,8 @@ public: */ Point getPointOnCircumference (float radius, float angle) const noexcept { - return Point (static_cast (x + radius * std::sin (angle)), - static_cast (y - radius * std::cos (angle))); + return Point (static_cast (x + radius * std::sin (angle)), + static_cast (y - radius * std::cos (angle))); } /** Taking this point to be the centre of an ellipse, this returns a point on its circumference. @@ -180,8 +181,8 @@ public: */ Point getPointOnCircumference (float radiusX, float radiusY, float angle) const noexcept { - return Point (static_cast (x + radiusX * std::sin (angle)), - static_cast (y - radiusY * std::cos (angle))); + return Point (static_cast (x + radiusX * std::sin (angle)), + static_cast (y - radiusY * std::cos (angle))); } /** Returns the dot-product of two points (x1 * x2 + y1 * y2). */ @@ -204,13 +205,13 @@ public: //============================================================================== /** Casts this point to a Point object. */ - Point toInt() const noexcept { return Point (static_cast (x), static_cast (y)); } + Point toInt() const noexcept { return Point (static_cast (x), static_cast (y)); } /** Casts this point to a Point object. */ - Point toFloat() const noexcept { return Point (static_cast (x), static_cast (y)); } + Point toFloat() const noexcept { return Point (static_cast (x), static_cast (y)); } /** Casts this point to a Point object. */ - Point toDouble() const noexcept { return Point (static_cast (x), static_cast (y)); } + Point toDouble() const noexcept { return Point (static_cast (x), static_cast (y)); } /** Returns the point as a string in the form "x, y". */ String toString() const { return String (x) + ", " + String (y); } diff --git a/JuceLibraryCode/modules/juce_graphics/geometry/juce_Rectangle.h b/JuceLibraryCode/modules/juce_graphics/geometry/juce_Rectangle.h index 1fc9bd6..6191d1a 100644 --- a/JuceLibraryCode/modules/juce_graphics/geometry/juce_Rectangle.h +++ b/JuceLibraryCode/modules/juce_graphics/geometry/juce_Rectangle.h @@ -174,6 +174,12 @@ public: /** Changes the rectangle's height */ inline void setHeight (const ValueType newHeight) noexcept { h = newHeight; } + /** Changes the position of the rectangle's centre (leaving its size unchanged). */ + inline void setCentre (const ValueType newCentreX, const ValueType newCentreY) noexcept { pos.x = newCentreX - w / (ValueType) 2; pos.y = newCentreY - h / (ValueType) 2; } + + /** Changes the position of the rectangle's centre (leaving its size unchanged). */ + inline void setCentre (const Point newCentre) noexcept { setCentre (newCentre.x, newCentre.y); } + /** Returns a rectangle which has the same size and y-position as this one, but with a different x-position. */ Rectangle withX (const ValueType newX) const noexcept { return Rectangle (newX, pos.y, w, h); } @@ -189,6 +195,10 @@ public: /** Returns a rectangle whose size is the same as this one, but whose top-left position is (0, 0). */ Rectangle withZeroOrigin() const noexcept { return Rectangle (w, h); } + /** Returns a rectangle with the same size as this one, but a new centre position. */ + Rectangle withCentre (const Point newCentre) const noexcept { return Rectangle (newCentre.x - w / (ValueType) 2, + newCentre.y - h / (ValueType) 2, w, h); } + /** Returns a rectangle which has the same position and height as this one, but with a different width. */ Rectangle withWidth (ValueType newWidth) const noexcept { return Rectangle (pos.x, pos.y, newWidth, h); } diff --git a/JuceLibraryCode/modules/juce_graphics/images/juce_Image.cpp b/JuceLibraryCode/modules/juce_graphics/images/juce_Image.cpp index e3ab8d5..d9aa0c4 100644 --- a/JuceLibraryCode/modules/juce_graphics/images/juce_Image.cpp +++ b/JuceLibraryCode/modules/juce_graphics/images/juce_Image.cpp @@ -31,6 +31,12 @@ ImagePixelData::ImagePixelData (const Image::PixelFormat format, const int w, co ImagePixelData::~ImagePixelData() { + listeners.call (&Listener::imageDataBeingDeleted, this); +} + +void ImagePixelData::sendDataChangeMessage() +{ + listeners.call (&Listener::imageDataChanged, this); } //============================================================================== @@ -69,15 +75,19 @@ public: LowLevelGraphicsContext* createLowLevelContext() override { + sendDataChangeMessage(); return new LowLevelGraphicsSoftwareRenderer (Image (this)); } - void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode) override + void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode mode) override { bitmap.data = imageData + x * pixelStride + y * lineStride; bitmap.pixelFormat = pixelFormat; bitmap.lineStride = lineStride; bitmap.pixelStride = pixelStride; + + if (mode != Image::BitmapData::readOnly) + sendDataChangeMessage(); } ImagePixelData* clone() override @@ -146,6 +156,9 @@ public: void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode mode) override { image->initialiseBitmapData (bitmap, x + area.getX(), y + area.getY(), mode); + + if (mode != Image::BitmapData::readOnly) + sendDataChangeMessage(); } ImagePixelData* clone() override diff --git a/JuceLibraryCode/modules/juce_graphics/images/juce_Image.h b/JuceLibraryCode/modules/juce_graphics/images/juce_Image.h index fdd376e..3580f9f 100644 --- a/JuceLibraryCode/modules/juce_graphics/images/juce_Image.h +++ b/JuceLibraryCode/modules/juce_graphics/images/juce_Image.h @@ -106,7 +106,7 @@ public: point to the same shared image data. To make sure that an Image object has its own unique, unshared internal data, call duplicateIfShared(). */ - Image (const Image& other); + Image (const Image&); /** Makes this image refer to the same underlying image as another object. @@ -117,7 +117,7 @@ public: Image& operator= (const Image&); #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS - Image (Image&& other) noexcept; + Image (Image&&) noexcept; Image& operator= (Image&&) noexcept; #endif @@ -455,6 +455,19 @@ public: typedef ReferenceCountedObjectPtr Ptr; + //============================================================================== + struct Listener + { + virtual ~Listener() {} + + virtual void imageDataChanged (ImagePixelData*) = 0; + virtual void imageDataBeingDeleted (ImagePixelData*) = 0; + }; + + ListenerList listeners; + + void sendDataChangeMessage(); + private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ImagePixelData) }; diff --git a/JuceLibraryCode/modules/juce_graphics/juce_module_info b/JuceLibraryCode/modules/juce_graphics/juce_module_info index 6c6e850..bb0125d 100644 --- a/JuceLibraryCode/modules/juce_graphics/juce_module_info +++ b/JuceLibraryCode/modules/juce_graphics/juce_module_info @@ -1,7 +1,7 @@ { "id": "juce_graphics", "name": "JUCE graphics classes", - "version": "3.0.1", + "version": "3.0.3", "description": "Classes for 2D vector graphics, image loading/saving, font handling, etc.", "website": "http://www.juce.com/juce", "license": "GPL/Commercial", diff --git a/JuceLibraryCode/modules/juce_graphics/native/juce_RenderingHelpers.h b/JuceLibraryCode/modules/juce_graphics/native/juce_RenderingHelpers.h index dae758c..10fb9dc 100644 --- a/JuceLibraryCode/modules/juce_graphics/native/juce_RenderingHelpers.h +++ b/JuceLibraryCode/modules/juce_graphics/native/juce_RenderingHelpers.h @@ -87,7 +87,8 @@ public: complexTransform = getTransformWith (t); isOnlyTranslated = false; - isRotated = (complexTransform.mat01 != 0 || complexTransform.mat10 != 0); + isRotated = (complexTransform.mat01 != 0 || complexTransform.mat10 != 0 + || complexTransform.mat00 < 0 || complexTransform.mat11 < 0); } float getPhysicalPixelScaleFactor() const noexcept @@ -283,11 +284,9 @@ public: glyph = glyphNumber; const float fontHeight = font.getHeight(); - edgeTable = typeface->getEdgeTableForGlyph (glyphNumber, AffineTransform::scale (fontHeight * font.getHorizontalScale(), - fontHeight)); - - if (edgeTable != nullptr) - edgeTable->multiplyLevels (1.5f); + edgeTable = typeface->getEdgeTableForGlyph (glyphNumber, + AffineTransform::scale (fontHeight * font.getHorizontalScale(), + fontHeight), fontHeight); } Font font; @@ -295,7 +294,7 @@ public: bool snapToIntegerCoordinate; private: - ScopedPointer edgeTable; + ScopedPointer edgeTable; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CachedGlyphEdgeTable) }; @@ -807,16 +806,19 @@ namespace EdgeTableFillers alphaLevel = (alphaLevel * extraAlpha) >> 8; x -= xOffset; - jassert (repeatPattern || (x >= 0 && x + width <= srcData.width)); - - if (alphaLevel < 0xfe) + if (repeatPattern) { - JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (repeatPattern ? (x++ % srcData.width) : x++), (uint32) alphaLevel)) + if (alphaLevel < 0xfe) + JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++ % srcData.width), (uint32) alphaLevel)) + else + JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++ % srcData.width))) } else { - if (repeatPattern) - JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++ % srcData.width))) + jassert (x >= 0 && x + width <= srcData.width); + + if (alphaLevel < 0xfe) + JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++), (uint32) alphaLevel)) else copyRow (dest, getSrcPixel (x), width); } @@ -827,16 +829,19 @@ namespace EdgeTableFillers DestPixelType* dest = getDestPixel (x); x -= xOffset; - jassert (repeatPattern || (x >= 0 && x + width <= srcData.width)); - - if (extraAlpha < 0xfe) + if (repeatPattern) { - JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (repeatPattern ? (x++ % srcData.width) : x++), (uint32) extraAlpha)) + if (extraAlpha < 0xfe) + JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++ % srcData.width), (uint32) extraAlpha)) + else + JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++ % srcData.width))) } else { - if (repeatPattern) - JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++ % srcData.width))) + jassert (x >= 0 && x + width <= srcData.width); + + if (extraAlpha < 0xfe) + JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++), (uint32) extraAlpha)) else copyRow (dest, getSrcPixel (x), width); } @@ -1351,7 +1356,7 @@ namespace EdgeTableFillers const int maxX, maxY; int y; DestPixelType* linePixels; - HeapBlock scratchBuffer; + HeapBlock scratchBuffer; size_t scratchSize; JUCE_DECLARE_NON_COPYABLE (TransformedImageFill) @@ -1369,16 +1374,16 @@ namespace EdgeTableFillers switch (srcData.pixelFormat) { case Image::ARGB: - if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } + if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } + else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } break; case Image::RGB: - if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } + if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } + else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } break; default: - if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } + if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } + else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } break; } break; @@ -1387,16 +1392,16 @@ namespace EdgeTableFillers switch (srcData.pixelFormat) { case Image::ARGB: - if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } + if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } + else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } break; case Image::RGB: - if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } + if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } + else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } break; default: - if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } + if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } + else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } break; } break; @@ -1405,16 +1410,16 @@ namespace EdgeTableFillers switch (srcData.pixelFormat) { case Image::ARGB: - if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } + if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } + else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } break; case Image::RGB: - if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } + if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } + else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } break; default: - if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } + if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } + else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } break; } break; @@ -1430,16 +1435,16 @@ namespace EdgeTableFillers switch (srcData.pixelFormat) { case Image::ARGB: - if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } + if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } + else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } break; case Image::RGB: - if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } + if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } + else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } break; default: - if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } + if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } + else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } break; } break; @@ -1448,16 +1453,16 @@ namespace EdgeTableFillers switch (srcData.pixelFormat) { case Image::ARGB: - if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } + if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } + else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } break; case Image::RGB: - if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } + if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } + else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } break; default: - if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } + if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } + else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } break; } break; @@ -1466,16 +1471,16 @@ namespace EdgeTableFillers switch (srcData.pixelFormat) { case Image::ARGB: - if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } + if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } + else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } break; case Image::RGB: - if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } + if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } + else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } break; default: - if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } + if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } + else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } break; } break; @@ -1487,12 +1492,12 @@ namespace EdgeTableFillers { if (replaceContents) { - EdgeTableFillers::SolidColour r (destData, fillColour); + EdgeTableFillers::SolidColour r (destData, fillColour); iter.iterate (r); } else { - EdgeTableFillers::SolidColour r (destData, fillColour); + EdgeTableFillers::SolidColour r (destData, fillColour); iter.iterate (r); } } @@ -1505,18 +1510,18 @@ namespace EdgeTableFillers { if (isIdentity) { - EdgeTableFillers::Gradient renderer (destData, g, transform, lookupTable, numLookupEntries); + EdgeTableFillers::Gradient renderer (destData, g, transform, lookupTable, numLookupEntries); iter.iterate (renderer); } else { - EdgeTableFillers::Gradient renderer (destData, g, transform, lookupTable, numLookupEntries); + EdgeTableFillers::Gradient renderer (destData, g, transform, lookupTable, numLookupEntries); iter.iterate (renderer); } } else { - EdgeTableFillers::Gradient renderer (destData, g, transform, lookupTable, numLookupEntries); + EdgeTableFillers::Gradient renderer (destData, g, transform, lookupTable, numLookupEntries); iter.iterate (renderer); } } @@ -1721,7 +1726,7 @@ struct ClipRegions template void transformedClipImage (const Image::BitmapData& srcData, const AffineTransform& transform, const Graphics::ResamplingQuality quality, const SrcPixelType*) { - EdgeTableFillers::TransformedImageFill renderer (srcData, srcData, transform, 255, quality); + EdgeTableFillers::TransformedImageFill renderer (srcData, srcData, transform, 255, quality); for (int y = 0; y < edgeTable.getMaximumBounds().getHeight(); ++y) renderer.clipEdgeTableLine (edgeTable, edgeTable.getMaximumBounds().getX(), y + edgeTable.getMaximumBounds().getY(), @@ -1734,7 +1739,7 @@ struct ClipRegions Rectangle r (imageX, imageY, srcData.width, srcData.height); edgeTable.clipToRectangle (r); - EdgeTableFillers::ImageFill renderer (srcData, srcData, 255, imageX, imageY); + EdgeTableFillers::ImageFill renderer (srcData, srcData, 255, imageX, imageY); for (int y = 0; y < r.getHeight(); ++y) renderer.clipEdgeTableLine (edgeTable, r.getX(), y + r.getY(), r.getWidth()); @@ -2002,7 +2007,7 @@ public: { } - SavedStateType& getThis() noexcept { return *static_cast (this); } + SavedStateType& getThis() noexcept { return *static_cast (this); } bool clipToRectangle (const Rectangle& r) { @@ -2253,11 +2258,20 @@ public: { EdgeTableRegionType* edgeTableClip = new EdgeTableRegionType (edgeTable); edgeTableClip->edgeTable.translate (x, y); + + if (fillType.isColour()) + { + float brightness = fillType.colour.getBrightness() - 0.5f; + + if (brightness > 0.0f) + edgeTableClip->edgeTable.multiplyLevels (1.0f + 1.6f * brightness); + } + fillShape (edgeTableClip, false); } } - void drawLine (const Line & line) + void drawLine (const Line& line) { Path p; p.addLineSegment (line, 1.0f); @@ -2437,7 +2451,7 @@ public: } } - typedef GlyphCache, SoftwareRendererSavedState> GlyphCacheType; + typedef GlyphCache, SoftwareRendererSavedState> GlyphCacheType; static void clearGlyphCache() { @@ -2480,7 +2494,7 @@ public: AffineTransform t (transform.getTransformWith (AffineTransform::scale (fontHeight * font.getHorizontalScale(), fontHeight) .followedBy (trans))); - const ScopedPointer et (font.getTypeface()->getEdgeTableForGlyph (glyphNumber, t)); + const ScopedPointer et (font.getTypeface()->getEdgeTableForGlyph (glyphNumber, t, fontHeight)); if (et != nullptr) fillShape (new EdgeTableRegionType (*et), false); @@ -2523,7 +2537,7 @@ public: template void fillWithGradient (IteratorType& iter, ColourGradient& gradient, const AffineTransform& trans, bool isIdentity) const { - HeapBlock lookupTable; + HeapBlock lookupTable; const int numLookupEntries = gradient.createLookupTable (trans, lookupTable); jassert (numLookupEntries > 0); @@ -2632,7 +2646,7 @@ public: void fillPath (const Path& path, const AffineTransform& t) override { stack->fillPath (path, t); } void drawImage (const Image& im, const AffineTransform& t) override { stack->drawImage (im, t); } void drawGlyph (int glyphNumber, const AffineTransform& t) override { stack->drawGlyph (glyphNumber, t); } - void drawLine (const Line & line) override { stack->drawLine (line); } + void drawLine (const Line& line) override { stack->drawLine (line); } void setFont (const Font& newFont) override { stack->font = newFont; } const Font& getFont() override { return stack->font; } diff --git a/JuceLibraryCode/modules/juce_graphics/native/juce_android_Fonts.cpp b/JuceLibraryCode/modules/juce_graphics/native/juce_android_Fonts.cpp index 837dd6b..29702a2 100644 --- a/JuceLibraryCode/modules/juce_graphics/native/juce_android_Fonts.cpp +++ b/JuceLibraryCode/modules/juce_graphics/native/juce_android_Fonts.cpp @@ -170,11 +170,11 @@ public: heightToPointsFactor = referenceFontSize / totalHeight; } - float getAscent() const { return ascent; } - float getDescent() const { return descent; } - float getHeightToPointsFactor() const { return heightToPointsFactor; } + float getAscent() const override { return ascent; } + float getDescent() const override { return descent; } + float getHeightToPointsFactor() const override { return heightToPointsFactor; } - float getStringWidth (const String& text) + float getStringWidth (const String& text) override { JNIEnv* env = getEnv(); const int numChars = text.length(); @@ -193,7 +193,7 @@ public: return x * referenceFontToUnits; } - void getGlyphPositions (const String& text, Array& glyphs, Array& xOffsets) + void getGlyphPositions (const String& text, Array& glyphs, Array& xOffsets) override { JNIEnv* env = getEnv(); const int numChars = text.length(); @@ -218,12 +218,12 @@ public: } } - bool getOutlineForGlyph (int /*glyphNumber*/, Path& /*destPath*/) + bool getOutlineForGlyph (int /*glyphNumber*/, Path& /*destPath*/) override { return false; } - EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& t) + EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& t, float /*fontHeight*/) override { JNIEnv* env = getEnv(); diff --git a/JuceLibraryCode/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h b/JuceLibraryCode/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h index 8a027c5..bf26ce8 100644 --- a/JuceLibraryCode/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h +++ b/JuceLibraryCode/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h @@ -84,7 +84,7 @@ private: struct SavedState { SavedState(); - SavedState (const SavedState& other); + SavedState (const SavedState&); ~SavedState(); void setFill (const FillType& newFill); diff --git a/JuceLibraryCode/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm b/JuceLibraryCode/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm index 7ae0114..03e47ff 100644 --- a/JuceLibraryCode/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm +++ b/JuceLibraryCode/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm @@ -52,15 +52,19 @@ public: LowLevelGraphicsContext* createLowLevelContext() override { + sendDataChangeMessage(); return new CoreGraphicsContext (context, height, 1.0f); } - void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode) override + void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode mode) override { bitmap.data = imageData + x * pixelStride + y * lineStride; bitmap.pixelFormat = pixelFormat; bitmap.lineStride = lineStride; bitmap.pixelStride = pixelStride; + + if (mode != Image::BitmapData::readOnly) + sendDataChangeMessage(); } ImagePixelData* clone() override diff --git a/JuceLibraryCode/modules/juce_graphics/native/juce_mac_Fonts.mm b/JuceLibraryCode/modules/juce_graphics/native/juce_mac_Fonts.mm index 2dfa209..e33acea 100644 --- a/JuceLibraryCode/modules/juce_graphics/native/juce_mac_Fonts.mm +++ b/JuceLibraryCode/modules/juce_graphics/native/juce_mac_Fonts.mm @@ -488,6 +488,7 @@ public: ctFontRef (nullptr), fontHeightToPointsFactor (1.0f), renderingTransform (CGAffineTransformIdentity), + isMemoryFont (false), attributedStringAtts (nullptr), ascent (0.0f), unitsToHeightScaleFactor (0.0f) @@ -507,6 +508,7 @@ public: ctFontRef (nullptr), fontHeightToPointsFactor (1.0f), renderingTransform (CGAffineTransformIdentity), + isMemoryFont (true), attributedStringAtts (nullptr), ascent (0.0f), unitsToHeightScaleFactor (0.0f) @@ -575,11 +577,11 @@ public: CFRelease (ctFontRef); } - float getAscent() const { return ascent; } - float getDescent() const { return 1.0f - ascent; } - float getHeightToPointsFactor() const { return fontHeightToPointsFactor; } + float getAscent() const override { return ascent; } + float getDescent() const override { return 1.0f - ascent; } + float getHeightToPointsFactor() const override { return fontHeightToPointsFactor; } - float getStringWidth (const String& text) + float getStringWidth (const String& text) override { float x = 0; @@ -612,7 +614,7 @@ public: return x; } - void getGlyphPositions (const String& text, Array & resultGlyphs, Array & xOffsets) + void getGlyphPositions (const String& text, Array & resultGlyphs, Array & xOffsets) override { xOffsets.add (0); @@ -648,18 +650,7 @@ public: } } - EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform) - { - Path path; - - if (getOutlineForGlyph (glyphNumber, path) && ! path.isEmpty()) - return new EdgeTable (path.getBoundsTransformed (transform).getSmallestIntegerContainer().expanded (1, 0), - path, transform); - - return nullptr; - } - - bool getOutlineForGlyph (int glyphNumber, Path& path) + bool getOutlineForGlyph (int glyphNumber, Path& path) override { jassert (path.isEmpty()); // we might need to apply a transform to the path, so this must be empty @@ -683,6 +674,8 @@ public: float fontHeightToPointsFactor; CGAffineTransform renderingTransform; + bool isMemoryFont; + private: CFDictionaryRef attributedStringAtts; float ascent, unitsToHeightScaleFactor; @@ -712,13 +705,12 @@ private: CTFontRef getCTFontFromTypeface (const Font& f) { - if (OSXTypeface* tf = dynamic_cast (f.getTypeface())) + if (OSXTypeface* tf = dynamic_cast (f.getTypeface())) return tf->ctFontRef; return 0; } - StringArray Font::findAllTypefaceNames() { StringArray names; @@ -906,11 +898,11 @@ public: #endif - float getAscent() const { return ascent; } - float getDescent() const { return 1.0f - ascent; } - float getHeightToPointsFactor() const { return fontHeightToPointsFactor; } + float getAscent() const override { return ascent; } + float getDescent() const override { return 1.0f - ascent; } + float getHeightToPointsFactor() const override { return fontHeightToPointsFactor; } - float getStringWidth (const String& text) + float getStringWidth (const String& text) override { if (fontRef == 0 || text.isEmpty()) return 0; @@ -923,7 +915,7 @@ public: #if SUPPORT_ONLY_10_4_FONTS HeapBlock advances (length); - [nsFont getAdvancements: advances forGlyphs: reinterpret_cast (glyphs.getData()) count: length]; + [nsFont getAdvancements: advances forGlyphs: reinterpret_cast (glyphs.getData()) count: length]; for (int i = 0; i < length; ++i) x += advances[i].width; @@ -951,7 +943,7 @@ public: return x * unitsToHeightScaleFactor; } - void getGlyphPositions (const String& text, Array & resultGlyphs, Array & xOffsets) + void getGlyphPositions (const String& text, Array& resultGlyphs, Array& xOffsets) override { xOffsets.add (0); @@ -1009,18 +1001,7 @@ public: #endif } - EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform) - { - Path path; - - if (getOutlineForGlyph (glyphNumber, path) && ! path.isEmpty()) - return new EdgeTable (path.getBoundsTransformed (transform).getSmallestIntegerContainer().expanded (1, 0), - path, transform); - - return nullptr; - } - - bool getOutlineForGlyph (int glyphNumber, Path& path) + bool getOutlineForGlyph (int glyphNumber, Path& path) override { #if JUCE_IOS return false; @@ -1174,8 +1155,8 @@ private: if (rangeOffset == 0) return delta + c; - else - return getValue16 (glyphIndexes, 2 * ((rangeOffset / 2) + (c - start) - (segCount - i))); + + return getValue16 (glyphIndexes, 2 * ((rangeOffset / 2) + (c - start) - (segCount - i))); } } @@ -1293,13 +1274,33 @@ Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font) return Typeface::createSystemTypefaceFor (newFont); } +#if JUCE_CORETEXT_AVAILABLE +static bool containsNoMemoryTypefaces (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 (f->getTypeface())) + if (tf->isMemoryFont) + return false; + + return true; +} +#endif + bool TextLayout::createNativeLayout (const AttributedString& text) { #if JUCE_CORETEXT_AVAILABLE - CoreTextTypeLayout::createLayout (*this, text); - return true; - #else + // 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)) + { + CoreTextTypeLayout::createLayout (*this, text); + return true; + } + #endif + (void) text; return false; - #endif } diff --git a/JuceLibraryCode/modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp b/JuceLibraryCode/modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp index 716a450..d8ca0bd 100644 --- a/JuceLibraryCode/modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp +++ b/JuceLibraryCode/modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp @@ -63,6 +63,9 @@ namespace DirectWriteTypeLayout { TextLayout* const layout = static_cast (clientDrawingContext); + if (! (baselineOriginY >= -1.0e10f && baselineOriginY <= 1.0e10f)) + baselineOriginY = 0; // DirectWrite sometimes sends NaNs in this parameter + if (baselineOriginY != lastOriginY) { lastOriginY = baselineOriginY; @@ -73,6 +76,7 @@ namespace DirectWriteTypeLayout jassert (currentLine == layout->getNumLines()); TextLayout::Line* const newLine = new TextLayout::Line(); layout->addLine (newLine); + newLine->lineOrigin = Point (baselineOriginX, baselineOriginY); } } @@ -165,6 +169,9 @@ namespace DirectWriteTypeLayout ComSmartPtr dwFontFace; dwFont->CreateFontFace (dwFontFace.resetAndGetPointerAddress()); + if (dwFontFace == nullptr) + return 1.0f; + DWRITE_FONT_METRICS dwFontMetrics; dwFontFace->GetMetrics (&dwFontMetrics); diff --git a/JuceLibraryCode/modules/juce_graphics/native/juce_win32_DirectWriteTypeface.cpp b/JuceLibraryCode/modules/juce_graphics/native/juce_win32_DirectWriteTypeface.cpp index 8cd8ddc..74b767c 100644 --- a/JuceLibraryCode/modules/juce_graphics/native/juce_win32_DirectWriteTypeface.cpp +++ b/JuceLibraryCode/modules/juce_graphics/native/juce_win32_DirectWriteTypeface.cpp @@ -237,17 +237,6 @@ public: } } - EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform) - { - Path path; - - if (getOutlineForGlyph (glyphNumber, path) && ! path.isEmpty()) - return new EdgeTable (path.getBoundsTransformed (transform).getSmallestIntegerContainer().expanded (1, 0), - path, transform); - - return nullptr; - } - bool getOutlineForGlyph (int glyphNumber, Path& path) { jassert (path.isEmpty()); // we might need to apply a transform to the path, so this must be empty diff --git a/JuceLibraryCode/modules/juce_graphics/placement/juce_RectanglePlacement.h b/JuceLibraryCode/modules/juce_graphics/placement/juce_RectanglePlacement.h index 122b428..9341e67 100644 --- a/JuceLibraryCode/modules/juce_graphics/placement/juce_RectanglePlacement.h +++ b/JuceLibraryCode/modules/juce_graphics/placement/juce_RectanglePlacement.h @@ -45,13 +45,13 @@ public: inline RectanglePlacement() noexcept : flags (centred) {} /** Creates a copy of another RectanglePlacement object. */ - RectanglePlacement (const RectanglePlacement& other) noexcept; + RectanglePlacement (const RectanglePlacement&) noexcept; /** Copies another RectanglePlacement object. */ - RectanglePlacement& operator= (const RectanglePlacement& other) noexcept; + RectanglePlacement& operator= (const RectanglePlacement&) noexcept; - bool operator== (const RectanglePlacement& other) const noexcept; - bool operator!= (const RectanglePlacement& other) const noexcept; + bool operator== (const RectanglePlacement&) const noexcept; + bool operator!= (const RectanglePlacement&) const noexcept; //============================================================================== /** Flag values that can be combined and used in the constructor. */ diff --git a/JuceLibraryCode/modules/juce_gui_basics/application/juce_Application.cpp b/JuceLibraryCode/modules/juce_gui_basics/application/juce_Application.cpp index e96ff68..4e21873 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/application/juce_Application.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/application/juce_Application.cpp @@ -50,7 +50,7 @@ ApplicationCommandTarget* JUCEApplication::getNextCommandTarget() return nullptr; } -void JUCEApplication::getAllCommands (Array & commands) +void JUCEApplication::getAllCommands (Array& commands) { commands.add (StandardApplicationCommandIDs::quit); } diff --git a/JuceLibraryCode/modules/juce_gui_basics/application/juce_Application.h b/JuceLibraryCode/modules/juce_gui_basics/application/juce_Application.h index bd4f82c..1ffb27e 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/application/juce_Application.h +++ b/JuceLibraryCode/modules/juce_gui_basics/application/juce_Application.h @@ -176,7 +176,7 @@ public: /** @internal */ void getCommandInfo (CommandID, ApplicationCommandInfo&); /** @internal */ - void getAllCommands (Array &); + void getAllCommands (Array&); /** @internal */ bool perform (const InvocationInfo&); diff --git a/JuceLibraryCode/modules/juce_gui_basics/buttons/juce_Button.cpp b/JuceLibraryCode/modules/juce_gui_basics/buttons/juce_Button.cpp index ac93013..be7e55c 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/buttons/juce_Button.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/buttons/juce_Button.cpp @@ -572,7 +572,7 @@ void Button::clearShortcuts() bool Button::isShortcutPressed() const { - if (! isCurrentlyBlockedByAnotherModalComponent()) + if (isShowing() && ! isCurrentlyBlockedByAnotherModalComponent()) for (int i = shortcuts.size(); --i >= 0;) if (shortcuts.getReference(i).isCurrentlyDown()) return true; diff --git a/JuceLibraryCode/modules/juce_gui_basics/components/juce_Component.cpp b/JuceLibraryCode/modules/juce_gui_basics/components/juce_Component.cpp index 414dc36..7e3b9f4 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/components/juce_Component.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/components/juce_Component.cpp @@ -173,6 +173,22 @@ private: JUCE_DECLARE_NON_COPYABLE (MouseListenerList) }; +//============================================================================== +struct FocusRestorer +{ + FocusRestorer() : lastFocus (Component::getCurrentlyFocusedComponent()) {} + + ~FocusRestorer() + { + if (lastFocus != nullptr && ! lastFocus->isCurrentlyBlockedByAnotherModalComponent()) + lastFocus->grabKeyboardFocus(); + } + + WeakReference lastFocus; + + JUCE_DECLARE_NON_COPYABLE (FocusRestorer) +}; + //============================================================================== struct ScalingHelpers { @@ -2288,7 +2304,10 @@ void Component::addComponentListener (ComponentListener* const newListener) { // if component methods are being called from threads other than the message // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - CHECK_MESSAGE_MANAGER_IS_LOCKED + #if JUCE_DEBUG || JUCE_LOG_ASSERTIONS + if (getParentComponent() != nullptr) + CHECK_MESSAGE_MANAGER_IS_LOCKED; + #endif componentListeners.add (newListener); } diff --git a/JuceLibraryCode/modules/juce_gui_basics/components/juce_ModalComponentManager.cpp b/JuceLibraryCode/modules/juce_gui_basics/components/juce_ModalComponentManager.cpp index e4d8e96..00f170c 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/components/juce_ModalComponentManager.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/components/juce_ModalComponentManager.cpp @@ -63,7 +63,9 @@ public: if (isActive) { isActive = false; - ModalComponentManager::getInstance()->triggerAsyncUpdate(); + + if (ModalComponentManager* mcm = ModalComponentManager::getInstanceWithoutCreating()) + mcm->triggerAsyncUpdate(); } } @@ -83,6 +85,7 @@ ModalComponentManager::ModalComponentManager() ModalComponentManager::~ModalComponentManager() { + stack.clear(); clearSingletonInstance(); } @@ -259,7 +262,7 @@ int ModalComponentManager::runEventLoopForCurrentComponent() if (Component* currentlyModal = getModalComponent (0)) { - WeakReference prevFocused (Component::getCurrentlyFocusedComponent()); + FocusRestorer focusRestorer; bool finished = false; attachCallback (currentlyModal, new ReturnValueRetriever (returnValue, finished)); @@ -273,9 +276,6 @@ int ModalComponentManager::runEventLoopForCurrentComponent() } } JUCE_CATCH_EXCEPTION - - if (prevFocused != nullptr && ! prevFocused->isCurrentlyBlockedByAnotherModalComponent()) - prevFocused->grabKeyboardFocus(); } return returnValue; diff --git a/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_Drawable.cpp b/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_Drawable.cpp index bd7e19d..3e88318 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_Drawable.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_Drawable.cpp @@ -107,6 +107,18 @@ void Drawable::setBoundsToEnclose (const Rectangle& area) setBounds (newBounds); } +//============================================================================== +bool Drawable::replaceColour (Colour original, Colour replacement) +{ + bool changed = false; + + for (int i = getNumChildComponents(); --i >= 0;) + if (Drawable* d = dynamic_cast (getChildComponent(i))) + changed = d->replaceColour (original, replacement) || changed; + + return changed; +} + //============================================================================== void Drawable::setOriginWithOriginalSize (Point originWithinParent) { diff --git a/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_Drawable.h b/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_Drawable.h index 6a59c59..b8956d5 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_Drawable.h +++ b/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_Drawable.h @@ -175,6 +175,11 @@ public: */ virtual Rectangle getDrawableBounds() const = 0; + /** Recursively replaces a colour that might be used for filling or stroking. + return true if any instances of this colour were found. + */ + virtual bool replaceColour (Colour originalColour, Colour replacementColour); + //============================================================================== /** Internal class used to manage ValueTrees that represent Drawables. */ class ValueTreeWrapperBase diff --git a/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableComposite.h b/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableComposite.h index 5089198..1de9111 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableComposite.h +++ b/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableComposite.h @@ -40,7 +40,7 @@ public: DrawableComposite(); /** Creates a copy of a DrawableComposite. */ - DrawableComposite (const DrawableComposite& other); + DrawableComposite (const DrawableComposite&); /** Destructor. */ ~DrawableComposite(); diff --git a/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableImage.h b/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableImage.h index 2ca0a35..6089dee 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableImage.h +++ b/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableImage.h @@ -37,7 +37,7 @@ class JUCE_API DrawableImage : public Drawable public: //============================================================================== DrawableImage(); - DrawableImage (const DrawableImage& other); + DrawableImage (const DrawableImage&); /** Destructor. */ ~DrawableImage(); diff --git a/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawablePath.h b/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawablePath.h index 89a6fd3..bed3895 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawablePath.h +++ b/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawablePath.h @@ -40,7 +40,7 @@ public: //============================================================================== /** Creates a DrawablePath. */ DrawablePath(); - DrawablePath (const DrawablePath& other); + DrawablePath (const DrawablePath&); /** Destructor. */ ~DrawablePath(); diff --git a/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableRectangle.h b/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableRectangle.h index 8e9b799..9bae02e 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableRectangle.h +++ b/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableRectangle.h @@ -39,7 +39,7 @@ class JUCE_API DrawableRectangle : public DrawableShape public: //============================================================================== DrawableRectangle(); - DrawableRectangle (const DrawableRectangle& other); + DrawableRectangle (const DrawableRectangle&); /** Destructor. */ ~DrawableRectangle(); diff --git a/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableShape.cpp b/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableShape.cpp index 308ac1c..5813493 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableShape.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableShape.cpp @@ -452,3 +452,21 @@ void DrawableShape::FillAndStrokeState::setStrokeType (const PathStrokeType& new state.setProperty (capStyle, newStrokeType.getEndStyle() == PathStrokeType::butt ? "butt" : (newStrokeType.getEndStyle() == PathStrokeType::square ? "square" : "round"), undoManager); } + +static bool replaceColourInFill (DrawableShape::RelativeFillType& fill, Colour original, Colour replacement) +{ + if (fill.fill.colour == original && fill.fill.isColour()) + { + fill = FillType (replacement); + return true; + } + + return false; +} + +bool DrawableShape::replaceColour (Colour original, Colour replacement) +{ + bool changed1 = replaceColourInFill (mainFill, original, replacement); + bool changed2 = replaceColourInFill (strokeFill, original, replacement); + return changed1 || changed2; +} diff --git a/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableShape.h b/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableShape.h index 14278d2..ed893f1 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableShape.h +++ b/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableShape.h @@ -147,6 +147,8 @@ public: void paint (Graphics&) override; /** @internal */ bool hitTest (int x, int y) override; + /** @internal */ + bool replaceColour (Colour originalColour, Colour replacementColour) override; protected: //============================================================================== diff --git a/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableText.h b/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableText.h index b5e829b..ac44fb4 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableText.h +++ b/JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableText.h @@ -38,7 +38,7 @@ public: //============================================================================== /** Creates a DrawableText object. */ DrawableText(); - DrawableText (const DrawableText& other); + DrawableText (const DrawableText&); /** Destructor. */ ~DrawableText(); diff --git a/JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_FileChooser.cpp b/JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_FileChooser.cpp index 01c8b32..71c148d 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_FileChooser.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_FileChooser.cpp @@ -79,7 +79,7 @@ bool FileChooser::browseForDirectory() bool FileChooser::showDialog (const int flags, FilePreviewComponent* const previewComp) { - WeakReference previouslyFocused (Component::getCurrentlyFocusedComponent()); + FocusRestorer focusRestorer; results.clear(); @@ -127,9 +127,6 @@ bool FileChooser::showDialog (const int flags, FilePreviewComponent* const previ } } - if (previouslyFocused != nullptr) - previouslyFocused->grabKeyboardFocus(); - return results.size() > 0; } #endif diff --git a/JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_FileFilter.cpp b/JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_FileFilter.cpp deleted file mode 100644 index d72309b..0000000 --- a/JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_FileFilter.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2013 - Raw Material Software Ltd. - - Permission is granted to use this software under the terms of either: - a) the GPL v2 (or any later version) - b) the Affero GPL v3 - - Details of these licenses can be found at: www.gnu.org/licenses - - JUCE is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - ------------------------------------------------------------------------------ - - To release a closed-source product which uses JUCE, commercial licenses are - available: visit www.juce.com for more information. - - ============================================================================== -*/ - -FileFilter::FileFilter (const String& filterDescription) - : description (filterDescription) -{ -} - -FileFilter::~FileFilter() -{ -} - -const String& FileFilter::getDescription() const noexcept -{ - return description; -} diff --git a/JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_FileFilter.h b/JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_FileFilter.h deleted file mode 100644 index 8a87a42..0000000 --- a/JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_FileFilter.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2013 - Raw Material Software Ltd. - - Permission is granted to use this software under the terms of either: - a) the GPL v2 (or any later version) - b) the Affero GPL v3 - - Details of these licenses can be found at: www.gnu.org/licenses - - JUCE is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - ------------------------------------------------------------------------------ - - To release a closed-source product which uses JUCE, commercial licenses are - available: visit www.juce.com for more information. - - ============================================================================== -*/ - -#ifndef JUCE_FILEFILTER_H_INCLUDED -#define JUCE_FILEFILTER_H_INCLUDED - - -//============================================================================== -/** - Interface for deciding which files are suitable for something. - - For example, this is used by DirectoryContentsList to select which files - go into the list. - - @see WildcardFileFilter, DirectoryContentsList, FileListComponent, FileBrowserComponent -*/ -class JUCE_API FileFilter -{ -public: - //============================================================================== - /** Creates a filter with the given description. - - The description can be returned later with the getDescription() method. - */ - FileFilter (const String& filterDescription); - - /** Destructor. */ - virtual ~FileFilter(); - - //============================================================================== - /** Returns the description that the filter was created with. */ - const String& getDescription() const noexcept; - - //============================================================================== - /** Should return true if this file is suitable for inclusion in whatever context - the object is being used. - */ - virtual bool isFileSuitable (const File& file) const = 0; - - /** Should return true if this directory is suitable for inclusion in whatever context - the object is being used. - */ - virtual bool isDirectorySuitable (const File& file) const = 0; - - -protected: - //============================================================================== - String description; -}; - - -#endif // JUCE_FILEFILTER_H_INCLUDED diff --git a/JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_FileListComponent.cpp b/JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_FileListComponent.cpp index 21a64ea..3125267 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_FileListComponent.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_FileListComponent.cpp @@ -91,8 +91,8 @@ class FileListComponent::ItemComponent : public Component, private AsyncUpdater { public: - ItemComponent (FileListComponent& owner_, TimeSliceThread& thread_) - : owner (owner_), thread (thread_), index (0), highlighted (false) + ItemComponent (FileListComponent& fc, TimeSliceThread& t) + : owner (fc), thread (t), index (0), highlighted (false) { } @@ -113,7 +113,7 @@ public: void mouseDown (const MouseEvent& e) override { - owner.selectRowsBasedOnModifierKeys (index, e.mods, false); + owner.selectRowsBasedOnModifierKeys (index, e.mods, true); owner.sendMouseClickMessage (file, e); } @@ -227,9 +227,9 @@ void FileListComponent::paintListBoxItem (int, Graphics&, int, int, bool) Component* FileListComponent::refreshComponentForRow (int row, bool isSelected, Component* existingComponentToUpdate) { - jassert (existingComponentToUpdate == nullptr || dynamic_cast (existingComponentToUpdate) != nullptr); + jassert (existingComponentToUpdate == nullptr || dynamic_cast (existingComponentToUpdate) != nullptr); - ItemComponent* comp = static_cast (existingComponentToUpdate); + ItemComponent* comp = static_cast (existingComponentToUpdate); if (comp == nullptr) comp = new ItemComponent (*this, fileList.getTimeSliceThread()); diff --git a/JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_WildcardFileFilter.cpp b/JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_WildcardFileFilter.cpp deleted file mode 100644 index a288507..0000000 --- a/JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_WildcardFileFilter.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2013 - Raw Material Software Ltd. - - Permission is granted to use this software under the terms of either: - a) the GPL v2 (or any later version) - b) the Affero GPL v3 - - Details of these licenses can be found at: www.gnu.org/licenses - - JUCE is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - ------------------------------------------------------------------------------ - - To release a closed-source product which uses JUCE, commercial licenses are - available: visit www.juce.com for more information. - - ============================================================================== -*/ - -WildcardFileFilter::WildcardFileFilter (const String& fileWildcardPatterns, - const String& directoryWildcardPatterns, - const String& desc) - : FileFilter (desc.isEmpty() ? fileWildcardPatterns - : (desc + " (" + fileWildcardPatterns + ")")) -{ - parse (fileWildcardPatterns, fileWildcards); - parse (directoryWildcardPatterns, directoryWildcards); -} - -WildcardFileFilter::~WildcardFileFilter() -{ -} - -bool WildcardFileFilter::isFileSuitable (const File& file) const -{ - return match (file, fileWildcards); -} - -bool WildcardFileFilter::isDirectorySuitable (const File& file) const -{ - return match (file, directoryWildcards); -} - -//============================================================================== -void WildcardFileFilter::parse (const String& pattern, StringArray& result) -{ - result.addTokens (pattern.toLowerCase(), ";,", "\"'"); - - result.trim(); - result.removeEmptyStrings(); - - // special case for *.*, because people use it to mean "any file", but it - // would actually ignore files with no extension. - for (int i = result.size(); --i >= 0;) - if (result[i] == "*.*") - result.set (i, "*"); -} - -bool WildcardFileFilter::match (const File& file, const StringArray& wildcards) -{ - const String filename (file.getFileName()); - - for (int i = wildcards.size(); --i >= 0;) - if (filename.matchesWildcard (wildcards[i], true)) - return true; - - return false; -} diff --git a/JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_WildcardFileFilter.h b/JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_WildcardFileFilter.h deleted file mode 100644 index 045c753..0000000 --- a/JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_WildcardFileFilter.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2013 - Raw Material Software Ltd. - - Permission is granted to use this software under the terms of either: - a) the GPL v2 (or any later version) - b) the Affero GPL v3 - - Details of these licenses can be found at: www.gnu.org/licenses - - JUCE is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - ------------------------------------------------------------------------------ - - To release a closed-source product which uses JUCE, commercial licenses are - available: visit www.juce.com for more information. - - ============================================================================== -*/ - -#ifndef JUCE_WILDCARDFILEFILTER_H_INCLUDED -#define JUCE_WILDCARDFILEFILTER_H_INCLUDED - - -//============================================================================== -/** - A type of FileFilter that works by wildcard pattern matching. - - This filter only allows files that match one of the specified patterns, but - allows all directories through. - - @see FileFilter, DirectoryContentsList, FileListComponent, FileBrowserComponent -*/ -class JUCE_API WildcardFileFilter : public FileFilter -{ -public: - //============================================================================== - /** - Creates a wildcard filter for one or more patterns. - - The wildcardPatterns parameter is a comma or semicolon-delimited set of - patterns, e.g. "*.wav;*.aiff" would look for files ending in either .wav - or .aiff. - - Passing an empty string as a pattern will fail to match anything, so by leaving - either the file or directory pattern parameter empty means you can control - whether files or directories are found. - - The description is a name to show the user in a list of possible patterns, so - for the wav/aiff example, your description might be "audio files". - */ - WildcardFileFilter (const String& fileWildcardPatterns, - const String& directoryWildcardPatterns, - const String& description); - - /** Destructor. */ - ~WildcardFileFilter(); - - //============================================================================== - /** Returns true if the filename matches one of the patterns specified. */ - bool isFileSuitable (const File& file) const; - - /** This always returns true. */ - bool isDirectorySuitable (const File& file) const; - -private: - //============================================================================== - StringArray fileWildcards, directoryWildcards; - - static void parse (const String& pattern, StringArray& result); - static bool match (const File& file, const StringArray& wildcards); - - JUCE_LEAK_DETECTOR (WildcardFileFilter) -}; - - - -#endif // JUCE_WILDCARDFILEFILTER_H_INCLUDED diff --git a/JuceLibraryCode/modules/juce_gui_basics/juce_gui_basics.cpp b/JuceLibraryCode/modules/juce_gui_basics/juce_gui_basics.cpp index a66d116..71f0554 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/juce_gui_basics.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/juce_gui_basics.cpp @@ -175,13 +175,11 @@ extern bool juce_areThereAnyAlwaysOnTopWindows(); #include "filebrowser/juce_FileBrowserComponent.cpp" #include "filebrowser/juce_FileChooser.cpp" #include "filebrowser/juce_FileChooserDialogBox.cpp" -#include "filebrowser/juce_FileFilter.cpp" #include "filebrowser/juce_FileListComponent.cpp" #include "filebrowser/juce_FilenameComponent.cpp" #include "filebrowser/juce_FileSearchPathListComponent.cpp" #include "filebrowser/juce_FileTreeComponent.cpp" #include "filebrowser/juce_ImagePreviewComponent.cpp" -#include "filebrowser/juce_WildcardFileFilter.cpp" #include "layout/juce_ComponentAnimator.cpp" #include "layout/juce_ComponentBoundsConstrainer.cpp" #include "layout/juce_ComponentBuilder.cpp" diff --git a/JuceLibraryCode/modules/juce_gui_basics/juce_gui_basics.h b/JuceLibraryCode/modules/juce_gui_basics/juce_gui_basics.h index 6b20f14..dedd3a0 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/juce_gui_basics.h +++ b/JuceLibraryCode/modules/juce_gui_basics/juce_gui_basics.h @@ -216,8 +216,6 @@ class DrawableButton; #include "windows/juce_ThreadWithProgressWindow.h" #include "windows/juce_TooltipWindow.h" #include "layout/juce_MultiDocumentPanel.h" -#include "filebrowser/juce_FileFilter.h" -#include "filebrowser/juce_WildcardFileFilter.h" #include "filebrowser/juce_FileBrowserListener.h" #include "filebrowser/juce_DirectoryContentsList.h" #include "filebrowser/juce_DirectoryContentsDisplayComponent.h" diff --git a/JuceLibraryCode/modules/juce_gui_basics/juce_module_info b/JuceLibraryCode/modules/juce_gui_basics/juce_module_info index a66035f..cd4d913 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/juce_module_info +++ b/JuceLibraryCode/modules/juce_gui_basics/juce_module_info @@ -1,7 +1,7 @@ { "id": "juce_gui_basics", "name": "JUCE GUI core classes", - "version": "3.0.1", + "version": "3.0.3", "description": "Basic user-interface components and related classes.", "website": "http://www.juce.com/juce", "license": "GPL/Commercial", diff --git a/JuceLibraryCode/modules/juce_gui_basics/layout/juce_AnimatedPositionBehaviours.h b/JuceLibraryCode/modules/juce_gui_basics/layout/juce_AnimatedPositionBehaviours.h index 503944e..026f36e 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/layout/juce_AnimatedPositionBehaviours.h +++ b/JuceLibraryCode/modules/juce_gui_basics/layout/juce_AnimatedPositionBehaviours.h @@ -129,7 +129,9 @@ namespace AnimatedPositionBehaviours const double snapSpeed = 10.0; const double velocity = (targetSnapPosition - oldPos) * snapSpeed; - return oldPos + velocity * elapsedSeconds; + const double newPos = oldPos + velocity * elapsedSeconds; + + return isStopped (newPos) ? targetSnapPosition : newPos; } /** Called by the AnimatedPosition class to check whether the object diff --git a/JuceLibraryCode/modules/juce_gui_basics/layout/juce_Viewport.h b/JuceLibraryCode/modules/juce_gui_basics/layout/juce_Viewport.h index 94404a6..f67b6b0 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/layout/juce_Viewport.h +++ b/JuceLibraryCode/modules/juce_gui_basics/layout/juce_Viewport.h @@ -131,10 +131,12 @@ public: */ bool autoScroll (int mouseX, int mouseY, int distanceFromEdge, int maximumSpeed); - /** Returns the position within the child component of the top-left of its visible area. - */ + /** Returns the position within the child component of the top-left of its visible area. */ Point getViewPosition() const noexcept { return lastVisibleArea.getPosition(); } + /** Returns the visible area of the child component, relative to its top-left */ + Rectangle getViewArea() const noexcept { return lastVisibleArea; } + /** Returns the position within the child component of the top-left of its visible area. @see getViewWidth, setViewPosition */ diff --git a/JuceLibraryCode/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp b/JuceLibraryCode/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp index bf6ebe8..85045f7 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp @@ -104,6 +104,9 @@ LookAndFeel_V2::LookAndFeel_V2() ComboBox::backgroundColourId, 0xffffffff, ComboBox::arrowColourId, 0x99000000, + PropertyComponent::backgroundColourId, 0x66ffffff, + PropertyComponent::labelTextColourId, 0xff000000, + TextPropertyComponent::backgroundColourId, 0xffffffff, TextPropertyComponent::textColourId, 0xff000000, TextPropertyComponent::outlineColourId, standardOutlineColour, @@ -175,6 +178,7 @@ LookAndFeel_V2::LookAndFeel_V2() 0x1005005, /*MidiKeyboardComponent::textLabelColourId*/ 0xff000000, 0x1005006, /*MidiKeyboardComponent::upDownButtonBackgroundColourId*/ 0xffd3d3d3, 0x1005007, /*MidiKeyboardComponent::upDownButtonArrowColourId*/ 0xff000000, + 0x1005008, /*MidiKeyboardComponent::shadowColourId*/ 0x4c000000, 0x1004500, /*CodeEditorComponent::backgroundColourId*/ 0xffffffff, 0x1004502, /*CodeEditorComponent::highlightColourId*/ textHighlightColour, @@ -1455,6 +1459,8 @@ Label* LookAndFeel_V2::createSliderTextBox (Slider& slider) l->setColour (TextEditor::outlineColourId, slider.findColour (Slider::textBoxOutlineColourId)); + l->setColour (TextEditor::highlightColourId, slider.findColour (Slider::textBoxHighlightColourId)); + return l; } @@ -2301,20 +2307,16 @@ void LookAndFeel_V2::drawPropertyPanelSectionHeader (Graphics& g, const String& g.drawText (name, textX, 0, width - textX - 4, height, Justification::centredLeft, true); } -void LookAndFeel_V2::drawPropertyComponentBackground (Graphics& g, int width, int height, - PropertyComponent&) +void LookAndFeel_V2::drawPropertyComponentBackground (Graphics& g, int width, int height, PropertyComponent& component) { - g.setColour (Colour (0x66ffffff)); + g.setColour (component.findColour (PropertyComponent::backgroundColourId)); g.fillRect (0, 0, width, height - 1); } -void LookAndFeel_V2::drawPropertyComponentLabel (Graphics& g, int, int height, - PropertyComponent& component) +void LookAndFeel_V2::drawPropertyComponentLabel (Graphics& g, int, int height, PropertyComponent& component) { - g.setColour (Colours::black); - - if (! component.isEnabled()) - g.setOpacity (0.6f); + g.setColour (component.findColour (PropertyComponent::labelTextColourId) + .withMultipliedAlpha (component.isEnabled() ? 1.0f : 0.6f)); g.setFont (jmin (height, 24) * 0.65f); diff --git a/JuceLibraryCode/modules/juce_gui_basics/misc/juce_DropShadower.cpp b/JuceLibraryCode/modules/juce_gui_basics/misc/juce_DropShadower.cpp index 871cbc1..c6d0d77 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/misc/juce_DropShadower.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/misc/juce_DropShadower.cpp @@ -55,6 +55,14 @@ public: repaint(); // (needed for correct repainting) } + float getDesktopScaleFactor() const override + { + if (target != nullptr) + return target->getDesktopScaleFactor(); + + return Component::getDesktopScaleFactor(); + } + private: WeakReference target; DropShadow shadow; diff --git a/JuceLibraryCode/modules/juce_gui_basics/mouse/juce_ComponentDragger.h b/JuceLibraryCode/modules/juce_gui_basics/mouse/juce_ComponentDragger.h index f6c3147..0bb5cbe 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/mouse/juce_ComponentDragger.h +++ b/JuceLibraryCode/modules/juce_gui_basics/mouse/juce_ComponentDragger.h @@ -75,10 +75,8 @@ public: /** Call this from your mouseDrag() callback to move the component. - This will move the component, but will first check the validity of the - component's new position using the checkPosition() method, which you - can override if you need to enforce special positioning limits on the - component. + This will move the component, using the given constrainer object to check + the new position. @param componentToDrag the component that you want to drag @param e the current mouse-drag event diff --git a/JuceLibraryCode/modules/juce_gui_basics/native/juce_linux_FileChooser.cpp b/JuceLibraryCode/modules/juce_gui_basics/native/juce_linux_FileChooser.cpp index 5d8028a..d7a5083 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/native/juce_linux_FileChooser.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/native/juce_linux_FileChooser.cpp @@ -41,7 +41,7 @@ bool FileChooser::isPlatformDialogAvailable() void FileChooser::showPlatformDialog (Array& results, const String& title, const File& file, - const String& /* filters */, + const String& filters, bool isDirectory, bool /* selectsFiles */, bool isSave, @@ -80,10 +80,14 @@ void FileChooser::showPlatformDialog (Array& results, String startPath; - if (file.exists() || file.getParentDirectory().exists()) + if (file.exists()) { startPath = file.getFullPathName(); } + else if (file.getParentDirectory().exists()) + { + startPath = file.getParentDirectory().getFullPathName(); + } else { startPath = File::getSpecialLocation (File::userHomeDirectory).getFullPathName(); @@ -93,6 +97,8 @@ void FileChooser::showPlatformDialog (Array& results, } args.add (startPath); + args.add (filters.replaceCharacter (';', ' ')); + args.add ("2>/dev/null"); } else { diff --git a/JuceLibraryCode/modules/juce_gui_basics/native/juce_linux_Windowing.cpp b/JuceLibraryCode/modules/juce_gui_basics/native/juce_linux_Windowing.cpp index 5ab5c4d..3a8ddfa 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/native/juce_linux_Windowing.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/native/juce_linux_Windowing.cpp @@ -617,15 +617,19 @@ public: LowLevelGraphicsContext* createLowLevelContext() override { + sendDataChangeMessage(); return new LowLevelGraphicsSoftwareRenderer (Image (this)); } - void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode) override + void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode mode) override { bitmap.data = imageData + x * pixelStride + y * lineStride; bitmap.pixelFormat = pixelFormat; bitmap.lineStride = lineStride; bitmap.pixelStride = pixelStride; + + if (mode != Image::BitmapData::readOnly) + sendDataChangeMessage(); } ImagePixelData* clone() override @@ -1364,7 +1368,7 @@ public: const ModifierKeys oldMods (currentModifiers); bool keyPressed = false; - if ((sym & 0xff00) == 0xff00) + if ((sym & 0xff00) == 0xff00 || sym == XK_ISO_Left_Tab) { switch (sym) // Translate keypad { diff --git a/JuceLibraryCode/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm b/JuceLibraryCode/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm index 54bce81..94eed9f 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm +++ b/JuceLibraryCode/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm @@ -378,6 +378,16 @@ public: return fullScreen; } + bool isKioskMode() const override + { + #if defined (MAC_OS_X_VERSION_10_7) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 + if (hasNativeTitleBar() && ([window styleMask] & NSFullScreenWindowMask) != 0) + return true; + #endif + + return ComponentPeer::isKioskMode(); + } + bool contains (Point localPos, bool trueIfInAChildWindow) const override { NSRect frameRect = [view frame]; diff --git a/JuceLibraryCode/modules/juce_gui_basics/native/juce_win32_FileChooser.cpp b/JuceLibraryCode/modules/juce_gui_basics/native/juce_win32_FileChooser.cpp index 930bf55..f3a26b5 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/native/juce_win32_FileChooser.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/native/juce_win32_FileChooser.cpp @@ -198,7 +198,7 @@ void FileChooser::showPlatformDialog (Array& results, const String& title_ } else { - DWORD flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR | OFN_HIDEREADONLY; + DWORD flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_ENABLESIZING; if (warnAboutOverwritingExistingFiles) flags |= OFN_OVERWRITEPROMPT; diff --git a/JuceLibraryCode/modules/juce_gui_basics/native/juce_win32_Windowing.cpp b/JuceLibraryCode/modules/juce_gui_basics/native/juce_win32_Windowing.cpp index aa3e096..9b36820 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/native/juce_win32_Windowing.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/native/juce_win32_Windowing.cpp @@ -328,15 +328,19 @@ public: LowLevelGraphicsContext* createLowLevelContext() override { + sendDataChangeMessage(); return new LowLevelGraphicsSoftwareRenderer (Image (this)); } - void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode) override + void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode mode) override { bitmap.data = imageData + x * pixelStride + y * lineStride; bitmap.pixelFormat = pixelFormat; bitmap.lineStride = lineStride; bitmap.pixelStride = pixelStride; + + if (mode != Image::BitmapData::readOnly) + sendDataChangeMessage(); } ImagePixelData* clone() override @@ -3169,15 +3173,30 @@ String SystemClipboard::getTextFromClipboard() //============================================================================== void Desktop::setKioskComponent (Component* kioskModeComponent, bool enableOrDisable, bool /*allowMenusAndBars*/) { + if (TopLevelWindow* tlw = dynamic_cast (kioskModeComponent)) + tlw->setUsingNativeTitleBar (! enableOrDisable); + if (enableOrDisable) kioskModeComponent->setBounds (getDisplays().getMainDisplay().totalArea); } //============================================================================== -static BOOL CALLBACK enumMonitorsProc (HMONITOR, HDC, LPRECT r, LPARAM userInfo) +struct MonitorInfo +{ + MonitorInfo (Rectangle rect, bool main) noexcept : isMain (main), bounds (rect) {} + + Rectangle bounds; + bool isMain; +}; + +static BOOL CALLBACK enumMonitorsProc (HMONITOR hm, HDC, LPRECT r, LPARAM userInfo) { - Array >* const monitorCoords = (Array >*) userInfo; - monitorCoords->add (rectangleFromRECT (*r)); + MONITORINFO info = { 0 }; + info.cbSize = sizeof (info); + GetMonitorInfo (hm, &info); + const bool isMain = (info.dwFlags & 1 /* MONITORINFOF_PRIMARY */) != 0; + ((Array*) userInfo)->add (MonitorInfo (rectangleFromRECT (*r), isMain)); + return TRUE; } @@ -3185,17 +3204,17 @@ void Desktop::Displays::findDisplays (float masterScale) { setDPIAwareness(); - Array > monitors; + Array monitors; EnumDisplayMonitors (0, 0, &enumMonitorsProc, (LPARAM) &monitors); + if (monitors.size() == 0) + monitors.add (MonitorInfo (rectangleFromRECT (getWindowRect (GetDesktopWindow())), true)); + // make sure the first in the list is the main monitor for (int i = 1; i < monitors.size(); ++i) - if (monitors.getReference(i).getPosition().isOrigin()) + if (monitors.getReference(i).isMain) monitors.swap (i, 0); - if (monitors.size() == 0) - monitors.add (rectangleFromRECT (getWindowRect (GetDesktopWindow()))); - RECT workArea; SystemParametersInfo (SPI_GETWORKAREA, 0, &workArea, 0); @@ -3204,12 +3223,12 @@ void Desktop::Displays::findDisplays (float masterScale) for (int i = 0; i < monitors.size(); ++i) { Display d; - d.userArea = d.totalArea = monitors.getReference(i) / masterScale; - d.isMain = (i == 0); - d.scale = masterScale; - d.dpi = dpi; + d.userArea = d.totalArea = monitors.getReference(i).bounds / masterScale; + d.isMain = monitors.getReference(i).isMain; + d.scale = masterScale; + d.dpi = dpi; - if (i == 0) + if (d.isMain) d.userArea = d.userArea.getIntersection (rectangleFromRECT (workArea) / masterScale); displays.add (d); diff --git a/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_MarkerList.h b/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_MarkerList.h index 348c1b8..05131e4 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_MarkerList.h +++ b/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_MarkerList.h @@ -40,9 +40,9 @@ public: /** Creates an empty marker list. */ MarkerList(); /** Creates a copy of another marker list. */ - MarkerList (const MarkerList& other); + MarkerList (const MarkerList&); /** Copies another marker list to this one. */ - MarkerList& operator= (const MarkerList& other); + MarkerList& operator= (const MarkerList&); /** Destructor. */ ~MarkerList(); @@ -52,7 +52,7 @@ public: { public: /** Creates a copy of another Marker. */ - Marker (const Marker& other); + Marker (const Marker&); /** Creates a Marker with a given name and position. */ Marker (const String& name, const RelativeCoordinate& position); @@ -110,9 +110,9 @@ public: void removeMarker (const String& name); /** Returns true if all the markers in these two lists match exactly. */ - bool operator== (const MarkerList& other) const noexcept; + bool operator== (const MarkerList&) const noexcept; /** Returns true if not all the markers in these two lists match exactly. */ - bool operator!= (const MarkerList& other) const noexcept; + bool operator!= (const MarkerList&) const noexcept; //============================================================================== /** diff --git a/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativeCoordinate.h b/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativeCoordinate.h index 2e62fb0..c1f4eb4 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativeCoordinate.h +++ b/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativeCoordinate.h @@ -39,12 +39,12 @@ public: /** Creates a zero coordinate. */ RelativeCoordinate(); RelativeCoordinate (const Expression& expression); - RelativeCoordinate (const RelativeCoordinate& other); - RelativeCoordinate& operator= (const RelativeCoordinate& other); + RelativeCoordinate (const RelativeCoordinate&); + RelativeCoordinate& operator= (const RelativeCoordinate&); #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS - RelativeCoordinate (RelativeCoordinate&& other) noexcept; - RelativeCoordinate& operator= (RelativeCoordinate&& other) noexcept; + RelativeCoordinate (RelativeCoordinate&&) noexcept; + RelativeCoordinate& operator= (RelativeCoordinate&&) noexcept; #endif /** Creates an absolute position from the parent origin on either the X or Y axis. @@ -63,8 +63,8 @@ public: /** Destructor. */ ~RelativeCoordinate(); - bool operator== (const RelativeCoordinate& other) const noexcept; - bool operator!= (const RelativeCoordinate& other) const noexcept; + bool operator== (const RelativeCoordinate&) const noexcept; + bool operator!= (const RelativeCoordinate&) const noexcept; //============================================================================== /** Calculates the absolute position of this coordinate. diff --git a/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativeCoordinatePositioner.cpp b/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativeCoordinatePositioner.cpp index b8de9af..589eb26 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativeCoordinatePositioner.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativeCoordinatePositioner.cpp @@ -27,7 +27,7 @@ class MarkerListScope : public Expression::Scope public: MarkerListScope (Component& comp) : component (comp) {} - Expression getSymbolValue (const String& symbol) const + Expression getSymbolValue (const String& symbol) const override { switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol)) { @@ -44,7 +44,7 @@ public: return Expression::Scope::getSymbolValue (symbol); } - void visitRelativeScope (const String& scopeName, Visitor& visitor) const + void visitRelativeScope (const String& scopeName, Visitor& visitor) const override { if (scopeName == RelativeCoordinate::Strings::parent) { @@ -58,7 +58,7 @@ public: Expression::Scope::visitRelativeScope (scopeName, visitor); } - String getScopeUID() const + String getScopeUID() const override { return String::toHexString ((pointer_sized_int) (void*) &component) + "m"; } @@ -150,12 +150,12 @@ Component* RelativeCoordinatePositionerBase::ComponentScope::findSiblingComponen class RelativeCoordinatePositionerBase::DependencyFinderScope : public ComponentScope { public: - DependencyFinderScope (Component& comp, RelativeCoordinatePositionerBase& positioner_, bool& ok_) - : ComponentScope (comp), positioner (positioner_), ok (ok_) + DependencyFinderScope (Component& comp, RelativeCoordinatePositionerBase& p, bool& result) + : ComponentScope (comp), positioner (p), ok (result) { } - Expression getSymbolValue (const String& symbol) const + Expression getSymbolValue (const String& symbol) const override { switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol)) { @@ -193,7 +193,7 @@ public: return ComponentScope::getSymbolValue (symbol); } - void visitRelativeScope (const String& scopeName, Visitor& visitor) const + void visitRelativeScope (const String& scopeName, Visitor& visitor) const override { if (Component* const targetComp = (scopeName == RelativeCoordinate::Strings::parent) ? component.getParentComponent() diff --git a/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativeParallelogram.h b/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativeParallelogram.h index 00a3555..ee426d2 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativeParallelogram.h +++ b/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativeParallelogram.h @@ -50,8 +50,8 @@ public: AffineTransform resetToPerpendicular (Expression::Scope* scope); bool isDynamic() const; - bool operator== (const RelativeParallelogram& other) const noexcept; - bool operator!= (const RelativeParallelogram& other) const noexcept; + bool operator== (const RelativeParallelogram&) const noexcept; + bool operator!= (const RelativeParallelogram&) const noexcept; static Point getInternalCoordForPoint (const Point* parallelogramCorners, Point point) noexcept; static Point getPointForInternalCoord (const Point* parallelogramCorners, Point internalPoint) noexcept; diff --git a/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativePoint.h b/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativePoint.h index 78c971a..43f7c44 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativePoint.h +++ b/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativePoint.h @@ -54,8 +54,8 @@ public: */ RelativePoint (const String& stringVersion); - bool operator== (const RelativePoint& other) const noexcept; - bool operator!= (const RelativePoint& other) const noexcept; + bool operator== (const RelativePoint&) const noexcept; + bool operator!= (const RelativePoint&) const noexcept; /** Calculates the absolute position of this point. diff --git a/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativePointPath.h b/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativePointPath.h index 8514ec2..d705b44 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativePointPath.h +++ b/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativePointPath.h @@ -40,12 +40,12 @@ class JUCE_API RelativePointPath public: //============================================================================== RelativePointPath(); - RelativePointPath (const RelativePointPath& other); + RelativePointPath (const RelativePointPath&); explicit RelativePointPath (const Path& path); ~RelativePointPath(); - bool operator== (const RelativePointPath& other) const noexcept; - bool operator!= (const RelativePointPath& other) const noexcept; + bool operator== (const RelativePointPath&) const noexcept; + bool operator!= (const RelativePointPath&) const noexcept; //============================================================================== /** Resolves this points in this path and adds them to a normal Path object. */ @@ -55,7 +55,7 @@ public: bool containsAnyDynamicPoints() const; /** Quickly swaps the contents of this path with another. */ - void swapWith (RelativePointPath& other) noexcept; + void swapWith (RelativePointPath&) noexcept; //============================================================================== /** The types of element that may be contained in this path. diff --git a/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativeRectangle.h b/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativeRectangle.h index 5d210b8..b8afbe0 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativeRectangle.h +++ b/JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativeRectangle.h @@ -56,8 +56,8 @@ public: */ explicit RelativeRectangle (const String& stringVersion); - bool operator== (const RelativeRectangle& other) const noexcept; - bool operator!= (const RelativeRectangle& other) const noexcept; + bool operator== (const RelativeRectangle&) const noexcept; + bool operator!= (const RelativeRectangle&) const noexcept; //============================================================================== /** Calculates the absolute position of this rectangle. diff --git a/JuceLibraryCode/modules/juce_gui_basics/properties/juce_PropertyComponent.h b/JuceLibraryCode/modules/juce_gui_basics/properties/juce_PropertyComponent.h index de45f32..2fd3d7a 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/properties/juce_PropertyComponent.h +++ b/JuceLibraryCode/modules/juce_gui_basics/properties/juce_PropertyComponent.h @@ -102,6 +102,22 @@ public: /** By default, this just repaints the component. */ void enablementChanged() override; + //============================================================================== + /** A set of colour IDs to use to change the colour of various aspects of the combo box. + + These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() + methods. + + To change the colours of the menu that pops up + + @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + */ + enum ColourIds + { + backgroundColourId = 0x1008300, /**< The background colour to fill the component with. */ + labelTextColourId = 0x1008301, /**< The colour for the property's label text. */ + }; + //============================================================================== /** This abstract base class is implemented by LookAndFeel classes. */ struct JUCE_API LookAndFeelMethods diff --git a/JuceLibraryCode/modules/juce_gui_basics/widgets/juce_TextEditor.cpp b/JuceLibraryCode/modules/juce_gui_basics/widgets/juce_TextEditor.cpp index b66cd43..abbc102 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/widgets/juce_TextEditor.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/widgets/juce_TextEditor.cpp @@ -53,6 +53,8 @@ struct TextAtom return String::repeatedString (String::charToString (passwordCharacter), numChars); } + + JUCE_LEAK_DETECTOR (TextAtom) }; //============================================================================== @@ -60,7 +62,7 @@ struct TextAtom class TextEditor::UniformTextSection { public: - UniformTextSection (const String& text, const Font& f, const Colour col, const juce_wchar passwordChar) + UniformTextSection (const String& text, const Font& f, Colour col, juce_wchar passwordChar) : font (f), colour (col) { initialiseAtoms (text, passwordChar); @@ -69,23 +71,10 @@ public: UniformTextSection (const UniformTextSection& other) : font (other.font), colour (other.colour) { - atoms.ensureStorageAllocated (other.atoms.size()); - - for (int i = 0; i < other.atoms.size(); ++i) - atoms.add (new TextAtom (*other.atoms.getUnchecked(i))); - } - - ~UniformTextSection() {} // (no need to delete the atoms, as they're explicitly deleted by the caller) - - void clear() - { - for (int i = atoms.size(); --i >= 0;) - delete atoms.getUnchecked (i); - - atoms.clear(); + atoms.addCopiesOf (other.atoms); } - void append (const UniformTextSection& other, const juce_wchar passwordChar) + void append (UniformTextSection& other, const juce_wchar passwordChar) { if (other.atoms.size() > 0) { @@ -115,6 +104,8 @@ public: atoms.add (other.atoms.getUnchecked(i)); ++i; } + + other.atoms.clear (false); } } @@ -134,9 +125,7 @@ public: for (int j = i; j < atoms.size(); ++j) section2->atoms.add (atoms.getUnchecked (j)); - for (int j = atoms.size(); --j >= i;) - atoms.remove (j); - + atoms.removeRange (i, atoms.size(), false); break; } else if (indexToBreakAt >= index && indexToBreakAt < nextIndex) @@ -156,9 +145,7 @@ public: for (int j = i + 1; j < atoms.size(); ++j) section2->atoms.add (atoms.getUnchecked (j)); - for (int j = atoms.size(); --j > i;) - atoms.remove (j); - + atoms.removeRange (i + 1, atoms.size(), false); break; } @@ -224,7 +211,7 @@ public: //============================================================================== Font font; Colour colour; - Array atoms; + OwnedArray atoms; private: void initialiseAtoms (const String& textToParse, const juce_wchar passwordChar) @@ -274,16 +261,15 @@ private: } } - TextAtom* const atom = new TextAtom(); + TextAtom* const atom = atoms.add (new TextAtom()); + atom->atomText = String (start, numChars); atom->width = font.getStringWidthFloat (atom->getText (passwordChar)); atom->numChars = (uint16) numChars; - - atoms.add (atom); } } - UniformTextSection& operator= (const UniformTextSection& other); + UniformTextSection& operator= (const UniformTextSection&); JUCE_LEAK_DETECTOR (UniformTextSection) }; @@ -291,7 +277,7 @@ private: class TextEditor::Iterator { public: - Iterator (const Array & sectionList, + Iterator (const OwnedArray& sectionList, const float wrapWidth, const juce_wchar passwordChar) : indexInText (0), @@ -685,7 +671,7 @@ public: const UniformTextSection* currentSection; private: - const Array & sections; + const OwnedArray& sections; int sectionIndex, atomIndex; const float wordWrapWidth; const juce_wchar passwordCharacter; @@ -772,22 +758,13 @@ public: const Range rangeToRemove, const int oldCaret, const int newCaret, - const Array & oldSections) + const Array& oldSections) : owner (ed), range (rangeToRemove), oldCaretPos (oldCaret), - newCaretPos (newCaret), - removedSections (oldSections) + newCaretPos (newCaret) { - } - - ~RemoveAction() - { - for (int i = removedSections.size(); --i >= 0;) - { - ScopedPointer section (removedSections.getUnchecked (i)); - section->clear(); - } + removedSections.addArray (oldSections); } bool perform() @@ -816,7 +793,7 @@ private: TextEditor& owner; const Range range; const int oldCaretPos, newCaretPos; - Array removedSections; + OwnedArray removedSections; JUCE_DECLARE_NON_COPYABLE (RemoveAction) }; @@ -966,7 +943,7 @@ TextEditor::~TextEditor() textValue.removeListener (textHolder); textValue.referTo (Value()); - clearInternal (0); + viewport = nullptr; textHolder = nullptr; } @@ -1183,7 +1160,7 @@ void TextEditor::setScrollBarThickness (const int newThicknessPixels) //============================================================================== void TextEditor::clear() { - clearInternal (0); + clearInternal (nullptr); updateTextHolderSize(); undoManager.clearUndoHistory(); } @@ -1200,7 +1177,7 @@ void TextEditor::setText (const String& newText, int oldCursorPos = caretPosition; const bool cursorWasAtEnd = oldCursorPos >= getTotalNumChars(); - clearInternal (0); + clearInternal (nullptr); insert (newText, 0, currentFont, findColour (textColourId), 0, caretPosition); // if you're adding text with line-feeds to a single-line text editor, it @@ -1447,47 +1424,40 @@ void TextEditor::scrollToMakeSureCursorIsVisible() if (keepCaretOnScreen) { - int x = viewport->getViewPositionX(); - int y = viewport->getViewPositionY(); - - const Rectangle caretPos (getCaretRectangle()); + Point viewPos (viewport->getViewPosition()); + const Rectangle caretRect (getCaretRectangle()); - const int relativeCursorX = caretPos.getX() - x; - const int relativeCursorY = caretPos.getY() - y; + const Point relativeCursor = caretRect.getPosition() - viewPos; - if (relativeCursorX < jmax (1, proportionOfWidth (0.05f))) + if (relativeCursor.x < jmax (1, proportionOfWidth (0.05f))) { - x += relativeCursorX - proportionOfWidth (0.2f); + viewPos.x += relativeCursor.x - proportionOfWidth (0.2f); } - else if (relativeCursorX > jmax (0, viewport->getMaximumVisibleWidth() - (wordWrap ? 2 : 10))) + else if (relativeCursor.x > jmax (0, viewport->getMaximumVisibleWidth() - (wordWrap ? 2 : 10))) { - x += relativeCursorX + (isMultiLine() ? proportionOfWidth (0.2f) : 10) - viewport->getMaximumVisibleWidth(); + viewPos.x += relativeCursor.x + (isMultiLine() ? proportionOfWidth (0.2f) : 10) - viewport->getMaximumVisibleWidth(); } - x = jlimit (0, jmax (0, textHolder->getWidth() + 8 - viewport->getMaximumVisibleWidth()), x); + viewPos.x = jlimit (0, jmax (0, textHolder->getWidth() + 8 - viewport->getMaximumVisibleWidth()), viewPos.x); if (! isMultiLine()) { - y = (getHeight() - textHolder->getHeight() - topIndent) / -2; + viewPos.y = (getHeight() - textHolder->getHeight() - topIndent) / -2; } - else + else if (relativeCursor.y < 0) { - if (relativeCursorY < 0) - { - y = jmax (0, relativeCursorY + y); - } - else if (relativeCursorY > jmax (0, viewport->getMaximumVisibleHeight() - topIndent - caretPos.getHeight())) - { - y += relativeCursorY + 2 + caretPos.getHeight() + topIndent - viewport->getMaximumVisibleHeight(); - } + viewPos.y = jmax (0, relativeCursor.y + viewPos.y); + } + else if (relativeCursor.y > jmax (0, viewport->getMaximumVisibleHeight() - topIndent - caretRect.getHeight())) + { + viewPos.y += relativeCursor.y + 2 + caretRect.getHeight() + topIndent - viewport->getMaximumVisibleHeight(); } - viewport->setViewPosition (x, y); + viewport->setViewPosition (viewPos); } } -void TextEditor::moveCaretTo (const int newPosition, - const bool isSelecting) +void TextEditor::moveCaretTo (const int newPosition, const bool isSelecting) { if (isSelecting) { @@ -1700,9 +1670,9 @@ void TextEditor::addPopupMenuItems (PopupMenu& m, const MouseEvent*) { m.addItem (StandardApplicationCommandIDs::cut, TRANS("Cut"), writable); m.addItem (StandardApplicationCommandIDs::copy, TRANS("Copy"), ! selection.isEmpty()); - m.addItem (StandardApplicationCommandIDs::paste, TRANS("Paste"), writable); } + m.addItem (StandardApplicationCommandIDs::paste, TRANS("Paste"), writable); m.addItem (StandardApplicationCommandIDs::del, TRANS("Delete"), writable); m.addSeparator(); m.addItem (StandardApplicationCommandIDs::selectAll, TRANS("Select All")); @@ -2234,8 +2204,7 @@ void TextEditor::insert (const String& text, } } -void TextEditor::reinsert (const int insertIndex, - const Array & sectionsToInsert) +void TextEditor::reinsert (const int insertIndex, const OwnedArray& sectionsToInsert) { int index = 0; int nextIndex = 0; @@ -2275,9 +2244,7 @@ void TextEditor::reinsert (const int insertIndex, valueTextNeedsUpdating = true; } -void TextEditor::remove (Range range, - UndoManager* const um, - const int caretPositionToMoveTo) +void TextEditor::remove (Range range, UndoManager* const um, const int caretPositionToMoveTo) { if (! range.isEmpty()) { @@ -2310,7 +2277,7 @@ void TextEditor::remove (Range range, if (um != nullptr) { - Array removedSections; + Array removedSections; for (int i = 0; i < sections.size(); ++i) { @@ -2345,9 +2312,7 @@ void TextEditor::remove (Range range, if (remainingRange.getStart() <= index && remainingRange.getEnd() >= nextIndex) { - sections.remove(i); - section->clear(); - delete section; + sections.remove (i); remainingRange.setEnd (remainingRange.getEnd() - (nextIndex - index)); if (remainingRange.isEmpty()) @@ -2528,8 +2493,7 @@ int TextEditor::findWordBreakBefore (const int position) const //============================================================================== -void TextEditor::splitSection (const int sectionIndex, - const int charToSplitAt) +void TextEditor::splitSection (const int sectionIndex, const int charToSplitAt) { jassert (sections[sectionIndex] != nullptr); @@ -2549,7 +2513,6 @@ void TextEditor::coalesceSimilarSections() { s1->append (*s2, passwordCharacter); sections.remove (i + 1); - delete s2; --i; } } diff --git a/JuceLibraryCode/modules/juce_gui_basics/widgets/juce_TextEditor.h b/JuceLibraryCode/modules/juce_gui_basics/widgets/juce_TextEditor.h index f4a9784..2ccbfe0 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/widgets/juce_TextEditor.h +++ b/JuceLibraryCode/modules/juce_gui_basics/widgets/juce_TextEditor.h @@ -657,7 +657,7 @@ private: friend class InsertAction; friend class RemoveAction; - ScopedPointer viewport; + ScopedPointer viewport; TextHolderComponent* textHolder; BorderSize borderSize; @@ -683,7 +683,7 @@ private: Font currentFont; mutable int totalNumChars; int caretPosition; - Array sections; + OwnedArray sections; String textToShowWhenEmpty; Colour colourForTextWhenEmpty; juce_wchar passwordCharacter; @@ -707,7 +707,7 @@ private: void splitSection (int sectionIndex, int charToSplitAt); void clearInternal (UndoManager*); void insert (const String&, int insertIndex, const Font&, const Colour, UndoManager*, int newCaretPos); - void reinsert (int insertIndex, const Array &); + void reinsert (int insertIndex, const OwnedArray&); void remove (Range range, UndoManager*, int caretPositionToMoveTo); void getCharPosition (int index, float& x, float& y, float& lineHeight) const; void updateCaretPosition(); diff --git a/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp b/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp index c6e1930..976c5a4 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp @@ -79,6 +79,11 @@ void ComponentPeer::updateBounds() setBounds (ScalingHelpers::scaledScreenPosToUnscaled (component, component.getBoundsInParent()), false); } +bool ComponentPeer::isKioskMode() const +{ + return Desktop::getInstance().getKioskModeComponent() == &component; +} + //============================================================================== void ComponentPeer::handleMouseEvent (const int touchIndex, const Point positionWithinPeer, const ModifierKeys newMods, const int64 time) diff --git a/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ComponentPeer.h b/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ComponentPeer.h index 2dc2d3f..9cdc807 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ComponentPeer.h +++ b/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ComponentPeer.h @@ -102,7 +102,7 @@ public: /** Returns the raw handle to whatever kind of window is being used. On windows, this is probably a HWND, on the mac, it's likely to be a WindowRef, - but rememeber there's no guarantees what you'll get back. + but remember there's no guarantees what you'll get back. */ virtual void* getNativeHandle() const = 0; @@ -176,6 +176,9 @@ public: /** True if the window is currently full-screen. */ virtual bool isFullScreen() const = 0; + /** True if the window is in kiosk-mode. */ + virtual bool isKioskMode() const; + /** Sets the size to restore to if fullscreen mode is turned off. */ void setNonFullScreenBounds (const Rectangle& newBounds) noexcept; diff --git a/JuceLibraryCode/modules/juce_gui_basics/windows/juce_DocumentWindow.cpp b/JuceLibraryCode/modules/juce_gui_basics/windows/juce_DocumentWindow.cpp index 9afd1fb..83a0a9d 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/windows/juce_DocumentWindow.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/windows/juce_DocumentWindow.cpp @@ -249,17 +249,17 @@ void DocumentWindow::resized() BorderSize DocumentWindow::getBorderThickness() { - return BorderSize ((isFullScreen() || isUsingNativeTitleBar()) - ? 0 : (resizableBorder != nullptr ? 4 : 1)); + return ResizableWindow::getBorderThickness(); } BorderSize DocumentWindow::getContentComponentBorder() { BorderSize border (getBorderThickness()); - border.setTop (border.getTop() - + (isUsingNativeTitleBar() ? 0 : titleBarHeight) - + (menuBar != nullptr ? menuBarHeight : 0)); + if (! isKioskMode()) + border.setTop (border.getTop() + + (isUsingNativeTitleBar() ? 0 : titleBarHeight) + + (menuBar != nullptr ? menuBarHeight : 0)); return border; } @@ -273,6 +273,9 @@ Rectangle DocumentWindow::getTitleBarArea() { const BorderSize border (getBorderThickness()); + if (isKioskMode()) + return Rectangle(); + return Rectangle (border.getLeft(), border.getTop(), getWidth() - border.getLeftAndRight(), getTitleBarHeight()); } diff --git a/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ResizableWindow.cpp b/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ResizableWindow.cpp index 300373b..f30defc 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ResizableWindow.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ResizableWindow.cpp @@ -167,7 +167,10 @@ void ResizableWindow::setContentComponentSize (int width, int height) BorderSize ResizableWindow::getBorderThickness() { - return BorderSize (isUsingNativeTitleBar() ? 0 : ((resizableBorder != nullptr && ! isFullScreen()) ? 5 : 3)); + if (isUsingNativeTitleBar() || isKioskMode()) + return BorderSize(); + + return BorderSize ((resizableBorder != nullptr && ! isFullScreen()) ? 4 : 1); } BorderSize ResizableWindow::getContentComponentBorder() @@ -177,27 +180,23 @@ BorderSize ResizableWindow::getContentComponentBorder() void ResizableWindow::moved() { - updateLastPos(); + updateLastPosIfShowing(); } void ResizableWindow::visibilityChanged() { TopLevelWindow::visibilityChanged(); - updateLastPos(); + updateLastPosIfShowing(); } void ResizableWindow::resized() { + const bool resizerHidden = isFullScreen() || isKioskMode() || isUsingNativeTitleBar(); + if (resizableBorder != nullptr) { - #if JUCE_WINDOWS || JUCE_LINUX - // hide the resizable border if the OS already provides one.. - resizableBorder->setVisible (! (isFullScreen() || isUsingNativeTitleBar())); - #else - resizableBorder->setVisible (! isFullScreen()); - #endif - + resizableBorder->setVisible (! resizerHidden); resizableBorder->setBorderThickness (getBorderThickness()); resizableBorder->setSize (getWidth(), getHeight()); resizableBorder->toBack(); @@ -205,12 +204,7 @@ void ResizableWindow::resized() if (resizableCorner != nullptr) { - #if JUCE_MAC - // hide the resizable border if the OS already provides one.. - resizableCorner->setVisible (! (isFullScreen() || isUsingNativeTitleBar())); - #else - resizableCorner->setVisible (! isFullScreen()); - #endif + resizableCorner->setVisible (! resizerHidden); const int resizerSize = 18; resizableCorner->setBounds (getWidth() - resizerSize, @@ -227,7 +221,7 @@ void ResizableWindow::resized() contentComponent->setBoundsInset (getContentComponentBorder()); } - updateLastPos(); + updateLastPosIfShowing(); #if JUCE_DEBUG hasBeenResized = true; @@ -424,7 +418,7 @@ void ResizableWindow::setFullScreen (const bool shouldBeFullScreen) { if (shouldBeFullScreen != isFullScreen()) { - updateLastPos(); + updateLastPosIfShowing(); fullscreen = shouldBeFullScreen; if (isOnDesktop()) @@ -470,7 +464,7 @@ void ResizableWindow::setMinimised (const bool shouldMinimise) { if (ComponentPeer* const peer = getPeer()) { - updateLastPos(); + updateLastPosIfShowing(); peer->setMinimised (shouldMinimise); } else @@ -480,9 +474,24 @@ void ResizableWindow::setMinimised (const bool shouldMinimise) } } -void ResizableWindow::updateLastPos() +bool ResizableWindow::isKioskMode() const +{ + if (isOnDesktop()) + if (ComponentPeer* peer = getPeer()) + return peer->isKioskMode(); + + return Desktop::getInstance().getKioskModeComponent() == this; +} + +void ResizableWindow::updateLastPosIfShowing() +{ + if (isShowing()) + updateLastPosIfNotFullScreen(); +} + +void ResizableWindow::updateLastPosIfNotFullScreen() { - if (isShowing() && ! (isFullScreen() || isMinimised())) + if (! (isFullScreen() || isMinimised() || isKioskMode())) lastNonFullScreenPos = getBounds(); } @@ -495,8 +504,8 @@ void ResizableWindow::parentSizeChanged() //============================================================================== String ResizableWindow::getWindowStateAsString() { - updateLastPos(); - return (isFullScreen() ? "fs " : "") + lastNonFullScreenPos.toString(); + updateLastPosIfShowing(); + return (isFullScreen() && ! isKioskMode() ? "fs " : "") + lastNonFullScreenPos.toString(); } bool ResizableWindow::restoreWindowStateFromString (const String& s) @@ -548,7 +557,7 @@ bool ResizableWindow::restoreWindowStateFromString (const String& s) peer->setNonFullScreenBounds (newPos); } - lastNonFullScreenPos = newPos; + updateLastPosIfNotFullScreen(); setFullScreen (fs); if (! fs) diff --git a/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ResizableWindow.h b/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ResizableWindow.h index 7a7ffd7..dd9f806 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ResizableWindow.h +++ b/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ResizableWindow.h @@ -190,6 +190,11 @@ public: */ void setMinimised (bool shouldMinimise); + /** Returns true if the window has been placed in kiosk-mode. + @see Desktop::setKioskComponent + */ + bool isKioskMode() const; + //============================================================================== /** Returns a string which encodes the window's current size and position. @@ -379,7 +384,8 @@ private: #endif void initialise (bool addToDesktop); - void updateLastPos(); + void updateLastPosIfNotFullScreen(); + void updateLastPosIfShowing(); void setContent (Component*, bool takeOwnership, bool resizeToFit); #if JUCE_CATCH_DEPRECATED_CODE_MISUSE diff --git a/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.cpp b/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.cpp index 82d12aa..559bcab 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.cpp @@ -25,12 +25,13 @@ ThreadWithProgressWindow::ThreadWithProgressWindow (const String& title, const bool hasProgressBar, const bool hasCancelButton, - const int timeOutMsWhenCancelling_, + const int cancellingTimeOutMs, const String& cancelButtonText, Component* componentToCentreAround) - : Thread ("Juce Progress Window"), - progress (0.0), - timeOutMsWhenCancelling (timeOutMsWhenCancelling_) + : Thread ("ThreadWithProgressWindow"), + progress (0.0), + timeOutMsWhenCancelling (cancellingTimeOutMs), + wasCancelledByUser (false) { alertWindow = LookAndFeel::getDefaultLookAndFeel() .createAlertWindow (title, String(), @@ -52,8 +53,7 @@ ThreadWithProgressWindow::~ThreadWithProgressWindow() stopThread (timeOutMsWhenCancelling); } -#if JUCE_MODAL_LOOPS_PERMITTED -bool ThreadWithProgressWindow::runThread (const int priority) +void ThreadWithProgressWindow::launchThread (int priority) { jassert (MessageManager::getInstance()->isThisTheMessageThread()); @@ -65,15 +65,8 @@ bool ThreadWithProgressWindow::runThread (const int priority) alertWindow->setMessage (message); } - const bool finishedNaturally = alertWindow->runModalLoop() != 0; - - stopThread (timeOutMsWhenCancelling); - - alertWindow->setVisible (false); - - return finishedNaturally; + alertWindow->enterModalState(); } -#endif void ThreadWithProgressWindow::setProgress (const double newProgress) { @@ -88,15 +81,34 @@ void ThreadWithProgressWindow::setStatusMessage (const String& newStatusMessage) void ThreadWithProgressWindow::timerCallback() { - if (! isThreadRunning()) + bool threadStillRunning = isThreadRunning(); + + if (! (threadStillRunning && alertWindow->isCurrentlyModal())) { - // thread has finished normally.. + stopTimer(); + stopThread (timeOutMsWhenCancelling); alertWindow->exitModalState (1); alertWindow->setVisible (false); + + wasCancelledByUser = threadStillRunning; + threadComplete (threadStillRunning); + return; // (this may be deleted now) } - else - { - const ScopedLock sl (messageLock); - alertWindow->setMessage (message); - } + + const ScopedLock sl (messageLock); + alertWindow->setMessage (message); +} + +void ThreadWithProgressWindow::threadComplete (bool) {} + +#if JUCE_MODAL_LOOPS_PERMITTED +bool ThreadWithProgressWindow::runThread (const int priority) +{ + launchThread (priority); + + while (isTimerRunning()) + MessageManager::getInstance()->runDispatchLoopUntil (5); + + return ! wasCancelledByUser; } +#endif diff --git a/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.h b/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.h index 7bf8522..ec68244 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.h +++ b/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.h @@ -111,6 +111,7 @@ public: ~ThreadWithProgressWindow(); //============================================================================== + #if JUCE_MODAL_LOOPS_PERMITTED /** Starts the thread and waits for it to finish. This will start the thread, make the dialog box appear, and wait until either @@ -123,6 +124,18 @@ public: @returns true if the thread finished normally; false if the user pressed cancel */ bool runThread (int threadPriority = 5); + #endif + + /** Starts the thread and returns. + + This will start the thread and make the dialog box appear in a modal state. When + the thread finishes normally, or the cancel button is pressed, the window will be + hidden and the threadComplete() method will be called. + + @param threadPriority the priority to use when starting the thread - see + Thread::startThread() for values + */ + void launchThread (int threadPriority = 5); /** The thread should call this periodically to update the position of the progress bar. @@ -137,15 +150,22 @@ public: /** Returns the AlertWindow that is being used. */ AlertWindow* getAlertWindow() const noexcept { return alertWindow; } + //============================================================================== + /** This method is called (on the message thread) when the operation has finished. + You may choose to use this callback to delete the ThreadWithProgressWindow object. + */ + virtual void threadComplete (bool userPressedCancel); + private: //============================================================================== void timerCallback() override; double progress; - ScopedPointer alertWindow; + ScopedPointer alertWindow; String message; CriticalSection messageLock; const int timeOutMsWhenCancelling; + bool wasCancelledByUser; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ThreadWithProgressWindow) }; diff --git a/JuceLibraryCode/modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp b/JuceLibraryCode/modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp index 8cba8b3..0eb6ac4 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp @@ -242,6 +242,7 @@ void TopLevelWindow::setUsingNativeTitleBar (const bool shouldUseNativeTitleBar) { if (useNativeTitleBar != shouldUseNativeTitleBar) { + FocusRestorer focusRestorer; useNativeTitleBar = shouldUseNativeTitleBar; recreateDesktopWindow(); sendLookAndFeelChange(); diff --git a/JuceLibraryCode/modules/juce_gui_extra/code_editor/juce_CodeDocument.h b/JuceLibraryCode/modules/juce_gui_extra/code_editor/juce_CodeDocument.h index eb4b1c4..1f12137 100644 --- a/JuceLibraryCode/modules/juce_gui_extra/code_editor/juce_CodeDocument.h +++ b/JuceLibraryCode/modules/juce_gui_extra/code_editor/juce_CodeDocument.h @@ -93,15 +93,15 @@ public: This will copy the position, but the new object will not be set to maintain its position, even if the source object was set to do so. */ - Position (const Position& other) noexcept; + Position (const Position&) noexcept; /** Destructor. */ ~Position(); - Position& operator= (const Position& other); + Position& operator= (const Position&); - bool operator== (const Position& other) const noexcept; - bool operator!= (const Position& other) const noexcept; + bool operator== (const Position&) const noexcept; + bool operator!= (const Position&) const noexcept; /** Points this object at a new position within the document. @@ -355,8 +355,8 @@ public: { public: Iterator (const CodeDocument& document) noexcept; - Iterator (const Iterator& other) noexcept; - Iterator& operator= (const Iterator& other) noexcept; + Iterator (const Iterator&) noexcept; + Iterator& operator= (const Iterator&) noexcept; ~Iterator() noexcept; /** Reads the next character and returns it. diff --git a/JuceLibraryCode/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp b/JuceLibraryCode/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp index cd10127..04a4ed5 100644 --- a/JuceLibraryCode/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp +++ b/JuceLibraryCode/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp @@ -438,7 +438,15 @@ void CodeEditorComponent::setLineNumbersShown (const bool shouldBeShown) void CodeEditorComponent::setReadOnly (bool b) noexcept { - readOnly = b; + if (readOnly != b) + { + readOnly = b; + + if (b) + removeChildComponent (caret); + else + addAndMakeVisible (caret); + } } //============================================================================== @@ -1316,10 +1324,10 @@ bool CodeEditorComponent::performCommand (const CommandID commandID) //============================================================================== void CodeEditorComponent::addPopupMenuItems (PopupMenu& m, const MouseEvent*) { - m.addItem (StandardApplicationCommandIDs::cut, TRANS ("Cut")); + m.addItem (StandardApplicationCommandIDs::cut, TRANS ("Cut"), isHighlightActive() && ! readOnly); m.addItem (StandardApplicationCommandIDs::copy, TRANS ("Copy"), ! getHighlightedRegion().isEmpty()); - m.addItem (StandardApplicationCommandIDs::paste, TRANS ("Paste")); - m.addItem (StandardApplicationCommandIDs::del, TRANS ("Delete")); + m.addItem (StandardApplicationCommandIDs::paste, TRANS ("Paste"), ! readOnly); + m.addItem (StandardApplicationCommandIDs::del, TRANS ("Delete"), ! readOnly); m.addSeparator(); m.addItem (StandardApplicationCommandIDs::selectAll, TRANS ("Select All")); m.addSeparator(); diff --git a/JuceLibraryCode/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.h b/JuceLibraryCode/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.h index bb3fb16..1039da2 100644 --- a/JuceLibraryCode/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.h +++ b/JuceLibraryCode/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.h @@ -109,6 +109,12 @@ public: */ CodeDocument::Position getPositionAt (int x, int y); + /** Returns the start of the selection as a position. */ + CodeDocument::Position getSelectionStart() const { return selectionStart; } + + /** Returns the end of the selection as a position. */ + CodeDocument::Position getSelectionEnd() const { return selectionEnd; } + /** Enables or disables the line-number display in the gutter. */ void setLineNumbersShown (bool shouldBeShown); @@ -161,13 +167,13 @@ public: struct State { /** Creates an object containing the state of the given editor. */ - State (const CodeEditorComponent& editor); + State (const CodeEditorComponent&); /** Creates a state object from a string that was previously created with toString(). */ State (const String& stringifiedVersion); - State (const State& other) noexcept; + State (const State&) noexcept; /** Updates the given editor with this saved state. */ - void restoreState (CodeEditorComponent& editor) const; + void restoreState (CodeEditorComponent&) const; /** Returns a stringified version of this state that can be used to recreate it later. */ String toString() const; @@ -339,7 +345,7 @@ public: /** @internal */ bool isTextInputActive() const override; /** @internal */ - void setTemporaryUnderlining (const Array >&) override; + void setTemporaryUnderlining (const Array >&) override; /** @internal */ ApplicationCommandTarget* getNextCommandTarget() override; /** @internal */ @@ -391,12 +397,12 @@ private: ColourScheme colourScheme; class CodeEditorLine; - OwnedArray lines; + OwnedArray lines; void rebuildLineTokens(); void rebuildLineTokensAsync(); void codeDocumentChanged (int start, int end); - OwnedArray cachedIterators; + OwnedArray cachedIterators; void clearCachedIterators (int firstLineToBeInvalid); void updateCachedIterators (int maxLineNum); void getIteratorForPosition (int position, CodeDocument::Iterator&); @@ -406,7 +412,7 @@ private: //============================================================================== void insertText (const String&); - void updateCaretPosition(); + virtual void updateCaretPosition(); void updateScrollBars(); void scrollToLineInternal (int line); void scrollToColumnInternal (double column); diff --git a/JuceLibraryCode/modules/juce_gui_extra/juce_module_info b/JuceLibraryCode/modules/juce_gui_extra/juce_module_info index 5bbabdc..ebe4e74 100644 --- a/JuceLibraryCode/modules/juce_gui_extra/juce_module_info +++ b/JuceLibraryCode/modules/juce_gui_extra/juce_module_info @@ -1,7 +1,7 @@ { "id": "juce_gui_extra", "name": "JUCE extended GUI classes", - "version": "3.0.1", + "version": "3.0.3", "description": "Miscellaneous GUI classes for specialised tasks.", "website": "http://www.juce.com/juce", "license": "GPL/Commercial", diff --git a/JuceLibraryCode/modules/juce_gui_extra/native/juce_mac_NSViewComponent.mm b/JuceLibraryCode/modules/juce_gui_extra/native/juce_mac_NSViewComponent.mm index ff769d0..b31eb86 100644 --- a/JuceLibraryCode/modules/juce_gui_extra/native/juce_mac_NSViewComponent.mm +++ b/JuceLibraryCode/modules/juce_gui_extra/native/juce_mac_NSViewComponent.mm @@ -22,24 +22,95 @@ ============================================================================== */ + +struct NSViewResizeWatcher +{ + NSViewResizeWatcher() : callback (nil) {} + + virtual ~NSViewResizeWatcher() + { + // must call detachViewWatcher() first + jassert (callback == nil); + } + + void attachViewWatcher (NSView* view) + { + static ViewFrameChangeCallbackClass cls; + callback = [cls.createInstance() init]; + ViewFrameChangeCallbackClass::setTarget (callback, this); + + [[NSNotificationCenter defaultCenter] addObserver: callback + selector: @selector (frameChanged:) + name: NSViewFrameDidChangeNotification + object: view]; + } + + void detachViewWatcher() + { + if (callback != nil) + { + [[NSNotificationCenter defaultCenter] removeObserver: callback]; + [callback release]; + callback = nil; + } + } + + virtual void viewResized() = 0; + +private: + id callback; + + //============================================================================== + struct ViewFrameChangeCallbackClass : public ObjCClass + { + ViewFrameChangeCallbackClass() : ObjCClass ("JUCE_NSViewCallback_") + { + addIvar ("target"); + addMethod (@selector (frameChanged:), frameChanged, "v@:@"); + registerClass(); + } + + static void setTarget (id self, NSViewResizeWatcher* c) + { + object_setInstanceVariable (self, "target", c); + } + + private: + static void frameChanged (id self, SEL, NSNotification*) + { + if (NSViewResizeWatcher* const target = getIvar (self, "target")) + target->viewResized(); + } + + JUCE_DECLARE_NON_COPYABLE (ViewFrameChangeCallbackClass); + }; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NSViewResizeWatcher) +}; + +//============================================================================== class NSViewAttachment : public ReferenceCountedObject, - public ComponentMovementWatcher + public ComponentMovementWatcher, + private NSViewResizeWatcher { public: NSViewAttachment (NSView* const v, Component& comp) : ComponentMovementWatcher (&comp), - view (v), - owner (comp), + view (v), owner (comp), currentPeer (nullptr) { [view retain]; + [view setPostsFrameChangedNotifications: YES]; if (owner.isShowing()) componentPeerChanged(); + + attachViewWatcher (view); } ~NSViewAttachment() { + detachViewWatcher(); removeFromParent(); [view release]; } @@ -91,6 +162,11 @@ public: componentPeerChanged(); } + void viewResized() override + { + owner.childBoundsChanged (nullptr); + } + NSView* const view; private: @@ -124,7 +200,7 @@ void NSViewComponent::setView (void* const view) void* NSViewComponent::getView() const { - return attachment != nullptr ? static_cast (attachment.get())->view + return attachment != nullptr ? static_cast (attachment.get())->view : nullptr; } @@ -132,7 +208,7 @@ void NSViewComponent::resizeToFitView() { if (attachment != nullptr) { - NSRect r = [static_cast (attachment.get())->view frame]; + NSRect r = [static_cast (attachment.get())->view frame]; setBounds (Rectangle ((int) r.size.width, (int) r.size.height)); } } diff --git a/JuceLibraryCode/modules/juce_gui_extra/native/juce_win32_WebBrowserComponent.cpp b/JuceLibraryCode/modules/juce_gui_extra/native/juce_win32_WebBrowserComponent.cpp index 76f4c1d..0a5b307 100644 --- a/JuceLibraryCode/modules/juce_gui_extra/native/juce_win32_WebBrowserComponent.cpp +++ b/JuceLibraryCode/modules/juce_gui_extra/native/juce_win32_WebBrowserComponent.cpp @@ -158,7 +158,7 @@ private: owner.pageFinishedLoading (getStringFromVariant (pDispParams->rgvarg[0].pvarVal)); return S_OK; } - else if (dispIdMember == DISPID_WINDOWCLOSING) + else if (dispIdMember == 263 /*DISPID_WINDOWCLOSING*/) { owner.windowCloseRequest(); diff --git a/README.md b/README.md index 6f047c4..cc3e240 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,11 @@ Dexed FM Synth Software Emulator ================================ Dexed is a multi platform, multi format plugin synth that is closely modeled on the Yamaha DX7. -Under the hood, it uses [music-synthesizer-for-android](https://code.google.com/p/music-synthesizer-for-android) +Under the hood it uses [music-synthesizer-for-android](https://code.google.com/p/music-synthesizer-for-android) for the synth engine and [JUCE](http://wwww.juce.com) as a plugin wrapper. The goal of this project is to be a great tool/companion for the original DX7. Yes, the sound engine -with 'float' values parameter; different waveform (à la TX81z) would be great but anything that +with 'float' value parameters; different waveform (à la TX81z) would be great but anything that goes beyond the DX7 should will be a fork of this project. This is to keep the compatiblity with the original synth. @@ -17,19 +17,17 @@ Features -------- * Multi platform (OS X, Windows, Linux) and multi format (VST, AU and others that I don't use); by using JUCE * The sound engine [music-synthesizer-for-android](https://code.google.com/p/music-synthesizer-for-android) is closely modeled on the original DX7 characteristics -* All of the 144 DX7 parameters are available from one single panel +* 144 DAW automatable DX7 parameters available from one single panel * Fully supports DX7 input and output Sysex messages; including controller change. This means that you can use this with a native DX7/TX7 as a patch editor * Each operator have a realtime VU meter to know wich one is active * Can load/save any DX7/TX7 sysex programs. It is also possible to save a single program into a different sysex file. Binary downloads ---------------- -Dexed is not a finished product but it is stable enough to be used in a DAW environment: in normal operation it doesn't crash -and the VST state saving works. +Dexed is not a finished product but it is stable enough to be used in a DAW environment: +in normal operation it shouldn't crash and the VST state saving works. -* Version 0.3.0 [vst win32](http://le-son666.com/software/dexed/dexed-0.3.0-win32.zip) -- [vst win64](http://le-son666.com/software/dexed/dexed-0.3.0-win64.zip) -- [vst os x](http://le-son666.com/software/dexed/dexed-0.3.0-osx.vst.zip) +* Version 0.3.0 [vst win32](http://le-son666.com/software/dexed/dexed-0.3.0-win32.zip) - [vst win64](http://le-son666.com/software/dexed/dexed-0.3.0-win64.zip) - [vst os x](http://le-son666.com/software/dexed/dexed-0.3.0-osx.vst.zip) Using as a DX7 editor --------------------- @@ -53,7 +51,7 @@ valid checksum for your DX7 keyboard. I'm in now way responsible if this breaks Credits & thanks ---------------- -Raph Levien and msfa team, markusthegeek, Jean-Marc Desprez and all the crew who made these historic +Raph Levien and the msfa team, markusthegeek, Jean-Marc Desprez and all the crew who made these historic DX programs: (Dave Benson, Frank Carvalho, Tim Conrardy, Jack Deckard, Chris Dodunski, Tim Garrett, Hitaye, Stephan Ibsen, Christian Jezreel, Narfman, Godric Wilkie) @@ -67,5 +65,4 @@ TODO - Dexed TODO - msfa ----------- * LFO Amplitude -* MOD Wheel action * Algo 4 & 6 feedback diff --git a/Source/DXComponents.cpp b/Source/DXComponents.cpp index 7f52049..84a8e61 100644 --- a/Source/DXComponents.cpp +++ b/Source/DXComponents.cpp @@ -143,7 +143,7 @@ void EnvDisplay::paint(Graphics &g) { char *rates = pvalues; float dist[4]; - float total; + float total = 0; int old = levels[3]; @@ -213,7 +213,7 @@ void PitchEnvDisplay::paint(Graphics &g) { char *rates = pvalues; float dist[4]; - float total; + float total = 0; int old = pitchenv_tab[levels[3]] + 128; // find the scale diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 430916b..f8cce46 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -75,6 +75,7 @@ void DexedAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock) currentNote = 0; controllers.values_[kControllerPitch] = 0x2000; + controllers.values_[KcontrollerModWheel] = 0; sustain = false; extra_buf_size = 0; @@ -226,6 +227,12 @@ void DexedAudioProcessor::processMidiMessage(MidiMessage *msg) { int controller = buf[1]; int value = buf[2]; + // mod wheel + if ( controller == 1 ) { + controllers.values_[KcontrollerModWheel] = value; + return; + } + // pedal if (controller == 64) { sustain = value != 0; @@ -237,6 +244,7 @@ void DexedAudioProcessor::processMidiMessage(MidiMessage *msg) { } } } + return; } } return; diff --git a/Source/msfa/controllers.h b/Source/msfa/controllers.h index b63d7ed..0b5fc27 100755 --- a/Source/msfa/controllers.h +++ b/Source/msfa/controllers.h @@ -18,7 +18,7 @@ #define __CONTROLLERS_H // State of MIDI controllers - +const int KcontrollerModWheel = 1; const int kControllerPitch = 128; class Controllers { diff --git a/Source/msfa/dx7note.cc b/Source/msfa/dx7note.cc index bf7141d..b516bfd 100755 --- a/Source/msfa/dx7note.cc +++ b/Source/msfa/dx7note.cc @@ -184,12 +184,12 @@ void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, int32_t pitchmod = pitchenv_.getsample(); uint32_t pmd = pitchmoddepth_ * lfo_delay; // Q32 // TODO: add modulation sources (mod wheel, etc) + uint32_t pwmd = (ctrls->values_[KcontrollerModWheel] * 0.7874) * (1 << 24); int32_t senslfo = pitchmodsens_ * (lfo_val - (1 << 23)); + + pitchmod += (((int64_t)pwmd) * (int64_t)senslfo) >> 39; pitchmod += (((int64_t)pmd) * (int64_t)senslfo) >> 39; - uint32_t amd = ampmoddepth_ * lfo_delay; // should be Q32 - - // hardcodes a pitchbend range of 3 semitones, TODO make configurable int pitchbend = ctrls->values_[kControllerPitch]; int32_t pb = (pitchbend - 0x2000) << 9; @@ -197,9 +197,6 @@ void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, for (int op = 0; op < 6; op++) { params_[op].gain[0] = params_[op].gain[1]; int32_t level = env_[op].getsample(); - - - int32_t gain = Exp2::lookup(level - (14 * (1 << 24))); //int32_t gain = pow(2, 10 + level * (1.0 / (1 << 24))); params_[op].freq = Freqlut::lookup(basepitch_[op] + pitchmod); @@ -223,12 +220,7 @@ void Dx7Note::update(const char patch[156], int midinote) { int fine = patch[off + 19]; int detune = patch[off + 20]; basepitch_[op] = osc_freq(midinote, mode, coarse, fine, detune); - }/* - for (int i = 0; i < 4; i++) { - rates[i] = patch[126 + i]; - levels[i] = patch[130 + i]; } - pitchenv_.set(rates, levels);*/ algorithm_ = patch[134]; int feedback = patch[135]; fb_shift_ = feedback != 0 ? 8 - feedback : 16; @@ -236,8 +228,6 @@ void Dx7Note::update(const char patch[156], int midinote) { pitchmodsens_ = pitchmodsenstab[patch[143] & 7]; } -void dexed_trace(const char *source, const char *fmt, ...); - void Dx7Note::peekVoiceStatus(VoiceStatus &status) { for(int i=0;i<6;i++) { status.amp[i] = params_[i].gain[1]; diff --git a/Source/msfa/pitchenv.cc b/Source/msfa/pitchenv.cc index e5aac6c..4a8de21 100644 --- a/Source/msfa/pitchenv.cc +++ b/Source/msfa/pitchenv.cc @@ -90,7 +90,6 @@ void PitchEnv::advance(int newix) { void PitchEnv::getPosition(char *step) { *step = ix_; - }