From dc5560392f61dada1b092b5f6e980c05e17158d7 Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Sat, 20 Dec 2014 20:59:48 +0000 Subject: [PATCH] - Library code update - project update (added Eigen) git-svn-id: http://moon:8086/svn/software/trunk/projects/mpsk_rx_gui@94 b431acfa-c32f-4a4a-93f1-934dc6c82436 --- Builds/Linux/Makefile | 12 +- JuceLibraryCode/JuceHeader.h | 2 + .../buffers/juce_AudioDataConverters.cpp | 32 +- .../buffers/juce_AudioSampleBuffer.cpp | 10 +- .../buffers/juce_FloatVectorOperations.cpp | 174 ++++- .../buffers/juce_FloatVectorOperations.h | 30 + .../juce_audio_basics/effects/juce_Reverb.h | 2 +- .../juce_audio_basics/juce_audio_basics.cpp | 2 + .../juce_audio_basics/juce_module_info | 2 +- .../midi/juce_MidiBuffer.cpp | 4 +- .../juce_audio_basics/midi/juce_MidiBuffer.h | 10 +- .../midi/juce_MidiMessage.cpp | 10 +- .../midi/juce_MidiMessageSequence.cpp | 25 +- .../midi/juce_MidiMessageSequence.h | 24 +- .../sources/juce_ResamplingAudioSource.cpp | 20 +- .../sources/juce_ResamplingAudioSource.h | 3 + .../synthesisers/juce_Synthesiser.cpp | 97 ++- .../synthesisers/juce_Synthesiser.h | 86 ++- .../audio_io/juce_AudioDeviceManager.cpp | 22 +- .../audio_io/juce_AudioDeviceManager.h | 43 +- .../audio_io/juce_AudioIODevice.cpp | 19 +- .../audio_io/juce_AudioIODevice.h | 5 + .../audio_io/juce_AudioIODeviceType.h | 2 +- .../juce_audio_devices/juce_audio_devices.cpp | 1 + .../juce_audio_devices/juce_module_info | 2 +- .../native/juce_android_OpenSL.cpp | 75 ++- .../native/juce_ios_Audio.cpp | 72 +-- .../native/juce_linux_ALSA.cpp | 2 +- .../native/juce_mac_CoreAudio.cpp | 35 +- .../native/juce_win32_ASIO.cpp | 2 +- .../native/juce_win32_WASAPI.cpp | 4 +- .../sources/juce_AudioTransportSource.cpp | 4 + .../codecs/juce_AiffAudioFormat.cpp | 6 +- .../codecs/juce_LAMEEncoderAudioFormat.cpp | 4 +- .../codecs/juce_WavAudioFormat.cpp | 212 +++++-- .../codecs/juce_WavAudioFormat.h | 3 + .../format/juce_AudioFormatReader.cpp | 135 ++-- .../format/juce_AudioFormatReader.h | 28 +- .../format/juce_AudioFormatWriter.cpp | 30 + .../format/juce_AudioFormatWriter.h | 21 +- .../juce_audio_formats/juce_module_info | 2 +- .../sampler/juce_Sampler.cpp | 10 +- .../juce_audio_formats/sampler/juce_Sampler.h | 6 +- .../format/juce_AudioPluginFormat.h | 2 +- .../format/juce_AudioPluginFormatManager.h | 2 +- .../format_types/juce_AudioUnitPluginFormat.h | 2 +- .../juce_AudioUnitPluginFormat.mm | 53 +- .../format_types/juce_LADSPAPluginFormat.cpp | 4 +- .../format_types/juce_VST3Common.h | 83 ++- .../format_types/juce_VST3PluginFormat.cpp | 430 +++++++++++-- .../format_types/juce_VSTPluginFormat.cpp | 388 ++++++------ .../juce_audio_processors.cpp | 34 +- .../juce_audio_processors.h | 1 + .../juce_audio_processors/juce_module_info | 2 +- .../processors/juce_AudioProcessor.cpp | 186 +++++- .../processors/juce_AudioProcessor.h | 53 +- .../processors/juce_AudioProcessorEditor.cpp | 14 +- .../processors/juce_AudioProcessorEditor.h | 44 +- .../processors/juce_AudioProcessorGraph.h | 6 +- .../juce_GenericAudioProcessorEditor.cpp | 41 +- .../processors/juce_PluginDescription.cpp | 18 +- .../processors/juce_PluginDescription.h | 10 +- .../scanning/juce_KnownPluginList.cpp | 8 +- .../gui/juce_AudioDeviceSelectorComponent.cpp | 282 +++++---- .../gui/juce_AudioDeviceSelectorComponent.h | 9 +- .../gui/juce_AudioThumbnail.cpp | 55 +- .../gui/juce_MidiKeyboardComponent.cpp | 2 +- .../modules/juce_audio_utils/juce_module_info | 2 +- .../containers/juce_AbstractFifo.cpp | 2 +- .../modules/juce_core/containers/juce_Array.h | 5 +- .../containers/juce_DynamicObject.cpp | 56 +- .../juce_core/containers/juce_DynamicObject.h | 2 +- .../containers/juce_NamedValueSet.cpp | 230 +++---- .../juce_core/containers/juce_NamedValueSet.h | 70 +- .../juce_core/containers/juce_OwnedArray.h | 2 +- .../containers/juce_ReferenceCountedArray.h | 4 +- .../modules/juce_core/files/juce_File.cpp | 2 +- .../modules/juce_core/files/juce_File.h | 13 + .../juce_core/files/juce_FileInputStream.cpp | 35 +- .../juce_core/files/juce_FileInputStream.h | 18 +- .../files/juce_WildcardFileFilter.cpp | 53 +- .../juce_core/files/juce_WildcardFileFilter.h | 4 - .../juce_core/javascript/juce_JSON.cpp | 4 +- .../juce_core/javascript/juce_Javascript.cpp | 49 +- .../juce_core/javascript/juce_Javascript.h | 7 +- .../modules/juce_core/juce_core.cpp | 3 + JuceLibraryCode/modules/juce_core/juce_core.h | 2 + .../modules/juce_core/juce_module_info | 2 +- .../juce_core/maths/juce_BigInteger.cpp | 51 +- .../juce_core/maths/juce_MathsFunctions.h | 22 + .../modules/juce_core/maths/juce_Range.h | 7 + .../modules/juce_core/memory/juce_Atomic.h | 2 +- .../modules/juce_core/memory/juce_ByteOrder.h | 52 +- .../juce_core/memory/juce_MemoryBlock.cpp | 6 +- .../memory/juce_ReferenceCountedObject.h | 2 +- .../juce_core/memory/juce_ScopedPointer.h | 8 +- .../memory/juce_SharedResourcePointer.h | 2 +- .../juce_core/memory/juce_WeakReference.h | 4 +- .../native/java/JuceAppActivity.java | 11 +- .../native/juce_android_JNIHelpers.h | 33 +- .../juce_core/native/juce_android_Network.cpp | 2 +- .../native/juce_android_SystemStats.cpp | 15 +- .../juce_core/native/juce_linux_Network.cpp | 36 +- .../native/juce_linux_SystemStats.cpp | 2 +- .../juce_core/native/juce_linux_Threads.cpp | 7 +- .../juce_core/native/juce_mac_Network.mm | 13 +- .../juce_core/native/juce_mac_SystemStats.mm | 37 +- .../juce_core/native/juce_posix_SharedCode.h | 76 ++- .../juce_core/native/juce_win32_Files.cpp | 32 +- .../juce_core/native/juce_win32_Network.cpp | 75 ++- .../native/juce_win32_SystemStats.cpp | 50 +- .../juce_core/native/juce_win32_Threads.cpp | 2 +- .../modules/juce_core/network/juce_Socket.cpp | 14 +- .../modules/juce_core/network/juce_URL.cpp | 10 +- .../modules/juce_core/network/juce_URL.h | 3 + .../juce_core/streams/juce_InputStream.cpp | 4 +- .../juce_core/streams/juce_InputStream.h | 6 +- .../streams/juce_MemoryInputStream.cpp | 4 +- .../streams/juce_MemoryOutputStream.cpp | 4 +- .../streams/juce_MemoryOutputStream.h | 4 +- .../juce_core/streams/juce_OutputStream.cpp | 4 +- .../juce_core/streams/juce_OutputStream.h | 2 +- .../juce_core/system/juce_PlatformDefs.h | 130 ++-- .../juce_core/system/juce_StandardHeader.h | 6 +- .../juce_core/system/juce_SystemStats.h | 7 +- .../juce_core/system/juce_TargetPlatform.h | 6 +- .../juce_core/text/juce_Identifier.cpp | 38 +- .../modules/juce_core/text/juce_Identifier.h | 38 +- .../juce_core/text/juce_LocalisedStrings.cpp | 8 +- .../juce_core/text/juce_LocalisedStrings.h | 8 +- .../modules/juce_core/text/juce_String.cpp | 136 +++- .../modules/juce_core/text/juce_String.h | 23 +- .../juce_core/text/juce_StringArray.cpp | 20 +- .../modules/juce_core/text/juce_StringArray.h | 17 +- .../juce_core/text/juce_StringPool.cpp | 175 +++-- .../modules/juce_core/text/juce_StringPool.h | 44 +- .../modules/juce_core/time/juce_Time.cpp | 53 +- .../modules/juce_core/time/juce_Time.h | 32 +- .../juce_core/xml/juce_XmlDocument.cpp | 5 +- .../modules/juce_core/xml/juce_XmlElement.cpp | 63 +- .../modules/juce_core/xml/juce_XmlElement.h | 77 ++- .../modules/juce_core/zip/juce_ZipFile.cpp | 15 +- .../encryption/juce_RSAKey.cpp | 5 + .../encryption/juce_RSAKey.h | 62 +- .../juce_cryptography/hashing/juce_MD5.h | 16 +- .../juce_cryptography/juce_module_info | 2 +- .../app_properties/juce_PropertiesFile.cpp | 5 +- .../app_properties/juce_PropertiesFile.h | 3 +- .../juce_data_structures/juce_module_info | 2 +- .../undomanager/juce_UndoManager.cpp | 50 +- .../undomanager/juce_UndoManager.h | 47 +- .../values/juce_Value.cpp | 123 +--- .../juce_data_structures/values/juce_Value.h | 18 +- .../values/juce_ValueTree.cpp | 10 +- .../values/juce_ValueTree.h | 10 +- .../broadcasters/juce_ActionBroadcaster.cpp | 9 +- .../broadcasters/juce_AsyncUpdater.cpp | 4 +- .../broadcasters/juce_AsyncUpdater.h | 4 +- .../juce_ConnectedChildProcess.cpp | 25 +- .../interprocess/juce_ConnectedChildProcess.h | 16 +- .../juce_InterprocessConnection.cpp | 44 +- .../juce_InterprocessConnection.h | 1 + .../modules/juce_events/juce_module_info | 2 +- .../messages/juce_ApplicationBase.cpp | 13 +- .../messages/juce_ApplicationBase.h | 8 +- .../messages/juce_Initialisation.h | 26 +- .../messages/juce_MessageManager.cpp | 51 +- .../messages/juce_MessageManager.h | 9 +- .../native/juce_win32_Messaging.cpp | 2 +- .../contexts/juce_GraphicsContext.cpp | 10 +- .../contexts/juce_GraphicsContext.h | 6 +- ...uce_LowLevelGraphicsPostScriptRenderer.cpp | 2 +- .../juce_graphics/fonts/juce_CustomTypeface.h | 7 +- .../modules/juce_graphics/fonts/juce_Font.cpp | 6 +- .../modules/juce_graphics/fonts/juce_Font.h | 10 +- .../fonts/juce_GlyphArrangement.cpp | 352 ++++++----- .../fonts/juce_GlyphArrangement.h | 11 +- .../geometry/juce_AffineTransform.h | 27 +- .../juce_graphics/geometry/juce_Path.cpp | 24 +- .../juce_graphics/geometry/juce_Path.h | 8 +- .../juce_graphics/geometry/juce_Point.h | 3 + .../geometry/juce_RectangleList.h | 11 + .../image_formats/juce_PNGLoader.cpp | 7 +- .../image_formats/pnglib/pngread.c | 2 +- .../juce_graphics/images/juce_Image.cpp | 6 +- .../modules/juce_graphics/images/juce_Image.h | 6 +- .../modules/juce_graphics/juce_module_info | 2 +- .../native/juce_RenderingHelpers.h | 4 + .../native/juce_mac_CoreGraphicsContext.mm | 40 +- .../juce_graphics/native/juce_mac_Fonts.mm | 14 +- .../juce_win32_DirectWriteTypeLayout.cpp | 47 +- .../native/juce_win32_DirectWriteTypeface.cpp | 30 +- .../juce_graphics/native/juce_win32_Fonts.cpp | 4 +- .../application/juce_Application.h | 8 +- .../juce_gui_basics/buttons/juce_Button.cpp | 12 +- .../juce_gui_basics/buttons/juce_Button.h | 22 +- .../buttons/juce_DrawableButton.cpp | 58 +- .../buttons/juce_DrawableButton.h | 7 +- .../buttons/juce_TextButton.cpp | 21 +- .../juce_gui_basics/buttons/juce_TextButton.h | 35 +- .../juce_ApplicationCommandManager.cpp | 39 +- .../commands/juce_ApplicationCommandManager.h | 1 + .../juce_ApplicationCommandTarget.cpp | 4 +- .../commands/juce_ApplicationCommandTarget.h | 2 +- .../commands/juce_KeyPressMappingSet.cpp | 2 +- .../components/juce_Component.cpp | 191 +++--- .../components/juce_Component.h | 102 +-- .../components/juce_Desktop.cpp | 32 +- .../juce_gui_basics/components/juce_Desktop.h | 6 +- .../components/juce_ModalComponentManager.cpp | 11 + .../components/juce_ModalComponentManager.h | 5 + .../drawables/juce_SVGParser.cpp | 162 ++--- .../juce_DirectoryContentsList.cpp | 5 +- .../filebrowser/juce_FileChooserDialogBox.cpp | 2 +- .../filebrowser/juce_FilenameComponent.cpp | 14 +- .../filebrowser/juce_FilenameComponent.h | 5 + .../juce_gui_basics/juce_gui_basics.cpp | 8 +- .../modules/juce_gui_basics/juce_module_info | 2 +- .../keyboard/juce_TextInputTarget.h | 17 + .../layout/juce_ComponentAnimator.cpp | 13 +- .../layout/juce_ComponentAnimator.h | 4 +- .../layout/juce_ComponentBuilder.cpp | 2 +- .../layout/juce_ComponentBuilder.h | 2 +- .../layout/juce_TabbedButtonBar.cpp | 4 +- .../layout/juce_TabbedButtonBar.h | 2 +- .../juce_gui_basics/layout/juce_Viewport.cpp | 27 +- .../lookandfeel/juce_LookAndFeel_V2.cpp | 47 +- .../lookandfeel/juce_LookAndFeel_V2.h | 38 +- .../lookandfeel/juce_LookAndFeel_V3.cpp | 4 +- .../menus/juce_MenuBarComponent.cpp | 30 +- .../menus/juce_MenuBarComponent.h | 9 +- .../juce_gui_basics/menus/juce_MenuBarModel.h | 14 +- .../juce_gui_basics/menus/juce_PopupMenu.cpp | 13 +- .../juce_gui_basics/menus/juce_PopupMenu.h | 3 + .../mouse/juce_ComponentDragger.cpp | 2 +- .../mouse/juce_DragAndDropContainer.cpp | 50 +- .../mouse/juce_DragAndDropContainer.h | 6 + .../mouse/juce_MouseCursor.cpp | 2 +- .../juce_gui_basics/mouse/juce_MouseCursor.h | 4 +- .../juce_gui_basics/mouse/juce_MouseEvent.cpp | 36 +- .../juce_gui_basics/mouse/juce_MouseEvent.h | 34 +- .../mouse/juce_MouseInputSource.cpp | 163 +++-- .../mouse/juce_MouseInputSource.h | 16 +- .../native/juce_android_Windowing.cpp | 48 +- .../native/juce_ios_UIViewComponentPeer.mm | 174 +++-- .../native/juce_ios_Windowing.mm | 6 +- .../native/juce_linux_FileChooser.cpp | 201 +++--- .../native/juce_linux_Windowing.cpp | 138 ++-- .../native/juce_mac_NSViewComponentPeer.mm | 114 ++-- .../native/juce_mac_Windowing.mm | 55 +- .../native/juce_win32_Windowing.cpp | 179 ++++-- .../positioning/juce_RelativeRectangle.h | 5 +- .../juce_BooleanPropertyComponent.cpp | 2 +- .../juce_BooleanPropertyComponent.h | 18 + .../juce_ChoicePropertyComponent.cpp | 2 +- .../properties/juce_ChoicePropertyComponent.h | 10 +- .../properties/juce_SliderPropertyComponent.h | 4 + .../juce_gui_basics/widgets/juce_ComboBox.cpp | 19 +- .../juce_gui_basics/widgets/juce_ComboBox.h | 15 +- .../juce_gui_basics/widgets/juce_Label.cpp | 30 +- .../juce_gui_basics/widgets/juce_Label.h | 40 +- .../juce_gui_basics/widgets/juce_ListBox.cpp | 39 +- .../juce_gui_basics/widgets/juce_ListBox.h | 32 +- .../juce_gui_basics/widgets/juce_Slider.cpp | 128 ++-- .../widgets/juce_TableHeaderComponent.cpp | 2 +- .../widgets/juce_TableListBox.cpp | 31 +- .../widgets/juce_TableListBox.h | 51 +- .../widgets/juce_TextEditor.cpp | 6 +- .../juce_gui_basics/widgets/juce_TextEditor.h | 3 + .../juce_gui_basics/widgets/juce_Toolbar.cpp | 8 +- .../juce_gui_basics/widgets/juce_TreeView.cpp | 13 +- .../juce_gui_basics/widgets/juce_TreeView.h | 2 +- .../windows/juce_AlertWindow.cpp | 17 +- .../windows/juce_CallOutBox.cpp | 14 +- .../juce_gui_basics/windows/juce_CallOutBox.h | 12 + .../windows/juce_ComponentPeer.cpp | 18 +- .../windows/juce_ComponentPeer.h | 22 +- .../windows/juce_DialogWindow.h | 2 +- .../windows/juce_TooltipWindow.cpp | 6 +- .../windows/juce_TooltipWindow.h | 2 +- .../windows/juce_TopLevelWindow.cpp | 62 +- .../windows/juce_TopLevelWindow.h | 4 +- .../juce_CPlusPlusCodeTokeniserFunctions.h | 100 +++ .../code_editor/juce_CodeDocument.cpp | 18 +- .../code_editor/juce_CodeEditorComponent.cpp | 20 +- .../documents/juce_FileBasedDocument.cpp | 2 +- .../modules/juce_gui_extra/juce_gui_extra.cpp | 5 - .../modules/juce_gui_extra/juce_module_info | 2 +- .../juce_gui_extra/misc/juce_ColourSelector.h | 2 +- .../misc/juce_LiveConstantEditor.cpp | 14 +- .../misc/juce_LiveConstantEditor.h | 11 +- .../native/juce_mac_NSViewComponent.mm | 5 +- .../native/juce_mac_SystemTrayIcon.cpp | 15 +- .../native/juce_mac_WebBrowserComponent.mm | 5 + .../native/juce_win32_ActiveXComponent.cpp | 2 +- .../native/juce_win32_SystemTrayIcon.cpp | 4 +- .../native/juce_win32_WebBrowserComponent.cpp | 6 + .../modules/juce_opengl/juce_module_info | 2 +- .../modules/juce_opengl/juce_opengl.h | 24 +- .../juce_opengl/native/juce_OpenGL_ios.h | 22 +- .../juce_opengl/native/juce_OpenGL_win32.h | 29 +- .../juce_opengl/opengl/juce_OpenGLContext.cpp | 68 +- .../opengl/juce_OpenGLGraphicsContext.cpp | 71 ++- .../juce_opengl/opengl/juce_OpenGLHelpers.cpp | 6 +- .../juce_video/capture/juce_CameraDevice.h | 19 +- .../modules/juce_video/juce_module_info | 2 +- .../modules/juce_video/juce_video.cpp | 4 + .../native/juce_android_CameraDevice.cpp | 114 ++-- .../native/juce_mac_CameraDevice.mm | 239 +++---- .../native/juce_win32_CameraDevice.cpp | 597 ++++++++---------- .../native/juce_win32_DirectShowComponent.cpp | 3 + M-PSK Receiver.jucer | 8 +- 312 files changed, 6349 insertions(+), 4195 deletions(-) diff --git a/Builds/Linux/Makefile b/Builds/Linux/Makefile index d073d24..2b528a4 100644 --- a/Builds/Linux/Makefile +++ b/Builds/Linux/Makefile @@ -18,12 +18,12 @@ ifeq ($(CONFIG),Debug) TARGET_ARCH := -march=native endif - CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -D "radio_float_t=float" -D "fir_float_t=float" -D "JUCER_LINUX_MAKE_7346DA2A=1" -D "JUCE_APP_VERSION=1.0.0" -D "JUCE_APP_VERSION_HEX=0x10000" -I /usr/include -I /usr/include/freetype2 -I ../../JuceLibraryCode -I ../../JuceLibraryCode/modules -I ../../../../libsrc -I ../../Source + CPPFLAGS := $(DEPFLAGS) -std=c++11 -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -D "radio_float_t=float" -D "fir_float_t=float" -D "JUCER_LINUX_MAKE_7346DA2A=1" -D "JUCE_APP_VERSION=1.0.0" -D "JUCE_APP_VERSION_HEX=0x10000" -I /usr/include -I /usr/include/freetype2 -I ../../JuceLibraryCode -I ../../JuceLibraryCode/modules -I ../../../../libsrc -I ../../../../libsrc/cpp -I ../../Source -I /usr/local/include/eigen3 CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -g -ggdb -O0 -std=c++11 -pg CXXFLAGS += $(CFLAGS) - LDFLAGS += $(TARGET_ARCH) -L$(BINDIR) -L$(LIBDIR) -L/usr/X11R6/lib/ -L../../../../libsrc/radio/build/linux -L../../../../libsrc/fir/build/linux -L../../../../libsrc/crc/build/linux -lGL -lX11 -lXext -lXinerama -lasound -ldl -lfreetype -lpthread -lrt -lradio -lfir -lcrc + LDFLAGS += $(TARGET_ARCH) -L$(BINDIR) -L$(LIBDIR) -L/usr/X11R6/lib/ -L../../../../libsrc/build/linux -lGL -lX11 -lXext -lXinerama -lasound -ldl -lfreetype -lpthread -lrt -lradio -lfir -lcrc LDDEPS := - RESFLAGS := -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -D "radio_float_t=float" -D "fir_float_t=float" -D "JUCER_LINUX_MAKE_7346DA2A=1" -D "JUCE_APP_VERSION=1.0.0" -D "JUCE_APP_VERSION_HEX=0x10000" -I /usr/include -I /usr/include/freetype2 -I ../../JuceLibraryCode -I ../../JuceLibraryCode/modules -I ../../../../libsrc -I ../../Source + RESFLAGS := -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -D "radio_float_t=float" -D "fir_float_t=float" -D "JUCER_LINUX_MAKE_7346DA2A=1" -D "JUCE_APP_VERSION=1.0.0" -D "JUCE_APP_VERSION_HEX=0x10000" -I /usr/include -I /usr/include/freetype2 -I ../../JuceLibraryCode -I ../../JuceLibraryCode/modules -I ../../../../libsrc -I ../../../../libsrc/cpp -I ../../Source -I /usr/local/include/eigen3 TARGET := M-PSK\ Receiver BLDCMD = $(CXX) -o $(OUTDIR)/$(TARGET) $(OBJECTS) $(LDFLAGS) $(RESOURCES) $(TARGET_ARCH) CLEANCMD = rm -rf $(OUTDIR)/$(TARGET) $(OBJDIR) @@ -39,12 +39,12 @@ ifeq ($(CONFIG),Release) TARGET_ARCH := -march=native endif - CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -D "radio_float_t=float" -D "fir_float_t=float" -D "JUCER_LINUX_MAKE_7346DA2A=1" -D "JUCE_APP_VERSION=1.0.0" -D "JUCE_APP_VERSION_HEX=0x10000" -I /usr/include -I /usr/include/freetype2 -I ../../JuceLibraryCode -I ../../JuceLibraryCode/modules -I ../../../../libsrc -I ../../Source + CPPFLAGS := $(DEPFLAGS) -std=c++11 -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -D "radio_float_t=float" -D "fir_float_t=float" -D "JUCER_LINUX_MAKE_7346DA2A=1" -D "JUCE_APP_VERSION=1.0.0" -D "JUCE_APP_VERSION_HEX=0x10000" -I /usr/include -I /usr/include/freetype2 -I ../../JuceLibraryCode -I ../../JuceLibraryCode/modules -I ../../../../libsrc -I ../../../../libsrc/cpp -I ../../Source -I /usr/local/include/eigen3 CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -g -ggdb -O3 -std=c++11 -pg CXXFLAGS += $(CFLAGS) - LDFLAGS += $(TARGET_ARCH) -L$(BINDIR) -L$(LIBDIR) -L/usr/X11R6/lib/ -L../../../../libsrc/radio/build/linux -L../../../../libsrc/fir/build/linux -L../../../../libsrc/crc/build/linux -lGL -lX11 -lXext -lXinerama -lasound -ldl -lfreetype -lpthread -lrt -lradio -lfir -lcrc + LDFLAGS += $(TARGET_ARCH) -L$(BINDIR) -L$(LIBDIR) -L/usr/X11R6/lib/ -L../../../../libsrc/build/linux -lGL -lX11 -lXext -lXinerama -lasound -ldl -lfreetype -lpthread -lrt -lradio -lfir -lcrc LDDEPS := - RESFLAGS := -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -D "radio_float_t=float" -D "fir_float_t=float" -D "JUCER_LINUX_MAKE_7346DA2A=1" -D "JUCE_APP_VERSION=1.0.0" -D "JUCE_APP_VERSION_HEX=0x10000" -I /usr/include -I /usr/include/freetype2 -I ../../JuceLibraryCode -I ../../JuceLibraryCode/modules -I ../../../../libsrc -I ../../Source + RESFLAGS := -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -D "radio_float_t=float" -D "fir_float_t=float" -D "JUCER_LINUX_MAKE_7346DA2A=1" -D "JUCE_APP_VERSION=1.0.0" -D "JUCE_APP_VERSION_HEX=0x10000" -I /usr/include -I /usr/include/freetype2 -I ../../JuceLibraryCode -I ../../JuceLibraryCode/modules -I ../../../../libsrc -I ../../../../libsrc/cpp -I ../../Source -I /usr/local/include/eigen3 TARGET := M-PSK\ Receiver BLDCMD = $(CXX) -o $(OUTDIR)/$(TARGET) $(OBJECTS) $(LDFLAGS) $(RESOURCES) $(TARGET_ARCH) CLEANCMD = rm -rf $(OUTDIR)/$(TARGET) $(OBJDIR) diff --git a/JuceLibraryCode/JuceHeader.h b/JuceLibraryCode/JuceHeader.h index 4e8fcc9..44915da 100644 --- a/JuceLibraryCode/JuceHeader.h +++ b/JuceLibraryCode/JuceHeader.h @@ -35,11 +35,13 @@ using namespace juce; #endif +#if ! JUCE_DONT_DECLARE_PROJECTINFO namespace ProjectInfo { const char* const projectName = "M-QAM Transceiver"; const char* const versionString = "1.0.0"; const int versionNumber = 0x10000; } +#endif #endif // __APPHEADERFILE_GMZMR9__ diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp index 95d228e..a78b395 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp @@ -25,7 +25,7 @@ void AudioDataConverters::convertFloatToInt16LE (const float* source, void* dest, int numSamples, const int destBytesPerSample) { const double maxVal = (double) 0x7fff; - char* intData = static_cast (dest); + char* intData = static_cast (dest); if (dest != (void*) source || destBytesPerSample <= 4) { @@ -50,7 +50,7 @@ void AudioDataConverters::convertFloatToInt16LE (const float* source, void* dest void AudioDataConverters::convertFloatToInt16BE (const float* source, void* dest, int numSamples, const int destBytesPerSample) { const double maxVal = (double) 0x7fff; - char* intData = static_cast (dest); + char* intData = static_cast (dest); if (dest != (void*) source || destBytesPerSample <= 4) { @@ -75,7 +75,7 @@ void AudioDataConverters::convertFloatToInt16BE (const float* source, void* dest void AudioDataConverters::convertFloatToInt24LE (const float* source, void* dest, int numSamples, const int destBytesPerSample) { const double maxVal = (double) 0x7fffff; - char* intData = static_cast (dest); + char* intData = static_cast (dest); if (dest != (void*) source || destBytesPerSample <= 4) { @@ -100,7 +100,7 @@ void AudioDataConverters::convertFloatToInt24LE (const float* source, void* dest void AudioDataConverters::convertFloatToInt24BE (const float* source, void* dest, int numSamples, const int destBytesPerSample) { const double maxVal = (double) 0x7fffff; - char* intData = static_cast (dest); + char* intData = static_cast (dest); if (dest != (void*) source || destBytesPerSample <= 4) { @@ -125,7 +125,7 @@ void AudioDataConverters::convertFloatToInt24BE (const float* source, void* dest void AudioDataConverters::convertFloatToInt32LE (const float* source, void* dest, int numSamples, const int destBytesPerSample) { const double maxVal = (double) 0x7fffffff; - char* intData = static_cast (dest); + char* intData = static_cast (dest); if (dest != (void*) source || destBytesPerSample <= 4) { @@ -150,7 +150,7 @@ void AudioDataConverters::convertFloatToInt32LE (const float* source, void* dest void AudioDataConverters::convertFloatToInt32BE (const float* source, void* dest, int numSamples, const int destBytesPerSample) { const double maxVal = (double) 0x7fffffff; - char* intData = static_cast (dest); + char* intData = static_cast (dest); if (dest != (void*) source || destBytesPerSample <= 4) { @@ -176,7 +176,7 @@ void AudioDataConverters::convertFloatToFloat32LE (const float* source, void* de { jassert (dest != (void*) source || destBytesPerSample <= 4); // This op can't be performed on in-place data! - char* d = static_cast (dest); + char* d = static_cast (dest); for (int i = 0; i < numSamples; ++i) { @@ -194,7 +194,7 @@ void AudioDataConverters::convertFloatToFloat32BE (const float* source, void* de { jassert (dest != (void*) source || destBytesPerSample <= 4); // This op can't be performed on in-place data! - char* d = static_cast (dest); + char* d = static_cast (dest); for (int i = 0; i < numSamples; ++i) { @@ -212,7 +212,7 @@ void AudioDataConverters::convertFloatToFloat32BE (const float* source, void* de void AudioDataConverters::convertInt16LEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) { const float scale = 1.0f / 0x7fff; - const char* intData = static_cast (source); + const char* intData = static_cast (source); if (source != (void*) dest || srcBytesPerSample >= 4) { @@ -237,7 +237,7 @@ void AudioDataConverters::convertInt16LEToFloat (const void* const source, float void AudioDataConverters::convertInt16BEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) { const float scale = 1.0f / 0x7fff; - const char* intData = static_cast (source); + const char* intData = static_cast (source); if (source != (void*) dest || srcBytesPerSample >= 4) { @@ -262,7 +262,7 @@ void AudioDataConverters::convertInt16BEToFloat (const void* const source, float void AudioDataConverters::convertInt24LEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) { const float scale = 1.0f / 0x7fffff; - const char* intData = static_cast (source); + const char* intData = static_cast (source); if (source != (void*) dest || srcBytesPerSample >= 4) { @@ -287,7 +287,7 @@ void AudioDataConverters::convertInt24LEToFloat (const void* const source, float void AudioDataConverters::convertInt24BEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) { const float scale = 1.0f / 0x7fffff; - const char* intData = static_cast (source); + const char* intData = static_cast (source); if (source != (void*) dest || srcBytesPerSample >= 4) { @@ -312,7 +312,7 @@ void AudioDataConverters::convertInt24BEToFloat (const void* const source, float void AudioDataConverters::convertInt32LEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) { const float scale = 1.0f / 0x7fffffff; - const char* intData = static_cast (source); + const char* intData = static_cast (source); if (source != (void*) dest || srcBytesPerSample >= 4) { @@ -337,7 +337,7 @@ void AudioDataConverters::convertInt32LEToFloat (const void* const source, float void AudioDataConverters::convertInt32BEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) { const float scale = 1.0f / 0x7fffffff; - const char* intData = static_cast (source); + const char* intData = static_cast (source); if (source != (void*) dest || srcBytesPerSample >= 4) { @@ -361,7 +361,7 @@ void AudioDataConverters::convertInt32BEToFloat (const void* const source, float void AudioDataConverters::convertFloat32LEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) { - const char* s = static_cast (source); + const char* s = static_cast (source); for (int i = 0; i < numSamples; ++i) { @@ -378,7 +378,7 @@ void AudioDataConverters::convertFloat32LEToFloat (const void* const source, flo void AudioDataConverters::convertFloat32BEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) { - const char* s = static_cast (source); + const char* s = static_cast (source); for (int i = 0; i < numSamples; ++i) { diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.cpp b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.cpp index 72d7f0d..15b59da 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.cpp @@ -91,7 +91,7 @@ AudioSampleBuffer::AudioSampleBuffer (float* const* dataToReferTo, allocatedBytes (0) { jassert (dataToReferTo != nullptr); - jassert (numChans >= 0); + jassert (numChans >= 0 && numSamples >= 0); allocateChannels (dataToReferTo, 0); } @@ -105,7 +105,7 @@ AudioSampleBuffer::AudioSampleBuffer (float* const* dataToReferTo, isClear (false) { jassert (dataToReferTo != nullptr); - jassert (numChans >= 0); + jassert (numChans >= 0 && startSample >= 0 && numSamples >= 0); allocateChannels (dataToReferTo, startSample); } @@ -114,7 +114,7 @@ void AudioSampleBuffer::setDataToReferTo (float** dataToReferTo, const int newNumSamples) noexcept { jassert (dataToReferTo != nullptr); - jassert (newNumChannels >= 0); + jassert (newNumChannels >= 0 && newNumSamples >= 0); allocatedBytes = 0; allocatedData.free(); @@ -128,6 +128,8 @@ void AudioSampleBuffer::setDataToReferTo (float** dataToReferTo, void AudioSampleBuffer::allocateChannels (float* const* const dataToReferTo, int offset) { + jassert (offset >= 0); + // (try to avoid doing a malloc here, as that'll blow up things like Pro-Tools) if (numChannels < (int) numElementsInArray (preallocatedChannelSpace)) { @@ -163,6 +165,8 @@ AudioSampleBuffer& AudioSampleBuffer::operator= (const AudioSampleBuffer& other) } else { + isClear = false; + for (int i = 0; i < numChannels; ++i) FloatVectorOperations::copy (channels[i], other.channels[i], size); } diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp index 1880b27..2fc6898 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp @@ -24,8 +24,9 @@ namespace FloatVectorHelpers { - #define JUCE_INCREMENT_SRC_DEST dest += (16 / sizeof (*dest)); src += (16 / sizeof (*dest)); - #define JUCE_INCREMENT_DEST dest += (16 / sizeof (*dest)); + #define JUCE_INCREMENT_SRC_DEST dest += (16 / sizeof (*dest)); src += (16 / sizeof (*dest)); + #define JUCE_INCREMENT_SRC1_SRC2_DEST dest += (16 / sizeof (*dest)); src1 += (16 / sizeof (*dest)); src2 += (16 / sizeof (*dest)); + #define JUCE_INCREMENT_DEST dest += (16 / sizeof (*dest)); #if JUCE_USE_SSE_INTRINSICS static bool sse2Present = false; @@ -122,6 +123,17 @@ namespace FloatVectorHelpers } \ JUCE_FINISH_VEC_OP (normalOp) + #define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST(normalOp, vecOp, locals, increment, setupOp) \ + JUCE_BEGIN_VEC_OP \ + setupOp \ + { \ + Mode::ParallelType (&loadSrc1) (const Mode::Type* v) = FloatVectorHelpers::isAligned (src1) ? Mode::loadA : Mode::loadU; \ + Mode::ParallelType (&loadSrc2) (const Mode::Type* v) = FloatVectorHelpers::isAligned (src2) ? Mode::loadA : Mode::loadU; \ + void (&storeDst) (Mode::Type* dest, Mode::ParallelType a) = FloatVectorHelpers::isAligned (dest) ? Mode::storeA : Mode::storeU; \ + JUCE_VEC_LOOP_TWO_SOURCES (vecOp, loadSrc1, loadSrc2, storeDst, locals, increment); \ + } \ + JUCE_FINISH_VEC_OP (normalOp) + //============================================================================== #elif JUCE_USE_ARM_NEON @@ -193,6 +205,12 @@ namespace FloatVectorHelpers JUCE_VEC_LOOP (vecOp, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \ JUCE_FINISH_VEC_OP (normalOp) + #define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST(normalOp, vecOp, locals, increment, setupOp) \ + JUCE_BEGIN_VEC_OP \ + setupOp \ + JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \ + JUCE_FINISH_VEC_OP (normalOp) + //============================================================================== #else #define JUCE_PERFORM_VEC_OP_DEST(normalOp, vecOp, locals, setupOp) \ @@ -201,6 +219,8 @@ namespace FloatVectorHelpers #define JUCE_PERFORM_VEC_OP_SRC_DEST(normalOp, vecOp, locals, increment, setupOp) \ for (int i = 0; i < num; ++i) normalOp; + #define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST(normalOp, vecOp, locals, increment, setupOp) \ + for (int i = 0; i < num; ++i) normalOp; #endif //============================================================================== @@ -212,10 +232,19 @@ namespace FloatVectorHelpers increment; \ } + #define JUCE_VEC_LOOP_TWO_SOURCES(vecOp, src1Load, src2Load, dstStore, locals, increment) \ + for (int i = 0; i < numLongOps; ++i) \ + { \ + locals (src1Load, src2Load); \ + dstStore (dest, vecOp); \ + increment; \ + } + #define JUCE_LOAD_NONE(srcLoad, dstLoad) - #define JUCE_LOAD_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest); - #define JUCE_LOAD_SRC(srcLoad, dstLoad) const Mode::ParallelType s = srcLoad (src); - #define JUCE_LOAD_SRC_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest), s = srcLoad (src); + #define JUCE_LOAD_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest); + #define JUCE_LOAD_SRC(srcLoad, dstLoad) const Mode::ParallelType s = srcLoad (src); + #define JUCE_LOAD_SRC1_SRC2(src1Load, src2Load) const Mode::ParallelType s1 = src1Load (src1), s2 = src2Load (src2); + #define JUCE_LOAD_SRC_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest), s = srcLoad (src); #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON template struct ModeType { typedef BasicOps32 Mode; }; @@ -229,7 +258,7 @@ namespace FloatVectorHelpers static Type findMinOrMax (const Type* src, int num, const bool isMinimum) noexcept { - const int numLongOps = num / Mode::numParallel; + int numLongOps = num / Mode::numParallel; #if JUCE_USE_SSE_INTRINSICS if (numLongOps > 1 && isSSE2Available()) @@ -246,7 +275,7 @@ namespace FloatVectorHelpers if (isMinimum) { - for (int i = 1; i < numLongOps; ++i) + while (--numLongOps > 0) { src += Mode::numParallel; val = Mode::min (val, Mode::loadA (src)); @@ -254,7 +283,7 @@ namespace FloatVectorHelpers } else { - for (int i = 1; i < numLongOps; ++i) + while (--numLongOps > 0) { src += Mode::numParallel; val = Mode::max (val, Mode::loadA (src)); @@ -268,7 +297,7 @@ namespace FloatVectorHelpers if (isMinimum) { - for (int i = 1; i < numLongOps; ++i) + while (--numLongOps > 0) { src += Mode::numParallel; val = Mode::min (val, Mode::loadU (src)); @@ -276,7 +305,7 @@ namespace FloatVectorHelpers } else { - for (int i = 1; i < numLongOps; ++i) + while (--numLongOps > 0) { src += Mode::numParallel; val = Mode::max (val, Mode::loadU (src)); @@ -288,6 +317,7 @@ namespace FloatVectorHelpers : Mode::max (val); num &= (Mode::numParallel - 1); + src += Mode::numParallel; for (int i = 0; i < num; ++i) result = isMinimum ? jmin (result, src[i]) @@ -302,7 +332,7 @@ namespace FloatVectorHelpers static Range findMinAndMax (const Type* src, int num) noexcept { - const int numLongOps = num / Mode::numParallel; + int numLongOps = num / Mode::numParallel; #if JUCE_USE_SSE_INTRINSICS if (numLongOps > 1 && isSSE2Available()) @@ -318,7 +348,7 @@ namespace FloatVectorHelpers mn = Mode::loadA (src); mx = mn; - for (int i = 1; i < numLongOps; ++i) + while (--numLongOps > 0) { src += Mode::numParallel; const ParallelType v = Mode::loadA (src); @@ -332,7 +362,7 @@ namespace FloatVectorHelpers mn = Mode::loadU (src); mx = mn; - for (int i = 1; i < numLongOps; ++i) + while (--numLongOps > 0) { src += Mode::numParallel; const ParallelType v = Mode::loadU (src); @@ -344,7 +374,9 @@ namespace FloatVectorHelpers Range result (Mode::min (mn), Mode::max (mx)); - num &= 3; + num &= (Mode::numParallel - 1); + src += Mode::numParallel; + for (int i = 0; i < num; ++i) result = result.getUnionWith (src[i]); @@ -409,7 +441,7 @@ void JUCE_CALLTYPE FloatVectorOperations::copy (double* dest, const double* src, void JUCE_CALLTYPE FloatVectorOperations::copyWithMultiply (float* dest, const float* src, float multiplier, int num) noexcept { #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vsmul (src, 1, &multiplier, dest, 1, num); + vDSP_vsmul (src, 1, &multiplier, dest, 1, (vDSP_Length) num); #else JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier, Mode::mul (mult, s), JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, @@ -420,7 +452,7 @@ void JUCE_CALLTYPE FloatVectorOperations::copyWithMultiply (float* dest, const f void JUCE_CALLTYPE FloatVectorOperations::copyWithMultiply (double* dest, const double* src, double multiplier, int num) noexcept { #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vsmulD (src, 1, &multiplier, dest, 1, num); + vDSP_vsmulD (src, 1, &multiplier, dest, 1, (vDSP_Length) num); #else JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier, Mode::mul (mult, s), JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, @@ -440,10 +472,32 @@ void JUCE_CALLTYPE FloatVectorOperations::add (double* dest, double amount, int const Mode::ParallelType amountToAdd = Mode::load1 (amount);) } +void JUCE_CALLTYPE FloatVectorOperations::add (float* dest, float* src, float amount, int num) noexcept +{ + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vsadd (src, 1, &amount, dest, 1, (vDSP_Length) num); + #else + JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] + amount, Mode::add (am, s), + JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, + const Mode::ParallelType am = Mode::load1 (amount);) + #endif +} + +void JUCE_CALLTYPE FloatVectorOperations::add (double* dest, double* src, double amount, int num) noexcept +{ + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vsaddD (src, 1, &amount, dest, 1, (vDSP_Length) num); + #else + JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] + amount, Mode::add (am, s), + JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, + const Mode::ParallelType am = Mode::load1 (amount);) + #endif +} + void JUCE_CALLTYPE FloatVectorOperations::add (float* dest, const float* src, int num) noexcept { #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vadd (src, 1, dest, 1, dest, 1, num); + vDSP_vadd (src, 1, dest, 1, dest, 1, (vDSP_Length) num); #else JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i], Mode::add (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, ) #endif @@ -452,16 +506,34 @@ void JUCE_CALLTYPE FloatVectorOperations::add (float* dest, const float* src, in void JUCE_CALLTYPE FloatVectorOperations::add (double* dest, const double* src, int num) noexcept { #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vaddD (src, 1, dest, 1, dest, 1, num); + vDSP_vaddD (src, 1, dest, 1, dest, 1, (vDSP_Length) num); #else JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i], Mode::add (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, ) #endif } +void JUCE_CALLTYPE FloatVectorOperations::add (float* dest, const float* src1, const float* src2, int num) noexcept +{ + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vadd (src1, 1, src2, 1, dest, 1, (vDSP_Length) num); + #else + JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] + src2[i], Mode::add (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, ) + #endif +} + +void JUCE_CALLTYPE FloatVectorOperations::add (double* dest, const double* src1, const double* src2, int num) noexcept +{ + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vaddD (src1, 1, src2, 1, dest, 1, (vDSP_Length) num); + #else + JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] + src2[i], Mode::add (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, ) + #endif +} + void JUCE_CALLTYPE FloatVectorOperations::subtract (float* dest, const float* src, int num) noexcept { #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vsub (src, 1, dest, 1, dest, 1, num); + vDSP_vsub (src, 1, dest, 1, dest, 1, (vDSP_Length) num); #else JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] -= src[i], Mode::sub (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, ) #endif @@ -470,12 +542,30 @@ void JUCE_CALLTYPE FloatVectorOperations::subtract (float* dest, const float* sr void JUCE_CALLTYPE FloatVectorOperations::subtract (double* dest, const double* src, int num) noexcept { #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vsubD (src, 1, dest, 1, dest, 1, num); + vDSP_vsubD (src, 1, dest, 1, dest, 1, (vDSP_Length) num); #else JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] -= src[i], Mode::sub (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, ) #endif } +void JUCE_CALLTYPE FloatVectorOperations::subtract (float* dest, const float* src1, const float* src2, int num) noexcept +{ + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vsub (src2, 1, src1, 1, dest, 1, (vDSP_Length) num); + #else + JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] - src2[i], Mode::sub (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, ) + #endif +} + +void JUCE_CALLTYPE FloatVectorOperations::subtract (double* dest, const double* src1, const double* src2, int num) noexcept +{ + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vsubD (src2, 1, src1, 1, dest, 1, (vDSP_Length) num); + #else + JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] - src2[i], Mode::sub (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, ) + #endif +} + void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (float* dest, const float* src, float multiplier, int num) noexcept { JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i] * multiplier, Mode::add (d, Mode::mul (mult, s)), @@ -493,7 +583,7 @@ void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (double* dest, const d void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, const float* src, int num) noexcept { #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vmul (src, 1, dest, 1, dest, 1, num); + vDSP_vmul (src, 1, dest, 1, dest, 1, (vDSP_Length) num); #else JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] *= src[i], Mode::mul (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, ) #endif @@ -502,16 +592,34 @@ void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, const float* sr void JUCE_CALLTYPE FloatVectorOperations::multiply (double* dest, const double* src, int num) noexcept { #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vmulD (src, 1, dest, 1, dest, 1, num); + vDSP_vmulD (src, 1, dest, 1, dest, 1, (vDSP_Length) num); #else JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] *= src[i], Mode::mul (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, ) #endif } +void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, const float* src1, const float* src2, int num) noexcept +{ + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vmul (src1, 1, src2, 1, dest, 1, (vDSP_Length) num); + #else + JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] * src2[i], Mode::mul (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, ) + #endif +} + +void JUCE_CALLTYPE FloatVectorOperations::multiply (double* dest, const double* src1, const double* src2, int num) noexcept +{ + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vmulD (src1, 1, src2, 1, dest, 1, (vDSP_Length) num); + #else + JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] * src2[i], Mode::mul (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, ) + #endif +} + void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, float multiplier, int num) noexcept { #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vsmul (dest, 1, &multiplier, dest, 1, num); + vDSP_vsmul (dest, 1, &multiplier, dest, 1, (vDSP_Length) num); #else JUCE_PERFORM_VEC_OP_DEST (dest[i] *= multiplier, Mode::mul (d, mult), JUCE_LOAD_DEST, const Mode::ParallelType mult = Mode::load1 (multiplier);) @@ -521,13 +629,27 @@ void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, float multiplie void JUCE_CALLTYPE FloatVectorOperations::multiply (double* dest, double multiplier, int num) noexcept { #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vsmulD (dest, 1, &multiplier, dest, 1, num); + vDSP_vsmulD (dest, 1, &multiplier, dest, 1, (vDSP_Length) num); #else JUCE_PERFORM_VEC_OP_DEST (dest[i] *= multiplier, Mode::mul (d, mult), JUCE_LOAD_DEST, const Mode::ParallelType mult = Mode::load1 (multiplier);) #endif } +void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, const float* src, float multiplier, int num) noexcept +{ + JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier, Mode::mul (mult, s), + JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, + const Mode::ParallelType mult = Mode::load1 (multiplier);) +} + +void JUCE_CALLTYPE FloatVectorOperations::multiply (double* dest, const double* src, double multiplier, int num) noexcept +{ + JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier, Mode::mul (mult, s), + JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, + const Mode::ParallelType mult = Mode::load1 (multiplier);) +} + void FloatVectorOperations::negate (float* dest, const float* src, int num) noexcept { #if JUCE_USE_VDSP_FRAMEWORK @@ -640,8 +762,8 @@ public: const int range = random.nextBool() ? 500 : 10; const int num = random.nextInt (range) + 1; - HeapBlock buffer1 (num + 16), buffer2 (num + 16); - HeapBlock buffer3 (num + 16); + HeapBlock buffer1 ((size_t) num + 16), buffer2 ((size_t) num + 16); + HeapBlock buffer3 ((size_t) num + 16); #if JUCE_ARM ValueType* const data1 = buffer1; diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h index 54821d2..0b3fcb6 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h +++ b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h @@ -65,18 +65,36 @@ public: /** Adds a fixed value to the destination values. */ static void JUCE_CALLTYPE add (double* dest, double amountToAdd, int numValues) noexcept; + /** Adds a fixed value to each source value and stores it in the destination array. */ + static void JUCE_CALLTYPE add (float* dest, float* src, float amount, int numValues) noexcept; + + /** Adds a fixed value to each source value and stores it in the destination array. */ + static void JUCE_CALLTYPE add (double* dest, double* src, double amount, int numValues) noexcept; + /** Adds the source values to the destination values. */ static void JUCE_CALLTYPE add (float* dest, const float* src, int numValues) noexcept; /** Adds the source values to the destination values. */ static void JUCE_CALLTYPE add (double* dest, const double* src, int numValues) noexcept; + /** Adds each source1 value to the corresponding source2 value and stores the result in the destination array. */ + static void JUCE_CALLTYPE add (float* dest, const float* src1, const float* src2, int num) noexcept; + + /** Adds each source1 value to the corresponding source2 value and stores the result in the destination array. */ + static void JUCE_CALLTYPE add (double* dest, const double* src1, const double* src2, int num) noexcept; + /** Subtracts the source values from the destination values. */ static void JUCE_CALLTYPE subtract (float* dest, const float* src, int numValues) noexcept; /** Subtracts the source values from the destination values. */ static void JUCE_CALLTYPE subtract (double* dest, const double* src, int numValues) noexcept; + /** Subtracts each source2 value from the corresponding source1 value and stores the result in the destination array. */ + static void JUCE_CALLTYPE subtract (float* dest, const float* src1, const float* src2, int num) noexcept; + + /** Subtracts each source2 value from the corresponding source1 value and stores the result in the destination array. */ + static void JUCE_CALLTYPE subtract (double* dest, const double* src1, const double* src2, int num) noexcept; + /** Multiplies each source value by the given multiplier, then adds it to the destination value. */ static void JUCE_CALLTYPE addWithMultiply (float* dest, const float* src, float multiplier, int numValues) noexcept; @@ -89,12 +107,24 @@ public: /** Multiplies the destination values by the source values. */ static void JUCE_CALLTYPE multiply (double* dest, const double* src, int numValues) noexcept; + /** Multiplies each source1 value by the correspinding source2 value, then stores it in the destination array. */ + static void JUCE_CALLTYPE multiply (float* dest, const float* src1, const float* src2, int numValues) noexcept; + + /** Multiplies each source1 value by the correspinding source2 value, then stores it in the destination array. */ + static void JUCE_CALLTYPE multiply (double* dest, const double* src1, const double* src2, int numValues) noexcept; + /** Multiplies each of the destination values by a fixed multiplier. */ static void JUCE_CALLTYPE multiply (float* dest, float multiplier, int numValues) noexcept; /** Multiplies each of the destination values by a fixed multiplier. */ static void JUCE_CALLTYPE multiply (double* dest, double multiplier, int numValues) noexcept; + /** Multiplies each of the source values by a fixed multiplier and stores the result in the destination array. */ + static void JUCE_CALLTYPE multiply (float* dest, const float* src, float multiplier, int num) noexcept; + + /** Multiplies each of the source values by a fixed multiplier and stores the result in the destination array. */ + static void JUCE_CALLTYPE multiply (double* dest, const double* src, double multiplier, int num) noexcept; + /** Copies a source vector to a destination, negating each value. */ static void JUCE_CALLTYPE negate (float* dest, const float* src, int numValues) noexcept; diff --git a/JuceLibraryCode/modules/juce_audio_basics/effects/juce_Reverb.h b/JuceLibraryCode/modules/juce_audio_basics/effects/juce_Reverb.h index fceb0a0..53457a6 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/effects/juce_Reverb.h +++ b/JuceLibraryCode/modules/juce_audio_basics/effects/juce_Reverb.h @@ -181,7 +181,7 @@ public: for (int j = 0; j < numAllPasses; ++j) // run the allpass filters in series output = allPass[0][j].process (output); - samples[i] = output * wet1 + input * dry; + samples[i] = output * wet1 + samples[i] * dry; } } diff --git a/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.cpp b/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.cpp index dcd53cd..da98659 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.cpp @@ -57,7 +57,9 @@ #endif #if (JUCE_MAC || JUCE_IOS) && JUCE_USE_VDSP_FRAMEWORK + #define Point CarbonDummyPointName // (workaround to avoid definition of "Point" by old Carbon headers) #include + #undef Point #else #undef JUCE_USE_VDSP_FRAMEWORK #endif diff --git a/JuceLibraryCode/modules/juce_audio_basics/juce_module_info b/JuceLibraryCode/modules/juce_audio_basics/juce_module_info index 624c49d..c9cdd3d 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.5", + "version": "3.0.8", "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_MidiBuffer.cpp b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiBuffer.cpp index 0a6a1f9..43ab4c1 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiBuffer.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiBuffer.cpp @@ -210,7 +210,7 @@ bool MidiBuffer::Iterator::getNextEvent (const uint8* &midiData, int& numBytes, const int itemSize = MidiBufferHelpers::getEventDataSize (data); numBytes = itemSize; midiData = data + sizeof (int32) + sizeof (uint16); - data += sizeof (int32) + sizeof (uint16) + itemSize; + data += sizeof (int32) + sizeof (uint16) + (size_t) itemSize; return true; } @@ -223,7 +223,7 @@ bool MidiBuffer::Iterator::getNextEvent (MidiMessage& result, int& samplePositio samplePosition = MidiBufferHelpers::getEventTime (data); const int itemSize = MidiBufferHelpers::getEventDataSize (data); result = MidiMessage (data + sizeof (int32) + sizeof (uint16), itemSize, samplePosition); - data += sizeof (int32) + sizeof (uint16) + itemSize; + data += sizeof (int32) + sizeof (uint16) + (size_t) itemSize; return true; } diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiBuffer.h b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiBuffer.h index 7dfc458..ecbc56a 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiBuffer.h +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiBuffer.h @@ -186,9 +186,10 @@ public: /** Retrieves a copy of the next event from the buffer. - @param result on return, this will be the message (the MidiMessage's timestamp - is not set) - @param samplePosition on return, this will be the position of the event + @param result on return, this will be the message. The MidiMessage's timestamp + is set to the same value as samplePosition. + @param samplePosition on return, this will be the position of the event, as a + sample index in the buffer @returns true if an event was found, or false if the iterator has reached the end of the buffer */ @@ -203,7 +204,8 @@ public: temporarily until the MidiBuffer is altered. @param numBytesOfMidiData on return, this is the number of bytes of data used by the midi message - @param samplePosition on return, this will be the position of the event + @param samplePosition on return, this will be the position of the event, as a + sample index in the buffer @returns true if an event was found, or false if the iterator has reached the end of the buffer */ diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.cpp b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.cpp index 18733a3..07e2ccd 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.cpp @@ -129,7 +129,7 @@ MidiMessage::MidiMessage (const MidiMessage& other) { if (other.allocatedData != nullptr) { - allocatedData.malloc (size); + allocatedData.malloc ((size_t) size); memcpy (allocatedData, other.allocatedData, (size_t) size); } else @@ -143,7 +143,7 @@ MidiMessage::MidiMessage (const MidiMessage& other, const double newTimeStamp) { if (other.allocatedData != nullptr) { - allocatedData.malloc (size); + allocatedData.malloc ((size_t) size); memcpy (allocatedData, other.allocatedData, (size_t) size); } else @@ -255,7 +255,7 @@ MidiMessage& MidiMessage::operator= (const MidiMessage& other) if (other.allocatedData != nullptr) { - allocatedData.malloc (size); + allocatedData.malloc ((size_t) size); memcpy (allocatedData, other.allocatedData, (size_t) size); } else @@ -297,7 +297,7 @@ uint8* MidiMessage::allocateSpace (int bytes) { if (bytes > 4) { - allocatedData.malloc (bytes); + allocatedData.malloc ((size_t) bytes); return allocatedData; } @@ -661,7 +661,7 @@ String MidiMessage::getTextFromTextMetaEvent() const MidiMessage MidiMessage::textMetaEvent (int type, StringRef text) { - jassert (type > 0 && type < 16) + jassert (type > 0 && type < 16); MidiMessage result; diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp index effefbb..94a6b9b 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp @@ -29,6 +29,7 @@ MidiMessageSequence::MidiMessageSequence() MidiMessageSequence::MidiMessageSequence (const MidiMessageSequence& other) { list.addCopiesOf (other.list); + updateMatchedPairs(); } MidiMessageSequence& MidiMessageSequence::operator= (const MidiMessageSequence& other) @@ -52,17 +53,17 @@ void MidiMessageSequence::clear() list.clear(); } -int MidiMessageSequence::getNumEvents() const +int MidiMessageSequence::getNumEvents() const noexcept { return list.size(); } -MidiMessageSequence::MidiEventHolder* MidiMessageSequence::getEventPointer (const int index) const +MidiMessageSequence::MidiEventHolder* MidiMessageSequence::getEventPointer (const int index) const noexcept { return list [index]; } -double MidiMessageSequence::getTimeOfMatchingKeyUp (const int index) const +double MidiMessageSequence::getTimeOfMatchingKeyUp (const int index) const noexcept { if (const MidiEventHolder* const meh = list [index]) if (meh->noteOffObject != nullptr) @@ -71,7 +72,7 @@ double MidiMessageSequence::getTimeOfMatchingKeyUp (const int index) const return 0.0; } -int MidiMessageSequence::getIndexOfMatchingKeyUp (const int index) const +int MidiMessageSequence::getIndexOfMatchingKeyUp (const int index) const noexcept { if (const MidiEventHolder* const meh = list [index]) return list.indexOf (meh->noteOffObject); @@ -79,12 +80,12 @@ int MidiMessageSequence::getIndexOfMatchingKeyUp (const int index) const return -1; } -int MidiMessageSequence::getIndexOf (MidiEventHolder* const event) const +int MidiMessageSequence::getIndexOf (MidiEventHolder* const event) const noexcept { return list.indexOf (event); } -int MidiMessageSequence::getNextIndexAtTime (const double timeStamp) const +int MidiMessageSequence::getNextIndexAtTime (const double timeStamp) const noexcept { const int numEvents = list.size(); @@ -97,17 +98,17 @@ int MidiMessageSequence::getNextIndexAtTime (const double timeStamp) const } //============================================================================== -double MidiMessageSequence::getStartTime() const +double MidiMessageSequence::getStartTime() const noexcept { return getEventTime (0); } -double MidiMessageSequence::getEndTime() const +double MidiMessageSequence::getEndTime() const noexcept { return getEventTime (list.size() - 1); } -double MidiMessageSequence::getEventTime (const int index) const +double MidiMessageSequence::getEventTime (const int index) const noexcept { if (const MidiEventHolder* const meh = list [index]) return meh->message.getTimeStamp(); @@ -181,13 +182,13 @@ void MidiMessageSequence::addSequence (const MidiMessageSequence& other, } //============================================================================== -void MidiMessageSequence::sort() +void MidiMessageSequence::sort() noexcept { MidiMessageSequenceSorter sorter; list.sort (sorter, true); } -void MidiMessageSequence::updateMatchedPairs() +void MidiMessageSequence::updateMatchedPairs() noexcept { for (int i = 0; i < list.size(); ++i) { @@ -226,7 +227,7 @@ void MidiMessageSequence::updateMatchedPairs() } } -void MidiMessageSequence::addTimeToMessages (const double delta) +void MidiMessageSequence::addTimeToMessages (const double delta) noexcept { for (int i = list.size(); --i >= 0;) { diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.h b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.h index d91ed8b..b62940c 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.h +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.h @@ -91,47 +91,47 @@ public: void clear(); /** Returns the number of events in the sequence. */ - int getNumEvents() const; + int getNumEvents() const noexcept; /** Returns a pointer to one of the events. */ - MidiEventHolder* getEventPointer (int index) const; + MidiEventHolder* getEventPointer (int index) const noexcept; /** Returns the time of the note-up that matches the note-on at this index. If the event at this index isn't a note-on, it'll just return 0. @see MidiMessageSequence::MidiEventHolder::noteOffObject */ - double getTimeOfMatchingKeyUp (int index) const; + double getTimeOfMatchingKeyUp (int index) const noexcept; /** Returns the index of the note-up that matches the note-on at this index. If the event at this index isn't a note-on, it'll just return -1. @see MidiMessageSequence::MidiEventHolder::noteOffObject */ - int getIndexOfMatchingKeyUp (int index) const; + int getIndexOfMatchingKeyUp (int index) const noexcept; /** Returns the index of an event. */ - int getIndexOf (MidiEventHolder* event) const; + int getIndexOf (MidiEventHolder* event) const noexcept; /** Returns the index of the first event on or after the given timestamp. If the time is beyond the end of the sequence, this will return the number of events. */ - int getNextIndexAtTime (double timeStamp) const; + int getNextIndexAtTime (double timeStamp) const noexcept; //============================================================================== /** Returns the timestamp of the first event in the sequence. @see getEndTime */ - double getStartTime() const; + double getStartTime() const noexcept; /** Returns the timestamp of the last event in the sequence. @see getStartTime */ - double getEndTime() const; + double getEndTime() const noexcept; /** Returns the timestamp of the event at a given index. If the index is out-of-range, this will return 0.0 */ - double getEventTime (int index) const; + double getEventTime (int index) const noexcept; //============================================================================== /** Inserts a midi message into the sequence. @@ -185,13 +185,13 @@ public: will scan the list and make sure all the note-offs in the MidiEventHolder structures are pointing at the correct ones. */ - void updateMatchedPairs(); + void updateMatchedPairs() noexcept; /** Forces a sort of the sequence. You may need to call this if you've manually modified the timestamps of some events such that the overall order now needs updating. */ - void sort(); + void sort() noexcept; //============================================================================== /** Copies all the messages for a particular midi channel to another sequence. @@ -224,7 +224,7 @@ public: /** Adds an offset to the timestamps of all events in the sequence. @param deltaTime the amount to add to each timestamp. */ - void addTimeToMessages (double deltaTime); + void addTimeToMessages (double deltaTime) noexcept; //============================================================================== /** Scans through the sequence to determine the state of any midi controllers at diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp index 52fc730..6a0704e 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp @@ -47,23 +47,28 @@ void ResamplingAudioSource::setResamplingRatio (const double samplesInPerOutputS ratio = jmax (0.0, samplesInPerOutputSample); } -void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected, - double sampleRate) +void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected, double sampleRate) { const SpinLock::ScopedLockType sl (ratioLock); input->prepareToPlay (samplesPerBlockExpected, sampleRate); buffer.setSize (numChannels, roundToInt (samplesPerBlockExpected * ratio) + 32); - buffer.clear(); - sampsInBuffer = 0; - bufferPos = 0; - subSampleOffset = 0.0; filterStates.calloc ((size_t) numChannels); srcBuffers.calloc ((size_t) numChannels); destBuffers.calloc ((size_t) numChannels); createLowPass (ratio); + + flushBuffers(); +} + +void ResamplingAudioSource::flushBuffers() +{ + buffer.clear(); + bufferPos = 0; + sampsInBuffer = 0; + subSampleOffset = 0.0; resetFilters(); } @@ -225,7 +230,8 @@ void ResamplingAudioSource::setFilterCoefficients (double c1, double c2, double void ResamplingAudioSource::resetFilters() { - filterStates.clear ((size_t) numChannels); + if (filterStates != nullptr) + filterStates.clear ((size_t) numChannels); } void ResamplingAudioSource::applyFilter (float* samples, int num, FilterState& fs) diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.h b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.h index 20886e6..09d27a8 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.h +++ b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.h @@ -66,6 +66,9 @@ public: */ double getResamplingRatio() const noexcept { return ratio; } + /** Clears any buffers and filters that the resampler is using. */ + void flushBuffers(); + //============================================================================== void prepareToPlay (int samplesPerBlockExpected, double sampleRate) override; void releaseResources() override; diff --git a/JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp b/JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp index 7a72d00..6a889b4 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp @@ -163,10 +163,7 @@ void Synthesiser::renderNextBlock (AudioSampleBuffer& outputBuffer, const MidiBu : numSamples; if (numThisTime > 0) - { - for (int i = voices.size(); --i >= 0;) - voices.getUnchecked (i)->renderNextBlock (outputBuffer, startSample, numThisTime); - } + renderVoices (outputBuffer, startSample, numThisTime); if (useEvent) handleMidiEvent (m); @@ -176,6 +173,12 @@ void Synthesiser::renderNextBlock (AudioSampleBuffer& outputBuffer, const MidiBu } } +void Synthesiser::renderVoices (AudioSampleBuffer& buffer, int startSample, int numSamples) +{ + for (int i = voices.size(); --i >= 0;) + voices.getUnchecked (i)->renderNextBlock (buffer, startSample, numSamples); +} + void Synthesiser::handleMidiEvent (const MidiMessage& m) { if (m.isNoteOn()) @@ -184,7 +187,7 @@ void Synthesiser::handleMidiEvent (const MidiMessage& m) } else if (m.isNoteOff()) { - noteOff (m.getChannel(), m.getNoteNumber(), true); + noteOff (m.getChannel(), m.getNoteNumber(), m.getFloatVelocity(), true); } else if (m.isAllNotesOff() || m.isAllSoundOff()) { @@ -230,10 +233,10 @@ void Synthesiser::noteOn (const int midiChannel, if (voice->getCurrentlyPlayingNote() == midiNoteNumber && voice->isPlayingChannel (midiChannel)) - stopVoice (voice, true); + stopVoice (voice, 1.0f, true); } - startVoice (findFreeVoice (sound, shouldStealNotes), + startVoice (findFreeVoice (sound, midiChannel, midiNoteNumber, shouldStealNotes), sound, midiChannel, midiNoteNumber, velocity); } } @@ -248,7 +251,7 @@ void Synthesiser::startVoice (SynthesiserVoice* const voice, if (voice != nullptr && sound != nullptr) { if (voice->currentlyPlayingSound != nullptr) - voice->stopNote (false); + voice->stopNote (0.0f, false); voice->startNote (midiNoteNumber, velocity, sound, lastPitchWheelValues [midiChannel - 1]); @@ -261,11 +264,11 @@ void Synthesiser::startVoice (SynthesiserVoice* const voice, } } -void Synthesiser::stopVoice (SynthesiserVoice* voice, const bool allowTailOff) +void Synthesiser::stopVoice (SynthesiserVoice* voice, float velocity, const bool allowTailOff) { jassert (voice != nullptr); - voice->stopNote (allowTailOff); + voice->stopNote (velocity, allowTailOff); // the subclass MUST call clearCurrentNote() if it's not tailing off! RTFM for stopNote()! jassert (allowTailOff || (voice->getCurrentlyPlayingNote() < 0 && voice->getCurrentlyPlayingSound() == 0)); @@ -273,6 +276,7 @@ void Synthesiser::stopVoice (SynthesiserVoice* voice, const bool allowTailOff) void Synthesiser::noteOff (const int midiChannel, const int midiNoteNumber, + const float velocity, const bool allowTailOff) { const ScopedLock sl (lock); @@ -291,7 +295,7 @@ void Synthesiser::noteOff (const int midiChannel, voice->keyIsDown = false; if (! (sustainPedalsDown [midiChannel] || voice->sostenutoPedalDown)) - stopVoice (voice, allowTailOff); + stopVoice (voice, velocity, allowTailOff); } } } @@ -307,7 +311,7 @@ void Synthesiser::allNotesOff (const int midiChannel, const bool allowTailOff) SynthesiserVoice* const voice = voices.getUnchecked (i); if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel)) - voice->stopNote (allowTailOff); + voice->stopNote (1.0f, allowTailOff); } sustainPedalsDown.clear(); @@ -379,7 +383,7 @@ void Synthesiser::handleSustainPedal (int midiChannel, bool isDown) SynthesiserVoice* const voice = voices.getUnchecked (i); if (voice->isPlayingChannel (midiChannel) && ! voice->keyIsDown) - stopVoice (voice, true); + stopVoice (voice, 1.0f, true); } sustainPedalsDown.clearBit (midiChannel); @@ -400,7 +404,7 @@ void Synthesiser::handleSostenutoPedal (int midiChannel, bool isDown) if (isDown) voice->sostenutoPedalDown = true; else if (voice->sostenutoPedalDown) - stopVoice (voice, true); + stopVoice (voice, 1.0f, true); } } } @@ -412,7 +416,9 @@ void Synthesiser::handleSoftPedal (int midiChannel, bool /*isDown*/) } //============================================================================== -SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay, const bool stealIfNoneAvailable) const +SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay, + int midiChannel, int midiNoteNumber, + const bool stealIfNoneAvailable) const { const ScopedLock sl (lock); @@ -425,25 +431,68 @@ SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay, con } if (stealIfNoneAvailable) - return findVoiceToSteal (soundToPlay); + return findVoiceToSteal (soundToPlay, midiChannel, midiNoteNumber); return nullptr; } -SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay) const +struct VoiceAgeSorter { - // currently this just steals the one that's been playing the longest, but could be made a bit smarter.. - SynthesiserVoice* oldest = nullptr; + static int compareElements (SynthesiserVoice* v1, SynthesiserVoice* v2) noexcept + { + return v1->wasStartedBefore (*v2) ? 1 : (v2->wasStartedBefore (*v1) ? -1 : 0); + } +}; + +SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay, + int /*midiChannel*/, int midiNoteNumber) const +{ + SynthesiserVoice* bottom = nullptr; + SynthesiserVoice* top = nullptr; + + // this is a list of voices we can steal, sorted by how long they've been running + Array usableVoices; + usableVoices.ensureStorageAllocated (voices.size()); for (int i = 0; i < voices.size(); ++i) { SynthesiserVoice* const voice = voices.getUnchecked (i); - if (voice->canPlaySound (soundToPlay) - && (oldest == nullptr || voice->wasStartedBefore (*oldest))) - oldest = voice; + if (voice->canPlaySound (soundToPlay)) + { + VoiceAgeSorter sorter; + usableVoices.addSorted (sorter, voice); + + const int note = voice->getCurrentlyPlayingNote(); + + if (bottom == nullptr || note < bottom->getCurrentlyPlayingNote()) + bottom = voice; + + if (top == nullptr || note > top->getCurrentlyPlayingNote()) + top = voice; + } } - jassert (oldest != nullptr); - return oldest; + jassert (bottom != nullptr && top != nullptr); + + // The oldest note that's playing with the target pitch playing is ideal.. + for (int i = 0; i < usableVoices.size(); ++i) + { + SynthesiserVoice* const voice = usableVoices.getUnchecked (i); + + if (voice->getCurrentlyPlayingNote() == midiNoteNumber) + return voice; + } + + // ..otherwise, look for the oldest note that isn't the top or bottom note.. + for (int i = 0; i < usableVoices.size(); ++i) + { + SynthesiserVoice* const voice = usableVoices.getUnchecked (i); + + if (voice != bottom && voice != top) + return voice; + } + + // ..otherwise, there's only one or two voices to choose from - we'll return the top one.. + return top; } diff --git a/JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h b/JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h index e765697..6a32ced 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h +++ b/JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h @@ -55,14 +55,14 @@ public: The Synthesiser will use this information when deciding which sounds to trigger for a given note. */ - virtual bool appliesToNote (const int midiNoteNumber) = 0; + virtual bool appliesToNote (int midiNoteNumber) = 0; /** Returns true if the sound should be triggered by midi events on a given channel. The Synthesiser will use this information when deciding which sounds to trigger for a given note. */ - virtual bool appliesToChannel (const int midiChannel) = 0; + virtual bool appliesToChannel (int midiChannel) = 0; /** The class is reference-counted, so this is a handy pointer class for it. */ typedef ReferenceCountedObjectPtr Ptr; @@ -127,6 +127,8 @@ public: This will be called during the rendering callback, so must be fast and thread-safe. + The velocity indicates how quickly the note was released - 0 is slowly, 1 is quickly. + If allowTailOff is false or the voice doesn't want to tail-off, then it must stop all sound immediately, and must call clearCurrentNote() to reset the state of this voice and allow the synth to reassign it another sound. @@ -136,7 +138,7 @@ public: finishes playing (during the rendering callback), it must make sure that it calls clearCurrentNote(). */ - virtual void stopNote (bool allowTailOff) = 0; + virtual void stopNote (float velocity, bool allowTailOff) = 0; /** Called to let the voice know that the pitch wheel has been moved. This will be called during the rendering callback, so must be fast and thread-safe. @@ -173,13 +175,6 @@ public: int startSample, int numSamples) = 0; - /** Returns true if the voice is currently playing a sound which is mapped to the given - midi channel. - - If it's not currently playing, this will return false. - */ - bool isPlayingChannel (int midiChannel) const; - /** Changes the voice's reference sample rate. The rate is set so that subclasses know the output rate and can set their pitch @@ -188,7 +183,19 @@ public: This method is called by the synth, and subclasses can access the current rate with the currentSampleRate member. */ - void setCurrentPlaybackSampleRate (double newRate); + virtual void setCurrentPlaybackSampleRate (double newRate); + + /** Returns the current target sample rate at which rendering is being done. + Subclasses may need to know this so that they can pitch things correctly. + */ + double getSampleRate() const noexcept { return currentSampleRate; } + + /** Returns true if the voice is currently playing a sound which is mapped to the given + midi channel. + + If it's not currently playing, this will return false. + */ + bool isPlayingChannel (int midiChannel) const; /** Returns true if the key that triggered this voice is still held down. Note that the voice may still be playing after the key was released (e.g because the @@ -203,13 +210,6 @@ public: bool wasStartedBefore (const SynthesiserVoice& other) const noexcept; protected: - //============================================================================== - /** Returns the current target sample rate at which rendering is being done. - - This is available for subclasses so they can pitch things correctly. - */ - double getSampleRate() const { return currentSampleRate; } - /** Resets the state of this voice after a sound has finished playing. The subclass must call this when it finishes playing a note and becomes available @@ -235,6 +235,11 @@ private: SynthesiserSound::Ptr currentlyPlayingSound; bool keyIsDown, sostenutoPedalDown; + #if JUCE_CATCH_DEPRECATED_CODE_MISUSE + // Note the new parameters for this method. + virtual int stopNote (bool) { return 0; } + #endif + JUCE_LEAK_DETECTOR (SynthesiserVoice) }; @@ -268,8 +273,7 @@ class JUCE_API Synthesiser public: //============================================================================== /** Creates a new synthesiser. - - You'll need to add some sounds and voices before it'll make any sound.. + You'll need to add some sounds and voices before it'll make any sound. */ Synthesiser(); @@ -365,6 +369,7 @@ public: */ virtual void noteOff (int midiChannel, int midiNoteNumber, + float velocity, bool allowTailOff); /** Turns off all notes. @@ -444,7 +449,7 @@ public: This value is propagated to the voices so that they can use it to render the correct pitches. */ - void setCurrentPlaybackSampleRate (double sampleRate); + virtual void setCurrentPlaybackSampleRate (double sampleRate); /** Creates the next block of audio output. @@ -463,6 +468,11 @@ public: int startSample, int numSamples); + /** Returns the current target sample rate at which rendering is being done. + Subclasses may need to know this so that they can pitch things correctly. + */ + double getSampleRate() const noexcept { return sampleRate; } + protected: //============================================================================== /** This is used to control access to the rendering callback and the note trigger methods. */ @@ -474,21 +484,34 @@ protected: /** The last pitch-wheel values for each midi channel. */ int lastPitchWheelValues [16]; - /** Searches through the voices to find one that's not currently playing, and which - can play the given sound. + /** Renders the voices for the given range. + By default this just calls renderNextBlock() on each voice, but you may need + to override it to handle custom cases. + */ + virtual void renderVoices (AudioSampleBuffer& outputAudio, + int startSample, int numSamples); + + /** Searches through the voices to find one that's not currently playing, and + which can play the given sound. Returns nullptr if all voices are busy and stealing isn't enabled. - This can be overridden to implement custom voice-stealing algorithms. + To implement a custom note-stealing algorithm, you can either override this + method, or (preferably) override findVoiceToSteal(). */ virtual SynthesiserVoice* findFreeVoice (SynthesiserSound* soundToPlay, - const bool stealIfNoneAvailable) const; + int midiChannel, + int midiNoteNumber, + bool stealIfNoneAvailable) const; /** Chooses a voice that is most suitable for being re-used. - The default method returns the one that has been playing for the longest, but - you may want to override this and do something more cunning instead. + The default method will attempt to find the oldest voice that isn't the + bottom or top note being played. If that's not suitable for your synth, + you can override this method and do something more cunning instead. */ - virtual SynthesiserVoice* findVoiceToSteal (SynthesiserSound* soundToPlay) const; + virtual SynthesiserVoice* findVoiceToSteal (SynthesiserSound* soundToPlay, + int midiChannel, + int midiNoteNumber) const; /** Starts a specified voice playing a particular sound. @@ -511,11 +534,14 @@ private: bool shouldStealNotes; BigInteger sustainPedalsDown; - void stopVoice (SynthesiserVoice*, bool allowTailOff); + void stopVoice (SynthesiserVoice*, float velocity, bool allowTailOff); #if JUCE_CATCH_DEPRECATED_CODE_MISUSE - // Note the new parameters for this method. + // Note the new parameters for these methods. virtual int findFreeVoice (const bool) const { return 0; } + virtual int noteOff (int, int, int) { return 0; } + virtual int findFreeVoice (SynthesiserSound*, const bool) { return 0; } + virtual int findVoiceToSteal (SynthesiserSound*) const { return 0; } #endif JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Synthesiser) diff --git a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp index e3584d9..fad5eea 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp @@ -859,8 +859,11 @@ void AudioDeviceManager::addMidiInputCallback (const String& name, MidiInputCall if (name.isEmpty() || isMidiInputEnabled (name)) { const ScopedLock sl (midiCallbackLock); - midiCallbacks.add (callbackToAdd); - midiCallbackDevices.add (name); + + MidiCallbackInfo mc; + mc.deviceName = name; + mc.callback = callbackToAdd; + midiCallbacks.add (mc); } } @@ -868,11 +871,12 @@ void AudioDeviceManager::removeMidiInputCallback (const String& name, MidiInputC { for (int i = midiCallbacks.size(); --i >= 0;) { - if (midiCallbackDevices[i] == name && midiCallbacks.getUnchecked(i) == callbackToRemove) + const MidiCallbackInfo& mc = midiCallbacks.getReference(i); + + if (mc.callback == callbackToRemove && mc.deviceName == name) { const ScopedLock sl (midiCallbackLock); midiCallbacks.remove (i); - midiCallbackDevices.remove (i); } } } @@ -881,16 +885,14 @@ void AudioDeviceManager::handleIncomingMidiMessageInt (MidiInput* source, const { if (! message.isActiveSense()) { - const bool isDefaultSource = (source == nullptr || source == enabledMidiInputs.getFirst()); - const ScopedLock sl (midiCallbackLock); - for (int i = midiCallbackDevices.size(); --i >= 0;) + for (int i = 0; i < midiCallbacks.size(); ++i) { - const String name (midiCallbackDevices[i]); + const MidiCallbackInfo& mc = midiCallbacks.getReference(i); - if ((isDefaultSource && name.isEmpty()) || (name.isNotEmpty() && name == source->getName())) - midiCallbacks.getUnchecked(i)->handleIncomingMidiMessage (source, message); + if (mc.deviceName.isEmpty() || mc.deviceName == source->getName()) + mc.callback->handleIncomingMidiMessage (source, message); } } } diff --git a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h index 839edc2..f1e483f 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h +++ b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h @@ -209,10 +209,9 @@ public: //============================================================================== /** Returns the current device properties that are in use. - @see setAudioDeviceSetup */ - void getAudioDeviceSetup (AudioDeviceSetup& setup); + void getAudioDeviceSetup (AudioDeviceSetup& result); /** Changes the current device or its settings. @@ -261,9 +260,7 @@ public: void setCurrentAudioDeviceType (const String& type, bool treatAsChosenDevice); - /** Closes the currently-open device. - You can call restartLastAudioDevice() later to reopen it in the same state that it was just in. */ @@ -305,8 +302,8 @@ public: //============================================================================== /** Returns the average proportion of available CPU being spent inside the audio callbacks. - - Returns a value between 0 and 1.0 + @returns A value between 0 and 1.0 to indicate the approximate proportion of CPU + time spent in the callbacks. */ double getCpuUsage() const; @@ -333,16 +330,16 @@ public: void setMidiInputEnabled (const String& midiInputDeviceName, bool enabled); /** Returns true if a given midi input device is being used. - @see setMidiInputEnabled */ bool isMidiInputEnabled (const String& midiInputDeviceName) const; /** Registers a listener for callbacks when midi events arrive from a midi input. - The device name can be empty to indicate that it wants events from whatever the - current "default" device is. Or it can be the name of one of the midi input devices - (see MidiInput::getDevices() for the names). + The device name can be empty to indicate that it wants to receive all incoming + events from all the enabled MIDI inputs. Or it can be the name of one of the + MIDI input devices if it just wants the events from that device. (see + MidiInput::getDevices() for the list of device names). Only devices which are enabled (see the setMidiInputEnabled() method) will have their events forwarded on to listeners. @@ -350,8 +347,7 @@ public: void addMidiInputCallback (const String& midiInputDeviceName, MidiInputCallback* callback); - /** Removes a listener that was previously registered with addMidiInputCallback(). - */ + /** Removes a listener that was previously registered with addMidiInputCallback(). */ void removeMidiInputCallback (const String& midiInputDeviceName, MidiInputCallback* callback); @@ -371,22 +367,17 @@ public: void setDefaultMidiOutput (const String& deviceName); /** Returns the name of the default midi output. - @see setDefaultMidiOutput, getDefaultMidiOutput */ - String getDefaultMidiOutputName() const { return defaultMidiOutputName; } + const String& getDefaultMidiOutputName() const noexcept { return defaultMidiOutputName; } /** Returns the current default midi output device. - - If no device has been selected, or the device can't be opened, this will - return 0. - + If no device has been selected, or the device can't be opened, this will return nullptr. @see getDefaultMidiOutputName */ MidiOutput* getDefaultMidiOutput() const noexcept { return defaultMidiOutput; } - /** Returns a list of the types of device supported. - */ + /** Returns a list of the types of device supported. */ const OwnedArray& getAvailableDeviceTypes(); //============================================================================== @@ -429,9 +420,7 @@ public: void enableInputLevelMeasurement (bool enableMeasurement); /** Returns the current input level. - To use this, you must first enable it by calling enableInputLevelMeasurement(). - See enableInputLevelMeasurement() for more info. */ double getCurrentInputLevel() const; @@ -468,10 +457,16 @@ private: int testSoundPosition; AudioSampleBuffer tempBuffer; + struct MidiCallbackInfo + { + String deviceName; + MidiInputCallback* callback; + }; + StringArray midiInsFromXml; OwnedArray enabledMidiInputs; - Array midiCallbacks; - StringArray midiCallbackDevices; + Array midiCallbacks; + String defaultMidiOutputName; ScopedPointer defaultMidiOutput; CriticalSection audioCallbackLock, midiCallbackLock; diff --git a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODevice.cpp b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODevice.cpp index 1386d0c..95221ba 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODevice.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODevice.cpp @@ -22,20 +22,16 @@ ============================================================================== */ -AudioIODevice::AudioIODevice (const String& deviceName, const String& typeName_) - : name (deviceName), - typeName (typeName_) +AudioIODevice::AudioIODevice (const String& deviceName, const String& deviceTypeName) + : name (deviceName), typeName (deviceTypeName) { } -AudioIODevice::~AudioIODevice() -{ -} +AudioIODevice::~AudioIODevice() {} -bool AudioIODevice::hasControlPanel() const -{ - return false; -} +void AudioIODeviceCallback::audioDeviceError (const String&) {} +bool AudioIODevice::setAudioPreprocessingEnabled (bool) { return false; } +bool AudioIODevice::hasControlPanel() const { return false; } bool AudioIODevice::showControlPanel() { @@ -43,6 +39,3 @@ bool AudioIODevice::showControlPanel() // their hasControlPanel() method. return false; } - -//============================================================================== -void AudioIODeviceCallback::audioDeviceError (const String&) {} diff --git a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODevice.h b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODevice.h index 6817ae6..8ce41d0 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODevice.h +++ b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODevice.h @@ -289,6 +289,11 @@ public: */ virtual bool showControlPanel(); + /** On devices which support it, this allows automatic gain control or other + mic processing to be disabled. + If the device doesn't support this operation, it'll return false. + */ + virtual bool setAudioPreprocessingEnabled (bool shouldBeEnabled); //============================================================================== protected: diff --git a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h index da32b2b..d6cd99a 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h +++ b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h @@ -34,7 +34,7 @@ method. Each of the objects returned can then be used to list the available devices of that type. E.g. @code - OwnedArray types; + OwnedArray types; myAudioDeviceManager.createAudioDeviceTypes (types); for (int i = 0; i < types.size(); ++i) diff --git a/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.cpp b/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.cpp index cd91ecf..a9733db 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.cpp @@ -125,6 +125,7 @@ #if JUCE_USE_ANDROID_OPENSLES #include #include + #include #endif #endif diff --git a/JuceLibraryCode/modules/juce_audio_devices/juce_module_info b/JuceLibraryCode/modules/juce_audio_devices/juce_module_info index 90fc19f..6ef2131 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.5", + "version": "3.0.8", "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_android_OpenSL.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_OpenSL.cpp index 842b42e..53dc5df 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_OpenSL.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_OpenSL.cpp @@ -80,7 +80,7 @@ public: Array getAvailableSampleRates() override { - static const double rates[] = { 8000.0, 16000.0, 32000.0, 44100.0, 48000.0 }; + static const double rates[] = { 8000.0, 16000.0, 32000.0, 44100.0, 48000.0 }; return Array (rates, numElementsInArray (rates)); } @@ -165,6 +165,33 @@ public: oldCallback->audioDeviceStopped(); } + bool setAudioPreprocessingEnabled (bool enable) override + { + return recorder != nullptr && recorder->setAudioPreprocessingEnabled (enable); + } + +private: + //================================================================================================== + CriticalSection callbackLock; + AudioIODeviceCallback* callback; + int actualBufferSize, sampleRate; + int inputLatency, outputLatency; + bool deviceOpen; + String lastError; + BigInteger activeOutputChans, activeInputChans; + int numInputChannels, numOutputChannels; + AudioSampleBuffer inputBuffer, outputBuffer; + struct Player; + struct Recorder; + + AudioIODeviceCallback* setCallback (AudioIODeviceCallback* const newCallback) + { + const ScopedLock sl (callbackLock); + AudioIODeviceCallback* const oldCallback = callback; + callback = newCallback; + return oldCallback; + } + void run() override { if (recorder != nullptr) recorder->start(); @@ -190,28 +217,6 @@ public: } } -private: - //================================================================================================== - CriticalSection callbackLock; - AudioIODeviceCallback* callback; - int actualBufferSize, sampleRate; - int inputLatency, outputLatency; - bool deviceOpen; - String lastError; - BigInteger activeOutputChans, activeInputChans; - int numInputChannels, numOutputChannels; - AudioSampleBuffer inputBuffer, outputBuffer; - struct Player; - struct Recorder; - - AudioIODeviceCallback* setCallback (AudioIODeviceCallback* const newCallback) - { - const ScopedLock sl (callbackLock); - AudioIODeviceCallback* const oldCallback = callback; - callback = newCallback; - return oldCallback; - } - //================================================================================================== struct Engine { @@ -230,6 +235,7 @@ private: SL_IID_ANDROIDSIMPLEBUFFERQUEUE = (SLInterfaceID*) library.getFunction ("SL_IID_ANDROIDSIMPLEBUFFERQUEUE"); SL_IID_PLAY = (SLInterfaceID*) library.getFunction ("SL_IID_PLAY"); SL_IID_RECORD = (SLInterfaceID*) library.getFunction ("SL_IID_RECORD"); + SL_IID_ANDROIDCONFIGURATION = (SLInterfaceID*) library.getFunction ("SL_IID_ANDROIDCONFIGURATION"); check ((*engineObject)->Realize (engineObject, SL_BOOLEAN_FALSE)); check ((*engineObject)->GetInterface (engineObject, *SL_IID_ENGINE, &engineInterface)); @@ -271,6 +277,7 @@ private: SLInterfaceID* SL_IID_ANDROIDSIMPLEBUFFERQUEUE; SLInterfaceID* SL_IID_PLAY; SLInterfaceID* SL_IID_RECORD; + SLInterfaceID* SL_IID_ANDROIDCONFIGURATION; private: DynamicLibrary library; @@ -334,8 +341,8 @@ private: SLDataFormat_PCM pcmFormat = { SL_DATAFORMAT_PCM, - numChannels, - sampleRate * 1000, // (sample rate units are millihertz) + (SLuint32) numChannels, + (SLuint32) (sampleRate * 1000), // (sample rate units are millihertz) SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16, SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, @@ -434,7 +441,8 @@ private: struct Recorder { Recorder (int numChannels, int sampleRate, Engine& engine) - : recorderObject (nullptr), recorderRecord (nullptr), recorderBufferQueue (nullptr), + : recorderObject (nullptr), recorderRecord (nullptr), + recorderBufferQueue (nullptr), configObject (nullptr), bufferList (numChannels) { jassert (numChannels == 1); // STEREO doesn't always work!! @@ -442,8 +450,8 @@ private: SLDataFormat_PCM pcmFormat = { SL_DATAFORMAT_PCM, - numChannels, - sampleRate * 1000, // (sample rate units are millihertz) + (SLuint32) numChannels, + (SLuint32) (sampleRate * 1000), // (sample rate units are millihertz) SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16, (numChannels == 1) ? SL_SPEAKER_FRONT_CENTER : (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT), @@ -466,6 +474,7 @@ private: { check ((*recorderObject)->GetInterface (recorderObject, *engine.SL_IID_RECORD, &recorderRecord)); check ((*recorderObject)->GetInterface (recorderObject, *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &recorderBufferQueue)); + check ((*recorderObject)->GetInterface (recorderObject, *engine.SL_IID_ANDROIDCONFIGURATION, &configObject)); check ((*recorderBufferQueue)->RegisterCallback (recorderBufferQueue, staticCallback, this)); check ((*recorderRecord)->SetRecordState (recorderRecord, SL_RECORDSTATE_STOPPED)); @@ -532,10 +541,20 @@ private: } } + bool setAudioPreprocessingEnabled (bool enable) + { + SLuint32 mode = enable ? SL_ANDROID_RECORDING_PRESET_GENERIC + : SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION; + + return configObject != nullptr + && check ((*configObject)->SetConfiguration (configObject, SL_ANDROID_KEY_RECORDING_PRESET, &mode, sizeof (mode))); + } + private: SLObjectItf recorderObject; SLRecordItf recorderRecord; SLAndroidSimpleBufferQueueItf recorderBufferQueue; + SLAndroidConfigurationItf configObject; BufferList bufferList; 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 6016a51..70490aa 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_ios_Audio.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_ios_Audio.cpp @@ -67,7 +67,12 @@ public: return s; } - Array getAvailableSampleRates() override { return sampleRates; } + Array getAvailableSampleRates() override + { + // can't find a good way to actually ask the device for which of these it supports.. + static const double rates[] = { 8000.0, 16000.0, 22050.0, 32000.0, 44100.0, 48000.0 }; + return Array (rates, numElementsInArray (rates)); + } Array getAvailableBufferSizes() override { @@ -79,7 +84,7 @@ public: return r; } - int getDefaultBufferSize() override { return 1024; } + int getDefaultBufferSize() override { return 1024; } String open (const BigInteger& inputChannelsWanted, const BigInteger& outputChannelsWanted, @@ -117,10 +122,9 @@ public: AudioSessionAddPropertyListener (kAudioSessionProperty_AudioRouteChange, routingChangedStatic, this); fixAudioRouteIfSetToReceiver(); - updateDeviceInfo(); setSessionFloat64Property (kAudioSessionProperty_PreferredHardwareSampleRate, targetSampleRate); - updateSampleRates(); + updateDeviceInfo(); setSessionFloat32Property (kAudioSessionProperty_PreferredHardwareIOBufferDuration, preferredBufferSize / sampleRate); updateCurrentBufferSize(); @@ -162,8 +166,15 @@ public: BigInteger getActiveOutputChannels() const override { return activeOutputChans; } BigInteger getActiveInputChannels() const override { return activeInputChans; } - int getOutputLatencyInSamples() override { return 0; } //xxx - int getInputLatencyInSamples() override { return 0; } //xxx + int getOutputLatencyInSamples() override { return getLatency (kAudioSessionProperty_CurrentHardwareOutputLatency); } + int getInputLatencyInSamples() override { return getLatency (kAudioSessionProperty_CurrentHardwareInputLatency); } + + int getLatency (AudioSessionPropertyID propID) + { + Float32 latency = 0; + getSessionProperty (propID, latency); + return roundToInt (latency * getCurrentSampleRate()); + } void start (AudioIODeviceCallback* newCallback) override { @@ -197,11 +208,16 @@ public: bool isPlaying() override { return isRunning && callback != nullptr; } String getLastError() override { return lastError; } + bool setAudioPreprocessingEnabled (bool enable) override + { + return setSessionUInt32Property (kAudioSessionProperty_Mode, enable ? kAudioSessionMode_Default + : kAudioSessionMode_Measurement); + } + private: //================================================================================================== CriticalSection callbackLock; Float64 sampleRate; - Array sampleRates; int numInputChannels, numOutputChannels; int preferredBufferSize, actualBufferSize; bool isRunning; @@ -322,38 +338,6 @@ private: getSessionProperty (kAudioSessionProperty_AudioInputAvailable, audioInputIsAvailable); } - void updateSampleRates() - { - getSessionProperty (kAudioSessionProperty_CurrentHardwareSampleRate, sampleRate); - - sampleRates.clear(); - sampleRates.add (sampleRate); - - const int commonSampleRates[] = { 8000, 16000, 22050, 32000, 44100, 48000 }; - - for (int i = 0; i < numElementsInArray (commonSampleRates); ++i) - { - Float64 rate = (Float64) commonSampleRates[i]; - - if (rate != sampleRate) - { - setSessionFloat64Property (kAudioSessionProperty_PreferredHardwareSampleRate, rate); - - Float64 actualSampleRate = 0.0; - getSessionProperty (kAudioSessionProperty_CurrentHardwareSampleRate, actualSampleRate); - - if (actualSampleRate == rate) - sampleRates.add (actualSampleRate); - } - } - - DefaultElementComparator comparator; - sampleRates.sort (comparator); - - setSessionFloat64Property (kAudioSessionProperty_PreferredHardwareSampleRate, sampleRate); - getSessionProperty (kAudioSessionProperty_CurrentHardwareSampleRate, sampleRate); - } - void updateCurrentBufferSize() { Float32 bufferDuration = sampleRate > 0 ? (Float32) (preferredBufferSize / sampleRate) : 0.0f; @@ -455,12 +439,12 @@ private: static OSStatus processStatic (void* client, AudioUnitRenderActionFlags* flags, const AudioTimeStamp* time, UInt32 /*busNumber*/, UInt32 numFrames, AudioBufferList* data) { - return static_cast (client)->process (flags, time, numFrames, data); + return static_cast (client)->process (flags, time, numFrames, data); } static void routingChangedStatic (void* client, AudioSessionPropertyID, UInt32 /*inDataSize*/, const void* propertyValue) { - static_cast (client)->routingChanged (propertyValue); + static_cast (client)->routingChanged (propertyValue); } //================================================================================================== @@ -552,9 +536,9 @@ private: return AudioSessionGetProperty (propID, &valueSize, &result); } - static void setSessionUInt32Property (AudioSessionPropertyID propID, UInt32 v) noexcept { AudioSessionSetProperty (propID, sizeof (v), &v); } - static void setSessionFloat32Property (AudioSessionPropertyID propID, Float32 v) noexcept { AudioSessionSetProperty (propID, sizeof (v), &v); } - static void setSessionFloat64Property (AudioSessionPropertyID propID, Float64 v) noexcept { AudioSessionSetProperty (propID, sizeof (v), &v); } + static bool setSessionUInt32Property (AudioSessionPropertyID propID, UInt32 v) noexcept { return AudioSessionSetProperty (propID, sizeof (v), &v) == kAudioSessionNoError; } + static bool setSessionFloat32Property (AudioSessionPropertyID propID, Float32 v) noexcept { return AudioSessionSetProperty (propID, sizeof (v), &v) == kAudioSessionNoError; } + static bool setSessionFloat64Property (AudioSessionPropertyID propID, Float64 v) noexcept { return AudioSessionSetProperty (propID, sizeof (v), &v) == kAudioSessionNoError; } JUCE_DECLARE_NON_COPYABLE (iOSAudioIODevice) }; diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_ALSA.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_ALSA.cpp index 9bc7ecf..091ffba 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_ALSA.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_ALSA.cpp @@ -41,7 +41,7 @@ namespace return err; } #else - #define JUCE_ALSA_LOG(x) + #define JUCE_ALSA_LOG(x) {} #define JUCE_CHECKED_RESULT(x) (x) #endif 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 625f1b8..d7044eb 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp @@ -144,6 +144,7 @@ public: : owner (d), inputLatency (0), outputLatency (0), + bitDepth (32), callback (nullptr), #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 audioProcID (0), @@ -232,7 +233,7 @@ public: size = sizeof (nameNSString); pa.mSelector = kAudioObjectPropertyElementName; - pa.mElement = chanNum + 1; + pa.mElement = (AudioObjectPropertyElement) chanNum + 1; if (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, &nameNSString) == noErr) { @@ -352,6 +353,22 @@ public: return (int) lat; } + int getBitDepthFromDevice (AudioObjectPropertyScope scope) const + { + AudioObjectPropertyAddress pa; + pa.mElement = kAudioObjectPropertyElementMaster; + pa.mSelector = kAudioStreamPropertyPhysicalFormat; + pa.mScope = scope; + + AudioStreamBasicDescription asbd; + UInt32 size = sizeof (asbd); + + if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, &asbd))) + return (int) asbd.mBitsPerChannel; + + return 0; + } + void updateDetailsFromDevice() { stopTimer(); @@ -377,7 +394,7 @@ public: if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, &sr))) sampleRate = sr; - UInt32 framesPerBuf = bufferSize; + UInt32 framesPerBuf = (UInt32) bufferSize; size = sizeof (framesPerBuf); pa.mSelector = kAudioDevicePropertyBufferFrameSize; AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, &framesPerBuf); @@ -392,6 +409,13 @@ public: StringArray newInNames (getChannelInfo (true, newInChans)); StringArray newOutNames (getChannelInfo (false, newOutChans)); + const int inputBitDepth = getBitDepthFromDevice (kAudioDevicePropertyScopeInput); + const int outputBitDepth = getBitDepthFromDevice (kAudioDevicePropertyScopeOutput); + + bitDepth = jmax (inputBitDepth, outputBitDepth); + if (bitDepth <= 0) + bitDepth = 32; + // after getting the new values, lock + apply them const ScopedLock sl (callbackLock); @@ -728,6 +752,7 @@ public: //============================================================================== CoreAudioIODevice& owner; int inputLatency, outputLatency; + int bitDepth; BigInteger activeInputChans, activeOutputChans; StringArray inChanNames, outChanNames; Array sampleRates; @@ -886,7 +911,7 @@ public: Array getAvailableBufferSizes() override { return internal->bufferSizes; } double getCurrentSampleRate() override { return internal->getSampleRate(); } - int getCurrentBitDepth() override { return 32; } // no way to find out, so just assume it's high.. + int getCurrentBitDepth() override { return internal->bitDepth; } int getCurrentBufferSizeSamples() override { return internal->getBufferSize(); } int getDefaultBufferSize() override @@ -1387,7 +1412,7 @@ private: d.done = (d.numInputChans == 0); } - for (int tries = 3;;) + for (int tries = 5;;) { bool anyRemaining = false; @@ -1434,7 +1459,7 @@ private: d.done = (d.numOutputChans == 0); } - for (int tries = 3;;) + for (int tries = 5;;) { bool anyRemaining = false; diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_ASIO.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_ASIO.cpp index 1b520dd..b171bed 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_ASIO.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_ASIO.cpp @@ -365,7 +365,7 @@ public: void updateSampleRates() { // find a list of sample rates.. - const int possibleSampleRates[] = { 44100, 48000, 88200, 96000, 176400, 192000 }; + const int possibleSampleRates[] = { 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000 }; Array newRates; if (asioObject != nullptr) diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_WASAPI.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_WASAPI.cpp index 98e276c..320eca1 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_WASAPI.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_WASAPI.cpp @@ -33,8 +33,8 @@ namespace WasapiClasses void logFailure (HRESULT hr) { (void) hr; - jassert (hr != 0x800401f0); // If you hit this, it means you're trying to call from - // a thread which hasn't been initialised with CoInitialize(). + jassert (hr != (HRESULT) 0x800401f0); // If you hit this, it means you're trying to call from + // a thread which hasn't been initialised with CoInitialize(). #if JUCE_WASAPI_LOGGING if (FAILED (hr)) diff --git a/JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp b/JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp index e923b46..feb58a9 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp @@ -182,6 +182,10 @@ void AudioTransportSource::setNextReadPosition (int64 newPosition) newPosition = (int64) (newPosition * sourceSampleRate / sampleRate); positionableSource->setNextReadPosition (newPosition); + + if (resamplerSource != nullptr) + resamplerSource->flushBuffers(); + inputStreamEOF = false; } } diff --git a/JuceLibraryCode/modules/juce_audio_formats/codecs/juce_AiffAudioFormat.cpp b/JuceLibraryCode/modules/juce_audio_formats/codecs/juce_AiffAudioFormat.cpp index d7edd45..2029bc8 100644 --- a/JuceLibraryCode/modules/juce_audio_formats/codecs/juce_AiffAudioFormat.cpp +++ b/JuceLibraryCode/modules/juce_audio_formats/codecs/juce_AiffAudioFormat.cpp @@ -37,7 +37,7 @@ const char* const AiffAudioFormat::appleKey = "apple key"; //============================================================================== namespace AiffFileHelpers { - inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); } + inline int chunkName (const char* name) noexcept { return (int) ByteOrder::littleEndianInt (name); } #if JUCE_MSVC #pragma pack (push, 1) @@ -888,13 +888,13 @@ AiffAudioFormat::~AiffAudioFormat() Array AiffAudioFormat::getPossibleSampleRates() { const int rates[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, 0 }; - return Array (rates); + return Array (rates); } Array AiffAudioFormat::getPossibleBitDepths() { const int depths[] = { 8, 16, 24, 0 }; - return Array (depths); + return Array (depths); } bool AiffAudioFormat::canDoStereo() { return true; } diff --git a/JuceLibraryCode/modules/juce_audio_formats/codecs/juce_LAMEEncoderAudioFormat.cpp b/JuceLibraryCode/modules/juce_audio_formats/codecs/juce_LAMEEncoderAudioFormat.cpp index 5d30d44..8a5263c 100644 --- a/JuceLibraryCode/modules/juce_audio_formats/codecs/juce_LAMEEncoderAudioFormat.cpp +++ b/JuceLibraryCode/modules/juce_audio_formats/codecs/juce_LAMEEncoderAudioFormat.cpp @@ -165,13 +165,13 @@ bool LAMEEncoderAudioFormat::canHandleFile (const File&) Array LAMEEncoderAudioFormat::getPossibleSampleRates() { const int rates[] = { 32000, 44100, 48000, 0 }; - return Array (rates); + return Array (rates); } Array LAMEEncoderAudioFormat::getPossibleBitDepths() { const int depths[] = { 16, 0 }; - return Array (depths); + return Array (depths); } bool LAMEEncoderAudioFormat::canDoStereo() { return true; } diff --git a/JuceLibraryCode/modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp b/JuceLibraryCode/modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp index 058ff73..473e744 100644 --- a/JuceLibraryCode/modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp +++ b/JuceLibraryCode/modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp @@ -65,6 +65,7 @@ const char* const WavAudioFormat::acidNumerator = "acid numerator"; const char* const WavAudioFormat::acidTempo = "acid tempo"; const char* const WavAudioFormat::ISRC = "ISRC"; +const char* const WavAudioFormat::tracktionLoopInfo = "tracktion loop info"; //============================================================================== namespace WavFileHelpers @@ -471,6 +472,46 @@ namespace WavFileHelpers } } + //============================================================================== + namespace ListInfoChunk + { + static bool writeValue (const StringPairArray& values, MemoryOutputStream& out, const char* paramName) + { + const String value (values.getValue (paramName, String())); + + if (value.isEmpty()) + return false; + + const int valueLength = (int) value.getNumBytesAsUTF8() + 1; + const int chunkLength = valueLength + (valueLength & 1); + + out.writeInt (chunkName (paramName)); + out.writeInt (chunkLength); + out.write (value.toUTF8(), (size_t) valueLength); + + if ((out.getDataSize() & 1) != 0) + out.writeByte (0); + + return true; + } + + static MemoryBlock createFrom (const StringPairArray& values) + { + static const char* params[] = { "INAM", "IART", "IPRD", "IPRT", "ISFT", + "ISRC", "IGNR", "ICMT", "ICOP", "ICRD" }; + + MemoryOutputStream out; + out.writeInt (chunkName ("INFO")); + bool anyParamsDefined = false; + + for (int i = 0; i < numElementsInArray (params); ++i) + if (writeValue (values, out, params[i])) + anyParamsDefined = true; + + return anyParamsDefined ? out.getMemoryBlock() : MemoryBlock(); + } + } + //============================================================================== struct AcidChunk { @@ -481,6 +522,38 @@ namespace WavFileHelpers input.read (this, (int) jmin (sizeof (*this), length)); } + AcidChunk (const StringPairArray& values) + { + zerostruct (*this); + + flags = getFlagIfPresent (values, WavAudioFormat::acidOneShot, 0x01) + | getFlagIfPresent (values, WavAudioFormat::acidRootSet, 0x02) + | getFlagIfPresent (values, WavAudioFormat::acidStretch, 0x04) + | getFlagIfPresent (values, WavAudioFormat::acidDiskBased, 0x08) + | getFlagIfPresent (values, WavAudioFormat::acidizerFlag, 0x10); + + if (values[WavAudioFormat::acidRootSet].getIntValue() != 0) + rootNote = ByteOrder::swapIfBigEndian ((uint16) values[WavAudioFormat::acidRootNote].getIntValue()); + + numBeats = ByteOrder::swapIfBigEndian ((uint32) values[WavAudioFormat::acidBeats].getIntValue()); + meterDenominator = ByteOrder::swapIfBigEndian ((uint16) values[WavAudioFormat::acidDenominator].getIntValue()); + meterNumerator = ByteOrder::swapIfBigEndian ((uint16) values[WavAudioFormat::acidNumerator].getIntValue()); + + if (values.containsKey (WavAudioFormat::acidTempo)) + tempo = swapFloatByteOrder (values[WavAudioFormat::acidTempo].getFloatValue()); + } + + static MemoryBlock createFrom (const StringPairArray& values) + { + return AcidChunk (values).toMemoryBlock(); + } + + MemoryBlock toMemoryBlock() const + { + return (flags != 0 || rootNote != 0 || numBeats != 0 || meterDenominator != 0 || meterNumerator != 0) + ? MemoryBlock (this, sizeof (*this)) : MemoryBlock(); + } + void addToMetadata (StringPairArray& values) const { setBoolFlag (values, WavAudioFormat::acidOneShot, 0x01); @@ -490,30 +563,65 @@ namespace WavFileHelpers setBoolFlag (values, WavAudioFormat::acidizerFlag, 0x10); if (flags & 0x02) // root note set - values.set (WavAudioFormat::acidRootNote, String (rootNote)); + values.set (WavAudioFormat::acidRootNote, String (ByteOrder::swapIfBigEndian (rootNote))); - values.set (WavAudioFormat::acidBeats, String (numBeats)); - values.set (WavAudioFormat::acidDenominator, String (meterDenominator)); - values.set (WavAudioFormat::acidNumerator, String (meterNumerator)); - values.set (WavAudioFormat::acidTempo, String (tempo)); + values.set (WavAudioFormat::acidBeats, String (ByteOrder::swapIfBigEndian (numBeats))); + values.set (WavAudioFormat::acidDenominator, String (ByteOrder::swapIfBigEndian (meterDenominator))); + values.set (WavAudioFormat::acidNumerator, String (ByteOrder::swapIfBigEndian (meterNumerator))); + values.set (WavAudioFormat::acidTempo, String (swapFloatByteOrder (tempo))); } - void setBoolFlag (StringPairArray& values, const char* name, int32 mask) const + void setBoolFlag (StringPairArray& values, const char* name, uint32 mask) const { - values.set (name, (flags & mask) ? "1" : "0"); + values.set (name, (flags & ByteOrder::swapIfBigEndian (mask)) ? "1" : "0"); } - int32 flags; - int16 rootNote; - int16 reserved1; + static uint32 getFlagIfPresent (const StringPairArray& values, const char* name, uint32 flag) + { + return values[name].getIntValue() != 0 ? ByteOrder::swapIfBigEndian (flag) : 0; + } + + static float swapFloatByteOrder (const float x) noexcept + { + #ifdef JUCE_BIG_ENDIAN + union { uint32 asInt; float asFloat; } n; + n.asFloat = x; + n.asInt = ByteOrder::swap (n.asInt); + return n.asFloat; + #else + return x; + #endif + } + + uint32 flags; + uint16 rootNote; + uint16 reserved1; float reserved2; - int32 numBeats; - int16 meterDenominator; - int16 meterNumerator; + uint32 numBeats; + uint16 meterDenominator; + uint16 meterNumerator; float tempo; } JUCE_PACKED; + //============================================================================== + struct TracktionChunk + { + static MemoryBlock createFrom (const StringPairArray& values) + { + const String s = values[WavAudioFormat::tracktionLoopInfo]; + MemoryBlock data; + + if (s.isNotEmpty()) + { + MemoryOutputStream os (data, false); + os.writeString (s); + } + + return data; + } + }; + //============================================================================== namespace AXMLChunk { @@ -816,6 +924,12 @@ public: { AcidChunk (*input, length).addToMetadata (metadataValues); } + else if (chunkType == chunkName ("Trkn")) + { + MemoryBlock tracktion; + input->readIntoMemoryBlock (tracktion, (ssize_t) length); + metadataValues.set (WavAudioFormat::tracktionLoopInfo, tracktion.toString()); + } else if (chunkEnd <= input->getPosition()) { break; @@ -913,12 +1027,15 @@ public: // key should be removed (or set to "WAV") once this has been done jassert (metadataValues.getValue ("MetaDataSource", "None") != "AIFF"); - bwavChunk = BWAVChunk::createFrom (metadataValues); - axmlChunk = AXMLChunk::createFrom (metadataValues); - smplChunk = SMPLChunk::createFrom (metadataValues); - instChunk = InstChunk::createFrom (metadataValues); - cueChunk = CueChunk ::createFrom (metadataValues); - listChunk = ListChunk::createFrom (metadataValues); + bwavChunk = BWAVChunk::createFrom (metadataValues); + axmlChunk = AXMLChunk::createFrom (metadataValues); + smplChunk = SMPLChunk::createFrom (metadataValues); + instChunk = InstChunk::createFrom (metadataValues); + cueChunk = CueChunk ::createFrom (metadataValues); + listChunk = ListChunk::createFrom (metadataValues); + listInfoChunk = ListInfoChunk::createFrom (metadataValues); + acidChunk = AcidChunk::createFrom (metadataValues); + trckChunk = TracktionChunk::createFrom (metadataValues); } headerPosition = out->getPosition(); @@ -927,12 +1044,6 @@ public: ~WavAudioFormatWriter() { - if ((bytesWritten & 1) != 0) // pad to an even length - { - ++bytesWritten; - output->writeByte (0); - } - writeHeader(); } @@ -972,8 +1083,22 @@ public: return true; } + bool flush() override + { + const int64 lastWritePos = output->getPosition(); + writeHeader(); + + if (output->setPosition (lastWritePos)) + return true; + + // if this fails, you've given it an output stream that can't seek! It needs + // to be able to seek back to write the header + jassertfalse; + return false; + } + private: - MemoryBlock tempBlock, bwavChunk, axmlChunk, smplChunk, instChunk, cueChunk, listChunk; + MemoryBlock tempBlock, bwavChunk, axmlChunk, smplChunk, instChunk, cueChunk, listChunk, listInfoChunk, acidChunk, trckChunk; uint64 lengthInSamples, bytesWritten; int64 headerPosition; bool writeFailed; @@ -998,13 +1123,18 @@ private: void writeHeader() { - using namespace WavFileHelpers; - const bool seekedOk = output->setPosition (headerPosition); - (void) seekedOk; + if ((bytesWritten & 1) != 0) // pad to an even length + output->writeByte (0); - // if this fails, you've given it an output stream that can't seek! It needs - // to be able to seek back to write the header - jassert (seekedOk); + using namespace WavFileHelpers; + + if (headerPosition != output->getPosition() && ! output->setPosition (headerPosition)) + { + // if this fails, you've given it an output stream that can't seek! It needs to be + // able to seek back to go back and write the header after the data has been written. + jassertfalse; + return; + } const size_t bytesPerFrame = numChannels * bitsPerSample / 8; uint64 audioDataSize = bytesPerFrame * lengthInSamples; @@ -1020,6 +1150,9 @@ private: + chunkSize (instChunk) + chunkSize (cueChunk) + chunkSize (listChunk) + + chunkSize (listInfoChunk) + + chunkSize (acidChunk) + + chunkSize (trckChunk) + (8 + 28)); // (ds64 chunk) riffChunkSize += (riffChunkSize & 1); @@ -1093,12 +1226,15 @@ private: output->write (subFormat.data4, sizeof (subFormat.data4)); } - writeChunk (bwavChunk, chunkName ("bext")); - writeChunk (axmlChunk, chunkName ("axml")); - writeChunk (smplChunk, chunkName ("smpl")); - writeChunk (instChunk, chunkName ("inst"), 7); - writeChunk (cueChunk, chunkName ("cue ")); - writeChunk (listChunk, chunkName ("LIST")); + writeChunk (bwavChunk, chunkName ("bext")); + writeChunk (axmlChunk, chunkName ("axml")); + writeChunk (smplChunk, chunkName ("smpl")); + writeChunk (instChunk, chunkName ("inst"), 7); + writeChunk (cueChunk, chunkName ("cue ")); + writeChunk (listChunk, chunkName ("LIST")); + writeChunk (listInfoChunk, chunkName ("LIST")); + writeChunk (acidChunk, chunkName ("acid")); + writeChunk (trckChunk, chunkName ("Trkn")); writeChunkHeader (chunkName ("data"), isRF64 ? -1 : (int) (lengthInSamples * bytesPerFrame)); diff --git a/JuceLibraryCode/modules/juce_audio_formats/codecs/juce_WavAudioFormat.h b/JuceLibraryCode/modules/juce_audio_formats/codecs/juce_WavAudioFormat.h index f80695c..62de05a 100644 --- a/JuceLibraryCode/modules/juce_audio_formats/codecs/juce_WavAudioFormat.h +++ b/JuceLibraryCode/modules/juce_audio_formats/codecs/juce_WavAudioFormat.h @@ -135,6 +135,9 @@ public: /** Metadata property name used when reading an ISRC code from an AXML chunk. */ static const char* const ISRC; + /** Metadata property name used when reading a WAV file with a Tracktion chunk. */ + static const char* const tracktionLoopInfo; + //============================================================================== Array getPossibleSampleRates() override; Array getPossibleBitDepths() override; diff --git a/JuceLibraryCode/modules/juce_audio_formats/format/juce_AudioFormatReader.cpp b/JuceLibraryCode/modules/juce_audio_formats/format/juce_AudioFormatReader.cpp index 501e339..5db3149 100644 --- a/JuceLibraryCode/modules/juce_audio_formats/format/juce_AudioFormatReader.cpp +++ b/JuceLibraryCode/modules/juce_audio_formats/format/juce_AudioFormatReader.cpp @@ -162,7 +162,7 @@ void AudioFormatReader::read (AudioSampleBuffer* buffer, } else { - HeapBlock chans (numTargetChannels); + HeapBlock chans ((size_t) numTargetChannels); readChannels (*this, chans, buffer, startSample, numSamples, readerStartSample, numTargetChannels); } @@ -173,35 +173,54 @@ void AudioFormatReader::read (AudioSampleBuffer* buffer, } } -template -static Range getChannelMinAndMax (SampleType* channel, int numSamples) noexcept +void AudioFormatReader::readMaxLevels (int64 startSampleInFile, int64 numSamples, + Range* const results, const int channelsToRead) { - return Range::findMinAndMax (channel, numSamples); -} + jassert (channelsToRead > 0 && channelsToRead <= (int) numChannels); -static Range getChannelMinAndMax (float* channel, int numSamples) noexcept -{ - return FloatVectorOperations::findMinAndMax (channel, numSamples); -} - -template -static void getStereoMinAndMax (SampleType* const* channels, const int numChannels, const int numSamples, - SampleType& lmin, SampleType& lmax, SampleType& rmin, SampleType& rmax) -{ - Range range (getChannelMinAndMax (channels[0], numSamples)); - lmax = jmax (lmax, range.getEnd()); - lmin = jmin (lmin, range.getStart()); - - if (numChannels > 1) + if (numSamples <= 0) { - range = getChannelMinAndMax (channels[1], numSamples); - rmax = jmax (rmax, range.getEnd()); - rmin = jmin (rmin, range.getStart()); + for (int i = 0; i < channelsToRead; ++i) + results[i] = Range(); + + return; } - else + + const int bufferSize = (int) jmin (numSamples, (int64) 4096); + AudioSampleBuffer tempSampleBuffer ((int) channelsToRead, bufferSize); + + float* const* const floatBuffer = tempSampleBuffer.getArrayOfWritePointers(); + int* const* intBuffer = reinterpret_cast (floatBuffer); + bool isFirstBlock = true; + + while (numSamples > 0) { - rmax = lmax; - rmin = lmin; + const int numToDo = (int) jmin (numSamples, (int64) bufferSize); + if (! read (intBuffer, channelsToRead, startSampleInFile, numToDo, false)) + break; + + for (int i = 0; i < channelsToRead; ++i) + { + Range r; + + if (usesFloatingPointData) + { + r = FloatVectorOperations::findMinAndMax (floatBuffer[i], numToDo); + } + else + { + Range intRange (Range::findMinAndMax (intBuffer[i], numToDo)); + + r = Range (intRange.getStart() / (float) std::numeric_limits::max(), + intRange.getEnd() / (float) std::numeric_limits::max()); + } + + results[i] = isFirstBlock ? r : results[i].getUnionWith (r); + } + + isFirstBlock = false; + numSamples -= numToDo; + startSampleInFile += numToDo; } } @@ -209,66 +228,20 @@ void AudioFormatReader::readMaxLevels (int64 startSampleInFile, int64 numSamples float& lowestLeft, float& highestLeft, float& lowestRight, float& highestRight) { - if (numSamples <= 0) + Range levels[2]; + readMaxLevels (startSampleInFile, numSamples, levels, jmin (2, (int) numChannels)); + lowestLeft = levels[0].getStart(); + highestLeft = levels[0].getEnd(); + + if (numChannels > 1) { - lowestLeft = 0; - lowestRight = 0; - highestLeft = 0; - highestRight = 0; - return; - } - - const int bufferSize = (int) jmin (numSamples, (int64) 4096); - AudioSampleBuffer tempSampleBuffer ((int) numChannels, bufferSize); - - float* const* const floatBuffer = tempSampleBuffer.getArrayOfWritePointers(); - int* const* intBuffer = reinterpret_cast (floatBuffer); - - if (usesFloatingPointData) - { - float lmin = 1.0e6f; - float lmax = -lmin; - float rmin = lmin; - float rmax = lmax; - - while (numSamples > 0) - { - const int numToDo = (int) jmin (numSamples, (int64) bufferSize); - if (! read (intBuffer, 2, startSampleInFile, numToDo, false)) - break; - - numSamples -= numToDo; - startSampleInFile += numToDo; - getStereoMinAndMax (floatBuffer, (int) numChannels, numToDo, lmin, lmax, rmin, rmax); - } - - lowestLeft = lmin; - highestLeft = lmax; - lowestRight = rmin; - highestRight = rmax; + lowestRight = levels[1].getStart(); + highestRight = levels[1].getEnd(); } else { - int lmax = std::numeric_limits::min(); - int lmin = std::numeric_limits::max(); - int rmax = std::numeric_limits::min(); - int rmin = std::numeric_limits::max(); - - while (numSamples > 0) - { - const int numToDo = (int) jmin (numSamples, (int64) bufferSize); - if (! read (intBuffer, 2, startSampleInFile, numToDo, false)) - break; - - numSamples -= numToDo; - startSampleInFile += numToDo; - getStereoMinAndMax (intBuffer, (int) numChannels, numToDo, lmin, lmax, rmin, rmax); - } - - lowestLeft = lmin / (float) std::numeric_limits::max(); - highestLeft = lmax / (float) std::numeric_limits::max(); - lowestRight = rmin / (float) std::numeric_limits::max(); - highestRight = rmax / (float) std::numeric_limits::max(); + lowestRight = lowestLeft; + highestRight = highestLeft; } } diff --git a/JuceLibraryCode/modules/juce_audio_formats/format/juce_AudioFormatReader.h b/JuceLibraryCode/modules/juce_audio_formats/format/juce_AudioFormatReader.h index d7cdd9c..065388a 100644 --- a/JuceLibraryCode/modules/juce_audio_formats/format/juce_AudioFormatReader.h +++ b/JuceLibraryCode/modules/juce_audio_formats/format/juce_AudioFormatReader.h @@ -121,6 +121,25 @@ public: bool useReaderLeftChan, bool useReaderRightChan); + /** Finds the highest and lowest sample levels from a section of the audio stream. + + This will read a block of samples from the stream, and measure the + highest and lowest sample levels from the channels in that section, returning + these as normalised floating-point levels. + + @param startSample the offset into the audio stream to start reading from. It's + ok for this to be beyond the start or end of the stream. + @param numSamples how many samples to read + @param results this array will be filled with Range values for each channel. + The array must contain numChannels elements. + @param numChannelsToRead the number of channels of data to scan. This must be + more than zero, but not more than the total number of channels + that the reader contains + @see read + */ + virtual void readMaxLevels (int64 startSample, int64 numSamples, + Range* results, int numChannelsToRead); + /** Finds the highest and lowest sample levels from a section of the audio stream. This will read a block of samples from the stream, and measure the @@ -138,12 +157,9 @@ public: channel (if there is one) @see read */ - virtual void readMaxLevels (int64 startSample, - int64 numSamples, - float& lowestLeft, - float& highestLeft, - float& lowestRight, - float& highestRight); + virtual void readMaxLevels (int64 startSample, int64 numSamples, + float& lowestLeft, float& highestLeft, + float& lowestRight, float& highestRight); /** Scans the source looking for a sample whose magnitude is in a specified range. diff --git a/JuceLibraryCode/modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp b/JuceLibraryCode/modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp index cd1ffc9..065f36a 100644 --- a/JuceLibraryCode/modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp +++ b/JuceLibraryCode/modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp @@ -183,6 +183,11 @@ bool AudioFormatWriter::writeFromAudioSampleBuffer (const AudioSampleBuffer& sou return writeFromFloatArrays (chans, numSourceChannels, numSamples); } +bool AudioFormatWriter::flush() +{ + return false; +} + //============================================================================== class AudioFormatWriter::ThreadedWriter::Buffer : private TimeSliceClient { @@ -194,6 +199,8 @@ public: writer (w), receiver (nullptr), samplesWritten (0), + samplesPerFlush (0), + flushSampleCounter (0), isRunning (true) { timeSliceThread.addTimeSliceClient (this); @@ -266,6 +273,18 @@ public: } fifo.finishedRead (size1 + size2); + + if (samplesPerFlush > 0) + { + flushSampleCounter -= size1 + size2; + + if (flushSampleCounter <= 0) + { + flushSampleCounter = samplesPerFlush; + writer->flush(); + } + } + return 0; } @@ -279,6 +298,11 @@ public: samplesWritten = 0; } + void setFlushInterval (int numSamples) noexcept + { + samplesPerFlush = numSamples; + } + private: AbstractFifo fifo; AudioSampleBuffer buffer; @@ -287,6 +311,7 @@ private: CriticalSection thumbnailLock; IncomingDataReceiver* receiver; int64 samplesWritten; + int samplesPerFlush, flushSampleCounter; volatile bool isRunning; JUCE_DECLARE_NON_COPYABLE (Buffer) @@ -310,3 +335,8 @@ void AudioFormatWriter::ThreadedWriter::setDataReceiver (AudioFormatWriter::Thre { buffer->setDataReceiver (receiver); } + +void AudioFormatWriter::ThreadedWriter::setFlushInterval (int numSamplesPerFlush) noexcept +{ + buffer->setFlushInterval (numSamplesPerFlush); +} diff --git a/JuceLibraryCode/modules/juce_audio_formats/format/juce_AudioFormatWriter.h b/JuceLibraryCode/modules/juce_audio_formats/format/juce_AudioFormatWriter.h index ceb54da..9098c75 100644 --- a/JuceLibraryCode/modules/juce_audio_formats/format/juce_AudioFormatWriter.h +++ b/JuceLibraryCode/modules/juce_audio_formats/format/juce_AudioFormatWriter.h @@ -91,8 +91,18 @@ public: to pass it into the method. @param numSamples the number of samples to write */ - virtual bool write (const int** samplesToWrite, - int numSamples) = 0; + virtual bool write (const int** samplesToWrite, int numSamples) = 0; + + /** Some formats may support a flush operation that makes sure the file is in a + valid state before carrying on. + If supported, this means that by calling flush periodically when writing data + to a large file, then it should still be left in a readable state if your program + crashes. + It goes without saying that this method must be called from the same thread that's + calling write()! + If the format supports flushing and the operation succeeds, this returns true. + */ + virtual bool flush(); //============================================================================== /** Reads a section of samples from an AudioFormatReader, and writes these to @@ -197,7 +207,12 @@ public: The object passed-in must not be deleted while this writer is still using it. */ - void setDataReceiver (IncomingDataReceiver* receiver); + void setDataReceiver (IncomingDataReceiver*); + + /** Sets how many samples should be written before calling the AudioFormatWriter::flush method. + Set this to 0 to disable flushing (this is the default). + */ + void setFlushInterval (int numSamplesPerFlush) noexcept; private: class Buffer; diff --git a/JuceLibraryCode/modules/juce_audio_formats/juce_module_info b/JuceLibraryCode/modules/juce_audio_formats/juce_module_info index 8ecc4bd..e355719 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.5", + "version": "3.0.8", "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_formats/sampler/juce_Sampler.cpp b/JuceLibraryCode/modules/juce_audio_formats/sampler/juce_Sampler.cpp index 9dbe7b3..4e7583e 100644 --- a/JuceLibraryCode/modules/juce_audio_formats/sampler/juce_Sampler.cpp +++ b/JuceLibraryCode/modules/juce_audio_formats/sampler/juce_Sampler.cpp @@ -59,12 +59,12 @@ SamplerSound::~SamplerSound() { } -bool SamplerSound::appliesToNote (const int midiNoteNumber) +bool SamplerSound::appliesToNote (int midiNoteNumber) { return midiNotes [midiNoteNumber]; } -bool SamplerSound::appliesToChannel (const int /*midiChannel*/) +bool SamplerSound::appliesToChannel (int /*midiChannel*/) { return true; } @@ -127,7 +127,7 @@ void SamplerVoice::startNote (const int midiNoteNumber, } } -void SamplerVoice::stopNote (const bool allowTailOff) +void SamplerVoice::stopNote (float /*velocity*/, bool allowTailOff) { if (allowTailOff) { @@ -197,7 +197,7 @@ void SamplerVoice::renderNextBlock (AudioSampleBuffer& outputBuffer, int startSa if (attackReleaseLevel <= 0.0f) { - stopNote (false); + stopNote (0.0f, false); break; } } @@ -216,7 +216,7 @@ void SamplerVoice::renderNextBlock (AudioSampleBuffer& outputBuffer, int startSa if (sourceSamplePosition > playingSound->length) { - stopNote (false); + stopNote (0.0f, false); break; } } diff --git a/JuceLibraryCode/modules/juce_audio_formats/sampler/juce_Sampler.h b/JuceLibraryCode/modules/juce_audio_formats/sampler/juce_Sampler.h index 51133ad..f801bf2 100644 --- a/JuceLibraryCode/modules/juce_audio_formats/sampler/juce_Sampler.h +++ b/JuceLibraryCode/modules/juce_audio_formats/sampler/juce_Sampler.h @@ -82,8 +82,8 @@ public: //============================================================================== - bool appliesToNote (const int midiNoteNumber) override; - bool appliesToChannel (const int midiChannel) override; + bool appliesToNote (int midiNoteNumber) override; + bool appliesToChannel (int midiChannel) override; private: @@ -124,7 +124,7 @@ public: bool canPlaySound (SynthesiserSound*) override; void startNote (int midiNoteNumber, float velocity, SynthesiserSound*, int pitchWheel) override; - void stopNote (bool allowTailOff) override; + void stopNote (float velocity, bool allowTailOff) override; void pitchWheelMoved (int newValue); void controllerMoved (int controllerNumber, int newValue) override; diff --git a/JuceLibraryCode/modules/juce_audio_processors/format/juce_AudioPluginFormat.h b/JuceLibraryCode/modules/juce_audio_processors/format/juce_AudioPluginFormat.h index 6336b5b..d0af201 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format/juce_AudioPluginFormat.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format/juce_AudioPluginFormat.h @@ -54,7 +54,7 @@ public: (e.g. VST shells) can use a single DLL to create a set of different plugin subtypes, so in that case, each subtype is returned as a separate object. */ - virtual void findAllTypesForFile (OwnedArray & results, + virtual void findAllTypesForFile (OwnedArray& results, const String& fileOrIdentifier) = 0; /** Tries to recreate a type from a previously generated PluginDescription. diff --git a/JuceLibraryCode/modules/juce_audio_processors/format/juce_AudioPluginFormatManager.h b/JuceLibraryCode/modules/juce_audio_processors/format/juce_AudioPluginFormatManager.h index 7e502b3..a6f1607 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format/juce_AudioPluginFormatManager.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format/juce_AudioPluginFormatManager.h @@ -89,7 +89,7 @@ public: private: //============================================================================== - OwnedArray formats; + OwnedArray formats; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginFormatManager) }; diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.h index ef6d59a..46c2b10 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.h @@ -37,7 +37,7 @@ public: //============================================================================== String getName() const override { return "AudioUnit"; } - void findAllTypesForFile (OwnedArray &, const String& fileOrIdentifier) override; + void findAllTypesForFile (OwnedArray&, const String& fileOrIdentifier) override; AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc, double, int) override; bool fileMightContainThisPluginType (const String& fileOrIdentifier) override; String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) override; 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 60d4c99..2877509 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm @@ -62,7 +62,7 @@ namespace AudioUnitFormatHelpers static ThreadLocalValue insideCallback; #endif - String osTypeToString (OSType type) + String osTypeToString (OSType type) noexcept { const juce_wchar s[4] = { (juce_wchar) ((type >> 24) & 0xff), (juce_wchar) ((type >> 16) & 0xff), @@ -88,9 +88,6 @@ namespace AudioUnitFormatHelpers String createPluginIdentifier (const AudioComponentDescription& desc) { - jassert (osTypeToString ('abcd') == "abcd"); // agh, must have got the endianness wrong.. - jassert (stringToOSType ("abcd") == (OSType) 'abcd'); // ditto - String s (auIdentifierPrefix); if (desc.componentType == kAudioUnitType_MusicDevice) @@ -138,7 +135,7 @@ namespace AudioUnitFormatHelpers fileOrIdentifier.lastIndexOfChar ('/')) + 1)); StringArray tokens; - tokens.addTokens (s, ",", String()); + tokens.addTokens (s, ",", StringRef()); tokens.removeEmptyStrings(); if (tokens.size() == 3) @@ -215,9 +212,11 @@ namespace AudioUnitFormatHelpers const short resFileId = CFBundleOpenBundleResourceMap (bundleRef); UseResFile (resFileId); - for (ResourceIndex i = 1; i <= Count1Resources ('thng'); ++i) + const OSType thngType = stringToOSType ("thng"); + + for (ResourceIndex i = 1; i <= Count1Resources (thngType); ++i) { - if (Handle h = Get1IndResource ('thng', i)) + if (Handle h = Get1IndResource (thngType, i)) { HLock (h); const uint32* const types = (const uint32*) *h; @@ -346,11 +345,21 @@ public: refreshParameterList(); updateNumChannels(); producesMidiMessages = canProduceMidiOutput(); - setPluginCallbacks(); setPlayConfigDetails (numInputBusChannels * numInputBusses, numOutputBusChannels * numOutputBusses, rate, blockSize); setLatencySamples (0); + + if (parameters.size() == 0) + { + // some plugins crash if initialiseAudioUnit() is called too soon (sigh..), so we'll + // only call it here if it seems like they it's one of the awkward plugins that can + // only create their parameters after it has been initialised. + initialiseAudioUnit(); + refreshParameterList(); + } + + setPluginCallbacks(); } //============================================================================== @@ -915,7 +924,7 @@ private: bool automatable; }; - OwnedArray parameters; + OwnedArray parameters; MidiDataConcatenator midiConcatenator; CriticalSection midiInLock; @@ -972,16 +981,11 @@ private: for (int i = 0; i < parameters.size(); ++i) { - const ParamInfo& p = *parameters.getUnchecked(i); - - AudioUnitParameter paramToAdd; - paramToAdd.mAudioUnit = audioUnit; - paramToAdd.mParameterID = p.paramID; - paramToAdd.mScope = kAudioUnitScope_Global; - paramToAdd.mElement = 0; - AudioUnitEvent event; - event.mArgument.mParameter = paramToAdd; + event.mArgument.mParameter.mAudioUnit = audioUnit; + event.mArgument.mParameter.mParameterID = parameters.getUnchecked(i)->paramID; + event.mArgument.mParameter.mScope = kAudioUnitScope_Global; + event.mArgument.mParameter.mElement = 0; event.mEventType = kAudioUnitEvent_ParameterValueChange; AUEventListenerAddEventType (eventListenerRef, nullptr, &event); @@ -992,6 +996,16 @@ private: event.mEventType = kAudioUnitEvent_EndParameterChangeGesture; AUEventListenerAddEventType (eventListenerRef, nullptr, &event); } + + // Add a listener for program changes + AudioUnitEvent event; + event.mArgument.mProperty.mAudioUnit = audioUnit; + event.mArgument.mProperty.mPropertyID = kAudioUnitProperty_PresentPreset; + event.mArgument.mProperty.mScope = kAudioUnitScope_Global; + event.mArgument.mProperty.mElement = 0; + + event.mEventType = kAudioUnitEvent_PropertyChange; + AUEventListenerAddEventType (eventListenerRef, nullptr, &event); } } @@ -1022,6 +1036,7 @@ private: break; default: + sendAllParametersChangedEvents(); break; } } @@ -1600,7 +1615,7 @@ AudioUnitPluginFormat::~AudioUnitPluginFormat() { } -void AudioUnitPluginFormat::findAllTypesForFile (OwnedArray & results, +void AudioUnitPluginFormat::findAllTypesForFile (OwnedArray& results, const String& fileOrIdentifier) { if (! fileMightContainThisPluginType (fileOrIdentifier)) diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.cpp index 81b369a..1bb2413 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.cpp @@ -118,8 +118,8 @@ class LADSPAPluginInstance : public AudioPluginInstance { public: LADSPAPluginInstance (const LADSPAModuleHandle::Ptr& m) - : plugin (nullptr), handle (nullptr), initialised (false), - tempBuffer (1, 1), module (m) + : module (m), plugin (nullptr), handle (nullptr), + initialised (false), tempBuffer (1, 1) { ++insideLADSPACallback; diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3Common.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3Common.h index c91411c..d7e66cd 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3Common.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3Common.h @@ -85,6 +85,18 @@ static Steinberg::Vst::TChar* toString (const juce::String& source) noexcept //============================================================================== +static Steinberg::Vst::SpeakerArrangement getArrangementForBus (Steinberg::Vst::IAudioProcessor* processor, + bool isInput, int busIndex) +{ + Steinberg::Vst::SpeakerArrangement arrangement = Steinberg::Vst::SpeakerArr::kEmpty; + + if (processor != nullptr) + processor->getBusArrangement (isInput ? Steinberg::Vst::kInput : Steinberg::Vst::kOutput, + (Steinberg::int32) busIndex, arrangement); + + return arrangement; +} + /** For the sake of simplicity, there can only be 1 arrangement type per channel count. i.e.: 4 channels == k31Cine OR k40Cine */ @@ -126,9 +138,9 @@ class ComSmartPtr { public: ComSmartPtr() noexcept : source (nullptr) {} - ComSmartPtr (ObjectType* object) noexcept : source (object) { if (source != nullptr) source->addRef(); } - ComSmartPtr (const ComSmartPtr& other) noexcept : source (other.source) { if (source != nullptr) source->addRef(); } - ~ComSmartPtr() { if (source != nullptr) source->release(); } + ComSmartPtr (ObjectType* object, bool autoAddRef = true) noexcept : source (object) { if (source != nullptr && autoAddRef) source->addRef(); } + ComSmartPtr (const ComSmartPtr& other) noexcept : source (other.source) { if (source != nullptr) source->addRef(); } + ~ComSmartPtr() { if (source != nullptr) source->release(); } operator ObjectType*() const noexcept { return source; } ObjectType* get() const noexcept { return source; } @@ -341,7 +353,7 @@ namespace VST3BufferExchange Bus& bus, AudioSampleBuffer& buffer, int numChannels, int channelStartOffset, - int sampleOffset = 0) noexcept + int sampleOffset = 0) { const int channelEnd = numChannels + channelStartOffset; jassert (channelEnd >= 0 && channelEnd <= buffer.getNumChannels()); @@ -356,37 +368,52 @@ namespace VST3BufferExchange vstBuffers.silenceFlags = 0; } + static void mapArrangementToBusses (int& channelIndexOffset, int index, + Array& result, + BusMap& busMapToUse, Steinberg::Vst::SpeakerArrangement arrangement, + AudioSampleBuffer& source) + { + const int numChansForBus = BigInteger ((juce::int64) arrangement).countNumberOfSetBits(); + + if (index >= result.size()) + result.add (Steinberg::Vst::AudioBusBuffers()); + + if (index >= busMapToUse.size()) + busMapToUse.add (Bus()); + + if (numChansForBus > 0) + { + associateBufferTo (result.getReference (index), + busMapToUse.getReference (index), + source, numChansForBus, channelIndexOffset); + } + + channelIndexOffset += numChansForBus; + } + + static void mapBufferToBusses (Array& result, BusMap& busMapToUse, + const Array& arrangements, + AudioSampleBuffer& source) + { + int channelIndexOffset = 0; + + for (int i = 0; i < arrangements.size(); ++i) + mapArrangementToBusses (channelIndexOffset, i, result, busMapToUse, + arrangements.getUnchecked (i), source); + } + static void mapBufferToBusses (Array& result, Steinberg::Vst::IAudioProcessor& processor, - BusMap& busMapToUse, - bool isInput, int numBusses, + BusMap& busMapToUse, bool isInput, int numBusses, AudioSampleBuffer& source) { int channelIndexOffset = 0; for (int i = 0; i < numBusses; ++i) - { - Steinberg::Vst::SpeakerArrangement arrangement = 0; - processor.getBusArrangement (isInput ? Steinberg::Vst::kInput : Steinberg::Vst::kOutput, - (Steinberg::int32) i, arrangement); - - const int numChansForBus = BigInteger ((juce::int64) arrangement).countNumberOfSetBits(); - - if (i >= result.size()) - result.add (Steinberg::Vst::AudioBusBuffers()); - - if (i >= busMapToUse.size()) - busMapToUse.add (Bus()); - - if (numChansForBus > 0) - { - associateBufferTo (result.getReference (i), - busMapToUse.getReference (i), - source, numChansForBus, channelIndexOffset); - } - - channelIndexOffset += numChansForBus; - } + mapArrangementToBusses (channelIndexOffset, i, + result, busMapToUse, + getArrangementForBus (&processor, isInput, i), + source); } } 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 4dfd4f8..a741626 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp @@ -31,6 +31,7 @@ #define JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY 1 #endif +#include #include "juce_VST3Headers.h" #undef JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY @@ -111,6 +112,7 @@ static void createPluginDescription (PluginDescription& description, description.lastFileModTime = pluginFile.getLastModificationTime(); description.manufacturerName = company; description.name = name; + description.descriptiveName = name; description.pluginFormatName = "VST3"; description.numInputChannels = numInputs; description.numOutputChannels = numOutputs; @@ -378,32 +380,65 @@ public: FUnknown* getFUnknown() { return static_cast (this); } + static bool hasFlag (Steinberg::int32 source, Steinberg::int32 flag) noexcept + { + return (source & flag) == flag; + } + //============================================================================== - tresult PLUGIN_API beginEdit (Vst::ParamID) override + tresult PLUGIN_API beginEdit (Vst::ParamID paramID) override { - // XXX todo.. - return kResultFalse; + const int index = getIndexOfParamID (paramID); + + if (index < 0) + return kResultFalse; + + owner->beginParameterChangeGesture (index); + return kResultTrue; } - tresult PLUGIN_API performEdit (Vst::ParamID id, Vst::ParamValue valueNormalized) override + tresult PLUGIN_API performEdit (Vst::ParamID paramID, Vst::ParamValue valueNormalized) override { - if (owner != nullptr) - return owner->editController->setParamNormalized (id, valueNormalized); + const int index = getIndexOfParamID (paramID); - return kResultFalse; + if (index < 0) + return kResultFalse; + + owner->sendParamChangeMessageToListeners (index, (float) valueNormalized); + return owner->editController->setParamNormalized (paramID, valueNormalized); } - tresult PLUGIN_API endEdit (Vst::ParamID) override + tresult PLUGIN_API endEdit (Vst::ParamID paramID) override { - // XXX todo.. - return kResultFalse; + const int index = getIndexOfParamID (paramID); + + if (index < 0) + return kResultFalse; + + owner->endParameterChangeGesture (index); + return kResultTrue; } - tresult PLUGIN_API restartComponent (Steinberg::int32) override + tresult PLUGIN_API restartComponent (Steinberg::int32 flags) override { if (owner != nullptr) { - owner->reset(); + if (hasFlag (flags, Vst::kReloadComponent)) + owner->reset(); + + if (hasFlag (flags, Vst::kIoChanged)) + { + const double sampleRate = owner->getSampleRate(); + const int blockSize = owner->getBlockSize(); + + owner->prepareToPlay (sampleRate >= 8000 ? sampleRate : 44100.0, + blockSize > 0 ? blockSize : 1024); + } + + if (hasFlag (flags, Vst::kLatencyChanged)) + if (owner->processor != nullptr) + owner->setLatencySamples (jmax (0, (int) owner->processor->getLatencySamples())); + owner->updateHostDisplay(); return kResultTrue; } @@ -437,9 +472,171 @@ public: return kResultFalse; } + //============================================================================== + class ContextMenu : public Vst::IContextMenu + { + public: + ContextMenu (VST3PluginInstance& pluginInstance) : owner (pluginInstance) {} + virtual ~ContextMenu() {} + + JUCE_DECLARE_VST3_COM_REF_METHODS + JUCE_DECLARE_VST3_COM_QUERY_METHODS + + Steinberg::int32 PLUGIN_API getItemCount() override { return (Steinberg::int32) items.size(); } + + tresult PLUGIN_API addItem (const Item& item, IContextMenuTarget* target) override + { + jassert (target != nullptr); + + ItemAndTarget newItem; + newItem.item = item; + newItem.target = target; + + items.add (newItem); + return kResultOk; + } + + tresult PLUGIN_API removeItem (const Item& toRemove, IContextMenuTarget* target) override + { + for (int i = items.size(); --i >= 0;) + { + ItemAndTarget& item = items.getReference(i); + + if (item.item.tag == toRemove.tag && item.target == target) + items.remove (i); + } + + return kResultOk; + } + + tresult PLUGIN_API getItem (Steinberg::int32 tag, Item& result, IContextMenuTarget** target) override + { + for (int i = 0; i < items.size(); ++i) + { + const ItemAndTarget& item = items.getReference(i); + + if (item.item.tag == tag) + { + result = item.item; + + if (target != nullptr) + *target = item.target; + + return kResultTrue; + } + } + + zerostruct (result); + return kResultFalse; + } + + tresult PLUGIN_API popup (Steinberg::UCoord x, Steinberg::UCoord y) override + { + Array subItemStack; + OwnedArray menuStack; + PopupMenu* topLevelMenu = menuStack.add (new PopupMenu()); + + for (int i = 0; i < items.size(); ++i) + { + const Item& item = items.getReference (i).item; + + PopupMenu* menuToUse = menuStack.getLast(); + + if (hasFlag (item.flags, Item::kIsGroupStart & ~Item::kIsDisabled)) + { + subItemStack.add (&item); + menuStack.add (new PopupMenu()); + } + else if (hasFlag (item.flags, Item::kIsGroupEnd)) + { + if (const Item* subItem = subItemStack.getLast()) + { + if (PopupMenu* m = menuStack [menuStack.size() - 2]) + m->addSubMenu (toString (subItem->name), *menuToUse, + ! hasFlag (subItem->flags, Item::kIsDisabled), + nullptr, + hasFlag (subItem->flags, Item::kIsChecked)); + + menuStack.removeLast (1); + subItemStack.removeLast (1); + } + } + else if (hasFlag (item.flags, Item::kIsSeparator)) + { + menuToUse->addSeparator(); + } + else + { + menuToUse->addItem (item.tag != 0 ? (int) item.tag : (int) zeroTagReplacement, + toString (item.name), + ! hasFlag (item.flags, Item::kIsDisabled), + hasFlag (item.flags, Item::kIsChecked)); + } + } + + PopupMenu::Options options; + + if (AudioProcessorEditor* ed = owner.getActiveEditor()) + options = options.withTargetScreenArea (ed->getScreenBounds().translated ((int) x, (int) y).withSize (1, 1)); + + #if JUCE_MODAL_LOOPS_PERMITTED + // Unfortunately, Steinberg's docs explicitly say this should be modal.. + handleResult (topLevelMenu->showMenu (options)); + #else + topLevelMenu->showMenuAsync (options, ModalCallbackFunction::create (menuFinished, ComSmartPtr (this))); + #endif + + return kResultOk; + } + + #if ! JUCE_MODAL_LOOPS_PERMITTED + static void menuFinished (int modalResult, ComSmartPtr menu) { menu->handleResult (modalResult); } + #endif + + private: + enum { zeroTagReplacement = 0x7fffffff }; + + Atomic refCount; + VST3PluginInstance& owner; + + struct ItemAndTarget + { + Item item; + ComSmartPtr target; + }; + + Array items; + + void handleResult (int result) + { + if (result == 0) + return; + + if (result == zeroTagReplacement) + result = 0; + + for (int i = 0; i < items.size(); ++i) + { + const ItemAndTarget& item = items.getReference(i); + + if ((int) item.item.tag == result) + { + if (item.target != nullptr) + item.target->executeMenuItem ((Steinberg::int32) result); + + break; + } + } + } + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ContextMenu) + }; + Vst::IContextMenu* PLUGIN_API createContextMenu (IPlugView*, const Vst::ParamID*) override { - jassertfalse; + if (owner != nullptr) + return new ContextMenu (*owner); + return nullptr; } @@ -549,9 +746,42 @@ public: private: //============================================================================== - Atomic refCount; + VST3PluginInstance* const owner; + Atomic refCount; String appName; - VST3PluginInstance* owner; + + typedef std::map ParamMapType; + ParamMapType paramToIndexMap; + + int getIndexOfParamID (Vst::ParamID paramID) + { + if (owner == nullptr || owner->editController == nullptr) + return -1; + + int result = getMappedParamID (paramID); + + if (result < 0) + { + const int numParams = owner->editController->getParameterCount(); + + for (int i = 0; i < numParams; ++i) + { + Vst::ParameterInfo paramInfo; + owner->editController->getParameterInfo (i, paramInfo); + paramToIndexMap[paramInfo.id] = i; + } + + result = getMappedParamID (paramID); + } + + return result; + } + + int getMappedParamID (Vst::ParamID paramID) + { + const ParamMapType::iterator it (paramToIndexMap.find (paramID)); + return it != paramToIndexMap.end() ? it->second : -1; + } //============================================================================== class Message : public Vst::IMessage @@ -577,9 +807,9 @@ private: JUCE_DECLARE_VST3_COM_REF_METHODS JUCE_DECLARE_VST3_COM_QUERY_METHODS - FIDString PLUGIN_API getMessageID() { return messageId.toRawUTF8(); } - void PLUGIN_API setMessageID (FIDString id) { messageId = toString (id); } - Vst::IAttributeList* PLUGIN_API getAttributes() { return attributeList; } + FIDString PLUGIN_API getMessageID() override { return messageId.toRawUTF8(); } + void PLUGIN_API setMessageID (FIDString id) override { messageId = toString (id); } + Vst::IAttributeList* PLUGIN_API getAttributes() override { return attributeList; } var value; @@ -587,7 +817,7 @@ private: VST3HostContext& owner; ComSmartPtr attributeList; String messageId; - Atomic refCount; + Atomic refCount; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Message) }; @@ -715,7 +945,7 @@ private: private: VST3HostContext* owner; - Atomic refCount; + Atomic refCount; //============================================================================== template @@ -1195,7 +1425,8 @@ public: VST3PluginWindow (AudioProcessor* owner, IPlugView* pluginView) : AudioProcessorEditor (owner), ComponentMovementWatcher (this), - view (pluginView), + refCount (1), + view (pluginView, false), pluginHandle (nullptr), recursiveResize (false) { @@ -1213,7 +1444,9 @@ public: ~VST3PluginWindow() { warnOnFailure (view->removed()); - getAudioProcessor()->editorBeingDeleted (this); + warnOnFailure (view->setFrame (nullptr)); + + processor.editorBeingDeleted (this); #if JUCE_MAC dummyComponent.setView (nullptr); @@ -1266,20 +1499,32 @@ public: { rect.right = (Steinberg::int32) getWidth(); rect.bottom = (Steinberg::int32) getHeight(); + view->checkSizeConstraint (&rect); + + setSize ((int) rect.getWidth(), (int) rect.getHeight()); + + #if JUCE_WINDOWS + SetWindowPos (pluginHandle, 0, + pos.x, pos.y, rect.getWidth(), rect.getHeight(), + isVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW); + #elif JUCE_MAC + dummyComponent.setBounds (getLocalBounds()); + #endif + view->onSize (&rect); } else { warnOnFailure (view->getSize (&rect)); - } - #if JUCE_WINDOWS - SetWindowPos (pluginHandle, 0, - pos.x, pos.y, rect.getWidth(), rect.getHeight(), - isVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW); - #elif JUCE_MAC - dummyComponent.setBounds (0, 0, (int) rect.getWidth(), (int) rect.getHeight()); - #endif + #if JUCE_WINDOWS + SetWindowPos (pluginHandle, 0, + pos.x, pos.y, rect.getWidth(), rect.getHeight(), + isVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW); + #elif JUCE_MAC + dummyComponent.setBounds (0, 0, (int) rect.getWidth(), (int) rect.getHeight()); + #endif + } // Some plugins don't update their cursor correctly when mousing out the window Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate(); @@ -1364,7 +1609,7 @@ private: if (peer != nullptr) pluginHandle = (HandleFormat) peer->getNativeHandle(); #elif JUCE_MAC - dummyComponent.setBounds (getBounds().withZeroOrigin()); + dummyComponent.setBounds (getLocalBounds()); addAndMakeVisible (dummyComponent); pluginHandle = (NSView*) dummyComponent.getView(); jassert (pluginHandle != nil); @@ -1391,7 +1636,8 @@ public: midiInputs (new MidiEventList()), midiOutputs (new MidiEventList()), isComponentInitialised (false), - isControllerInitialised (false) + isControllerInitialised (false), + isActive (false) { host = new VST3HostContext (this); } @@ -1413,7 +1659,6 @@ public: if (isControllerInitialised) editController->terminate(); if (isComponentInitialised) component->terminate(); - //Deletion order appears to matter: componentConnection = nullptr; editControllerConnection = nullptr; unitData = nullptr; @@ -1425,6 +1670,8 @@ public: editController2 = nullptr; editController = nullptr; component = nullptr; + host = nullptr; + module = nullptr; } bool initialise() @@ -1478,8 +1725,27 @@ public: return module != nullptr ? module->name : String::empty; } + void repopulateArrangements() + { + inputArrangements.clearQuick(); + outputArrangements.clearQuick(); + + // NB: Some plugins need a valid arrangement despite specifying 0 for their I/O busses + for (int i = 0; i < jmax (1, numInputAudioBusses); ++i) + inputArrangements.add (getArrangementForBus (processor, true, i)); + + for (int i = 0; i < jmax (1, numOutputAudioBusses); ++i) + outputArrangements.add (getArrangementForBus (processor, false, i)); + } + void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock) override { + // Avoid redundantly calling things like setActive, which can be a heavy-duty call for some plugins: + if (isActive + && getSampleRate() == sampleRate + && getBlockSize() == estimatedSamplesPerBlock) + return; + using namespace Vst; ProcessSetup setup; @@ -1495,20 +1761,25 @@ public: editController->setComponentHandler (host); - Array inArrangements, outArrangements; + if (inputArrangements.size() <= 0 || outputArrangements.size() <= 0) + repopulateArrangements(); - for (int i = 0; i < numInputAudioBusses; ++i) - inArrangements.add (getArrangementForNumChannels (jmax (0, (int) getBusInfo (true, true, i).channelCount))); - - for (int i = 0; i < numOutputAudioBusses; ++i) - outArrangements.add (getArrangementForNumChannels (jmax (0, (int) getBusInfo (false, true, i).channelCount))); - - warnOnFailure (processor->setBusArrangements (inArrangements.getRawDataPointer(), numInputAudioBusses, - outArrangements.getRawDataPointer(), numOutputAudioBusses)); + warnOnFailure (processor->setBusArrangements (inputArrangements.getRawDataPointer(), numInputAudioBusses, + outputArrangements.getRawDataPointer(), numOutputAudioBusses)); // Update the num. busses in case the configuration has been modified by the plugin. (May affect number of channels!): - numInputAudioBusses = getNumSingleDirectionBussesFor (component, true, true); - numOutputAudioBusses = getNumSingleDirectionBussesFor (component, false, true); + const int newNumInputAudioBusses = getNumSingleDirectionBussesFor (component, true, true); + const int newNumOutputAudioBusses = getNumSingleDirectionBussesFor (component, false, true); + + // Repopulate arrangements if the number of busses have changed: + if (numInputAudioBusses != newNumInputAudioBusses + || numOutputAudioBusses != newNumOutputAudioBusses) + { + numInputAudioBusses = newNumInputAudioBusses; + numOutputAudioBusses = newNumOutputAudioBusses; + + repopulateArrangements(); + } // Needed for having the same sample rate in processBlock(); some plugins need this! setPlayConfigDetails (getNumSingleDirectionChannelsFor (component, true, true), @@ -1517,21 +1788,30 @@ public: setStateForAllBusses (true); + setLatencySamples (jmax (0, (int) processor->getLatencySamples())); + warnOnFailure (component->setActive (true)); warnOnFailure (processor->setProcessing (true)); + + isActive = true; } void releaseResources() override { + if (! isActive) + return; // Avoids redundantly calling things like setActive + JUCE_TRY { + isActive = false; + setStateForAllBusses (false); if (processor != nullptr) - processor->setProcessing (false); + warnOnFailure (processor->setProcessing (false)); if (component != nullptr) - component->setActive (false); + warnOnFailure (component->setActive (false)); } JUCE_CATCH_ALL_ASSERT } @@ -1540,7 +1820,8 @@ public: { using namespace Vst; - if (processor != nullptr + if (isActive + && processor != nullptr && processor->canProcessSampleSize (kSample32) == kResultTrue) { const int numSamples = buffer.getNumSamples(); @@ -1612,15 +1893,22 @@ public: //============================================================================== bool silenceInProducesSilenceOut() const override { - return processor == nullptr; + if (processor != nullptr) + return processor->getTailSamples() == Vst::kNoTail; + + return true; } /** May return a negative value as a means of informing us that the plugin has "infinite tail," or 0 for "no tail." */ double getTailLengthSeconds() const override { if (processor != nullptr) - return (double) jmin ((int) jmax ((Steinberg::uint32) 0, processor->getTailSamples()), 0x7fffffff) - * getSampleRate(); + { + const double sampleRate = getSampleRate(); + + if (sampleRate > 0.0) + return jlimit (0, 0x7fffffff, (int) processor->getTailSamples()) / sampleRate; + } return 0.0; } @@ -1640,7 +1928,7 @@ public: if (getActiveEditor() != nullptr) return true; - ComSmartPtr view (tryCreatingView()); + ComSmartPtr view (tryCreatingView(), false); return view != nullptr; } @@ -1706,6 +1994,16 @@ public: return toString (result); } + //============================================================================== + void reset() override + { + if (component != nullptr) + { + component->setActive (false); + component->setActive (true); + } + } + //============================================================================== void getStateInformation (MemoryBlock& destData) override { @@ -1785,6 +2083,7 @@ private: as very poorly specified by the Steinberg SDK */ int numInputAudioBusses, numOutputAudioBusses; + Array inputArrangements, outputArrangements; // Caching to improve performance and to avoid possible non-thread-safe calls to getBusArrangements(). VST3BufferExchange::BusMap inputBusMap, outputBusMap; Array inputBusses, outputBusses; @@ -1813,7 +2112,11 @@ private: MemoryBlock mem; if (mem.fromBase64Encoding (state->getAllSubText())) - stream = new Steinberg::MemoryStream (mem.getData(), (TSize) mem.getSize()); + { + stream = new Steinberg::MemoryStream(); + stream->setSize ((TSize) mem.getSize()); + mem.copyTo (stream->getData(), 0, mem.getSize()); + } } return stream; @@ -1829,21 +2132,21 @@ private: JUCE_DECLARE_VST3_COM_REF_METHODS JUCE_DECLARE_VST3_COM_QUERY_METHODS - Steinberg::int32 PLUGIN_API getParameterCount() { return 0; } + Steinberg::int32 PLUGIN_API getParameterCount() override { return 0; } - Vst::IParamValueQueue* PLUGIN_API getParameterData (Steinberg::int32) + Vst::IParamValueQueue* PLUGIN_API getParameterData (Steinberg::int32) override { return nullptr; } - Vst::IParamValueQueue* PLUGIN_API addParameterData (const Vst::ParamID&, Steinberg::int32& index) + Vst::IParamValueQueue* PLUGIN_API addParameterData (const Vst::ParamID&, Steinberg::int32& index) override { index = 0; return nullptr; } private: - Atomic refCount; + Atomic refCount; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParameterChangeList) }; @@ -1851,7 +2154,7 @@ private: ComSmartPtr inputParameterChanges, outputParameterChanges; ComSmartPtr midiInputs, midiOutputs; Vst::ProcessContext timingInfo; //< Only use this in processBlock()! - bool isComponentInitialised, isControllerInitialised; + bool isComponentInitialised, isControllerInitialised, isActive; //============================================================================== bool fetchComponentAndController (IPluginFactory* factory, const Steinberg::int32 numClasses) @@ -2031,11 +2334,11 @@ private: Vst::BusInfo getBusInfo (bool forInput, bool forAudio, int index = 0) const { Vst::BusInfo busInfo; + busInfo.mediaType = forAudio ? Vst::kAudio : Vst::kEvent; + busInfo.direction = forInput ? Vst::kInput : Vst::kOutput; - component->getBusInfo (forAudio ? Vst::kAudio : Vst::kEvent, - forInput ? Vst::kInput : Vst::kOutput, + component->getBusInfo (busInfo.mediaType, busInfo.direction, (Steinberg::int32) index, busInfo); - return busInfo; } @@ -2056,11 +2359,8 @@ private: { using namespace VST3BufferExchange; - mapBufferToBusses (inputBusses, *processor, inputBusMap, - true, numInputAudioBusses, buffer); - - mapBufferToBusses (outputBusses, *processor, outputBusMap, - false, numOutputAudioBusses, buffer); + mapBufferToBusses (inputBusses, inputBusMap, inputArrangements, buffer); + mapBufferToBusses (outputBusses, outputBusMap, outputArrangements, buffer); destination.inputs = inputBusses.getRawDataPointer(); destination.outputs = outputBusses.getRawDataPointer(); 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 c6084e3..5509e2c 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp @@ -29,13 +29,6 @@ #include "../../juce_gui_extra/native/juce_mac_CarbonViewWrapperComponent.h" #endif -#if JUCE_MAC - static bool makeFSRefFromPath (FSRef* destFSRef, const String& path) - { - return FSPathMakeRef (reinterpret_cast (path.toRawUTF8()), destFSRef, 0) == noErr; - } -#endif - //============================================================================== #undef PRAGMA_ALIGN_SUPPORTED #define VST_FORCE_DEPRECATED 0 @@ -84,74 +77,68 @@ #endif //============================================================================== -const int fxbVersionNum = 1; - -struct fxProgram -{ - VstInt32 chunkMagic; // 'CcnK' - VstInt32 byteSize; // of this chunk, excl. magic + byteSize - VstInt32 fxMagic; // 'FxCk' - VstInt32 version; - VstInt32 fxID; // fx unique id - VstInt32 fxVersion; - VstInt32 numParams; - char prgName[28]; - float params[1]; // variable no. of parameters -}; - -struct fxSet -{ - VstInt32 chunkMagic; // 'CcnK' - VstInt32 byteSize; // of this chunk, excl. magic + byteSize - VstInt32 fxMagic; // 'FxBk' - VstInt32 version; - VstInt32 fxID; // fx unique id - VstInt32 fxVersion; - VstInt32 numPrograms; - char future[128]; - fxProgram programs[1]; // variable no. of programs -}; - -struct fxChunkSet -{ - VstInt32 chunkMagic; // 'CcnK' - VstInt32 byteSize; // of this chunk, excl. magic + byteSize - VstInt32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh' - VstInt32 version; - VstInt32 fxID; // fx unique id - VstInt32 fxVersion; - VstInt32 numPrograms; - char future[128]; - VstInt32 chunkSize; - char chunk[8]; // variable -}; - -struct fxProgramSet -{ - VstInt32 chunkMagic; // 'CcnK' - VstInt32 byteSize; // of this chunk, excl. magic + byteSize - VstInt32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh' - VstInt32 version; - VstInt32 fxID; // fx unique id - VstInt32 fxVersion; - VstInt32 numPrograms; - char name[28]; - VstInt32 chunkSize; - char chunk[8]; // variable -}; - namespace { - VstInt32 vst_swap (const VstInt32 x) noexcept - { - #ifdef JUCE_LITTLE_ENDIAN - return (VstInt32) ByteOrder::swap ((uint32) x); - #else - return x; - #endif - } + const int fxbVersionNum = 1; - float vst_swapFloat (const float x) noexcept + struct fxProgram + { + VstInt32 chunkMagic; // 'CcnK' + VstInt32 byteSize; // of this chunk, excl. magic + byteSize + VstInt32 fxMagic; // 'FxCk' + VstInt32 version; + VstInt32 fxID; // fx unique id + VstInt32 fxVersion; + VstInt32 numParams; + char prgName[28]; + float params[1]; // variable no. of parameters + }; + + struct fxSet + { + VstInt32 chunkMagic; // 'CcnK' + VstInt32 byteSize; // of this chunk, excl. magic + byteSize + VstInt32 fxMagic; // 'FxBk' + VstInt32 version; + VstInt32 fxID; // fx unique id + VstInt32 fxVersion; + VstInt32 numPrograms; + char future[128]; + fxProgram programs[1]; // variable no. of programs + }; + + struct fxChunkSet + { + VstInt32 chunkMagic; // 'CcnK' + VstInt32 byteSize; // of this chunk, excl. magic + byteSize + VstInt32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh' + VstInt32 version; + VstInt32 fxID; // fx unique id + VstInt32 fxVersion; + VstInt32 numPrograms; + char future[128]; + VstInt32 chunkSize; + char chunk[8]; // variable + }; + + struct fxProgramSet + { + VstInt32 chunkMagic; // 'CcnK' + VstInt32 byteSize; // of this chunk, excl. magic + byteSize + VstInt32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh' + VstInt32 version; + VstInt32 fxID; // fx unique id + VstInt32 fxVersion; + VstInt32 numPrograms; + char name[28]; + VstInt32 chunkSize; + char chunk[8]; // variable + }; + + static VstInt32 fxbName (const char* name) noexcept { return (VstInt32) ByteOrder::bigEndianInt (name); } + static VstInt32 fxbSwap (const VstInt32 x) noexcept { return (VstInt32) ByteOrder::swapIfLittleEndian ((uint32) x); } + + static float fxbSwapFloat (const float x) noexcept { #ifdef JUCE_LITTLE_ENDIAN union { uint32 asInt; float asFloat; } n; @@ -162,8 +149,12 @@ namespace return x; #endif } +} - double getVSTHostTimeNanoseconds() +//============================================================================== +namespace +{ + static double getVSTHostTimeNanoseconds() noexcept { #if JUCE_WINDOWS return timeGetTime() * 1000000.0; @@ -177,40 +168,52 @@ namespace return micro.lo * 1000.0; #endif } + + static int shellUIDToCreate = 0; + static int insideVSTCallback = 0; + + struct IdleCallRecursionPreventer + { + IdleCallRecursionPreventer() : isMessageThread (MessageManager::getInstance()->isThisTheMessageThread()) + { + if (isMessageThread) + ++insideVSTCallback; + } + + ~IdleCallRecursionPreventer() + { + if (isMessageThread) + --insideVSTCallback; + } + + const bool isMessageThread; + JUCE_DECLARE_NON_COPYABLE (IdleCallRecursionPreventer) + }; + + #if JUCE_MAC + static bool makeFSRefFromPath (FSRef* destFSRef, const String& path) + { + return FSPathMakeRef (reinterpret_cast (path.toRawUTF8()), destFSRef, 0) == noErr; + } + #endif + + #if JUCE_MAC && JUCE_PPC + static void* newCFMFromMachO (void* const machofp) noexcept + { + void* result = (void*) new char[8]; + + ((void**) result)[0] = machofp; + ((void**) result)[1] = result; + + return result; + } + #endif } //============================================================================== typedef AEffect* (VSTCALLBACK *MainCall) (audioMasterCallback); - static VstIntPtr VSTCALLBACK audioMaster (AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt); -static int shellUIDToCreate = 0; -static int insideVSTCallback = 0; - -class IdleCallRecursionPreventer -{ -public: - IdleCallRecursionPreventer() - : isMessageThread (MessageManager::getInstance()->isThisTheMessageThread()) - { - if (isMessageThread) - ++insideVSTCallback; - } - - ~IdleCallRecursionPreventer() - { - if (isMessageThread) - --insideVSTCallback; - } - -private: - const bool isMessageThread; - - JUCE_DECLARE_NON_COPYABLE (IdleCallRecursionPreventer) -}; - -class VSTPluginWindow; - //============================================================================== // Change this to disable logging of various VST activities #ifndef VST_LOGGING @@ -223,27 +226,12 @@ class VSTPluginWindow; #define JUCE_VST_LOG(a) #endif -//============================================================================== -#if JUCE_MAC && JUCE_PPC -static void* NewCFMFromMachO (void* const machofp) noexcept -{ - void* result = (void*) new char[8]; - - ((void**) result)[0] = machofp; - ((void**) result)[1] = result; - - return result; -} -#endif - //============================================================================== #if JUCE_LINUX extern Display* display; extern XContext windowHandleXContext; -typedef void (*EventProcPtr) (XEvent* ev); - namespace { static bool xErrorTriggered = false; @@ -254,6 +242,8 @@ namespace return 0; } + typedef void (*EventProcPtr) (XEvent* ev); + static EventProcPtr getPropertyFromXWindow (Window handle, Atom atom) { XErrorHandler oldErrorHandler = XSetErrorHandler (temporaryErrorHandler); @@ -269,8 +259,7 @@ namespace XSetErrorHandler (oldErrorHandler); - return (userCount == 1 && ! xErrorTriggered) ? *reinterpret_cast (data) - : 0; + return (userCount == 1 && ! xErrorTriggered) ? *reinterpret_cast (data) : nullptr; } Window getChildWindow (Window windowToCheck) @@ -279,12 +268,7 @@ namespace Window* childWindows; unsigned int numChildren = 0; - XQueryTree (display, - windowToCheck, - &rootWindow, - &parentWindow, - &childWindows, - &numChildren); + XQueryTree (display, windowToCheck, &rootWindow, &parentWindow, &childWindows, &numChildren); if (numChildren > 0) return childWindows [0]; @@ -354,9 +338,9 @@ public: typedef ReferenceCountedObjectPtr Ptr; - static Array & getActiveModules() + static Array& getActiveModules() { - static Array activeModules; + static Array activeModules; return activeModules; } @@ -470,7 +454,7 @@ public: { if (HGLOBAL hGlob = LoadResource (dllModule, res)) { - const char* data = static_cast (LockResource (hGlob)); + const char* data = static_cast (LockResource (hGlob)); return String::fromUTF8 (data, SizeofResource (dllModule, res)); } } @@ -552,7 +536,7 @@ public: } } } -#if JUCE_PPC + #if JUCE_PPC else { FSRef fn; @@ -605,7 +589,7 @@ public: } } } -#endif + #endif return ok; } @@ -683,7 +667,7 @@ public: static void disposeMachOFromCFM (void* ptr) { - delete[] static_cast (ptr); + delete[] static_cast (ptr); } void coerceAEffectFunctionCalls (AEffect* eff) @@ -715,11 +699,11 @@ class VSTPluginInstance : public AudioPluginInstance, private AsyncUpdater { public: - VSTPluginInstance (const ModuleHandle::Ptr& module_) + VSTPluginInstance (const ModuleHandle::Ptr& mh) : effect (nullptr), - module (module_), + module (mh), usesCocoaNSView (false), - name (module_->pluginName), + name (mh->pluginName), wantsMidiMessages (false), initialised (false), isPowerOn (false), @@ -741,7 +725,7 @@ public: { static void* audioMasterCoerced = nullptr; if (audioMasterCoerced == nullptr) - audioMasterCoerced = NewCFMFromMachO ((void*) &audioMaster); + audioMasterCoerced = newCFMFromMachO ((void*) &audioMaster); effect = module->moduleMain ((audioMasterCallback) audioMasterCoerced); } @@ -803,7 +787,7 @@ public: char buffer [512] = { 0 }; dispatch (effGetEffectName, 0, 0, buffer, 0); - desc.descriptiveName = String (buffer).trim(); + desc.descriptiveName = String::fromUTF8 (buffer).trim(); if (desc.descriptiveName.isEmpty()) desc.descriptiveName = name; @@ -818,7 +802,7 @@ public: { char buffer [kVstMaxVendorStrLen + 8] = { 0 }; dispatch (effGetVendorString, 0, 0, buffer, 0); - desc.manufacturerName = buffer; + desc.manufacturerName = String::fromUTF8 (buffer); } desc.version = getVersion(); @@ -1146,8 +1130,7 @@ public: bool isValidChannel (int index, bool isInput) const { - return isInput ? (index < getNumInputChannels()) - : (index < getNumOutputChannels()); + return isPositiveAndBelow (index, isInput ? getNumInputChannels() : getNumOutputChannels()); } //============================================================================== @@ -1214,7 +1197,7 @@ public: char nm[264] = { 0 }; if (dispatch (effGetProgramNameIndexed, jlimit (0, getNumPrograms(), index), -1, nm, 0) != 0) - return String (CharPointer_UTF8 (nm)).trim(); + return String::fromUTF8 (nm).trim(); } } @@ -1285,7 +1268,8 @@ public: handleUpdateNowIfNeeded(); for (int i = ComponentPeer::getNumPeers(); --i >= 0;) - ComponentPeer::getPeer(i)->performAnyPendingRepaintsNow(); + if (ComponentPeer* p = ComponentPeer::getPeer(i)) + p->performAnyPendingRepaintsNow(); } break; @@ -1448,20 +1432,20 @@ public: const fxSet* const set = (const fxSet*) data; - if ((vst_swap (set->chunkMagic) != 'CcnK' && vst_swap (set->chunkMagic) != 'KncC') - || vst_swap (set->version) > fxbVersionNum) + if ((set->chunkMagic != fxbName ("CcnK") && set->chunkMagic != fxbName ("KncC")) + || fxbSwap (set->version) > fxbVersionNum) return false; - if (vst_swap (set->fxMagic) == 'FxBk') + if (set->fxMagic == fxbName ("FxBk")) { // bank of programs - if (vst_swap (set->numPrograms) >= 0) + if (fxbSwap (set->numPrograms) >= 0) { const int oldProg = getCurrentProgram(); - const int numParams = vst_swap (((const fxProgram*) (set->programs))->numParams); + const int numParams = fxbSwap (((const fxProgram*) (set->programs))->numParams); const int progLen = sizeof (fxProgram) + (numParams - 1) * sizeof (float); - for (int i = 0; i < vst_swap (set->numPrograms); ++i) + for (int i = 0; i < fxbSwap (set->numPrograms); ++i) { if (i != oldProg) { @@ -1469,7 +1453,7 @@ public: if (((const char*) prog) - ((const char*) set) >= (ssize_t) dataSize) return false; - if (vst_swap (set->numPrograms) > 0) + if (fxbSwap (set->numPrograms) > 0) setCurrentProgram (i); if (! restoreProgramSettings (prog)) @@ -1477,7 +1461,7 @@ public: } } - if (vst_swap (set->numPrograms) > 0) + if (fxbSwap (set->numPrograms) > 0) setCurrentProgram (oldProg); const fxProgram* const prog = (const fxProgram*) (((const char*) (set->programs)) + oldProg * progLen); @@ -1488,38 +1472,38 @@ public: return false; } } - else if (vst_swap (set->fxMagic) == 'FxCk') + else if (set->fxMagic == fxbName ("FxCk")) { // single program const fxProgram* const prog = (const fxProgram*) data; - if (vst_swap (prog->chunkMagic) != 'CcnK') + if (prog->chunkMagic != fxbName ("CcnK")) return false; changeProgramName (getCurrentProgram(), prog->prgName); - for (int i = 0; i < vst_swap (prog->numParams); ++i) - setParameter (i, vst_swapFloat (prog->params[i])); + for (int i = 0; i < fxbSwap (prog->numParams); ++i) + setParameter (i, fxbSwapFloat (prog->params[i])); } - else if (vst_swap (set->fxMagic) == 'FBCh' || vst_swap (set->fxMagic) == 'hCBF') + else if (set->fxMagic == fxbName ("FBCh") || set->fxMagic == fxbName ("hCBF")) { // non-preset chunk const fxChunkSet* const cset = (const fxChunkSet*) data; - if (vst_swap (cset->chunkSize) + sizeof (fxChunkSet) - 8 > (unsigned int) dataSize) + if (fxbSwap (cset->chunkSize) + sizeof (fxChunkSet) - 8 > (unsigned int) dataSize) return false; - setChunkData (cset->chunk, vst_swap (cset->chunkSize), false); + setChunkData (cset->chunk, fxbSwap (cset->chunkSize), false); } - else if (vst_swap (set->fxMagic) == 'FPCh' || vst_swap (set->fxMagic) == 'hCPF') + else if (set->fxMagic == fxbName ("FPCh") || set->fxMagic == fxbName ("hCPF")) { // preset chunk const fxProgramSet* const cset = (const fxProgramSet*) data; - if (vst_swap (cset->chunkSize) + sizeof (fxProgramSet) - 8 > (unsigned int) dataSize) + if (fxbSwap (cset->chunkSize) + sizeof (fxProgramSet) - 8 > (unsigned int) dataSize) return false; - setChunkData (cset->chunk, vst_swap (cset->chunkSize), true); + setChunkData (cset->chunk, fxbSwap (cset->chunkSize), true); changeProgramName (getCurrentProgram(), cset->name); } @@ -1547,14 +1531,14 @@ public: dest.setSize (totalLen, true); fxChunkSet* const set = (fxChunkSet*) dest.getData(); - set->chunkMagic = vst_swap ('CcnK'); + set->chunkMagic = fxbName ("CcnK"); set->byteSize = 0; - set->fxMagic = vst_swap ('FBCh'); - set->version = vst_swap (fxbVersionNum); - set->fxID = vst_swap (getUID()); - set->fxVersion = vst_swap (getVersionNumber()); - set->numPrograms = vst_swap (numPrograms); - set->chunkSize = vst_swap ((VstInt32) chunk.getSize()); + set->fxMagic = fxbName ("FBCh"); + set->version = fxbSwap (fxbVersionNum); + set->fxID = fxbSwap (getUID()); + set->fxVersion = fxbSwap (getVersionNumber()); + set->numPrograms = fxbSwap (numPrograms); + set->chunkSize = fxbSwap ((VstInt32) chunk.getSize()); chunk.copyTo (set->chunk, 0, chunk.getSize()); } @@ -1564,14 +1548,14 @@ public: dest.setSize (totalLen, true); fxProgramSet* const set = (fxProgramSet*) dest.getData(); - set->chunkMagic = vst_swap ('CcnK'); + set->chunkMagic = fxbName ("CcnK"); set->byteSize = 0; - set->fxMagic = vst_swap ('FPCh'); - set->version = vst_swap (fxbVersionNum); - set->fxID = vst_swap (getUID()); - set->fxVersion = vst_swap (getVersionNumber()); - set->numPrograms = vst_swap (numPrograms); - set->chunkSize = vst_swap ((VstInt32) chunk.getSize()); + set->fxMagic = fxbName ("FPCh"); + set->version = fxbSwap (fxbVersionNum); + set->fxID = fxbSwap (getUID()); + set->fxVersion = fxbSwap (getVersionNumber()); + set->numPrograms = fxbSwap (numPrograms); + set->chunkSize = fxbSwap ((VstInt32) chunk.getSize()); getCurrentProgramName().copyToUTF8 (set->name, sizeof (set->name) - 1); chunk.copyTo (set->chunk, 0, chunk.getSize()); @@ -1586,13 +1570,13 @@ public: dest.setSize (len, true); fxSet* const set = (fxSet*) dest.getData(); - set->chunkMagic = vst_swap ('CcnK'); + set->chunkMagic = fxbName ("CcnK"); set->byteSize = 0; - set->fxMagic = vst_swap ('FxBk'); - set->version = vst_swap (fxbVersionNum); - set->fxID = vst_swap (getUID()); - set->fxVersion = vst_swap (getVersionNumber()); - set->numPrograms = vst_swap (numPrograms); + set->fxMagic = fxbName ("FxBk"); + set->version = fxbSwap (fxbVersionNum); + set->fxID = fxbSwap (getUID()); + set->fxVersion = fxbSwap (getVersionNumber()); + set->numPrograms = fxbSwap (numPrograms); const int oldProgram = getCurrentProgram(); MemoryBlock oldSettings; @@ -1687,12 +1671,12 @@ private: bool restoreProgramSettings (const fxProgram* const prog) { - if (vst_swap (prog->chunkMagic) == 'CcnK' && vst_swap (prog->fxMagic) == 'FxCk') + if (prog->chunkMagic == fxbName ("CcnK") && prog->fxMagic == fxbName ("FxCk")) { changeProgramName (getCurrentProgram(), prog->prgName); - for (int i = 0; i < vst_swap (prog->numParams); ++i) - setParameter (i, vst_swapFloat (prog->params[i])); + for (int i = 0; i < fxbSwap (prog->numParams); ++i) + setParameter (i, fxbSwapFloat (prog->params[i])); return true; } @@ -1741,18 +1725,18 @@ private: { const int numParams = getNumParameters(); - prog->chunkMagic = vst_swap ('CcnK'); + prog->chunkMagic = fxbName ("CcnK"); prog->byteSize = 0; - prog->fxMagic = vst_swap ('FxCk'); - prog->version = vst_swap (fxbVersionNum); - prog->fxID = vst_swap (getUID()); - prog->fxVersion = vst_swap (getVersionNumber()); - prog->numParams = vst_swap (numParams); + prog->fxMagic = fxbName ("FxCk"); + prog->version = fxbSwap (fxbVersionNum); + prog->fxID = fxbSwap (getUID()); + prog->fxVersion = fxbSwap (getVersionNumber()); + prog->numParams = fxbSwap (numParams); getCurrentProgramName().copyToUTF8 (prog->prgName, sizeof (prog->prgName) - 1); for (int i = 0; i < numParams; ++i) - prog->params[i] = vst_swapFloat (getParameter (i)); + prog->params[i] = fxbSwapFloat (getParameter (i)); } void updateStoredProgramNames() @@ -1894,7 +1878,8 @@ private: }; //============================================================================== -static Array activeVSTWindows; +class VSTPluginWindow; +static Array activeVSTWindows; //============================================================================== class VSTPluginWindow : public AudioProcessorEditor, @@ -2232,10 +2217,11 @@ private: #pragma warning (push) #pragma warning (disable: 4244) - originalWndProc = (void*) GetWindowLongPtr (pluginHWND, GWLP_WNDPROC); - if (! pluginWantsKeys) + { + originalWndProc = (void*) GetWindowLongPtr (pluginHWND, GWLP_WNDPROC); SetWindowLongPtr (pluginHWND, GWLP_WNDPROC, (LONG_PTR) vstHookWndProc); + } #pragma warning (pop) @@ -2317,26 +2303,24 @@ private: { if (isOpen) { - #if ! (JUCE_MAC && JUCE_SUPPORT_CARBON) JUCE_VST_LOG ("Closing VST UI: " + plugin.getName()); isOpen = false; - dispatch (effEditClose, 0, 0, 0, 0); stopTimer(); #if JUCE_WINDOWS #pragma warning (push) #pragma warning (disable: 4244) - if (pluginHWND != 0 && IsWindow (pluginHWND)) + if (originalWndProc != 0 && pluginHWND != 0 && IsWindow (pluginHWND)) SetWindowLongPtr (pluginHWND, GWLP_WNDPROC, (LONG_PTR) originalWndProc); #pragma warning (pop) + originalWndProc = 0; pluginHWND = 0; #elif JUCE_LINUX pluginWindow = 0; pluginProc = 0; #endif - #endif } } @@ -2845,7 +2829,7 @@ FileSearchPath VSTPluginFormat::getDefaultLocationsToSearch() const XmlElement* VSTPluginFormat::getVSTXML (AudioPluginInstance* plugin) { - if (VSTPluginInstance* const vst = dynamic_cast (plugin)) + if (VSTPluginInstance* const vst = dynamic_cast (plugin)) if (vst->module != nullptr) return vst->module->vstXml.get(); @@ -2854,7 +2838,7 @@ const XmlElement* VSTPluginFormat::getVSTXML (AudioPluginInstance* plugin) bool VSTPluginFormat::loadFromFXBFile (AudioPluginInstance* plugin, const void* data, size_t dataSize) { - if (VSTPluginInstance* vst = dynamic_cast (plugin)) + if (VSTPluginInstance* vst = dynamic_cast (plugin)) return vst->loadFromFXBFile (data, dataSize); return false; @@ -2862,7 +2846,7 @@ bool VSTPluginFormat::loadFromFXBFile (AudioPluginInstance* plugin, const void* bool VSTPluginFormat::saveToFXBFile (AudioPluginInstance* plugin, MemoryBlock& dest, bool asFXB) { - if (VSTPluginInstance* vst = dynamic_cast (plugin)) + if (VSTPluginInstance* vst = dynamic_cast (plugin)) return vst->saveToFXBFile (dest, asFXB); return false; @@ -2870,7 +2854,7 @@ bool VSTPluginFormat::saveToFXBFile (AudioPluginInstance* plugin, MemoryBlock& d bool VSTPluginFormat::getChunkData (AudioPluginInstance* plugin, MemoryBlock& result, bool isPreset) { - if (VSTPluginInstance* vst = dynamic_cast (plugin)) + if (VSTPluginInstance* vst = dynamic_cast (plugin)) return vst->getChunkData (result, isPreset, 128); return false; @@ -2878,7 +2862,7 @@ bool VSTPluginFormat::getChunkData (AudioPluginInstance* plugin, MemoryBlock& re bool VSTPluginFormat::setChunkData (AudioPluginInstance* plugin, const void* data, int size, bool isPreset) { - if (VSTPluginInstance* vst = dynamic_cast (plugin)) + if (VSTPluginInstance* vst = dynamic_cast (plugin)) return vst->setChunkData (data, size, isPreset); return false; @@ -2888,13 +2872,13 @@ void VSTPluginFormat::setExtraFunctions (AudioPluginInstance* plugin, ExtraFunct { ScopedPointer f (functions); - if (VSTPluginInstance* vst = dynamic_cast (plugin)) + if (VSTPluginInstance* vst = dynamic_cast (plugin)) vst->extraFunctions = f; } VSTPluginFormat::VstIntPtr JUCE_CALLTYPE VSTPluginFormat::dispatcher (AudioPluginInstance* plugin, int32 opcode, int32 index, VstIntPtr value, void* ptr, float opt) { - if (VSTPluginInstance* vst = dynamic_cast (plugin)) + if (VSTPluginInstance* vst = dynamic_cast (plugin)) return vst->dispatch (opcode, index, value, ptr, opt); return 0; diff --git a/JuceLibraryCode/modules/juce_audio_processors/juce_audio_processors.cpp b/JuceLibraryCode/modules/juce_audio_processors/juce_audio_processors.cpp index 78d3387..d1f1679 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/juce_audio_processors.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/juce_audio_processors.cpp @@ -41,8 +41,9 @@ //============================================================================== #if JUCE_MAC - #if (JUCE_PLUGINHOST_VST || JUCE_PLUGINHOST_AU) \ - || ! (defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6) + #if JUCE_SUPPORT_CARBON \ + && ((JUCE_PLUGINHOST_VST || JUCE_PLUGINHOST_AU) \ + || ! (defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6)) #define Point CarbonDummyPointName // (workaround to avoid definition of "Point" by old Carbon headers) #define Component CarbonDummyCompName #include @@ -112,27 +113,24 @@ struct AutoResizingNSViewComponentWithParent : public AutoResizingNSViewCompone setView (v); [v release]; - startTimer (100); + startTimer (30); + } + + NSView* getChildView() const + { + if (NSView* parent = (NSView*) getView()) + if ([[parent subviews] count] > 0) + return [[parent subviews] objectAtIndex: 0]; + + return nil; } void timerCallback() override { - if (NSView* parent = (NSView*) getView()) + if (NSView* child = getChildView()) { - 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]; - } - } - } + stopTimer(); + setView (child); } } }; diff --git a/JuceLibraryCode/modules/juce_audio_processors/juce_audio_processors.h b/JuceLibraryCode/modules/juce_audio_processors/juce_audio_processors.h index 3854d2a..2811656 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/juce_audio_processors.h +++ b/JuceLibraryCode/modules/juce_audio_processors/juce_audio_processors.h @@ -76,6 +76,7 @@ class AudioProcessor; #include "processors/juce_AudioPlayHead.h" #include "processors/juce_AudioProcessorEditor.h" #include "processors/juce_AudioProcessorListener.h" +#include "processors/juce_AudioProcessorParameter.h" #include "processors/juce_AudioProcessor.h" #include "processors/juce_PluginDescription.h" #include "processors/juce_AudioPluginInstance.h" diff --git a/JuceLibraryCode/modules/juce_audio_processors/juce_module_info b/JuceLibraryCode/modules/juce_audio_processors/juce_module_info index 9645846..40a0d87 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.5", + "version": "3.0.8", "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.cpp b/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp index 501fedf..e46dba3 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp @@ -118,19 +118,6 @@ void AudioProcessor::setParameterNotifyingHost (const int parameterIndex, sendParamChangeMessageToListeners (parameterIndex, newValue); } -String AudioProcessor::getParameterName (int parameterIndex, int maximumStringLength) -{ - return getParameterName (parameterIndex).substring (0, maximumStringLength); -} - -String AudioProcessor::getParameterText (int parameterIndex, int maximumStringLength) -{ - return getParameterText (parameterIndex).substring (0, maximumStringLength); -} - -int AudioProcessor::getParameterNumSteps (int /*parameterIndex*/) { return 0x7fffffff; } -float AudioProcessor::getParameterDefaultValue (int /*parameterIndex*/) { return 0.0f; } - AudioProcessorListener* AudioProcessor::getListenerLocked (const int index) const noexcept { const ScopedLock sl (listenerLock); @@ -201,9 +188,129 @@ void AudioProcessor::updateHostDisplay() l->audioProcessorChanged (this); } -String AudioProcessor::getParameterLabel (int) const { return String(); } -bool AudioProcessor::isParameterAutomatable (int) const { return true; } -bool AudioProcessor::isMetaParameter (int) const { return false; } +const OwnedArray& AudioProcessor::getParameters() const noexcept +{ + return managedParameters; +} + +int AudioProcessor::getNumParameters() +{ + return managedParameters.size(); +} + +float AudioProcessor::getParameter (int index) +{ + if (AudioProcessorParameter* p = getParamChecked (index)) + return p->getValue(); + + return 0; +} + +void AudioProcessor::setParameter (int index, float newValue) +{ + if (AudioProcessorParameter* p = getParamChecked (index)) + p->setValue (newValue); +} + +float AudioProcessor::getParameterDefaultValue (int index) +{ + if (AudioProcessorParameter* p = managedParameters[index]) + return p->getDefaultValue(); + + return 0; +} + +const String AudioProcessor::getParameterName (int index) +{ + if (AudioProcessorParameter* p = getParamChecked (index)) + return p->getName (512); + + return String(); +} + +String AudioProcessor::getParameterName (int index, int maximumStringLength) +{ + if (AudioProcessorParameter* p = managedParameters[index]) + return p->getName (maximumStringLength); + + return getParameterName (index).substring (0, maximumStringLength); +} + +const String AudioProcessor::getParameterText (int index) +{ + return getParameterText (index, 1024); +} + +String AudioProcessor::getParameterText (int index, int maximumStringLength) +{ + if (AudioProcessorParameter* p = managedParameters[index]) + return p->getText (p->getValue(), maximumStringLength); + + return getParameterText (index).substring (0, maximumStringLength); +} + +int AudioProcessor::getParameterNumSteps (int index) +{ + if (AudioProcessorParameter* p = managedParameters[index]) + return p->getNumSteps(); + + return AudioProcessor::getDefaultNumParameterSteps(); +} + +int AudioProcessor::getDefaultNumParameterSteps() noexcept +{ + return 0x7fffffff; +} + +String AudioProcessor::getParameterLabel (int index) const +{ + if (AudioProcessorParameter* p = managedParameters[index]) + return p->getLabel(); + + return String(); +} + +bool AudioProcessor::isParameterAutomatable (int index) const +{ + if (AudioProcessorParameter* p = managedParameters[index]) + return p->isAutomatable(); + + return true; +} + +bool AudioProcessor::isParameterOrientationInverted (int index) const +{ + if (AudioProcessorParameter* p = managedParameters[index]) + return p->isOrientationInverted(); + + return false; +} + +bool AudioProcessor::isMetaParameter (int index) const +{ + if (AudioProcessorParameter* p = managedParameters[index]) + return p->isMetaParameter(); + + return false; +} + +AudioProcessorParameter* AudioProcessor::getParamChecked (int index) const noexcept +{ + AudioProcessorParameter* p = managedParameters[index]; + + // If you hit this, then you're either trying to access parameters that are out-of-range, + // or you're not using addParameter and the managed parameter list, but have failed + // to override some essential virtual methods and implement them appropriately. + jassert (p != nullptr); + return p; +} + +void AudioProcessor::addParameter (AudioProcessorParameter* p) +{ + p->processor = this; + p->parameterIndex = managedParameters.size(); + managedParameters.add (p); +} void AudioProcessor::suspendProcessing (const bool shouldBeSuspended) { @@ -230,9 +337,6 @@ AudioProcessorEditor* AudioProcessor::createEditorIfNeeded() AudioProcessorEditor* const ed = createEditor(); - // You must make your hasEditor() method return a consistent result! - jassert (hasEditor() == (ed != nullptr)); - if (ed != nullptr) { // you must give your editor comp a size before returning it.. @@ -242,6 +346,9 @@ AudioProcessorEditor* AudioProcessor::createEditorIfNeeded() activeEditor = ed; } + // You must make your hasEditor() method return a consistent result! + jassert (hasEditor() == (ed != nullptr)); + return ed; } @@ -294,6 +401,47 @@ XmlElement* AudioProcessor::getXmlFromBinary (const void* data, const int sizeIn void AudioProcessorListener::audioProcessorParameterChangeGestureBegin (AudioProcessor*, int) {} void AudioProcessorListener::audioProcessorParameterChangeGestureEnd (AudioProcessor*, int) {} +//============================================================================== +AudioProcessorParameter::AudioProcessorParameter() noexcept + : processor (nullptr), parameterIndex (-1) +{} + +AudioProcessorParameter::~AudioProcessorParameter() {} + +void AudioProcessorParameter::setValueNotifyingHost (float newValue) +{ + // This method can't be used until the parameter has been attached to a processor! + jassert (processor != nullptr && parameterIndex >= 0); + + return processor->setParameterNotifyingHost (parameterIndex, newValue); +} + +void AudioProcessorParameter::beginChangeGesture() +{ + // This method can't be used until the parameter has been attached to a processor! + jassert (processor != nullptr && parameterIndex >= 0); + + processor->beginParameterChangeGesture (parameterIndex); +} + +void AudioProcessorParameter::endChangeGesture() +{ + // This method can't be used until the parameter has been attached to a processor! + jassert (processor != nullptr && parameterIndex >= 0); + + processor->endParameterChangeGesture (parameterIndex); +} + +bool AudioProcessorParameter::isOrientationInverted() const { return false; } +bool AudioProcessorParameter::isAutomatable() const { return true; } +bool AudioProcessorParameter::isMetaParameter() const { return false; } +int AudioProcessorParameter::getNumSteps() const { return AudioProcessor::getDefaultNumParameterSteps(); } + +String AudioProcessorParameter::getText (float value, int /*maximumStringLength*/) const +{ + return String (value, 2); +} + //============================================================================== bool AudioPlayHead::CurrentPositionInfo::operator== (const CurrentPositionInfo& other) const noexcept { diff --git a/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessor.h b/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessor.h index e54b84a..aaae9ef 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessor.h +++ b/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessor.h @@ -44,11 +44,7 @@ class JUCE_API AudioProcessor { protected: //============================================================================== - /** Constructor. - - You can also do your initialisation tasks in the initialiseFilterInfo() - call, which will be made after this object has been created. - */ + /** Constructor. */ AudioProcessor(); public: @@ -293,9 +289,9 @@ public: filter will return an empty buffer, but won't block the audio thread like it would do if you use the getCallbackLock() critical section to synchronise access. - If you're going to use this, your processBlock() method must call isSuspended() and - check whether it's suspended or not. If it is, then it should skip doing any real - processing, either emitting silence or passing the input through unchanged. + Any code that calls processBlock() should call isSuspended() before doing so, and + if the processor is suspended, it should avoid the call and emit silence or + whatever is appropriate. @see getCallbackLock */ @@ -329,7 +325,7 @@ public: /** Called by the host to tell this processor whether it's being used in a non-realtime capacity for offline rendering or bouncing. */ - void setNonRealtime (bool isNonRealtime) noexcept; + virtual void setNonRealtime (bool isNonRealtime) noexcept; //============================================================================== /** Creates the filter's UI. @@ -381,10 +377,10 @@ public: /** This must return the correct value immediately after the object has been created, and mustn't change the number of parameters later. */ - virtual int getNumParameters() = 0; + virtual int getNumParameters(); /** Returns the name of a particular parameter. */ - virtual const String getParameterName (int parameterIndex) = 0; + virtual const String getParameterName (int parameterIndex); /** Called by the host to find out the value of one of the filter's parameters. @@ -394,10 +390,10 @@ public: It's also likely to be called by non-UI threads, so the code in here should be thread-aware. */ - virtual float getParameter (int parameterIndex) = 0; + virtual float getParameter (int parameterIndex); /** Returns the value of a parameter as a text string. */ - virtual const String getParameterText (int parameterIndex) = 0; + virtual const String getParameterText (int parameterIndex); /** Returns the name of a parameter as a text string with a preferred maximum length. If you want to provide customised short versions of your parameter names that @@ -418,12 +414,18 @@ public: virtual String getParameterText (int parameterIndex, int maximumStringLength); /** Returns the number of discrete steps that this parameter can represent. - The default return value if you don't implement this method is 0x7fffffff. + The default return value if you don't implement this method is + AudioProcessor::getDefaultNumParameterSteps(). If your parameter is boolean, then you may want to make this return 2. The value that is returned may or may not be used, depending on the host. */ virtual int getParameterNumSteps (int parameterIndex); + /** Returns the default number of steps for a parameter. + @see getParameterNumSteps + */ + static int getDefaultNumParameterSteps() noexcept; + /** Returns the default value for the parameter. By default, this just returns 0. The value that is returned may or may not be used, depending on the host. @@ -435,6 +437,11 @@ public: */ virtual String getParameterLabel (int index) const; + /** This can be overridden to tell the host that particular parameters operate in the + reverse direction. (Not all plugin formats or hosts will actually use this information). + */ + virtual bool isParameterOrientationInverted (int index) const; + /** The host will call this method to change the value of one of the filter's parameters. The host may call this at any time, including during the audio processing @@ -448,7 +455,7 @@ public: The value passed will be between 0 and 1.0. */ - virtual void setParameter (int parameterIndex, float newValue) = 0; + virtual void setParameter (int parameterIndex, float newValue); /** Your filter can call this when it needs to change one of its parameters. @@ -463,16 +470,13 @@ public: void setParameterNotifyingHost (int parameterIndex, float newValue); /** Returns true if the host can automate this parameter. - By default, this returns true for all parameters. */ virtual bool isParameterAutomatable (int parameterIndex) const; /** Should return true if this parameter is a "meta" parameter. - A meta-parameter is a parameter that changes other params. It is used by some hosts (e.g. AudioUnit hosts). - By default this returns false. */ virtual bool isMetaParameter (int parameterIndex) const; @@ -503,6 +507,16 @@ public: */ void updateHostDisplay(); + //============================================================================== + /** Adds a parameter to the list. + The parameter object will be managed and deleted automatically by the list + when no longer needed. + */ + void addParameter (AudioProcessorParameter*); + + /** Returns the current list of parameters. */ + const OwnedArray& getParameters() const noexcept; + //============================================================================== /** Returns the number of preset programs the filter supports. @@ -659,6 +673,9 @@ private: CriticalSection callbackLock, listenerLock; String inputSpeakerArrangement, outputSpeakerArrangement; + OwnedArray managedParameters; + AudioProcessorParameter* getParamChecked (int) const noexcept; + #if JUCE_DEBUG BigInteger changingParams; #endif diff --git a/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp b/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp index a4c9d29..a625411 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp @@ -22,16 +22,22 @@ ============================================================================== */ -AudioProcessorEditor::AudioProcessorEditor (AudioProcessor* const p) - : owner (p) +AudioProcessorEditor::AudioProcessorEditor (AudioProcessor& p) noexcept : processor (p) +{ +} + +AudioProcessorEditor::AudioProcessorEditor (AudioProcessor* p) noexcept : processor (*p) { // the filter must be valid.. - jassert (owner != nullptr); + jassert (p != nullptr); } AudioProcessorEditor::~AudioProcessorEditor() { // if this fails, then the wrapper hasn't called editorBeingDeleted() on the // filter for some reason.. - jassert (owner->getActiveEditor() != this); + jassert (processor.getActiveEditor() != this); } + +void AudioProcessorEditor::setControlHighlight (ParameterControlHighlightInfo) {} +int AudioProcessorEditor::getControlParameterIndex (Component&) { return -1; } diff --git a/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h b/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h index 3c811a2..1755497 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h +++ b/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h @@ -39,9 +39,11 @@ class JUCE_API AudioProcessorEditor : public Component { protected: //============================================================================== - /** Creates an editor for the specified processor. - */ - AudioProcessorEditor (AudioProcessor* owner); + /** Creates an editor for the specified processor. */ + AudioProcessorEditor (AudioProcessor&) noexcept; + + /** Creates an editor for the specified processor. */ + AudioProcessorEditor (AudioProcessor*) noexcept; public: /** Destructor. */ @@ -49,14 +51,40 @@ public: //============================================================================== - /** Returns a pointer to the processor that this editor represents. */ - AudioProcessor* getAudioProcessor() const noexcept { return owner; } + /** The AudioProcessor that this editor represents. */ + AudioProcessor& processor; + /** Returns a pointer to the processor that this editor represents. + This method is here to support legacy code, but it's easier to just use the + AudioProcessorEditor::processor member variable directly to get this object. + */ + AudioProcessor* getAudioProcessor() const noexcept { return &processor; } + + //============================================================================== + /** Used by the setParameterHighlighting() method. */ + struct ParameterControlHighlightInfo + { + int parameterIndex; + bool isHighlighted; + Colour suggestedColour; + }; + + /** Some types of plugin can call this to suggest that the control for a particular + parameter should be highlighted. + Currently only AAX plugins will call this, and implementing it is optional. + */ + virtual void setControlHighlight (ParameterControlHighlightInfo); + + /** Called by certain plug-in wrappers to find out whether a component is used + to control a parameter. + + If the given component represents a particular plugin parameter, then this + method should return the index of that parameter. If not, it should return -1. + Currently only AAX plugins will call this, and implementing it is optional. + */ + virtual int getControlParameterIndex (Component&); private: - //============================================================================== - AudioProcessor* const owner; - JUCE_DECLARE_NON_COPYABLE (AudioProcessorEditor) }; diff --git a/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h b/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h index 7deb9b5..d944682 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h +++ b/JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h @@ -388,11 +388,11 @@ public: private: //============================================================================== - ReferenceCountedArray nodes; - OwnedArray connections; + ReferenceCountedArray nodes; + OwnedArray connections; uint32 lastNodeId; AudioSampleBuffer renderingBuffers; - OwnedArray midiBuffers; + OwnedArray midiBuffers; Array renderingOps; friend class AudioGraphIOProcessor; diff --git a/JuceLibraryCode/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp b/JuceLibraryCode/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp index 4b9da9b..c94411d 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp @@ -27,12 +27,12 @@ class ProcessorParameterPropertyComp : public PropertyComponent, private Timer { public: - ProcessorParameterPropertyComp (const String& name, AudioProcessor& p, const int index_) + ProcessorParameterPropertyComp (const String& name, AudioProcessor& p, int paramIndex) : PropertyComponent (name), owner (p), - index (index_), + index (paramIndex), paramHasChanged (false), - slider (p, index_) + slider (p, paramIndex) { startTimer (100); addAndMakeVisible (slider); @@ -44,15 +44,19 @@ public: owner.removeListener (this); } - void refresh() + void refresh() override { paramHasChanged = false; - slider.setValue (owner.getParameter (index), dontSendNotification); + + if (slider.getThumbBeingDragged() < 0) + slider.setValue (owner.getParameter (index), dontSendNotification); + + slider.updateText(); } - void audioProcessorChanged (AudioProcessor*) {} + void audioProcessorChanged (AudioProcessor*) override {} - void audioProcessorParameterChanged (AudioProcessor*, int parameterIndex, float) + void audioProcessorParameterChanged (AudioProcessor*, int parameterIndex, float) override { if (parameterIndex == index) paramHasChanged = true; @@ -76,27 +80,34 @@ private: class ParamSlider : public Slider { public: - ParamSlider (AudioProcessor& p, const int index_) - : owner (p), - index (index_) + ParamSlider (AudioProcessor& p, int paramIndex) : owner (p), index (paramIndex) { - setRange (0.0, 1.0, 0.0); + const int steps = owner.getParameterNumSteps (index); + + if (steps > 1 && steps < 0x7fffffff) + setRange (0.0, 1.0, 1.0 / (steps - 1.0)); + else + setRange (0.0, 1.0); + setSliderStyle (Slider::LinearBar); setTextBoxIsEditable (false); - setScrollWheelEnabled (false); + setScrollWheelEnabled (true); } - void valueChanged() + void valueChanged() override { const float newVal = (float) getValue(); if (owner.getParameter (index) != newVal) + { owner.setParameterNotifyingHost (index, newVal); + updateText(); + } } - String getTextFromValue (double /*value*/) + String getTextFromValue (double /*value*/) override { - return owner.getParameterText (index); + return owner.getParameterText (index) + " " + owner.getParameterLabel (index).trimEnd(); } private: diff --git a/JuceLibraryCode/modules/juce_audio_processors/processors/juce_PluginDescription.cpp b/JuceLibraryCode/modules/juce_audio_processors/processors/juce_PluginDescription.cpp index 8e1010f..5eafc07 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/processors/juce_PluginDescription.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/processors/juce_PluginDescription.cpp @@ -71,18 +71,26 @@ PluginDescription& PluginDescription::operator= (const PluginDescription& other) return *this; } -bool PluginDescription::isDuplicateOf (const PluginDescription& other) const +bool PluginDescription::isDuplicateOf (const PluginDescription& other) const noexcept { return fileOrIdentifier == other.fileOrIdentifier && uid == other.uid; } +static String getPluginDescSuffix (const PluginDescription& d) +{ + return "-" + String::toHexString (d.fileOrIdentifier.hashCode()) + + "-" + String::toHexString (d.uid); +} + +bool PluginDescription::matchesIdentifierString (const String& identifierString) const +{ + return identifierString.endsWithIgnoreCase (getPluginDescSuffix (*this)); +} + String PluginDescription::createIdentifierString() const { - return pluginFormatName - + "-" + name - + "-" + String::toHexString (fileOrIdentifier.hashCode()) - + "-" + String::toHexString (uid); + return pluginFormatName + "-" + name + getPluginDescSuffix (*this); } XmlElement* PluginDescription::createXml() const diff --git a/JuceLibraryCode/modules/juce_audio_processors/processors/juce_PluginDescription.h b/JuceLibraryCode/modules/juce_audio_processors/processors/juce_PluginDescription.h index 6361775..24b17e5 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/processors/juce_PluginDescription.h +++ b/JuceLibraryCode/modules/juce_audio_processors/processors/juce_PluginDescription.h @@ -107,7 +107,15 @@ public: This isn't quite as simple as them just having the same file (because of shell plug-ins). */ - bool isDuplicateOf (const PluginDescription& other) const; + bool isDuplicateOf (const PluginDescription& other) const noexcept; + + /** Return true if this description is equivalent to another one which created the + given identifier string. + + Note that this isn't quite as simple as them just calling createIdentifierString() + and comparing the strings, because the identifers can differ (thanks to shell plug-ins). + */ + bool matchesIdentifierString (const String& identifierString) const; //============================================================================== /** Returns a string that can be saved and used to uniquely identify the diff --git a/JuceLibraryCode/modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp b/JuceLibraryCode/modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp index afbf23e..081ba11 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp @@ -46,7 +46,7 @@ PluginDescription* KnownPluginList::getTypeForFile (const String& fileOrIdentifi PluginDescription* KnownPluginList::getTypeForIdentifierString (const String& identifierString) const { for (int i = 0; i < types.size(); ++i) - if (types.getUnchecked(i)->createIdentifierString() == identifierString) + if (types.getUnchecked(i)->matchesIdentifierString (identifierString)) return types.getUnchecked(i); return nullptr; @@ -259,15 +259,15 @@ struct PluginSorter switch (method) { - case KnownPluginList::sortByCategory: diff = first->category.compareLexicographically (second->category); break; - case KnownPluginList::sortByManufacturer: diff = first->manufacturerName.compareLexicographically (second->manufacturerName); break; + case KnownPluginList::sortByCategory: diff = first->category.compareNatural (second->category); break; + case KnownPluginList::sortByManufacturer: diff = first->manufacturerName.compareNatural (second->manufacturerName); break; case KnownPluginList::sortByFormat: diff = first->pluginFormatName.compare (second->pluginFormatName); break; case KnownPluginList::sortByFileSystemLocation: diff = lastPathPart (first->fileOrIdentifier).compare (lastPathPart (second->fileOrIdentifier)); break; default: break; } if (diff == 0) - diff = first->name.compareLexicographically (second->name); + diff = first->name.compareNatural (second->name); return diff * direction; } diff --git a/JuceLibraryCode/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp b/JuceLibraryCode/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp index 64801fc..fd437f3 100644 --- a/JuceLibraryCode/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp +++ b/JuceLibraryCode/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp @@ -75,11 +75,10 @@ class AudioDeviceSelectorComponent::MidiInputSelectorComponentListBox : public private ListBoxModel { public: - MidiInputSelectorComponentListBox (AudioDeviceManager& dm, - const String& noItemsMessage_) + MidiInputSelectorComponentListBox (AudioDeviceManager& dm, const String& noItems) : ListBox (String::empty, nullptr), deviceManager (dm), - noItemsMessage (noItemsMessage_) + noItemsMessage (noItems) { items = MidiInput::getDevices(); @@ -87,15 +86,12 @@ public: setOutlineThickness (1); } - int getNumRows() + int getNumRows() override { return items.size(); } - void paintListBoxItem (int row, - Graphics& g, - int width, int height, - bool rowIsSelected) + void paintListBoxItem (int row, Graphics& g, int width, int height, bool rowIsSelected) override { if (isPositiveAndBelow (row, items.size())) { @@ -118,7 +114,7 @@ public: } } - void listBoxItemClicked (int row, const MouseEvent& e) + void listBoxItemClicked (int row, const MouseEvent& e) override { selectRow (row); @@ -126,12 +122,12 @@ public: flipEnablement (row); } - void listBoxItemDoubleClicked (int row, const MouseEvent&) + void listBoxItemDoubleClicked (int row, const MouseEvent&) override { flipEnablement (row); } - void returnKeyPressed (int row) + void returnKeyPressed (int row) override { flipEnablement (row); } @@ -214,7 +210,6 @@ public: type.scanForDevices(); setup.manager->addChangeListener (this); - updateAllControls(); } ~AudioDeviceSettingsPanel() @@ -224,83 +219,107 @@ public: void resized() override { - const int lx = proportionOfWidth (0.35f); - const int w = proportionOfWidth (0.4f); - const int h = 24; - const int space = 6; - const int dh = h + space; - int y = 0; - - if (outputDeviceDropDown != nullptr) + if (AudioDeviceSelectorComponent* parent = findParentComponentOfClass()) { - outputDeviceDropDown->setBounds (lx, y, w, h); + Rectangle r (proportionOfWidth (0.35f), 0, proportionOfWidth (0.6f), 3000); - if (testButton != nullptr) - testButton->setBounds (proportionOfWidth (0.77f), - outputDeviceDropDown->getY(), - proportionOfWidth (0.18f), - h); - y += dh; + const int maxListBoxHeight = 100; + const int h = parent->getItemHeight(); + const int space = h / 4; + + if (outputDeviceDropDown != nullptr) + { + Rectangle row (r.removeFromTop (h)); + + if (testButton != nullptr) + { + testButton->changeWidthToFitText (h); + testButton->setBounds (row.removeFromRight (testButton->getWidth())); + row.removeFromRight (space); + } + + outputDeviceDropDown->setBounds (row); + r.removeFromTop (space); + } + + if (inputDeviceDropDown != nullptr) + { + Rectangle row (r.removeFromTop (h)); + + inputLevelMeter->setBounds (row.removeFromRight (testButton != nullptr ? testButton->getWidth() : row.getWidth() / 6)); + row.removeFromRight (space); + inputDeviceDropDown->setBounds (row); + r.removeFromTop (space); + } + + if (outputChanList != nullptr) + { + outputChanList->setBounds (r.removeFromTop (outputChanList->getBestHeight (maxListBoxHeight))); + outputChanLabel->setBounds (0, outputChanList->getBounds().getCentreY() - h / 2, r.getX(), h); + r.removeFromTop (space); + } + + if (inputChanList != nullptr) + { + inputChanList->setBounds (r.removeFromTop (inputChanList->getBestHeight (maxListBoxHeight))); + inputChanLabel->setBounds (0, inputChanList->getBounds().getCentreY() - h / 2, r.getX(), h); + r.removeFromTop (space); + } + + r.removeFromTop (space * 2); + + if (showAdvancedSettingsButton != nullptr) + { + showAdvancedSettingsButton->setBounds (r.withHeight (h)); + showAdvancedSettingsButton->changeWidthToFitText(); + } + + const bool advancedSettingsVisible = showAdvancedSettingsButton == nullptr + || ! showAdvancedSettingsButton->isVisible(); + + if (sampleRateDropDown != nullptr) + { + sampleRateDropDown->setVisible (advancedSettingsVisible); + sampleRateDropDown->setBounds (r.removeFromTop (h)); + r.removeFromTop (space); + } + + if (bufferSizeDropDown != nullptr) + { + bufferSizeDropDown->setVisible (advancedSettingsVisible); + bufferSizeDropDown->setBounds (r.removeFromTop (h)); + r.removeFromTop (space); + } + + r.removeFromTop (space); + + if (showUIButton != nullptr || resetDeviceButton != nullptr) + { + Rectangle buttons (r.removeFromTop (h)); + + if (showUIButton != nullptr) + { + showUIButton->setVisible (advancedSettingsVisible); + showUIButton->changeWidthToFitText (h); + showUIButton->setBounds (buttons.removeFromLeft (showUIButton->getWidth())); + buttons.removeFromLeft (space); + } + + if (resetDeviceButton != nullptr) + { + resetDeviceButton->setVisible (advancedSettingsVisible); + resetDeviceButton->changeWidthToFitText (h); + resetDeviceButton->setBounds (buttons.removeFromLeft (resetDeviceButton->getWidth())); + } + + r.removeFromTop (space); + } + + setSize (getWidth(), r.getY()); } - - if (inputDeviceDropDown != nullptr) + else { - inputDeviceDropDown->setBounds (lx, y, w, h); - - inputLevelMeter->setBounds (proportionOfWidth (0.77f), - inputDeviceDropDown->getY(), - proportionOfWidth (0.18f), - h); - y += dh; - } - - const int maxBoxHeight = 100; - - if (outputChanList != nullptr) - { - const int bh = outputChanList->getBestHeight (maxBoxHeight); - outputChanList->setBounds (lx, y, proportionOfWidth (0.55f), bh); - y += bh + space; - } - - if (inputChanList != nullptr) - { - const int bh = inputChanList->getBestHeight (maxBoxHeight); - inputChanList->setBounds (lx, y, proportionOfWidth (0.55f), bh); - y += bh + space; - } - - y += space * 2; - - if (showAdvancedSettingsButton != nullptr) - { - showAdvancedSettingsButton->changeWidthToFitText (h); - showAdvancedSettingsButton->setTopLeftPosition (lx, y); - } - - if (sampleRateDropDown != nullptr) - { - sampleRateDropDown->setVisible (showAdvancedSettingsButton == nullptr - || ! showAdvancedSettingsButton->isVisible()); - - sampleRateDropDown->setBounds (lx, y, w, h); - y += dh; - } - - if (bufferSizeDropDown != nullptr) - { - bufferSizeDropDown->setVisible (showAdvancedSettingsButton == nullptr - || ! showAdvancedSettingsButton->isVisible()); - bufferSizeDropDown->setBounds (lx, y, w, h); - y += dh; - } - - if (showUIButton != nullptr) - { - showUIButton->setVisible (showAdvancedSettingsButton == nullptr - || ! showAdvancedSettingsButton->isVisible()); - showUIButton->changeWidthToFitText (h); - showUIButton->setTopLeftPosition (lx, y); + jassertfalse; } } @@ -398,6 +417,10 @@ public: { setup.manager->playTestSound(); } + else if (button == resetDeviceButton) + { + resetDevice(); + } } void updateAllControls() @@ -406,6 +429,7 @@ public: updateInputsComboBox(); updateControlPanelButton(); + updateResetButton(); if (AudioIODevice* const currentDevice = setup.manager->getCurrentAudioDevice()) { @@ -418,6 +442,7 @@ public: = new ChannelSelectorListBox (setup, ChannelSelectorListBox::audioOutputType, TRANS ("(no audio output channels found)"))); outputChanLabel = new Label (String::empty, TRANS("Active output channels:")); + outputChanLabel->setJustificationType (Justification::centredRight); outputChanLabel->attachToComponent (outputChanList, true); } @@ -438,6 +463,7 @@ public: = new ChannelSelectorListBox (setup, ChannelSelectorListBox::audioInputType, TRANS("(no audio input channels found)"))); inputChanLabel = new Label (String::empty, TRANS("Active input channels:")); + inputChanLabel->setJustificationType (Justification::centredRight); inputChanLabel->attachToComponent (inputChanList, true); } @@ -468,6 +494,7 @@ public: inputDeviceDropDown->setSelectedId (-1, dontSendNotification); } + sendLookAndFeelChange(); resized(); setSize (getWidth(), getLowestY() + 4); } @@ -477,6 +504,12 @@ public: updateAllControls(); } + void resetDevice() + { + setup.manager->closeAudioDevice(); + setup.manager->restartLastAudioDevice(); + } + private: AudioIODeviceType& type; const AudioDeviceSetupDetails setup; @@ -485,7 +518,7 @@ private: ScopedPointer