diff --git a/.gitignore b/.gitignore index 84ce603e..9a661870 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,9 @@ +# In case you dont't want add unnecessary files +#**/JuceLibraryCOde +#**/Builds + +**/.DS_Store + *.swp build diff --git a/Builds/MacOSX/Info-AU.plist b/Builds/MacOSX/Info-AU.plist index 56a7b151..ff1934f8 100644 --- a/Builds/MacOSX/Info-AU.plist +++ b/Builds/MacOSX/Info-AU.plist @@ -42,6 +42,13 @@ Tmpr version 65539 + resourceUsage + + network.client + + temporary-exception.files.all.read-write + + diff --git a/Builds/MacOSX/Temper.xcodeproj/project.pbxproj b/Builds/MacOSX/Temper.xcodeproj/project.pbxproj index fbfb4486..48cc80dc 100644 --- a/Builds/MacOSX/Temper.xcodeproj/project.pbxproj +++ b/Builds/MacOSX/Temper.xcodeproj/project.pbxproj @@ -6,278 +6,865 @@ objectVersion = 46; objects = { - 3B9D697D29F5DFF7BFC1B20A = {isa = PBXBuildFile; fileRef = 329DB2BBEB45BD6A9C25C06E; }; - 783DDBA43AF33A5DA10275DE = {isa = PBXBuildFile; fileRef = DE34C9EED8B65542DF1F7EA5; }; - 154876FE753F96C6DBB1035D = {isa = PBXBuildFile; fileRef = D382B2EFF926D55A5494CF1D; }; - E8AD28E0C82240E8E5BFD0B7 = {isa = PBXBuildFile; fileRef = CE24234A805A548104752B18; }; - 1B7D68D6BB5C540D38FF9122 = {isa = PBXBuildFile; fileRef = 51985E139AA96A0DF9BDD53F; }; - 79FECC7AD35E7CD7C30569E3 = {isa = PBXBuildFile; fileRef = 984DC7C1FFB0CC7F4AE7C47F; }; - 61AD7A33F376FB4318E4F7AF = {isa = PBXBuildFile; fileRef = C65386B81096933FA9436F33; }; - BF91BC76FFFCCFD8A5A3DB90 = {isa = PBXBuildFile; fileRef = 6D2D628981FCF64C310B884E; }; - B19EF2739AFA3DDA44EA7526 = {isa = PBXBuildFile; fileRef = C33B7FFCC2442377C56E393D; }; - C3B45D6C33FC8D2DFFAFD911 = {isa = PBXBuildFile; fileRef = 0A8426AE91646F9776A6C30E; }; - 08B71F44034B3235DC256506 = {isa = PBXBuildFile; fileRef = 43C47DA992C4DBF75FF9D24B; }; - 26DDC2E8A87CED2C233559FF = {isa = PBXBuildFile; fileRef = 0479B2108EC3D3086C664EF5; }; - 5B7726FEB45B778ABED69629 = {isa = PBXBuildFile; fileRef = 0DB16E6AED0AC5A84706C552; }; - 02843AA0A5FDADC7EEAC6BEE = {isa = PBXBuildFile; fileRef = 7D2F3F0955AD000B1DD805E0; }; - 1CDB95CBF8A78E121703AABD = {isa = PBXBuildFile; fileRef = 56F1E6FB20F3E088CBFB1377; }; - 3C0CF21B9D661657A7DBB61D = {isa = PBXBuildFile; fileRef = 7CE94819A159EB97C4EB7CB0; }; - 5AA57ADA8E950DE1913F8074 = {isa = PBXBuildFile; fileRef = F038472164BBF13DB46AE980; }; - 2CD8DDC837D8042EBD00FAAC = {isa = PBXBuildFile; fileRef = 3B0C1CD3678A6F387D9FA74A; }; - DE69B418D3E6B6893977CDC1 = {isa = PBXBuildFile; fileRef = 50AF3FA7DCE765C398861AA7; }; - CFE6846487945890AEFA253B = {isa = PBXBuildFile; fileRef = 946060CD40B148EF6582DC18; }; - F683B8ED17E7E74361810BC1 = {isa = PBXBuildFile; fileRef = E46DA1382F4DD483C8752E50; }; - D9997560B40DD7D50FA3E9A0 = {isa = PBXBuildFile; fileRef = 4257FBF05F2E14AA226A1659; }; - B6142B2DF81E50A0E4E76F52 = {isa = PBXBuildFile; fileRef = 67BAE8E7B8157752734DFC9F; }; - 0988CF5ED15E82CC78B53137 = {isa = PBXBuildFile; fileRef = 427C295AC9AA6CB38233C5B0; }; - 7895E7D833D1029782229EBF = {isa = PBXBuildFile; fileRef = 468E08BC5AA0C3D8D1C9F410; }; - 7D138E4AA28C1C976EA1D186 = {isa = PBXBuildFile; fileRef = A8ED8DC046DDC1B796F6203C; }; - 5996B7821900A1790016AADE = {isa = PBXBuildFile; fileRef = 0DF7613DEBCCF4E1B2EDC4A8; }; - 1E62DE5EE4512FECE82E2E09 = {isa = PBXBuildFile; fileRef = 5D9FB702C8DE497F23332C5A; }; - 46761BF0558068478B8ABEC2 = {isa = PBXBuildFile; fileRef = 51A99C88D24F6FA6EB420D8C; }; - CB115CA1ED358F980E1CBE6F = {isa = PBXBuildFile; fileRef = 41F4ED3215862F7062B2B713; }; - 9C5A0DCFFD53650C343E142F = {isa = PBXBuildFile; fileRef = E7656FD65D0D145C3C20CF7D; }; - 9E6E52EFC3B57F61D701EC19 = {isa = PBXBuildFile; fileRef = 7A4D78B059F3D62B97671462; }; - 274D467D0A8753F7EDBD04DF = {isa = PBXBuildFile; fileRef = 28457B87BE9A7E186933D826; }; - 9494E786CFDC756E9821102A = {isa = PBXBuildFile; fileRef = 71AA66A84B31985D165C57FE; }; - 0B753ED8F52C2C248C53F0AB = {isa = PBXBuildFile; fileRef = A95AA746A1E8C497E09449B6; }; - DAB193581FCC69B9691223B5 = {isa = PBXBuildFile; fileRef = 8AB4F0CE47D006D5C910503B; }; - 5D22FDD5F55141A80CE432EC = {isa = PBXBuildFile; fileRef = 219AB01EF105570D181D3987; }; - 8FD7DF91F80816C75804E626 = {isa = PBXBuildFile; fileRef = BF41B9FD27A763715E7A3E73; }; - 3A43512BD12733D784697343 = {isa = PBXBuildFile; fileRef = BFAAC07638C61F5B0F3E0C09; }; - FBFDB86DECA46E503320CAEE = {isa = PBXBuildFile; fileRef = C4753B9659A6D64B908A54C9; }; - E8CDF6E5A8E80EB92013DBFE = {isa = PBXBuildFile; fileRef = 15DE670E1E07882F1D0F3310; }; - 10066F8FBF6EC9E37E0DE1AD = {isa = PBXBuildFile; fileRef = 1BEC912E78E170204E96C754; }; - B99E04E3BBE9E0D0DB1797C7 = {isa = PBXBuildFile; fileRef = 49E01B9883E491C0375E0D98; }; - 8689BCA55706DB2AF975F6BE = {isa = PBXBuildFile; fileRef = DD06BAFD7F940C41E23CF89A; }; - 7020F5FC4892253AEDC4B6C1 = {isa = PBXBuildFile; fileRef = 9B28F0E03AEBA79649A0DB4C; }; - FEC45F5FAA0B8F0B2EB4D62C = {isa = PBXBuildFile; fileRef = 2DEA38455C24F477A432448A; }; - 6348ED75152CC9DCD4327937 = {isa = PBXBuildFile; fileRef = BDA0CC6C16D3F2E9A387D7AB; }; - 631BBF5C0B44B9CAF4248FAD = {isa = PBXBuildFile; fileRef = 1CE564D2DE96733ADF54A601; }; - 2F31CF09BE378AD7ED861925 = {isa = PBXBuildFile; fileRef = C338756E3C93438896949FB9; }; - C4199DF380BE36A4BB61C542 = {isa = PBXBuildFile; fileRef = 94F53D7F00CBDBAF99D78072; }; - F26E07F79FD441C416B3E98E = {isa = PBXBuildFile; fileRef = 2D8348666CEF4F114F75186D; }; - 37FC7CDE7C515B3ABEFCBF20 = {isa = PBXBuildFile; fileRef = 08FBE4E80406DFC06A801885; }; - E7FA2C8749C360EBAC0C497E = {isa = PBXBuildFile; fileRef = 75A9FD8847C6F1C0FB785025; }; - AFB47B9448D55B25E1D20E8F = {isa = PBXBuildFile; fileRef = FB2A68BF92DB5683C7EA4255; }; - 0479B2108EC3D3086C664EF5 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; - 06368B2E4634AEF03549D2A7 = {isa = PBXFileReference; lastKnownFileType = file.xml; name = DefaultPreset.xml; path = ../../Assets/DefaultPreset.xml; sourceTree = "SOURCE_ROOT"; }; - 06F1639F9ACD9530D7553818 = {isa = PBXFileReference; lastKnownFileType = file.xml; name = MorningAtTheDMVPreset.xml; path = ../../Assets/MorningAtTheDMVPreset.xml; sourceTree = "SOURCE_ROOT"; }; - 08FBE4E80406DFC06A801885 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_gui_extra.mm"; path = "../../JuceLibraryCode/include_juce_gui_extra.mm"; sourceTree = "SOURCE_ROOT"; }; - 096DEFCE628676E9EDC08240 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_audio_devices"; path = "../../JuceLibraryCode/modules/juce_audio_devices"; sourceTree = "SOURCE_ROOT"; }; - 0A8426AE91646F9776A6C30E = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVKit.framework; path = System/Library/Frameworks/AVKit.framework; sourceTree = SDKROOT; }; - 0CD23932791610E5366E2581 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_data_structures"; path = "../../JuceLibraryCode/modules/juce_data_structures"; sourceTree = "SOURCE_ROOT"; }; - 0DB16E6AED0AC5A84706C552 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; }; - 0DF7613DEBCCF4E1B2EDC4A8 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FaustUIBridge.cpp; path = ../../Source/FaustUIBridge.cpp; sourceTree = "SOURCE_ROOT"; }; - 12E2E64B4BA3D4D3F7FDD5C7 = {isa = PBXFileReference; lastKnownFileType = file.otf; name = "Montserrat-Light.otf"; path = "../../Assets/Montserrat-Light.otf"; sourceTree = "SOURCE_ROOT"; }; - 15DE670E1E07882F1D0F3310 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "include_juce_audio_plugin_client_VST2.cpp"; path = "../../JuceLibraryCode/include_juce_audio_plugin_client_VST2.cpp"; sourceTree = "SOURCE_ROOT"; }; - 16ABFACFA41328E1822C64FC = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Info-VST3.plist"; path = "Info-VST3.plist"; sourceTree = "SOURCE_ROOT"; }; - 1B6CAB86422500A32B9A2268 = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Info-VST.plist"; path = "Info-VST.plist"; sourceTree = "SOURCE_ROOT"; }; - 1BEC912E78E170204E96C754 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "include_juce_audio_plugin_client_VST3.cpp"; path = "../../JuceLibraryCode/include_juce_audio_plugin_client_VST3.cpp"; sourceTree = "SOURCE_ROOT"; }; - 1CE564D2DE96733ADF54A601 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_dsp.mm"; path = "../../JuceLibraryCode/include_juce_dsp.mm"; sourceTree = "SOURCE_ROOT"; }; - 1FAFF3E78F94C4EFE22718DD = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Temper.entitlements; path = Temper.entitlements; sourceTree = "SOURCE_ROOT"; }; - 219AB01EF105570D181D3987 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_audio_plugin_client_AU_2.mm"; path = "../../JuceLibraryCode/include_juce_audio_plugin_client_AU_2.mm"; sourceTree = "SOURCE_ROOT"; }; - 253002B26ADB2119AD3ECFCC = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_audio_basics"; path = "../../JuceLibraryCode/modules/juce_audio_basics"; sourceTree = "SOURCE_ROOT"; }; - 28457B87BE9A7E186933D826 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_audio_devices.mm"; path = "../../JuceLibraryCode/include_juce_audio_devices.mm"; sourceTree = "SOURCE_ROOT"; }; - 2D8348666CEF4F114F75186D = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_gui_basics.mm"; path = "../../JuceLibraryCode/include_juce_gui_basics.mm"; sourceTree = "SOURCE_ROOT"; }; - 2DEA38455C24F477A432448A = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_cryptography.mm"; path = "../../JuceLibraryCode/include_juce_cryptography.mm"; sourceTree = "SOURCE_ROOT"; }; - 329DB2BBEB45BD6A9C25C06E = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Temper.vst; sourceTree = "BUILT_PRODUCTS_DIR"; }; - 38AD97F621B0472920539505 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PluginEditor.h; path = ../../Source/PluginEditor.h; sourceTree = "SOURCE_ROOT"; }; - 3B0C1CD3678A6F387D9FA74A = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; - 3C2BE373BB1BAB3D5D38E8B6 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_core"; path = "../../JuceLibraryCode/modules/juce_core"; sourceTree = "SOURCE_ROOT"; }; - 3D60425B91F9969B127BDB48 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_opengl"; path = "../../JuceLibraryCode/modules/juce_opengl"; sourceTree = "SOURCE_ROOT"; }; - 41F4ED3215862F7062B2B713 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = PluginEditor.cpp; path = ../../Source/PluginEditor.cpp; sourceTree = "SOURCE_ROOT"; }; - 4257FBF05F2E14AA226A1659 = {isa = PBXFileReference; lastKnownFileType = file.nib; name = RecentFilesMenuTemplate.nib; path = RecentFilesMenuTemplate.nib; sourceTree = "SOURCE_ROOT"; }; - 427C295AC9AA6CB38233C5B0 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MainComponent.cpp; path = ../../Source/MainComponent.cpp; sourceTree = "SOURCE_ROOT"; }; - 43C47DA992C4DBF75FF9D24B = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; }; - 45005A864595D15B0C0A0A06 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_cryptography"; path = "../../JuceLibraryCode/modules/juce_cryptography"; sourceTree = "SOURCE_ROOT"; }; - 468E08BC5AA0C3D8D1C9F410 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TemperLookAndFeel.cpp; path = ../../Source/TemperLookAndFeel.cpp; sourceTree = "SOURCE_ROOT"; }; - 49E01B9883E491C0375E0D98 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_audio_processors.mm"; path = "../../JuceLibraryCode/include_juce_audio_processors.mm"; sourceTree = "SOURCE_ROOT"; }; - 4B8BCF2F0AEF77E1734081AE = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BinaryData.h; path = ../../JuceLibraryCode/BinaryData.h; sourceTree = "SOURCE_ROOT"; }; - 50AF3FA7DCE765C398861AA7 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; - 51A99C88D24F6FA6EB420D8C = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = PluginProcessor.cpp; path = ../../Source/PluginProcessor.cpp; sourceTree = "SOURCE_ROOT"; }; - 56F1E6FB20F3E088CBFB1377 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; }; - 5916961A8219D0B65503FCC1 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_audio_plugin_client"; path = "../../JuceLibraryCode/modules/juce_audio_plugin_client"; sourceTree = "SOURCE_ROOT"; }; - 5D9FB702C8DE497F23332C5A = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TemperDsp.cpp; path = ../../Source/TemperDsp.cpp; sourceTree = "SOURCE_ROOT"; }; - 655E5FC18EFF266ED39F59A0 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RestrictionProcessor.h; path = ../../Source/RestrictionProcessor.h; sourceTree = "SOURCE_ROOT"; }; - 67BAE8E7B8157752734DFC9F = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SpectroscopeComponent.cpp; path = ../../Source/SpectroscopeComponent.cpp; sourceTree = "SOURCE_ROOT"; }; - 68478345A384B80536B12B21 = {isa = PBXFileReference; lastKnownFileType = file.xml; name = FlyingUnitedPreset.xml; path = ../../Assets/FlyingUnitedPreset.xml; sourceTree = "SOURCE_ROOT"; }; - 6BC0FF159358D5B4A032A59E = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_dsp"; path = "../../JuceLibraryCode/modules/juce_dsp"; sourceTree = "SOURCE_ROOT"; }; - 6D2D628981FCF64C310B884E = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; }; - 71AA66A84B31985D165C57FE = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_audio_formats.mm"; path = "../../JuceLibraryCode/include_juce_audio_formats.mm"; sourceTree = "SOURCE_ROOT"; }; - 73E7C5339E54B3E9C178B88A = {isa = PBXFileReference; lastKnownFileType = image.png; name = Background.png; path = ../../Assets/Background.png; sourceTree = "SOURCE_ROOT"; }; - 75A9FD8847C6F1C0FB785025 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_opengl.mm"; path = "../../JuceLibraryCode/include_juce_opengl.mm"; sourceTree = "SOURCE_ROOT"; }; - 77A91BB0FF221C1C2DA56F78 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_audio_utils"; path = "../../JuceLibraryCode/modules/juce_audio_utils"; sourceTree = "SOURCE_ROOT"; }; - 7A4D78B059F3D62B97671462 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_audio_basics.mm"; path = "../../JuceLibraryCode/include_juce_audio_basics.mm"; sourceTree = "SOURCE_ROOT"; }; - 7CE94819A159EB97C4EB7CB0 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMIDI.framework; path = System/Library/Frameworks/CoreMIDI.framework; sourceTree = SDKROOT; }; - 7D2F3F0955AD000B1DD805E0 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudioKit.framework; path = System/Library/Frameworks/CoreAudioKit.framework; sourceTree = SDKROOT; }; - 82F2F6F25EBB1289086EEDAE = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_graphics"; path = "../../JuceLibraryCode/modules/juce_graphics"; sourceTree = "SOURCE_ROOT"; }; - 84C933187392AB5213F68E7D = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_events"; path = "../../JuceLibraryCode/modules/juce_events"; sourceTree = "SOURCE_ROOT"; }; - 85D5F537A586A7233EA46537 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_gui_basics"; path = "../../JuceLibraryCode/modules/juce_gui_basics"; sourceTree = "SOURCE_ROOT"; }; - 88AE69AE0F81E844A525CC9A = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SpectroscopeComponent.h; path = ../../Source/SpectroscopeComponent.h; sourceTree = "SOURCE_ROOT"; }; - 8AB4F0CE47D006D5C910503B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_audio_plugin_client_AU_1.mm"; path = "../../JuceLibraryCode/include_juce_audio_plugin_client_AU_1.mm"; sourceTree = "SOURCE_ROOT"; }; - 946060CD40B148EF6582DC18 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; - 94F53D7F00CBDBAF99D78072 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_graphics.mm"; path = "../../JuceLibraryCode/include_juce_graphics.mm"; sourceTree = "SOURCE_ROOT"; }; - 984DC7C1FFB0CC7F4AE7C47F = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; - 9B28F0E03AEBA79649A0DB4C = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_core.mm"; path = "../../JuceLibraryCode/include_juce_core.mm"; sourceTree = "SOURCE_ROOT"; }; - A8ED8DC046DDC1B796F6203C = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RestrictionProcessor.cpp; path = ../../Source/RestrictionProcessor.cpp; sourceTree = "SOURCE_ROOT"; }; - A95AA746A1E8C497E09449B6 = {isa = PBXFileReference; lastKnownFileType = file.r; name = "include_juce_audio_plugin_client_AU.r"; path = "../../JuceLibraryCode/include_juce_audio_plugin_client_AU.r"; sourceTree = "SOURCE_ROOT"; }; - AF7A7862770F586EB8CF8E8C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MainComponent.h; path = ../../Source/MainComponent.h; sourceTree = "SOURCE_ROOT"; }; - B855EA5B24A1278D206CDC63 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_audio_processors"; path = "../../JuceLibraryCode/modules/juce_audio_processors"; sourceTree = "SOURCE_ROOT"; }; - B90EE98DE447E998BF9AC67B = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_video"; path = "../../JuceLibraryCode/modules/juce_video"; sourceTree = "SOURCE_ROOT"; }; - BDA0CC6C16D3F2E9A387D7AB = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_data_structures.mm"; path = "../../JuceLibraryCode/include_juce_data_structures.mm"; sourceTree = "SOURCE_ROOT"; }; - BED083CDF59E8F98DFACA442 = {isa = PBXFileReference; lastKnownFileType = image.png; name = GraphBackground.png; path = ../../Assets/GraphBackground.png; sourceTree = "SOURCE_ROOT"; }; - BF41B9FD27A763715E7A3E73 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "include_juce_audio_plugin_client_Standalone.cpp"; path = "../../JuceLibraryCode/include_juce_audio_plugin_client_Standalone.cpp"; sourceTree = "SOURCE_ROOT"; }; - BFAAC07638C61F5B0F3E0C09 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "include_juce_audio_plugin_client_utils.cpp"; path = "../../JuceLibraryCode/include_juce_audio_plugin_client_utils.cpp"; sourceTree = "SOURCE_ROOT"; }; - C338756E3C93438896949FB9 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_events.mm"; path = "../../JuceLibraryCode/include_juce_events.mm"; sourceTree = "SOURCE_ROOT"; }; - C33B7FFCC2442377C56E393D = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; - C4753B9659A6D64B908A54C9 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_audio_plugin_client_VST_utils.mm"; path = "../../JuceLibraryCode/include_juce_audio_plugin_client_VST_utils.mm"; sourceTree = "SOURCE_ROOT"; }; - C65386B81096933FA9436F33 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; - DA17DD1163220461EDB43F01 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PluginProcessor.h; path = ../../Source/PluginProcessor.h; sourceTree = "SOURCE_ROOT"; }; - DA229717FA82D3728EE12635 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = JuceHeader.h; path = ../../JuceLibraryCode/JuceHeader.h; sourceTree = "SOURCE_ROOT"; }; - DD06BAFD7F940C41E23CF89A = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_audio_utils.mm"; path = "../../JuceLibraryCode/include_juce_audio_utils.mm"; sourceTree = "SOURCE_ROOT"; }; - DE34C9EED8B65542DF1F7EA5 = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Temper.vst3; sourceTree = "BUILT_PRODUCTS_DIR"; }; - D382B2EFF926D55A5494CF1D = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Temper.component; sourceTree = "BUILT_PRODUCTS_DIR"; }; - CE24234A805A548104752B18 = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Temper.app; sourceTree = "BUILT_PRODUCTS_DIR"; }; - 51985E139AA96A0DF9BDD53F = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libTemper.a; sourceTree = "BUILT_PRODUCTS_DIR"; }; - DEDC7CAC683D9B79D66AC5BC = {isa = PBXFileReference; lastKnownFileType = file.xml; name = BeeStingPreset.xml; path = ../../Assets/BeeStingPreset.xml; sourceTree = "SOURCE_ROOT"; }; - E15F6B7B3DBDF9B9DA0014F2 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_audio_formats"; path = "../../JuceLibraryCode/modules/juce_audio_formats"; sourceTree = "SOURCE_ROOT"; }; - E46DA1382F4DD483C8752E50 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; - E4D7E302FD79D8288EDC02DF = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Info-AU.plist"; path = "Info-AU.plist"; sourceTree = "SOURCE_ROOT"; }; - E7656FD65D0D145C3C20CF7D = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = BinaryData.cpp; path = ../../JuceLibraryCode/BinaryData.cpp; sourceTree = "SOURCE_ROOT"; }; - E9E983AE01932CE7AABF122A = {isa = PBXFileReference; lastKnownFileType = file.xml; name = StubbedToePreset.xml; path = ../../Assets/StubbedToePreset.xml; sourceTree = "SOURCE_ROOT"; }; - EB5F70D3AED2FCD441751394 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TemperLookAndFeel.h; path = ../../Source/TemperLookAndFeel.h; sourceTree = "SOURCE_ROOT"; }; - ED786270C053227B54793072 = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Info-Standalone_Plugin.plist"; path = "Info-Standalone_Plugin.plist"; sourceTree = "SOURCE_ROOT"; }; - F038472164BBF13DB46AE980 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DiscRecording.framework; path = System/Library/Frameworks/DiscRecording.framework; sourceTree = SDKROOT; }; - F0E83AB8627EEB12A5F354C9 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FaustUIBridge.h; path = ../../Source/FaustUIBridge.h; sourceTree = "SOURCE_ROOT"; }; - F18B8A5D50E29FDAEF2E5581 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AppConfig.h; path = ../../JuceLibraryCode/AppConfig.h; sourceTree = "SOURCE_ROOT"; }; - F4E576760B96BFC53ADE07E8 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_gui_extra"; path = "../../JuceLibraryCode/modules/juce_gui_extra"; sourceTree = "SOURCE_ROOT"; }; - FB2A68BF92DB5683C7EA4255 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_video.mm"; path = "../../JuceLibraryCode/include_juce_video.mm"; sourceTree = "SOURCE_ROOT"; }; - 0783BBC300C13B7B7471518C = {isa = PBXGroup; children = ( - 73E7C5339E54B3E9C178B88A, - DEDC7CAC683D9B79D66AC5BC, - 06368B2E4634AEF03549D2A7, - 68478345A384B80536B12B21, - BED083CDF59E8F98DFACA442, - 12E2E64B4BA3D4D3F7FDD5C7, - 06F1639F9ACD9530D7553818, - E9E983AE01932CE7AABF122A, ); name = Assets; sourceTree = ""; }; - 5239F8DD8842949279B144DD = {isa = PBXGroup; children = ( - 67BAE8E7B8157752734DFC9F, - 88AE69AE0F81E844A525CC9A, - 427C295AC9AA6CB38233C5B0, - AF7A7862770F586EB8CF8E8C, - 468E08BC5AA0C3D8D1C9F410, - EB5F70D3AED2FCD441751394, - A8ED8DC046DDC1B796F6203C, - 655E5FC18EFF266ED39F59A0, - 0DF7613DEBCCF4E1B2EDC4A8, - F0E83AB8627EEB12A5F354C9, - 5D9FB702C8DE497F23332C5A, - 51A99C88D24F6FA6EB420D8C, - DA17DD1163220461EDB43F01, - 41F4ED3215862F7062B2B713, - 38AD97F621B0472920539505, ); name = Source; sourceTree = ""; }; - 78D8756494305AA83D310EA9 = {isa = PBXGroup; children = ( - 0783BBC300C13B7B7471518C, - 5239F8DD8842949279B144DD, ); name = Temper; sourceTree = ""; }; - FC58AB75B20CF5AE97BA51D3 = {isa = PBXGroup; children = ( - 253002B26ADB2119AD3ECFCC, - 096DEFCE628676E9EDC08240, - E15F6B7B3DBDF9B9DA0014F2, - 5916961A8219D0B65503FCC1, - B855EA5B24A1278D206CDC63, - 77A91BB0FF221C1C2DA56F78, - 3C2BE373BB1BAB3D5D38E8B6, - 45005A864595D15B0C0A0A06, - 0CD23932791610E5366E2581, - 6BC0FF159358D5B4A032A59E, - 84C933187392AB5213F68E7D, - 82F2F6F25EBB1289086EEDAE, - 85D5F537A586A7233EA46537, - F4E576760B96BFC53ADE07E8, - 3D60425B91F9969B127BDB48, - B90EE98DE447E998BF9AC67B, ); name = "JUCE Modules"; sourceTree = ""; }; - 7F3BE1629581C7BA6B7F806F = {isa = PBXGroup; children = ( - F18B8A5D50E29FDAEF2E5581, - E7656FD65D0D145C3C20CF7D, - 4B8BCF2F0AEF77E1734081AE, - 7A4D78B059F3D62B97671462, - 28457B87BE9A7E186933D826, - 71AA66A84B31985D165C57FE, - A95AA746A1E8C497E09449B6, - 8AB4F0CE47D006D5C910503B, - 219AB01EF105570D181D3987, - BF41B9FD27A763715E7A3E73, - BFAAC07638C61F5B0F3E0C09, - C4753B9659A6D64B908A54C9, - 15DE670E1E07882F1D0F3310, - 1BEC912E78E170204E96C754, - 49E01B9883E491C0375E0D98, - DD06BAFD7F940C41E23CF89A, - 9B28F0E03AEBA79649A0DB4C, - 2DEA38455C24F477A432448A, - BDA0CC6C16D3F2E9A387D7AB, - 1CE564D2DE96733ADF54A601, - C338756E3C93438896949FB9, - 94F53D7F00CBDBAF99D78072, - 2D8348666CEF4F114F75186D, - 08FBE4E80406DFC06A801885, - 75A9FD8847C6F1C0FB785025, - FB2A68BF92DB5683C7EA4255, - DA229717FA82D3728EE12635, ); name = "JUCE Library Code"; sourceTree = ""; }; - 7B6C20AA19B30308B7071BB6 = {isa = PBXGroup; children = ( - 1B6CAB86422500A32B9A2268, - 16ABFACFA41328E1822C64FC, - E4D7E302FD79D8288EDC02DF, - ED786270C053227B54793072, - 4257FBF05F2E14AA226A1659, ); name = Resources; sourceTree = ""; }; - 4EB0C2E5B91B060521668B43 = {isa = PBXGroup; children = ( - 984DC7C1FFB0CC7F4AE7C47F, - C65386B81096933FA9436F33, - 6D2D628981FCF64C310B884E, - C33B7FFCC2442377C56E393D, - 0A8426AE91646F9776A6C30E, - 43C47DA992C4DBF75FF9D24B, - 0479B2108EC3D3086C664EF5, - 0DB16E6AED0AC5A84706C552, - 7D2F3F0955AD000B1DD805E0, - 56F1E6FB20F3E088CBFB1377, - 7CE94819A159EB97C4EB7CB0, - F038472164BBF13DB46AE980, - 3B0C1CD3678A6F387D9FA74A, - 50AF3FA7DCE765C398861AA7, - 946060CD40B148EF6582DC18, - E46DA1382F4DD483C8752E50, ); name = Frameworks; sourceTree = ""; }; - D70C3C34C34A0174F5CCAECB = {isa = PBXGroup; children = ( - 329DB2BBEB45BD6A9C25C06E, - DE34C9EED8B65542DF1F7EA5, - D382B2EFF926D55A5494CF1D, - CE24234A805A548104752B18, - 51985E139AA96A0DF9BDD53F, ); name = Products; sourceTree = ""; }; - 16B7A8795DC462581C0D3409 = {isa = PBXGroup; children = ( - 1FAFF3E78F94C4EFE22718DD, - 78D8756494305AA83D310EA9, - FC58AB75B20CF5AE97BA51D3, - 7F3BE1629581C7BA6B7F806F, - 7B6C20AA19B30308B7071BB6, - 4EB0C2E5B91B060521668B43, - D70C3C34C34A0174F5CCAECB, ); name = Source; sourceTree = ""; }; - C7002CCFFE56C8F1B385BDA7 = {isa = XCBuildConfiguration; buildSettings = { - MACOSX_DEPLOYMENT_TARGET = 10.9; }; name = Debug; }; - D652EDE4F3E5F7F37B76225A = {isa = XCBuildConfiguration; buildSettings = { - MACOSX_DEPLOYMENT_TARGET = 10.9; }; name = Release; }; - 992799EC591C91E642CD3D65 = {isa = XCBuildConfiguration; buildSettings = { - MACOSX_DEPLOYMENT_TARGET = 10.9; }; name = Demo; }; - 037777277548B3E4413ECEF1 = {isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "c++14"; +/* Begin PBXAggregateTarget section */ + 2BEC471FAEF6D07D8826CB28 /* Temper - All */ = { + isa = PBXAggregateTarget; + buildConfigurationList = C256B4ADC5A4B7C840FAB917; + buildPhases = ( + ); + dependencies = ( + 573E0BBB6A953C208DF6AF13, + A2FCC569F3B99DB3BC84295D, + EAD29230987F2FC5BD2AEBCB, + 67479A2F14D73BB854CE20CD, + 77215A3EEEC42A17A98F1946, + ); + name = "Temper - All"; + productName = Temper; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 02843AA0A5FDADC7EEAC6BEE /* CoreAudioKit.framework */ = {isa = PBXBuildFile; fileRef = 7D2F3F0955AD000B1DD805E0; }; + 08B71F44034B3235DC256506 /* Carbon.framework */ = {isa = PBXBuildFile; fileRef = 43C47DA992C4DBF75FF9D24B; }; + 0988CF5ED15E82CC78B53137 /* MainComponent.cpp */ = {isa = PBXBuildFile; fileRef = 427C295AC9AA6CB38233C5B0; }; + 0B753ED8F52C2C248C53F0AB /* include_juce_audio_plugin_client_AU.r */ = {isa = PBXBuildFile; fileRef = A95AA746A1E8C497E09449B6; }; + 10066F8FBF6EC9E37E0DE1AD /* include_juce_audio_plugin_client_VST3.cpp */ = {isa = PBXBuildFile; fileRef = 1BEC912E78E170204E96C754; }; + 154876FE753F96C6DBB1035D /* AU */ = {isa = PBXBuildFile; fileRef = D382B2EFF926D55A5494CF1D; }; + 1B7D68D6BB5C540D38FF9122 /* Shared Code */ = {isa = PBXBuildFile; fileRef = 51985E139AA96A0DF9BDD53F; }; + 1CDB95CBF8A78E121703AABD /* CoreMedia.framework */ = {isa = PBXBuildFile; fileRef = 56F1E6FB20F3E088CBFB1377; }; + 1E62DE5EE4512FECE82E2E09 /* TemperDsp.cpp */ = {isa = PBXBuildFile; fileRef = 5D9FB702C8DE497F23332C5A; }; + 26DDC2E8A87CED2C233559FF /* Cocoa.framework */ = {isa = PBXBuildFile; fileRef = 0479B2108EC3D3086C664EF5; }; + 274D467D0A8753F7EDBD04DF /* include_juce_audio_devices.mm */ = {isa = PBXBuildFile; fileRef = 28457B87BE9A7E186933D826; }; + 2CD8DDC837D8042EBD00FAAC /* IOKit.framework */ = {isa = PBXBuildFile; fileRef = 3B0C1CD3678A6F387D9FA74A; }; + 2F31CF09BE378AD7ED861925 /* include_juce_events.mm */ = {isa = PBXBuildFile; fileRef = C338756E3C93438896949FB9; }; + 37FC7CDE7C515B3ABEFCBF20 /* include_juce_gui_extra.mm */ = {isa = PBXBuildFile; fileRef = 08FBE4E80406DFC06A801885; }; + 3A43512BD12733D784697343 /* include_juce_audio_plugin_client_utils.cpp */ = {isa = PBXBuildFile; fileRef = BFAAC07638C61F5B0F3E0C09; }; + 3B9D697D29F5DFF7BFC1B20A /* VST */ = {isa = PBXBuildFile; fileRef = 329DB2BBEB45BD6A9C25C06E; }; + 3C0CF21B9D661657A7DBB61D /* CoreMIDI.framework */ = {isa = PBXBuildFile; fileRef = 7CE94819A159EB97C4EB7CB0; }; + 46761BF0558068478B8ABEC2 /* PluginProcessor.cpp */ = {isa = PBXBuildFile; fileRef = 51A99C88D24F6FA6EB420D8C; }; + 5996B7821900A1790016AADE /* FaustUIBridge.cpp */ = {isa = PBXBuildFile; fileRef = 0DF7613DEBCCF4E1B2EDC4A8; }; + 5AA57ADA8E950DE1913F8074 /* DiscRecording.framework */ = {isa = PBXBuildFile; fileRef = F038472164BBF13DB46AE980; }; + 5B7726FEB45B778ABED69629 /* CoreAudio.framework */ = {isa = PBXBuildFile; fileRef = 0DB16E6AED0AC5A84706C552; }; + 5D22FDD5F55141A80CE432EC /* include_juce_audio_plugin_client_AU_2.mm */ = {isa = PBXBuildFile; fileRef = 219AB01EF105570D181D3987; }; + 61AD7A33F376FB4318E4F7AF /* AudioToolbox.framework */ = {isa = PBXBuildFile; fileRef = C65386B81096933FA9436F33; }; + 631BBF5C0B44B9CAF4248FAD /* include_juce_dsp.mm */ = {isa = PBXBuildFile; fileRef = 1CE564D2DE96733ADF54A601; }; + 6348ED75152CC9DCD4327937 /* include_juce_data_structures.mm */ = {isa = PBXBuildFile; fileRef = BDA0CC6C16D3F2E9A387D7AB; }; + 7020F5FC4892253AEDC4B6C1 /* include_juce_core.mm */ = {isa = PBXBuildFile; fileRef = 9B28F0E03AEBA79649A0DB4C; }; + 783DDBA43AF33A5DA10275DE /* VST3 */ = {isa = PBXBuildFile; fileRef = DE34C9EED8B65542DF1F7EA5; }; + 7895E7D833D1029782229EBF /* TemperLookAndFeel.cpp */ = {isa = PBXBuildFile; fileRef = 468E08BC5AA0C3D8D1C9F410; }; + 79FECC7AD35E7CD7C30569E3 /* Accelerate.framework */ = {isa = PBXBuildFile; fileRef = 984DC7C1FFB0CC7F4AE7C47F; }; + 7D138E4AA28C1C976EA1D186 /* RestrictionProcessor.cpp */ = {isa = PBXBuildFile; fileRef = A8ED8DC046DDC1B796F6203C; }; + 8689BCA55706DB2AF975F6BE /* include_juce_audio_utils.mm */ = {isa = PBXBuildFile; fileRef = DD06BAFD7F940C41E23CF89A; }; + 8FD7DF91F80816C75804E626 /* include_juce_audio_plugin_client_Standalone.cpp */ = {isa = PBXBuildFile; fileRef = BF41B9FD27A763715E7A3E73; }; + 9494E786CFDC756E9821102A /* include_juce_audio_formats.mm */ = {isa = PBXBuildFile; fileRef = 71AA66A84B31985D165C57FE; }; + 9C5A0DCFFD53650C343E142F /* BinaryData.cpp */ = {isa = PBXBuildFile; fileRef = E7656FD65D0D145C3C20CF7D; }; + 9E6E52EFC3B57F61D701EC19 /* include_juce_audio_basics.mm */ = {isa = PBXBuildFile; fileRef = 7A4D78B059F3D62B97671462; }; + AFB47B9448D55B25E1D20E8F /* include_juce_video.mm */ = {isa = PBXBuildFile; fileRef = FB2A68BF92DB5683C7EA4255; }; + B19EF2739AFA3DDA44EA7526 /* AVFoundation.framework */ = {isa = PBXBuildFile; fileRef = C33B7FFCC2442377C56E393D; }; + B6142B2DF81E50A0E4E76F52 /* SpectroscopeComponent.cpp */ = {isa = PBXBuildFile; fileRef = 67BAE8E7B8157752734DFC9F; }; + B99E04E3BBE9E0D0DB1797C7 /* include_juce_audio_processors.mm */ = {isa = PBXBuildFile; fileRef = 49E01B9883E491C0375E0D98; }; + BF91BC76FFFCCFD8A5A3DB90 /* AudioUnit.framework */ = {isa = PBXBuildFile; fileRef = 6D2D628981FCF64C310B884E; }; + C3B45D6C33FC8D2DFFAFD911 /* AVKit.framework */ = {isa = PBXBuildFile; fileRef = 0A8426AE91646F9776A6C30E; }; + C4199DF380BE36A4BB61C542 /* include_juce_graphics.mm */ = {isa = PBXBuildFile; fileRef = 94F53D7F00CBDBAF99D78072; }; + C7C2EA44D4C9727417B79D74 /* Foundation.framework */ = {isa = PBXBuildFile; fileRef = D203737AE0E9D572DA5C83BD; }; + CB115CA1ED358F980E1CBE6F /* PluginEditor.cpp */ = {isa = PBXBuildFile; fileRef = 41F4ED3215862F7062B2B713; }; + CFE6846487945890AEFA253B /* QuartzCore.framework */ = {isa = PBXBuildFile; fileRef = 946060CD40B148EF6582DC18; }; + D9997560B40DD7D50FA3E9A0 /* RecentFilesMenuTemplate.nib */ = {isa = PBXBuildFile; fileRef = 4257FBF05F2E14AA226A1659; }; + DAB193581FCC69B9691223B5 /* include_juce_audio_plugin_client_AU_1.mm */ = {isa = PBXBuildFile; fileRef = 8AB4F0CE47D006D5C910503B; }; + DE69B418D3E6B6893977CDC1 /* OpenGL.framework */ = {isa = PBXBuildFile; fileRef = 50AF3FA7DCE765C398861AA7; }; + E7FA2C8749C360EBAC0C497E /* include_juce_opengl.mm */ = {isa = PBXBuildFile; fileRef = 75A9FD8847C6F1C0FB785025; }; + E8AD28E0C82240E8E5BFD0B7 /* Standalone Plugin */ = {isa = PBXBuildFile; fileRef = CE24234A805A548104752B18; }; + E8CDF6E5A8E80EB92013DBFE /* include_juce_audio_plugin_client_VST2.cpp */ = {isa = PBXBuildFile; fileRef = 15DE670E1E07882F1D0F3310; }; + F26E07F79FD441C416B3E98E /* include_juce_gui_basics.mm */ = {isa = PBXBuildFile; fileRef = 2D8348666CEF4F114F75186D; }; + F683B8ED17E7E74361810BC1 /* WebKit.framework */ = {isa = PBXBuildFile; fileRef = E46DA1382F4DD483C8752E50; }; + FBFDB86DECA46E503320CAEE /* include_juce_audio_plugin_client_VST_utils.mm */ = {isa = PBXBuildFile; fileRef = C4753B9659A6D64B908A54C9; }; + FEC45F5FAA0B8F0B2EB4D62C /* include_juce_cryptography.mm */ = {isa = PBXBuildFile; fileRef = 2DEA38455C24F477A432448A; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0479B2108EC3D3086C664EF5 /* Cocoa.framework */ /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 06368B2E4634AEF03549D2A7 /* DefaultPreset.xml */ /* DefaultPreset.xml */ = {isa = PBXFileReference; lastKnownFileType = file.xml; name = DefaultPreset.xml; path = ../../Assets/DefaultPreset.xml; sourceTree = SOURCE_ROOT; }; + 06F1639F9ACD9530D7553818 /* MorningAtTheDMVPreset.xml */ /* MorningAtTheDMVPreset.xml */ = {isa = PBXFileReference; lastKnownFileType = file.xml; name = MorningAtTheDMVPreset.xml; path = ../../Assets/MorningAtTheDMVPreset.xml; sourceTree = SOURCE_ROOT; }; + 08FBE4E80406DFC06A801885 /* include_juce_gui_extra.mm */ /* include_juce_gui_extra.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_gui_extra.mm; path = ../../JuceLibraryCode/include_juce_gui_extra.mm; sourceTree = SOURCE_ROOT; }; + 096DEFCE628676E9EDC08240 /* juce_audio_devices */ /* juce_audio_devices */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_audio_devices; path = ../../JuceLibraryCode/modules/juce_audio_devices; sourceTree = SOURCE_ROOT; }; + 0A8426AE91646F9776A6C30E /* AVKit.framework */ /* AVKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVKit.framework; path = System/Library/Frameworks/AVKit.framework; sourceTree = SDKROOT; }; + 0CD23932791610E5366E2581 /* juce_data_structures */ /* juce_data_structures */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_data_structures; path = ../../JuceLibraryCode/modules/juce_data_structures; sourceTree = SOURCE_ROOT; }; + 0DB16E6AED0AC5A84706C552 /* CoreAudio.framework */ /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; }; + 0DF7613DEBCCF4E1B2EDC4A8 /* FaustUIBridge.cpp */ /* FaustUIBridge.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FaustUIBridge.cpp; path = ../../Source/FaustUIBridge.cpp; sourceTree = SOURCE_ROOT; }; + 12E2E64B4BA3D4D3F7FDD5C7 /* Montserrat-Light.otf */ /* Montserrat-Light.otf */ = {isa = PBXFileReference; lastKnownFileType = file.otf; name = "Montserrat-Light.otf"; path = "../../Assets/Montserrat-Light.otf"; sourceTree = SOURCE_ROOT; }; + 15DE670E1E07882F1D0F3310 /* include_juce_audio_plugin_client_VST2.cpp */ /* include_juce_audio_plugin_client_VST2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = include_juce_audio_plugin_client_VST2.cpp; path = ../../JuceLibraryCode/include_juce_audio_plugin_client_VST2.cpp; sourceTree = SOURCE_ROOT; }; + 16ABFACFA41328E1822C64FC /* Info-VST3.plist */ /* Info-VST3.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Info-VST3.plist"; path = "Info-VST3.plist"; sourceTree = SOURCE_ROOT; }; + 1B6CAB86422500A32B9A2268 /* Info-VST.plist */ /* Info-VST.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Info-VST.plist"; path = "Info-VST.plist"; sourceTree = SOURCE_ROOT; }; + 1BEC912E78E170204E96C754 /* include_juce_audio_plugin_client_VST3.cpp */ /* include_juce_audio_plugin_client_VST3.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = include_juce_audio_plugin_client_VST3.cpp; path = ../../JuceLibraryCode/include_juce_audio_plugin_client_VST3.cpp; sourceTree = SOURCE_ROOT; }; + 1CE564D2DE96733ADF54A601 /* include_juce_dsp.mm */ /* include_juce_dsp.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_dsp.mm; path = ../../JuceLibraryCode/include_juce_dsp.mm; sourceTree = SOURCE_ROOT; }; + 219AB01EF105570D181D3987 /* include_juce_audio_plugin_client_AU_2.mm */ /* include_juce_audio_plugin_client_AU_2.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_audio_plugin_client_AU_2.mm; path = ../../JuceLibraryCode/include_juce_audio_plugin_client_AU_2.mm; sourceTree = SOURCE_ROOT; }; + 253002B26ADB2119AD3ECFCC /* juce_audio_basics */ /* juce_audio_basics */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_audio_basics; path = ../../JuceLibraryCode/modules/juce_audio_basics; sourceTree = SOURCE_ROOT; }; + 28457B87BE9A7E186933D826 /* include_juce_audio_devices.mm */ /* include_juce_audio_devices.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_audio_devices.mm; path = ../../JuceLibraryCode/include_juce_audio_devices.mm; sourceTree = SOURCE_ROOT; }; + 2D8348666CEF4F114F75186D /* include_juce_gui_basics.mm */ /* include_juce_gui_basics.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_gui_basics.mm; path = ../../JuceLibraryCode/include_juce_gui_basics.mm; sourceTree = SOURCE_ROOT; }; + 2DEA38455C24F477A432448A /* include_juce_cryptography.mm */ /* include_juce_cryptography.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_cryptography.mm; path = ../../JuceLibraryCode/include_juce_cryptography.mm; sourceTree = SOURCE_ROOT; }; + 329DB2BBEB45BD6A9C25C06E /* VST */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Temper.vst; sourceTree = BUILT_PRODUCTS_DIR; }; + 38AD97F621B0472920539505 /* PluginEditor.h */ /* PluginEditor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PluginEditor.h; path = ../../Source/PluginEditor.h; sourceTree = SOURCE_ROOT; }; + 3B0C1CD3678A6F387D9FA74A /* IOKit.framework */ /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 3C2BE373BB1BAB3D5D38E8B6 /* juce_core */ /* juce_core */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_core; path = ../../JuceLibraryCode/modules/juce_core; sourceTree = SOURCE_ROOT; }; + 3D60425B91F9969B127BDB48 /* juce_opengl */ /* juce_opengl */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_opengl; path = ../../JuceLibraryCode/modules/juce_opengl; sourceTree = SOURCE_ROOT; }; + 41F4ED3215862F7062B2B713 /* PluginEditor.cpp */ /* PluginEditor.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = PluginEditor.cpp; path = ../../Source/PluginEditor.cpp; sourceTree = SOURCE_ROOT; }; + 4257FBF05F2E14AA226A1659 /* RecentFilesMenuTemplate.nib */ /* RecentFilesMenuTemplate.nib */ = {isa = PBXFileReference; lastKnownFileType = file.nib; name = RecentFilesMenuTemplate.nib; path = RecentFilesMenuTemplate.nib; sourceTree = SOURCE_ROOT; }; + 427C295AC9AA6CB38233C5B0 /* MainComponent.cpp */ /* MainComponent.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MainComponent.cpp; path = ../../Source/MainComponent.cpp; sourceTree = SOURCE_ROOT; }; + 43C47DA992C4DBF75FF9D24B /* Carbon.framework */ /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; }; + 45005A864595D15B0C0A0A06 /* juce_cryptography */ /* juce_cryptography */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_cryptography; path = ../../JuceLibraryCode/modules/juce_cryptography; sourceTree = SOURCE_ROOT; }; + 468E08BC5AA0C3D8D1C9F410 /* TemperLookAndFeel.cpp */ /* TemperLookAndFeel.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TemperLookAndFeel.cpp; path = ../../Source/TemperLookAndFeel.cpp; sourceTree = SOURCE_ROOT; }; + 49E01B9883E491C0375E0D98 /* include_juce_audio_processors.mm */ /* include_juce_audio_processors.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_audio_processors.mm; path = ../../JuceLibraryCode/include_juce_audio_processors.mm; sourceTree = SOURCE_ROOT; }; + 4B8BCF2F0AEF77E1734081AE /* BinaryData.h */ /* BinaryData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BinaryData.h; path = ../../JuceLibraryCode/BinaryData.h; sourceTree = SOURCE_ROOT; }; + 50AF3FA7DCE765C398861AA7 /* OpenGL.framework */ /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 51985E139AA96A0DF9BDD53F /* Shared Code */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libTemper.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 51A99C88D24F6FA6EB420D8C /* PluginProcessor.cpp */ /* PluginProcessor.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = PluginProcessor.cpp; path = ../../Source/PluginProcessor.cpp; sourceTree = SOURCE_ROOT; }; + 56F1E6FB20F3E088CBFB1377 /* CoreMedia.framework */ /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; }; + 5916961A8219D0B65503FCC1 /* juce_audio_plugin_client */ /* juce_audio_plugin_client */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_audio_plugin_client; path = ../../JuceLibraryCode/modules/juce_audio_plugin_client; sourceTree = SOURCE_ROOT; }; + 5D9FB702C8DE497F23332C5A /* TemperDsp.cpp */ /* TemperDsp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TemperDsp.cpp; path = ../../Source/TemperDsp.cpp; sourceTree = SOURCE_ROOT; }; + 655E5FC18EFF266ED39F59A0 /* RestrictionProcessor.h */ /* RestrictionProcessor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RestrictionProcessor.h; path = ../../Source/RestrictionProcessor.h; sourceTree = SOURCE_ROOT; }; + 67BAE8E7B8157752734DFC9F /* SpectroscopeComponent.cpp */ /* SpectroscopeComponent.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SpectroscopeComponent.cpp; path = ../../Source/SpectroscopeComponent.cpp; sourceTree = SOURCE_ROOT; }; + 68478345A384B80536B12B21 /* FlyingUnitedPreset.xml */ /* FlyingUnitedPreset.xml */ = {isa = PBXFileReference; lastKnownFileType = file.xml; name = FlyingUnitedPreset.xml; path = ../../Assets/FlyingUnitedPreset.xml; sourceTree = SOURCE_ROOT; }; + 6BC0FF159358D5B4A032A59E /* juce_dsp */ /* juce_dsp */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_dsp; path = ../../JuceLibraryCode/modules/juce_dsp; sourceTree = SOURCE_ROOT; }; + 6D2D628981FCF64C310B884E /* AudioUnit.framework */ /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; }; + 71AA66A84B31985D165C57FE /* include_juce_audio_formats.mm */ /* include_juce_audio_formats.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_audio_formats.mm; path = ../../JuceLibraryCode/include_juce_audio_formats.mm; sourceTree = SOURCE_ROOT; }; + 73E7C5339E54B3E9C178B88A /* Background.png */ /* Background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Background.png; path = ../../Assets/Background.png; sourceTree = SOURCE_ROOT; }; + 75A9FD8847C6F1C0FB785025 /* include_juce_opengl.mm */ /* include_juce_opengl.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_opengl.mm; path = ../../JuceLibraryCode/include_juce_opengl.mm; sourceTree = SOURCE_ROOT; }; + 77A91BB0FF221C1C2DA56F78 /* juce_audio_utils */ /* juce_audio_utils */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_audio_utils; path = ../../JuceLibraryCode/modules/juce_audio_utils; sourceTree = SOURCE_ROOT; }; + 7A4D78B059F3D62B97671462 /* include_juce_audio_basics.mm */ /* include_juce_audio_basics.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_audio_basics.mm; path = ../../JuceLibraryCode/include_juce_audio_basics.mm; sourceTree = SOURCE_ROOT; }; + 7CE94819A159EB97C4EB7CB0 /* CoreMIDI.framework */ /* CoreMIDI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMIDI.framework; path = System/Library/Frameworks/CoreMIDI.framework; sourceTree = SDKROOT; }; + 7D2F3F0955AD000B1DD805E0 /* CoreAudioKit.framework */ /* CoreAudioKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudioKit.framework; path = System/Library/Frameworks/CoreAudioKit.framework; sourceTree = SDKROOT; }; + 82F2F6F25EBB1289086EEDAE /* juce_graphics */ /* juce_graphics */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_graphics; path = ../../JuceLibraryCode/modules/juce_graphics; sourceTree = SOURCE_ROOT; }; + 84C933187392AB5213F68E7D /* juce_events */ /* juce_events */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_events; path = ../../JuceLibraryCode/modules/juce_events; sourceTree = SOURCE_ROOT; }; + 85D5F537A586A7233EA46537 /* juce_gui_basics */ /* juce_gui_basics */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_gui_basics; path = ../../JuceLibraryCode/modules/juce_gui_basics; sourceTree = SOURCE_ROOT; }; + 88AE69AE0F81E844A525CC9A /* SpectroscopeComponent.h */ /* SpectroscopeComponent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SpectroscopeComponent.h; path = ../../Source/SpectroscopeComponent.h; sourceTree = SOURCE_ROOT; }; + 8AB4F0CE47D006D5C910503B /* include_juce_audio_plugin_client_AU_1.mm */ /* include_juce_audio_plugin_client_AU_1.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_audio_plugin_client_AU_1.mm; path = ../../JuceLibraryCode/include_juce_audio_plugin_client_AU_1.mm; sourceTree = SOURCE_ROOT; }; + 9177203C336BA8019CF98FFD /* JucePluginDefines.h */ /* JucePluginDefines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = JucePluginDefines.h; path = ../../JuceLibraryCode/JucePluginDefines.h; sourceTree = SOURCE_ROOT; }; + 946060CD40B148EF6582DC18 /* QuartzCore.framework */ /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + 94F53D7F00CBDBAF99D78072 /* include_juce_graphics.mm */ /* include_juce_graphics.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_graphics.mm; path = ../../JuceLibraryCode/include_juce_graphics.mm; sourceTree = SOURCE_ROOT; }; + 984DC7C1FFB0CC7F4AE7C47F /* Accelerate.framework */ /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; + 9B28F0E03AEBA79649A0DB4C /* include_juce_core.mm */ /* include_juce_core.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_core.mm; path = ../../JuceLibraryCode/include_juce_core.mm; sourceTree = SOURCE_ROOT; }; + A8ED8DC046DDC1B796F6203C /* RestrictionProcessor.cpp */ /* RestrictionProcessor.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RestrictionProcessor.cpp; path = ../../Source/RestrictionProcessor.cpp; sourceTree = SOURCE_ROOT; }; + A95AA746A1E8C497E09449B6 /* include_juce_audio_plugin_client_AU.r */ /* include_juce_audio_plugin_client_AU.r */ = {isa = PBXFileReference; lastKnownFileType = file.r; name = include_juce_audio_plugin_client_AU.r; path = ../../JuceLibraryCode/include_juce_audio_plugin_client_AU.r; sourceTree = SOURCE_ROOT; }; + AF7A7862770F586EB8CF8E8C /* MainComponent.h */ /* MainComponent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MainComponent.h; path = ../../Source/MainComponent.h; sourceTree = SOURCE_ROOT; }; + B855EA5B24A1278D206CDC63 /* juce_audio_processors */ /* juce_audio_processors */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_audio_processors; path = ../../JuceLibraryCode/modules/juce_audio_processors; sourceTree = SOURCE_ROOT; }; + B90EE98DE447E998BF9AC67B /* juce_video */ /* juce_video */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_video; path = ../../JuceLibraryCode/modules/juce_video; sourceTree = SOURCE_ROOT; }; + BDA0CC6C16D3F2E9A387D7AB /* include_juce_data_structures.mm */ /* include_juce_data_structures.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_data_structures.mm; path = ../../JuceLibraryCode/include_juce_data_structures.mm; sourceTree = SOURCE_ROOT; }; + BED083CDF59E8F98DFACA442 /* GraphBackground.png */ /* GraphBackground.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = GraphBackground.png; path = ../../Assets/GraphBackground.png; sourceTree = SOURCE_ROOT; }; + BF41B9FD27A763715E7A3E73 /* include_juce_audio_plugin_client_Standalone.cpp */ /* include_juce_audio_plugin_client_Standalone.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = include_juce_audio_plugin_client_Standalone.cpp; path = ../../JuceLibraryCode/include_juce_audio_plugin_client_Standalone.cpp; sourceTree = SOURCE_ROOT; }; + BFAAC07638C61F5B0F3E0C09 /* include_juce_audio_plugin_client_utils.cpp */ /* include_juce_audio_plugin_client_utils.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = include_juce_audio_plugin_client_utils.cpp; path = ../../JuceLibraryCode/include_juce_audio_plugin_client_utils.cpp; sourceTree = SOURCE_ROOT; }; + C338756E3C93438896949FB9 /* include_juce_events.mm */ /* include_juce_events.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_events.mm; path = ../../JuceLibraryCode/include_juce_events.mm; sourceTree = SOURCE_ROOT; }; + C33B7FFCC2442377C56E393D /* AVFoundation.framework */ /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; + C4753B9659A6D64B908A54C9 /* include_juce_audio_plugin_client_VST_utils.mm */ /* include_juce_audio_plugin_client_VST_utils.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_audio_plugin_client_VST_utils.mm; path = ../../JuceLibraryCode/include_juce_audio_plugin_client_VST_utils.mm; sourceTree = SOURCE_ROOT; }; + C65386B81096933FA9436F33 /* AudioToolbox.framework */ /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; + CE24234A805A548104752B18 /* Standalone Plugin */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Temper.app; sourceTree = BUILT_PRODUCTS_DIR; }; + D203737AE0E9D572DA5C83BD /* Foundation.framework */ /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + D382B2EFF926D55A5494CF1D /* AU */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Temper.component; sourceTree = BUILT_PRODUCTS_DIR; }; + DA17DD1163220461EDB43F01 /* PluginProcessor.h */ /* PluginProcessor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PluginProcessor.h; path = ../../Source/PluginProcessor.h; sourceTree = SOURCE_ROOT; }; + DA229717FA82D3728EE12635 /* JuceHeader.h */ /* JuceHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = JuceHeader.h; path = ../../JuceLibraryCode/JuceHeader.h; sourceTree = SOURCE_ROOT; }; + DD06BAFD7F940C41E23CF89A /* include_juce_audio_utils.mm */ /* include_juce_audio_utils.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_audio_utils.mm; path = ../../JuceLibraryCode/include_juce_audio_utils.mm; sourceTree = SOURCE_ROOT; }; + DE34C9EED8B65542DF1F7EA5 /* VST3 */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Temper.vst3; sourceTree = BUILT_PRODUCTS_DIR; }; + DEDC7CAC683D9B79D66AC5BC /* BeeStingPreset.xml */ /* BeeStingPreset.xml */ = {isa = PBXFileReference; lastKnownFileType = file.xml; name = BeeStingPreset.xml; path = ../../Assets/BeeStingPreset.xml; sourceTree = SOURCE_ROOT; }; + E15F6B7B3DBDF9B9DA0014F2 /* juce_audio_formats */ /* juce_audio_formats */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_audio_formats; path = ../../JuceLibraryCode/modules/juce_audio_formats; sourceTree = SOURCE_ROOT; }; + E46DA1382F4DD483C8752E50 /* WebKit.framework */ /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; + E4D7E302FD79D8288EDC02DF /* Info-AU.plist */ /* Info-AU.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Info-AU.plist"; path = "Info-AU.plist"; sourceTree = SOURCE_ROOT; }; + E7656FD65D0D145C3C20CF7D /* BinaryData.cpp */ /* BinaryData.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = BinaryData.cpp; path = ../../JuceLibraryCode/BinaryData.cpp; sourceTree = SOURCE_ROOT; }; + E9E983AE01932CE7AABF122A /* StubbedToePreset.xml */ /* StubbedToePreset.xml */ = {isa = PBXFileReference; lastKnownFileType = file.xml; name = StubbedToePreset.xml; path = ../../Assets/StubbedToePreset.xml; sourceTree = SOURCE_ROOT; }; + EB5F70D3AED2FCD441751394 /* TemperLookAndFeel.h */ /* TemperLookAndFeel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TemperLookAndFeel.h; path = ../../Source/TemperLookAndFeel.h; sourceTree = SOURCE_ROOT; }; + ED786270C053227B54793072 /* Info-Standalone_Plugin.plist */ /* Info-Standalone_Plugin.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Info-Standalone_Plugin.plist"; path = "Info-Standalone_Plugin.plist"; sourceTree = SOURCE_ROOT; }; + F038472164BBF13DB46AE980 /* DiscRecording.framework */ /* DiscRecording.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DiscRecording.framework; path = System/Library/Frameworks/DiscRecording.framework; sourceTree = SDKROOT; }; + F0E83AB8627EEB12A5F354C9 /* FaustUIBridge.h */ /* FaustUIBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FaustUIBridge.h; path = ../../Source/FaustUIBridge.h; sourceTree = SOURCE_ROOT; }; + F18B8A5D50E29FDAEF2E5581 /* AppConfig.h */ /* AppConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AppConfig.h; path = ../../JuceLibraryCode/AppConfig.h; sourceTree = SOURCE_ROOT; }; + F4E576760B96BFC53ADE07E8 /* juce_gui_extra */ /* juce_gui_extra */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_gui_extra; path = ../../JuceLibraryCode/modules/juce_gui_extra; sourceTree = SOURCE_ROOT; }; + FB2A68BF92DB5683C7EA4255 /* include_juce_video.mm */ /* include_juce_video.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_video.mm; path = ../../JuceLibraryCode/include_juce_video.mm; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E3200D6DA0BBFD4B9F1E6CA = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + BF91BC76FFFCCFD8A5A3DB90, + 79FECC7AD35E7CD7C30569E3, + 61AD7A33F376FB4318E4F7AF, + B19EF2739AFA3DDA44EA7526, + C3B45D6C33FC8D2DFFAFD911, + 08B71F44034B3235DC256506, + 26DDC2E8A87CED2C233559FF, + 5B7726FEB45B778ABED69629, + 02843AA0A5FDADC7EEAC6BEE, + 1CDB95CBF8A78E121703AABD, + 3C0CF21B9D661657A7DBB61D, + 5AA57ADA8E950DE1913F8074, + C7C2EA44D4C9727417B79D74, + 2CD8DDC837D8042EBD00FAAC, + DE69B418D3E6B6893977CDC1, + CFE6846487945890AEFA253B, + F683B8ED17E7E74361810BC1, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8A0947884E4255028FEBC1BF = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 79FECC7AD35E7CD7C30569E3, + 61AD7A33F376FB4318E4F7AF, + B19EF2739AFA3DDA44EA7526, + C3B45D6C33FC8D2DFFAFD911, + 08B71F44034B3235DC256506, + 26DDC2E8A87CED2C233559FF, + 5B7726FEB45B778ABED69629, + 02843AA0A5FDADC7EEAC6BEE, + 1CDB95CBF8A78E121703AABD, + 3C0CF21B9D661657A7DBB61D, + 5AA57ADA8E950DE1913F8074, + C7C2EA44D4C9727417B79D74, + 2CD8DDC837D8042EBD00FAAC, + DE69B418D3E6B6893977CDC1, + CFE6846487945890AEFA253B, + F683B8ED17E7E74361810BC1, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D534DBA3B54AC47DC17473BB = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 79FECC7AD35E7CD7C30569E3, + 61AD7A33F376FB4318E4F7AF, + B19EF2739AFA3DDA44EA7526, + C3B45D6C33FC8D2DFFAFD911, + 08B71F44034B3235DC256506, + 26DDC2E8A87CED2C233559FF, + 5B7726FEB45B778ABED69629, + 02843AA0A5FDADC7EEAC6BEE, + 1CDB95CBF8A78E121703AABD, + 3C0CF21B9D661657A7DBB61D, + 5AA57ADA8E950DE1913F8074, + C7C2EA44D4C9727417B79D74, + 2CD8DDC837D8042EBD00FAAC, + DE69B418D3E6B6893977CDC1, + CFE6846487945890AEFA253B, + F683B8ED17E7E74361810BC1, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E4030EA573A5E9CC6D454AD5 = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 79FECC7AD35E7CD7C30569E3, + 61AD7A33F376FB4318E4F7AF, + B19EF2739AFA3DDA44EA7526, + C3B45D6C33FC8D2DFFAFD911, + 08B71F44034B3235DC256506, + 26DDC2E8A87CED2C233559FF, + 5B7726FEB45B778ABED69629, + 02843AA0A5FDADC7EEAC6BEE, + 1CDB95CBF8A78E121703AABD, + 3C0CF21B9D661657A7DBB61D, + 5AA57ADA8E950DE1913F8074, + C7C2EA44D4C9727417B79D74, + 2CD8DDC837D8042EBD00FAAC, + DE69B418D3E6B6893977CDC1, + CFE6846487945890AEFA253B, + F683B8ED17E7E74361810BC1, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0783BBC300C13B7B7471518C /* Assets */ = { + isa = PBXGroup; + children = ( + 73E7C5339E54B3E9C178B88A, + DEDC7CAC683D9B79D66AC5BC, + 06368B2E4634AEF03549D2A7, + 68478345A384B80536B12B21, + BED083CDF59E8F98DFACA442, + 12E2E64B4BA3D4D3F7FDD5C7, + 06F1639F9ACD9530D7553818, + E9E983AE01932CE7AABF122A, + ); + name = Assets; + sourceTree = ""; + }; + 16B7A8795DC462581C0D3409 /* Source */ = { + isa = PBXGroup; + children = ( + 78D8756494305AA83D310EA9, + FC58AB75B20CF5AE97BA51D3, + 7F3BE1629581C7BA6B7F806F, + 7B6C20AA19B30308B7071BB6, + 4EB0C2E5B91B060521668B43, + D70C3C34C34A0174F5CCAECB, + ); + name = Source; + sourceTree = ""; + }; + 4EB0C2E5B91B060521668B43 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 6D2D628981FCF64C310B884E, + 984DC7C1FFB0CC7F4AE7C47F, + C65386B81096933FA9436F33, + C33B7FFCC2442377C56E393D, + 0A8426AE91646F9776A6C30E, + 43C47DA992C4DBF75FF9D24B, + 0479B2108EC3D3086C664EF5, + 0DB16E6AED0AC5A84706C552, + 7D2F3F0955AD000B1DD805E0, + 56F1E6FB20F3E088CBFB1377, + 7CE94819A159EB97C4EB7CB0, + F038472164BBF13DB46AE980, + D203737AE0E9D572DA5C83BD, + 3B0C1CD3678A6F387D9FA74A, + 50AF3FA7DCE765C398861AA7, + 946060CD40B148EF6582DC18, + E46DA1382F4DD483C8752E50, + ); + name = Frameworks; + sourceTree = ""; + }; + 5239F8DD8842949279B144DD /* Source */ = { + isa = PBXGroup; + children = ( + 67BAE8E7B8157752734DFC9F, + 88AE69AE0F81E844A525CC9A, + 427C295AC9AA6CB38233C5B0, + AF7A7862770F586EB8CF8E8C, + 468E08BC5AA0C3D8D1C9F410, + EB5F70D3AED2FCD441751394, + A8ED8DC046DDC1B796F6203C, + 655E5FC18EFF266ED39F59A0, + 0DF7613DEBCCF4E1B2EDC4A8, + F0E83AB8627EEB12A5F354C9, + 5D9FB702C8DE497F23332C5A, + 51A99C88D24F6FA6EB420D8C, + DA17DD1163220461EDB43F01, + 41F4ED3215862F7062B2B713, + 38AD97F621B0472920539505, + ); + name = Source; + sourceTree = ""; + }; + 78D8756494305AA83D310EA9 /* Temper */ = { + isa = PBXGroup; + children = ( + 0783BBC300C13B7B7471518C, + 5239F8DD8842949279B144DD, + ); + name = Temper; + sourceTree = ""; + }; + 7B6C20AA19B30308B7071BB6 /* Resources */ = { + isa = PBXGroup; + children = ( + 1B6CAB86422500A32B9A2268, + 16ABFACFA41328E1822C64FC, + E4D7E302FD79D8288EDC02DF, + ED786270C053227B54793072, + 4257FBF05F2E14AA226A1659, + ); + name = Resources; + sourceTree = ""; + }; + 7F3BE1629581C7BA6B7F806F /* JUCE Library Code */ = { + isa = PBXGroup; + children = ( + F18B8A5D50E29FDAEF2E5581, + E7656FD65D0D145C3C20CF7D, + 4B8BCF2F0AEF77E1734081AE, + 7A4D78B059F3D62B97671462, + 28457B87BE9A7E186933D826, + 71AA66A84B31985D165C57FE, + A95AA746A1E8C497E09449B6, + 8AB4F0CE47D006D5C910503B, + 219AB01EF105570D181D3987, + BF41B9FD27A763715E7A3E73, + BFAAC07638C61F5B0F3E0C09, + C4753B9659A6D64B908A54C9, + 15DE670E1E07882F1D0F3310, + 1BEC912E78E170204E96C754, + 49E01B9883E491C0375E0D98, + DD06BAFD7F940C41E23CF89A, + 9B28F0E03AEBA79649A0DB4C, + 2DEA38455C24F477A432448A, + BDA0CC6C16D3F2E9A387D7AB, + 1CE564D2DE96733ADF54A601, + C338756E3C93438896949FB9, + 94F53D7F00CBDBAF99D78072, + 2D8348666CEF4F114F75186D, + 08FBE4E80406DFC06A801885, + 75A9FD8847C6F1C0FB785025, + FB2A68BF92DB5683C7EA4255, + DA229717FA82D3728EE12635, + 9177203C336BA8019CF98FFD, + ); + name = "JUCE Library Code"; + sourceTree = ""; + }; + D70C3C34C34A0174F5CCAECB /* Products */ = { + isa = PBXGroup; + children = ( + 329DB2BBEB45BD6A9C25C06E, + DE34C9EED8B65542DF1F7EA5, + D382B2EFF926D55A5494CF1D, + CE24234A805A548104752B18, + 51985E139AA96A0DF9BDD53F, + ); + name = Products; + sourceTree = ""; + }; + FC58AB75B20CF5AE97BA51D3 /* JUCE Modules */ = { + isa = PBXGroup; + children = ( + 253002B26ADB2119AD3ECFCC, + 096DEFCE628676E9EDC08240, + E15F6B7B3DBDF9B9DA0014F2, + 5916961A8219D0B65503FCC1, + B855EA5B24A1278D206CDC63, + 77A91BB0FF221C1C2DA56F78, + 3C2BE373BB1BAB3D5D38E8B6, + 45005A864595D15B0C0A0A06, + 0CD23932791610E5366E2581, + 6BC0FF159358D5B4A032A59E, + 84C933187392AB5213F68E7D, + 82F2F6F25EBB1289086EEDAE, + 85D5F537A586A7233EA46537, + F4E576760B96BFC53ADE07E8, + 3D60425B91F9969B127BDB48, + B90EE98DE447E998BF9AC67B, + ); + name = "JUCE Modules"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 78A0F1CBC813E0CDBA206E64 /* Temper - AU */ = { + isa = PBXNativeTarget; + buildConfigurationList = BC3EFCFB70AFB99B7FF7EDF3; + buildPhases = ( + 1DFB37F4AC1199CB4B36BD8C, + AA87E9A6A56329DA6FD6236F, + AA9C33298E6831FD8EDE97AA, + 5E3200D6DA0BBFD4B9F1E6CA, + ); + buildRules = ( + ); + dependencies = ( + C7B66673E40FE444739187BF, + ); + name = "Temper - AU"; + productName = Temper; + productReference = D382B2EFF926D55A5494CF1D; + productType = "com.apple.product-type.bundle"; + }; + B4FFFFFD24A70BAECA79D226 /* Temper - Standalone Plugin */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1E432B7236708FF6C39EE7B3; + buildPhases = ( + F8A8036273438FF53B74788C, + 99326F02268010B1AB8B4EE8, + D534DBA3B54AC47DC17473BB, + ); + buildRules = ( + ); + dependencies = ( + 224D00E1C3708000B0AD3C4D, + ); + name = "Temper - Standalone Plugin"; + productName = Temper; + productReference = CE24234A805A548104752B18; + productType = "com.apple.product-type.application"; + }; + B7EF72187EFCA6F380E6881C /* Temper - Shared Code */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4BD7DC1DB3BF44FD80C19DF7; + buildPhases = ( + 7E7EA50BF37C2E45F7FED2C2, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Temper - Shared Code"; + productName = Temper; + productReference = 51985E139AA96A0DF9BDD53F; + productType = "com.apple.product-type.library.static"; + }; + C4D91950F59C6AC78BBE99D9 /* Temper - VST3 */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5AF127382B498C3B12F47803; + buildPhases = ( + 2396A6A5A1A0F028BA9634FA, + 6CD0340BC5ECC5349164024F, + E4030EA573A5E9CC6D454AD5, + ); + buildRules = ( + ); + dependencies = ( + 6B5436F7F831A4486B024595, + ); + name = "Temper - VST3"; + productName = Temper; + productReference = DE34C9EED8B65542DF1F7EA5; + productType = "com.apple.product-type.bundle"; + }; + EFB06C11706FA2BED72C0177 /* Temper - VST */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2B4B8962A4E44E38B04ED195; + buildPhases = ( + 433E22463C7FB20A34E42C96, + C7DBA2ED2AAB16409521B539, + 8A0947884E4255028FEBC1BF, + ); + buildRules = ( + ); + dependencies = ( + 71275140D7F49315243D90A9, + ); + name = "Temper - VST"; + productName = Temper; + productReference = 329DB2BBEB45BD6A9C25C06E; + productType = "com.apple.product-type.bundle"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 161A016FC5B702D86E73B434 = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1320; + ORGANIZATIONNAME = "Creative Intent"; + TargetAttributes = { + 2BEC471FAEF6D07D8826CB28 = { + SystemCapabilities = { + com.apple.ApplicationGroups.iOS = { + enabled = 0; + }; + com.apple.HardenedRuntime = { + enabled = 0; + }; + com.apple.InAppPurchase = { + enabled = 0; + }; + com.apple.InterAppAudio = { + enabled = 0; + }; + com.apple.Push = { + enabled = 0; + }; + com.apple.Sandbox = { + enabled = 0; + }; + }; + }; + 78A0F1CBC813E0CDBA206E64 = { + SystemCapabilities = { + com.apple.ApplicationGroups.iOS = { + enabled = 0; + }; + com.apple.HardenedRuntime = { + enabled = 0; + }; + com.apple.InAppPurchase = { + enabled = 0; + }; + com.apple.InterAppAudio = { + enabled = 0; + }; + com.apple.Push = { + enabled = 0; + }; + com.apple.Sandbox = { + enabled = 0; + }; + }; + }; + B4FFFFFD24A70BAECA79D226 = { + SystemCapabilities = { + com.apple.ApplicationGroups.iOS = { + enabled = 0; + }; + com.apple.HardenedRuntime = { + enabled = 0; + }; + com.apple.InAppPurchase = { + enabled = 0; + }; + com.apple.InterAppAudio = { + enabled = 0; + }; + com.apple.Push = { + enabled = 0; + }; + com.apple.Sandbox = { + enabled = 0; + }; + }; + }; + B7EF72187EFCA6F380E6881C = { + SystemCapabilities = { + com.apple.ApplicationGroups.iOS = { + enabled = 0; + }; + com.apple.HardenedRuntime = { + enabled = 0; + }; + com.apple.InAppPurchase = { + enabled = 0; + }; + com.apple.InterAppAudio = { + enabled = 0; + }; + com.apple.Push = { + enabled = 0; + }; + com.apple.Sandbox = { + enabled = 0; + }; + }; + }; + C4D91950F59C6AC78BBE99D9 = { + SystemCapabilities = { + com.apple.ApplicationGroups.iOS = { + enabled = 0; + }; + com.apple.HardenedRuntime = { + enabled = 0; + }; + com.apple.InAppPurchase = { + enabled = 0; + }; + com.apple.InterAppAudio = { + enabled = 0; + }; + com.apple.Push = { + enabled = 0; + }; + com.apple.Sandbox = { + enabled = 0; + }; + }; + }; + EFB06C11706FA2BED72C0177 = { + SystemCapabilities = { + com.apple.ApplicationGroups.iOS = { + enabled = 0; + }; + com.apple.HardenedRuntime = { + enabled = 0; + }; + com.apple.InAppPurchase = { + enabled = 0; + }; + com.apple.InterAppAudio = { + enabled = 0; + }; + com.apple.Push = { + enabled = 0; + }; + com.apple.Sandbox = { + enabled = 0; + }; + }; + }; + }; + }; + buildConfigurationList = E3D10272E9BD334B9AC87536; + compatibilityVersion = "Xcode 3.2"; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 16B7A8795DC462581C0D3409; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 2BEC471FAEF6D07D8826CB28, + EFB06C11706FA2BED72C0177, + C4D91950F59C6AC78BBE99D9, + 78A0F1CBC813E0CDBA206E64, + B4FFFFFD24A70BAECA79D226, + B7EF72187EFCA6F380E6881C, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 1DFB37F4AC1199CB4B36BD8C = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D9997560B40DD7D50FA3E9A0, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2396A6A5A1A0F028BA9634FA = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D9997560B40DD7D50FA3E9A0, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 433E22463C7FB20A34E42C96 = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D9997560B40DD7D50FA3E9A0, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F8A8036273438FF53B74788C = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D9997560B40DD7D50FA3E9A0, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXRezBuildPhase section */ + AA87E9A6A56329DA6FD6236F = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + 0B753ED8F52C2C248C53F0AB, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXRezBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 6CD0340BC5ECC5349164024F = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 10066F8FBF6EC9E37E0DE1AD, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7E7EA50BF37C2E45F7FED2C2 = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B6142B2DF81E50A0E4E76F52, + 0988CF5ED15E82CC78B53137, + 7895E7D833D1029782229EBF, + 7D138E4AA28C1C976EA1D186, + 5996B7821900A1790016AADE, + 1E62DE5EE4512FECE82E2E09, + 46761BF0558068478B8ABEC2, + CB115CA1ED358F980E1CBE6F, + 9C5A0DCFFD53650C343E142F, + 9E6E52EFC3B57F61D701EC19, + 274D467D0A8753F7EDBD04DF, + 9494E786CFDC756E9821102A, + 3A43512BD12733D784697343, + FBFDB86DECA46E503320CAEE, + B99E04E3BBE9E0D0DB1797C7, + 8689BCA55706DB2AF975F6BE, + 7020F5FC4892253AEDC4B6C1, + FEC45F5FAA0B8F0B2EB4D62C, + 6348ED75152CC9DCD4327937, + 631BBF5C0B44B9CAF4248FAD, + 2F31CF09BE378AD7ED861925, + C4199DF380BE36A4BB61C542, + F26E07F79FD441C416B3E98E, + 37FC7CDE7C515B3ABEFCBF20, + E7FA2C8749C360EBAC0C497E, + AFB47B9448D55B25E1D20E8F, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 99326F02268010B1AB8B4EE8 = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8FD7DF91F80816C75804E626, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + AA9C33298E6831FD8EDE97AA = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DAB193581FCC69B9691223B5, + 5D22FDD5F55141A80CE432EC, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C7DBA2ED2AAB16409521B539 = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E8CDF6E5A8E80EB92013DBFE, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 224D00E1C3708000B0AD3C4D = { + isa = PBXTargetDependency; + target = B7EF72187EFCA6F380E6881C; + }; + 573E0BBB6A953C208DF6AF13 = { + isa = PBXTargetDependency; + target = EFB06C11706FA2BED72C0177; + }; + 67479A2F14D73BB854CE20CD = { + isa = PBXTargetDependency; + target = B4FFFFFD24A70BAECA79D226; + }; + 6B5436F7F831A4486B024595 = { + isa = PBXTargetDependency; + target = B7EF72187EFCA6F380E6881C; + }; + 71275140D7F49315243D90A9 = { + isa = PBXTargetDependency; + target = B7EF72187EFCA6F380E6881C; + }; + 77215A3EEEC42A17A98F1946 = { + isa = PBXTargetDependency; + target = B7EF72187EFCA6F380E6881C; + }; + A2FCC569F3B99DB3BC84295D = { + isa = PBXTargetDependency; + target = C4D91950F59C6AC78BBE99D9; + }; + C7B66673E40FE444739187BF = { + isa = PBXTargetDependency; + target = B7EF72187EFCA6F380E6881C; + }; + EAD29230987F2FC5BD2AEBCB = { + isa = PBXTargetDependency; + target = 78A0F1CBC813E0CDBA206E64; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 037777277548B3E4413ECEF1 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; CLANG_LINK_OBJC_RUNTIME = NO; + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; COPY_PHASE_STRIP = NO; DEPLOYMENT_LOCATION = YES; DSTROOT = /; + EXCLUDED_ARCHS = ""; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -292,76 +879,114 @@ "JucePlugin_Build_AUv3=0", "JucePlugin_Build_RTAS=0", "JucePlugin_Build_AAX=0", - "JucePlugin_Build_Standalone=0", ); + "JucePlugin_Build_Standalone=0", + "JucePlugin_Build_Unity=0", + ); GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GENERATE_PKGINFO_FILE = YES; - HEADER_SEARCH_PATHS = ("../../VST3_SDK", "../../JuceLibraryCode", "../../JuceLibraryCode/modules", "../../Include", "../../JuceLibraryCode/modules/juce_audio_plugin_client", "$(inherited)"); + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK", + "$(SRCROOT)/../../JuceLibraryCode", + "$(SRCROOT)/../../JuceLibraryCode/modules", + "$(SRCROOT)/../../Include", + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client", + "$(inherited)", + ); INFOPLIST_FILE = Info-VST.plist; INFOPLIST_PREPROCESS = NO; INSTALL_PATH = "$(BUILD_DIR)/$(CONFIGURATION)"; LIBRARY_STYLE = Bundle; MACOSX_DEPLOYMENT_TARGET = 10.9; - MACOSX_DEPLOYMENT_TARGET_ppc = 10.4; + MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../JuceLibraryCode/modules $(SRCROOT)/../../Include $(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client"; OTHER_LDFLAGS = "-bundle -lTemper"; PRODUCT_BUNDLE_IDENTIFIER = com.creativeintent.temper; - SDKROOT_ppc = macosx10.5; + PRODUCT_NAME = "Temper"; USE_HEADERMAP = NO; - WRAPPER_EXTENSION = vst; }; name = Debug; }; - 149F966C3EF21DFC25242E76 = {isa = XCBuildConfiguration; buildSettings = { + VALIDATE_WORKSPACE_SKIPPED_SDK_FRAMEWORKS = OpenGL; + VALID_ARCHS = "i386 x86_64 arm64 arm64e"; + WRAPPER_EXTENSION = vst; + }; + name = Debug; + }; + 0653AFD32E461E60585D3F41 /* Demo */ = { + isa = XCBuildConfiguration; + buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "c++14"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; CLANG_LINK_OBJC_RUNTIME = NO; + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; DEAD_CODE_STRIPPING = YES; DEPLOYMENT_LOCATION = YES; DSTROOT = /; + EXCLUDED_ARCHS = ""; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = ( "_NDEBUG=1", "NDEBUG=1", + "TEMPER_DEMO_BUILD=1", "JUCER_XCODE_MAC_F6D2F4CF=1", "JUCE_APP_VERSION=1.0.3", "JUCE_APP_VERSION_HEX=0x10003", - "JucePlugin_Build_VST=1", + "JucePlugin_Build_VST=0", "JucePlugin_Build_VST3=0", - "JucePlugin_Build_AU=0", + "JucePlugin_Build_AU=1", "JucePlugin_Build_AUv3=0", "JucePlugin_Build_RTAS=0", "JucePlugin_Build_AAX=0", - "JucePlugin_Build_Standalone=0", ); - GCC_SYMBOLS_PRIVATE_EXTERN = YES; + "JucePlugin_Build_Standalone=0", + "JucePlugin_Build_Unity=0", + ); GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GENERATE_PKGINFO_FILE = YES; - HEADER_SEARCH_PATHS = ("../../VST3_SDK", "../../JuceLibraryCode", "../../JuceLibraryCode/modules", "../../Include", "../../JuceLibraryCode/modules/juce_audio_plugin_client", "$(inherited)"); - INFOPLIST_FILE = Info-VST.plist; + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK", + "$(SRCROOT)/../../JuceLibraryCode", + "$(SRCROOT)/../../JuceLibraryCode/modules", + "$(SRCROOT)/../../Include", + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client", + "$(inherited)", + ); + INFOPLIST_FILE = Info-AU.plist; INFOPLIST_PREPROCESS = NO; INSTALL_PATH = "$(BUILD_DIR)/$(CONFIGURATION)"; LIBRARY_STYLE = Bundle; LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 10.9; - MACOSX_DEPLOYMENT_TARGET_ppc = 10.4; - OTHER_LDFLAGS = "-bundle -lTemper"; + MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../JuceLibraryCode/modules $(SRCROOT)/../../Include $(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client"; + OTHER_LDFLAGS = "-bundle -lTemper\\ (Demo)"; + OTHER_REZFLAGS = "-d ppc_$ppc -d i386_$i386 -d ppc64_$ppc64 -d x86_64_$x86_64 -d arm64_$arm64 -I /System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Versions/A/Headers -I \"$(DEVELOPER_DIR)/Extras/CoreAudio/AudioUnits/AUPublic/AUBase\" -I \"$(DEVELOPER_DIR)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/AudioUnit.framework/Headers\""; PRODUCT_BUNDLE_IDENTIFIER = com.creativeintent.temper; - SDKROOT_ppc = macosx10.5; + PRODUCT_NAME = "Temper (Demo)"; USE_HEADERMAP = NO; - WRAPPER_EXTENSION = vst; }; name = Release; }; - 34EC70CEAF046ADDCB554E68 = {isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "c++14"; + VALIDATE_WORKSPACE_SKIPPED_SDK_FRAMEWORKS = OpenGL; + VALID_ARCHS = "i386 x86_64 arm64 arm64e"; + WRAPPER_EXTENSION = component; + }; + name = Demo; + }; + 149F966C3EF21DFC25242E76 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; CLANG_LINK_OBJC_RUNTIME = NO; + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; DEAD_CODE_STRIPPING = YES; DEPLOYMENT_LOCATION = YES; DSTROOT = /; + EXCLUDED_ARCHS = ""; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = ( "_NDEBUG=1", "NDEBUG=1", - "TEMPER_DEMO_BUILD=1", "JUCER_XCODE_MAC_F6D2F4CF=1", "JUCE_APP_VERSION=1.0.3", "JUCE_APP_VERSION_HEX=0x10003", @@ -371,110 +996,109 @@ "JucePlugin_Build_AUv3=0", "JucePlugin_Build_RTAS=0", "JucePlugin_Build_AAX=0", - "JucePlugin_Build_Standalone=0", ); - GCC_SYMBOLS_PRIVATE_EXTERN = YES; + "JucePlugin_Build_Standalone=0", + "JucePlugin_Build_Unity=0", + ); GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GENERATE_PKGINFO_FILE = YES; - HEADER_SEARCH_PATHS = ("../../VST3_SDK", "../../JuceLibraryCode", "../../JuceLibraryCode/modules", "../../Include", "../../JuceLibraryCode/modules/juce_audio_plugin_client", "$(inherited)"); + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK", + "$(SRCROOT)/../../JuceLibraryCode", + "$(SRCROOT)/../../JuceLibraryCode/modules", + "$(SRCROOT)/../../Include", + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client", + "$(inherited)", + ); INFOPLIST_FILE = Info-VST.plist; INFOPLIST_PREPROCESS = NO; INSTALL_PATH = "$(BUILD_DIR)/$(CONFIGURATION)"; LIBRARY_STYLE = Bundle; LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 10.9; - MACOSX_DEPLOYMENT_TARGET_ppc = 10.4; - OTHER_LDFLAGS = "-bundle -lTemper\\ (Demo)"; - PRODUCT_BUNDLE_IDENTIFIER = com.creativeintent.temper; - SDKROOT_ppc = macosx10.5; - USE_HEADERMAP = NO; - WRAPPER_EXTENSION = vst; }; name = Demo; }; - BB20A7A862DDF30947CA24ED = {isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "c++14"; - CLANG_LINK_OBJC_RUNTIME = NO; - COMBINE_HIDPI_IMAGES = YES; - CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; - COPY_PHASE_STRIP = NO; - DEPLOYMENT_LOCATION = YES; - DSTROOT = /; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "_DEBUG=1", - "DEBUG=1", - "JUCER_XCODE_MAC_F6D2F4CF=1", - "JUCE_APP_VERSION=1.0.3", - "JUCE_APP_VERSION_HEX=0x10003", - "JucePlugin_Build_VST=0", - "JucePlugin_Build_VST3=1", - "JucePlugin_Build_AU=0", - "JucePlugin_Build_AUv3=0", - "JucePlugin_Build_RTAS=0", - "JucePlugin_Build_AAX=0", - "JucePlugin_Build_Standalone=0", ); - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - GENERATE_PKGINFO_FILE = YES; - HEADER_SEARCH_PATHS = ("../../VST3_SDK", "../../JuceLibraryCode", "../../JuceLibraryCode/modules", "../../Include", "../../JuceLibraryCode/modules/juce_audio_plugin_client", "$(inherited)"); - INFOPLIST_FILE = Info-VST3.plist; - INFOPLIST_PREPROCESS = NO; - INSTALL_PATH = "$(BUILD_DIR)/$(CONFIGURATION)"; - LIBRARY_STYLE = Bundle; - MACOSX_DEPLOYMENT_TARGET = 10.9; - MACOSX_DEPLOYMENT_TARGET_ppc = 10.4; + MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../JuceLibraryCode/modules $(SRCROOT)/../../Include $(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client"; OTHER_LDFLAGS = "-bundle -lTemper"; PRODUCT_BUNDLE_IDENTIFIER = com.creativeintent.temper; - SDKROOT_ppc = macosx10.5; + PRODUCT_NAME = "Temper"; USE_HEADERMAP = NO; - WRAPPER_EXTENSION = vst3; }; name = Debug; }; - 552BE47D98F05E7E2A1BE1E5 = {isa = XCBuildConfiguration; buildSettings = { + VALIDATE_WORKSPACE_SKIPPED_SDK_FRAMEWORKS = OpenGL; + VALID_ARCHS = "i386 x86_64 arm64 arm64e"; + WRAPPER_EXTENSION = vst; + }; + name = Release; + }; + 34EC70CEAF046ADDCB554E68 /* Demo */ = { + isa = XCBuildConfiguration; + buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "c++14"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; CLANG_LINK_OBJC_RUNTIME = NO; + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; DEAD_CODE_STRIPPING = YES; DEPLOYMENT_LOCATION = YES; DSTROOT = /; + EXCLUDED_ARCHS = ""; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = ( "_NDEBUG=1", "NDEBUG=1", + "TEMPER_DEMO_BUILD=1", "JUCER_XCODE_MAC_F6D2F4CF=1", "JUCE_APP_VERSION=1.0.3", "JUCE_APP_VERSION_HEX=0x10003", - "JucePlugin_Build_VST=0", - "JucePlugin_Build_VST3=1", + "JucePlugin_Build_VST=1", + "JucePlugin_Build_VST3=0", "JucePlugin_Build_AU=0", "JucePlugin_Build_AUv3=0", "JucePlugin_Build_RTAS=0", "JucePlugin_Build_AAX=0", - "JucePlugin_Build_Standalone=0", ); - GCC_SYMBOLS_PRIVATE_EXTERN = YES; + "JucePlugin_Build_Standalone=0", + "JucePlugin_Build_Unity=0", + ); GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GENERATE_PKGINFO_FILE = YES; - HEADER_SEARCH_PATHS = ("../../VST3_SDK", "../../JuceLibraryCode", "../../JuceLibraryCode/modules", "../../Include", "../../JuceLibraryCode/modules/juce_audio_plugin_client", "$(inherited)"); - INFOPLIST_FILE = Info-VST3.plist; + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK", + "$(SRCROOT)/../../JuceLibraryCode", + "$(SRCROOT)/../../JuceLibraryCode/modules", + "$(SRCROOT)/../../Include", + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client", + "$(inherited)", + ); + INFOPLIST_FILE = Info-VST.plist; INFOPLIST_PREPROCESS = NO; INSTALL_PATH = "$(BUILD_DIR)/$(CONFIGURATION)"; LIBRARY_STYLE = Bundle; LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 10.9; - MACOSX_DEPLOYMENT_TARGET_ppc = 10.4; - OTHER_LDFLAGS = "-bundle -lTemper"; + MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../JuceLibraryCode/modules $(SRCROOT)/../../Include $(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client"; + OTHER_LDFLAGS = "-bundle -lTemper\\ (Demo)"; PRODUCT_BUNDLE_IDENTIFIER = com.creativeintent.temper; - SDKROOT_ppc = macosx10.5; + PRODUCT_NAME = "Temper (Demo)"; USE_HEADERMAP = NO; - WRAPPER_EXTENSION = vst3; }; name = Release; }; - 48C2A0C89EB5B272FB1A3BE4 = {isa = XCBuildConfiguration; buildSettings = { + VALIDATE_WORKSPACE_SKIPPED_SDK_FRAMEWORKS = OpenGL; + VALID_ARCHS = "i386 x86_64 arm64 arm64e"; + WRAPPER_EXTENSION = vst; + }; + name = Demo; + }; + 48C2A0C89EB5B272FB1A3BE4 /* Demo */ = { + isa = XCBuildConfiguration; + buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "c++14"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; CLANG_LINK_OBJC_RUNTIME = NO; + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; DEAD_CODE_STRIPPING = YES; DEPLOYMENT_LOCATION = YES; DSTROOT = /; + EXCLUDED_ARCHS = ""; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -490,32 +1114,98 @@ "JucePlugin_Build_AUv3=0", "JucePlugin_Build_RTAS=0", "JucePlugin_Build_AAX=0", - "JucePlugin_Build_Standalone=0", ); - GCC_SYMBOLS_PRIVATE_EXTERN = YES; + "JucePlugin_Build_Standalone=0", + "JucePlugin_Build_Unity=0", + ); GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GENERATE_PKGINFO_FILE = YES; - HEADER_SEARCH_PATHS = ("../../VST3_SDK", "../../JuceLibraryCode", "../../JuceLibraryCode/modules", "../../Include", "../../JuceLibraryCode/modules/juce_audio_plugin_client", "$(inherited)"); + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK", + "$(SRCROOT)/../../JuceLibraryCode", + "$(SRCROOT)/../../JuceLibraryCode/modules", + "$(SRCROOT)/../../Include", + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client", + "$(inherited)", + ); INFOPLIST_FILE = Info-VST3.plist; INFOPLIST_PREPROCESS = NO; INSTALL_PATH = "$(BUILD_DIR)/$(CONFIGURATION)"; LIBRARY_STYLE = Bundle; LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 10.9; - MACOSX_DEPLOYMENT_TARGET_ppc = 10.4; + MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../JuceLibraryCode/modules $(SRCROOT)/../../Include $(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client"; OTHER_LDFLAGS = "-bundle -lTemper\\ (Demo)"; PRODUCT_BUNDLE_IDENTIFIER = com.creativeintent.temper; - SDKROOT_ppc = macosx10.5; + PRODUCT_NAME = "Temper (Demo)"; USE_HEADERMAP = NO; - WRAPPER_EXTENSION = vst3; }; name = Demo; }; - 51D636E6D50164DCD40BB553 = {isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "c++14"; + VALIDATE_WORKSPACE_SKIPPED_SDK_FRAMEWORKS = OpenGL; + VALID_ARCHS = "i386 x86_64 arm64 arm64e"; + WRAPPER_EXTENSION = vst3; + }; + name = Demo; + }; + 51B52684D34AD98BE008AE8C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = ""; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = NO; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_INLINES_ARE_PRIVATE_EXTERN = YES; + GCC_MODEL_TUNING = G5; + GCC_NO_COMMON_BLOCKS = YES; + GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; + GCC_WARN_MISSING_PARENTHESES = YES; + GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; + GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PRODUCT_NAME = "Temper"; + SDKROOT = macosx; + WARNING_CFLAGS = "-Wreorder"; + ZERO_LINK = NO; + }; + name = Release; + }; + 51D636E6D50164DCD40BB553 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; CLANG_LINK_OBJC_RUNTIME = NO; + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; COPY_PHASE_STRIP = NO; DEPLOYMENT_LOCATION = YES; DSTROOT = /; + EXCLUDED_ARCHS = ""; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -530,31 +1220,50 @@ "JucePlugin_Build_AUv3=0", "JucePlugin_Build_RTAS=0", "JucePlugin_Build_AAX=0", - "JucePlugin_Build_Standalone=0", ); + "JucePlugin_Build_Standalone=0", + "JucePlugin_Build_Unity=0", + ); GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GENERATE_PKGINFO_FILE = YES; - HEADER_SEARCH_PATHS = ("../../VST3_SDK", "../../JuceLibraryCode", "../../JuceLibraryCode/modules", "../../Include", "../../JuceLibraryCode/modules/juce_audio_plugin_client", "$(inherited)"); + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK", + "$(SRCROOT)/../../JuceLibraryCode", + "$(SRCROOT)/../../JuceLibraryCode/modules", + "$(SRCROOT)/../../Include", + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client", + "$(inherited)", + ); INFOPLIST_FILE = Info-AU.plist; INFOPLIST_PREPROCESS = NO; INSTALL_PATH = "$(BUILD_DIR)/$(CONFIGURATION)"; LIBRARY_STYLE = Bundle; MACOSX_DEPLOYMENT_TARGET = 10.9; - MACOSX_DEPLOYMENT_TARGET_ppc = 10.4; + MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../JuceLibraryCode/modules $(SRCROOT)/../../Include $(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client"; OTHER_LDFLAGS = "-bundle -lTemper"; - OTHER_REZFLAGS = "-d ppc_$ppc -d i386_$i386 -d ppc64_$ppc64 -d x86_64_$x86_64 -I /System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Versions/A/Headers -I \"$(DEVELOPER_DIR)/Extras/CoreAudio/AudioUnits/AUPublic/AUBase\""; + OTHER_REZFLAGS = "-d ppc_$ppc -d i386_$i386 -d ppc64_$ppc64 -d x86_64_$x86_64 -d arm64_$arm64 -I /System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Versions/A/Headers -I \"$(DEVELOPER_DIR)/Extras/CoreAudio/AudioUnits/AUPublic/AUBase\" -I \"$(DEVELOPER_DIR)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/AudioUnit.framework/Headers\""; PRODUCT_BUNDLE_IDENTIFIER = com.creativeintent.temper; - SDKROOT_ppc = macosx10.5; + PRODUCT_NAME = "Temper"; USE_HEADERMAP = NO; - WRAPPER_EXTENSION = component; }; name = Debug; }; - EE445B6674AB52157101266D = {isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "c++14"; + VALIDATE_WORKSPACE_SKIPPED_SDK_FRAMEWORKS = OpenGL; + VALID_ARCHS = "i386 x86_64 arm64 arm64e"; + WRAPPER_EXTENSION = component; + }; + name = Debug; + }; + 552BE47D98F05E7E2A1BE1E5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; CLANG_LINK_OBJC_RUNTIME = NO; + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; DEAD_CODE_STRIPPING = YES; DEPLOYMENT_LOCATION = YES; DSTROOT = /; + EXCLUDED_ARCHS = ""; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -564,38 +1273,101 @@ "JUCE_APP_VERSION=1.0.3", "JUCE_APP_VERSION_HEX=0x10003", "JucePlugin_Build_VST=0", - "JucePlugin_Build_VST3=0", - "JucePlugin_Build_AU=1", + "JucePlugin_Build_VST3=1", + "JucePlugin_Build_AU=0", "JucePlugin_Build_AUv3=0", "JucePlugin_Build_RTAS=0", "JucePlugin_Build_AAX=0", - "JucePlugin_Build_Standalone=0", ); - GCC_SYMBOLS_PRIVATE_EXTERN = YES; + "JucePlugin_Build_Standalone=0", + "JucePlugin_Build_Unity=0", + ); GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GENERATE_PKGINFO_FILE = YES; - HEADER_SEARCH_PATHS = ("../../VST3_SDK", "../../JuceLibraryCode", "../../JuceLibraryCode/modules", "../../Include", "../../JuceLibraryCode/modules/juce_audio_plugin_client", "$(inherited)"); - INFOPLIST_FILE = Info-AU.plist; + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK", + "$(SRCROOT)/../../JuceLibraryCode", + "$(SRCROOT)/../../JuceLibraryCode/modules", + "$(SRCROOT)/../../Include", + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client", + "$(inherited)", + ); + INFOPLIST_FILE = Info-VST3.plist; INFOPLIST_PREPROCESS = NO; INSTALL_PATH = "$(BUILD_DIR)/$(CONFIGURATION)"; LIBRARY_STYLE = Bundle; LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 10.9; - MACOSX_DEPLOYMENT_TARGET_ppc = 10.4; + MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../JuceLibraryCode/modules $(SRCROOT)/../../Include $(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client"; OTHER_LDFLAGS = "-bundle -lTemper"; - OTHER_REZFLAGS = "-d ppc_$ppc -d i386_$i386 -d ppc64_$ppc64 -d x86_64_$x86_64 -I /System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Versions/A/Headers -I \"$(DEVELOPER_DIR)/Extras/CoreAudio/AudioUnits/AUPublic/AUBase\""; PRODUCT_BUNDLE_IDENTIFIER = com.creativeintent.temper; - SDKROOT_ppc = macosx10.5; + PRODUCT_NAME = "Temper"; USE_HEADERMAP = NO; - WRAPPER_EXTENSION = component; }; name = Release; }; - 0653AFD32E461E60585D3F41 = {isa = XCBuildConfiguration; buildSettings = { + VALIDATE_WORKSPACE_SKIPPED_SDK_FRAMEWORKS = OpenGL; + VALID_ARCHS = "i386 x86_64 arm64 arm64e"; + WRAPPER_EXTENSION = vst3; + }; + name = Release; + }; + 729619C61C81AE021832EB20 /* Demo */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = ""; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = NO; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_INLINES_ARE_PRIVATE_EXTERN = YES; + GCC_MODEL_TUNING = G5; + GCC_NO_COMMON_BLOCKS = YES; + GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; + GCC_WARN_MISSING_PARENTHESES = YES; + GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; + GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PRODUCT_NAME = "Temper (Demo)"; + SDKROOT = macosx; + WARNING_CFLAGS = "-Wreorder"; + ZERO_LINK = NO; + }; + name = Demo; + }; + 7C721E226241FBB4FB038A8E /* Demo */ = { + isa = XCBuildConfiguration; + buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "c++14"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; CLANG_LINK_OBJC_RUNTIME = NO; + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; DEAD_CODE_STRIPPING = YES; - DEPLOYMENT_LOCATION = YES; - DSTROOT = /; + EXCLUDED_ARCHS = ""; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -607,40 +1379,53 @@ "JUCE_APP_VERSION_HEX=0x10003", "JucePlugin_Build_VST=0", "JucePlugin_Build_VST3=0", - "JucePlugin_Build_AU=1", + "JucePlugin_Build_AU=0", "JucePlugin_Build_AUv3=0", "JucePlugin_Build_RTAS=0", "JucePlugin_Build_AAX=0", - "JucePlugin_Build_Standalone=0", ); - GCC_SYMBOLS_PRIVATE_EXTERN = YES; + "JucePlugin_Build_Standalone=1", + "JucePlugin_Build_Unity=0", + ); GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - GENERATE_PKGINFO_FILE = YES; - HEADER_SEARCH_PATHS = ("../../VST3_SDK", "../../JuceLibraryCode", "../../JuceLibraryCode/modules", "../../Include", "../../JuceLibraryCode/modules/juce_audio_plugin_client", "$(inherited)"); - INFOPLIST_FILE = Info-AU.plist; + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK", + "$(SRCROOT)/../../JuceLibraryCode", + "$(SRCROOT)/../../JuceLibraryCode/modules", + "$(SRCROOT)/../../Include", + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client", + "$(inherited)", + ); + INFOPLIST_FILE = Info-Standalone_Plugin.plist; INFOPLIST_PREPROCESS = NO; - INSTALL_PATH = "$(BUILD_DIR)/$(CONFIGURATION)"; - LIBRARY_STYLE = Bundle; LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 10.9; - MACOSX_DEPLOYMENT_TARGET_ppc = 10.4; - OTHER_LDFLAGS = "-bundle -lTemper\\ (Demo)"; - OTHER_REZFLAGS = "-d ppc_$ppc -d i386_$i386 -d ppc64_$ppc64 -d x86_64_$x86_64 -I /System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Versions/A/Headers -I \"$(DEVELOPER_DIR)/Extras/CoreAudio/AudioUnits/AUPublic/AUBase\""; + MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../JuceLibraryCode/modules $(SRCROOT)/../../Include $(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client"; + OTHER_LDFLAGS = "-lTemper\\ (Demo)"; PRODUCT_BUNDLE_IDENTIFIER = com.creativeintent.temper; - SDKROOT_ppc = macosx10.5; + PRODUCT_NAME = "Temper (Demo)"; USE_HEADERMAP = NO; - WRAPPER_EXTENSION = component; }; name = Demo; }; - B3463E7EB0C6F6B8B3CEB9F9 = {isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "c++14"; + VALIDATE_WORKSPACE_SKIPPED_SDK_FRAMEWORKS = OpenGL; + VALID_ARCHS = "i386 x86_64 arm64 arm64e"; + }; + name = Demo; + }; + 8E12410EC2444CFE892522F2 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; CLANG_LINK_OBJC_RUNTIME = NO; + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; - COPY_PHASE_STRIP = NO; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; + DEAD_CODE_STRIPPING = YES; + EXCLUDED_ARCHS = ""; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = ( - "_DEBUG=1", - "DEBUG=1", + "_NDEBUG=1", + "NDEBUG=1", "JUCER_XCODE_MAC_F6D2F4CF=1", "JUCE_APP_VERSION=1.0.3", "JUCE_APP_VERSION_HEX=0x10003", @@ -650,64 +1435,108 @@ "JucePlugin_Build_AUv3=0", "JucePlugin_Build_RTAS=0", "JucePlugin_Build_AAX=0", - "JucePlugin_Build_Standalone=1", ); + "JucePlugin_Build_Standalone=1", + "JucePlugin_Build_Unity=0", + ); GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - HEADER_SEARCH_PATHS = ("../../VST3_SDK", "../../JuceLibraryCode", "../../JuceLibraryCode/modules", "../../Include", "../../JuceLibraryCode/modules/juce_audio_plugin_client", "$(inherited)"); + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK", + "$(SRCROOT)/../../JuceLibraryCode", + "$(SRCROOT)/../../JuceLibraryCode/modules", + "$(SRCROOT)/../../Include", + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client", + "$(inherited)", + ); INFOPLIST_FILE = Info-Standalone_Plugin.plist; INFOPLIST_PREPROCESS = NO; + LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 10.9; - MACOSX_DEPLOYMENT_TARGET_ppc = 10.4; + MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../JuceLibraryCode/modules $(SRCROOT)/../../Include $(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client"; OTHER_LDFLAGS = "-lTemper"; PRODUCT_BUNDLE_IDENTIFIER = com.creativeintent.temper; - SDKROOT_ppc = macosx10.5; - USE_HEADERMAP = NO; }; name = Debug; }; - 8E12410EC2444CFE892522F2 = {isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "c++14"; + PRODUCT_NAME = "Temper"; + USE_HEADERMAP = NO; + VALIDATE_WORKSPACE_SKIPPED_SDK_FRAMEWORKS = OpenGL; + VALID_ARCHS = "i386 x86_64 arm64 arm64e"; + }; + name = Release; + }; + 8F02B3FB70199C61B246690E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; CLANG_LINK_OBJC_RUNTIME = NO; + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; - DEAD_CODE_STRIPPING = YES; - GCC_GENERATE_DEBUGGING_SYMBOLS = NO; - GCC_OPTIMIZATION_LEVEL = 3; + COPY_PHASE_STRIP = NO; + EXCLUDED_ARCHS = ""; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( - "_NDEBUG=1", - "NDEBUG=1", + "_DEBUG=1", + "DEBUG=1", "JUCER_XCODE_MAC_F6D2F4CF=1", "JUCE_APP_VERSION=1.0.3", "JUCE_APP_VERSION_HEX=0x10003", - "JucePlugin_Build_VST=0", - "JucePlugin_Build_VST3=0", - "JucePlugin_Build_AU=0", + "JucePlugin_Build_VST=1", + "JucePlugin_Build_VST3=1", + "JucePlugin_Build_AU=1", "JucePlugin_Build_AUv3=0", "JucePlugin_Build_RTAS=0", "JucePlugin_Build_AAX=0", - "JucePlugin_Build_Standalone=1", ); - GCC_SYMBOLS_PRIVATE_EXTERN = YES; + "JucePlugin_Build_Standalone=1", + "JucePlugin_Build_Unity=0", + "JUCE_SHARED_CODE=1", + ); GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - HEADER_SEARCH_PATHS = ("../../VST3_SDK", "../../JuceLibraryCode", "../../JuceLibraryCode/modules", "../../Include", "../../JuceLibraryCode/modules/juce_audio_plugin_client", "$(inherited)"); - INFOPLIST_FILE = Info-Standalone_Plugin.plist; - INFOPLIST_PREPROCESS = NO; - LLVM_LTO = YES; + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK", + "$(SRCROOT)/../../JuceLibraryCode", + "$(SRCROOT)/../../JuceLibraryCode/modules", + "$(SRCROOT)/../../Include", + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client", + "$(inherited)", + ); + INSTALL_PATH = "@executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.9; - MACOSX_DEPLOYMENT_TARGET_ppc = 10.4; - OTHER_LDFLAGS = "-lTemper"; + MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../JuceLibraryCode/modules $(SRCROOT)/../../Include $(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client"; PRODUCT_BUNDLE_IDENTIFIER = com.creativeintent.temper; - SDKROOT_ppc = macosx10.5; - USE_HEADERMAP = NO; }; name = Release; }; - 7C721E226241FBB4FB038A8E = {isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "c++14"; + PRODUCT_NAME = "Temper"; + SKIP_INSTALL = YES; + USE_HEADERMAP = NO; + VALIDATE_WORKSPACE_SKIPPED_SDK_FRAMEWORKS = OpenGL; + VALID_ARCHS = "i386 x86_64 arm64 arm64e"; + }; + name = Debug; + }; + 992799EC591C91E642CD3D65 /* Demo */ = { + isa = XCBuildConfiguration; + buildSettings = { + MACOSX_DEPLOYMENT_TARGET = 10.9; + SDKROOT = macosx; + }; + name = Demo; + }; + B3463E7EB0C6F6B8B3CEB9F9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; CLANG_LINK_OBJC_RUNTIME = NO; + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; - DEAD_CODE_STRIPPING = YES; - GCC_GENERATE_DEBUGGING_SYMBOLS = NO; - GCC_OPTIMIZATION_LEVEL = 3; + COPY_PHASE_STRIP = NO; + EXCLUDED_ARCHS = ""; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( - "_NDEBUG=1", - "NDEBUG=1", - "TEMPER_DEMO_BUILD=1", + "_DEBUG=1", + "DEBUG=1", "JUCER_XCODE_MAC_F6D2F4CF=1", "JUCE_APP_VERSION=1.0.3", "JUCE_APP_VERSION_HEX=0x10003", @@ -717,31 +1546,48 @@ "JucePlugin_Build_AUv3=0", "JucePlugin_Build_RTAS=0", "JucePlugin_Build_AAX=0", - "JucePlugin_Build_Standalone=1", ); - GCC_SYMBOLS_PRIVATE_EXTERN = YES; + "JucePlugin_Build_Standalone=1", + "JucePlugin_Build_Unity=0", + ); GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - HEADER_SEARCH_PATHS = ("../../VST3_SDK", "../../JuceLibraryCode", "../../JuceLibraryCode/modules", "../../Include", "../../JuceLibraryCode/modules/juce_audio_plugin_client", "$(inherited)"); + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK", + "$(SRCROOT)/../../JuceLibraryCode", + "$(SRCROOT)/../../JuceLibraryCode/modules", + "$(SRCROOT)/../../Include", + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client", + "$(inherited)", + ); INFOPLIST_FILE = Info-Standalone_Plugin.plist; INFOPLIST_PREPROCESS = NO; - LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 10.9; - MACOSX_DEPLOYMENT_TARGET_ppc = 10.4; - OTHER_LDFLAGS = "-lTemper\\ (Demo)"; + MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../JuceLibraryCode/modules $(SRCROOT)/../../Include $(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client"; + OTHER_LDFLAGS = "-lTemper"; PRODUCT_BUNDLE_IDENTIFIER = com.creativeintent.temper; - SDKROOT_ppc = macosx10.5; - USE_HEADERMAP = NO; }; name = Demo; }; - 8F02B3FB70199C61B246690E = {isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "c++14"; + PRODUCT_NAME = "Temper"; + USE_HEADERMAP = NO; + VALIDATE_WORKSPACE_SKIPPED_SDK_FRAMEWORKS = OpenGL; + VALID_ARCHS = "i386 x86_64 arm64 arm64e"; + }; + name = Debug; + }; + B705C6672E96DCA45E3645EA /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; CLANG_LINK_OBJC_RUNTIME = NO; + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; - COPY_PHASE_STRIP = NO; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; + DEAD_CODE_STRIPPING = YES; + EXCLUDED_ARCHS = ""; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = ( - "_DEBUG=1", - "DEBUG=1", + "_NDEBUG=1", + "NDEBUG=1", "JUCER_XCODE_MAC_F6D2F4CF=1", "JUCE_APP_VERSION=1.0.3", "JUCE_APP_VERSION_HEX=0x10003", @@ -752,55 +1598,100 @@ "JucePlugin_Build_RTAS=0", "JucePlugin_Build_AAX=0", "JucePlugin_Build_Standalone=1", - "JUCE_SHARED_CODE=1", ); + "JucePlugin_Build_Unity=0", + "JUCE_SHARED_CODE=1", + ); GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - HEADER_SEARCH_PATHS = ("../../VST3_SDK", "../../JuceLibraryCode", "../../JuceLibraryCode/modules", "../../Include", "../../JuceLibraryCode/modules/juce_audio_plugin_client", "$(inherited)"); + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK", + "$(SRCROOT)/../../JuceLibraryCode", + "$(SRCROOT)/../../JuceLibraryCode/modules", + "$(SRCROOT)/../../Include", + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client", + "$(inherited)", + ); INSTALL_PATH = "@executable_path/../Frameworks"; + LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 10.9; - MACOSX_DEPLOYMENT_TARGET_ppc = 10.4; + MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../JuceLibraryCode/modules $(SRCROOT)/../../Include $(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client"; PRODUCT_BUNDLE_IDENTIFIER = com.creativeintent.temper; - SDKROOT_ppc = macosx10.5; - USE_HEADERMAP = NO; }; name = Debug; }; - B705C6672E96DCA45E3645EA = {isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "c++14"; + PRODUCT_NAME = "Temper"; + SKIP_INSTALL = YES; + USE_HEADERMAP = NO; + VALIDATE_WORKSPACE_SKIPPED_SDK_FRAMEWORKS = OpenGL; + VALID_ARCHS = "i386 x86_64 arm64 arm64e"; + }; + name = Release; + }; + BB20A7A862DDF30947CA24ED /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; CLANG_LINK_OBJC_RUNTIME = NO; + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; - DEAD_CODE_STRIPPING = YES; - GCC_GENERATE_DEBUGGING_SYMBOLS = NO; - GCC_OPTIMIZATION_LEVEL = 3; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = /; + EXCLUDED_ARCHS = ""; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( - "_NDEBUG=1", - "NDEBUG=1", + "_DEBUG=1", + "DEBUG=1", "JUCER_XCODE_MAC_F6D2F4CF=1", "JUCE_APP_VERSION=1.0.3", "JUCE_APP_VERSION_HEX=0x10003", - "JucePlugin_Build_VST=1", + "JucePlugin_Build_VST=0", "JucePlugin_Build_VST3=1", - "JucePlugin_Build_AU=1", + "JucePlugin_Build_AU=0", "JucePlugin_Build_AUv3=0", "JucePlugin_Build_RTAS=0", "JucePlugin_Build_AAX=0", - "JucePlugin_Build_Standalone=1", - "JUCE_SHARED_CODE=1", ); - GCC_SYMBOLS_PRIVATE_EXTERN = YES; + "JucePlugin_Build_Standalone=0", + "JucePlugin_Build_Unity=0", + ); GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - HEADER_SEARCH_PATHS = ("../../VST3_SDK", "../../JuceLibraryCode", "../../JuceLibraryCode/modules", "../../Include", "../../JuceLibraryCode/modules/juce_audio_plugin_client", "$(inherited)"); - INSTALL_PATH = "@executable_path/../Frameworks"; - LLVM_LTO = YES; + GENERATE_PKGINFO_FILE = YES; + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK", + "$(SRCROOT)/../../JuceLibraryCode", + "$(SRCROOT)/../../JuceLibraryCode/modules", + "$(SRCROOT)/../../Include", + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client", + "$(inherited)", + ); + INFOPLIST_FILE = Info-VST3.plist; + INFOPLIST_PREPROCESS = NO; + INSTALL_PATH = "$(BUILD_DIR)/$(CONFIGURATION)"; + LIBRARY_STYLE = Bundle; MACOSX_DEPLOYMENT_TARGET = 10.9; - MACOSX_DEPLOYMENT_TARGET_ppc = 10.4; + MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../JuceLibraryCode/modules $(SRCROOT)/../../Include $(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client"; + OTHER_LDFLAGS = "-bundle -lTemper"; PRODUCT_BUNDLE_IDENTIFIER = com.creativeintent.temper; - SDKROOT_ppc = macosx10.5; - USE_HEADERMAP = NO; }; name = Release; }; - BFB4F18F1645324BD3D4A03E = {isa = XCBuildConfiguration; buildSettings = { + PRODUCT_NAME = "Temper"; + USE_HEADERMAP = NO; + VALIDATE_WORKSPACE_SKIPPED_SDK_FRAMEWORKS = OpenGL; + VALID_ARCHS = "i386 x86_64 arm64 arm64e"; + WRAPPER_EXTENSION = vst3; + }; + name = Debug; + }; + BFB4F18F1645324BD3D4A03E /* Demo */ = { + isa = XCBuildConfiguration; + buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "c++14"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; CLANG_LINK_OBJC_RUNTIME = NO; + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; DEAD_CODE_STRIPPING = YES; + EXCLUDED_ARCHS = ""; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -817,41 +1708,78 @@ "JucePlugin_Build_RTAS=0", "JucePlugin_Build_AAX=0", "JucePlugin_Build_Standalone=1", - "JUCE_SHARED_CODE=1", ); - GCC_SYMBOLS_PRIVATE_EXTERN = YES; + "JucePlugin_Build_Unity=0", + "JUCE_SHARED_CODE=1", + ); GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - HEADER_SEARCH_PATHS = ("../../VST3_SDK", "../../JuceLibraryCode", "../../JuceLibraryCode/modules", "../../Include", "../../JuceLibraryCode/modules/juce_audio_plugin_client", "$(inherited)"); + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK", + "$(SRCROOT)/../../JuceLibraryCode", + "$(SRCROOT)/../../JuceLibraryCode/modules", + "$(SRCROOT)/../../Include", + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client", + "$(inherited)", + ); INSTALL_PATH = "@executable_path/../Frameworks"; LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 10.9; - MACOSX_DEPLOYMENT_TARGET_ppc = 10.4; + MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../JuceLibraryCode/modules $(SRCROOT)/../../Include $(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client"; PRODUCT_BUNDLE_IDENTIFIER = com.creativeintent.temper; - SDKROOT_ppc = macosx10.5; - USE_HEADERMAP = NO; }; name = Demo; }; - DC54FEFECC7EE960E754B824 = {isa = XCBuildConfiguration; buildSettings = { + PRODUCT_NAME = "Temper (Demo)"; + SKIP_INSTALL = YES; + USE_HEADERMAP = NO; + VALIDATE_WORKSPACE_SKIPPED_SDK_FRAMEWORKS = OpenGL; + VALID_ARCHS = "i386 x86_64 arm64 arm64e"; + }; + name = Demo; + }; + C7002CCFFE56C8F1B385BDA7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + MACOSX_DEPLOYMENT_TARGET = 10.9; + SDKROOT = macosx; + }; + name = Debug; + }; + D652EDE4F3E5F7F37B76225A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + MACOSX_DEPLOYMENT_TARGET = 10.9; + SDKROOT = macosx; + }; + name = Release; + }; + DC54FEFECC7EE960E754B824 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - DEBUG_INFORMATION_FORMAT = "dwarf"; + CODE_SIGN_IDENTITY = ""; + DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; + ENABLE_TESTABILITY = NO; GCC_C_LANGUAGE_STANDARD = c11; GCC_INLINES_ARE_PRIVATE_EXTERN = YES; GCC_MODEL_TUNING = G5; GCC_NO_COMMON_BLOCKS = YES; + GCC_SYMBOLS_PRIVATE_EXTERN = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; @@ -863,251 +1791,145 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; PRODUCT_NAME = "Temper"; - WARNING_CFLAGS = -Wreorder; - ZERO_LINK = NO; }; name = Debug; }; - 51B52684D34AD98BE008AE8C = {isa = XCBuildConfiguration; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - DEBUG_INFORMATION_FORMAT = "dwarf"; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = c11; - GCC_INLINES_ARE_PRIVATE_EXTERN = YES; - GCC_MODEL_TUNING = G5; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; - GCC_WARN_MISSING_PARENTHESES = YES; - GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; - GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; + SDKROOT = macosx; + WARNING_CFLAGS = "-Wreorder"; + ZERO_LINK = NO; + }; + name = Debug; + }; + EE445B6674AB52157101266D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_LINK_OBJC_RUNTIME = NO; + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; + DEAD_CODE_STRIPPING = YES; + DEPLOYMENT_LOCATION = YES; + DSTROOT = /; + EXCLUDED_ARCHS = ""; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_PREPROCESSOR_DEFINITIONS = ( + "_NDEBUG=1", + "NDEBUG=1", + "JUCER_XCODE_MAC_F6D2F4CF=1", + "JUCE_APP_VERSION=1.0.3", + "JUCE_APP_VERSION_HEX=0x10003", + "JucePlugin_Build_VST=0", + "JucePlugin_Build_VST3=0", + "JucePlugin_Build_AU=1", + "JucePlugin_Build_AUv3=0", + "JucePlugin_Build_RTAS=0", + "JucePlugin_Build_AAX=0", + "JucePlugin_Build_Standalone=0", + "JucePlugin_Build_Unity=0", + ); + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GENERATE_PKGINFO_FILE = YES; + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK", + "$(SRCROOT)/../../JuceLibraryCode", + "$(SRCROOT)/../../JuceLibraryCode/modules", + "$(SRCROOT)/../../Include", + "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client", + "$(inherited)", + ); + INFOPLIST_FILE = Info-AU.plist; + INFOPLIST_PREPROCESS = NO; + INSTALL_PATH = "$(BUILD_DIR)/$(CONFIGURATION)"; + LIBRARY_STYLE = Bundle; + LLVM_LTO = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../JuceLibraryCode/modules $(SRCROOT)/../../Include $(SRCROOT)/../../JuceLibraryCode/modules/juce_audio_plugin_client"; + OTHER_LDFLAGS = "-bundle -lTemper"; + OTHER_REZFLAGS = "-d ppc_$ppc -d i386_$i386 -d ppc64_$ppc64 -d x86_64_$x86_64 -d arm64_$arm64 -I /System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Versions/A/Headers -I \"$(DEVELOPER_DIR)/Extras/CoreAudio/AudioUnits/AUPublic/AUBase\" -I \"$(DEVELOPER_DIR)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/AudioUnit.framework/Headers\""; + PRODUCT_BUNDLE_IDENTIFIER = com.creativeintent.temper; PRODUCT_NAME = "Temper"; - WARNING_CFLAGS = -Wreorder; - ZERO_LINK = NO; }; name = Release; }; - 729619C61C81AE021832EB20 = {isa = XCBuildConfiguration; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - DEBUG_INFORMATION_FORMAT = "dwarf"; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = c11; - GCC_INLINES_ARE_PRIVATE_EXTERN = YES; - GCC_MODEL_TUNING = G5; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; - GCC_WARN_MISSING_PARENTHESES = YES; - GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; - GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - PRODUCT_NAME = "Temper (Demo)"; - WARNING_CFLAGS = -Wreorder; - ZERO_LINK = NO; }; name = Demo; }; - 6EF46BEEB6961E85FE3E778A = {isa = PBXTargetDependency; target = EFB06C11706FA2BED72C0177; }; - 4A9EE988B3731B0E78C7F6EF = {isa = PBXTargetDependency; target = C4D91950F59C6AC78BBE99D9; }; - 1C26FAA488863CF312B1CE9F = {isa = PBXTargetDependency; target = 78A0F1CBC813E0CDBA206E64; }; - B89C1BC467892DF12D5BECDB = {isa = PBXTargetDependency; target = B4FFFFFD24A70BAECA79D226; }; - BDECFAD9F9178C805ECF040C = {isa = PBXTargetDependency; target = B7EF72187EFCA6F380E6881C; }; - E3D10272E9BD334B9AC87536 = {isa = XCConfigurationList; buildConfigurations = ( - DC54FEFECC7EE960E754B824, - 51B52684D34AD98BE008AE8C, - 729619C61C81AE021832EB20, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; - C256B4ADC5A4B7C840FAB917 = {isa = XCConfigurationList; buildConfigurations = ( - C7002CCFFE56C8F1B385BDA7, - D652EDE4F3E5F7F37B76225A, - 992799EC591C91E642CD3D65, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; - 2BEC471FAEF6D07D8826CB28 = {isa = PBXAggregateTarget; buildConfigurationList = C256B4ADC5A4B7C840FAB917; buildPhases = ( ); buildRules = ( ); dependencies = ( - 6EF46BEEB6961E85FE3E778A, - 4A9EE988B3731B0E78C7F6EF, - 1C26FAA488863CF312B1CE9F, - B89C1BC467892DF12D5BECDB, - BDECFAD9F9178C805ECF040C, ); name = "Temper - All"; productName = Temper; }; - 2B4B8962A4E44E38B04ED195 = {isa = XCConfigurationList; buildConfigurations = ( - 037777277548B3E4413ECEF1, - 149F966C3EF21DFC25242E76, - 34EC70CEAF046ADDCB554E68, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; - 433E22463C7FB20A34E42C96 = {isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - D9997560B40DD7D50FA3E9A0, ); runOnlyForDeploymentPostprocessing = 0; }; - C7DBA2ED2AAB16409521B539 = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - E8CDF6E5A8E80EB92013DBFE, ); runOnlyForDeploymentPostprocessing = 0; }; - 8A0947884E4255028FEBC1BF = {isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 79FECC7AD35E7CD7C30569E3, - 61AD7A33F376FB4318E4F7AF, - B19EF2739AFA3DDA44EA7526, - C3B45D6C33FC8D2DFFAFD911, - 08B71F44034B3235DC256506, - 26DDC2E8A87CED2C233559FF, - 5B7726FEB45B778ABED69629, - 1CDB95CBF8A78E121703AABD, - 3C0CF21B9D661657A7DBB61D, - 5AA57ADA8E950DE1913F8074, - 2CD8DDC837D8042EBD00FAAC, - DE69B418D3E6B6893977CDC1, - CFE6846487945890AEFA253B, - F683B8ED17E7E74361810BC1, ); runOnlyForDeploymentPostprocessing = 0; }; - EFB06C11706FA2BED72C0177 = {isa = PBXNativeTarget; buildConfigurationList = 2B4B8962A4E44E38B04ED195; buildPhases = ( - 433E22463C7FB20A34E42C96, - C7DBA2ED2AAB16409521B539, - 8A0947884E4255028FEBC1BF, ); buildRules = ( ); dependencies = ( - BDECFAD9F9178C805ECF040C, ); name = "Temper - VST"; productName = Temper; productReference = 329DB2BBEB45BD6A9C25C06E; productType = "com.apple.product-type.bundle"; }; - 5AF127382B498C3B12F47803 = {isa = XCConfigurationList; buildConfigurations = ( - BB20A7A862DDF30947CA24ED, - 552BE47D98F05E7E2A1BE1E5, - 48C2A0C89EB5B272FB1A3BE4, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; - 2396A6A5A1A0F028BA9634FA = {isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - D9997560B40DD7D50FA3E9A0, ); runOnlyForDeploymentPostprocessing = 0; }; - 6CD0340BC5ECC5349164024F = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 10066F8FBF6EC9E37E0DE1AD, ); runOnlyForDeploymentPostprocessing = 0; }; - E4030EA573A5E9CC6D454AD5 = {isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 79FECC7AD35E7CD7C30569E3, - 61AD7A33F376FB4318E4F7AF, - B19EF2739AFA3DDA44EA7526, - C3B45D6C33FC8D2DFFAFD911, - 08B71F44034B3235DC256506, - 26DDC2E8A87CED2C233559FF, - 5B7726FEB45B778ABED69629, - 1CDB95CBF8A78E121703AABD, - 3C0CF21B9D661657A7DBB61D, - 5AA57ADA8E950DE1913F8074, - 2CD8DDC837D8042EBD00FAAC, - DE69B418D3E6B6893977CDC1, - CFE6846487945890AEFA253B, - F683B8ED17E7E74361810BC1, ); runOnlyForDeploymentPostprocessing = 0; }; - C4D91950F59C6AC78BBE99D9 = {isa = PBXNativeTarget; buildConfigurationList = 5AF127382B498C3B12F47803; buildPhases = ( - 2396A6A5A1A0F028BA9634FA, - 6CD0340BC5ECC5349164024F, - E4030EA573A5E9CC6D454AD5, ); buildRules = ( ); dependencies = ( - BDECFAD9F9178C805ECF040C, ); name = "Temper - VST3"; productName = Temper; productReference = DE34C9EED8B65542DF1F7EA5; productType = "com.apple.product-type.bundle"; }; - BC3EFCFB70AFB99B7FF7EDF3 = {isa = XCConfigurationList; buildConfigurations = ( - 51D636E6D50164DCD40BB553, - EE445B6674AB52157101266D, - 0653AFD32E461E60585D3F41, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; - 1DFB37F4AC1199CB4B36BD8C = {isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - D9997560B40DD7D50FA3E9A0, ); runOnlyForDeploymentPostprocessing = 0; }; - AA87E9A6A56329DA6FD6236F = {isa = PBXRezBuildPhase; buildActionMask = 2147483647; files = ( - 0B753ED8F52C2C248C53F0AB, ); runOnlyForDeploymentPostprocessing = 0; }; - AA9C33298E6831FD8EDE97AA = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - DAB193581FCC69B9691223B5, - 5D22FDD5F55141A80CE432EC, ); runOnlyForDeploymentPostprocessing = 0; }; - 5E3200D6DA0BBFD4B9F1E6CA = {isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 79FECC7AD35E7CD7C30569E3, - 61AD7A33F376FB4318E4F7AF, - BF91BC76FFFCCFD8A5A3DB90, - B19EF2739AFA3DDA44EA7526, - C3B45D6C33FC8D2DFFAFD911, - 08B71F44034B3235DC256506, - 26DDC2E8A87CED2C233559FF, - 5B7726FEB45B778ABED69629, - 02843AA0A5FDADC7EEAC6BEE, - 1CDB95CBF8A78E121703AABD, - 3C0CF21B9D661657A7DBB61D, - 5AA57ADA8E950DE1913F8074, - 2CD8DDC837D8042EBD00FAAC, - DE69B418D3E6B6893977CDC1, - CFE6846487945890AEFA253B, - F683B8ED17E7E74361810BC1, ); runOnlyForDeploymentPostprocessing = 0; }; - 78A0F1CBC813E0CDBA206E64 = {isa = PBXNativeTarget; buildConfigurationList = BC3EFCFB70AFB99B7FF7EDF3; buildPhases = ( - 1DFB37F4AC1199CB4B36BD8C, - AA87E9A6A56329DA6FD6236F, - AA9C33298E6831FD8EDE97AA, - 5E3200D6DA0BBFD4B9F1E6CA, ); buildRules = ( ); dependencies = ( - BDECFAD9F9178C805ECF040C, ); name = "Temper - AU"; productName = Temper; productReference = D382B2EFF926D55A5494CF1D; productType = "com.apple.product-type.bundle"; }; - 1E432B7236708FF6C39EE7B3 = {isa = XCConfigurationList; buildConfigurations = ( - B3463E7EB0C6F6B8B3CEB9F9, - 8E12410EC2444CFE892522F2, - 7C721E226241FBB4FB038A8E, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; - F8A8036273438FF53B74788C = {isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - D9997560B40DD7D50FA3E9A0, ); runOnlyForDeploymentPostprocessing = 0; }; - 99326F02268010B1AB8B4EE8 = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8FD7DF91F80816C75804E626, ); runOnlyForDeploymentPostprocessing = 0; }; - D534DBA3B54AC47DC17473BB = {isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 79FECC7AD35E7CD7C30569E3, - 61AD7A33F376FB4318E4F7AF, - B19EF2739AFA3DDA44EA7526, - C3B45D6C33FC8D2DFFAFD911, - 08B71F44034B3235DC256506, - 26DDC2E8A87CED2C233559FF, - 5B7726FEB45B778ABED69629, - 1CDB95CBF8A78E121703AABD, - 3C0CF21B9D661657A7DBB61D, - 5AA57ADA8E950DE1913F8074, - 2CD8DDC837D8042EBD00FAAC, - DE69B418D3E6B6893977CDC1, - CFE6846487945890AEFA253B, - F683B8ED17E7E74361810BC1, ); runOnlyForDeploymentPostprocessing = 0; }; - B4FFFFFD24A70BAECA79D226 = {isa = PBXNativeTarget; buildConfigurationList = 1E432B7236708FF6C39EE7B3; buildPhases = ( - F8A8036273438FF53B74788C, - 99326F02268010B1AB8B4EE8, - D534DBA3B54AC47DC17473BB, ); buildRules = ( ); dependencies = ( - BDECFAD9F9178C805ECF040C, ); name = "Temper - Standalone Plugin"; productName = Temper; productReference = CE24234A805A548104752B18; productType = "com.apple.product-type.application"; }; - 4BD7DC1DB3BF44FD80C19DF7 = {isa = XCConfigurationList; buildConfigurations = ( - 8F02B3FB70199C61B246690E, - B705C6672E96DCA45E3645EA, - BFB4F18F1645324BD3D4A03E, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; - 7E7EA50BF37C2E45F7FED2C2 = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - B6142B2DF81E50A0E4E76F52, - 0988CF5ED15E82CC78B53137, - 7895E7D833D1029782229EBF, - 7D138E4AA28C1C976EA1D186, - 5996B7821900A1790016AADE, - 1E62DE5EE4512FECE82E2E09, - 46761BF0558068478B8ABEC2, - CB115CA1ED358F980E1CBE6F, - 9C5A0DCFFD53650C343E142F, - 9E6E52EFC3B57F61D701EC19, - 274D467D0A8753F7EDBD04DF, - 9494E786CFDC756E9821102A, - 3A43512BD12733D784697343, - FBFDB86DECA46E503320CAEE, - B99E04E3BBE9E0D0DB1797C7, - 8689BCA55706DB2AF975F6BE, - 7020F5FC4892253AEDC4B6C1, - FEC45F5FAA0B8F0B2EB4D62C, - 6348ED75152CC9DCD4327937, - 631BBF5C0B44B9CAF4248FAD, - 2F31CF09BE378AD7ED861925, - C4199DF380BE36A4BB61C542, - F26E07F79FD441C416B3E98E, - 37FC7CDE7C515B3ABEFCBF20, - E7FA2C8749C360EBAC0C497E, - AFB47B9448D55B25E1D20E8F, ); runOnlyForDeploymentPostprocessing = 0; }; - B7EF72187EFCA6F380E6881C = {isa = PBXNativeTarget; buildConfigurationList = 4BD7DC1DB3BF44FD80C19DF7; buildPhases = ( - 7E7EA50BF37C2E45F7FED2C2, ); buildRules = ( ); dependencies = ( ); name = "Temper - Shared Code"; productName = Temper; productReference = 51985E139AA96A0DF9BDD53F; productType = "com.apple.product-type.library.static"; }; - 161A016FC5B702D86E73B434 = {isa = PBXProject; buildConfigurationList = E3D10272E9BD334B9AC87536; attributes = { LastUpgradeCheck = 0830; ORGANIZATIONNAME = "Creative Intent"; TargetAttributes = { 2BEC471FAEF6D07D8826CB28 = { SystemCapabilities = {com.apple.ApplicationGroups.iOS = { enabled = 0; }; com.apple.InAppPurchase = { enabled = 0; }; com.apple.InterAppAudio = { enabled = 0; }; com.apple.Push = { enabled = 0; }; com.apple.Sandbox = { enabled = 0; }; }; };EFB06C11706FA2BED72C0177 = { SystemCapabilities = {com.apple.ApplicationGroups.iOS = { enabled = 0; }; com.apple.InAppPurchase = { enabled = 0; }; com.apple.InterAppAudio = { enabled = 0; }; com.apple.Push = { enabled = 0; }; com.apple.Sandbox = { enabled = 0; }; }; };C4D91950F59C6AC78BBE99D9 = { SystemCapabilities = {com.apple.ApplicationGroups.iOS = { enabled = 0; }; com.apple.InAppPurchase = { enabled = 0; }; com.apple.InterAppAudio = { enabled = 0; }; com.apple.Push = { enabled = 0; }; com.apple.Sandbox = { enabled = 0; }; }; };78A0F1CBC813E0CDBA206E64 = { SystemCapabilities = {com.apple.ApplicationGroups.iOS = { enabled = 0; }; com.apple.InAppPurchase = { enabled = 0; }; com.apple.InterAppAudio = { enabled = 0; }; com.apple.Push = { enabled = 0; }; com.apple.Sandbox = { enabled = 0; }; }; };B4FFFFFD24A70BAECA79D226 = { SystemCapabilities = {com.apple.ApplicationGroups.iOS = { enabled = 0; }; com.apple.InAppPurchase = { enabled = 0; }; com.apple.InterAppAudio = { enabled = 0; }; com.apple.Push = { enabled = 0; }; com.apple.Sandbox = { enabled = 0; }; }; };B7EF72187EFCA6F380E6881C = { SystemCapabilities = {com.apple.ApplicationGroups.iOS = { enabled = 0; }; com.apple.InAppPurchase = { enabled = 0; }; com.apple.InterAppAudio = { enabled = 0; }; com.apple.Push = { enabled = 0; }; com.apple.Sandbox = { enabled = 0; }; }; }; }; }; compatibilityVersion = "Xcode 3.2"; hasScannedForEncodings = 0; mainGroup = 16B7A8795DC462581C0D3409; projectDirPath = ""; projectRoot = ""; targets = (2BEC471FAEF6D07D8826CB28, EFB06C11706FA2BED72C0177, C4D91950F59C6AC78BBE99D9, 78A0F1CBC813E0CDBA206E64, B4FFFFFD24A70BAECA79D226, B7EF72187EFCA6F380E6881C); }; + USE_HEADERMAP = NO; + VALIDATE_WORKSPACE_SKIPPED_SDK_FRAMEWORKS = OpenGL; + VALID_ARCHS = "i386 x86_64 arm64 arm64e"; + WRAPPER_EXTENSION = component; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1E432B7236708FF6C39EE7B3 = { + isa = XCConfigurationList; + buildConfigurations = ( + B3463E7EB0C6F6B8B3CEB9F9, + 8E12410EC2444CFE892522F2, + 7C721E226241FBB4FB038A8E, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + 2B4B8962A4E44E38B04ED195 = { + isa = XCConfigurationList; + buildConfigurations = ( + 037777277548B3E4413ECEF1, + 149F966C3EF21DFC25242E76, + 34EC70CEAF046ADDCB554E68, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + 4BD7DC1DB3BF44FD80C19DF7 = { + isa = XCConfigurationList; + buildConfigurations = ( + 8F02B3FB70199C61B246690E, + B705C6672E96DCA45E3645EA, + BFB4F18F1645324BD3D4A03E, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + 5AF127382B498C3B12F47803 = { + isa = XCConfigurationList; + buildConfigurations = ( + BB20A7A862DDF30947CA24ED, + 552BE47D98F05E7E2A1BE1E5, + 48C2A0C89EB5B272FB1A3BE4, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + BC3EFCFB70AFB99B7FF7EDF3 = { + isa = XCConfigurationList; + buildConfigurations = ( + 51D636E6D50164DCD40BB553, + EE445B6674AB52157101266D, + 0653AFD32E461E60585D3F41, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + C256B4ADC5A4B7C840FAB917 = { + isa = XCConfigurationList; + buildConfigurations = ( + C7002CCFFE56C8F1B385BDA7, + D652EDE4F3E5F7F37B76225A, + 992799EC591C91E642CD3D65, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + E3D10272E9BD334B9AC87536 = { + isa = XCConfigurationList; + buildConfigurations = ( + 51B52684D34AD98BE008AE8C, + 729619C61C81AE021832EB20, + DC54FEFECC7EE960E754B824, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ }; - rootObject = 161A016FC5B702D86E73B434; + rootObject = 161A016FC5B702D86E73B434 /* Project object */; } diff --git a/Builds/MacOSX/Temper.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Builds/MacOSX/Temper.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/Builds/MacOSX/Temper.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Builds/MacOSX/Temper.xcodeproj/xcshareddata/xcschemes/Temper - AU.xcscheme b/Builds/MacOSX/Temper.xcodeproj/xcshareddata/xcschemes/Temper - AU.xcscheme new file mode 100644 index 00000000..acb4287b --- /dev/null +++ b/Builds/MacOSX/Temper.xcodeproj/xcshareddata/xcschemes/Temper - AU.xcscheme @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Builds/Temper-AU-ARM.zip b/Builds/Temper-AU-ARM.zip new file mode 100644 index 00000000..a5b52350 Binary files /dev/null and b/Builds/Temper-AU-ARM.zip differ diff --git a/Builds/VisualStudio2017/Temper.sln b/Builds/VisualStudio2017/Temper.sln index af209a80..cdf71f4e 100644 --- a/Builds/VisualStudio2017/Temper.sln +++ b/Builds/VisualStudio2017/Temper.sln @@ -1,5 +1,6 @@ + Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2017 +# Visual Studio 15 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Temper - Standalone Plugin", "Temper_StandalonePlugin.vcxproj", "{1511B662-19BF-4E37-E98C-33640F16251F}" ProjectSection(ProjectDependencies) = postProject diff --git a/Builds/VisualStudio2017/Temper_SharedCode.vcxproj b/Builds/VisualStudio2017/Temper_SharedCode.vcxproj index 04be792f..f0538e56 100644 --- a/Builds/VisualStudio2017/Temper_SharedCode.vcxproj +++ b/Builds/VisualStudio2017/Temper_SharedCode.vcxproj @@ -31,8 +31,6 @@ {CF7351B9-562C-0B35-A11A-4F7935496955} - v141 - 10.0.16299.0 false false v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -49,8 +47,7 @@ false false v141 - v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -58,7 +55,7 @@ false true v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -66,8 +63,7 @@ false true v141 - v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -75,7 +71,7 @@ false true v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -83,8 +79,7 @@ false true v141 - v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -93,10 +88,6 @@ Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform"/> - - v141 - 10.0.16299.0 - <_ProjectFileVersion>10.0.30319.1 .lib @@ -124,8 +115,6 @@ $(Platform)\$(Configuration)\Shared Code\ Temper (x64)(Demo) true - v141 - 10.0.16299.0 @@ -138,18 +127,18 @@ Disabled ProgramDatabase - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JUCE_SHARED_CODE=1;_LIB;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JucePlugin_Build_Unity=0;JUCE_SHARED_CODE=1;_LIB;%(PreprocessorDefinitions) MultiThreadedDebugDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper.pdb Level4 true true - stdcpp14 + stdcpp20 _DEBUG;%(PreprocessorDefinitions) @@ -168,7 +157,6 @@ true $(IntDir)\Temper.bsc - MachineX86 @@ -184,18 +172,18 @@ Disabled ProgramDatabase - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JUCE_SHARED_CODE=1;_LIB;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JucePlugin_Build_Unity=0;JUCE_SHARED_CODE=1;_LIB;%(PreprocessorDefinitions) MultiThreadedDebugDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper (x64).pdb Level4 true true - stdcpp14 + stdcpp20 _DEBUG;%(PreprocessorDefinitions) @@ -213,7 +201,6 @@ true $(IntDir)\Temper (x64).bsc - @@ -225,18 +212,18 @@ Full - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JUCE_SHARED_CODE=1;_LIB;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JucePlugin_Build_Unity=0;JUCE_SHARED_CODE=1;_LIB;%(PreprocessorDefinitions) MultiThreadedDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper.pdb Level4 true true - stdcpp14 + stdcpp20 NDEBUG;%(PreprocessorDefinitions) @@ -252,12 +239,12 @@ true true true + UseLinkTimeCodeGeneration true $(IntDir)\Temper.bsc - MachineX86 @@ -272,18 +259,18 @@ Full - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JUCE_SHARED_CODE=1;_LIB;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JucePlugin_Build_Unity=0;JUCE_SHARED_CODE=1;_LIB;%(PreprocessorDefinitions) MultiThreadedDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper (x64).pdb Level4 true true - stdcpp14 + stdcpp20 NDEBUG;%(PreprocessorDefinitions) @@ -298,12 +285,12 @@ true true true + UseLinkTimeCodeGeneration true $(IntDir)\Temper (x64).bsc - @@ -315,18 +302,18 @@ Full - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;TEMPER_DEMO_BUILD=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JUCE_SHARED_CODE=1;_LIB;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;TEMPER_DEMO_BUILD=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JucePlugin_Build_Unity=0;JUCE_SHARED_CODE=1;_LIB;%(PreprocessorDefinitions) MultiThreadedDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper (Demo).pdb Level4 true true - stdcpp14 + stdcpp20 NDEBUG;%(PreprocessorDefinitions) @@ -342,12 +329,12 @@ true true true + UseLinkTimeCodeGeneration true $(IntDir)\Temper (Demo).bsc - MachineX86 @@ -362,18 +349,18 @@ Full - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;TEMPER_DEMO_BUILD=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JUCE_SHARED_CODE=1;_LIB;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;TEMPER_DEMO_BUILD=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JucePlugin_Build_Unity=0;JUCE_SHARED_CODE=1;_LIB;%(PreprocessorDefinitions) MultiThreadedDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper (x64)(Demo).pdb Level4 true true - stdcpp14 + stdcpp20 NDEBUG;%(PreprocessorDefinitions) @@ -388,12 +375,12 @@ true true true + UseLinkTimeCodeGeneration true $(IntDir)\Temper (x64)(Demo).bsc - @@ -410,16 +397,25 @@ true + + true + true - + true - + true - + + true + + + true + + true @@ -494,6 +490,24 @@ true + + true + + + true + + + true + + + true + + + true + + + true + true @@ -506,10 +520,178 @@ true + + true + + + true + true - + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + true @@ -530,6 +712,9 @@ true + + true + true @@ -539,9 +724,6 @@ true - - true - true @@ -608,70 +790,73 @@ true - + + true + + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -731,87 +916,93 @@ true - + + true + + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true true + + true + true @@ -830,6 +1021,9 @@ true + + true + true @@ -845,12 +1039,33 @@ true - + + true + + + true + + + true + + + true + + true true + + true + + + true + + + true + true @@ -872,9 +1087,15 @@ true + + true + true + + true + true @@ -905,6 +1126,9 @@ true + + true + true @@ -914,9 +1138,18 @@ true + + true + true + + true + + + true + true @@ -938,6 +1171,9 @@ true + + true + true @@ -965,16 +1201,19 @@ true + + true + true - + true - + true - + true @@ -983,6 +1222,9 @@ true + + true + true @@ -1019,6 +1261,9 @@ true + + true + true @@ -1124,6 +1369,9 @@ true + + true + true @@ -1226,12 +1474,21 @@ true + + true + true true + + true + + + true + true @@ -1241,6 +1498,9 @@ true + + true + true @@ -1250,6 +1510,9 @@ true + + true + true @@ -1271,21 +1534,60 @@ true + + true + + + true + + + true + true true + + true + true - + true true + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + true @@ -1307,6 +1609,9 @@ true + + true + true @@ -1325,6 +1630,9 @@ true + + true + true @@ -1400,6 +1708,9 @@ true + + true + true @@ -1646,6 +1957,9 @@ true + + true + true @@ -1694,12 +2008,18 @@ true - + true true + + true + + + true + true @@ -1796,9 +2116,6 @@ true - - true - true @@ -1871,6 +2188,9 @@ true + + true + true @@ -1895,6 +2215,24 @@ true + + true + + + true + + + true + + + true + + + true + + + true + true @@ -1913,13 +2251,7 @@ true - - true - - - true - - + true @@ -1961,6 +2293,9 @@ true + + true + true @@ -2120,6 +2455,9 @@ true + + true + true @@ -2129,6 +2467,12 @@ true + + true + + + true + true @@ -2181,7 +2525,9 @@ - + + /bigobj %(AdditionalOptions) + @@ -2197,15 +2543,26 @@ + - - - - - - + + + + + + + + + + + + + + + + @@ -2232,21 +2589,94 @@ + + + + + + + - - + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - @@ -2279,50 +2709,51 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2345,72 +2776,100 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + @@ -2421,8 +2880,13 @@ + + + + + + - @@ -2432,14 +2896,16 @@ + + - + @@ -2450,6 +2916,7 @@ + @@ -2460,6 +2927,7 @@ + @@ -2473,28 +2941,34 @@ + + + + + - - - + + + + @@ -2513,6 +2987,7 @@ + @@ -2552,6 +3027,7 @@ + @@ -2569,7 +3045,6 @@ - @@ -2577,7 +3052,6 @@ - @@ -2585,17 +3059,19 @@ + - - + + + @@ -2605,23 +3081,34 @@ - + + + - + - - + + - - + + + + + + + + + + + + - @@ -2630,6 +3117,7 @@ + @@ -2641,12 +3129,12 @@ + - @@ -2691,6 +3179,7 @@ + @@ -2698,6 +3187,7 @@ + @@ -2705,7 +3195,15 @@ - + + + + + + + + + @@ -2724,8 +3222,11 @@ - + + + + @@ -2789,6 +3290,7 @@ + @@ -2800,11 +3302,33 @@ + - + + + + + + + + + + + + + + + + + + + + + + @@ -2815,6 +3339,7 @@ + @@ -2838,13 +3363,13 @@ + - @@ -2855,6 +3380,7 @@ + @@ -2871,19 +3397,21 @@ + - - + + + @@ -2893,21 +3421,24 @@ + - + + + - + @@ -2918,14 +3449,24 @@ + + + + + + + + + + + + + - - - diff --git a/Builds/VisualStudio2017/Temper_SharedCode.vcxproj.filters b/Builds/VisualStudio2017/Temper_SharedCode.vcxproj.filters index a80221cc..abfe5cd3 100644 --- a/Builds/VisualStudio2017/Temper_SharedCode.vcxproj.filters +++ b/Builds/VisualStudio2017/Temper_SharedCode.vcxproj.filters @@ -17,8 +17,8 @@ {5FCF559E-451A-CB1E-B177-A5DC5A0005BB} - - {31054003-EA72-6A9D-D650-56451D9820E6} + + {05CE33FC-868F-AA1A-12B8-79C98E753648} {D78296AF-218E-B17E-7F8B-9D148601188D} @@ -35,15 +35,51 @@ {8292766D-2459-2E7E-7615-17216318BA93} + + {9BD56105-DAB4-EBD5-00DD-BD540E98FE88} + {10472B2C-9888-D269-F351-0D0AC3BCD16C} {BF23FC10-1D57-2A9B-706F-6DD8A7B593D4} + + {386862D5-4DCC-A4B3-5642-60A201E303EF} + {092EFC17-7C95-7E04-0ACA-0D61A462EE81} + + {285118C6-8FDA-7DCE-BEF4-FFB2120876C5} + + + {69ED6B61-9B8D-D47E-E4A6-2E9F9A94A75A} + + + {7CDB7CD1-BB96-F593-3C78-1E06182B5839} + + + {B0A708DE-B4CF-196B-14FB-DC8221509B8E} + + + {34F46ADE-EE31-227A-A69E-7732E70145F1} + + + {BB9B3C77-17FB-E994-8B75-88F1727E4655} + + + {C0971D77-2F14-190A-E2AE-89D6285F4D5A} + + + {AABEA333-6524-8891-51C7-6DAEB5700628} + + + {F2D29337-983E-BAD7-7B5C-E0AB3D53D404} + + + {C674B0FB-1FC0-2986-94B1-083845018994} + {0AFC1CE8-F6E6-9817-8C21-8432B2A375DA} @@ -68,26 +104,26 @@ {9EB3EC7F-2AB7-DDAA-3C05-DF382B728D3F} - - {02D37B85-7DE2-C8E7-A274-A5A0FBE99D69} + + {6B9FBFDC-1D10-6246-356D-00FF4535CECB} - - {DAF3BAAF-5207-4C34-61B9-A97DDC930D50} + + {D6FCFC8E-7136-9109-78C0-91A3EB4C443F} - - {C7885588-8436-4C21-DC1E-58879BF53BDC} + + {EBF18AC1-F0ED-937A-2824-4307CE2ADAF7} - - {E4ECEA39-0EFF-2443-91B3-1E5DA7AD5AE4} + + {5A0F7922-2EFB-6465-57E4-A445B804EFB5} - - {210B8D25-68E0-32C3-1449-6A40F109C5E9} + + {4EC45416-0E7C-7567-6F75-D0C8CEE7DC4F} - - {378AD911-E8E4-D230-E76B-34542849509D} + + {C2985031-0496-55B5-41A8-BAB99E53D89D} - - {F6CED5B6-0A8C-56D2-C1AC-DED6BE774A13} + + {FB4AB426-7009-0036-BB75-E34256AA7C89} {E684D858-09E8-0251-8E86-5657129641E1} @@ -104,27 +140,60 @@ {E824435F-FC7B-10BE-5D1A-5DACC51A8836} - - {ECAD3047-D178-10EE-BAA7-61ABC3B53CF0} - - - {355704C0-2A0C-6AFD-71D3-80264445D7DF} - - - {725C0EA8-9736-764D-81E6-01695B6B00B3} - {09E4D4E3-1D92-962B-C66E-DD8C8C935FF6} - - {AA010709-292F-011A-F2AB-0D1B4A7B8328} - {BA0A76FA-458F-0B1C-02E9-ECFBF81140EC} {86737735-F6BA-F64A-5EC7-5C9F36755F79} + + {4DC60E78-BBC0-B540-63A2-37E14ABBEF09} + + + {80C72173-A1E1-C3C5-9288-B889CE2EAFEA} + + + {4138B955-AA0B-FA86-DBF9-404CAFFFA866} + + + {2B4166B8-F470-F07C-4F51-D2DAAAECBB18} + + + {9C295115-C0CD-3129-1C4D-FB53299B23FB} + + + {65526A8B-3447-9DF0-FD5D-00D111126027} + + + {A54A1F5C-F32F-F97B-9E8A-69922B770A54} + + + {B90A44F3-B62D-B5C0-81A2-683D2650AEE6} + + + {DAF30656-5915-0E45-C4E4-54439617D525} + + + {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} + + + {9C713CBA-A9E2-5F4E-F83C-2CAB8533913C} + + + {63571A07-9AA3-5BB0-1103-0B42A2E6BC9E} + + + {314F43F2-BC8F-B464-EAE7-86B9675454E9} + + + {874C5D0C-6D29-68EE-38BB-26200B56BC89} + + + {86BAA7A7-DC50-35B6-910B-932AEAF257F2} + {6B7BE34D-1BC1-C7B9-111F-C55CA8250943} @@ -176,6 +245,9 @@ {09B91E68-1FF4-C7ED-9055-D4D96E66A0BA} + + {30B3DA63-C1E4-F2EA-CEF0-8035D8CBFF64} + {4F24EEED-AA33-AC6C-9A39-72E71CF83EF0} @@ -251,6 +323,9 @@ {DDF4BA73-8578-406D-21F8-06B9BC70BFEA} + + {73374573-0194-9A6E-461A-A81EEB511C26} + {5DD60D0E-B16A-0BED-EDC4-C56E6960CA9E} @@ -308,6 +383,15 @@ {4CED05DA-E0A2-E548-F753-1F2EF299A8E3} + + {46AE69B8-AD58-4381-6CDE-25C8D75B01D2} + + + {E56CB4FC-32E8-8740-A3BB-B323CD937A99} + + + {4ECDCA0C-BB38-0729-A6B6-2FB0B4D0863B} + {294E4CD5-B06F-97D1-04A3-51871CEA507C} @@ -320,6 +404,9 @@ {E4EA47E5-B41C-2A19-1783-7E9104096ECD} + + {B331BC33-9770-3DB5-73F2-BC2469ECCF7F} + {46A17AC9-0BFF-B5CE-26D6-B9D1992C88AC} @@ -344,6 +431,12 @@ {FE3CB19C-EF43-5CF5-DAF0-09D4E43D0AB9} + + {C0E5DD5D-F8F1-DD25-67D7-291946AB3828} + + + {FE7E6CD5-C7A0-DB20-4E7E-D6E7F08C4578} + {895C2D33-E08D-B1BA-BB36-FC4CA65090C8} @@ -445,17 +538,26 @@ JUCE Modules\juce_audio_basics\buffers + + JUCE Modules\juce_audio_basics\buffers + JUCE Modules\juce_audio_basics\buffers - - JUCE Modules\juce_audio_basics\effects + + JUCE Modules\juce_audio_basics\midi\ump + + + JUCE Modules\juce_audio_basics\midi\ump - - JUCE Modules\juce_audio_basics\effects + + JUCE Modules\juce_audio_basics\midi\ump - - JUCE Modules\juce_audio_basics\effects + + JUCE Modules\juce_audio_basics\midi\ump + + + JUCE Modules\juce_audio_basics\midi\ump JUCE Modules\juce_audio_basics\midi @@ -529,6 +631,24 @@ JUCE Modules\juce_audio_basics\synthesisers + + JUCE Modules\juce_audio_basics\utilities + + + JUCE Modules\juce_audio_basics\utilities + + + JUCE Modules\juce_audio_basics\utilities + + + JUCE Modules\juce_audio_basics\utilities + + + JUCE Modules\juce_audio_basics\utilities + + + JUCE Modules\juce_audio_basics\utilities + JUCE Modules\juce_audio_basics @@ -544,12 +664,180 @@ JUCE Modules\juce_audio_devices\audio_io - + + JUCE Modules\juce_audio_devices\midi_io\ump + + JUCE Modules\juce_audio_devices\midi_io - + JUCE Modules\juce_audio_devices\midi_io + + JUCE Modules\juce_audio_devices\native\oboe\src\aaudio + + + JUCE Modules\juce_audio_devices\native\oboe\src\aaudio + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\fifo + + + JUCE Modules\juce_audio_devices\native\oboe\src\fifo + + + JUCE Modules\juce_audio_devices\native\oboe\src\fifo + + + JUCE Modules\juce_audio_devices\native\oboe\src\fifo + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph\resampler + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph\resampler + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph\resampler + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph\resampler + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph\resampler + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph\resampler + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph\resampler + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph\resampler + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\opensles + + + JUCE Modules\juce_audio_devices\native\oboe\src\opensles + + + JUCE Modules\juce_audio_devices\native\oboe\src\opensles + + + JUCE Modules\juce_audio_devices\native\oboe\src\opensles + + + JUCE Modules\juce_audio_devices\native\oboe\src\opensles + + + JUCE Modules\juce_audio_devices\native\oboe\src\opensles + + + JUCE Modules\juce_audio_devices\native\oboe\src\opensles + JUCE Modules\juce_audio_devices\native @@ -568,6 +856,9 @@ JUCE Modules\juce_audio_devices\native + + JUCE Modules\juce_audio_devices\native + JUCE Modules\juce_audio_devices\native @@ -577,7 +868,7 @@ JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -649,71 +940,74 @@ JUCE Modules\juce_audio_formats\codecs\flac\libFLAC - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib + + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib JUCE Modules\juce_audio_formats\codecs\oggvorbis @@ -775,89 +1069,89 @@ JUCE Modules\juce_audio_formats - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_plugin_client\utility - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_plugin_client - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_plugin_client - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\thread\source - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting - - JUCE Modules\juce_audio_plugin_client\Standalone + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting - - JUCE Modules\juce_audio_plugin_client\utility + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst - - JUCE Modules\juce_audio_plugin_client\VST + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst - - JUCE Modules\juce_audio_plugin_client\VST + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst - - JUCE Modules\juce_audio_plugin_client + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst - - JUCE Modules\juce_audio_plugin_client + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst - - JUCE Modules\juce_audio_processors\format + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst - - JUCE Modules\juce_audio_processors\format + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst JUCE Modules\juce_audio_processors\format_types @@ -865,6 +1159,9 @@ JUCE Modules\juce_audio_processors\format_types + + JUCE Modules\juce_audio_processors\format_types + JUCE Modules\juce_audio_processors\format_types @@ -883,6 +1180,9 @@ JUCE Modules\juce_audio_processors\processors + + JUCE Modules\juce_audio_processors\processors + JUCE Modules\juce_audio_processors\processors @@ -898,12 +1198,33 @@ JUCE Modules\juce_audio_processors\scanning - + + JUCE Modules\juce_audio_processors\utilities + + + JUCE Modules\juce_audio_processors\utilities + + + JUCE Modules\juce_audio_processors\utilities + + + JUCE Modules\juce_audio_processors\utilities + + JUCE Modules\juce_audio_processors\utilities JUCE Modules\juce_audio_processors\utilities + + JUCE Modules\juce_audio_processors\utilities + + + JUCE Modules\juce_audio_processors\utilities + + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors @@ -928,9 +1249,15 @@ JUCE Modules\juce_audio_utils\gui + + JUCE Modules\juce_audio_utils\gui + JUCE Modules\juce_audio_utils\gui + + JUCE Modules\juce_audio_utils\gui + JUCE Modules\juce_audio_utils\native @@ -976,6 +1303,9 @@ JUCE Modules\juce_core\containers + + JUCE Modules\juce_core\containers + JUCE Modules\juce_core\containers @@ -985,9 +1315,18 @@ JUCE Modules\juce_core\containers + + JUCE Modules\juce_core\containers + JUCE Modules\juce_core\containers + + JUCE Modules\juce_core\containers + + + JUCE Modules\juce_core\containers + JUCE Modules\juce_core\containers @@ -1009,6 +1348,9 @@ JUCE Modules\juce_core\files + + JUCE Modules\juce_core\files + JUCE Modules\juce_core\files @@ -1036,16 +1378,19 @@ JUCE Modules\juce_core\maths + + JUCE Modules\juce_core\memory + JUCE Modules\juce_core\memory - + JUCE Modules\juce_core\misc - + JUCE Modules\juce_core\misc - + JUCE Modules\juce_core\misc @@ -1054,6 +1399,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -1105,6 +1453,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -1210,6 +1561,9 @@ JUCE Modules\juce_core\threads + + JUCE Modules\juce_core\threads + JUCE Modules\juce_core\time @@ -1318,6 +1672,9 @@ JUCE Modules\juce_data_structures\values + + JUCE Modules\juce_data_structures\values + JUCE Modules\juce_data_structures\values @@ -1327,6 +1684,12 @@ JUCE Modules\juce_data_structures + + JUCE Modules\juce_dsp\containers + + + JUCE Modules\juce_dsp\containers + JUCE Modules\juce_dsp\containers @@ -1336,6 +1699,9 @@ JUCE Modules\juce_dsp\frequency + + JUCE Modules\juce_dsp\frequency + JUCE Modules\juce_dsp\frequency @@ -1345,6 +1711,9 @@ JUCE Modules\juce_dsp\frequency + + JUCE Modules\juce_dsp\maths + JUCE Modules\juce_dsp\maths @@ -1366,21 +1735,60 @@ JUCE Modules\juce_dsp\native + + JUCE Modules\juce_dsp\processors + + + JUCE Modules\juce_dsp\processors + + + JUCE Modules\juce_dsp\processors + JUCE Modules\juce_dsp\processors JUCE Modules\juce_dsp\processors + + JUCE Modules\juce_dsp\processors + JUCE Modules\juce_dsp\processors - + JUCE Modules\juce_dsp\processors JUCE Modules\juce_dsp\processors + + JUCE Modules\juce_dsp\processors + + + JUCE Modules\juce_dsp\processors + + + JUCE Modules\juce_dsp\processors + + + JUCE Modules\juce_dsp\widgets + + + JUCE Modules\juce_dsp\widgets + + + JUCE Modules\juce_dsp\widgets + + + JUCE Modules\juce_dsp\widgets + + + JUCE Modules\juce_dsp\widgets + + + JUCE Modules\juce_dsp\widgets + JUCE Modules\juce_dsp @@ -1405,6 +1813,9 @@ JUCE Modules\juce_events\interprocess + + JUCE Modules\juce_events\interprocess + JUCE Modules\juce_events\messages @@ -1429,6 +1840,9 @@ JUCE Modules\juce_events\native + + JUCE Modules\juce_events\native + JUCE Modules\juce_events\native @@ -1507,6 +1921,9 @@ JUCE Modules\juce_graphics\geometry + + JUCE Modules\juce_graphics\geometry + JUCE Modules\juce_graphics\image_formats\jpglib @@ -1762,6 +2179,9 @@ JUCE Modules\juce_graphics + + JUCE Modules\juce_gui_basics\accessibility + JUCE Modules\juce_gui_basics\application @@ -1810,12 +2230,18 @@ JUCE Modules\juce_gui_basics\components - + JUCE Modules\juce_gui_basics\components JUCE Modules\juce_gui_basics\components + + JUCE Modules\juce_gui_basics\desktop + + + JUCE Modules\juce_gui_basics\desktop + JUCE Modules\juce_gui_basics\drawables @@ -1912,9 +2338,6 @@ JUCE Modules\juce_gui_basics\layout - - JUCE Modules\juce_gui_basics\layout - JUCE Modules\juce_gui_basics\layout @@ -1987,6 +2410,9 @@ JUCE Modules\juce_gui_basics\misc + + JUCE Modules\juce_gui_basics\misc + JUCE Modules\juce_gui_basics\misc @@ -2011,6 +2437,33 @@ JUCE Modules\juce_gui_basics\mouse + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\x11 + + + JUCE Modules\juce_gui_basics\native\x11 + + + JUCE Modules\juce_gui_basics\native\x11 + JUCE Modules\juce_gui_basics\native @@ -2038,13 +2491,7 @@ JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native - - - JUCE Modules\juce_gui_basics\native - - + JUCE Modules\juce_gui_basics\native @@ -2101,6 +2548,9 @@ JUCE Modules\juce_gui_basics\properties + + JUCE Modules\juce_gui_basics\properties + JUCE Modules\juce_gui_basics\properties @@ -2275,6 +2725,9 @@ JUCE Modules\juce_gui_extra\native + + JUCE Modules\juce_gui_extra\native + JUCE Modules\juce_gui_extra\native @@ -2287,6 +2740,12 @@ JUCE Modules\juce_gui_extra + + JUCE Modules\juce_opengl\opengl + + + JUCE Modules\juce_opengl\opengl + JUCE Modules\juce_opengl\opengl @@ -2415,33 +2874,66 @@ JUCE Modules\juce_audio_basics\buffers + + JUCE Modules\juce_audio_basics\buffers + JUCE Modules\juce_audio_basics\buffers JUCE Modules\juce_audio_basics\buffers - - JUCE Modules\juce_audio_basics\effects + + JUCE Modules\juce_audio_basics\midi\ump - - JUCE Modules\juce_audio_basics\effects + + JUCE Modules\juce_audio_basics\midi\ump - - JUCE Modules\juce_audio_basics\effects + + JUCE Modules\juce_audio_basics\midi\ump - - JUCE Modules\juce_audio_basics\effects + + JUCE Modules\juce_audio_basics\midi\ump - - JUCE Modules\juce_audio_basics\effects + + JUCE Modules\juce_audio_basics\midi\ump - - JUCE Modules\juce_audio_basics\effects + + JUCE Modules\juce_audio_basics\midi\ump + + + JUCE Modules\juce_audio_basics\midi\ump + + + JUCE Modules\juce_audio_basics\midi\ump + + + JUCE Modules\juce_audio_basics\midi\ump + + + JUCE Modules\juce_audio_basics\midi\ump + + + JUCE Modules\juce_audio_basics\midi\ump + + + JUCE Modules\juce_audio_basics\midi\ump + + + JUCE Modules\juce_audio_basics\midi\ump + + + JUCE Modules\juce_audio_basics\midi\ump + + + JUCE Modules\juce_audio_basics\midi\ump JUCE Modules\juce_audio_basics\midi + + JUCE Modules\juce_audio_basics\midi + JUCE Modules\juce_audio_basics\midi @@ -2520,14 +3012,32 @@ JUCE Modules\juce_audio_basics\synthesisers - - JUCE Modules\juce_audio_basics + + JUCE Modules\juce_audio_basics\utilities - - JUCE Modules\juce_audio_basics + + JUCE Modules\juce_audio_basics\utilities - - JUCE Modules\juce_audio_devices\audio_io + + JUCE Modules\juce_audio_basics\utilities + + + JUCE Modules\juce_audio_basics\utilities + + + JUCE Modules\juce_audio_basics\utilities + + + JUCE Modules\juce_audio_basics\utilities + + + JUCE Modules\juce_audio_basics\utilities + + + JUCE Modules\juce_audio_basics + + + JUCE Modules\juce_audio_devices\audio_io JUCE Modules\juce_audio_devices\audio_io @@ -2538,19 +3048,223 @@ JUCE Modules\juce_audio_devices\audio_io - + + JUCE Modules\juce_audio_devices\midi_io\ump + + + JUCE Modules\juce_audio_devices\midi_io\ump + + JUCE Modules\juce_audio_devices\midi_io JUCE Modules\juce_audio_devices\midi_io - - JUCE Modules\juce_audio_devices\midi_io + + JUCE Modules\juce_audio_devices\native\oboe\include\oboe - + + JUCE Modules\juce_audio_devices\native\oboe\include\oboe + + + JUCE Modules\juce_audio_devices\native\oboe\include\oboe + + + JUCE Modules\juce_audio_devices\native\oboe\include\oboe + + + JUCE Modules\juce_audio_devices\native\oboe\include\oboe + + + JUCE Modules\juce_audio_devices\native\oboe\include\oboe + + + JUCE Modules\juce_audio_devices\native\oboe\include\oboe + + + JUCE Modules\juce_audio_devices\native\oboe\include\oboe + + + JUCE Modules\juce_audio_devices\native\oboe\include\oboe + + + JUCE Modules\juce_audio_devices\native\oboe\include\oboe + + + JUCE Modules\juce_audio_devices\native\oboe\include\oboe + + + JUCE Modules\juce_audio_devices\native\oboe\src\aaudio + + + JUCE Modules\juce_audio_devices\native\oboe\src\aaudio + + + JUCE Modules\juce_audio_devices\native\oboe\src\aaudio + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\common + + + JUCE Modules\juce_audio_devices\native\oboe\src\fifo + + + JUCE Modules\juce_audio_devices\native\oboe\src\fifo + + + JUCE Modules\juce_audio_devices\native\oboe\src\fifo + + + JUCE Modules\juce_audio_devices\native\oboe\src\fifo + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph\resampler + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph\resampler + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph\resampler + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph\resampler + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph\resampler + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph\resampler + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph\resampler + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph\resampler + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph\resampler + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph\resampler + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\flowgraph + + + JUCE Modules\juce_audio_devices\native\oboe\src\opensles + + + JUCE Modules\juce_audio_devices\native\oboe\src\opensles + + + JUCE Modules\juce_audio_devices\native\oboe\src\opensles + + + JUCE Modules\juce_audio_devices\native\oboe\src\opensles + + + JUCE Modules\juce_audio_devices\native\oboe\src\opensles + + + JUCE Modules\juce_audio_devices\native\oboe\src\opensles + + + JUCE Modules\juce_audio_devices\native\oboe\src\opensles + + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -2562,9 +3276,6 @@ JUCE Modules\juce_audio_devices - - JUCE Modules\juce_audio_devices - JUCE Modules\juce_audio_formats\codecs\flac\libFLAC\include\private @@ -2661,131 +3372,131 @@ JUCE Modules\juce_audio_formats\codecs\flac - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\books\coupled + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\books\coupled - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\books\coupled + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\books\coupled - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\books\floor + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\books\floor - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\books\uncoupled + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\books\uncoupled - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\modes + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\modes - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\modes + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\modes - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\modes + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\modes - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\modes + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\modes - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\modes + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\modes - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\modes + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\modes - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\modes + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\modes - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\modes + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\modes - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\modes + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\modes - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\modes + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\modes - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\modes + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\modes - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\modes + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\modes - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\modes + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\modes - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\modes + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\modes - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\modes + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\modes - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\modes + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\modes - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\modes + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\modes - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\modes + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\modes - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib\modes + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib\modes - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib - - JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.2\lib + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7\lib JUCE Modules\juce_audio_formats\codecs\oggvorbis @@ -2793,6 +3504,9 @@ JUCE Modules\juce_audio_formats\codecs\oggvorbis + + JUCE Modules\juce_audio_formats\codecs\oggvorbis + JUCE Modules\juce_audio_formats\codecs\oggvorbis @@ -2859,155 +3573,233 @@ JUCE Modules\juce_audio_formats - - JUCE Modules\juce_audio_formats + + JUCE Modules\juce_audio_plugin_client\utility - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_plugin_client\utility - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_plugin_client\utility - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_plugin_client\utility - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_plugin_client\utility - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_plugin_client\utility - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_plugin_client\utility - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_plugin_client - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\thread\include - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_plugin_client\AU\CoreAudioUtilityClasses + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\gui - - JUCE Modules\juce_audio_plugin_client\Standalone + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\gui - - JUCE Modules\juce_audio_plugin_client\utility + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst - - JUCE Modules\juce_audio_plugin_client\utility + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst - - JUCE Modules\juce_audio_plugin_client\utility + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst - - JUCE Modules\juce_audio_plugin_client\utility + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst - - JUCE Modules\juce_audio_plugin_client\utility + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst - - JUCE Modules\juce_audio_plugin_client\utility + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst - - JUCE Modules\juce_audio_plugin_client\utility + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst - - JUCE Modules\juce_audio_plugin_client\VST + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst - - JUCE Modules\juce_audio_plugin_client + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst - - JUCE Modules\juce_audio_plugin_client + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst - - JUCE Modules\juce_audio_processors\format + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst - - JUCE Modules\juce_audio_processors\format + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\vst + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst + + + JUCE Modules\juce_audio_processors\format_types JUCE Modules\juce_audio_processors\format_types @@ -3027,9 +3819,6 @@ JUCE Modules\juce_audio_processors\format_types - - JUCE Modules\juce_audio_processors\format_types - JUCE Modules\juce_audio_processors\format_types @@ -3045,6 +3834,9 @@ JUCE Modules\juce_audio_processors\processors + + JUCE Modules\juce_audio_processors\processors + JUCE Modules\juce_audio_processors\processors @@ -3054,9 +3846,15 @@ JUCE Modules\juce_audio_processors\processors + + JUCE Modules\juce_audio_processors\processors + JUCE Modules\juce_audio_processors\processors + + JUCE Modules\juce_audio_processors\processors + JUCE Modules\juce_audio_processors\processors @@ -3087,10 +3885,25 @@ JUCE Modules\juce_audio_processors\utilities - - JUCE Modules\juce_audio_processors + + JUCE Modules\juce_audio_processors\utilities + + + JUCE Modules\juce_audio_processors\utilities + + + JUCE Modules\juce_audio_processors\utilities + + + JUCE Modules\juce_audio_processors\utilities + + + JUCE Modules\juce_audio_processors\utilities + + + JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors @@ -3120,9 +3933,15 @@ JUCE Modules\juce_audio_utils\gui + + JUCE Modules\juce_audio_utils\gui + JUCE Modules\juce_audio_utils\gui + + JUCE Modules\juce_audio_utils\gui + JUCE Modules\juce_audio_utils\players @@ -3132,9 +3951,6 @@ JUCE Modules\juce_audio_utils - - JUCE Modules\juce_audio_utils - JUCE Modules\juce_core\containers @@ -3144,6 +3960,9 @@ JUCE Modules\juce_core\containers + + JUCE Modules\juce_core\containers + JUCE Modules\juce_core\containers @@ -3174,6 +3993,9 @@ JUCE Modules\juce_core\containers + + JUCE Modules\juce_core\containers + JUCE Modules\juce_core\containers @@ -3204,6 +4026,9 @@ JUCE Modules\juce_core\files + + JUCE Modules\juce_core\files + JUCE Modules\juce_core\files @@ -3243,6 +4068,9 @@ JUCE Modules\juce_core\maths + + JUCE Modules\juce_core\memory + JUCE Modules\juce_core\memory @@ -3255,6 +4083,9 @@ JUCE Modules\juce_core\memory + + JUCE Modules\juce_core\memory + JUCE Modules\juce_core\memory @@ -3270,6 +4101,9 @@ JUCE Modules\juce_core\memory + + JUCE Modules\juce_core\memory + JUCE Modules\juce_core\memory @@ -3282,13 +4116,16 @@ JUCE Modules\juce_core\memory - + JUCE Modules\juce_core\misc - + JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc @@ -3303,10 +4140,16 @@ JUCE Modules\juce_core\native - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native @@ -3363,6 +4206,9 @@ JUCE Modules\juce_core\system + + JUCE Modules\juce_core\system + JUCE Modules\juce_core\system @@ -3480,6 +4326,9 @@ JUCE Modules\juce_core\unit_tests + + JUCE Modules\juce_core\unit_tests + JUCE Modules\juce_core\xml @@ -3531,9 +4380,6 @@ JUCE Modules\juce_core - - JUCE Modules\juce_core - JUCE Modules\juce_cryptography\encryption @@ -3555,9 +4401,6 @@ JUCE Modules\juce_cryptography - - JUCE Modules\juce_cryptography - JUCE Modules\juce_data_structures\app_properties @@ -3579,24 +4422,27 @@ JUCE Modules\juce_data_structures\values - + JUCE Modules\juce_data_structures\values - + JUCE Modules\juce_data_structures\values JUCE Modules\juce_data_structures - - JUCE Modules\juce_data_structures - JUCE Modules\juce_dsp\containers + + JUCE Modules\juce_dsp\containers + JUCE Modules\juce_dsp\containers + + JUCE Modules\juce_dsp\containers + JUCE Modules\juce_dsp\filter_design @@ -3612,6 +4458,9 @@ JUCE Modules\juce_dsp\maths + + JUCE Modules\juce_dsp\maths + JUCE Modules\juce_dsp\maths @@ -3639,13 +4488,19 @@ JUCE Modules\juce_dsp\native - + + JUCE Modules\juce_dsp\processors + + + JUCE Modules\juce_dsp\processors + + JUCE Modules\juce_dsp\processors JUCE Modules\juce_dsp\processors - + JUCE Modules\juce_dsp\processors @@ -3654,13 +4509,13 @@ JUCE Modules\juce_dsp\processors - + JUCE Modules\juce_dsp\processors - + JUCE Modules\juce_dsp\processors - + JUCE Modules\juce_dsp\processors @@ -3675,19 +4530,46 @@ JUCE Modules\juce_dsp\processors - - JUCE Modules\juce_dsp\processors - JUCE Modules\juce_dsp\processors - + JUCE Modules\juce_dsp\processors - - JUCE Modules\juce_dsp + + JUCE Modules\juce_dsp\widgets + + + JUCE Modules\juce_dsp\widgets + + + JUCE Modules\juce_dsp\widgets + + + JUCE Modules\juce_dsp\widgets + + + JUCE Modules\juce_dsp\widgets + + + JUCE Modules\juce_dsp\widgets + + + JUCE Modules\juce_dsp\widgets - + + JUCE Modules\juce_dsp\widgets + + + JUCE Modules\juce_dsp\widgets + + + JUCE Modules\juce_dsp\widgets + + + JUCE Modules\juce_dsp\widgets + + JUCE Modules\juce_dsp @@ -3714,6 +4596,9 @@ JUCE Modules\juce_events\interprocess + + JUCE Modules\juce_events\interprocess + JUCE Modules\juce_events\messages @@ -3747,6 +4632,9 @@ JUCE Modules\juce_events\native + + JUCE Modules\juce_events\native + JUCE Modules\juce_events\native @@ -3762,9 +4650,6 @@ JUCE Modules\juce_events - - JUCE Modules\juce_events - JUCE Modules\juce_graphics\colour @@ -3897,6 +4782,9 @@ JUCE Modules\juce_graphics\image_formats\pnglib + + JUCE Modules\juce_graphics\image_formats\pnglib + JUCE Modules\juce_graphics\image_formats\pnglib @@ -3918,6 +4806,9 @@ JUCE Modules\juce_graphics\images + + JUCE Modules\juce_graphics\images + JUCE Modules\juce_graphics\native @@ -3939,8 +4830,32 @@ JUCE Modules\juce_graphics - - JUCE Modules\juce_graphics + + JUCE Modules\juce_gui_basics\accessibility\enums + + + JUCE Modules\juce_gui_basics\accessibility\enums + + + JUCE Modules\juce_gui_basics\accessibility\enums + + + JUCE Modules\juce_gui_basics\accessibility\interfaces + + + JUCE Modules\juce_gui_basics\accessibility\interfaces + + + JUCE Modules\juce_gui_basics\accessibility\interfaces + + + JUCE Modules\juce_gui_basics\accessibility\interfaces + + + JUCE Modules\juce_gui_basics\accessibility + + + JUCE Modules\juce_gui_basics\accessibility JUCE Modules\juce_gui_basics\application @@ -3996,12 +4911,21 @@ JUCE Modules\juce_gui_basics\components - + + JUCE Modules\juce_gui_basics\components + + JUCE Modules\juce_gui_basics\components JUCE Modules\juce_gui_basics\components + + JUCE Modules\juce_gui_basics\desktop + + + JUCE Modules\juce_gui_basics\desktop + JUCE Modules\juce_gui_basics\drawables @@ -4191,6 +5115,9 @@ JUCE Modules\juce_gui_basics\misc + + JUCE Modules\juce_gui_basics\misc + JUCE Modules\juce_gui_basics\misc @@ -4224,6 +5151,9 @@ JUCE Modules\juce_gui_basics\mouse + + JUCE Modules\juce_gui_basics\mouse + JUCE Modules\juce_gui_basics\mouse @@ -4233,12 +5163,75 @@ JUCE Modules\juce_gui_basics\mouse - - JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native\x11 + + + JUCE Modules\juce_gui_basics\native\x11 JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + JUCE Modules\juce_gui_basics\positioning @@ -4269,6 +5262,9 @@ JUCE Modules\juce_gui_basics\properties + + JUCE Modules\juce_gui_basics\properties + JUCE Modules\juce_gui_basics\properties @@ -4338,6 +5334,9 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -4356,9 +5355,6 @@ JUCE Modules\juce_gui_basics - - JUCE Modules\juce_gui_basics - JUCE Modules\juce_gui_extra\code_editor @@ -4389,6 +5385,9 @@ JUCE Modules\juce_gui_extra\embedding + + JUCE Modules\juce_gui_extra\embedding + JUCE Modules\juce_gui_extra\embedding @@ -4437,10 +5436,10 @@ JUCE Modules\juce_gui_extra\native - - JUCE Modules\juce_gui_extra + + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra @@ -4455,9 +5454,6 @@ JUCE Modules\juce_opengl\geometry - - JUCE Modules\juce_opengl\native - JUCE Modules\juce_opengl\native @@ -4476,6 +5472,15 @@ JUCE Modules\juce_opengl\native + + JUCE Modules\juce_opengl\opengl + + + JUCE Modules\juce_opengl\opengl + + + JUCE Modules\juce_opengl\opengl + JUCE Modules\juce_opengl\opengl @@ -4503,21 +5508,27 @@ JUCE Modules\juce_opengl\opengl + + JUCE Modules\juce_opengl\opengl + JUCE Modules\juce_opengl\utils JUCE Modules\juce_opengl - - JUCE Modules\juce_opengl - JUCE Modules\juce_video\capture JUCE Modules\juce_video\native + + JUCE Modules\juce_video\native + + + JUCE Modules\juce_video\native + JUCE Modules\juce_video\native @@ -4527,6 +5538,9 @@ JUCE Modules\juce_video\native + + JUCE Modules\juce_video\native + JUCE Modules\juce_video\native @@ -4536,9 +5550,6 @@ JUCE Modules\juce_video - - JUCE Modules\juce_video - JUCE Library Code @@ -4548,6 +5559,9 @@ JUCE Library Code + + JUCE Library Code + @@ -4574,12 +5588,51 @@ Temper\Assets + + JUCE Modules\juce_audio_devices\native\oboe + + + JUCE Modules\juce_audio_devices\native\oboe + JUCE Modules\juce_audio_formats\codecs\flac + + JUCE Modules\juce_audio_formats\codecs\oggvorbis\libvorbis-1.3.7 + JUCE Modules\juce_audio_formats\codecs\oggvorbis + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK + + + JUCE Modules\juce_core\native\java + JUCE Modules\juce_graphics\image_formats\jpglib @@ -4587,9 +5640,4 @@ JUCE Modules\juce_graphics\image_formats\pnglib - - - JUCE Library Code - - diff --git a/Builds/VisualStudio2017/Temper_StandalonePlugin.vcxproj b/Builds/VisualStudio2017/Temper_StandalonePlugin.vcxproj index 3b92f0c8..cdbe3b04 100644 --- a/Builds/VisualStudio2017/Temper_StandalonePlugin.vcxproj +++ b/Builds/VisualStudio2017/Temper_StandalonePlugin.vcxproj @@ -31,8 +31,6 @@ {1511B662-19BF-4E37-E98C-33640F16251F} - v141 - 10.0.16299.0 false false v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -49,8 +47,7 @@ false false v141 - v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -58,7 +55,7 @@ false true v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -66,8 +63,7 @@ false true v141 - v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -75,7 +71,7 @@ false true v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -83,8 +79,7 @@ false true v141 - v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -93,10 +88,6 @@ Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform"/> - - v141 - 10.0.16299.0 - <_ProjectFileVersion>10.0.30319.1 .exe @@ -130,8 +121,6 @@ Temper (x64)(Demo) true $(LibraryPath);.\Demo\Shared Code - v141 - 10.0.16299.0 @@ -144,18 +133,18 @@ Disabled ProgramDatabase - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper.pdb Level4 true true - stdcpp14 + stdcpp20 _DEBUG;%(PreprocessorDefinitions) @@ -190,18 +179,18 @@ Disabled ProgramDatabase - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper (x64).pdb Level4 true true - stdcpp14 + stdcpp20 _DEBUG;%(PreprocessorDefinitions) @@ -234,18 +223,18 @@ Full - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper.pdb Level4 true true - stdcpp14 + stdcpp20 NDEBUG;%(PreprocessorDefinitions) @@ -261,6 +250,7 @@ true true true + UseLinkTimeCodeGeneration Temper.lib;%(AdditionalDependencies) @@ -281,18 +271,18 @@ Full - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper (x64).pdb Level4 true true - stdcpp14 + stdcpp20 NDEBUG;%(PreprocessorDefinitions) @@ -307,6 +297,7 @@ true true true + UseLinkTimeCodeGeneration Temper (x64).lib;%(AdditionalDependencies) @@ -327,18 +318,18 @@ Full - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;TEMPER_DEMO_BUILD=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;TEMPER_DEMO_BUILD=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper (Demo).pdb Level4 true true - stdcpp14 + stdcpp20 NDEBUG;%(PreprocessorDefinitions) @@ -354,6 +345,7 @@ true true true + UseLinkTimeCodeGeneration Temper (Demo).lib;%(AdditionalDependencies) @@ -374,18 +366,18 @@ Full - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;TEMPER_DEMO_BUILD=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;TEMPER_DEMO_BUILD=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper (x64)(Demo).pdb Level4 true true - stdcpp14 + stdcpp20 NDEBUG;%(PreprocessorDefinitions) @@ -400,6 +392,7 @@ true true true + UseLinkTimeCodeGeneration Temper (x64)(Demo).lib;%(AdditionalDependencies) @@ -411,9 +404,17 @@ + + true + + + true + - + + + diff --git a/Builds/VisualStudio2017/Temper_StandalonePlugin.vcxproj.filters b/Builds/VisualStudio2017/Temper_StandalonePlugin.vcxproj.filters index 3de3310a..0f0f6fed 100644 --- a/Builds/VisualStudio2017/Temper_StandalonePlugin.vcxproj.filters +++ b/Builds/VisualStudio2017/Temper_StandalonePlugin.vcxproj.filters @@ -2,16 +2,35 @@ + + {725C0EA8-9736-764D-81E6-01695B6B00B3} + + + {BA0A76FA-458F-0B1C-02E9-ECFBF81140EC} + + + {FE955B6B-68AC-AA07-70D8-2413F6DB65C8} + {7ED5A90E-41AF-A1EF-659B-37CEEAB9BA61} + + JUCE Modules\juce_audio_plugin_client\Standalone + + + JUCE Modules\juce_audio_plugin_client + JUCE Library Code - + + + JUCE Modules\juce_audio_plugin_client\Standalone + + JUCE Library Code diff --git a/Builds/VisualStudio2017/Temper_VST.vcxproj b/Builds/VisualStudio2017/Temper_VST.vcxproj index 7a7ebb15..eaf7c512 100644 --- a/Builds/VisualStudio2017/Temper_VST.vcxproj +++ b/Builds/VisualStudio2017/Temper_VST.vcxproj @@ -31,8 +31,6 @@ {A5024CB7-A1BE-4B03-D444-20B1B619F68C} - v141 - 10.0.16299.0 false false v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -49,8 +47,7 @@ false false v141 - v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -58,7 +55,7 @@ false true v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -66,8 +63,7 @@ false true v141 - v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -75,7 +71,7 @@ false true v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -83,8 +79,7 @@ false true v141 - v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -93,10 +88,6 @@ Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform"/> - - v141 - 10.0.16299.0 - <_ProjectFileVersion>10.0.30319.1 .dll @@ -130,8 +121,6 @@ Temper (x64)(Demo) true $(LibraryPath);.\Demo\Shared Code - v141 - 10.0.16299.0 @@ -144,18 +133,18 @@ Disabled ProgramDatabase - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper.pdb Level4 true true - stdcpp14 + stdcpp20 _DEBUG;%(PreprocessorDefinitions) @@ -190,18 +179,18 @@ Disabled ProgramDatabase - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper (x64).pdb Level4 true true - stdcpp14 + stdcpp20 _DEBUG;%(PreprocessorDefinitions) @@ -234,18 +223,18 @@ Full - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper.pdb Level4 true true - stdcpp14 + stdcpp20 NDEBUG;%(PreprocessorDefinitions) @@ -261,6 +250,7 @@ true true true + UseLinkTimeCodeGeneration Temper.lib;%(AdditionalDependencies) @@ -281,18 +271,18 @@ Full - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper (x64).pdb Level4 true true - stdcpp14 + stdcpp20 NDEBUG;%(PreprocessorDefinitions) @@ -307,6 +297,7 @@ true true true + UseLinkTimeCodeGeneration Temper (x64).lib;%(AdditionalDependencies) @@ -327,18 +318,18 @@ Full - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;TEMPER_DEMO_BUILD=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;TEMPER_DEMO_BUILD=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper (Demo).pdb Level4 true true - stdcpp14 + stdcpp20 NDEBUG;%(PreprocessorDefinitions) @@ -354,6 +345,7 @@ true true true + UseLinkTimeCodeGeneration Temper (Demo).lib;%(AdditionalDependencies) @@ -374,18 +366,18 @@ Full - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;TEMPER_DEMO_BUILD=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;TEMPER_DEMO_BUILD=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=1;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper (x64)(Demo).pdb Level4 true true - stdcpp14 + stdcpp20 NDEBUG;%(PreprocessorDefinitions) @@ -400,6 +392,7 @@ true true true + UseLinkTimeCodeGeneration Temper (x64)(Demo).lib;%(AdditionalDependencies) @@ -411,6 +404,12 @@ + + true + + + true + diff --git a/Builds/VisualStudio2017/Temper_VST.vcxproj.filters b/Builds/VisualStudio2017/Temper_VST.vcxproj.filters index 056b9af3..488094da 100644 --- a/Builds/VisualStudio2017/Temper_VST.vcxproj.filters +++ b/Builds/VisualStudio2017/Temper_VST.vcxproj.filters @@ -2,11 +2,29 @@ + + {AA010709-292F-011A-F2AB-0D1B4A7B8328} + + + {BA0A76FA-458F-0B1C-02E9-ECFBF81140EC} + + + {FE955B6B-68AC-AA07-70D8-2413F6DB65C8} + {7ED5A90E-41AF-A1EF-659B-37CEEAB9BA61} + + JUCE Modules\juce_audio_plugin_client\VST + + + JUCE Modules\juce_audio_plugin_client\VST + + + JUCE Modules\juce_audio_plugin_client + JUCE Library Code diff --git a/Builds/VisualStudio2017/Temper_VST3.vcxproj b/Builds/VisualStudio2017/Temper_VST3.vcxproj index 6034ec5a..cbd8fa95 100644 --- a/Builds/VisualStudio2017/Temper_VST3.vcxproj +++ b/Builds/VisualStudio2017/Temper_VST3.vcxproj @@ -31,8 +31,6 @@ {E387E7A1-3E3B-4BD1-C6D3-C0970595C243} - v141 - 10.0.16299.0 false false v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -49,8 +47,7 @@ false false v141 - v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -58,7 +55,7 @@ false true v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -66,8 +63,7 @@ false true v141 - v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -75,7 +71,7 @@ false true v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -83,8 +79,7 @@ false true v141 - v141 - 10.0.16299.0 + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) @@ -93,10 +88,6 @@ Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform"/> - - v141 - 10.0.16299.0 - <_ProjectFileVersion>10.0.30319.1 .vst3 @@ -130,8 +121,6 @@ Temper (x64)(Demo) true $(LibraryPath);.\Demo\Shared Code - v141 - 10.0.16299.0 @@ -144,18 +133,18 @@ Disabled ProgramDatabase - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper.pdb Level4 true true - stdcpp14 + stdcpp20 _DEBUG;%(PreprocessorDefinitions) @@ -190,18 +179,18 @@ Disabled ProgramDatabase - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper (x64).pdb Level4 true true - stdcpp14 + stdcpp20 _DEBUG;%(PreprocessorDefinitions) @@ -234,18 +223,18 @@ Full - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper.pdb Level4 true true - stdcpp14 + stdcpp20 NDEBUG;%(PreprocessorDefinitions) @@ -261,6 +250,7 @@ true true true + UseLinkTimeCodeGeneration Temper.lib;%(AdditionalDependencies) @@ -281,18 +271,18 @@ Full - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper (x64).pdb Level4 true true - stdcpp14 + stdcpp20 NDEBUG;%(PreprocessorDefinitions) @@ -307,6 +297,7 @@ true true true + UseLinkTimeCodeGeneration Temper (x64).lib;%(AdditionalDependencies) @@ -327,18 +318,18 @@ Full - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;TEMPER_DEMO_BUILD=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;TEMPER_DEMO_BUILD=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper (Demo).pdb Level4 true true - stdcpp14 + stdcpp20 NDEBUG;%(PreprocessorDefinitions) @@ -354,6 +345,7 @@ true true true + UseLinkTimeCodeGeneration Temper (Demo).lib;%(AdditionalDependencies) @@ -374,18 +366,18 @@ Full - ..\..\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;TEMPER_DEMO_BUILD=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions) + ..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;../../Include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;TEMPER_DEMO_BUILD=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.3;JUCE_APP_VERSION_HEX=0x10003;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDLL true - + NotUsing $(IntDir)\ $(IntDir)\ - $(IntDir)\ + $(IntDir)\Temper (x64)(Demo).pdb Level4 true true - stdcpp14 + stdcpp20 NDEBUG;%(PreprocessorDefinitions) @@ -400,6 +392,7 @@ true true true + UseLinkTimeCodeGeneration Temper (x64)(Demo).lib;%(AdditionalDependencies) @@ -411,6 +404,12 @@ + + true + + + true + diff --git a/Builds/VisualStudio2017/Temper_VST3.vcxproj.filters b/Builds/VisualStudio2017/Temper_VST3.vcxproj.filters index d8775dc7..49e2400e 100644 --- a/Builds/VisualStudio2017/Temper_VST3.vcxproj.filters +++ b/Builds/VisualStudio2017/Temper_VST3.vcxproj.filters @@ -2,11 +2,26 @@ + + {68760A18-ED41-41C7-2560-F3A65E9AD133} + + + {BA0A76FA-458F-0B1C-02E9-ECFBF81140EC} + + + {FE955B6B-68AC-AA07-70D8-2413F6DB65C8} + {7ED5A90E-41AF-A1EF-659B-37CEEAB9BA61} + + JUCE Modules\juce_audio_plugin_client\VST3 + + + JUCE Modules\juce_audio_plugin_client + JUCE Library Code diff --git a/Builds/VisualStudio2017/resources.rc b/Builds/VisualStudio2017/resources.rc index 30bc90c6..e0c4c0ed 100644 --- a/Builds/VisualStudio2017/resources.rc +++ b/Builds/VisualStudio2017/resources.rc @@ -1,3 +1,5 @@ +#pragma code_page(65001) + #ifdef JUCE_USER_DEFINED_RC_FILE #include JUCE_USER_DEFINED_RC_FILE #else diff --git a/JuceLibraryCode/AppConfig.h b/JuceLibraryCode/AppConfig.h index 66fa0354..a403a361 100644 --- a/JuceLibraryCode/AppConfig.h +++ b/JuceLibraryCode/AppConfig.h @@ -20,15 +20,17 @@ // [END_USER_CODE_SECTION] +#include "JucePluginDefines.h" + /* ============================================================================== - In accordance with the terms of the JUCE 5 End-Use License Agreement, the + In accordance with the terms of the JUCE 6 End-Use License Agreement, the JUCE Code in SECTION A cannot be removed, changed or otherwise rendered ineffective unless you have a JUCE Indie or Pro license, or are using JUCE under the GPL v3 license. - End User License Agreement: www.juce.com/juce-5-licence + End User License Agreement: www.juce.com/juce-6-licence ============================================================================== */ @@ -39,14 +41,12 @@ #define JUCE_DISPLAY_SPLASH_SCREEN 0 #endif -#ifndef JUCE_REPORT_APP_USAGE - #define JUCE_REPORT_APP_USAGE 0 -#endif - // END SECTION A #define JUCE_USE_DARK_SPLASH_SCREEN 1 +#define JUCE_PROJUCER_VERSION 0x60106 + //============================================================================== #define JUCE_MODULE_AVAILABLE_juce_audio_basics 1 #define JUCE_MODULE_AVAILABLE_juce_audio_devices 1 @@ -70,6 +70,10 @@ //============================================================================== // juce_audio_devices flags: +#ifndef JUCE_USE_WINRT_MIDI + //#define JUCE_USE_WINRT_MIDI 0 +#endif + #ifndef JUCE_ASIO //#define JUCE_ASIO 0 #endif @@ -78,10 +82,6 @@ //#define JUCE_WASAPI 1 #endif -#ifndef JUCE_WASAPI_EXCLUSIVE - //#define JUCE_WASAPI_EXCLUSIVE 0 -#endif - #ifndef JUCE_DIRECTSOUND //#define JUCE_DIRECTSOUND 1 #endif @@ -94,16 +94,20 @@ //#define JUCE_JACK 0 #endif +#ifndef JUCE_BELA + //#define JUCE_BELA 0 +#endif + #ifndef JUCE_USE_ANDROID_OBOE - //#define JUCE_USE_ANDROID_OBOE 0 + //#define JUCE_USE_ANDROID_OBOE 1 #endif -#ifndef JUCE_USE_ANDROID_OPENSLES - //#define JUCE_USE_ANDROID_OPENSLES 0 +#ifndef JUCE_USE_OBOE_STABILIZED_CALLBACK + //#define JUCE_USE_OBOE_STABILIZED_CALLBACK 0 #endif -#ifndef JUCE_USE_WINRT_MIDI - //#define JUCE_USE_WINRT_MIDI 0 +#ifndef JUCE_USE_ANDROID_OPENSLES + //#define JUCE_USE_ANDROID_OPENSLES 0 #endif #ifndef JUCE_DISABLE_AUDIO_MIXING_WITH_OTHER_APPS @@ -136,6 +140,10 @@ //============================================================================== // juce_audio_plugin_client flags: +#ifndef JUCE_VST3_CAN_REPLACE_VST2 + //#define JUCE_VST3_CAN_REPLACE_VST2 1 +#endif + #ifndef JUCE_FORCE_USE_LEGACY_PARAM_IDS //#define JUCE_FORCE_USE_LEGACY_PARAM_IDS 0 #endif @@ -148,6 +156,10 @@ //#define JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS 1 #endif +#ifndef JUCE_AU_WRAPPERS_SAVE_PROGRAM_STATES + //#define JUCE_AU_WRAPPERS_SAVE_PROGRAM_STATES 0 +#endif + #ifndef JUCE_STANDALONE_FILTER_WINDOW_USE_KIOSK_MODE //#define JUCE_STANDALONE_FILTER_WINDOW_USE_KIOSK_MODE 0 #endif @@ -167,6 +179,14 @@ //#define JUCE_PLUGINHOST_AU 0 #endif +#ifndef JUCE_PLUGINHOST_LADSPA + //#define JUCE_PLUGINHOST_LADSPA 0 +#endif + +#ifndef JUCE_CUSTOM_VST3_SDK + //#define JUCE_CUSTOM_VST3_SDK 0 +#endif + //============================================================================== // juce_audio_utils flags: @@ -202,15 +222,27 @@ #endif #ifndef JUCE_USE_CURL - //#define JUCE_USE_CURL 0 + //#define JUCE_USE_CURL 1 +#endif + +#ifndef JUCE_LOAD_CURL_SYMBOLS_LAZILY + //#define JUCE_LOAD_CURL_SYMBOLS_LAZILY 0 #endif #ifndef JUCE_CATCH_UNHANDLED_EXCEPTIONS - //#define JUCE_CATCH_UNHANDLED_EXCEPTIONS 1 + //#define JUCE_CATCH_UNHANDLED_EXCEPTIONS 0 #endif #ifndef JUCE_ALLOW_STATIC_NULL_VARIABLES - //#define JUCE_ALLOW_STATIC_NULL_VARIABLES 1 + //#define JUCE_ALLOW_STATIC_NULL_VARIABLES 0 +#endif + +#ifndef JUCE_STRICT_REFCOUNTEDPOINTER + //#define JUCE_STRICT_REFCOUNTEDPOINTER 0 +#endif + +#ifndef JUCE_ENABLE_ALLOCATION_HOOKS + //#define JUCE_ENABLE_ALLOCATION_HOOKS 0 #endif //============================================================================== @@ -239,8 +271,8 @@ //============================================================================== // juce_events flags: -#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK - //#define JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK 0 +#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK + //#define JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK 0 #endif //============================================================================== @@ -254,6 +286,10 @@ //#define JUCE_USE_DIRECTWRITE 1 #endif +#ifndef JUCE_DISABLE_COREGRAPHICS_FONT_SMOOTHING + //#define JUCE_DISABLE_COREGRAPHICS_FONT_SMOOTHING 0 +#endif + //============================================================================== // juce_gui_basics flags: @@ -281,6 +317,10 @@ //#define JUCE_USE_XCURSOR 1 #endif +#ifndef JUCE_WIN_PER_MONITOR_DPI_AWARE + //#define JUCE_WIN_PER_MONITOR_DPI_AWARE 1 +#endif + //============================================================================== // juce_gui_extra flags: @@ -288,6 +328,10 @@ //#define JUCE_WEB_BROWSER 1 #endif +#ifndef JUCE_USE_WIN_WEBVIEW2 + //#define JUCE_USE_WIN_WEBVIEW2 0 +#endif + #ifndef JUCE_ENABLE_LIVE_CONSTANT_EDITOR //#define JUCE_ENABLE_LIVE_CONSTANT_EDITOR 0 #endif @@ -298,6 +342,11 @@ #ifndef JUCE_USE_CAMERA //#define JUCE_USE_CAMERA 0 #endif + +#ifndef JUCE_SYNC_VIDEO_VOLUME_WITH_OS_MEDIA_VOLUME + //#define JUCE_SYNC_VIDEO_VOLUME_WITH_OS_MEDIA_VOLUME 1 +#endif + //============================================================================== #ifndef JUCE_STANDALONE_APPLICATION #if defined(JucePlugin_Name) && defined(JucePlugin_Build_Standalone) @@ -306,142 +355,3 @@ #define JUCE_STANDALONE_APPLICATION 0 #endif #endif - -//============================================================================== -// Audio plugin settings.. - -#ifndef JucePlugin_Build_VST - #define JucePlugin_Build_VST 1 -#endif -#ifndef JucePlugin_Build_VST3 - #define JucePlugin_Build_VST3 1 -#endif -#ifndef JucePlugin_Build_AU - #define JucePlugin_Build_AU 1 -#endif -#ifndef JucePlugin_Build_AUv3 - #define JucePlugin_Build_AUv3 0 -#endif -#ifndef JucePlugin_Build_RTAS - #define JucePlugin_Build_RTAS 0 -#endif -#ifndef JucePlugin_Build_AAX - #define JucePlugin_Build_AAX 0 -#endif -#ifndef JucePlugin_Build_Standalone - #define JucePlugin_Build_Standalone 1 -#endif -#ifndef JucePlugin_Enable_IAA - #define JucePlugin_Enable_IAA 0 -#endif -#ifndef JucePlugin_Name - #define JucePlugin_Name "Temper" -#endif -#ifndef JucePlugin_Desc - #define JucePlugin_Desc "Modern digital distortion." -#endif -#ifndef JucePlugin_Manufacturer - #define JucePlugin_Manufacturer "Creative Intent" -#endif -#ifndef JucePlugin_ManufacturerWebsite - #define JucePlugin_ManufacturerWebsite "http://www.creativeintent.co" -#endif -#ifndef JucePlugin_ManufacturerEmail - #define JucePlugin_ManufacturerEmail "" -#endif -#ifndef JucePlugin_ManufacturerCode - #define JucePlugin_ManufacturerCode 0x4376696e // 'Cvin' -#endif -#ifndef JucePlugin_PluginCode - #define JucePlugin_PluginCode 0x546d7072 // 'Tmpr' -#endif -#ifndef JucePlugin_IsSynth - #define JucePlugin_IsSynth 0 -#endif -#ifndef JucePlugin_WantsMidiInput - #define JucePlugin_WantsMidiInput 0 -#endif -#ifndef JucePlugin_ProducesMidiOutput - #define JucePlugin_ProducesMidiOutput 0 -#endif -#ifndef JucePlugin_IsMidiEffect - #define JucePlugin_IsMidiEffect 0 -#endif -#ifndef JucePlugin_EditorRequiresKeyboardFocus - #define JucePlugin_EditorRequiresKeyboardFocus 0 -#endif -#ifndef JucePlugin_Version - #define JucePlugin_Version 1.0.3 -#endif -#ifndef JucePlugin_VersionCode - #define JucePlugin_VersionCode 0x10003 -#endif -#ifndef JucePlugin_VersionString - #define JucePlugin_VersionString "1.0.3" -#endif -#ifndef JucePlugin_VSTUniqueID - #define JucePlugin_VSTUniqueID JucePlugin_PluginCode -#endif -#ifndef JucePlugin_VSTCategory - #define JucePlugin_VSTCategory kPlugCategEffect -#endif -#ifndef JucePlugin_AUMainType - #define JucePlugin_AUMainType kAudioUnitType_Effect -#endif -#ifndef JucePlugin_AUSubType - #define JucePlugin_AUSubType JucePlugin_PluginCode -#endif -#ifndef JucePlugin_AUExportPrefix - #define JucePlugin_AUExportPrefix TemperAU -#endif -#ifndef JucePlugin_AUExportPrefixQuoted - #define JucePlugin_AUExportPrefixQuoted "TemperAU" -#endif -#ifndef JucePlugin_AUManufacturerCode - #define JucePlugin_AUManufacturerCode JucePlugin_ManufacturerCode -#endif -#ifndef JucePlugin_CFBundleIdentifier - #define JucePlugin_CFBundleIdentifier com.creativeintent.temper -#endif -#ifndef JucePlugin_RTASCategory - #define JucePlugin_RTASCategory ePlugInCategory_None -#endif -#ifndef JucePlugin_RTASManufacturerCode - #define JucePlugin_RTASManufacturerCode JucePlugin_ManufacturerCode -#endif -#ifndef JucePlugin_RTASProductId - #define JucePlugin_RTASProductId JucePlugin_PluginCode -#endif -#ifndef JucePlugin_RTASDisableBypass - #define JucePlugin_RTASDisableBypass 0 -#endif -#ifndef JucePlugin_RTASDisableMultiMono - #define JucePlugin_RTASDisableMultiMono 0 -#endif -#ifndef JucePlugin_AAXIdentifier - #define JucePlugin_AAXIdentifier com.creativeintent.temper -#endif -#ifndef JucePlugin_AAXManufacturerCode - #define JucePlugin_AAXManufacturerCode JucePlugin_ManufacturerCode -#endif -#ifndef JucePlugin_AAXProductId - #define JucePlugin_AAXProductId JucePlugin_PluginCode -#endif -#ifndef JucePlugin_AAXCategory - #define JucePlugin_AAXCategory AAX_ePlugInCategory_Dynamics -#endif -#ifndef JucePlugin_AAXDisableBypass - #define JucePlugin_AAXDisableBypass 0 -#endif -#ifndef JucePlugin_AAXDisableMultiMono - #define JucePlugin_AAXDisableMultiMono 0 -#endif -#ifndef JucePlugin_IAAType - #define JucePlugin_IAAType 0x61757278 // 'aurx' -#endif -#ifndef JucePlugin_IAASubType - #define JucePlugin_IAASubType JucePlugin_PluginCode -#endif -#ifndef JucePlugin_IAAName - #define JucePlugin_IAAName "Creative Intent: Temper" -#endif diff --git a/JuceLibraryCode/BinaryData.cpp b/JuceLibraryCode/BinaryData.cpp index 8599f870..5ef434f5 100644 --- a/JuceLibraryCode/BinaryData.cpp +++ b/JuceLibraryCode/BinaryData.cpp @@ -19605,11 +19605,12 @@ static const unsigned char temp_binary_data_7[] = const char* StubbedToePreset_xml = (const char*) temp_binary_data_7; -const char* getNamedResource (const char*, int&) throw(); -const char* getNamedResource (const char* resourceNameUTF8, int& numBytes) throw() +const char* getNamedResource (const char* resourceNameUTF8, int& numBytes); +const char* getNamedResource (const char* resourceNameUTF8, int& numBytes) { unsigned int hash = 0; - if (resourceNameUTF8 != 0) + + if (resourceNameUTF8 != nullptr) while (*resourceNameUTF8 != 0) hash = 31 * hash + (unsigned int) *resourceNameUTF8++; @@ -19627,7 +19628,7 @@ const char* getNamedResource (const char* resourceNameUTF8, int& numBytes) throw } numBytes = 0; - return 0; + return nullptr; } const char* namedResourceList[] = @@ -19642,4 +19643,28 @@ const char* namedResourceList[] = "StubbedToePreset_xml" }; +const char* originalFilenames[] = +{ + "Background.png", + "BeeStingPreset.xml", + "DefaultPreset.xml", + "FlyingUnitedPreset.xml", + "GraphBackground.png", + "Montserrat-Light.otf", + "MorningAtTheDMVPreset.xml", + "StubbedToePreset.xml" +}; + +const char* getNamedResourceOriginalFilename (const char* resourceNameUTF8); +const char* getNamedResourceOriginalFilename (const char* resourceNameUTF8) +{ + for (unsigned int i = 0; i < (sizeof (namedResourceList) / sizeof (namedResourceList[0])); ++i) + { + if (namedResourceList[i] == resourceNameUTF8) + return originalFilenames[i]; + } + + return nullptr; +} + } diff --git a/JuceLibraryCode/BinaryData.h b/JuceLibraryCode/BinaryData.h index 6f655ad2..9d551d98 100644 --- a/JuceLibraryCode/BinaryData.h +++ b/JuceLibraryCode/BinaryData.h @@ -32,13 +32,20 @@ namespace BinaryData extern const char* StubbedToePreset_xml; const int StubbedToePreset_xmlSize = 252; + // Number of elements in the namedResourceList and originalFileNames arrays. + const int namedResourceListSize = 8; + // Points to the start of a list of resource names. extern const char* namedResourceList[]; - // Number of elements in the namedResourceList array. - const int namedResourceListSize = 8; + // Points to the start of a list of resource filenames. + extern const char* originalFilenames[]; // If you provide the name of one of the binary resource variables above, this function will // return the corresponding data and its size (or a null pointer if the name isn't found). - const char* getNamedResource (const char* resourceNameUTF8, int& dataSizeInBytes) throw(); + const char* getNamedResource (const char* resourceNameUTF8, int& dataSizeInBytes); + + // If you provide the name of one of the binary resource variables above, this function will + // return the corresponding original, non-mangled filename (or a null pointer if the name isn't found). + const char* getNamedResourceOriginalFilename (const char* resourceNameUTF8); } diff --git a/JuceLibraryCode/JuceHeader.h b/JuceLibraryCode/JuceHeader.h index 6bb7e959..268441f8 100644 --- a/JuceLibraryCode/JuceHeader.h +++ b/JuceLibraryCode/JuceHeader.h @@ -33,6 +33,15 @@ #include "BinaryData.h" +#if defined (JUCE_PROJUCER_VERSION) && JUCE_PROJUCER_VERSION < JUCE_VERSION + /** If you've hit this error then the version of the Projucer that was used to generate this project is + older than the version of the JUCE modules being included. To fix this error, re-save your project + using the latest version of the Projucer or, if you aren't using the Projucer to manage your project, + remove the JUCE_PROJUCER_VERSION define. + */ + #error "This project was last saved using an outdated version of the Projucer! Re-save this project with the latest version to fix this error." +#endif + #if ! DONT_SET_USING_JUCE_NAMESPACE // If your code uses a lot of JUCE classes, then this will obviously save you // a lot of typing, but can be disabled by setting DONT_SET_USING_JUCE_NAMESPACE. @@ -43,6 +52,7 @@ namespace ProjectInfo { const char* const projectName = "Temper"; + const char* const companyName = "Creative Intent"; const char* const versionString = "1.0.3"; const int versionNumber = 0x10003; } diff --git a/JuceLibraryCode/JucePluginDefines.h b/JuceLibraryCode/JucePluginDefines.h new file mode 100644 index 00000000..f6c073db --- /dev/null +++ b/JuceLibraryCode/JucePluginDefines.h @@ -0,0 +1,159 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#pragma once + +//============================================================================== +// Audio plugin settings.. + +#ifndef JucePlugin_Build_VST + #define JucePlugin_Build_VST 1 +#endif +#ifndef JucePlugin_Build_VST3 + #define JucePlugin_Build_VST3 1 +#endif +#ifndef JucePlugin_Build_AU + #define JucePlugin_Build_AU 1 +#endif +#ifndef JucePlugin_Build_AUv3 + #define JucePlugin_Build_AUv3 0 +#endif +#ifndef JucePlugin_Build_RTAS + #define JucePlugin_Build_RTAS 0 +#endif +#ifndef JucePlugin_Build_AAX + #define JucePlugin_Build_AAX 0 +#endif +#ifndef JucePlugin_Build_Standalone + #define JucePlugin_Build_Standalone 1 +#endif +#ifndef JucePlugin_Build_Unity + #define JucePlugin_Build_Unity 0 +#endif +#ifndef JucePlugin_Enable_IAA + #define JucePlugin_Enable_IAA 0 +#endif +#ifndef JucePlugin_Name + #define JucePlugin_Name "Temper" +#endif +#ifndef JucePlugin_Desc + #define JucePlugin_Desc "Modern digital distortion." +#endif +#ifndef JucePlugin_Manufacturer + #define JucePlugin_Manufacturer "Creative Intent" +#endif +#ifndef JucePlugin_ManufacturerWebsite + #define JucePlugin_ManufacturerWebsite "http://www.creativeintent.co" +#endif +#ifndef JucePlugin_ManufacturerEmail + #define JucePlugin_ManufacturerEmail "" +#endif +#ifndef JucePlugin_ManufacturerCode + #define JucePlugin_ManufacturerCode 0x4376696e +#endif +#ifndef JucePlugin_PluginCode + #define JucePlugin_PluginCode 0x546d7072 +#endif +#ifndef JucePlugin_IsSynth + #define JucePlugin_IsSynth 0 +#endif +#ifndef JucePlugin_WantsMidiInput + #define JucePlugin_WantsMidiInput 0 +#endif +#ifndef JucePlugin_ProducesMidiOutput + #define JucePlugin_ProducesMidiOutput 0 +#endif +#ifndef JucePlugin_IsMidiEffect + #define JucePlugin_IsMidiEffect 0 +#endif +#ifndef JucePlugin_EditorRequiresKeyboardFocus + #define JucePlugin_EditorRequiresKeyboardFocus 0 +#endif +#ifndef JucePlugin_Version + #define JucePlugin_Version 1.0.3 +#endif +#ifndef JucePlugin_VersionCode + #define JucePlugin_VersionCode 0x10003 +#endif +#ifndef JucePlugin_VersionString + #define JucePlugin_VersionString "1.0.3" +#endif +#ifndef JucePlugin_VSTUniqueID + #define JucePlugin_VSTUniqueID JucePlugin_PluginCode +#endif +#ifndef JucePlugin_VSTCategory + #define JucePlugin_VSTCategory kPlugCategEffect +#endif +#ifndef JucePlugin_Vst3Category + #define JucePlugin_Vst3Category "Fx" +#endif +#ifndef JucePlugin_AUMainType + #define JucePlugin_AUMainType 'aufx' +#endif +#ifndef JucePlugin_AUSubType + #define JucePlugin_AUSubType JucePlugin_PluginCode +#endif +#ifndef JucePlugin_AUExportPrefix + #define JucePlugin_AUExportPrefix TemperAU +#endif +#ifndef JucePlugin_AUExportPrefixQuoted + #define JucePlugin_AUExportPrefixQuoted "TemperAU" +#endif +#ifndef JucePlugin_AUManufacturerCode + #define JucePlugin_AUManufacturerCode JucePlugin_ManufacturerCode +#endif +#ifndef JucePlugin_CFBundleIdentifier + #define JucePlugin_CFBundleIdentifier com.creativeintent.temper +#endif +#ifndef JucePlugin_RTASCategory + #define JucePlugin_RTASCategory 0 +#endif +#ifndef JucePlugin_RTASManufacturerCode + #define JucePlugin_RTASManufacturerCode JucePlugin_ManufacturerCode +#endif +#ifndef JucePlugin_RTASProductId + #define JucePlugin_RTASProductId JucePlugin_PluginCode +#endif +#ifndef JucePlugin_RTASDisableBypass + #define JucePlugin_RTASDisableBypass 0 +#endif +#ifndef JucePlugin_RTASDisableMultiMono + #define JucePlugin_RTASDisableMultiMono 0 +#endif +#ifndef JucePlugin_AAXIdentifier + #define JucePlugin_AAXIdentifier com.creativeintent.temper +#endif +#ifndef JucePlugin_AAXManufacturerCode + #define JucePlugin_AAXManufacturerCode JucePlugin_ManufacturerCode +#endif +#ifndef JucePlugin_AAXProductId + #define JucePlugin_AAXProductId JucePlugin_PluginCode +#endif +#ifndef JucePlugin_AAXCategory + #define JucePlugin_AAXCategory 2 +#endif +#ifndef JucePlugin_AAXDisableBypass + #define JucePlugin_AAXDisableBypass 0 +#endif +#ifndef JucePlugin_AAXDisableMultiMono + #define JucePlugin_AAXDisableMultiMono 0 +#endif +#ifndef JucePlugin_IAAType + #define JucePlugin_IAAType 0x61757278 +#endif +#ifndef JucePlugin_IAASubType + #define JucePlugin_IAASubType JucePlugin_PluginCode +#endif +#ifndef JucePlugin_IAAName + #define JucePlugin_IAAName "Creative Intent: Temper" +#endif +#ifndef JucePlugin_VSTNumMidiInputs + #define JucePlugin_VSTNumMidiInputs 16 +#endif +#ifndef JucePlugin_VSTNumMidiOutputs + #define JucePlugin_VSTNumMidiOutputs 16 +#endif diff --git a/JuceLibraryCode/include_juce_audio_plugin_client_Unity.cpp b/JuceLibraryCode/include_juce_audio_plugin_client_Unity.cpp new file mode 100644 index 00000000..6552559a --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_plugin_client_Unity.cpp @@ -0,0 +1,9 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include "AppConfig.h" +#include diff --git a/JuceLibraryCode/modules/juce_audio_basics/audio_play_head/juce_AudioPlayHead.h b/JuceLibraryCode/modules/juce_audio_basics/audio_play_head/juce_AudioPlayHead.h index 8a58c7ba..17bc7d83 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/audio_play_head/juce_AudioPlayHead.h +++ b/JuceLibraryCode/modules/juce_audio_basics/audio_play_head/juce_AudioPlayHead.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -39,10 +39,10 @@ class JUCE_API AudioPlayHead { protected: //============================================================================== - AudioPlayHead() {} + AudioPlayHead() = default; public: - virtual ~AudioPlayHead() {} + virtual ~AudioPlayHead() = default; //============================================================================== /** Frame rate types. */ @@ -60,29 +60,121 @@ class JUCE_API AudioPlayHead fpsUnknown = 99 }; + /** More descriptive frame rate type. */ + class JUCE_API FrameRate + { + public: + /** Creates a frame rate with a base rate of 0. */ + FrameRate() = default; + + /** Creates a FrameRate instance from a FrameRateType. */ + FrameRate (FrameRateType type) : FrameRate (fromType (type)) {} + + /** Gets the FrameRateType that matches the state of this FrameRate. + + Returns fpsUnknown if this FrameRate cannot be represented by any of the + other enum fields. + */ + FrameRateType getType() const + { + switch (base) + { + case 24: return pulldown ? fps23976 : fps24; + case 25: return fps25; + case 30: return pulldown ? (drop ? fps2997drop : fps2997) + : (drop ? fps30drop : fps30); + case 60: return drop ? fps60drop : fps60; + } + + return fpsUnknown; + } + + /** Returns the plain rate, without taking pulldown into account. */ + int getBaseRate() const { return base; } + + /** Returns true if drop-frame timecode is in use. */ + bool isDrop() const { return drop; } + + /** Returns true if the effective framerate is actually equal to the base rate divided by 1.001 */ + bool isPullDown() const { return pulldown; } + + /** Returns the actual rate described by this object, taking pulldown into account. */ + double getEffectiveRate() const { return pulldown ? (double) base / 1.001 : (double) base; } + + /** Returns a copy of this object with the specified base rate. */ + JUCE_NODISCARD FrameRate withBaseRate (int x) const { return with (&FrameRate::base, x); } + + /** Returns a copy of this object with drop frames enabled or disabled, as specified. */ + JUCE_NODISCARD FrameRate withDrop (bool x = true) const { return with (&FrameRate::drop, x); } + + /** Returns a copy of this object with pulldown enabled or disabled, as specified. */ + JUCE_NODISCARD FrameRate withPullDown (bool x = true) const { return with (&FrameRate::pulldown, x); } + + /** Returns true if this instance is equal to other. */ + bool operator== (const FrameRate& other) const + { + const auto tie = [] (const FrameRate& x) { return std::tie (x.base, x.drop, x.pulldown); }; + return tie (*this) == tie (other); + } + + /** Returns true if this instance is not equal to other. */ + bool operator!= (const FrameRate& other) const { return ! (*this == other); } + + private: + static FrameRate fromType (FrameRateType type) + { + switch (type) + { + case fps23976: return FrameRate().withBaseRate (24).withPullDown(); + case fps24: return FrameRate().withBaseRate (24); + case fps25: return FrameRate().withBaseRate (25); + case fps2997: return FrameRate().withBaseRate (30).withPullDown(); + case fps30: return FrameRate().withBaseRate (30); + case fps2997drop: return FrameRate().withBaseRate (30).withDrop().withPullDown(); + case fps30drop: return FrameRate().withBaseRate (30).withDrop(); + case fps60: return FrameRate().withBaseRate (60); + case fps60drop: return FrameRate().withBaseRate (60).withDrop(); + case fpsUnknown: break; + } + + return {}; + } + + template + FrameRate with (Member&& member, Value&& value) const + { + auto copy = *this; + copy.*member = std::forward (value); + return copy; + } + + int base = 0; + bool drop = false, pulldown = false; + }; + //============================================================================== /** This structure is filled-in by the AudioPlayHead::getCurrentPosition() method. */ struct JUCE_API CurrentPositionInfo { /** The tempo in BPM */ - double bpm; + double bpm = 120.0; /** Time signature numerator, e.g. the 3 of a 3/4 time sig */ - int timeSigNumerator; + int timeSigNumerator = 4; /** Time signature denominator, e.g. the 4 of a 3/4 time sig */ - int timeSigDenominator; + int timeSigDenominator = 4; /** The current play position, in samples from the start of the timeline. */ - int64 timeInSamples; + int64 timeInSamples = 0; /** The current play position, in seconds from the start of the timeline. */ - double timeInSeconds; + double timeInSeconds = 0; /** For timecode, the position of the start of the timeline, in seconds from 00:00:00:00. */ - double editOriginTime; + double editOriginTime = 0; /** The current play position, in units of quarter-notes. */ - double ppqPosition; + double ppqPosition = 0; /** The position of the start of the last bar, in units of quarter-notes. @@ -92,40 +184,67 @@ class JUCE_API AudioPlayHead Note - this value may be unavailable on some hosts, e.g. Pro-Tools. If it's not available, the value will be 0. */ - double ppqPositionOfLastBarStart; + double ppqPositionOfLastBarStart = 0; /** The video frame rate, if applicable. */ - FrameRateType frameRate; + FrameRate frameRate = FrameRateType::fps23976; /** True if the transport is currently playing. */ - bool isPlaying; + bool isPlaying = false; /** True if the transport is currently recording. (When isRecording is true, then isPlaying will also be true). */ - bool isRecording; + bool isRecording = false; /** The current cycle start position in units of quarter-notes. Note that not all hosts or plugin formats may provide this value. @see isLooping */ - double ppqLoopStart; + double ppqLoopStart = 0; /** The current cycle end position in units of quarter-notes. Note that not all hosts or plugin formats may provide this value. @see isLooping */ - double ppqLoopEnd; + double ppqLoopEnd = 0; /** True if the transport is currently looping. */ - bool isLooping; + bool isLooping = false; //============================================================================== - bool operator== (const CurrentPositionInfo& other) const noexcept; - bool operator!= (const CurrentPositionInfo& other) const noexcept; - - void resetToDefault(); + bool operator== (const CurrentPositionInfo& other) const noexcept + { + const auto tie = [] (const CurrentPositionInfo& i) + { + return std::tie (i.timeInSamples, + i.ppqPosition, + i.editOriginTime, + i.ppqPositionOfLastBarStart, + i.frameRate, + i.isPlaying, + i.isRecording, + i.bpm, + i.timeSigNumerator, + i.timeSigDenominator, + i.ppqLoopStart, + i.ppqLoopEnd, + i.isLooping); + }; + + return tie (*this) == tie (other); + } + + bool operator!= (const CurrentPositionInfo& other) const noexcept + { + return ! operator== (other); + } + + void resetToDefault() + { + *this = CurrentPositionInfo{}; + } }; //============================================================================== diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp index 4ca398ca..f7d74fd8 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -29,7 +29,7 @@ AudioChannelSet::AudioChannelSet (uint32 c) : channels (static_cast (c)) { } -AudioChannelSet::AudioChannelSet (const Array& c) +AudioChannelSet::AudioChannelSet (const std::initializer_list& c) { for (auto channel : c) addChannel (channel); @@ -75,6 +75,50 @@ String AudioChannelSet::getChannelTypeName (AudioChannelSet::ChannelType type) case ambisonicZ: return NEEDS_TRANS("Ambisonic Z"); case topSideLeft: return NEEDS_TRANS("Top Side Left"); case topSideRight: return NEEDS_TRANS("Top Side Right"); + case ambisonicACN4: return NEEDS_TRANS("Ambisonic 4"); + case ambisonicACN5: return NEEDS_TRANS("Ambisonic 5"); + case ambisonicACN6: return NEEDS_TRANS("Ambisonic 6"); + case ambisonicACN7: return NEEDS_TRANS("Ambisonic 7"); + case ambisonicACN8: return NEEDS_TRANS("Ambisonic 8"); + case ambisonicACN9: return NEEDS_TRANS("Ambisonic 9"); + case ambisonicACN10: return NEEDS_TRANS("Ambisonic 10"); + case ambisonicACN11: return NEEDS_TRANS("Ambisonic 11"); + case ambisonicACN12: return NEEDS_TRANS("Ambisonic 12"); + case ambisonicACN13: return NEEDS_TRANS("Ambisonic 13"); + case ambisonicACN14: return NEEDS_TRANS("Ambisonic 14"); + case ambisonicACN15: return NEEDS_TRANS("Ambisonic 15"); + case ambisonicACN16: return NEEDS_TRANS("Ambisonic 16"); + case ambisonicACN17: return NEEDS_TRANS("Ambisonic 17"); + case ambisonicACN18: return NEEDS_TRANS("Ambisonic 18"); + case ambisonicACN19: return NEEDS_TRANS("Ambisonic 19"); + case ambisonicACN20: return NEEDS_TRANS("Ambisonic 20"); + case ambisonicACN21: return NEEDS_TRANS("Ambisonic 21"); + case ambisonicACN22: return NEEDS_TRANS("Ambisonic 22"); + case ambisonicACN23: return NEEDS_TRANS("Ambisonic 23"); + case ambisonicACN24: return NEEDS_TRANS("Ambisonic 24"); + case ambisonicACN25: return NEEDS_TRANS("Ambisonic 25"); + case ambisonicACN26: return NEEDS_TRANS("Ambisonic 26"); + case ambisonicACN27: return NEEDS_TRANS("Ambisonic 27"); + case ambisonicACN28: return NEEDS_TRANS("Ambisonic 28"); + case ambisonicACN29: return NEEDS_TRANS("Ambisonic 29"); + case ambisonicACN30: return NEEDS_TRANS("Ambisonic 30"); + case ambisonicACN31: return NEEDS_TRANS("Ambisonic 31"); + case ambisonicACN32: return NEEDS_TRANS("Ambisonic 32"); + case ambisonicACN33: return NEEDS_TRANS("Ambisonic 33"); + case ambisonicACN34: return NEEDS_TRANS("Ambisonic 34"); + case ambisonicACN35: return NEEDS_TRANS("Ambisonic 35"); + case bottomFrontLeft: return NEEDS_TRANS("Bottom Front Left"); + case bottomFrontCentre: return NEEDS_TRANS("Bottom Front Centre"); + case bottomFrontRight: return NEEDS_TRANS("Bottom Front Right"); + case proximityLeft: return NEEDS_TRANS("Proximity Left"); + case proximityRight: return NEEDS_TRANS("Proximity Right"); + case bottomSideLeft: return NEEDS_TRANS("Bottom Side Left"); + case bottomSideRight: return NEEDS_TRANS("Bottom Side Right"); + case bottomRearLeft: return NEEDS_TRANS("Bottom Rear Left"); + case bottomRearCentre: return NEEDS_TRANS("Bottom Rear Centre"); + case bottomRearRight: return NEEDS_TRANS("Bottom Rear Right"); + case discreteChannel0: + case unknown: default: break; } @@ -115,8 +159,52 @@ String AudioChannelSet::getAbbreviatedChannelTypeName (AudioChannelSet::ChannelT case ambisonicACN1: return "ACN1"; case ambisonicACN2: return "ACN2"; case ambisonicACN3: return "ACN3"; + case ambisonicACN4: return "ACN4"; + case ambisonicACN5: return "ACN5"; + case ambisonicACN6: return "ACN6"; + case ambisonicACN7: return "ACN7"; + case ambisonicACN8: return "ACN8"; + case ambisonicACN9: return "ACN9"; + case ambisonicACN10: return "ACN10"; + case ambisonicACN11: return "ACN11"; + case ambisonicACN12: return "ACN12"; + case ambisonicACN13: return "ACN13"; + case ambisonicACN14: return "ACN14"; + case ambisonicACN15: return "ACN15"; + case ambisonicACN16: return "ACN16"; + case ambisonicACN17: return "ACN17"; + case ambisonicACN18: return "ACN18"; + case ambisonicACN19: return "ACN19"; + case ambisonicACN20: return "ACN20"; + case ambisonicACN21: return "ACN21"; + case ambisonicACN22: return "ACN22"; + case ambisonicACN23: return "ACN23"; + case ambisonicACN24: return "ACN24"; + case ambisonicACN25: return "ACN25"; + case ambisonicACN26: return "ACN26"; + case ambisonicACN27: return "ACN27"; + case ambisonicACN28: return "ACN28"; + case ambisonicACN29: return "ACN29"; + case ambisonicACN30: return "ACN30"; + case ambisonicACN31: return "ACN31"; + case ambisonicACN32: return "ACN32"; + case ambisonicACN33: return "ACN33"; + case ambisonicACN34: return "ACN34"; + case ambisonicACN35: return "ACN35"; case topSideLeft: return "Tsl"; case topSideRight: return "Tsr"; + case bottomFrontLeft: return "Bfl"; + case bottomFrontCentre: return "Bfc"; + case bottomFrontRight: return "Bfr"; + case proximityLeft: return "Pl"; + case proximityRight: return "Pr"; + case bottomSideLeft: return "Bsl"; + case bottomSideRight: return "Bsr"; + case bottomRearLeft: return "Brl"; + case bottomRearCentre: return "Brc"; + case bottomRearRight: return "Brr"; + case discreteChannel0: + case unknown: default: break; } @@ -130,38 +218,81 @@ AudioChannelSet::ChannelType AudioChannelSet::getChannelTypeFromAbbreviation (co { if (abbr.length() > 0 && (abbr[0] >= '0' && abbr[0] <= '9')) return static_cast (static_cast (discreteChannel0) - + abbr.getIntValue() + 1); - - if (abbr == "L") return left; - if (abbr == "R") return right; - if (abbr == "C") return centre; - if (abbr == "Lfe") return LFE; - if (abbr == "Ls") return leftSurround; - if (abbr == "Rs") return rightSurround; - if (abbr == "Lc") return leftCentre; - if (abbr == "Rc") return rightCentre; - if (abbr == "Cs") return centreSurround; - if (abbr == "Lrs") return leftSurroundRear; - if (abbr == "Rrs") return rightSurroundRear; - if (abbr == "Tm") return topMiddle; - if (abbr == "Tfl") return topFrontLeft; - if (abbr == "Tfc") return topFrontCentre; - if (abbr == "Tfr") return topFrontRight; - if (abbr == "Trl") return topRearLeft; - if (abbr == "Trc") return topRearCentre; - if (abbr == "Trr") return topRearRight; - if (abbr == "Wl") return wideLeft; - if (abbr == "Wr") return wideRight; - if (abbr == "Lfe2") return LFE2; - if (abbr == "Lss") return leftSurroundSide; - if (abbr == "Rss") return rightSurroundSide; - if (abbr == "W") return ambisonicW; - if (abbr == "X") return ambisonicX; - if (abbr == "Y") return ambisonicY; - if (abbr == "Z") return ambisonicZ; - if (abbr == "Tsl") return topSideLeft; - if (abbr == "Tsr") return topSideRight; - + + abbr.getIntValue() - 1); + + if (abbr == "L") return left; + if (abbr == "R") return right; + if (abbr == "C") return centre; + if (abbr == "Lfe") return LFE; + if (abbr == "Ls") return leftSurround; + if (abbr == "Rs") return rightSurround; + if (abbr == "Lc") return leftCentre; + if (abbr == "Rc") return rightCentre; + if (abbr == "Cs") return centreSurround; + if (abbr == "Lrs") return leftSurroundRear; + if (abbr == "Rrs") return rightSurroundRear; + if (abbr == "Tm") return topMiddle; + if (abbr == "Tfl") return topFrontLeft; + if (abbr == "Tfc") return topFrontCentre; + if (abbr == "Tfr") return topFrontRight; + if (abbr == "Trl") return topRearLeft; + if (abbr == "Trc") return topRearCentre; + if (abbr == "Trr") return topRearRight; + if (abbr == "Wl") return wideLeft; + if (abbr == "Wr") return wideRight; + if (abbr == "Lfe2") return LFE2; + if (abbr == "Lss") return leftSurroundSide; + if (abbr == "Rss") return rightSurroundSide; + if (abbr == "W") return ambisonicW; + if (abbr == "X") return ambisonicX; + if (abbr == "Y") return ambisonicY; + if (abbr == "Z") return ambisonicZ; + if (abbr == "ACN0") return ambisonicACN0; + if (abbr == "ACN1") return ambisonicACN1; + if (abbr == "ACN2") return ambisonicACN2; + if (abbr == "ACN3") return ambisonicACN3; + if (abbr == "ACN4") return ambisonicACN4; + if (abbr == "ACN5") return ambisonicACN5; + if (abbr == "ACN6") return ambisonicACN6; + if (abbr == "ACN7") return ambisonicACN7; + if (abbr == "ACN8") return ambisonicACN8; + if (abbr == "ACN9") return ambisonicACN9; + if (abbr == "ACN10") return ambisonicACN10; + if (abbr == "ACN11") return ambisonicACN11; + if (abbr == "ACN12") return ambisonicACN12; + if (abbr == "ACN13") return ambisonicACN13; + if (abbr == "ACN14") return ambisonicACN14; + if (abbr == "ACN15") return ambisonicACN15; + if (abbr == "ACN16") return ambisonicACN16; + if (abbr == "ACN17") return ambisonicACN17; + if (abbr == "ACN18") return ambisonicACN18; + if (abbr == "ACN19") return ambisonicACN19; + if (abbr == "ACN20") return ambisonicACN20; + if (abbr == "ACN21") return ambisonicACN21; + if (abbr == "ACN22") return ambisonicACN22; + if (abbr == "ACN23") return ambisonicACN23; + if (abbr == "ACN24") return ambisonicACN24; + if (abbr == "ACN25") return ambisonicACN25; + if (abbr == "ACN26") return ambisonicACN26; + if (abbr == "ACN27") return ambisonicACN27; + if (abbr == "ACN28") return ambisonicACN28; + if (abbr == "ACN29") return ambisonicACN29; + if (abbr == "ACN30") return ambisonicACN30; + if (abbr == "ACN31") return ambisonicACN31; + if (abbr == "ACN32") return ambisonicACN32; + if (abbr == "ACN33") return ambisonicACN33; + if (abbr == "ACN34") return ambisonicACN34; + if (abbr == "ACN35") return ambisonicACN35; + if (abbr == "Tsl") return topSideLeft; + if (abbr == "Tsr") return topSideRight; + if (abbr == "Bfl") return bottomFrontLeft; + if (abbr == "Bfc") return bottomFrontCentre; + if (abbr == "Bfr") return bottomFrontRight; + if (abbr == "Bsl") return bottomSideLeft; + if (abbr == "Bsr") return bottomSideRight; + if (abbr == "Brl") return bottomRearLeft; + if (abbr == "Brc") return bottomRearCentre; + if (abbr == "Brr") return bottomRearRight; return unknown; } @@ -208,6 +339,8 @@ String AudioChannelSet::getDescription() const if (*this == create5point0()) return "5.0 Surround"; if (*this == create5point1()) return "5.1 Surround"; + if (*this == create5point1point2()) return "5.1.2 Surround"; + if (*this == create5point1point4()) return "5.1.4 Surround"; if (*this == create6point0()) return "6.0 Surround"; if (*this == create6point1()) return "6.1 Surround"; if (*this == create6point0Music()) return "6.0 (Music) Surround"; @@ -217,7 +350,11 @@ String AudioChannelSet::getDescription() const if (*this == create7point0SDDS()) return "7.0 Surround SDDS"; if (*this == create7point1SDDS()) return "7.1 Surround SDDS"; if (*this == create7point0point2()) return "7.0.2 Surround"; + if (*this == create7point0point4()) return "7.0.4 Surround"; if (*this == create7point1point2()) return "7.1.2 Surround"; + if (*this == create7point1point4()) return "7.1.4 Surround"; + if (*this == create7point1point6()) return "7.1.6 Surround"; + if (*this == create9point1point6()) return "9.1.6 Surround"; if (*this == quadraphonic()) return "Quadraphonic"; if (*this == pentagonal()) return "Pentagonal"; @@ -311,27 +448,33 @@ void AudioChannelSet::removeChannel (ChannelType newChannel) } AudioChannelSet AudioChannelSet::disabled() { return {}; } -AudioChannelSet AudioChannelSet::mono() { return AudioChannelSet (1u << centre); } -AudioChannelSet AudioChannelSet::stereo() { return AudioChannelSet ((1u << left) | (1u << right)); } -AudioChannelSet AudioChannelSet::createLCR() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre)); } -AudioChannelSet AudioChannelSet::createLRS() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << surround)); } -AudioChannelSet AudioChannelSet::createLCRS() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << surround)); } -AudioChannelSet AudioChannelSet::create5point0() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurround) | (1u << rightSurround)); } -AudioChannelSet AudioChannelSet::create5point1() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurround) | (1u << rightSurround)); } -AudioChannelSet AudioChannelSet::create6point0() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurround) | (1u << rightSurround) | (1u << centreSurround)); } -AudioChannelSet AudioChannelSet::create6point1() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurround) | (1u << rightSurround) | (1u << centreSurround)); } -AudioChannelSet AudioChannelSet::create6point0Music() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << leftSurround) | (1u << rightSurround) | (1u << leftSurroundSide) | (1u << rightSurroundSide)); } -AudioChannelSet AudioChannelSet::create6point1Music() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << LFE) | (1u << leftSurround) | (1u << rightSurround) | (1u << leftSurroundSide) | (1u << rightSurroundSide)); } -AudioChannelSet AudioChannelSet::create7point0() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurroundSide) | (1u << rightSurroundSide) | (1u << leftSurroundRear) | (1u << rightSurroundRear)); } -AudioChannelSet AudioChannelSet::create7point0SDDS() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurround) | (1u << rightSurround) | (1u << leftCentre) | (1u << rightCentre)); } -AudioChannelSet AudioChannelSet::create7point1() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurroundSide) | (1u << rightSurroundSide) | (1u << leftSurroundRear) | (1u << rightSurroundRear)); } -AudioChannelSet AudioChannelSet::create7point1SDDS() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurround) | (1u << rightSurround) | (1u << leftCentre) | (1u << rightCentre)); } -AudioChannelSet AudioChannelSet::quadraphonic() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << leftSurround) | (1u << rightSurround)); } -AudioChannelSet AudioChannelSet::pentagonal() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurroundRear) | (1u << rightSurroundRear)); } -AudioChannelSet AudioChannelSet::hexagonal() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << centreSurround) | (1u << leftSurroundRear) | (1u << rightSurroundRear)); } -AudioChannelSet AudioChannelSet::octagonal() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurround) | (1u << rightSurround) | (1u << centreSurround) | (1u << wideLeft) | (1u << wideRight)); } -AudioChannelSet AudioChannelSet::create7point0point2() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurroundSide) | (1u << rightSurroundSide) | (1u << leftSurroundRear) | (1u << rightSurroundRear) | (1u << topSideLeft) | (1u << topSideRight)); } -AudioChannelSet AudioChannelSet::create7point1point2() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurroundSide) | (1u << rightSurroundSide) | (1u << leftSurroundRear) | (1u << rightSurroundRear) | (1u << topSideLeft) | (1u << topSideRight)); } +AudioChannelSet AudioChannelSet::mono() { return AudioChannelSet ({ centre }); } +AudioChannelSet AudioChannelSet::stereo() { return AudioChannelSet ({ left, right }); } +AudioChannelSet AudioChannelSet::createLCR() { return AudioChannelSet ({ left, right, centre }); } +AudioChannelSet AudioChannelSet::createLRS() { return AudioChannelSet ({ left, right, surround }); } +AudioChannelSet AudioChannelSet::createLCRS() { return AudioChannelSet ({ left, right, centre, surround }); } +AudioChannelSet AudioChannelSet::create5point0() { return AudioChannelSet ({ left, right, centre, leftSurround, rightSurround }); } +AudioChannelSet AudioChannelSet::create5point1() { return AudioChannelSet ({ left, right, centre, LFE, leftSurround, rightSurround }); } +AudioChannelSet AudioChannelSet::create6point0() { return AudioChannelSet ({ left, right, centre, leftSurround, rightSurround, centreSurround }); } +AudioChannelSet AudioChannelSet::create6point1() { return AudioChannelSet ({ left, right, centre, LFE, leftSurround, rightSurround, centreSurround }); } +AudioChannelSet AudioChannelSet::create6point0Music() { return AudioChannelSet ({ left, right, leftSurround, rightSurround, leftSurroundSide, rightSurroundSide }); } +AudioChannelSet AudioChannelSet::create6point1Music() { return AudioChannelSet ({ left, right, LFE, leftSurround, rightSurround, leftSurroundSide, rightSurroundSide }); } +AudioChannelSet AudioChannelSet::create7point0() { return AudioChannelSet ({ left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear }); } +AudioChannelSet AudioChannelSet::create7point0SDDS() { return AudioChannelSet ({ left, right, centre, leftSurround, rightSurround, leftCentre, rightCentre }); } +AudioChannelSet AudioChannelSet::create7point1() { return AudioChannelSet ({ left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear }); } +AudioChannelSet AudioChannelSet::create7point1SDDS() { return AudioChannelSet ({ left, right, centre, LFE, leftSurround, rightSurround, leftCentre, rightCentre }); } +AudioChannelSet AudioChannelSet::quadraphonic() { return AudioChannelSet ({ left, right, leftSurround, rightSurround }); } +AudioChannelSet AudioChannelSet::pentagonal() { return AudioChannelSet ({ left, right, centre, leftSurroundRear, rightSurroundRear }); } +AudioChannelSet AudioChannelSet::hexagonal() { return AudioChannelSet ({ left, right, centre, centreSurround, leftSurroundRear, rightSurroundRear }); } +AudioChannelSet AudioChannelSet::octagonal() { return AudioChannelSet ({ left, right, centre, leftSurround, rightSurround, centreSurround, wideLeft, wideRight }); } +AudioChannelSet AudioChannelSet::create5point1point2() { return AudioChannelSet ({ left, right, centre, LFE, leftSurround, rightSurround, topSideLeft, topSideRight }); } +AudioChannelSet AudioChannelSet::create5point1point4() { return AudioChannelSet ({ left, right, centre, LFE, leftSurround, rightSurround, topFrontLeft, topFrontRight, topRearLeft, topRearRight }); } +AudioChannelSet AudioChannelSet::create7point0point2() { return AudioChannelSet ({ left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topSideLeft, topSideRight }); } +AudioChannelSet AudioChannelSet::create7point1point2() { return AudioChannelSet ({ left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topSideLeft, topSideRight }); } +AudioChannelSet AudioChannelSet::create7point0point4() { return AudioChannelSet ({ left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topFrontLeft, topFrontRight, topRearLeft, topRearRight }); } +AudioChannelSet AudioChannelSet::create7point1point4() { return AudioChannelSet ({ left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topFrontLeft, topFrontRight, topRearLeft, topRearRight }); } +AudioChannelSet AudioChannelSet::create7point1point6() { return AudioChannelSet ({ left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight }); } +AudioChannelSet AudioChannelSet::create9point1point6() { return AudioChannelSet ({ left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight }); } AudioChannelSet AudioChannelSet::ambisonic (int order) { @@ -401,49 +544,55 @@ Array AudioChannelSet::channelSetsWithNumberOfChannels (int num { retval.add (AudioChannelSet::discreteChannels (numChannels)); - if (numChannels == 1) - { - retval.add (AudioChannelSet::mono()); - } - else if (numChannels == 2) - { - retval.add (AudioChannelSet::stereo()); - } - else if (numChannels == 3) - { - retval.add (AudioChannelSet::createLCR()); - retval.add (AudioChannelSet::createLRS()); - } - else if (numChannels == 4) - { - retval.add (AudioChannelSet::quadraphonic()); - retval.add (AudioChannelSet::createLCRS()); - } - else if (numChannels == 5) + retval.addArray ([numChannels]() -> Array { - retval.add (AudioChannelSet::create5point0()); - retval.add (AudioChannelSet::pentagonal()); - } - else if (numChannels == 6) - { - retval.add (AudioChannelSet::create5point1()); - retval.add (AudioChannelSet::create6point0()); - retval.add (AudioChannelSet::create6point0Music()); - retval.add (AudioChannelSet::hexagonal()); - } - else if (numChannels == 7) - { - retval.add (AudioChannelSet::create7point0()); - retval.add (AudioChannelSet::create7point0SDDS()); - retval.add (AudioChannelSet::create6point1()); - retval.add (AudioChannelSet::create6point1Music()); - } - else if (numChannels == 8) - { - retval.add (AudioChannelSet::create7point1()); - retval.add (AudioChannelSet::create7point1SDDS()); - retval.add (AudioChannelSet::octagonal()); - } + switch (numChannels) + { + case 1: + return { AudioChannelSet::mono() }; + case 2: + return { AudioChannelSet::stereo() }; + case 3: + return { AudioChannelSet::createLCR(), + AudioChannelSet::createLRS() }; + case 4: + return { AudioChannelSet::quadraphonic(), + AudioChannelSet::createLCRS() }; + case 5: + return { AudioChannelSet::create5point0(), + AudioChannelSet::pentagonal() }; + case 6: + return { AudioChannelSet::create5point1(), + AudioChannelSet::create6point0(), + AudioChannelSet::create6point0Music(), + AudioChannelSet::hexagonal() }; + case 7: + return { AudioChannelSet::create7point0(), + AudioChannelSet::create7point0SDDS(), + AudioChannelSet::create6point1(), + AudioChannelSet::create6point1Music() }; + case 8: + return { AudioChannelSet::create7point1(), + AudioChannelSet::create7point1SDDS(), + AudioChannelSet::octagonal(), + AudioChannelSet::create5point1point2() }; + case 9: + return { AudioChannelSet::create7point0point2() }; + case 10: + return { AudioChannelSet::create5point1point4(), + AudioChannelSet::create7point1point2() }; + case 11: + return { AudioChannelSet::create7point0point4() }; + case 12: + return { AudioChannelSet::create7point1point4() }; + case 14: + return { AudioChannelSet::create7point1point6() }; + case 16: + return { AudioChannelSet::create9point1point6() }; + } + + return {}; + }()); auto order = getAmbisonicOrderForNumChannels (numChannels); if (order >= 0) @@ -493,12 +642,17 @@ int JUCE_CALLTYPE AudioChannelSet::getAmbisonicOrderForNumChannels (int numChann return (static_cast (ambisonicOrder) == sqrtMinusOne ? ambisonicOrder : -1); } + +//============================================================================== //============================================================================== #if JUCE_UNIT_TESTS + class AudioChannelSetUnitTest : public UnitTest { public: - AudioChannelSetUnitTest() : UnitTest ("AudioChannelSetUnitTest", "Audio") {} + AudioChannelSetUnitTest() + : UnitTest ("AudioChannelSetUnitTest", UnitTestCategories::audio) + {} void runTest() override { @@ -581,6 +735,7 @@ class AudioChannelSetUnitTest : public UnitTest }; static AudioChannelSetUnitTest audioChannelSetUnitTest; + #endif } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h index 719e029f..423175f2 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h +++ b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -49,7 +49,7 @@ class JUCE_API AudioChannelSet /** Creates an empty channel set. You can call addChannel to add channels to the set. */ - AudioChannelSet() noexcept {} + AudioChannelSet() = default; /** Creates a zero-channel set which can be used to indicate that a bus is disabled. */ @@ -196,6 +196,18 @@ class JUCE_API AudioChannelSet */ static AudioChannelSet JUCE_CALLTYPE create7point1SDDS(); + /** Creates a set for a 5.1.2 surround setup (left, right, centre, LFE, leftSurround, rightSurround, topSideLeft, topSideRight). + + Is equivalent to: kAudioChannelLayoutTag_Atmos_5_1_2 (CoreAudio). + */ + static AudioChannelSet JUCE_CALLTYPE create5point1point2(); + + /** Creates a set for a 5.1.4 surround setup (left, right, centre, LFE, leftSurround, rightSurround, topFrontLeft, topFrontRight, topRearLeft, topRearRight). + + Is equivalent to: kAudioChannelLayoutTag_Atmos_5_1_4 (CoreAudio). + */ + static AudioChannelSet JUCE_CALLTYPE create5point1point4(); + /** Creates a set for Dolby Atmos 7.0.2 surround setup (left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topSideLeft, topSideRight). Is equivalent to: n/a (VST), AAX_eStemFormat_7_0_2 (AAX), n/a (CoreAudio) @@ -204,10 +216,33 @@ class JUCE_API AudioChannelSet /** Creates a set for Dolby Atmos 7.1.2 surround setup (left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, LFE, topSideLeft, topSideRight). - Is equivalent to: k71_2 (VST), AAX_eStemFormat_7_1_2 (AAX), n/a (CoreAudio) + Is equivalent to: k71_2 (VST), AAX_eStemFormat_7_1_2 (AAX), kAudioChannelLayoutTag_Atmos_7_1_2 (CoreAudio) */ static AudioChannelSet JUCE_CALLTYPE create7point1point2(); + /** Creates a set for Dolby Atmos 7.0.4 surround setup (left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topFrontLeft, topFrontRight, topRearLeft, topRearRight). + + Is equivalent to: n/a (VST), n/a (AAX), n/a (CoreAudio) + */ + static AudioChannelSet JUCE_CALLTYPE create7point0point4(); + + /** Creates a set for Dolby Atmos 7.1.4 surround setup (left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, LFE, topFrontLeft, topFrontRight, topRearLeft, topRearRight). + + Is equivalent to: k71_4 (VST), n/a (AAX), kAudioChannelLayoutTag_Atmos_7_1_4 (CoreAudio) + */ + static AudioChannelSet JUCE_CALLTYPE create7point1point4(); + + /** Creates a set for Dolby Atmos 7.1.6 surround setup (left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, LFE, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight). + + Is equivalent to: k71_6 (VST), n/a (AAX), n/a (CoreAudio) + */ + static AudioChannelSet JUCE_CALLTYPE create7point1point6(); + + /** Creates a set for a 9.1.6 surround setup (left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight). + + Is equivalent to: kAudioChannelLayoutTag_Atmos_9_1_6 (CoreAudio). + */ + static AudioChannelSet JUCE_CALLTYPE create9point1point6(); //============================================================================== /** Creates a set for quadraphonic surround setup (left, right, leftSurround, rightSurround) @@ -306,8 +341,8 @@ class JUCE_API AudioChannelSet //============================================================================== // Used by Dolby Atmos 7.0.2 and 7.1.2 - topSideLeft = 28, /**< Lts (AAX), Tsl (VST) channel for Dolby Atmos. */ - topSideRight = 29, /**< Rts (AAX), Tsr (VST) channel for Dolby Atmos. */ + topSideLeft = 28, /**< Lts (AAX), Tsl (VST), Ltm (AU) channel for Dolby Atmos. */ + topSideRight = 29, /**< Rts (AAX), Tsr (VST), Rtm (AU) channel for Dolby Atmos. */ //============================================================================== // Ambisonic ACN formats - all channels are SN3D normalised @@ -365,7 +400,21 @@ class JUCE_API AudioChannelSet ambisonicZ = ambisonicACN2, /**< Same as first-order ambisonic channel number 2. */ //============================================================================== - discreteChannel0 = 64 /**< Non-typed individual channels are indexed upwards from this value. */ + bottomFrontLeft = 62, /**< Bottom Front Left (Bfl) */ + bottomFrontCentre = 63, /**< Bottom Front Centre (Bfc) */ + bottomFrontRight = 64, /**< Bottom Front Right (Bfr) */ + + proximityLeft = 65, /**< Proximity Left (Pl) */ + proximityRight = 66, /**< Proximity Right (Pr) */ + + bottomSideLeft = 67, /**< Bottom Side Left (Bsl) */ + bottomSideRight = 68, /**< Bottom Side Right (Bsr) */ + bottomRearLeft = 69, /**< Bottom Rear Left (Brl) */ + bottomRearCentre = 70, /**< Bottom Rear Center (Brc) */ + bottomRearRight = 71, /**< Bottom Rear Right (Brr) */ + + //============================================================================== + discreteChannel0 = 128 /**< Non-typed individual channels are indexed upwards from this value. */ }; /** Returns the name of a given channel type. For example, this method may return "Surround Left". */ @@ -461,7 +510,7 @@ class JUCE_API AudioChannelSet //============================================================================== explicit AudioChannelSet (uint32); - explicit AudioChannelSet (const Array&); + explicit AudioChannelSet (const std::initializer_list&); //============================================================================== static int JUCE_CALLTYPE getAmbisonicOrderForNumChannels (int); diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp index e8fc19fb..7f7d59b5 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -23,16 +23,19 @@ namespace juce { -void AudioDataConverters::convertFloatToInt16LE (const float* source, void* dest, int numSamples, const int destBytesPerSample) +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") +JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996) + +void AudioDataConverters::convertFloatToInt16LE (const float* source, void* dest, int numSamples, int destBytesPerSample) { - const double maxVal = (double) 0x7fff; - char* intData = static_cast (dest); + auto maxVal = (double) 0x7fff; + auto intData = static_cast (dest); if (dest != (void*) source || destBytesPerSample <= 4) { for (int i = 0; i < numSamples; ++i) { - *(uint16*) intData = ByteOrder::swapIfBigEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); + *unalignedPointerCast (intData) = ByteOrder::swapIfBigEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); intData += destBytesPerSample; } } @@ -43,21 +46,21 @@ void AudioDataConverters::convertFloatToInt16LE (const float* source, void* dest for (int i = numSamples; --i >= 0;) { intData -= destBytesPerSample; - *(uint16*) intData = ByteOrder::swapIfBigEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); + *unalignedPointerCast (intData) = ByteOrder::swapIfBigEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); } } } -void AudioDataConverters::convertFloatToInt16BE (const float* source, void* dest, int numSamples, const int destBytesPerSample) +void AudioDataConverters::convertFloatToInt16BE (const float* source, void* dest, int numSamples, int destBytesPerSample) { - const double maxVal = (double) 0x7fff; - char* intData = static_cast (dest); + auto maxVal = (double) 0x7fff; + auto intData = static_cast (dest); if (dest != (void*) source || destBytesPerSample <= 4) { for (int i = 0; i < numSamples; ++i) { - *(uint16*) intData = ByteOrder::swapIfLittleEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); + *unalignedPointerCast (intData) = ByteOrder::swapIfLittleEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); intData += destBytesPerSample; } } @@ -68,15 +71,15 @@ void AudioDataConverters::convertFloatToInt16BE (const float* source, void* dest for (int i = numSamples; --i >= 0;) { intData -= destBytesPerSample; - *(uint16*) intData = ByteOrder::swapIfLittleEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); + *unalignedPointerCast (intData) = ByteOrder::swapIfLittleEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); } } } -void AudioDataConverters::convertFloatToInt24LE (const float* source, void* dest, int numSamples, const int destBytesPerSample) +void AudioDataConverters::convertFloatToInt24LE (const float* source, void* dest, int numSamples, int destBytesPerSample) { - const double maxVal = (double) 0x7fffff; - char* intData = static_cast (dest); + auto maxVal = (double) 0x7fffff; + auto intData = static_cast (dest); if (dest != (void*) source || destBytesPerSample <= 4) { @@ -98,10 +101,10 @@ void AudioDataConverters::convertFloatToInt24LE (const float* source, void* dest } } -void AudioDataConverters::convertFloatToInt24BE (const float* source, void* dest, int numSamples, const int destBytesPerSample) +void AudioDataConverters::convertFloatToInt24BE (const float* source, void* dest, int numSamples, int destBytesPerSample) { - const double maxVal = (double) 0x7fffff; - char* intData = static_cast (dest); + auto maxVal = (double) 0x7fffff; + auto intData = static_cast (dest); if (dest != (void*) source || destBytesPerSample <= 4) { @@ -123,16 +126,16 @@ void AudioDataConverters::convertFloatToInt24BE (const float* source, void* dest } } -void AudioDataConverters::convertFloatToInt32LE (const float* source, void* dest, int numSamples, const int destBytesPerSample) +void AudioDataConverters::convertFloatToInt32LE (const float* source, void* dest, int numSamples, int destBytesPerSample) { - const double maxVal = (double) 0x7fffffff; - char* intData = static_cast (dest); + auto maxVal = (double) 0x7fffffff; + auto intData = static_cast (dest); if (dest != (void*) source || destBytesPerSample <= 4) { for (int i = 0; i < numSamples; ++i) { - *(uint32*)intData = ByteOrder::swapIfBigEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); + *unalignedPointerCast (intData) = ByteOrder::swapIfBigEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); intData += destBytesPerSample; } } @@ -143,21 +146,21 @@ void AudioDataConverters::convertFloatToInt32LE (const float* source, void* dest for (int i = numSamples; --i >= 0;) { intData -= destBytesPerSample; - *(uint32*)intData = ByteOrder::swapIfBigEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); + *unalignedPointerCast (intData) = ByteOrder::swapIfBigEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); } } } -void AudioDataConverters::convertFloatToInt32BE (const float* source, void* dest, int numSamples, const int destBytesPerSample) +void AudioDataConverters::convertFloatToInt32BE (const float* source, void* dest, int numSamples, int destBytesPerSample) { - const double maxVal = (double) 0x7fffffff; - char* intData = static_cast (dest); + auto maxVal = (double) 0x7fffffff; + auto intData = static_cast (dest); if (dest != (void*) source || destBytesPerSample <= 4) { for (int i = 0; i < numSamples; ++i) { - *(uint32*)intData = ByteOrder::swapIfLittleEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); + *unalignedPointerCast (intData) = ByteOrder::swapIfLittleEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); intData += destBytesPerSample; } } @@ -168,12 +171,12 @@ void AudioDataConverters::convertFloatToInt32BE (const float* source, void* dest for (int i = numSamples; --i >= 0;) { intData -= destBytesPerSample; - *(uint32*)intData = ByteOrder::swapIfLittleEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); + *unalignedPointerCast (intData) = ByteOrder::swapIfLittleEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); } } } -void AudioDataConverters::convertFloatToFloat32LE (const float* source, void* dest, int numSamples, const int destBytesPerSample) +void AudioDataConverters::convertFloatToFloat32LE (const float* source, void* dest, int numSamples, int destBytesPerSample) { jassert (dest != (void*) source || destBytesPerSample <= 4); // This op can't be performed on in-place data! @@ -181,28 +184,28 @@ void AudioDataConverters::convertFloatToFloat32LE (const float* source, void* de for (int i = 0; i < numSamples; ++i) { - *(float*) d = source[i]; + *unalignedPointerCast (d) = source[i]; #if JUCE_BIG_ENDIAN - *(uint32*) d = ByteOrder::swap (*(uint32*) d); + *unalignedPointerCast (d) = ByteOrder::swap (*unalignedPointerCast (d)); #endif d += destBytesPerSample; } } -void AudioDataConverters::convertFloatToFloat32BE (const float* source, void* dest, int numSamples, const int destBytesPerSample) +void AudioDataConverters::convertFloatToFloat32BE (const float* source, void* dest, int numSamples, int destBytesPerSample) { jassert (dest != (void*) source || destBytesPerSample <= 4); // This op can't be performed on in-place data! - char* d = static_cast (dest); + auto d = static_cast (dest); for (int i = 0; i < numSamples; ++i) { - *(float*) d = source[i]; + *unalignedPointerCast (d) = source[i]; #if JUCE_LITTLE_ENDIAN - *(uint32*) d = ByteOrder::swap (*(uint32*) d); + *unalignedPointerCast (d) = ByteOrder::swap (*unalignedPointerCast (d)); #endif d += destBytesPerSample; @@ -210,16 +213,16 @@ void AudioDataConverters::convertFloatToFloat32BE (const float* source, void* de } //============================================================================== -void AudioDataConverters::convertInt16LEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) +void AudioDataConverters::convertInt16LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample) { const float scale = 1.0f / 0x7fff; - const char* intData = static_cast (source); + auto intData = static_cast (source); if (source != (void*) dest || srcBytesPerSample >= 4) { for (int i = 0; i < numSamples; ++i) { - dest[i] = scale * (short) ByteOrder::swapIfBigEndian (*(uint16*)intData); + dest[i] = scale * (short) ByteOrder::swapIfBigEndian (*unalignedPointerCast (intData)); intData += srcBytesPerSample; } } @@ -230,21 +233,21 @@ void AudioDataConverters::convertInt16LEToFloat (const void* const source, float for (int i = numSamples; --i >= 0;) { intData -= srcBytesPerSample; - dest[i] = scale * (short) ByteOrder::swapIfBigEndian (*(uint16*)intData); + dest[i] = scale * (short) ByteOrder::swapIfBigEndian (*unalignedPointerCast (intData)); } } } -void AudioDataConverters::convertInt16BEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) +void AudioDataConverters::convertInt16BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample) { const float scale = 1.0f / 0x7fff; - const char* intData = static_cast (source); + auto intData = static_cast (source); if (source != (void*) dest || srcBytesPerSample >= 4) { for (int i = 0; i < numSamples; ++i) { - dest[i] = scale * (short) ByteOrder::swapIfLittleEndian (*(uint16*)intData); + dest[i] = scale * (short) ByteOrder::swapIfLittleEndian (*unalignedPointerCast (intData)); intData += srcBytesPerSample; } } @@ -255,15 +258,15 @@ void AudioDataConverters::convertInt16BEToFloat (const void* const source, float for (int i = numSamples; --i >= 0;) { intData -= srcBytesPerSample; - dest[i] = scale * (short) ByteOrder::swapIfLittleEndian (*(uint16*)intData); + dest[i] = scale * (short) ByteOrder::swapIfLittleEndian (*unalignedPointerCast (intData)); } } } -void AudioDataConverters::convertInt24LEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) +void AudioDataConverters::convertInt24LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample) { const float scale = 1.0f / 0x7fffff; - const char* intData = static_cast (source); + auto intData = static_cast (source); if (source != (void*) dest || srcBytesPerSample >= 4) { @@ -285,10 +288,10 @@ void AudioDataConverters::convertInt24LEToFloat (const void* const source, float } } -void AudioDataConverters::convertInt24BEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) +void AudioDataConverters::convertInt24BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample) { const float scale = 1.0f / 0x7fffff; - const char* intData = static_cast (source); + auto intData = static_cast (source); if (source != (void*) dest || srcBytesPerSample >= 4) { @@ -310,16 +313,16 @@ void AudioDataConverters::convertInt24BEToFloat (const void* const source, float } } -void AudioDataConverters::convertInt32LEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) +void AudioDataConverters::convertInt32LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample) { - const auto scale = 1.0f / (float) 0x7fffffff; - const char* intData = static_cast (source); + const float scale = 1.0f / (float) 0x7fffffff; + auto intData = static_cast (source); if (source != (void*) dest || srcBytesPerSample >= 4) { for (int i = 0; i < numSamples; ++i) { - dest[i] = scale * (int) ByteOrder::swapIfBigEndian (*(uint32*) intData); + dest[i] = scale * (float) ByteOrder::swapIfBigEndian (*unalignedPointerCast (intData)); intData += srcBytesPerSample; } } @@ -330,21 +333,21 @@ void AudioDataConverters::convertInt32LEToFloat (const void* const source, float for (int i = numSamples; --i >= 0;) { intData -= srcBytesPerSample; - dest[i] = scale * (int) ByteOrder::swapIfBigEndian (*(uint32*) intData); + dest[i] = scale * (float) ByteOrder::swapIfBigEndian (*unalignedPointerCast (intData)); } } } -void AudioDataConverters::convertInt32BEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) +void AudioDataConverters::convertInt32BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample) { - const auto scale = 1.0f / (float) 0x7fffffff; - const char* intData = static_cast (source); + const float scale = 1.0f / (float) 0x7fffffff; + auto intData = static_cast (source); if (source != (void*) dest || srcBytesPerSample >= 4) { for (int i = 0; i < numSamples; ++i) { - dest[i] = scale * (int) ByteOrder::swapIfLittleEndian (*(uint32*) intData); + dest[i] = scale * (float) ByteOrder::swapIfLittleEndian (*unalignedPointerCast (intData)); intData += srcBytesPerSample; } } @@ -355,21 +358,21 @@ void AudioDataConverters::convertInt32BEToFloat (const void* const source, float for (int i = numSamples; --i >= 0;) { intData -= srcBytesPerSample; - dest[i] = scale * (int) ByteOrder::swapIfLittleEndian (*(uint32*) intData); + dest[i] = scale * (float) ByteOrder::swapIfLittleEndian (*unalignedPointerCast (intData)); } } } -void AudioDataConverters::convertFloat32LEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) +void AudioDataConverters::convertFloat32LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample) { - const char* s = static_cast (source); + auto s = static_cast (source); for (int i = 0; i < numSamples; ++i) { - dest[i] = *(float*)s; + dest[i] = *unalignedPointerCast (s); #if JUCE_BIG_ENDIAN - uint32* const d = (uint32*) (dest + i); + auto d = unalignedPointerCast (dest + i); *d = ByteOrder::swap (*d); #endif @@ -377,16 +380,16 @@ void AudioDataConverters::convertFloat32LEToFloat (const void* const source, flo } } -void AudioDataConverters::convertFloat32BEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) +void AudioDataConverters::convertFloat32BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample) { - const char* s = static_cast (source); + auto s = static_cast (source); for (int i = 0; i < numSamples; ++i) { - dest[i] = *(float*)s; + dest[i] = *unalignedPointerCast (s); #if JUCE_LITTLE_ENDIAN - uint32* const d = (uint32*) (dest + i); + auto d = unalignedPointerCast (dest + i); *d = ByteOrder::swap (*d); #endif @@ -396,10 +399,7 @@ void AudioDataConverters::convertFloat32BEToFloat (const void* const source, flo //============================================================================== -void AudioDataConverters::convertFloatToFormat (const DataFormat destFormat, - const float* const source, - void* const dest, - const int numSamples) +void AudioDataConverters::convertFloatToFormat (DataFormat destFormat, const float* source, void* dest, int numSamples) { switch (destFormat) { @@ -415,10 +415,7 @@ void AudioDataConverters::convertFloatToFormat (const DataFormat destFormat, } } -void AudioDataConverters::convertFormatToFloat (const DataFormat sourceFormat, - const void* const source, - float* const dest, - const int numSamples) +void AudioDataConverters::convertFormatToFloat (DataFormat sourceFormat, const void* source, float* dest, int numSamples) { switch (sourceFormat) { @@ -435,50 +432,34 @@ void AudioDataConverters::convertFormatToFloat (const DataFormat sourceFormat, } //============================================================================== -void AudioDataConverters::interleaveSamples (const float** const source, - float* const dest, - const int numSamples, - const int numChannels) +void AudioDataConverters::interleaveSamples (const float** source, float* dest, int numSamples, int numChannels) { - for (int chan = 0; chan < numChannels; ++chan) - { - int i = chan; - const float* src = source [chan]; + using Format = AudioData::Format; - for (int j = 0; j < numSamples; ++j) - { - dest [i] = src [j]; - i += numChannels; - } - } + AudioData::interleaveSamples (AudioData::NonInterleavedSource { source, numChannels }, + AudioData::InterleavedDest { dest, numChannels }, + numSamples); } -void AudioDataConverters::deinterleaveSamples (const float* const source, - float** const dest, - const int numSamples, - const int numChannels) +void AudioDataConverters::deinterleaveSamples (const float* source, float** dest, int numSamples, int numChannels) { - for (int chan = 0; chan < numChannels; ++chan) - { - int i = chan; - float* dst = dest [chan]; + using Format = AudioData::Format; - for (int j = 0; j < numSamples; ++j) - { - dst [j] = source [i]; - i += numChannels; - } - } + AudioData::deinterleaveSamples (AudioData::InterleavedSource { source, numChannels }, + AudioData::NonInterleavedDest { dest, numChannels }, + numSamples); } - +//============================================================================== //============================================================================== #if JUCE_UNIT_TESTS class AudioConversionTests : public UnitTest { public: - AudioConversionTests() : UnitTest ("Audio data conversion", "Audio") {} + AudioConversionTests() + : UnitTest ("Audio data conversion", UnitTestCategories::audio) + {} template struct Test5 @@ -489,10 +470,13 @@ class AudioConversionTests : public UnitTest test (unitTest, true, r); } + JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6262) static void test (UnitTest& unitTest, bool inPlace, Random& r) { const int numSamples = 2048; - int32 original [numSamples], converted [numSamples], reversed [numSamples]; + int32 original [(size_t) numSamples], + converted[(size_t) numSamples], + reversed [(size_t) numSamples]; { AudioData::Pointer d (original); @@ -514,13 +498,13 @@ class AudioConversionTests : public UnitTest } // convert data from the source to dest format.. - ScopedPointer conv (new AudioData::ConverterInstance , - AudioData::Pointer>()); + std::unique_ptr conv (new AudioData::ConverterInstance, + AudioData::Pointer>()); conv->convertSamples (inPlace ? reversed : converted, original, numSamples); // ..and back again.. - conv.reset (new AudioData::ConverterInstance , - AudioData::Pointer>()); + conv.reset (new AudioData::ConverterInstance, + AudioData::Pointer>()); if (! inPlace) zeromem (reversed, sizeof (reversed)); @@ -544,6 +528,7 @@ class AudioConversionTests : public UnitTest unitTest.expect (biggestDiff <= errorMargin); } } + JUCE_END_IGNORE_WARNINGS_MSVC }; template @@ -582,7 +567,7 @@ class AudioConversionTests : public UnitTest void runTest() override { - Random r = getRandom(); + auto r = getRandom(); beginTest ("Round-trip conversion: Int8"); Test1 ::test (*this, r); beginTest ("Round-trip conversion: Int16"); @@ -593,6 +578,50 @@ class AudioConversionTests : public UnitTest Test1 ::test (*this, r); beginTest ("Round-trip conversion: Float32"); Test1 ::test (*this, r); + + using Format = AudioData::Format; + + beginTest ("Interleaving"); + { + constexpr auto numChannels = 4; + constexpr auto numSamples = 512; + + AudioBuffer sourceBuffer { numChannels, numSamples }, + destBuffer { 1, numChannels * numSamples }; + + for (int ch = 0; ch < numChannels; ++ch) + for (int i = 0; i < numSamples; ++i) + sourceBuffer.setSample (ch, i, r.nextFloat()); + + AudioData::interleaveSamples (AudioData::NonInterleavedSource { sourceBuffer.getArrayOfReadPointers(), numChannels }, + AudioData::InterleavedDest { destBuffer.getWritePointer (0), numChannels }, + numSamples); + + for (int ch = 0; ch < numChannels; ++ch) + for (int i = 0; i < numSamples; ++i) + expect (destBuffer.getSample (0, ch + (i * numChannels)) == sourceBuffer.getSample (ch, i)); + } + + beginTest ("Deinterleaving"); + { + constexpr auto numChannels = 4; + constexpr auto numSamples = 512; + + AudioBuffer sourceBuffer { 1, numChannels * numSamples }, + destBuffer { numChannels, numSamples }; + + for (int ch = 0; ch < numChannels; ++ch) + for (int i = 0; i < numSamples; ++i) + sourceBuffer.setSample (0, ch + (i * numChannels), r.nextFloat()); + + AudioData::deinterleaveSamples (AudioData::InterleavedSource { sourceBuffer.getReadPointer (0), numChannels }, + AudioData::NonInterleavedDest { destBuffer.getArrayOfWritePointers(), numChannels }, + numSamples); + + for (int ch = 0; ch < numChannels; ++ch) + for (int i = 0; i < numSamples; ++i) + expect (sourceBuffer.getSample (0, ch + (i * numChannels)) == destBuffer.getSample (ch, i)); + } } }; @@ -600,4 +629,7 @@ static AudioConversionTests audioConversionUnitTests; #endif +JUCE_END_IGNORE_WARNINGS_MSVC +JUCE_END_IGNORE_WARNINGS_GCC_LIKE + } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h index ddf53198..fa694081 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h +++ b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -69,22 +69,22 @@ class JUCE_API AudioData class BigEndian { public: - template static inline float getAsFloat (SampleFormatType& s) noexcept { return s.getAsFloatBE(); } - template static inline void setAsFloat (SampleFormatType& s, float newValue) noexcept { s.setAsFloatBE (newValue); } - template static inline int32 getAsInt32 (SampleFormatType& s) noexcept { return s.getAsInt32BE(); } - template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) noexcept { s.setAsInt32BE (newValue); } - template static inline void copyFrom (DestType& dest, SourceType& source) noexcept { dest.copyFromBE (source); } + template static float getAsFloat (SampleFormatType& s) noexcept { return s.getAsFloatBE(); } + template static void setAsFloat (SampleFormatType& s, float newValue) noexcept { s.setAsFloatBE (newValue); } + template static int32 getAsInt32 (SampleFormatType& s) noexcept { return s.getAsInt32BE(); } + template static void setAsInt32 (SampleFormatType& s, int32 newValue) noexcept { s.setAsInt32BE (newValue); } + template static void copyFrom (DestType& dest, SourceType& source) noexcept { dest.copyFromBE (source); } enum { isBigEndian = 1 }; }; class LittleEndian { public: - template static inline float getAsFloat (SampleFormatType& s) noexcept { return s.getAsFloatLE(); } - template static inline void setAsFloat (SampleFormatType& s, float newValue) noexcept { s.setAsFloatLE (newValue); } - template static inline int32 getAsInt32 (SampleFormatType& s) noexcept { return s.getAsInt32LE(); } - template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) noexcept { s.setAsInt32LE (newValue); } - template static inline void copyFrom (DestType& dest, SourceType& source) noexcept { dest.copyFromLE (source); } + template static float getAsFloat (SampleFormatType& s) noexcept { return s.getAsFloatLE(); } + template static void setAsFloat (SampleFormatType& s, float newValue) noexcept { s.setAsFloatLE (newValue); } + template static int32 getAsInt32 (SampleFormatType& s) noexcept { return s.getAsInt32LE(); } + template static void setAsInt32 (SampleFormatType& s, int32 newValue) noexcept { s.setAsInt32LE (newValue); } + template static void copyFrom (DestType& dest, SourceType& source) noexcept { dest.copyFromLE (source); } enum { isBigEndian = 0 }; }; @@ -102,9 +102,9 @@ class JUCE_API AudioData inline void advance() noexcept { ++data; } inline void skip (int numSamples) noexcept { data += numSamples; } - inline float getAsFloatLE() const noexcept { return (float) (*data * (1.0 / (1.0 + maxValue))); } + inline float getAsFloatLE() const noexcept { return (float) (*data * (1.0 / (1.0 + (double) maxValue))); } inline float getAsFloatBE() const noexcept { return getAsFloatLE(); } - inline void setAsFloatLE (float newValue) noexcept { *data = (int8) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue))); } + inline void setAsFloatLE (float newValue) noexcept { *data = (int8) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + (double) maxValue))); } inline void setAsFloatBE (float newValue) noexcept { setAsFloatLE (newValue); } inline int32 getAsInt32LE() const noexcept { return (int) (*((uint8*) data) << 24); } inline int32 getAsInt32BE() const noexcept { return getAsInt32LE(); } @@ -127,9 +127,9 @@ class JUCE_API AudioData inline void advance() noexcept { ++data; } inline void skip (int numSamples) noexcept { data += numSamples; } - inline float getAsFloatLE() const noexcept { return (float) ((*data - 128) * (1.0 / (1.0 + maxValue))); } + inline float getAsFloatLE() const noexcept { return (float) ((*data - 128) * (1.0 / (1.0 + (double) maxValue))); } inline float getAsFloatBE() const noexcept { return getAsFloatLE(); } - inline void setAsFloatLE (float newValue) noexcept { *data = (uint8) jlimit (0, 255, 128 + roundToInt (newValue * (1.0 + maxValue))); } + inline void setAsFloatLE (float newValue) noexcept { *data = (uint8) jlimit (0, 255, 128 + roundToInt (newValue * (1.0 + (double) maxValue))); } inline void setAsFloatBE (float newValue) noexcept { setAsFloatLE (newValue); } inline int32 getAsInt32LE() const noexcept { return (int) (((uint8) (*data - 128)) << 24); } inline int32 getAsInt32BE() const noexcept { return getAsInt32LE(); } @@ -152,10 +152,10 @@ class JUCE_API AudioData inline void advance() noexcept { ++data; } inline void skip (int numSamples) noexcept { data += numSamples; } - inline float getAsFloatLE() const noexcept { return (float) ((1.0 / (1.0 + maxValue)) * (int16) ByteOrder::swapIfBigEndian (*data)); } - inline float getAsFloatBE() const noexcept { return (float) ((1.0 / (1.0 + maxValue)) * (int16) ByteOrder::swapIfLittleEndian (*data)); } - inline void setAsFloatLE (float newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint16) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue)))); } - inline void setAsFloatBE (float newValue) noexcept { *data = ByteOrder::swapIfLittleEndian ((uint16) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue)))); } + inline float getAsFloatLE() const noexcept { return (float) ((1.0 / (1.0 + (double) maxValue)) * (int16) ByteOrder::swapIfBigEndian (*data)); } + inline float getAsFloatBE() const noexcept { return (float) ((1.0 / (1.0 + (double) maxValue)) * (int16) ByteOrder::swapIfLittleEndian (*data)); } + inline void setAsFloatLE (float newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint16) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + (double) maxValue)))); } + inline void setAsFloatBE (float newValue) noexcept { *data = ByteOrder::swapIfLittleEndian ((uint16) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + (double) maxValue)))); } inline int32 getAsInt32LE() const noexcept { return (int32) (ByteOrder::swapIfBigEndian ((uint16) *data) << 16); } inline int32 getAsInt32BE() const noexcept { return (int32) (ByteOrder::swapIfLittleEndian ((uint16) *data) << 16); } inline void setAsInt32LE (int32 newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint16) (newValue >> 16)); } @@ -177,10 +177,10 @@ class JUCE_API AudioData inline void advance() noexcept { data += 3; } inline void skip (int numSamples) noexcept { data += 3 * numSamples; } - inline float getAsFloatLE() const noexcept { return (float) (ByteOrder::littleEndian24Bit (data) * (1.0 / (1.0 + maxValue))); } - inline float getAsFloatBE() const noexcept { return (float) (ByteOrder::bigEndian24Bit (data) * (1.0 / (1.0 + maxValue))); } - inline void setAsFloatLE (float newValue) noexcept { ByteOrder::littleEndian24BitToChars (jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue))), data); } - inline void setAsFloatBE (float newValue) noexcept { ByteOrder::bigEndian24BitToChars (jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue))), data); } + inline float getAsFloatLE() const noexcept { return (float) (ByteOrder::littleEndian24Bit (data) * (1.0 / (1.0 + (double) maxValue))); } + inline float getAsFloatBE() const noexcept { return (float) (ByteOrder::bigEndian24Bit (data) * (1.0 / (1.0 + (double) maxValue))); } + inline void setAsFloatLE (float newValue) noexcept { ByteOrder::littleEndian24BitToChars (jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + (double) maxValue))), data); } + inline void setAsFloatBE (float newValue) noexcept { ByteOrder::bigEndian24BitToChars (jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + (double) maxValue))), data); } inline int32 getAsInt32LE() const noexcept { return (int32) (((unsigned int) ByteOrder::littleEndian24Bit (data)) << 8); } inline int32 getAsInt32BE() const noexcept { return (int32) (((unsigned int) ByteOrder::bigEndian24Bit (data)) << 8); } inline void setAsInt32LE (int32 newValue) noexcept { ByteOrder::littleEndian24BitToChars (newValue >> 8, data); } @@ -202,10 +202,10 @@ class JUCE_API AudioData inline void advance() noexcept { ++data; } inline void skip (int numSamples) noexcept { data += numSamples; } - inline float getAsFloatLE() const noexcept { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfBigEndian (*data)); } - inline float getAsFloatBE() const noexcept { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfLittleEndian (*data)); } - inline void setAsFloatLE (float newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint32) (int32) (maxValue * jlimit (-1.0, 1.0, (double) newValue))); } - inline void setAsFloatBE (float newValue) noexcept { *data = ByteOrder::swapIfLittleEndian ((uint32) (int32) (maxValue * jlimit (-1.0, 1.0, (double) newValue))); } + inline float getAsFloatLE() const noexcept { return (float) ((1.0 / (1.0 + (double) maxValue)) * (int32) ByteOrder::swapIfBigEndian (*data)); } + inline float getAsFloatBE() const noexcept { return (float) ((1.0 / (1.0 + (double) maxValue)) * (int32) ByteOrder::swapIfLittleEndian (*data)); } + inline void setAsFloatLE (float newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint32) (int32) ((double) maxValue * jlimit (-1.0, 1.0, (double) newValue))); } + inline void setAsFloatBE (float newValue) noexcept { *data = ByteOrder::swapIfLittleEndian ((uint32) (int32) ((double) maxValue * jlimit (-1.0, 1.0, (double) newValue))); } inline int32 getAsInt32LE() const noexcept { return (int32) ByteOrder::swapIfBigEndian (*data); } inline int32 getAsInt32BE() const noexcept { return (int32) ByteOrder::swapIfLittleEndian (*data); } inline void setAsInt32LE (int32 newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint32) newValue); } @@ -226,10 +226,10 @@ class JUCE_API AudioData public: inline Int24in32 (void* d) noexcept : Int32 (d) {} - inline float getAsFloatLE() const noexcept { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfBigEndian (*data)); } - inline float getAsFloatBE() const noexcept { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfLittleEndian (*data)); } - inline void setAsFloatLE (float newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint32) (maxValue * jlimit (-1.0, 1.0, (double) newValue))); } - inline void setAsFloatBE (float newValue) noexcept { *data = ByteOrder::swapIfLittleEndian ((uint32) (maxValue * jlimit (-1.0, 1.0, (double) newValue))); } + inline float getAsFloatLE() const noexcept { return (float) ((1.0 / (1.0 + (double) maxValue)) * (int32) ByteOrder::swapIfBigEndian (*data)); } + inline float getAsFloatBE() const noexcept { return (float) ((1.0 / (1.0 + (double) maxValue)) * (int32) ByteOrder::swapIfLittleEndian (*data)); } + inline void setAsFloatLE (float newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint32) ((double) maxValue * jlimit (-1.0, 1.0, (double) newValue))); } + inline void setAsFloatBE (float newValue) noexcept { *data = ByteOrder::swapIfLittleEndian ((uint32) ((double) maxValue * jlimit (-1.0, 1.0, (double) newValue))); } inline int32 getAsInt32LE() const noexcept { return (int32) ByteOrder::swapIfBigEndian (*data) << 8; } inline int32 getAsInt32BE() const noexcept { return (int32) ByteOrder::swapIfLittleEndian (*data) << 8; } inline void setAsInt32LE (int32 newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint32) newValue >> 8); } @@ -261,8 +261,8 @@ class JUCE_API AudioData #endif inline int32 getAsInt32LE() const noexcept { return (int32) roundToInt (jlimit (-1.0, 1.0, (double) getAsFloatLE()) * (double) maxValue); } inline int32 getAsInt32BE() const noexcept { return (int32) roundToInt (jlimit (-1.0, 1.0, (double) getAsFloatBE()) * (double) maxValue); } - inline void setAsInt32LE (int32 newValue) noexcept { setAsFloatLE ((float) (newValue * (1.0 / (1.0 + maxValue)))); } - inline void setAsInt32BE (int32 newValue) noexcept { setAsFloatBE ((float) (newValue * (1.0 / (1.0 + maxValue)))); } + inline void setAsInt32LE (int32 newValue) noexcept { setAsFloatLE ((float) (newValue * (1.0 / (1.0 + (double) maxValue)))); } + inline void setAsInt32BE (int32 newValue) noexcept { setAsFloatBE ((float) (newValue * (1.0 / (1.0 + (double) maxValue)))); } inline void clear() noexcept { *data = 0; } inline void clearMultiple (int num) noexcept { zeromem (data, (size_t) (num * bytesPerSample)) ;} template inline void copyFromLE (SourceType& source) noexcept { setAsFloatLE (source.getAsFloat()); } @@ -277,14 +277,14 @@ class JUCE_API AudioData class NonInterleaved { public: - inline NonInterleaved() noexcept {} - inline NonInterleaved (const NonInterleaved&) noexcept {} + inline NonInterleaved() = default; + inline NonInterleaved (const NonInterleaved&) = default; inline NonInterleaved (const int) noexcept {} inline void copyFrom (const NonInterleaved&) noexcept {} template inline void advanceData (SampleFormatType& s) noexcept { s.advance(); } template inline void advanceDataBy (SampleFormatType& s, int numSamples) noexcept { s.skip (numSamples); } template inline void clear (SampleFormatType& s, int numSamples) noexcept { s.clearMultiple (numSamples); } - template inline static int getNumBytesBetweenSamples (const SampleFormatType&) noexcept { return SampleFormatType::bytesPerSample; } + template static int getNumBytesBetweenSamples (const SampleFormatType&) noexcept { return SampleFormatType::bytesPerSample; } enum { isInterleavedType = 0, numInterleavedChannels = 1 }; }; @@ -292,15 +292,15 @@ class JUCE_API AudioData class Interleaved { public: - inline Interleaved() noexcept : numInterleavedChannels (1) {} - inline Interleaved (const Interleaved& other) noexcept : numInterleavedChannels (other.numInterleavedChannels) {} + inline Interleaved() noexcept {} + inline Interleaved (const Interleaved& other) = default; inline Interleaved (const int numInterleavedChans) noexcept : numInterleavedChannels (numInterleavedChans) {} inline void copyFrom (const Interleaved& other) noexcept { numInterleavedChannels = other.numInterleavedChannels; } template inline void advanceData (SampleFormatType& s) noexcept { s.skip (numInterleavedChannels); } template inline void advanceDataBy (SampleFormatType& s, int numSamples) noexcept { s.skip (numInterleavedChannels * numSamples); } template inline void clear (SampleFormatType& s, int numSamples) noexcept { while (--numSamples >= 0) { s.clear(); s.skip (numInterleavedChannels); } } template inline int getNumBytesBetweenSamples (const SampleFormatType&) const noexcept { return numInterleavedChannels * SampleFormatType::bytesPerSample; } - int numInterleavedChannels; + int numInterleavedChannels = 1; enum { isInterleavedType = 1 }; }; @@ -308,16 +308,16 @@ class JUCE_API AudioData class NonConst { public: - typedef void VoidType; - static inline void* toVoidPtr (VoidType* v) noexcept { return v; } + using VoidType = void; + static void* toVoidPtr (VoidType* v) noexcept { return v; } enum { isConst = 0 }; }; class Const { public: - typedef const void VoidType; - static inline void* toVoidPtr (VoidType* v) noexcept { return const_cast (v); } + using VoidType = const void; + static void* toVoidPtr (VoidType* v) noexcept { return const_cast (v); } enum { isConst = 1 }; }; #endif @@ -528,8 +528,8 @@ class JUCE_API AudioData if (v < mn) mn = v; } - return Range (mn * (float) (1.0 / (1.0 + Int32::maxValue)), - mx * (float) (1.0 / (1.0 + Int32::maxValue))); + return Range ((float) mn * (float) (1.0 / (1.0 + (double) Int32::maxValue)), + (float) mx * (float) (1.0 / (1.0 + (double) Int32::maxValue))); } /** Scans a block of data, returning the lowest and highest levels as floats */ @@ -587,7 +587,7 @@ class JUCE_API AudioData class Converter { public: - virtual ~Converter() {} + virtual ~Converter() = default; /** Converts a sequence of samples from the converter's source format into the dest format. */ virtual void convertSamples (void* destSamples, const void* sourceSamples, int numSamples) const = 0; @@ -639,11 +639,152 @@ class JUCE_API AudioData const int sourceChannels, destChannels; }; -}; + //============================================================================== + /** A struct that contains a SampleFormat and Endianness to be used with the source and + destination types when calling the interleaveSamples() and deinterleaveSamples() helpers. + + @see interleaveSamples, deinterleaveSamples + */ + template + struct Format + { + using DataFormat = DataFormatIn; + using Endianness = EndiannessIn; + }; + +private: + template + struct ChannelDataSubtypes; + + template + struct ChannelDataSubtypes + { + using ElementType = std::remove_pointer_t; + using ChannelType = std::conditional_t; + using DataType = std::conditional_t; + using PointerType = Pointer, + std::conditional_t>; + }; + + template + struct ChannelDataSubtypes> + { + using Subtypes = ChannelDataSubtypes; + using DataType = typename Subtypes::DataType; + using PointerType = typename Subtypes::PointerType; + }; + + template + struct ChannelData + { + using Subtypes = ChannelDataSubtypes; + using DataType = typename Subtypes::DataType; + using PointerType = typename Subtypes::PointerType; + DataType data; + int channels; + }; + +public: + //============================================================================== + /** A sequence of interleaved samples used as the source for the deinterleaveSamples() method. */ + template using InterleavedSource = ChannelData; + /** A sequence of interleaved samples used as the destination for the interleaveSamples() method. */ + template using InterleavedDest = ChannelData; + /** A sequence of non-interleaved samples used as the source for the interleaveSamples() method. */ + template using NonInterleavedSource = ChannelData; + /** A sequence of non-interleaved samples used as the destination for the deinterleaveSamples() method. */ + template using NonInterleavedDest = ChannelData; + + /** A helper function for converting a sequence of samples from a non-interleaved source + to an interleaved destination. + + When calling this method you need to specify the source and destination data format and endianness + from the AudioData SampleFormat and Endianness types and provide the data and number of channels + for each. For example, to convert a floating-point stream of big endian samples to an interleaved, + native endian stream of 16-bit integer samples you would do the following: + + @code + using SourceFormat = AudioData::Format; + using DestFormat = AudioData::Format; + + AudioData::interleaveSamples (AudioData::NonInterleavedSource { sourceData, numSourceChannels }, + AudioData::InterleavedDest { destData, numDestChannels }, + numSamples); + @endcode + */ + template + static void interleaveSamples (NonInterleavedSource source, + InterleavedDest dest, + int numSamples) + { + using SourceType = typename decltype (source)::PointerType; + using DestType = typename decltype (dest) ::PointerType; + + for (int i = 0; i < dest.channels; ++i) + { + const DestType destType (addBytesToPointer (dest.data, i * DestType::getBytesPerSample()), dest.channels); + + if (i < source.channels) + { + if (*source.data != nullptr) + { + destType.convertSamples (SourceType { *source.data }, numSamples); + ++source.data; + } + } + else + { + destType.clearSamples (numSamples); + } + } + } + + /** A helper function for converting a sequence of samples from an interleaved source + to a non-interleaved destination. + + When calling this method you need to specify the source and destination data format and endianness + from the AudioData SampleFormat and Endianness types and provide the data and number of channels + for each. For example, to convert a floating-point stream of big endian samples to an non-interleaved, + native endian stream of 16-bit integer samples you would do the following: + + @code + using SourceFormat = AudioData::Format; + using DestFormat = AudioData::Format; + + AudioData::deinterleaveSamples (AudioData::InterleavedSource { sourceData, numSourceChannels }, + AudioData::NonInterleavedDest { destData, numDestChannels }, + numSamples); + @endcode + */ + template + static void deinterleaveSamples (InterleavedSource source, + NonInterleavedDest dest, + int numSamples) + { + using SourceType = typename decltype (source)::PointerType; + using DestType = typename decltype (dest) ::PointerType; + + for (int i = 0; i < dest.channels; ++i) + { + if (auto* targetChan = dest.data[i]) + { + const DestType destType (targetChan); + + if (i < source.channels) + destType.convertSamples (SourceType (addBytesToPointer (source.data, i * SourceType::getBytesPerSample()), source.channels), numSamples); + else + destType.clearSamples (numSamples); + } + } + } +}; //============================================================================== +#ifndef DOXYGEN /** A set of routines to convert buffers of 32-bit floating point data to and from various integer formats. @@ -653,7 +794,7 @@ class JUCE_API AudioData @tags{Audio} */ -class JUCE_API AudioDataConverters +class [[deprecated]] JUCE_API AudioDataConverters { public: //============================================================================== @@ -710,7 +851,7 @@ class JUCE_API AudioDataConverters private: AudioDataConverters(); - JUCE_DECLARE_NON_COPYABLE (AudioDataConverters) }; +#endif } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.cpp b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.cpp new file mode 100644 index 00000000..52697cfa --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.cpp @@ -0,0 +1,92 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +AudioProcessLoadMeasurer::AudioProcessLoadMeasurer() = default; +AudioProcessLoadMeasurer::~AudioProcessLoadMeasurer() = default; + +void AudioProcessLoadMeasurer::reset() +{ + reset (0, 0); +} + +void AudioProcessLoadMeasurer::reset (double sampleRate, int blockSize) +{ + cpuUsageProportion = 0; + xruns = 0; + + samplesPerBlock = blockSize; + + if (sampleRate > 0.0 && blockSize > 0) + { + msPerSample = 1000.0 / sampleRate; + timeToCpuScale = (msPerSample > 0.0) ? (1.0 / msPerSample) : 0.0; + } + else + { + msPerSample = 0; + timeToCpuScale = 0; + } +} + +void AudioProcessLoadMeasurer::registerBlockRenderTime (double milliseconds) +{ + registerRenderTime (milliseconds, samplesPerBlock); +} + +void AudioProcessLoadMeasurer::registerRenderTime (double milliseconds, int numSamples) +{ + const auto maxMilliseconds = numSamples * msPerSample; + const auto usedProportion = milliseconds / maxMilliseconds; + const auto filterAmount = 0.2; + cpuUsageProportion += filterAmount * (usedProportion - cpuUsageProportion); + + if (milliseconds > maxMilliseconds) + ++xruns; +} + +double AudioProcessLoadMeasurer::getLoadAsProportion() const { return jlimit (0.0, 1.0, cpuUsageProportion); } +double AudioProcessLoadMeasurer::getLoadAsPercentage() const { return 100.0 * getLoadAsProportion(); } + +int AudioProcessLoadMeasurer::getXRunCount() const { return xruns; } + +AudioProcessLoadMeasurer::ScopedTimer::ScopedTimer (AudioProcessLoadMeasurer& p) + : ScopedTimer (p, p.samplesPerBlock) +{ +} + +AudioProcessLoadMeasurer::ScopedTimer::ScopedTimer (AudioProcessLoadMeasurer& p, int numSamplesInBlock) + : owner (p), startTime (Time::getMillisecondCounterHiRes()), samplesInBlock (numSamplesInBlock) +{ + // numSamplesInBlock should never be zero. Did you remember to call AudioProcessLoadMeasurer::reset(), + // passing the expected samples per block? + jassert (numSamplesInBlock); +} + +AudioProcessLoadMeasurer::ScopedTimer::~ScopedTimer() +{ + owner.registerRenderTime (Time::getMillisecondCounterHiRes() - startTime, samplesInBlock); +} + +} // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.h b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.h new file mode 100644 index 00000000..ea0c1f76 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.h @@ -0,0 +1,104 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +//============================================================================== +/** + Maintains an ongoing measurement of the proportion of time which is being + spent inside an audio callback. + + @tags{Audio} +*/ +class JUCE_API AudioProcessLoadMeasurer +{ +public: + /** */ + AudioProcessLoadMeasurer(); + + /** Destructor. */ + ~AudioProcessLoadMeasurer(); + + //============================================================================== + /** Resets the state. */ + void reset(); + + /** Resets the counter, in preparation for use with the given sample rate and block size. */ + void reset (double sampleRate, int blockSize); + + /** Returns the current load as a proportion 0 to 1.0 */ + double getLoadAsProportion() const; + + /** Returns the current load as a percentage 0 to 100.0 */ + double getLoadAsPercentage() const; + + /** Returns the number of over- (or under-) runs recorded since the state was reset. */ + int getXRunCount() const; + + //============================================================================== + /** This class measures the time between its construction and destruction and + adds it to an AudioProcessLoadMeasurer. + + e.g. + @code + { + AudioProcessLoadMeasurer::ScopedTimer timer (myProcessLoadMeasurer); + myCallback->doTheCallback(); + } + @endcode + + @tags{Audio} + */ + struct JUCE_API ScopedTimer + { + ScopedTimer (AudioProcessLoadMeasurer&); + ScopedTimer (AudioProcessLoadMeasurer&, int numSamplesInBlock); + ~ScopedTimer(); + + private: + AudioProcessLoadMeasurer& owner; + double startTime; + int samplesInBlock; + + JUCE_DECLARE_NON_COPYABLE (ScopedTimer) + }; + + /** Can be called manually to add the time of a callback to the stats. + Normally you probably would never call this - it's simpler and more robust to + use a ScopedTimer to measure the time using an RAII pattern. + */ + void registerBlockRenderTime (double millisecondsTaken); + + /** Can be called manually to add the time of a callback to the stats. + Normally you probably would never call this - it's simpler and more robust to + use a ScopedTimer to measure the time using an RAII pattern. + */ + void registerRenderTime (double millisecondsTaken, int numSamples); + +private: + double cpuUsageProportion = 0, timeToCpuScale = 0, msPerSample = 0; + int xruns = 0, samplesPerBlock = 0; +}; + + +} // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h index 8ad74ea8..8d4b9229 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h +++ b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -23,6 +23,53 @@ namespace juce { +#ifndef DOXYGEN +/** The contents of this namespace are used to implement AudioBuffer and should + not be used elsewhere. Their interfaces (and existence) are liable to change! +*/ +namespace detail +{ + /** On iOS/arm7 the alignment of `double` is greater than the alignment of + `std::max_align_t`, so we can't trust max_align_t. Instead, we query + lots of primitive types and use the maximum alignment of all of them. + + We're putting this stuff outside AudioBuffer itself to avoid creating + unnecessary copies for each distinct template instantiation of + AudioBuffer. + + MSVC 2015 doesn't like when we write getMaxAlignment as a loop which + accumulates the max alignment (declarations not allowed in constexpr + function body) so instead we use this recursive version which + instantiates a zillion templates. + */ + + template struct Type {}; + + constexpr size_t getMaxAlignment() noexcept { return 0; } + + template + constexpr size_t getMaxAlignment (Type, Type... tail) noexcept + { + return jmax (alignof (Head), getMaxAlignment (tail...)); + } + + constexpr size_t maxAlignment = getMaxAlignment (Type{}, + Type{}, + Type{}, + Type{}, + Type{}, + Type{}, + Type{}, + Type{}, + Type{}, + Type{}, + Type{}, + Type{}, + Type{}, + Type{}); +} // namespace detail +#endif + //============================================================================== /** A multi-channel buffer containing floating point audio samples. @@ -116,7 +163,7 @@ class AudioBuffer /** Copies another buffer. This buffer will make its own copy of the other's data, unless the buffer was created - using an external data buffer, in which case boths buffers will just point to the same + using an external data buffer, in which case both buffers will just point to the same shared block of data. */ AudioBuffer (const AudioBuffer& other) @@ -145,6 +192,7 @@ class AudioBuffer } /** Copies another buffer onto this one. + This buffer's size will be changed to that of the other buffer. */ AudioBuffer& operator= (const AudioBuffer& other) @@ -170,16 +218,17 @@ class AudioBuffer } /** Destructor. + This will free any memory allocated by the buffer. */ - ~AudioBuffer() noexcept {} + ~AudioBuffer() = default; - /** Move constructor */ + /** Move constructor. */ AudioBuffer (AudioBuffer&& other) noexcept : numChannels (other.numChannels), size (other.size), allocatedBytes (other.allocatedBytes), - allocatedData (static_cast&&> (other.allocatedData)), + allocatedData (std::move (other.allocatedData)), isClear (other.isClear) { if (numChannels < (int) numElementsInArray (preallocatedChannelSpace)) @@ -199,13 +248,13 @@ class AudioBuffer other.allocatedBytes = 0; } - /** Move assignment */ + /** Move assignment. */ AudioBuffer& operator= (AudioBuffer&& other) noexcept { numChannels = other.numChannels; size = other.size; allocatedBytes = other.allocatedBytes; - allocatedData = static_cast&&> (other.allocatedData); + allocatedData = std::move (other.allocatedData); isClear = other.isClear; if (numChannels < (int) numElementsInArray (preallocatedChannelSpace)) @@ -228,18 +277,22 @@ class AudioBuffer //============================================================================== /** Returns the number of channels of audio data that this buffer contains. + @see getNumSamples, getReadPointer, getWritePointer */ int getNumChannels() const noexcept { return numChannels; } /** Returns the number of samples allocated in each of the buffer's channels. + @see getNumChannels, getReadPointer, getWritePointer */ int getNumSamples() const noexcept { return size; } /** Returns a pointer to an array of read-only samples in one of the buffer's channels. + For speed, this doesn't check whether the channel number is out of range, so be careful when using it! + If you need to write to the data, do NOT call this method and const_cast the result! Instead, you must call getWritePointer so that the buffer knows you're planning on modifying the data. @@ -251,8 +304,10 @@ class AudioBuffer } /** Returns a pointer to an array of read-only samples in one of the buffer's channels. + For speed, this doesn't check whether the channel number or index are out of range, so be careful when using it! + If you need to write to the data, do NOT call this method and const_cast the result! Instead, you must call getWritePointer so that the buffer knows you're planning on modifying the data. @@ -265,10 +320,20 @@ class AudioBuffer } /** Returns a writeable pointer to one of the buffer's channels. + For speed, this doesn't check whether the channel number is out of range, so be careful when using it! + Note that if you're not planning on writing to the data, you should always use getReadPointer instead. + + This will mark the buffer as not cleared and the hasBeenCleared method will return + false after this call. If you retain this write pointer and write some data to + the buffer after calling its clear method, subsequent clear calls will do nothing. + To avoid this either call this method each time you need to write data, or use the + setNotClear method to force the internal cleared flag to false. + + @see setNotClear */ Type* getWritePointer (int channelNumber) noexcept { @@ -278,10 +343,20 @@ class AudioBuffer } /** Returns a writeable pointer to one of the buffer's channels. + For speed, this doesn't check whether the channel number or index are out of range, so be careful when using it! + Note that if you're not planning on writing to the data, you should use getReadPointer instead. + + This will mark the buffer as not cleared and the hasBeenCleared method will return + false after this call. If you retain this write pointer and write some data to + the buffer after calling its clear method, subsequent clear calls will do nothing. + To avoid this either call this method each time you need to write data, or use the + setNotClear method to force the internal cleared flag to false. + + @see setNotClear */ Type* getWritePointer (int channelNumber, int sampleIndex) noexcept { @@ -302,6 +377,14 @@ class AudioBuffer Don't modify any of the pointers that are returned, and bear in mind that these will become invalid if the buffer is resized. + + This will mark the buffer as not cleared and the hasBeenCleared method will return + false after this call. If you retain this write pointer and write some data to + the buffer after calling its clear method, subsequent clear calls will do nothing. + To avoid this either call this method each time you need to write data, or use the + setNotClear method to force the internal cleared flag to false. + + @see setNotClear */ Type** getArrayOfWritePointers() noexcept { isClear = false; return channels; } @@ -310,23 +393,23 @@ class AudioBuffer This can expand or contract the buffer's length, and add or remove channels. - If keepExistingContent is true, it will try to preserve as much of the - old data as it can in the new buffer. - - If clearExtraSpace is true, then any extra channels or space that is - allocated will be also be cleared. If false, then this space is left - uninitialised. - - If avoidReallocating is true, then changing the buffer's size won't reduce the - amount of memory that is currently allocated (but it will still increase it if - the new size is bigger than the amount it currently has). If this is false, then - a new allocation will be done so that the buffer uses takes up the minimum amount - of memory that it needs. - Note that if keepExistingContent and avoidReallocating are both true, then it will only avoid reallocating if neither the channel count or length in samples increase. If the required memory can't be allocated, this will throw a std::bad_alloc exception. + + @param newNumChannels the new number of channels. + @param newNumSamples the new number of samples. + @param keepExistingContent if this is true, it will try to preserve as much of the + old data as it can in the new buffer. + @param clearExtraSpace if this is true, then any extra channels or space that is + allocated will be also be cleared. If false, then this space is left + uninitialised. + @param avoidReallocating if this is true, then changing the buffer's size won't reduce the + amount of memory that is currently allocated (but it will still + increase it if the new size is bigger than the amount it currently has). + If this is false, then a new allocation will be done so that the buffer + uses takes up the minimum amount of memory that it needs. */ void setSize (int newNumChannels, int newNumSamples, @@ -340,7 +423,7 @@ class AudioBuffer if (newNumSamples != size || newNumChannels != numChannels) { auto allocatedSamplesPerChannel = ((size_t) newNumSamples + 3) & ~3u; - auto channelListSize = ((sizeof (Type*) * (size_t) (newNumChannels + 1)) + 15) & ~15u; + auto channelListSize = ((static_cast (1 + newNumChannels) * sizeof (Type*)) + 15) & ~15u; auto newTotalBytes = ((size_t) newNumChannels * (size_t) allocatedSamplesPerChannel * sizeof (Type)) + channelListSize + 32; @@ -357,8 +440,8 @@ class AudioBuffer auto numSamplesToCopy = (size_t) jmin (newNumSamples, size); - auto newChannels = reinterpret_cast (newData.get()); - auto newChan = reinterpret_cast (newData + channelListSize); + auto newChannels = unalignedPointerCast (newData.get()); + auto newChan = unalignedPointerCast (newData + channelListSize); for (int j = 0; j < newNumChannels; ++j) { @@ -390,10 +473,10 @@ class AudioBuffer { allocatedBytes = newTotalBytes; allocatedData.allocate (newTotalBytes, clearExtraSpace || isClear); - channels = reinterpret_cast (allocatedData.get()); + channels = unalignedPointerCast (allocatedData.get()); } - auto* chan = reinterpret_cast (allocatedData + channelListSize); + auto* chan = unalignedPointerCast (allocatedData + channelListSize); for (int i = 0; i < newNumChannels; ++i) { @@ -417,6 +500,8 @@ class AudioBuffer will re-allocate memory internally and copy the existing data to this new area, so it will then stop directly addressing this memory. + The hasBeenCleared method will return false after this call. + @param dataToReferTo a pre-allocated array containing pointers to the data for each channel that should be used by this buffer. The buffer will only refer to this memory, it won't try to delete @@ -457,6 +542,8 @@ class AudioBuffer will re-allocate memory internally and copy the existing data to this new area, so it will then stop directly addressing this memory. + The hasBeenCleared method will return false after this call. + @param dataToReferTo a pre-allocated array containing pointers to the data for each channel that should be used by this buffer. The buffer will only refer to this memory, it won't try to delete @@ -474,8 +561,12 @@ class AudioBuffer } /** Resizes this buffer to match the given one, and copies all of its content across. + The source buffer can contain a different floating point type, so this can be used to convert between 32 and 64 bit float buffer types. + + The hasBeenCleared method will return false after this call if the other buffer + contains data. */ template void makeCopyOf (const AudioBuffer& other, bool avoidReallocating = false) @@ -502,7 +593,13 @@ class AudioBuffer } //============================================================================== - /** Clears all the samples in all channels. */ + /** Clears all the samples in all channels and marks the buffer as cleared. + + This method will do nothing if the buffer has been marked as cleared (i.e. the + hasBeenCleared method returns true.) + + @see hasBeenCleared, setNotClear + */ void clear() noexcept { if (! isClear) @@ -516,8 +613,15 @@ class AudioBuffer /** Clears a specified region of all the channels. + This will mark the buffer as cleared if the entire buffer contents are cleared. + For speed, this doesn't check whether the channel and sample number are in-range, so be careful! + + This method will do nothing if the buffer has been marked as cleared (i.e. the + hasBeenCleared method returns true.) + + @see hasBeenCleared, setNotClear */ void clear (int startSample, int numSamples) noexcept { @@ -525,11 +629,10 @@ class AudioBuffer if (! isClear) { - if (startSample == 0 && numSamples == size) - isClear = true; - for (int i = 0; i < numChannels; ++i) FloatVectorOperations::clear (channels[i] + startSample, numSamples); + + isClear = (startSample == 0 && numSamples == size); } } @@ -537,6 +640,11 @@ class AudioBuffer For speed, this doesn't check whether the channel and sample number are in-range, so be careful! + + This method will do nothing if the buffer has been marked as cleared (i.e. the + hasBeenCleared method returns true.) + + @see hasBeenCleared, setNotClear */ void clear (int channel, int startSample, int numSamples) noexcept { @@ -548,15 +656,26 @@ class AudioBuffer } /** Returns true if the buffer has been entirely cleared. + Note that this does not actually measure the contents of the buffer - it simply returns a flag that is set when the buffer is cleared, and which is reset whenever - functions like getWritePointer() are invoked. That means the method does not take - any time, but it may return false negatives when in fact the buffer is still empty. + functions like getWritePointer are invoked. That means the method is quick, but it + may return false negatives when in fact the buffer is still empty. */ bool hasBeenCleared() const noexcept { return isClear; } + /** Forces the internal cleared flag of the buffer to false. + + This may be useful in the case where you are holding on to a write pointer and call + the clear method before writing some data. You can then use this method to mark the + buffer as containing data so that subsequent clear calls will succeed. However a + better solution is to call getWritePointer each time you need to write data. + */ + void setNotClear() noexcept { isClear = false; } + //============================================================================== /** Returns a sample from the buffer. + The channel and index are not checked - they are expected to be in-range. If not, an assertion will be thrown, but in a release build, you're into 'undefined behaviour' territory. @@ -569,9 +688,12 @@ class AudioBuffer } /** Sets a sample in the buffer. + The channel and index are not checked - they are expected to be in-range. If not, an assertion will be thrown, but in a release build, you're into 'undefined behaviour' territory. + + The hasBeenCleared method will return false after this call. */ void setSample (int destChannel, int destSample, Type newValue) noexcept { @@ -582,9 +704,12 @@ class AudioBuffer } /** Adds a value to a sample in the buffer. + The channel and index are not checked - they are expected to be in-range. If not, an assertion will be thrown, but in a release build, you're into 'undefined behaviour' territory. + + The hasBeenCleared method will return false after this call. */ void addSample (int destChannel, int destSample, Type valueToAdd) noexcept { @@ -685,6 +810,9 @@ class AudioBuffer /** Adds samples from another buffer to this one. + The hasBeenCleared method will return false after this call if samples have + been added. + @param destChannel the channel within this buffer to add the samples to @param destStartSample the start sample within this buffer's channel @param source the source buffer to add from @@ -704,7 +832,10 @@ class AudioBuffer int numSamples, Type gainToApplyToSource = Type (1)) noexcept { - jassert (&source != this || sourceChannel != destChannel); + jassert (&source != this + || sourceChannel != destChannel + || sourceStartSample + numSamples <= destStartSample + || destStartSample + numSamples <= sourceStartSample); jassert (isPositiveAndBelow (destChannel, numChannels)); jassert (destStartSample >= 0 && numSamples >= 0 && destStartSample + numSamples <= size); jassert (isPositiveAndBelow (sourceChannel, source.numChannels)); @@ -736,6 +867,9 @@ class AudioBuffer /** Adds samples from an array of floats to one of the channels. + The hasBeenCleared method will return false after this call if samples have + been added. + @param destChannel the channel within this buffer to add the samples to @param destStartSample the start sample within this buffer's channel @param source the source data to use @@ -781,6 +915,9 @@ class AudioBuffer /** Adds samples from an array of floats, applying a gain ramp to them. + The hasBeenCleared method will return false after this call if samples have + been added. + @param destChannel the channel within this buffer to add the samples to @param destStartSample the start sample within this buffer's channel @param source the source data to use @@ -840,7 +977,10 @@ class AudioBuffer int sourceStartSample, int numSamples) noexcept { - jassert (&source != this || sourceChannel != destChannel); + jassert (&source != this + || sourceChannel != destChannel + || sourceStartSample + numSamples <= destStartSample + || destStartSample + numSamples <= sourceStartSample); jassert (isPositiveAndBelow (destChannel, numChannels)); jassert (destStartSample >= 0 && destStartSample + numSamples <= size); jassert (isPositiveAndBelow (sourceChannel, source.numChannels)); @@ -865,6 +1005,9 @@ class AudioBuffer /** Copies samples from an array of floats into one of the channels. + The hasBeenCleared method will return false after this call if samples have + been copied. + @param destChannel the channel within this buffer to copy the samples to @param destStartSample the start sample within this buffer's channel @param source the source buffer to read from @@ -890,6 +1033,9 @@ class AudioBuffer /** Copies samples from an array of floats into one of the channels, applying a gain to it. + The hasBeenCleared method will return false after this call if samples have + been copied. + @param destChannel the channel within this buffer to copy the samples to @param destStartSample the start sample within this buffer's channel @param source the source buffer to read from @@ -935,6 +1081,9 @@ class AudioBuffer /** Copies samples from an array of floats into one of the channels, applying a gain ramp. + The hasBeenCleared method will return false after this call if samples have + been copied. + @param destChannel the channel within this buffer to copy the samples to @param destStartSample the start sample within this buffer's channel @param source the source buffer to read from @@ -1062,7 +1211,7 @@ class AudioBuffer //============================================================================== /** This allows templated code that takes an AudioBuffer to access its sample type. */ - typedef Type SampleType; + using SampleType = Type; private: //============================================================================== @@ -1075,12 +1224,23 @@ class AudioBuffer void allocateData() { + #if (! JUCE_GCC || (__GNUC__ * 100 + __GNUC_MINOR__) >= 409) + static_assert (alignof (Type) <= detail::maxAlignment, + "AudioBuffer cannot hold types with alignment requirements larger than that guaranteed by malloc"); + #endif jassert (size >= 0); - auto channelListSize = sizeof (Type*) * (size_t) (numChannels + 1); + + auto channelListSize = (size_t) (numChannels + 1) * sizeof (Type*); + auto requiredSampleAlignment = std::alignment_of::value; + size_t alignmentOverflow = channelListSize % requiredSampleAlignment; + + if (alignmentOverflow != 0) + channelListSize += requiredSampleAlignment - alignmentOverflow; + allocatedBytes = (size_t) numChannels * (size_t) size * sizeof (Type) + channelListSize + 32; allocatedData.malloc (allocatedBytes); - channels = reinterpret_cast (allocatedData.get()); - auto* chan = (Type*) (allocatedData + channelListSize); + channels = unalignedPointerCast (allocatedData.get()); + auto chan = unalignedPointerCast (allocatedData + channelListSize); for (int i = 0; i < numChannels; ++i) { @@ -1104,7 +1264,7 @@ class AudioBuffer else { allocatedData.malloc (numChannels + 1, sizeof (Type*)); - channels = reinterpret_cast (allocatedData.get()); + channels = unalignedPointerCast (allocatedData.get()); } for (int i = 0; i < numChannels; ++i) @@ -1125,12 +1285,12 @@ class AudioBuffer /** A multi-channel buffer of 32-bit floating point audio samples. - This typedef is here for backwards compatibility with the older AudioSampleBuffer + This type is here for backwards compatibility with the older AudioSampleBuffer class, which was fixed for 32-bit data, but is otherwise the same as the new templated AudioBuffer class. @see AudioBuffer */ -typedef AudioBuffer AudioSampleBuffer; +using AudioSampleBuffer = AudioBuffer; } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp index 4dc3a86d..47eb058f 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -30,16 +30,16 @@ namespace FloatVectorHelpers #define JUCE_INCREMENT_DEST dest += (16 / sizeof (*dest)); #if JUCE_USE_SSE_INTRINSICS - inline static bool isAligned (const void* p) noexcept + static bool isAligned (const void* p) noexcept { return (((pointer_sized_int) p) & 15) == 0; } struct BasicOps32 { - typedef float Type; - typedef __m128 ParallelType; - typedef __m128 IntegerType; + using Type = float; + using ParallelType = __m128; + using IntegerType = __m128; enum { numParallel = 4 }; // Integer and parallel types are the same for SSE. On neon they have different types @@ -69,9 +69,9 @@ namespace FloatVectorHelpers struct BasicOps64 { - typedef double Type; - typedef __m128d ParallelType; - typedef __m128d IntegerType; + using Type = double; + using ParallelType = __m128d; + using IntegerType = __m128d; enum { numParallel = 2 }; // Integer and parallel types are the same for SSE. On neon they have different types @@ -102,15 +102,15 @@ namespace FloatVectorHelpers #define JUCE_BEGIN_VEC_OP \ - typedef FloatVectorHelpers::ModeType::Mode Mode; \ + using Mode = FloatVectorHelpers::ModeType::Mode; \ { \ - const int numLongOps = num / Mode::numParallel; + const auto numLongOps = num / Mode::numParallel; #define JUCE_FINISH_VEC_OP(normalOp) \ num &= (Mode::numParallel - 1); \ if (num == 0) return; \ } \ - for (int i = 0; i < num; ++i) normalOp; + for (auto i = (decltype (num)) 0; i < num; ++i) normalOp; #define JUCE_PERFORM_VEC_OP_DEST(normalOp, vecOp, locals, setupOp) \ JUCE_BEGIN_VEC_OP \ @@ -202,9 +202,9 @@ namespace FloatVectorHelpers struct BasicOps32 { - typedef float Type; - typedef float32x4_t ParallelType; - typedef uint32x4_t IntegerType; + using Type = float; + using ParallelType = float32x4_t; + using IntegerType = uint32x4_t; union signMaskUnion { ParallelType f; IntegerType i; }; enum { numParallel = 4 }; @@ -234,9 +234,9 @@ namespace FloatVectorHelpers struct BasicOps64 { - typedef double Type; - typedef double ParallelType; - typedef uint64 IntegerType; + using Type = double; + using ParallelType = double; + using IntegerType = uint64; union signMaskUnion { ParallelType f; IntegerType i; }; enum { numParallel = 1 }; @@ -265,16 +265,16 @@ namespace FloatVectorHelpers }; #define JUCE_BEGIN_VEC_OP \ - typedef FloatVectorHelpers::ModeType::Mode Mode; \ + using Mode = FloatVectorHelpers::ModeType::Mode; \ if (Mode::numParallel > 1) \ { \ - const int numLongOps = num / Mode::numParallel; + const auto numLongOps = num / Mode::numParallel; #define JUCE_FINISH_VEC_OP(normalOp) \ num &= (Mode::numParallel - 1); \ if (num == 0) return; \ } \ - for (int i = 0; i < num; ++i) normalOp; + for (auto i = (decltype (num)) 0; i < num; ++i) normalOp; #define JUCE_PERFORM_VEC_OP_DEST(normalOp, vecOp, locals, setupOp) \ JUCE_BEGIN_VEC_OP \ @@ -304,22 +304,22 @@ namespace FloatVectorHelpers //============================================================================== #else #define JUCE_PERFORM_VEC_OP_DEST(normalOp, vecOp, locals, setupOp) \ - for (int i = 0; i < num; ++i) normalOp; + for (auto i = (decltype (num)) 0; i < num; ++i) normalOp; #define JUCE_PERFORM_VEC_OP_SRC_DEST(normalOp, vecOp, locals, increment, setupOp) \ - for (int i = 0; i < num; ++i) normalOp; + for (auto i = (decltype (num)) 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; + for (auto i = (decltype (num)) 0; i < num; ++i) normalOp; #define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST(normalOp, vecOp, locals, increment, setupOp) \ - for (int i = 0; i < num; ++i) normalOp; + for (auto i = (decltype (num)) 0; i < num; ++i) normalOp; #endif //============================================================================== #define JUCE_VEC_LOOP(vecOp, srcLoad, dstLoad, dstStore, locals, increment) \ - for (int i = 0; i < numLongOps; ++i) \ + for (auto i = (decltype (numLongOps)) 0; i < numLongOps; ++i) \ { \ locals (srcLoad, dstLoad); \ dstStore (dest, vecOp); \ @@ -327,7 +327,7 @@ namespace FloatVectorHelpers } #define JUCE_VEC_LOOP_TWO_SOURCES(vecOp, src1Load, src2Load, dstStore, locals, increment) \ - for (int i = 0; i < numLongOps; ++i) \ + for (auto i = (decltype (numLongOps)) 0; i < numLongOps; ++i) \ { \ locals (src1Load, src2Load); \ dstStore (dest, vecOp); \ @@ -335,7 +335,7 @@ namespace FloatVectorHelpers } #define JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD(vecOp, src1Load, src2Load, dstLoad, dstStore, locals, increment) \ - for (int i = 0; i < numLongOps; ++i) \ + for (auto i = (decltype (numLongOps)) 0; i < numLongOps; ++i) \ { \ locals (src1Load, src2Load, dstLoad); \ dstStore (dest, vecOp); \ @@ -353,18 +353,19 @@ namespace FloatVectorHelpers union signMask64 { double d; uint64 i; }; #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON - template struct ModeType { typedef BasicOps32 Mode; }; - template<> struct ModeType<8> { typedef BasicOps64 Mode; }; + template struct ModeType { using Mode = BasicOps32; }; + template <> struct ModeType<8> { using Mode = BasicOps64; }; template struct MinMax { - typedef typename Mode::Type Type; - typedef typename Mode::ParallelType ParallelType; + using Type = typename Mode::Type; + using ParallelType = typename Mode::ParallelType; - static Type findMinOrMax (const Type* src, int num, const bool isMinimum) noexcept + template + static Type findMinOrMax (const Type* src, Size num, const bool isMinimum) noexcept { - int numLongOps = num / Mode::numParallel; + auto numLongOps = num / Mode::numParallel; if (numLongOps > 1) { @@ -421,20 +422,24 @@ namespace FloatVectorHelpers num &= (Mode::numParallel - 1); src += Mode::numParallel; - for (int i = 0; i < num; ++i) + for (auto i = (decltype (num)) 0; i < num; ++i) result = isMinimum ? jmin (result, src[i]) : jmax (result, src[i]); return result; } - return isMinimum ? juce::findMinimum (src, num) - : juce::findMaximum (src, num); + if (num <= 0) + return 0; + + return isMinimum ? *std::min_element (src, src + num) + : *std::max_element (src, src + num); } - static Range findMinAndMax (const Type* src, int num) noexcept + template + static Range findMinAndMax (const Type* src, Size num) noexcept { - int numLongOps = num / Mode::numParallel; + auto numLongOps = num / Mode::numParallel; if (numLongOps > 1) { @@ -475,7 +480,7 @@ namespace FloatVectorHelpers num &= (Mode::numParallel - 1); src += Mode::numParallel; - for (int i = 0; i < num; ++i) + for (auto i = (decltype (num)) 0; i < num; ++i) result = result.getUnionWith (src[i]); return result; @@ -485,547 +490,941 @@ namespace FloatVectorHelpers } }; #endif -} //============================================================================== namespace { - #if JUCE_USE_VDSP_FRAMEWORK - // This casts away constness to account for slightly different vDSP function signatures - // in OSX 10.8 SDK and below. Can be safely removed once those SDKs are obsolete. - template - ValueType* osx108sdkCompatibilityCast (const ValueType* arg) noexcept { return const_cast (arg); } - #endif -} + template + void clear (float* dest, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vclr (dest, 1, (vDSP_Length) num); + #else + zeromem (dest, (size_t) num * sizeof (float)); + #endif + } -//============================================================================== -void JUCE_CALLTYPE FloatVectorOperations::clear (float* dest, int num) noexcept -{ - #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vclr (dest, 1, (size_t) num); - #else - zeromem (dest, (size_t) num * sizeof (float)); - #endif -} + template + void clear (double* dest, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vclrD (dest, 1, (vDSP_Length) num); + #else + zeromem (dest, (size_t) num * sizeof (double)); + #endif + } -void JUCE_CALLTYPE FloatVectorOperations::clear (double* dest, int num) noexcept -{ - #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vclrD (dest, 1, (size_t) num); - #else - zeromem (dest, (size_t) num * sizeof (double)); - #endif -} + template + void fill (float* dest, float valueToFill, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vfill (&valueToFill, dest, 1, (vDSP_Length) num); + #else + JUCE_PERFORM_VEC_OP_DEST (dest[i] = valueToFill, + val, + JUCE_LOAD_NONE, + const Mode::ParallelType val = Mode::load1 (valueToFill);) + #endif + } -void JUCE_CALLTYPE FloatVectorOperations::fill (float* dest, float valueToFill, int num) noexcept -{ - #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vfill (&valueToFill, dest, 1, (size_t) num); - #else - JUCE_PERFORM_VEC_OP_DEST (dest[i] = valueToFill, val, JUCE_LOAD_NONE, - const Mode::ParallelType val = Mode::load1 (valueToFill);) - #endif -} + template + void fill (double* dest, double valueToFill, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vfillD (&valueToFill, dest, 1, (vDSP_Length) num); + #else + JUCE_PERFORM_VEC_OP_DEST (dest[i] = valueToFill, + val, + JUCE_LOAD_NONE, + const Mode::ParallelType val = Mode::load1 (valueToFill);) + #endif + } -void JUCE_CALLTYPE FloatVectorOperations::fill (double* dest, double valueToFill, int num) noexcept -{ - #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vfillD (&valueToFill, dest, 1, (size_t) num); - #else - JUCE_PERFORM_VEC_OP_DEST (dest[i] = valueToFill, val, JUCE_LOAD_NONE, - const Mode::ParallelType val = Mode::load1 (valueToFill);) - #endif -} + template + void copyWithMultiply (float* dest, const float* src, float multiplier, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + 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, + const Mode::ParallelType mult = Mode::load1 (multiplier);) + #endif + } -void JUCE_CALLTYPE FloatVectorOperations::copy (float* dest, const float* src, int num) noexcept -{ - memcpy (dest, src, (size_t) num * sizeof (float)); -} + template + void copyWithMultiply (double* dest, const double* src, double multiplier, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + 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, + const Mode::ParallelType mult = Mode::load1 (multiplier);) + #endif + } -void JUCE_CALLTYPE FloatVectorOperations::copy (double* dest, const double* src, int num) noexcept -{ - memcpy (dest, src, (size_t) num * sizeof (double)); -} + template + void add (float* dest, float amount, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vsadd (dest, 1, &amount, dest, 1, (vDSP_Length) num); + #else + JUCE_PERFORM_VEC_OP_DEST (dest[i] += amount, + Mode::add (d, amountToAdd), + JUCE_LOAD_DEST, + const Mode::ParallelType amountToAdd = Mode::load1 (amount);) + #endif + } -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, (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, - const Mode::ParallelType mult = Mode::load1 (multiplier);) - #endif -} + template + void add (double* dest, double amount, Size num) noexcept + { + JUCE_PERFORM_VEC_OP_DEST (dest[i] += amount, + Mode::add (d, amountToAdd), + JUCE_LOAD_DEST, + const Mode::ParallelType amountToAdd = Mode::load1 (amount);) + } -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, (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, - const Mode::ParallelType mult = Mode::load1 (multiplier);) - #endif -} + template + void add (float* dest, const float* src, float amount, Size 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 (float* dest, float amount, int num) noexcept -{ - #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vsadd (dest, 1, &amount, dest, 1, (vDSP_Length) num); - #else - JUCE_PERFORM_VEC_OP_DEST (dest[i] += amount, Mode::add (d, amountToAdd), JUCE_LOAD_DEST, - const Mode::ParallelType amountToAdd = Mode::load1 (amount);) - #endif -} + template + void add (double* dest, const double* src, double amount, Size 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 (double* dest, double amount, int num) noexcept -{ - JUCE_PERFORM_VEC_OP_DEST (dest[i] += amount, Mode::add (d, amountToAdd), JUCE_LOAD_DEST, - const Mode::ParallelType amountToAdd = Mode::load1 (amount);) -} + template + void add (float* dest, const float* src, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + 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 + } -void JUCE_CALLTYPE FloatVectorOperations::add (float* dest, const float* src, float amount, int num) noexcept -{ - #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vsadd (osx108sdkCompatibilityCast (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 -} + template + void add (double* dest, const double* src, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + 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 (double* dest, const double* src, double amount, int num) noexcept -{ - #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vsaddD (osx108sdkCompatibilityCast (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 -} + template + void add (float* dest, const float* src1, const float* src2, Size 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 (float* dest, const float* src, int num) noexcept -{ - #if JUCE_USE_VDSP_FRAMEWORK - 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 -} + template + void add (double* dest, const double* src1, const double* src2, Size 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::add (double* dest, const double* src, int num) noexcept -{ - #if JUCE_USE_VDSP_FRAMEWORK - 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 -} + template + void subtract (float* dest, const float* src, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + 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 + } -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 -} + template + void subtract (double* dest, const double* src, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + 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::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 -} + template + void subtract (float* dest, const float* src1, const float* src2, Size 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 (float* dest, const float* src, int num) noexcept -{ - #if JUCE_USE_VDSP_FRAMEWORK - 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 -} + template + void subtract (double* dest, const double* src1, const double* src2, Size 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::subtract (double* dest, const double* src, int num) noexcept -{ - #if JUCE_USE_VDSP_FRAMEWORK - 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 -} + template + void addWithMultiply (float* dest, const float* src, float multiplier, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vsma (src, 1, &multiplier, dest, 1, dest, 1, (vDSP_Length) num); + #else + JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i] * multiplier, + Mode::add (d, Mode::mul (mult, s)), + JUCE_LOAD_SRC_DEST, + JUCE_INCREMENT_SRC_DEST, + const Mode::ParallelType mult = Mode::load1 (multiplier);) + #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 -} + template + void addWithMultiply (double* dest, const double* src, double multiplier, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vsmaD (src, 1, &multiplier, dest, 1, dest, 1, (vDSP_Length) num); + #else + JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i] * multiplier, + Mode::add (d, Mode::mul (mult, s)), + JUCE_LOAD_SRC_DEST, + JUCE_INCREMENT_SRC_DEST, + const Mode::ParallelType mult = Mode::load1 (multiplier);) + #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 -} + template + void addWithMultiply (float* dest, const float* src1, const float* src2, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vma ((float*) src1, 1, (float*) src2, 1, dest, 1, dest, 1, (vDSP_Length) num); + #else + JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST (dest[i] += src1[i] * src2[i], + Mode::add (d, Mode::mul (s1, s2)), + JUCE_LOAD_SRC1_SRC2_DEST, + JUCE_INCREMENT_SRC1_SRC2_DEST, ) + #endif + } -void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (float* dest, const float* src, float multiplier, int num) noexcept -{ - #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vsma (src, 1, &multiplier, dest, 1, dest, 1, (vDSP_Length) num); - #else - JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i] * multiplier, Mode::add (d, Mode::mul (mult, s)), - JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, - const Mode::ParallelType mult = Mode::load1 (multiplier);) - #endif -} + template + void addWithMultiply (double* dest, const double* src1, const double* src2, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vmaD ((double*) src1, 1, (double*) src2, 1, dest, 1, dest, 1, (vDSP_Length) num); + #else + JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST (dest[i] += src1[i] * src2[i], + Mode::add (d, Mode::mul (s1, s2)), + JUCE_LOAD_SRC1_SRC2_DEST, + JUCE_INCREMENT_SRC1_SRC2_DEST, ) + #endif + } -void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (double* dest, const double* src, double multiplier, int num) noexcept -{ - #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vsmaD (src, 1, &multiplier, dest, 1, dest, 1, (vDSP_Length) num); - #else - JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i] * multiplier, Mode::add (d, Mode::mul (mult, s)), - JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, - const Mode::ParallelType mult = Mode::load1 (multiplier);) - #endif -} + template + void subtractWithMultiply (float* dest, const float* src, float multiplier, Size num) noexcept + { + JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] -= src[i] * multiplier, + Mode::sub (d, Mode::mul (mult, s)), + JUCE_LOAD_SRC_DEST, + JUCE_INCREMENT_SRC_DEST, + const Mode::ParallelType mult = Mode::load1 (multiplier);) + } -void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (float* dest, const float* src1, const float* src2, int num) noexcept -{ - #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vma ((float*) src1, 1, (float*) src2, 1, dest, 1, dest, 1, (vDSP_Length) num); - #else - JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST (dest[i] += src1[i] * src2[i], Mode::add (d, Mode::mul (s1, s2)), - JUCE_LOAD_SRC1_SRC2_DEST, - JUCE_INCREMENT_SRC1_SRC2_DEST, ) - #endif -} + template + void subtractWithMultiply (double* dest, const double* src, double multiplier, Size num) noexcept + { + JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] -= src[i] * multiplier, + Mode::sub (d, Mode::mul (mult, s)), + JUCE_LOAD_SRC_DEST, + JUCE_INCREMENT_SRC_DEST, + const Mode::ParallelType mult = Mode::load1 (multiplier);) + } -void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (double* dest, const double* src1, const double* src2, int num) noexcept -{ - #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vmaD ((double*) src1, 1, (double*) src2, 1, dest, 1, dest, 1, (vDSP_Length) num); - #else - JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST (dest[i] += src1[i] * src2[i], Mode::add (d, Mode::mul (s1, s2)), - JUCE_LOAD_SRC1_SRC2_DEST, - JUCE_INCREMENT_SRC1_SRC2_DEST, ) - #endif -} + template + void subtractWithMultiply (float* dest, const float* src1, const float* src2, Size num) noexcept + { + JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST (dest[i] -= src1[i] * src2[i], + Mode::sub (d, Mode::mul (s1, s2)), + JUCE_LOAD_SRC1_SRC2_DEST, + JUCE_INCREMENT_SRC1_SRC2_DEST, ) + } -void JUCE_CALLTYPE FloatVectorOperations::subtractWithMultiply (float* dest, const float* src, float multiplier, int num) noexcept -{ - JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] -= src[i] * multiplier, Mode::sub (d, Mode::mul (mult, s)), - JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, + template + void subtractWithMultiply (double* dest, const double* src1, const double* src2, Size num) noexcept + { + JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST (dest[i] -= src1[i] * src2[i], + Mode::sub (d, Mode::mul (s1, s2)), + JUCE_LOAD_SRC1_SRC2_DEST, + JUCE_INCREMENT_SRC1_SRC2_DEST, ) + } + + template + void multiply (float* dest, const float* src, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + 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 + } + + template + void multiply (double* dest, const double* src, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + 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 + } + + template + void multiply (float* dest, const float* src1, const float* src2, Size 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 + } + + template + void multiply (double* dest, const double* src1, const double* src2, Size 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 + } + + template + void multiply (float* dest, float multiplier, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + 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);) -} + #endif + } -void JUCE_CALLTYPE FloatVectorOperations::subtractWithMultiply (double* dest, const double* src, double multiplier, int num) noexcept -{ - JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] -= src[i] * multiplier, Mode::sub (d, Mode::mul (mult, s)), - JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, + template + void multiply (double* dest, double multiplier, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + 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::subtractWithMultiply (float* dest, const float* src1, const float* src2, int num) noexcept -{ - JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST (dest[i] -= src1[i] * src2[i], Mode::sub (d, Mode::mul (s1, s2)), - JUCE_LOAD_SRC1_SRC2_DEST, - JUCE_INCREMENT_SRC1_SRC2_DEST, ) -} + template + void multiply (float* dest, const float* src, float multiplier, Size 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);) + } + + template + void multiply (double* dest, const double* src, double multiplier, Size 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);) + } + + template + void negate (float* dest, const float* src, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vneg ((float*) src, 1, dest, 1, (vDSP_Length) num); + #else + copyWithMultiply (dest, src, -1.0f, num); + #endif + } + + template + void negate (double* dest, const double* src, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vnegD ((double*) src, 1, dest, 1, (vDSP_Length) num); + #else + copyWithMultiply (dest, src, -1.0f, num); + #endif + } + + template + void abs (float* dest, const float* src, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vabs ((float*) src, 1, dest, 1, (vDSP_Length) num); + #else + FloatVectorHelpers::signMask32 signMask; + signMask.i = 0x7fffffffUL; + JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = std::abs (src[i]), + Mode::bit_and (s, mask), + JUCE_LOAD_SRC, + JUCE_INCREMENT_SRC_DEST, + const Mode::ParallelType mask = Mode::load1 (signMask.f);) + + ignoreUnused (signMask); + #endif + } + + template + void abs (double* dest, const double* src, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vabsD ((double*) src, 1, dest, 1, (vDSP_Length) num); + #else + FloatVectorHelpers::signMask64 signMask; + signMask.i = 0x7fffffffffffffffULL; + + JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = std::abs (src[i]), + Mode::bit_and (s, mask), + JUCE_LOAD_SRC, + JUCE_INCREMENT_SRC_DEST, + const Mode::ParallelType mask = Mode::load1 (signMask.d);) + + ignoreUnused (signMask); + #endif + } + + template + void min (float* dest, const float* src, float comp, Size num) noexcept + { + JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmin (src[i], comp), + Mode::min (s, cmp), + JUCE_LOAD_SRC, + JUCE_INCREMENT_SRC_DEST, + const Mode::ParallelType cmp = Mode::load1 (comp);) + } + + template + void min (double* dest, const double* src, double comp, Size num) noexcept + { + JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmin (src[i], comp), + Mode::min (s, cmp), + JUCE_LOAD_SRC, + JUCE_INCREMENT_SRC_DEST, + const Mode::ParallelType cmp = Mode::load1 (comp);) + } + + template + void min (float* dest, const float* src1, const float* src2, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vmin ((float*) src1, 1, (float*) src2, 1, dest, 1, (vDSP_Length) num); + #else + JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmin (src1[i], src2[i]), + Mode::min (s1, s2), + JUCE_LOAD_SRC1_SRC2, + JUCE_INCREMENT_SRC1_SRC2_DEST, ) + #endif + } + + template + void min (double* dest, const double* src1, const double* src2, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vminD ((double*) src1, 1, (double*) src2, 1, dest, 1, (vDSP_Length) num); + #else + JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmin (src1[i], src2[i]), + Mode::min (s1, s2), + JUCE_LOAD_SRC1_SRC2, + JUCE_INCREMENT_SRC1_SRC2_DEST, ) + #endif + } + + template + void max (float* dest, const float* src, float comp, Size num) noexcept + { + JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (src[i], comp), + Mode::max (s, cmp), + JUCE_LOAD_SRC, + JUCE_INCREMENT_SRC_DEST, + const Mode::ParallelType cmp = Mode::load1 (comp);) + } + + template + void max (double* dest, const double* src, double comp, Size num) noexcept + { + JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (src[i], comp), + Mode::max (s, cmp), + JUCE_LOAD_SRC, + JUCE_INCREMENT_SRC_DEST, + const Mode::ParallelType cmp = Mode::load1 (comp);) + } + + template + void max (float* dest, const float* src1, const float* src2, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vmax ((float*) src1, 1, (float*) src2, 1, dest, 1, (vDSP_Length) num); + #else + JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmax (src1[i], src2[i]), + Mode::max (s1, s2), + JUCE_LOAD_SRC1_SRC2, + JUCE_INCREMENT_SRC1_SRC2_DEST, ) + #endif + } + + template + void max (double* dest, const double* src1, const double* src2, Size num) noexcept + { + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vmaxD ((double*) src1, 1, (double*) src2, 1, dest, 1, (vDSP_Length) num); + #else + JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmax (src1[i], src2[i]), + Mode::max (s1, s2), + JUCE_LOAD_SRC1_SRC2, + JUCE_INCREMENT_SRC1_SRC2_DEST, ) + #endif + } + + template + void clip (float* dest, const float* src, float low, float high, Size num) noexcept + { + jassert (high >= low); + + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vclip ((float*) src, 1, &low, &high, dest, 1, (vDSP_Length) num); + #else + JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (jmin (src[i], high), low), + Mode::max (Mode::min (s, hi), lo), + JUCE_LOAD_SRC, + JUCE_INCREMENT_SRC_DEST, + const Mode::ParallelType lo = Mode::load1 (low); + const Mode::ParallelType hi = Mode::load1 (high);) + #endif + } + + template + void clip (double* dest, const double* src, double low, double high, Size num) noexcept + { + jassert (high >= low); + + #if JUCE_USE_VDSP_FRAMEWORK + vDSP_vclipD ((double*) src, 1, &low, &high, dest, 1, (vDSP_Length) num); + #else + JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (jmin (src[i], high), low), + Mode::max (Mode::min (s, hi), lo), + JUCE_LOAD_SRC, + JUCE_INCREMENT_SRC_DEST, + const Mode::ParallelType lo = Mode::load1 (low); + const Mode::ParallelType hi = Mode::load1 (high);) + #endif + } + + template + Range findMinAndMax (const float* src, Size num) noexcept + { + #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON + return FloatVectorHelpers::MinMax::findMinAndMax (src, num); + #else + return Range::findMinAndMax (src, num); + #endif + } + + template + Range findMinAndMax (const double* src, Size num) noexcept + { + #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON + return FloatVectorHelpers::MinMax::findMinAndMax (src, num); + #else + return Range::findMinAndMax (src, num); + #endif + } + + template + float findMinimum (const float* src, Size num) noexcept + { + #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON + return FloatVectorHelpers::MinMax::findMinOrMax (src, num, true); + #else + return juce::findMinimum (src, num); + #endif + } + + template + double findMinimum (const double* src, Size num) noexcept + { + #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON + return FloatVectorHelpers::MinMax::findMinOrMax (src, num, true); + #else + return juce::findMinimum (src, num); + #endif + } + + template + float findMaximum (const float* src, Size num) noexcept + { + #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON + return FloatVectorHelpers::MinMax::findMinOrMax (src, num, false); + #else + return juce::findMaximum (src, num); + #endif + } + + template + double findMaximum (const double* src, Size num) noexcept + { + #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON + return FloatVectorHelpers::MinMax::findMinOrMax (src, num, false); + #else + return juce::findMaximum (src, num); + #endif + } + + template + void convertFixedToFloat (float* dest, const int* src, float multiplier, Size num) noexcept + { + #if JUCE_USE_ARM_NEON + JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = (float) src[i] * multiplier, + vmulq_n_f32 (vcvtq_f32_s32 (vld1q_s32 (src)), multiplier), + JUCE_LOAD_NONE, + JUCE_INCREMENT_SRC_DEST, ) + #else + JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = (float) src[i] * multiplier, + Mode::mul (mult, _mm_cvtepi32_ps (_mm_loadu_si128 (reinterpret_cast (src)))), + JUCE_LOAD_NONE, + JUCE_INCREMENT_SRC_DEST, + const Mode::ParallelType mult = Mode::load1 (multiplier);) + #endif + } + +} // namespace +} // namespace FloatVectorHelpers -void JUCE_CALLTYPE FloatVectorOperations::subtractWithMultiply (double* dest, const double* src1, const double* src2, int num) noexcept +//============================================================================== +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::clear (FloatType* dest, + CountType numValues) noexcept { - JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST (dest[i] -= src1[i] * src2[i], Mode::sub (d, Mode::mul (s1, s2)), - JUCE_LOAD_SRC1_SRC2_DEST, - JUCE_INCREMENT_SRC1_SRC2_DEST, ) + FloatVectorHelpers::clear (dest, numValues); } -void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, const float* src, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::fill (FloatType* dest, + FloatType valueToFill, + CountType numValues) noexcept { - #if JUCE_USE_VDSP_FRAMEWORK - 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 + FloatVectorHelpers::fill (dest, valueToFill, numValues); } -void JUCE_CALLTYPE FloatVectorOperations::multiply (double* dest, const double* src, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::copy (FloatType* dest, + const FloatType* src, + CountType numValues) noexcept { - #if JUCE_USE_VDSP_FRAMEWORK - 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 + memcpy (dest, src, (size_t) numValues * sizeof (FloatType)); } -void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, const float* src1, const float* src2, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::copyWithMultiply (FloatType* dest, + const FloatType* src, + FloatType multiplier, + CountType numValues) 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 + FloatVectorHelpers::copyWithMultiply (dest, src, multiplier, numValues); } -void JUCE_CALLTYPE FloatVectorOperations::multiply (double* dest, const double* src1, const double* src2, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::add (FloatType* dest, + FloatType amountToAdd, + CountType numValues) 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 + FloatVectorHelpers::add (dest, amountToAdd, numValues); } -void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, float multiplier, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::add (FloatType* dest, + const FloatType* src, + FloatType amount, + CountType numValues) noexcept { - #if JUCE_USE_VDSP_FRAMEWORK - 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);) - #endif + FloatVectorHelpers::add (dest, src, amount, numValues); } -void JUCE_CALLTYPE FloatVectorOperations::multiply (double* dest, double multiplier, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::add (FloatType* dest, + const FloatType* src, + CountType numValues) noexcept { - #if JUCE_USE_VDSP_FRAMEWORK - 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 + FloatVectorHelpers::add (dest, src, numValues); } -void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, const float* src, float multiplier, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::add (FloatType* dest, + const FloatType* src1, + const FloatType* src2, + CountType 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);) + FloatVectorHelpers::add (dest, src1, src2, num); } -void JUCE_CALLTYPE FloatVectorOperations::multiply (double* dest, const double* src, double multiplier, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::subtract (FloatType* dest, + const FloatType* src, + CountType numValues) 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);) + FloatVectorHelpers::subtract (dest, src, numValues); } -void FloatVectorOperations::negate (float* dest, const float* src, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::subtract (FloatType* dest, + const FloatType* src1, + const FloatType* src2, + CountType num) noexcept { - #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vneg ((float*) src, 1, dest, 1, (vDSP_Length) num); - #else - copyWithMultiply (dest, src, -1.0f, num); - #endif + FloatVectorHelpers::subtract (dest, src1, src2, num); } -void FloatVectorOperations::negate (double* dest, const double* src, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::addWithMultiply (FloatType* dest, + const FloatType* src, + FloatType multiplier, + CountType numValues) noexcept { - #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vnegD ((double*) src, 1, dest, 1, (vDSP_Length) num); - #else - copyWithMultiply (dest, src, -1.0f, num); - #endif + FloatVectorHelpers::addWithMultiply (dest, src, multiplier, numValues); } -void FloatVectorOperations::abs (float* dest, const float* src, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::addWithMultiply (FloatType* dest, + const FloatType* src1, + const FloatType* src2, + CountType num) noexcept { - #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vabs ((float*) src, 1, dest, 1, (vDSP_Length) num); - #else - FloatVectorHelpers::signMask32 signMask; - signMask.i = 0x7fffffffUL; - JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = std::abs (src[i]), Mode::bit_and (s, mask), - JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, - const Mode::ParallelType mask = Mode::load1 (signMask.f);) - - ignoreUnused (signMask); - #endif + FloatVectorHelpers::addWithMultiply (dest, src1, src2, num); } -void FloatVectorOperations::abs (double* dest, const double* src, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::subtractWithMultiply (FloatType* dest, + const FloatType* src, + FloatType multiplier, + CountType numValues) noexcept { - #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vabsD ((double*) src, 1, dest, 1, (vDSP_Length) num); - #else - FloatVectorHelpers::signMask64 signMask; - signMask.i = 0x7fffffffffffffffULL; - - JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = std::abs (src[i]), Mode::bit_and (s, mask), - JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, - const Mode::ParallelType mask = Mode::load1 (signMask.d);) - - ignoreUnused (signMask); - #endif + FloatVectorHelpers::subtractWithMultiply (dest, src, multiplier, numValues); } -void JUCE_CALLTYPE FloatVectorOperations::convertFixedToFloat (float* dest, const int* src, float multiplier, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::subtractWithMultiply (FloatType* dest, + const FloatType* src1, + const FloatType* src2, + CountType num) noexcept { - #if JUCE_USE_ARM_NEON - JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier, - vmulq_n_f32 (vcvtq_f32_s32 (vld1q_s32 (src)), multiplier), - JUCE_LOAD_NONE, JUCE_INCREMENT_SRC_DEST, ) - #else - JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = (float) src[i] * multiplier, - Mode::mul (mult, _mm_cvtepi32_ps (_mm_loadu_si128 ((const __m128i*) src))), - JUCE_LOAD_NONE, JUCE_INCREMENT_SRC_DEST, - const Mode::ParallelType mult = Mode::load1 (multiplier);) - #endif + FloatVectorHelpers::subtractWithMultiply (dest, src1, src2, num); } -void JUCE_CALLTYPE FloatVectorOperations::min (float* dest, const float* src, float comp, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::multiply (FloatType* dest, + const FloatType* src, + CountType numValues) noexcept { - JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmin (src[i], comp), Mode::min (s, cmp), - JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, - const Mode::ParallelType cmp = Mode::load1 (comp);) + FloatVectorHelpers::multiply (dest, src, numValues); } -void JUCE_CALLTYPE FloatVectorOperations::min (double* dest, const double* src, double comp, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::multiply (FloatType* dest, + const FloatType* src1, + const FloatType* src2, + CountType numValues) noexcept { - JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmin (src[i], comp), Mode::min (s, cmp), - JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, - const Mode::ParallelType cmp = Mode::load1 (comp);) + FloatVectorHelpers::multiply (dest, src1, src2, numValues); } -void JUCE_CALLTYPE FloatVectorOperations::min (float* dest, const float* src1, const float* src2, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::multiply (FloatType* dest, + FloatType multiplier, + CountType numValues) noexcept { - #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vmin ((float*) src1, 1, (float*) src2, 1, dest, 1, (vDSP_Length) num); - #else - JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmin (src1[i], src2[i]), Mode::min (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, ) - #endif + FloatVectorHelpers::multiply (dest, multiplier, numValues); } -void JUCE_CALLTYPE FloatVectorOperations::min (double* dest, const double* src1, const double* src2, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::multiply (FloatType* dest, + const FloatType* src, + FloatType multiplier, + CountType num) noexcept { - #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vminD ((double*) src1, 1, (double*) src2, 1, dest, 1, (vDSP_Length) num); - #else - JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmin (src1[i], src2[i]), Mode::min (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, ) - #endif + FloatVectorHelpers::multiply (dest, src, multiplier, num); } -void JUCE_CALLTYPE FloatVectorOperations::max (float* dest, const float* src, float comp, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::negate (FloatType* dest, + const FloatType* src, + CountType numValues) noexcept { - JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (src[i], comp), Mode::max (s, cmp), - JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, - const Mode::ParallelType cmp = Mode::load1 (comp);) + FloatVectorHelpers::negate (dest, src, numValues); } -void JUCE_CALLTYPE FloatVectorOperations::max (double* dest, const double* src, double comp, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::abs (FloatType* dest, + const FloatType* src, + CountType numValues) noexcept { - JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (src[i], comp), Mode::max (s, cmp), - JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, - const Mode::ParallelType cmp = Mode::load1 (comp);) + FloatVectorHelpers::abs (dest, src, numValues); } -void JUCE_CALLTYPE FloatVectorOperations::max (float* dest, const float* src1, const float* src2, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::min (FloatType* dest, + const FloatType* src, + FloatType comp, + CountType num) noexcept { - #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vmax ((float*) src1, 1, (float*) src2, 1, dest, 1, (vDSP_Length) num); - #else - JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmax (src1[i], src2[i]), Mode::max (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, ) - #endif + FloatVectorHelpers::min (dest, src, comp, num); } -void JUCE_CALLTYPE FloatVectorOperations::max (double* dest, const double* src1, const double* src2, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::min (FloatType* dest, + const FloatType* src1, + const FloatType* src2, + CountType num) noexcept { - #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vmaxD ((double*) src1, 1, (double*) src2, 1, dest, 1, (vDSP_Length) num); - #else - JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmax (src1[i], src2[i]), Mode::max (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, ) - #endif + FloatVectorHelpers::min (dest, src1, src2, num); } -void JUCE_CALLTYPE FloatVectorOperations::clip (float* dest, const float* src, float low, float high, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::max (FloatType* dest, + const FloatType* src, + FloatType comp, + CountType num) noexcept { - jassert(high >= low); - - #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vclip ((float*) src, 1, &low, &high, dest, 1, (vDSP_Length) num); - #else - JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (jmin (src[i], high), low), Mode::max (Mode::min (s, hi), lo), - JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, - const Mode::ParallelType lo = Mode::load1 (low); const Mode::ParallelType hi = Mode::load1 (high);) - #endif + FloatVectorHelpers::max (dest, src, comp, num); } -void JUCE_CALLTYPE FloatVectorOperations::clip (double* dest, const double* src, double low, double high, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::max (FloatType* dest, + const FloatType* src1, + const FloatType* src2, + CountType num) noexcept { - jassert(high >= low); - - #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vclipD ((double*) src, 1, &low, &high, dest, 1, (vDSP_Length) num); - #else - JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (jmin (src[i], high), low), Mode::max (Mode::min (s, hi), lo), - JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, - const Mode::ParallelType lo = Mode::load1 (low); const Mode::ParallelType hi = Mode::load1 (high);) - #endif + FloatVectorHelpers::max (dest, src1, src2, num); } -Range JUCE_CALLTYPE FloatVectorOperations::findMinAndMax (const float* src, int num) noexcept +template +void JUCE_CALLTYPE detail::FloatVectorOperationsBase::clip (FloatType* dest, + const FloatType* src, + FloatType low, + FloatType high, + CountType num) noexcept { - #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON - return FloatVectorHelpers::MinMax::findMinAndMax (src, num); - #else - return Range::findMinAndMax (src, num); - #endif + FloatVectorHelpers::clip (dest, src, low, high, num); } -Range JUCE_CALLTYPE FloatVectorOperations::findMinAndMax (const double* src, int num) noexcept +template +Range JUCE_CALLTYPE detail::FloatVectorOperationsBase::findMinAndMax (const FloatType* src, + CountType numValues) noexcept { - #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON - return FloatVectorHelpers::MinMax::findMinAndMax (src, num); - #else - return Range::findMinAndMax (src, num); - #endif + return FloatVectorHelpers::findMinAndMax (src, numValues); } -float JUCE_CALLTYPE FloatVectorOperations::findMinimum (const float* src, int num) noexcept +template +FloatType JUCE_CALLTYPE detail::FloatVectorOperationsBase::findMinimum (const FloatType* src, + CountType numValues) noexcept { - #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON - return FloatVectorHelpers::MinMax::findMinOrMax (src, num, true); - #else - return juce::findMinimum (src, num); - #endif + return FloatVectorHelpers::findMinimum (src, numValues); } -double JUCE_CALLTYPE FloatVectorOperations::findMinimum (const double* src, int num) noexcept +template +FloatType JUCE_CALLTYPE detail::FloatVectorOperationsBase::findMaximum (const FloatType* src, + CountType numValues) noexcept { - #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON - return FloatVectorHelpers::MinMax::findMinOrMax (src, num, true); - #else - return juce::findMinimum (src, num); - #endif + return FloatVectorHelpers::findMaximum (src, numValues); } -float JUCE_CALLTYPE FloatVectorOperations::findMaximum (const float* src, int num) noexcept +template struct detail::FloatVectorOperationsBase; +template struct detail::FloatVectorOperationsBase; +template struct detail::FloatVectorOperationsBase; +template struct detail::FloatVectorOperationsBase; + +void JUCE_CALLTYPE FloatVectorOperations::convertFixedToFloat (float* dest, const int* src, float multiplier, size_t num) noexcept { - #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON - return FloatVectorHelpers::MinMax::findMinOrMax (src, num, false); - #else - return juce::findMaximum (src, num); - #endif + FloatVectorHelpers::convertFixedToFloat (dest, src, multiplier, num); } -double JUCE_CALLTYPE FloatVectorOperations::findMaximum (const double* src, int num) noexcept +void JUCE_CALLTYPE FloatVectorOperations::convertFixedToFloat (float* dest, const int* src, float multiplier, int num) noexcept { - #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON - return FloatVectorHelpers::MinMax::findMinOrMax (src, num, false); - #else - return juce::findMaximum (src, num); - #endif + FloatVectorHelpers::convertFixedToFloat (dest, src, multiplier, num); } intptr_t JUCE_CALLTYPE FloatVectorOperations::getFpStatusRegister() noexcept @@ -1033,14 +1432,16 @@ intptr_t JUCE_CALLTYPE FloatVectorOperations::getFpStatusRegister() noexcept intptr_t fpsr = 0; #if JUCE_INTEL && JUCE_USE_SSE_INTRINSICS fpsr = static_cast (_mm_getcsr()); - #elif defined (__arm64__) || defined (__aarch64__) || JUCE_USE_ARM_NEON - #if defined (__arm64__) || defined (__aarch64__) - asm volatile("mrs %0, fpcr" : "=r" (fpsr)); + #elif defined(__arm64__) || defined(__aarch64__) || JUCE_USE_ARM_NEON + #if defined(__arm64__) || defined(__aarch64__) + asm volatile("mrs %0, fpcr" + : "=r"(fpsr)); #elif JUCE_USE_ARM_NEON - asm volatile("vmrs %0, fpscr" : "=r" (fpsr)); + asm volatile("vmrs %0, fpscr" + : "=r"(fpsr)); #endif #else - #if ! (defined (JUCE_INTEL) || defined (JUCE_ARM)) + #if ! (defined(JUCE_INTEL) || defined(JUCE_ARM)) jassertfalse; // No support for getting the floating point status register for your platform #endif #endif @@ -1051,16 +1452,22 @@ intptr_t JUCE_CALLTYPE FloatVectorOperations::getFpStatusRegister() noexcept void JUCE_CALLTYPE FloatVectorOperations::setFpStatusRegister (intptr_t fpsr) noexcept { #if JUCE_INTEL && JUCE_USE_SSE_INTRINSICS - auto fpsr_w = static_cast (fpsr); + // the volatile keyword here is needed to workaround a bug in AppleClang 13.0 + // which aggressively optimises away the variable otherwise + volatile auto fpsr_w = static_cast (fpsr); _mm_setcsr (fpsr_w); - #elif defined (__arm64__) || defined (__aarch64__) || JUCE_USE_ARM_NEON - #if defined (__arm64__) || defined (__aarch64__) - asm volatile("msr fpcr, %0" : : "ri" (fpsr)); + #elif defined(__arm64__) || defined(__aarch64__) || JUCE_USE_ARM_NEON + #if defined(__arm64__) || defined(__aarch64__) + asm volatile("msr fpcr, %0" + : + : "ri"(fpsr)); #elif JUCE_USE_ARM_NEON - asm volatile("vmsr fpscr, %0" : : "ri" (fpsr)); + asm volatile("vmsr fpscr, %0" + : + : "ri"(fpsr)); #endif #else - #if ! (defined (JUCE_INTEL) || defined (JUCE_ARM)) + #if ! (defined(JUCE_INTEL) || defined(JUCE_ARM)) jassertfalse; // No support for getting the floating point status register for your platform #endif ignoreUnused (fpsr); @@ -1069,7 +1476,7 @@ void JUCE_CALLTYPE FloatVectorOperations::setFpStatusRegister (intptr_t fpsr) no void JUCE_CALLTYPE FloatVectorOperations::enableFlushToZeroMode (bool shouldEnable) noexcept { - #if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined (__arm64__) || defined (__aarch64__)) + #if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined(__arm64__) || defined(__aarch64__)) #if JUCE_USE_SSE_INTRINSICS intptr_t mask = _MM_FLUSH_ZERO_MASK; #else /*JUCE_USE_ARM_NEON*/ @@ -1077,7 +1484,7 @@ void JUCE_CALLTYPE FloatVectorOperations::enableFlushToZeroMode (bool shouldEnab #endif setFpStatusRegister ((getFpStatusRegister() & (~mask)) | (shouldEnable ? mask : 0)); #else - #if ! (defined (JUCE_INTEL) || defined (JUCE_ARM)) + #if ! (defined(JUCE_INTEL) || defined(JUCE_ARM)) jassertfalse; // No support for flush to zero mode on your platform #endif ignoreUnused (shouldEnable); @@ -1086,7 +1493,7 @@ void JUCE_CALLTYPE FloatVectorOperations::enableFlushToZeroMode (bool shouldEnab void JUCE_CALLTYPE FloatVectorOperations::disableDenormalisedNumberSupport (bool shouldDisable) noexcept { - #if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined (__arm64__) || defined (__aarch64__)) + #if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined(__arm64__) || defined(__aarch64__)) #if JUCE_USE_SSE_INTRINSICS intptr_t mask = 0x8040; #else /*JUCE_USE_ARM_NEON*/ @@ -1097,7 +1504,7 @@ void JUCE_CALLTYPE FloatVectorOperations::disableDenormalisedNumberSupport (bool #else ignoreUnused (shouldDisable); - #if ! (defined (JUCE_INTEL) || defined (JUCE_ARM)) + #if ! (defined(JUCE_INTEL) || defined(JUCE_ARM)) jassertfalse; // No support for disable denormals mode on your platform #endif #endif @@ -1105,7 +1512,7 @@ void JUCE_CALLTYPE FloatVectorOperations::disableDenormalisedNumberSupport (bool bool JUCE_CALLTYPE FloatVectorOperations::areDenormalsDisabled() noexcept { - #if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined (__arm64__) || defined (__aarch64__)) + #if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined(__arm64__) || defined(__aarch64__)) #if JUCE_USE_SSE_INTRINSICS intptr_t mask = 0x8040; #else /*JUCE_USE_ARM_NEON*/ @@ -1120,7 +1527,7 @@ bool JUCE_CALLTYPE FloatVectorOperations::areDenormalsDisabled() noexcept ScopedNoDenormals::ScopedNoDenormals() noexcept { - #if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined (__arm64__) || defined (__aarch64__)) + #if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined(__arm64__) || defined(__aarch64__)) #if JUCE_USE_SSE_INTRINSICS intptr_t mask = 0x8040; #else /*JUCE_USE_ARM_NEON*/ @@ -1134,11 +1541,12 @@ ScopedNoDenormals::ScopedNoDenormals() noexcept ScopedNoDenormals::~ScopedNoDenormals() noexcept { - #if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined (__arm64__) || defined (__aarch64__)) + #if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined(__arm64__) || defined(__aarch64__)) FloatVectorOperations::setFpStatusRegister (fpsr); - #endif + #endif } + //============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -1146,7 +1554,9 @@ ScopedNoDenormals::~ScopedNoDenormals() noexcept class FloatVectorOperationsTests : public UnitTest { public: - FloatVectorOperationsTests() : UnitTest ("FloatVectorOperations", "Audio") {} + FloatVectorOperationsTests() + : UnitTest ("FloatVectorOperations", UnitTestCategories::audio) + {} template struct TestRunner diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h index 4ad122b1..2bdcef7a 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h +++ b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -32,187 +32,123 @@ namespace juce #endif class ScopedNoDenormals; -//============================================================================== -/** - A collection of simple vector operations on arrays of floats, accelerated with - SIMD instructions where possible. - - @tags{Audio} -*/ -class JUCE_API FloatVectorOperations +#if ! DOXYGEN +namespace detail { -public: - //============================================================================== - /** Clears a vector of floats. */ - static void JUCE_CALLTYPE clear (float* dest, int numValues) noexcept; - - /** Clears a vector of doubles. */ - static void JUCE_CALLTYPE clear (double* dest, int numValues) noexcept; - - /** Copies a repeated value into a vector of floats. */ - static void JUCE_CALLTYPE fill (float* dest, float valueToFill, int numValues) noexcept; - - /** Copies a repeated value into a vector of doubles. */ - static void JUCE_CALLTYPE fill (double* dest, double valueToFill, int numValues) noexcept; - - /** Copies a vector of floats. */ - static void JUCE_CALLTYPE copy (float* dest, const float* src, int numValues) noexcept; - - /** Copies a vector of doubles. */ - static void JUCE_CALLTYPE copy (double* dest, const double* src, int numValues) noexcept; - - /** Copies a vector of floats, multiplying each value by a given multiplier */ - static void JUCE_CALLTYPE copyWithMultiply (float* dest, const float* src, float multiplier, int numValues) noexcept; - - /** Copies a vector of doubles, multiplying each value by a given multiplier */ - static void JUCE_CALLTYPE copyWithMultiply (double* dest, const double* src, double multiplier, int numValues) noexcept; - - /** Adds a fixed value to the destination values. */ - static void JUCE_CALLTYPE add (float* dest, float amountToAdd, int numValues) noexcept; - - /** 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, const 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, const 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; - - /** Multiplies each source value by the given multiplier, then adds it to the destination value. */ - static void JUCE_CALLTYPE addWithMultiply (double* dest, const double* src, double multiplier, int numValues) noexcept; - - /** Multiplies each source1 value by the corresponding source2 value, then adds it to the destination value. */ - static void JUCE_CALLTYPE addWithMultiply (float* dest, const float* src1, const float* src2, int num) noexcept; - - /** Multiplies each source1 value by the corresponding source2 value, then adds it to the destination value. */ - static void JUCE_CALLTYPE addWithMultiply (double* dest, const double* src1, const double* src2, int num) noexcept; - - /** Multiplies each source value by the given multiplier, then subtracts it to the destination value. */ - static void JUCE_CALLTYPE subtractWithMultiply (float* dest, const float* src, float multiplier, int numValues) noexcept; - - /** Multiplies each source value by the given multiplier, then subtracts it to the destination value. */ - static void JUCE_CALLTYPE subtractWithMultiply (double* dest, const double* src, double multiplier, int numValues) noexcept; - - /** Multiplies each source1 value by the corresponding source2 value, then subtracts it to the destination value. */ - static void JUCE_CALLTYPE subtractWithMultiply (float* dest, const float* src1, const float* src2, int num) noexcept; - - /** Multiplies each source1 value by the corresponding source2 value, then subtracts it to the destination value. */ - static void JUCE_CALLTYPE subtractWithMultiply (double* dest, const double* src1, const double* src2, int num) noexcept; - - /** Multiplies the destination values by the source values. */ - static void JUCE_CALLTYPE multiply (float* dest, const float* src, int numValues) noexcept; - - /** 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; +template +struct FloatVectorOperationsBase +{ + static void JUCE_CALLTYPE clear (FloatType* dest, CountType numValues) noexcept; + static void JUCE_CALLTYPE fill (FloatType* dest, FloatType valueToFill, CountType numValues) noexcept; + static void JUCE_CALLTYPE copy (FloatType* dest, const FloatType* src, CountType numValues) noexcept; + static void JUCE_CALLTYPE copyWithMultiply (FloatType* dest, const FloatType* src, FloatType multiplier, CountType numValues) noexcept; + static void JUCE_CALLTYPE add (FloatType* dest, FloatType amountToAdd, CountType numValues) noexcept; + static void JUCE_CALLTYPE add (FloatType* dest, const FloatType* src, FloatType amount, CountType numValues) noexcept; + static void JUCE_CALLTYPE add (FloatType* dest, const FloatType* src, CountType numValues) noexcept; + static void JUCE_CALLTYPE add (FloatType* dest, const FloatType* src1, const FloatType* src2, CountType num) noexcept; + static void JUCE_CALLTYPE subtract (FloatType* dest, const FloatType* src, CountType numValues) noexcept; + static void JUCE_CALLTYPE subtract (FloatType* dest, const FloatType* src1, const FloatType* src2, CountType num) noexcept; + static void JUCE_CALLTYPE addWithMultiply (FloatType* dest, const FloatType* src, FloatType multiplier, CountType numValues) noexcept; + static void JUCE_CALLTYPE addWithMultiply (FloatType* dest, const FloatType* src1, const FloatType* src2, CountType num) noexcept; + static void JUCE_CALLTYPE subtractWithMultiply (FloatType* dest, const FloatType* src, FloatType multiplier, CountType numValues) noexcept; + static void JUCE_CALLTYPE subtractWithMultiply (FloatType* dest, const FloatType* src1, const FloatType* src2, CountType num) noexcept; + static void JUCE_CALLTYPE multiply (FloatType* dest, const FloatType* src, CountType numValues) noexcept; + static void JUCE_CALLTYPE multiply (FloatType* dest, const FloatType* src1, const FloatType* src2, CountType numValues) noexcept; + static void JUCE_CALLTYPE multiply (FloatType* dest, FloatType multiplier, CountType numValues) noexcept; + static void JUCE_CALLTYPE multiply (FloatType* dest, const FloatType* src, FloatType multiplier, CountType num) noexcept; + static void JUCE_CALLTYPE negate (FloatType* dest, const FloatType* src, CountType numValues) noexcept; + static void JUCE_CALLTYPE abs (FloatType* dest, const FloatType* src, CountType numValues) noexcept; + static void JUCE_CALLTYPE min (FloatType* dest, const FloatType* src, FloatType comp, CountType num) noexcept; + static void JUCE_CALLTYPE min (FloatType* dest, const FloatType* src1, const FloatType* src2, CountType num) noexcept; + static void JUCE_CALLTYPE max (FloatType* dest, const FloatType* src, FloatType comp, CountType num) noexcept; + static void JUCE_CALLTYPE max (FloatType* dest, const FloatType* src1, const FloatType* src2, CountType num) noexcept; + static void JUCE_CALLTYPE clip (FloatType* dest, const FloatType* src, FloatType low, FloatType high, CountType num) noexcept; + static Range JUCE_CALLTYPE findMinAndMax (const FloatType* src, CountType numValues) noexcept; + static FloatType JUCE_CALLTYPE findMinimum (const FloatType* src, CountType numValues) noexcept; + static FloatType JUCE_CALLTYPE findMaximum (const FloatType* src, CountType 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; +template +struct NameForwarder; - /** 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; +template +struct NameForwarder : Head {}; - /** Copies a source vector to a destination, negating each value. */ - static void JUCE_CALLTYPE negate (float* dest, const float* src, int numValues) noexcept; +template +struct NameForwarder : Head, NameForwarder +{ + using Head::clear; + using NameForwarder::clear; - /** Copies a source vector to a destination, negating each value. */ - static void JUCE_CALLTYPE negate (double* dest, const double* src, int numValues) noexcept; + using Head::fill; + using NameForwarder::fill; - /** Copies a source vector to a destination, taking the absolute of each value. */ - static void JUCE_CALLTYPE abs (float* dest, const float* src, int numValues) noexcept; + using Head::copy; + using NameForwarder::copy; - /** Copies a source vector to a destination, taking the absolute of each value. */ - static void JUCE_CALLTYPE abs (double* dest, const double* src, int numValues) noexcept; + using Head::copyWithMultiply; + using NameForwarder::copyWithMultiply; - /** Converts a stream of integers to floats, multiplying each one by the given multiplier. */ - static void JUCE_CALLTYPE convertFixedToFloat (float* dest, const int* src, float multiplier, int numValues) noexcept; + using Head::add; + using NameForwarder::add; - /** Each element of dest will be the minimum of the corresponding element of the source array and the given comp value. */ - static void JUCE_CALLTYPE min (float* dest, const float* src, float comp, int num) noexcept; + using Head::subtract; + using NameForwarder::subtract; - /** Each element of dest will be the minimum of the corresponding element of the source array and the given comp value. */ - static void JUCE_CALLTYPE min (double* dest, const double* src, double comp, int num) noexcept; + using Head::addWithMultiply; + using NameForwarder::addWithMultiply; - /** Each element of dest will be the minimum of the corresponding source1 and source2 values. */ - static void JUCE_CALLTYPE min (float* dest, const float* src1, const float* src2, int num) noexcept; + using Head::subtractWithMultiply; + using NameForwarder::subtractWithMultiply; - /** Each element of dest will be the minimum of the corresponding source1 and source2 values. */ - static void JUCE_CALLTYPE min (double* dest, const double* src1, const double* src2, int num) noexcept; + using Head::multiply; + using NameForwarder::multiply; - /** Each element of dest will be the maximum of the corresponding element of the source array and the given comp value. */ - static void JUCE_CALLTYPE max (float* dest, const float* src, float comp, int num) noexcept; + using Head::negate; + using NameForwarder::negate; - /** Each element of dest will be the maximum of the corresponding element of the source array and the given comp value. */ - static void JUCE_CALLTYPE max (double* dest, const double* src, double comp, int num) noexcept; + using Head::abs; + using NameForwarder::abs; - /** Each element of dest will be the maximum of the corresponding source1 and source2 values. */ - static void JUCE_CALLTYPE max (float* dest, const float* src1, const float* src2, int num) noexcept; + using Head::min; + using NameForwarder::min; - /** Each element of dest will be the maximum of the corresponding source1 and source2 values. */ - static void JUCE_CALLTYPE max (double* dest, const double* src1, const double* src2, int num) noexcept; + using Head::max; + using NameForwarder::max; - /** Each element of dest is calculated by hard clipping the corresponding src element so that it is in the range specified by the arguments low and high. */ - static void JUCE_CALLTYPE clip (float* dest, const float* src, float low, float high, int num) noexcept; + using Head::clip; + using NameForwarder::clip; - /** Each element of dest is calculated by hard clipping the corresponding src element so that it is in the range specified by the arguments low and high. */ - static void JUCE_CALLTYPE clip (double* dest, const double* src, double low, double high, int num) noexcept; + using Head::findMinAndMax; + using NameForwarder::findMinAndMax; - /** Finds the minimum and maximum values in the given array. */ - static Range JUCE_CALLTYPE findMinAndMax (const float* src, int numValues) noexcept; + using Head::findMinimum; + using NameForwarder::findMinimum; - /** Finds the minimum and maximum values in the given array. */ - static Range JUCE_CALLTYPE findMinAndMax (const double* src, int numValues) noexcept; + using Head::findMaximum; + using NameForwarder::findMaximum; +}; - /** Finds the minimum value in the given array. */ - static float JUCE_CALLTYPE findMinimum (const float* src, int numValues) noexcept; +} // namespace detail +#endif - /** Finds the minimum value in the given array. */ - static double JUCE_CALLTYPE findMinimum (const double* src, int numValues) noexcept; +//============================================================================== +/** + A collection of simple vector operations on arrays of floats, accelerated with + SIMD instructions where possible. - /** Finds the maximum value in the given array. */ - static float JUCE_CALLTYPE findMaximum (const float* src, int numValues) noexcept; + @tags{Audio} +*/ +class JUCE_API FloatVectorOperations : public detail::NameForwarder, + detail::FloatVectorOperationsBase, + detail::FloatVectorOperationsBase, + detail::FloatVectorOperationsBase> +{ +public: + static void JUCE_CALLTYPE convertFixedToFloat (float* dest, const int* src, float multiplier, int num) noexcept; - /** Finds the maximum value in the given array. */ - static double JUCE_CALLTYPE findMaximum (const double* src, int numValues) noexcept; + static void JUCE_CALLTYPE convertFixedToFloat (float* dest, const int* src, float multiplier, size_t num) noexcept; /** This method enables or disables the SSE/NEON flush-to-zero mode. */ static void JUCE_CALLTYPE enableFlushToZeroMode (bool shouldEnable) noexcept; diff --git a/JuceLibraryCode/modules/juce_audio_basics/effects/juce_CatmullRomInterpolator.cpp b/JuceLibraryCode/modules/juce_audio_basics/effects/juce_CatmullRomInterpolator.cpp deleted file mode 100644 index c6f59d4a..00000000 --- a/JuceLibraryCode/modules/juce_audio_basics/effects/juce_CatmullRomInterpolator.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -struct CatmullRomAlgorithm -{ - static forcedinline float valueAtOffset (const float* const inputs, const float offset) noexcept - { - auto y0 = inputs[3]; - auto y1 = inputs[2]; - auto y2 = inputs[1]; - auto y3 = inputs[0]; - - auto halfY0 = 0.5f * y0; - auto halfY3 = 0.5f * y3; - - return y1 + offset * ((0.5f * y2 - halfY0) - + (offset * (((y0 + 2.0f * y2) - (halfY3 + 2.5f * y1)) - + (offset * ((halfY3 + 1.5f * y1) - (halfY0 + 1.5f * y2)))))); - } -}; - -CatmullRomInterpolator::CatmullRomInterpolator() noexcept { reset(); } -CatmullRomInterpolator::~CatmullRomInterpolator() noexcept {} - -void CatmullRomInterpolator::reset() noexcept -{ - subSamplePos = 1.0; - - for (auto& s : lastInputSamples) - s = 0; -} - -int CatmullRomInterpolator::process (double actualRatio, const float* in, float* out, int numOut, int available, int wrap) noexcept -{ - return interpolate (lastInputSamples, subSamplePos, actualRatio, in, out, numOut, available, wrap); -} - -int CatmullRomInterpolator::process (double actualRatio, const float* in, float* out, int numOut) noexcept -{ - return interpolate (lastInputSamples, subSamplePos, actualRatio, in, out, numOut); -} - -int CatmullRomInterpolator::processAdding (double actualRatio, const float* in, float* out, int numOut, int available, int wrap, float gain) noexcept -{ - return interpolateAdding (lastInputSamples, subSamplePos, actualRatio, in, out, numOut, available, wrap, gain); -} - -int CatmullRomInterpolator::processAdding (double actualRatio, const float* in, float* out, int numOut, float gain) noexcept -{ - return interpolateAdding (lastInputSamples, subSamplePos, actualRatio, in, out, numOut, gain); -} - -} // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/effects/juce_CatmullRomInterpolator.h b/JuceLibraryCode/modules/juce_audio_basics/effects/juce_CatmullRomInterpolator.h deleted file mode 100644 index ab3ca754..00000000 --- a/JuceLibraryCode/modules/juce_audio_basics/effects/juce_CatmullRomInterpolator.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -/** - Interpolator for resampling a stream of floats using Catmull-Rom interpolation. - - Note that the resampler is stateful, so when there's a break in the continuity - of the input stream you're feeding it, you should call reset() before feeding - it any new data. And like with any other stateful filter, if you're resampling - multiple channels, make sure each one uses its own CatmullRomInterpolator - object. - - @see LagrangeInterpolator - - @tags{Audio} -*/ -class JUCE_API CatmullRomInterpolator -{ -public: - CatmullRomInterpolator() noexcept; - ~CatmullRomInterpolator() noexcept; - - /** Resets the state of the interpolator. - Call this when there's a break in the continuity of the input data stream. - */ - void reset() noexcept; - - /** Resamples a stream of samples. - - @param speedRatio the number of input samples to use for each output sample - @param inputSamples the source data to read from. This must contain at - least (speedRatio * numOutputSamplesToProduce) samples. - @param outputSamples the buffer to write the results into - @param numOutputSamplesToProduce the number of output samples that should be created - - @returns the actual number of input samples that were used - */ - int process (double speedRatio, - const float* inputSamples, - float* outputSamples, - int numOutputSamplesToProduce) noexcept; - - /** Resamples a stream of samples. - - @param speedRatio the number of input samples to use for each output sample - @param inputSamples the source data to read from. This must contain at - least (speedRatio * numOutputSamplesToProduce) samples. - @param outputSamples the buffer to write the results into - @param numOutputSamplesToProduce the number of output samples that should be created - @param available the number of available input samples. If it needs more samples - than available, it either wraps back for wrapAround samples, or - it feeds zeroes - @param wrapAround if the stream exceeds available samples, it wraps back for - wrapAround samples. If wrapAround is set to 0, it will feed zeroes. - - @returns the actual number of input samples that were used - */ - int process (double speedRatio, - const float* inputSamples, - float* outputSamples, - int numOutputSamplesToProduce, - int available, - int wrapAround) noexcept; - - /** Resamples a stream of samples, adding the results to the output data - with a gain. - - @param speedRatio the number of input samples to use for each output sample - @param inputSamples the source data to read from. This must contain at - least (speedRatio * numOutputSamplesToProduce) samples. - @param outputSamples the buffer to write the results to - the result values will be added - to any pre-existing data in this buffer after being multiplied by - the gain factor - @param numOutputSamplesToProduce the number of output samples that should be created - @param gain a gain factor to multiply the resulting samples by before - adding them to the destination buffer - - @returns the actual number of input samples that were used - */ - int processAdding (double speedRatio, - const float* inputSamples, - float* outputSamples, - int numOutputSamplesToProduce, - float gain) noexcept; - - /** Resamples a stream of samples, adding the results to the output data - with a gain. - - @param speedRatio the number of input samples to use for each output sample - @param inputSamples the source data to read from. This must contain at - least (speedRatio * numOutputSamplesToProduce) samples. - @param outputSamples the buffer to write the results to - the result values will be added - to any pre-existing data in this buffer after being multiplied by - the gain factor - @param numOutputSamplesToProduce the number of output samples that should be created - @param available the number of available input samples. If it needs more samples - than available, it either wraps back for wrapAround samples, or - it feeds zeroes - @param wrapAround if the stream exceeds available samples, it wraps back for - wrapAround samples. If wrapAround is set to 0, it will feed zeroes. - @param gain a gain factor to multiply the resulting samples by before - adding them to the destination buffer - - @returns the actual number of input samples that were used - */ - int processAdding (double speedRatio, - const float* inputSamples, - float* outputSamples, - int numOutputSamplesToProduce, - int available, - int wrapAround, - float gain) noexcept; - -private: - float lastInputSamples[5]; - double subSamplePos; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CatmullRomInterpolator) -}; - -} // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/effects/juce_LagrangeInterpolator.cpp b/JuceLibraryCode/modules/juce_audio_basics/effects/juce_LagrangeInterpolator.cpp deleted file mode 100644 index 60227f54..00000000 --- a/JuceLibraryCode/modules/juce_audio_basics/effects/juce_LagrangeInterpolator.cpp +++ /dev/null @@ -1,459 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -namespace -{ - static forcedinline void pushInterpolationSample (float* lastInputSamples, float newValue) noexcept - { - lastInputSamples[4] = lastInputSamples[3]; - lastInputSamples[3] = lastInputSamples[2]; - lastInputSamples[2] = lastInputSamples[1]; - lastInputSamples[1] = lastInputSamples[0]; - lastInputSamples[0] = newValue; - } - - static forcedinline void pushInterpolationSamples (float* lastInputSamples, const float* input, int numOut) noexcept - { - if (numOut >= 5) - { - for (int i = 0; i < 5; ++i) - lastInputSamples[i] = input[--numOut]; - } - else - { - for (int i = 0; i < numOut; ++i) - pushInterpolationSample (lastInputSamples, input[i]); - } - } - - static forcedinline void pushInterpolationSamples (float* lastInputSamples, const float* input, - int numOut, int available, int wrapAround) noexcept - { - if (numOut >= 5) - { - if (available >= 5) - { - for (int i = 0; i < 5; ++i) - lastInputSamples[i] = input[--numOut]; - } - else - { - for (int i = 0; i < available; ++i) - lastInputSamples[i] = input[--numOut]; - - if (wrapAround > 0) - { - numOut -= wrapAround; - - for (int i = available; i < 5; ++i) - lastInputSamples[i] = input[--numOut]; - } - else - { - for (int i = available; i < 5; ++i) - lastInputSamples[i] = 0.0f; - } - } - } - else - { - if (numOut > available) - { - for (int i = 0; i < available; ++i) - pushInterpolationSample (lastInputSamples, input[i]); - - if (wrapAround > 0) - { - for (int i = 0; i < numOut - available; ++i) - pushInterpolationSample (lastInputSamples, input[i + available - wrapAround]); - } - else - { - for (int i = 0; i < numOut - available; ++i) - pushInterpolationSample (lastInputSamples, 0); - } - } - else - { - for (int i = 0; i < numOut; ++i) - pushInterpolationSample (lastInputSamples, input[i]); - } - } - } - - template - static int interpolate (float* lastInputSamples, double& subSamplePos, double actualRatio, - const float* in, float* out, int numOut) noexcept - { - auto pos = subSamplePos; - - if (actualRatio == 1.0 && pos == 1.0) - { - memcpy (out, in, (size_t) numOut * sizeof (float)); - pushInterpolationSamples (lastInputSamples, in, numOut); - return numOut; - } - - int numUsed = 0; - - while (numOut > 0) - { - while (pos >= 1.0) - { - pushInterpolationSample (lastInputSamples, in[numUsed++]); - pos -= 1.0; - } - - *out++ = InterpolatorType::valueAtOffset (lastInputSamples, (float) pos); - pos += actualRatio; - --numOut; - } - - subSamplePos = pos; - return numUsed; - } - - template - static int interpolate (float* lastInputSamples, double& subSamplePos, double actualRatio, - const float* in, float* out, int numOut, int available, int wrap) noexcept - { - if (actualRatio == 1.0) - { - if (available >= numOut) - { - memcpy (out, in, (size_t) numOut * sizeof (float)); - pushInterpolationSamples (lastInputSamples, in, numOut, available, wrap); - } - else - { - memcpy (out, in, (size_t) available * sizeof (float)); - pushInterpolationSamples (lastInputSamples, in, numOut, available, wrap); - - if (wrap > 0) - { - memcpy (out + available, in + available - wrap, (size_t) (numOut - available) * sizeof (float)); - pushInterpolationSamples (lastInputSamples, in, numOut, available, wrap); - } - else - { - for (int i = 0; i < numOut - available; ++i) - pushInterpolationSample (lastInputSamples, 0); - } - } - - return numOut; - } - - auto originalIn = in; - auto pos = subSamplePos; - bool exceeded = false; - - if (actualRatio < 1.0) - { - for (int i = numOut; --i >= 0;) - { - if (pos >= 1.0) - { - if (exceeded) - { - pushInterpolationSample (lastInputSamples, 0); - } - else - { - pushInterpolationSample (lastInputSamples, *in++); - - if (--available <= 0) - { - if (wrap > 0) - { - in -= wrap; - available += wrap; - } - else - { - exceeded = true; - } - } - } - - pos -= 1.0; - } - - *out++ = InterpolatorType::valueAtOffset (lastInputSamples, (float) pos); - pos += actualRatio; - } - } - else - { - for (int i = numOut; --i >= 0;) - { - while (pos < actualRatio) - { - if (exceeded) - { - pushInterpolationSample (lastInputSamples, 0); - } - else - { - pushInterpolationSample (lastInputSamples, *in++); - - if (--available <= 0) - { - if (wrap > 0) - { - in -= wrap; - available += wrap; - } - else - { - exceeded = true; - } - } - } - - pos += 1.0; - } - - pos -= actualRatio; - *out++ = InterpolatorType::valueAtOffset (lastInputSamples, jmax (0.0f, 1.0f - (float) pos)); - } - } - - subSamplePos = pos; - return ((int) (in - originalIn) + wrap) % wrap; - } - - template - static int interpolateAdding (float* lastInputSamples, double& subSamplePos, double actualRatio, - const float* in, float* out, int numOut, - int available, int wrap, float gain) noexcept - { - if (actualRatio == 1.0) - { - if (available >= numOut) - { - FloatVectorOperations::addWithMultiply (out, in, gain, numOut); - pushInterpolationSamples (lastInputSamples, in, numOut, available, wrap); - } - else - { - FloatVectorOperations::addWithMultiply (out, in, gain, available); - pushInterpolationSamples (lastInputSamples, in, available, available, wrap); - - if (wrap > 0) - { - FloatVectorOperations::addWithMultiply (out, in - wrap, gain, numOut - available); - pushInterpolationSamples (lastInputSamples, in - wrap, numOut - available, available, wrap); - } - else - { - for (int i = 0; i < numOut-available; ++i) - pushInterpolationSample (lastInputSamples, 0.0); - } - } - - return numOut; - } - - auto originalIn = in; - auto pos = subSamplePos; - bool exceeded = false; - - if (actualRatio < 1.0) - { - for (int i = numOut; --i >= 0;) - { - if (pos >= 1.0) - { - if (exceeded) - { - pushInterpolationSample (lastInputSamples, 0.0); - } - else - { - pushInterpolationSample (lastInputSamples, *in++); - - if (--available <= 0) - { - if (wrap > 0) - { - in -= wrap; - available += wrap; - } - else - { - exceeded = true; - } - } - } - - pos -= 1.0; - } - - *out++ += gain * InterpolatorType::valueAtOffset (lastInputSamples, (float) pos); - pos += actualRatio; - } - } - else - { - for (int i = numOut; --i >= 0;) - { - while (pos < actualRatio) - { - if (exceeded) - { - pushInterpolationSample (lastInputSamples, 0.0); - } - else - { - pushInterpolationSample (lastInputSamples, *in++); - - if (--available <= 0) - { - if (wrap > 0) - { - in -= wrap; - available += wrap; - } - else - { - exceeded = true; - } - } - } - - pos += 1.0; - } - - pos -= actualRatio; - *out++ += gain * InterpolatorType::valueAtOffset (lastInputSamples, jmax (0.0f, 1.0f - (float) pos)); - } - } - - subSamplePos = pos; - return ((int) (in - originalIn) + wrap) % wrap; - } - - template - static int interpolateAdding (float* lastInputSamples, double& subSamplePos, double actualRatio, - const float* in, float* out, int numOut, float gain) noexcept - { - auto pos = subSamplePos; - - if (actualRatio == 1.0 && pos == 1.0) - { - FloatVectorOperations::addWithMultiply (out, in, gain, numOut); - pushInterpolationSamples (lastInputSamples, in, numOut); - return numOut; - } - - int numUsed = 0; - - while (numOut > 0) - { - while (pos >= 1.0) - { - pushInterpolationSample (lastInputSamples, in[numUsed++]); - pos -= 1.0; - } - - *out++ += gain * InterpolatorType::valueAtOffset (lastInputSamples, (float) pos); - pos += actualRatio; - --numOut; - } - - subSamplePos = pos; - return numUsed; - } -} - -//============================================================================== -template -struct LagrangeResampleHelper -{ - static forcedinline void calc (float& a, float b) noexcept { a *= b * (1.0f / k); } -}; - -template<> -struct LagrangeResampleHelper<0> -{ - static forcedinline void calc (float&, float) noexcept {} -}; - -struct LagrangeAlgorithm -{ - static forcedinline float valueAtOffset (const float* inputs, float offset) noexcept - { - return calcCoefficient<0> (inputs[4], offset) - + calcCoefficient<1> (inputs[3], offset) - + calcCoefficient<2> (inputs[2], offset) - + calcCoefficient<3> (inputs[1], offset) - + calcCoefficient<4> (inputs[0], offset); - } - - template - static forcedinline float calcCoefficient (float input, float offset) noexcept - { - LagrangeResampleHelper<0 - k>::calc (input, -2.0f - offset); - LagrangeResampleHelper<1 - k>::calc (input, -1.0f - offset); - LagrangeResampleHelper<2 - k>::calc (input, 0.0f - offset); - LagrangeResampleHelper<3 - k>::calc (input, 1.0f - offset); - LagrangeResampleHelper<4 - k>::calc (input, 2.0f - offset); - return input; - } -}; - -LagrangeInterpolator::LagrangeInterpolator() noexcept { reset(); } -LagrangeInterpolator::~LagrangeInterpolator() noexcept {} - -void LagrangeInterpolator::reset() noexcept -{ - subSamplePos = 1.0; - - for (auto& s : lastInputSamples) - s = 0; -} - -int LagrangeInterpolator::process (double actualRatio, const float* in, float* out, int numOut, int available, int wrap) noexcept -{ - return interpolate (lastInputSamples, subSamplePos, actualRatio, in, out, numOut, available, wrap); -} - -int LagrangeInterpolator::process (double actualRatio, const float* in, float* out, int numOut) noexcept -{ - return interpolate (lastInputSamples, subSamplePos, actualRatio, in, out, numOut); -} - -int LagrangeInterpolator::processAdding (double actualRatio, const float* in, float* out, int numOut, int available, int wrap, float gain) noexcept -{ - return interpolateAdding (lastInputSamples, subSamplePos, actualRatio, in, out, numOut, available, wrap, gain); -} - -int LagrangeInterpolator::processAdding (double actualRatio, const float* in, float* out, int numOut, float gain) noexcept -{ - return interpolateAdding (lastInputSamples, subSamplePos, actualRatio, in, out, numOut, gain); -} - -} // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/effects/juce_LagrangeInterpolator.h b/JuceLibraryCode/modules/juce_audio_basics/effects/juce_LagrangeInterpolator.h deleted file mode 100644 index 6914e465..00000000 --- a/JuceLibraryCode/modules/juce_audio_basics/effects/juce_LagrangeInterpolator.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -/** - Interpolator for resampling a stream of floats using 4-point lagrange interpolation. - - Note that the resampler is stateful, so when there's a break in the continuity - of the input stream you're feeding it, you should call reset() before feeding - it any new data. And like with any other stateful filter, if you're resampling - multiple channels, make sure each one uses its own LagrangeInterpolator - object. - - @see CatmullRomInterpolator - - @tags{Audio} -*/ -class JUCE_API LagrangeInterpolator -{ -public: - LagrangeInterpolator() noexcept; - ~LagrangeInterpolator() noexcept; - - /** Resets the state of the interpolator. - Call this when there's a break in the continuity of the input data stream. - */ - void reset() noexcept; - - /** Resamples a stream of samples. - - @param speedRatio the number of input samples to use for each output sample - @param inputSamples the source data to read from. This must contain at - least (speedRatio * numOutputSamplesToProduce) samples. - @param outputSamples the buffer to write the results into - @param numOutputSamplesToProduce the number of output samples that should be created - - @returns the actual number of input samples that were used - */ - int process (double speedRatio, - const float* inputSamples, - float* outputSamples, - int numOutputSamplesToProduce) noexcept; - - /** Resamples a stream of samples. - - @param speedRatio the number of input samples to use for each output sample - @param inputSamples the source data to read from. This must contain at - least (speedRatio * numOutputSamplesToProduce) samples. - @param outputSamples the buffer to write the results into - @param numOutputSamplesToProduce the number of output samples that should be created - @param available the number of available input samples. If it needs more samples - than available, it either wraps back for wrapAround samples, or - it feeds zeroes - @param wrapAround if the stream exceeds available samples, it wraps back for - wrapAround samples. If wrapAround is set to 0, it will feed zeroes. - - @returns the actual number of input samples that were used - */ - int process (double speedRatio, - const float* inputSamples, - float* outputSamples, - int numOutputSamplesToProduce, - int available, - int wrapAround) noexcept; - - /** Resamples a stream of samples, adding the results to the output data - with a gain. - - @param speedRatio the number of input samples to use for each output sample - @param inputSamples the source data to read from. This must contain at - least (speedRatio * numOutputSamplesToProduce) samples. - @param outputSamples the buffer to write the results to - the result values will be added - to any pre-existing data in this buffer after being multiplied by - the gain factor - @param numOutputSamplesToProduce the number of output samples that should be created - @param gain a gain factor to multiply the resulting samples by before - adding them to the destination buffer - - @returns the actual number of input samples that were used - */ - int processAdding (double speedRatio, - const float* inputSamples, - float* outputSamples, - int numOutputSamplesToProduce, - float gain) noexcept; - - /** Resamples a stream of samples, adding the results to the output data - with a gain. - - @param speedRatio the number of input samples to use for each output sample - @param inputSamples the source data to read from. This must contain at - least (speedRatio * numOutputSamplesToProduce) samples. - @param outputSamples the buffer to write the results to - the result values will be added - to any pre-existing data in this buffer after being multiplied by - the gain factor - @param numOutputSamplesToProduce the number of output samples that should be created - @param available the number of available input samples. If it needs more samples - than available, it either wraps back for wrapAround samples, or - it feeds zeroes - @param wrapAround if the stream exceeds available samples, it wraps back for - wrapAround samples. If wrapAround is set to 0, it will feed zeroes. - @param gain a gain factor to multiply the resulting samples by before - adding them to the destination buffer - - @returns the actual number of input samples that were used - */ - int processAdding (double speedRatio, - const float* inputSamples, - float* outputSamples, - int numOutputSamplesToProduce, - int available, - int wrapAround, - float gain) noexcept; - -private: - float lastInputSamples[5]; - double subSamplePos; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LagrangeInterpolator) -}; - -} // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/effects/juce_LinearSmoothedValue.h b/JuceLibraryCode/modules/juce_audio_basics/effects/juce_LinearSmoothedValue.h deleted file mode 100644 index 80dd6fc0..00000000 --- a/JuceLibraryCode/modules/juce_audio_basics/effects/juce_LinearSmoothedValue.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Utility class for linearly smoothed values like volume etc. that should - not change abruptly but as a linear ramp, to avoid audio glitches. - - @tags{Audio} -*/ -template -class LinearSmoothedValue -{ -public: - /** Constructor. */ - LinearSmoothedValue() noexcept - { - } - - /** Constructor. */ - LinearSmoothedValue (FloatType initialValue) noexcept - : currentValue (initialValue), target (initialValue) - { - } - - //============================================================================== - /** Reset to a new sample rate and ramp length. - @param sampleRate The sampling rate - @param rampLengthInSeconds The duration of the ramp in seconds - */ - void reset (double sampleRate, double rampLengthInSeconds) noexcept - { - jassert (sampleRate > 0 && rampLengthInSeconds >= 0); - stepsToTarget = (int) std::floor (rampLengthInSeconds * sampleRate); - currentValue = target; - countdown = 0; - } - - //============================================================================== - /** Set a new target value. - - @param newValue The new target value - @param force If true, the value will be set immediately, bypassing the ramp - */ - void setValue (FloatType newValue, bool force = false) noexcept - { - if (force) - { - target = currentValue = newValue; - countdown = 0; - return; - } - - if (target != newValue) - { - target = newValue; - countdown = stepsToTarget; - - if (countdown <= 0) - currentValue = target; - else - step = (target - currentValue) / (FloatType) countdown; - } - } - - //============================================================================== - /** Compute the next value. - @returns Smoothed value - */ - FloatType getNextValue() noexcept - { - if (countdown <= 0) - return target; - - --countdown; - currentValue += step; - return currentValue; - } - - /** Returns true if the current value is currently being interpolated. */ - bool isSmoothing() const noexcept - { - return countdown > 0; - } - - /** Returns the target value towards which the smoothed value is currently moving. */ - FloatType getTargetValue() const noexcept - { - return target; - } - - //============================================================================== - /** Applies a linear smoothed gain to a stream of samples - S[i] *= gain - @param samples Pointer to a raw array of samples - @param numSamples Length of array of samples - */ - void applyGain (FloatType* samples, int numSamples) noexcept - { - jassert(numSamples >= 0); - - if (isSmoothing()) - { - for (int i = 0; i < numSamples; i++) - samples[i] *= getNextValue(); - } - else - { - FloatVectorOperations::multiply (samples, target, numSamples); - } - } - - //============================================================================== - /** Computes output as linear smoothed gain applied to a stream of samples. - Sout[i] = Sin[i] * gain - @param samplesOut A pointer to a raw array of output samples - @param samplesIn A pointer to a raw array of input samples - @param numSamples The length of the array of samples - */ - void applyGain (FloatType* samplesOut, const FloatType* samplesIn, int numSamples) noexcept - { - jassert (numSamples >= 0); - - if (isSmoothing()) - { - for (int i = 0; i < numSamples; i++) - samplesOut[i] = samplesIn[i] * getNextValue(); - } - else - { - FloatVectorOperations::multiply (samplesOut, samplesIn, target, numSamples); - } - } - - //============================================================================== - /** Applies a linear smoothed gain to a buffer */ - void applyGain (AudioBuffer& buffer, int numSamples) noexcept - { - jassert (numSamples >= 0); - - if (isSmoothing()) - { - if (buffer.getNumChannels() == 1) - { - FloatType* samples = buffer.getWritePointer(0); - - for (int i = 0; i < numSamples; i++) - samples[i] *= getNextValue(); - } - else - { - for (int i = 0; i < numSamples; i++) - { - const FloatType gain = getNextValue(); - - for (int channel = 0; channel < buffer.getNumChannels(); channel++) - buffer.setSample (channel, i, buffer.getSample (channel, i) * gain); - } - } - } - else - { - buffer.applyGain (0, numSamples, target); - } - } - - //============================================================================== - /** Skip the next numSamples samples. - - This is identical to calling getNextValue numSamples times. - @see getNextValue - */ - void skip (int numSamples) noexcept - { - if (numSamples >= countdown) - { - currentValue = target; - countdown = 0; - } - else - { - currentValue += (step * static_cast (numSamples)); - countdown -= numSamples; - } - } - -private: - //============================================================================== - FloatType currentValue = 0, target = 0, step = 0; - int countdown = 0, stepsToTarget = 0; -}; - -} // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.cpp b/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.cpp index 56371d0d..3d0ab44d 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -56,9 +56,12 @@ #include "buffers/juce_AudioDataConverters.cpp" #include "buffers/juce_FloatVectorOperations.cpp" #include "buffers/juce_AudioChannelSet.cpp" -#include "effects/juce_IIRFilter.cpp" -#include "effects/juce_LagrangeInterpolator.cpp" -#include "effects/juce_CatmullRomInterpolator.cpp" +#include "buffers/juce_AudioProcessLoadMeasurer.cpp" +#include "utilities/juce_IIRFilter.cpp" +#include "utilities/juce_LagrangeInterpolator.cpp" +#include "utilities/juce_WindowedSincInterpolator.cpp" +#include "utilities/juce_Interpolators.cpp" +#include "utilities/juce_SmoothedValue.cpp" #include "midi/juce_MidiBuffer.cpp" #include "midi/juce_MidiFile.cpp" #include "midi/juce_MidiKeyboardState.cpp" @@ -83,3 +86,14 @@ #include "sources/juce_ReverbAudioSource.cpp" #include "sources/juce_ToneGeneratorAudioSource.cpp" #include "synthesisers/juce_Synthesiser.cpp" + +#include "midi/ump/juce_UMP.h" +#include "midi/ump/juce_UMPUtils.cpp" +#include "midi/ump/juce_UMPView.cpp" +#include "midi/ump/juce_UMPSysEx7.cpp" +#include "midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.cpp" + +#if JUCE_UNIT_TESTS + #include "utilities/juce_ADSR_test.cpp" + #include "midi/ump/juce_UMPTests.cpp" +#endif diff --git a/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.h b/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.h index 8c3c7896..97b559e8 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.h +++ b/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -20,26 +20,28 @@ ============================================================================== */ + /******************************************************************************* The block below describes the properties of this module, and is read by the Projucer to automatically generate project code that uses it. For details about the syntax and how to create or use a module, see the - JUCE Module Format.txt file. + JUCE Module Format.md file. BEGIN_JUCE_MODULE_DECLARATION - ID: juce_audio_basics - vendor: juce - version: 5.3.0 - name: JUCE audio and MIDI data classes - description: Classes for audio buffer manipulation, midi message handling, synthesis, etc. - website: http://www.juce.com/juce - license: ISC + ID: juce_audio_basics + vendor: juce + version: 6.1.6 + name: JUCE audio and MIDI data classes + description: Classes for audio buffer manipulation, midi message handling, synthesis, etc. + website: http://www.juce.com/juce + license: ISC + minimumCppStandard: 14 - dependencies: juce_core - OSXFrameworks: Accelerate - iOSFrameworks: Accelerate + dependencies: juce_core + OSXFrameworks: Accelerate + iOSFrameworks: Accelerate END_JUCE_MODULE_DECLARATION @@ -84,12 +86,14 @@ #include "buffers/juce_FloatVectorOperations.h" #include "buffers/juce_AudioSampleBuffer.h" #include "buffers/juce_AudioChannelSet.h" -#include "effects/juce_Decibels.h" -#include "effects/juce_IIRFilter.h" -#include "effects/juce_LagrangeInterpolator.h" -#include "effects/juce_CatmullRomInterpolator.h" -#include "effects/juce_LinearSmoothedValue.h" -#include "effects/juce_Reverb.h" +#include "buffers/juce_AudioProcessLoadMeasurer.h" +#include "utilities/juce_Decibels.h" +#include "utilities/juce_IIRFilter.h" +#include "utilities/juce_GenericInterpolator.h" +#include "utilities/juce_Interpolators.h" +#include "utilities/juce_SmoothedValue.h" +#include "utilities/juce_Reverb.h" +#include "utilities/juce_ADSR.h" #include "midi/juce_MidiMessage.h" #include "midi/juce_MidiBuffer.h" #include "midi/juce_MidiMessageSequence.h" diff --git a/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.mm b/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.mm index 588078c3..27a6289c 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.mm +++ b/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.mm @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiBuffer.cpp b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiBuffer.cpp index 91689d33..dfdf41ee 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiBuffer.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiBuffer.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -25,51 +25,52 @@ namespace juce namespace MidiBufferHelpers { - inline int getEventTime (const void* const d) noexcept + inline int getEventTime (const void* d) noexcept { return readUnaligned (d); } - inline uint16 getEventDataSize (const void* const d) noexcept + inline uint16 getEventDataSize (const void* d) noexcept { return readUnaligned (static_cast (d) + sizeof (int32)); } - inline uint16 getEventTotalSize (const void* const d) noexcept + inline uint16 getEventTotalSize (const void* d) noexcept { return (uint16) (getEventDataSize (d) + sizeof (int32) + sizeof (uint16)); } - static int findActualEventLength (const uint8* const data, const int maxBytes) noexcept + static int findActualEventLength (const uint8* data, int maxBytes) noexcept { - unsigned int byte = (unsigned int) *data; - int size = 0; + auto byte = (unsigned int) *data; if (byte == 0xf0 || byte == 0xf7) { - const uint8* d = data + 1; + int i = 1; - while (d < data + maxBytes) - if (*d++ == 0xf7) + while (i < maxBytes) + if (data[i++] == 0xf7) break; - size = (int) (d - data); + return i; } - else if (byte == 0xff) - { - int n; - const int bytesLeft = MidiMessage::readVariableLengthVal (data + 1, n); - size = jmin (maxBytes, n + 2 + bytesLeft); - } - else if (byte >= 0x80) + + if (byte == 0xff) { - size = jmin (maxBytes, MidiMessage::getMessageLengthFromFirstByte ((uint8) byte)); + if (maxBytes == 1) + return 1; + + const auto var = MidiMessage::readVariableLengthValue (data + 1, maxBytes - 1); + return jmin (maxBytes, var.value + 2 + var.bytesUsed); } - return size; + if (byte >= 0x80) + return jmin (maxBytes, MidiMessage::getMessageLengthFromFirstByte ((uint8) byte)); + + return 0; } - static uint8* findEventAfter (uint8* d, uint8* endData, const int samplePosition) noexcept + static uint8* findEventAfter (uint8* d, uint8* endData, int samplePosition) noexcept { while (d < endData && getEventTime (d) <= samplePosition) d += getEventTotalSize (d); @@ -79,17 +80,27 @@ namespace MidiBufferHelpers } //============================================================================== -MidiBuffer::MidiBuffer() noexcept {} -MidiBuffer::~MidiBuffer() {} +MidiBufferIterator& MidiBufferIterator::operator++() noexcept +{ + data += sizeof (int32) + sizeof (uint16) + size_t (MidiBufferHelpers::getEventDataSize (data)); + return *this; +} -MidiBuffer::MidiBuffer (const MidiBuffer& other) noexcept : data (other.data) {} +MidiBufferIterator MidiBufferIterator::operator++ (int) noexcept +{ + auto copy = *this; + ++(*this); + return copy; +} -MidiBuffer& MidiBuffer::operator= (const MidiBuffer& other) noexcept +MidiBufferIterator::reference MidiBufferIterator::operator*() const noexcept { - data = other.data; - return *this; + return { data + sizeof (int32) + sizeof (uint16), + MidiBufferHelpers::getEventDataSize (data), + MidiBufferHelpers::getEventTime (data) }; } +//============================================================================== MidiBuffer::MidiBuffer (const MidiMessage& message) noexcept { addEvent (message, 0); @@ -100,61 +111,67 @@ void MidiBuffer::clear() noexcept { data.clearQuick(); void MidiBuffer::ensureSize (size_t minimumNumBytes) { data.ensureStorageAllocated ((int) minimumNumBytes); } bool MidiBuffer::isEmpty() const noexcept { return data.size() == 0; } -void MidiBuffer::clear (const int startSample, const int numSamples) +void MidiBuffer::clear (int startSample, int numSamples) { - uint8* const start = MidiBufferHelpers::findEventAfter (data.begin(), data.end(), startSample - 1); - uint8* const end = MidiBufferHelpers::findEventAfter (start, data.end(), startSample + numSamples - 1); + auto start = MidiBufferHelpers::findEventAfter (data.begin(), data.end(), startSample - 1); + auto end = MidiBufferHelpers::findEventAfter (start, data.end(), startSample + numSamples - 1); - data.removeRange ((int) (start - data.begin()), (int) (end - data.begin())); + data.removeRange ((int) (start - data.begin()), (int) (end - start)); } -void MidiBuffer::addEvent (const MidiMessage& m, const int sampleNumber) +bool MidiBuffer::addEvent (const MidiMessage& m, int sampleNumber) { - addEvent (m.getRawData(), m.getRawDataSize(), sampleNumber); + return addEvent (m.getRawData(), m.getRawDataSize(), sampleNumber); } -void MidiBuffer::addEvent (const void* const newData, const int maxBytes, const int sampleNumber) +bool MidiBuffer::addEvent (const void* newData, int maxBytes, int sampleNumber) { - const int numBytes = MidiBufferHelpers::findActualEventLength (static_cast (newData), maxBytes); + auto numBytes = MidiBufferHelpers::findActualEventLength (static_cast (newData), maxBytes); + + if (numBytes <= 0) + return true; - if (numBytes > 0) + if (std::numeric_limits::max() < numBytes) { - const size_t newItemSize = (size_t) numBytes + sizeof (int32) + sizeof (uint16); - const int offset = (int) (MidiBufferHelpers::findEventAfter (data.begin(), data.end(), sampleNumber) - data.begin()); + // This method only supports messages smaller than (1 << 16) bytes + return false; + } - data.insertMultiple (offset, 0, (int) newItemSize); + auto newItemSize = (size_t) numBytes + sizeof (int32) + sizeof (uint16); + auto offset = (int) (MidiBufferHelpers::findEventAfter (data.begin(), data.end(), sampleNumber) - data.begin()); - uint8* const d = data.begin() + offset; - writeUnaligned (d, sampleNumber); - writeUnaligned (d + 4, static_cast (numBytes)); - memcpy (d + 6, newData, (size_t) numBytes); - } + data.insertMultiple (offset, 0, (int) newItemSize); + + auto* d = data.begin() + offset; + writeUnaligned (d, sampleNumber); + d += sizeof (int32); + writeUnaligned (d, static_cast (numBytes)); + d += sizeof (uint16); + memcpy (d, newData, (size_t) numBytes); + + return true; } void MidiBuffer::addEvents (const MidiBuffer& otherBuffer, - const int startSample, - const int numSamples, - const int sampleDeltaToAdd) + int startSample, int numSamples, int sampleDeltaToAdd) { - Iterator i (otherBuffer); - i.setNextSamplePosition (startSample); + for (auto i = otherBuffer.findNextSamplePosition (startSample); i != otherBuffer.cend(); ++i) + { + const auto metadata = *i; - const uint8* eventData; - int eventSize, position; + if (metadata.samplePosition >= startSample + numSamples && numSamples >= 0) + break; - while (i.getNextEvent (eventData, eventSize, position) - && (position < startSample + numSamples || numSamples < 0)) - { - addEvent (eventData, eventSize, position + sampleDeltaToAdd); + addEvent (metadata.data, metadata.numBytes, metadata.samplePosition + sampleDeltaToAdd); } } int MidiBuffer::getNumEvents() const noexcept { int n = 0; - const uint8* const end = data.end(); + auto end = data.end(); - for (const uint8* d = data.begin(); d < end; ++n) + for (auto d = data.begin(); d < end; ++n) d += MidiBufferHelpers::getEventTotalSize (d); return n; @@ -170,11 +187,11 @@ int MidiBuffer::getLastEventTime() const noexcept if (data.size() == 0) return 0; - const uint8* const endData = data.end(); + auto endData = data.end(); - for (const uint8* d = data.begin();;) + for (auto d = data.begin();;) { - const uint8* const nextOne = d + MidiBufferHelpers::getEventTotalSize (d); + auto nextOne = d + MidiBufferHelpers::getEventTotalSize (d); if (nextOne >= endData) return MidiBufferHelpers::getEventTime (d); @@ -183,48 +200,121 @@ int MidiBuffer::getLastEventTime() const noexcept } } -//============================================================================== -MidiBuffer::Iterator::Iterator (const MidiBuffer& b) noexcept - : buffer (b), data (b.data.begin()) +MidiBufferIterator MidiBuffer::findNextSamplePosition (int samplePosition) const noexcept { + return std::find_if (cbegin(), cend(), [&] (const MidiMessageMetadata& metadata) noexcept + { + return metadata.samplePosition >= samplePosition; + }); } -MidiBuffer::Iterator::~Iterator() noexcept{} +//============================================================================== +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") +JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996) -void MidiBuffer::Iterator::setNextSamplePosition (const int samplePosition) noexcept +MidiBuffer::Iterator::Iterator (const MidiBuffer& b) noexcept + : buffer (b), iterator (b.data.begin()) { - data = buffer.data.begin(); - const uint8* const dataEnd = buffer.data.end(); +} - while (data < dataEnd && MidiBufferHelpers::getEventTime (data) < samplePosition) - data += MidiBufferHelpers::getEventTotalSize (data); +void MidiBuffer::Iterator::setNextSamplePosition (int samplePosition) noexcept +{ + iterator = buffer.findNextSamplePosition (samplePosition); } -bool MidiBuffer::Iterator::getNextEvent (const uint8* &midiData, int& numBytes, int& samplePosition) noexcept +bool MidiBuffer::Iterator::getNextEvent (const uint8*& midiData, int& numBytes, int& samplePosition) noexcept { - if (data >= buffer.data.end()) + if (iterator == buffer.cend()) return false; - samplePosition = MidiBufferHelpers::getEventTime (data); - const int itemSize = MidiBufferHelpers::getEventDataSize (data); - numBytes = itemSize; - midiData = data + sizeof (int32) + sizeof (uint16); - data += sizeof (int32) + sizeof (uint16) + (size_t) itemSize; - + const auto metadata = *iterator++; + midiData = metadata.data; + numBytes = metadata.numBytes; + samplePosition = metadata.samplePosition; return true; } bool MidiBuffer::Iterator::getNextEvent (MidiMessage& result, int& samplePosition) noexcept { - if (data >= buffer.data.end()) + if (iterator == buffer.cend()) return false; - samplePosition = MidiBufferHelpers::getEventTime (data); - const int itemSize = MidiBufferHelpers::getEventDataSize (data); - result = MidiMessage (data + sizeof (int32) + sizeof (uint16), itemSize, samplePosition); - data += sizeof (int32) + sizeof (uint16) + (size_t) itemSize; - + const auto metadata = *iterator++; + result = metadata.getMessage(); + samplePosition = metadata.samplePosition; return true; } +JUCE_END_IGNORE_WARNINGS_MSVC +JUCE_END_IGNORE_WARNINGS_GCC_LIKE + +//============================================================================== +//============================================================================== +#if JUCE_UNIT_TESTS + +struct MidiBufferTest : public UnitTest +{ + MidiBufferTest() + : UnitTest ("MidiBuffer", UnitTestCategories::midi) + {} + + void runTest() override + { + beginTest ("Clear messages"); + { + const auto message = MidiMessage::noteOn (1, 64, 0.5f); + + const auto testBuffer = [&] + { + MidiBuffer buffer; + buffer.addEvent (message, 0); + buffer.addEvent (message, 10); + buffer.addEvent (message, 20); + buffer.addEvent (message, 30); + return buffer; + }(); + + { + auto buffer = testBuffer; + buffer.clear (10, 0); + expectEquals (buffer.getNumEvents(), 4); + } + + { + auto buffer = testBuffer; + buffer.clear (10, 1); + expectEquals (buffer.getNumEvents(), 3); + } + + { + auto buffer = testBuffer; + buffer.clear (10, 10); + expectEquals (buffer.getNumEvents(), 3); + } + + { + auto buffer = testBuffer; + buffer.clear (10, 20); + expectEquals (buffer.getNumEvents(), 2); + } + + { + auto buffer = testBuffer; + buffer.clear (10, 30); + expectEquals (buffer.getNumEvents(), 1); + } + + { + auto buffer = testBuffer; + buffer.clear (10, 300); + expectEquals (buffer.getNumEvents(), 1); + } + } + } +}; + +static MidiBufferTest midiBufferTest; + +#endif + } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiBuffer.h b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiBuffer.h index 27e86c7c..583c93ef 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiBuffer.h +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiBuffer.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -23,6 +23,108 @@ namespace juce { +//============================================================================== +/** + A view of MIDI message data stored in a contiguous buffer. + + Instances of this class do *not* own the midi data bytes that they point to. + Instead, they expect the midi data to live in a separate buffer that outlives + the MidiMessageMetadata instance. + + @tags{Audio} +*/ +struct MidiMessageMetadata final +{ + MidiMessageMetadata() noexcept = default; + + MidiMessageMetadata (const uint8* dataIn, int numBytesIn, int positionIn) noexcept + : data (dataIn), numBytes (numBytesIn), samplePosition (positionIn) + { + } + + /** Constructs a new MidiMessage instance from the data that this object is viewing. + + Note that MidiMessage owns its data storage, whereas MidiMessageMetadata does not. + */ + MidiMessage getMessage() const { return MidiMessage (data, numBytes, samplePosition); } + + /** Pointer to the first byte of a MIDI message. */ + const uint8* data = nullptr; + + /** The number of bytes in the MIDI message. */ + int numBytes = 0; + + /** The MIDI message's timestamp. */ + int samplePosition = 0; +}; + +//============================================================================== +/** + An iterator to move over contiguous raw MIDI data, which Allows iterating + over a MidiBuffer using C++11 range-for syntax. + + In the following example, we log all three-byte messages in a midi buffer. + @code + void processBlock (AudioBuffer&, MidiBuffer& midiBuffer) override + { + for (const MidiMessageMetadata metadata : midiBuffer) + if (metadata.numBytes == 3) + Logger::writeToLog (metadata.getMessage().getDescription()); + } + @endcode + + @tags{Audio} +*/ +class JUCE_API MidiBufferIterator +{ + using Ptr = const uint8*; + +public: + MidiBufferIterator() = default; + + /** Constructs an iterator pointing at the message starting at the byte `dataIn`. + `dataIn` must point to the start of a valid MIDI message. If it does not, + calling other member functions on the iterator will result in undefined + behaviour. + */ + explicit MidiBufferIterator (const uint8* dataIn) noexcept + : data (dataIn) + { + } + + using difference_type = std::iterator_traits::difference_type; + using value_type = MidiMessageMetadata; + using reference = MidiMessageMetadata; + using pointer = void; + using iterator_category = std::input_iterator_tag; + + /** Make this iterator point to the next message in the buffer. */ + MidiBufferIterator& operator++() noexcept; + + /** Create a copy of this object, make this iterator point to the next message in + the buffer, then return the copy. + */ + MidiBufferIterator operator++ (int) noexcept; + + /** Return true if this iterator points to the same message as another + iterator instance, otherwise return false. + */ + bool operator== (const MidiBufferIterator& other) const noexcept { return data == other.data; } + + /** Return false if this iterator points to the same message as another + iterator instance, otherwise returns true. + */ + bool operator!= (const MidiBufferIterator& other) const noexcept { return ! operator== (other); } + + /** Return an instance of MidiMessageMetadata which describes the message to which + the iterator is currently pointing. + */ + reference operator*() const noexcept; + +private: + Ptr data = nullptr; +}; + //============================================================================== /** Holds a sequence of time-stamped midi events. @@ -44,20 +146,11 @@ class JUCE_API MidiBuffer public: //============================================================================== /** Creates an empty MidiBuffer. */ - MidiBuffer() noexcept; + MidiBuffer() noexcept = default; /** Creates a MidiBuffer containing a single midi message. */ explicit MidiBuffer (const MidiMessage& message) noexcept; - /** Creates a copy of another MidiBuffer. */ - MidiBuffer (const MidiBuffer&) noexcept; - - /** Makes a copy of another MidiBuffer. */ - MidiBuffer& operator= (const MidiBuffer&) noexcept; - - /** Destructor */ - ~MidiBuffer(); - //============================================================================== /** Removes all events from the buffer. */ void clear() noexcept; @@ -70,7 +163,7 @@ class JUCE_API MidiBuffer void clear (int start, int numSamples); /** Returns true if the buffer is empty. - To actually retrieve the events, use a MidiBuffer::Iterator object + To actually retrieve the events, use a MidiBufferIterator object */ bool isEmpty() const noexcept; @@ -91,9 +184,11 @@ class JUCE_API MidiBuffer If an event is added whose sample position is the same as one or more events already in the buffer, the new event will be placed after the existing ones. - To retrieve events, use a MidiBuffer::Iterator object + To retrieve events, use a MidiBufferIterator object. + + Returns true on success, or false on failure. */ - void addEvent (const MidiMessage& midiMessage, int sampleNumber); + bool addEvent (const MidiMessage& midiMessage, int sampleNumber); /** Adds an event to the buffer from raw midi data. @@ -109,9 +204,11 @@ class JUCE_API MidiBuffer it'll actually only store 3 bytes. If the midi data is invalid, it might not add an event at all. - To retrieve events, use a MidiBuffer::Iterator object + To retrieve events, use a MidiBufferIterator object. + + Returns true on success, or false on failure. */ - void addEvent (const void* rawMidiData, + bool addEvent (const void* rawMidiData, int maxBytesOfMidiData, int sampleNumber); @@ -158,8 +255,27 @@ class JUCE_API MidiBuffer */ void ensureSize (size_t minimumNumBytes); + /** Get a read-only iterator pointing to the beginning of this buffer. */ + MidiBufferIterator begin() const noexcept { return cbegin(); } + + /** Get a read-only iterator pointing one past the end of this buffer. */ + MidiBufferIterator end() const noexcept { return cend(); } + + /** Get a read-only iterator pointing to the beginning of this buffer. */ + MidiBufferIterator cbegin() const noexcept { return MidiBufferIterator (data.begin()); } + + /** Get a read-only iterator pointing one past the end of this buffer. */ + MidiBufferIterator cend() const noexcept { return MidiBufferIterator (data.end()); } + + /** Get an iterator pointing to the first event with a timestamp greater-than or + equal-to `samplePosition`. + */ + MidiBufferIterator findNextSamplePosition (int samplePosition) const noexcept; + //============================================================================== - /** + #ifndef DOXYGEN + /** This class is now deprecated in favour of MidiBufferIterator. + Used to iterate through the events in a MidiBuffer. Note that altering the buffer while an iterator is using it will produce @@ -167,21 +283,12 @@ class JUCE_API MidiBuffer @see MidiBuffer */ - class JUCE_API Iterator + class [[deprecated]] JUCE_API Iterator { public: //============================================================================== /** Creates an Iterator for this MidiBuffer. */ - Iterator (const MidiBuffer&) noexcept; - - /** Creates a copy of an iterator. */ - Iterator (const Iterator&) = default; - - // VS2013 requires this, even if it's unused. - Iterator& operator= (const Iterator&) = delete; - - /** Destructor. */ - ~Iterator() noexcept; + Iterator (const MidiBuffer& b) noexcept; //============================================================================== /** Repositions the iterator so that the next event retrieved will be the first @@ -221,8 +328,9 @@ class JUCE_API MidiBuffer private: //============================================================================== const MidiBuffer& buffer; - const uint8* data; + MidiBufferIterator iterator; }; + #endif /** The raw data holding this buffer. Obviously access to this data is provided at your own risk. Its internal format could diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_MidiDataConcatenator.h b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiDataConcatenator.h similarity index 51% rename from JuceLibraryCode/modules/juce_audio_devices/native/juce_MidiDataConcatenator.h rename to JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiDataConcatenator.h index fa8080fa..342c33c5 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_MidiDataConcatenator.h +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiDataConcatenator.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -33,79 +33,68 @@ namespace juce class MidiDataConcatenator { public: - //============================================================================== MidiDataConcatenator (int initialBufferSize) - : pendingData ((size_t) initialBufferSize) + : pendingSysexData ((size_t) initialBufferSize) { } void reset() { - pendingBytes = 0; - runningStatus = 0; - pendingDataTime = 0; + currentMessageLen = 0; + pendingSysexSize = 0; + pendingSysexTime = 0; } template void pushMidiData (const void* inputData, int numBytes, double time, UserDataType* input, CallbackType& callback) { - const uint8* d = static_cast (inputData); + auto d = static_cast (inputData); while (numBytes > 0) { - if (pendingBytes > 0 || d[0] == 0xf0) + auto nextByte = *d; + + if (pendingSysexSize != 0 || nextByte == 0xf0) { processSysex (d, numBytes, time, input, callback); - runningStatus = 0; + currentMessageLen = 0; + continue; } - else - { - int len = 0; - uint8 data[3]; - - while (numBytes > 0) - { - // If there's a realtime message embedded in the middle of - // the normal message, handle it now.. - if (*d >= 0xf8 && *d <= 0xfe) - { - callback.handleIncomingMidiMessage (input, MidiMessage (*d++, time)); - --numBytes; - } - else - { - if (len == 0 && *d < 0x80 && runningStatus >= 0x80) - data[len++] = runningStatus; - - data[len++] = *d++; - --numBytes; - const uint8 firstByte = data[0]; + ++d; + --numBytes; - if (firstByte < 0x80 || firstByte == 0xf7) - { - len = 0; - break; // ignore this malformed MIDI message.. - } - - if (len >= MidiMessage::getMessageLengthFromFirstByte (firstByte)) - break; - } - } + if (isRealtimeMessage (nextByte)) + { + callback.handleIncomingMidiMessage (input, MidiMessage (nextByte, time)); + // These can be embedded in the middle of a normal message, so we won't + // reset the currentMessageLen here. + continue; + } - if (len > 0) - { - int used = 0; - const MidiMessage m (data, len, used, 0, time); + if (isInitialByte (nextByte)) + { + currentMessage[0] = nextByte; + currentMessageLen = 1; + } + else if (currentMessageLen > 0 && currentMessageLen < 3) + { + currentMessage[currentMessageLen++] = nextByte; + } + else + { + // message is too long or invalid MIDI - abandon it and start again with the next byte + currentMessageLen = 0; + continue; + } - if (used <= 0) - break; // malformed message.. + auto expectedLength = MidiMessage::getMessageLengthFromFirstByte (currentMessage[0]); - jassert (used == len); - callback.handleIncomingMidiMessage (input, m); - runningStatus = data[0]; - } + if (expectedLength == currentMessageLen) + { + callback.handleIncomingMidiMessage (input, MidiMessage (currentMessage, expectedLength, time)); + currentMessageLen = 1; // reset, but leave the first byte to use as the running status byte } } } @@ -117,22 +106,22 @@ class MidiDataConcatenator { if (*d == 0xf0) { - pendingBytes = 0; - pendingDataTime = time; + pendingSysexSize = 0; + pendingSysexTime = time; } - pendingData.ensureSize ((size_t) (pendingBytes + numBytes), false); - uint8* totalMessage = static_cast (pendingData.getData()); - uint8* dest = totalMessage + pendingBytes; + pendingSysexData.ensureSize ((size_t) (pendingSysexSize + numBytes), false); + auto totalMessage = static_cast (pendingSysexData.getData()); + auto dest = totalMessage + pendingSysexSize; do { - if (pendingBytes > 0 && *d >= 0x80) + if (pendingSysexSize > 0 && isStatusByte (*d)) { if (*d == 0xf7) { *dest++ = *d++; - ++pendingBytes; + ++pendingSysexSize; --numBytes; break; } @@ -145,7 +134,7 @@ class MidiDataConcatenator } else { - pendingBytes = 0; + pendingSysexSize = 0; int used = 0; const MidiMessage m (d, numBytes, used, 0, time); @@ -162,30 +151,36 @@ class MidiDataConcatenator else { *dest++ = *d++; - ++pendingBytes; + ++pendingSysexSize; --numBytes; } } while (numBytes > 0); - if (pendingBytes > 0) + if (pendingSysexSize > 0) { - if (totalMessage [pendingBytes - 1] == 0xf7) + if (totalMessage [pendingSysexSize - 1] == 0xf7) { - callback.handleIncomingMidiMessage (input, MidiMessage (totalMessage, pendingBytes, pendingDataTime)); - pendingBytes = 0; + callback.handleIncomingMidiMessage (input, MidiMessage (totalMessage, pendingSysexSize, pendingSysexTime)); + pendingSysexSize = 0; } else { - callback.handlePartialSysexMessage (input, totalMessage, pendingBytes, pendingDataTime); + callback.handlePartialSysexMessage (input, totalMessage, pendingSysexSize, pendingSysexTime); } } } - MemoryBlock pendingData; - double pendingDataTime = 0; - int pendingBytes = 0; - uint8 runningStatus = 0; + static bool isRealtimeMessage (uint8 byte) { return byte >= 0xf8 && byte <= 0xfe; } + static bool isStatusByte (uint8 byte) { return byte >= 0x80; } + static bool isInitialByte (uint8 byte) { return isStatusByte (byte) && byte != 0xf7; } + + uint8 currentMessage[3]; + int currentMessageLen = 0; + + MemoryBlock pendingSysexData; + double pendingSysexTime = 0; + int pendingSysexSize = 0; JUCE_DECLARE_NON_COPYABLE (MidiDataConcatenator) }; diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiFile.cpp b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiFile.cpp index 65e7b0ed..dd1c4329 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiFile.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiFile.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -46,23 +46,77 @@ namespace MidiFileHelpers } } - static bool parseMidiHeader (const uint8* &data, short& timeFormat, short& fileType, short& numberOfTracks) noexcept + template + struct Optional { - auto ch = ByteOrder::bigEndianInt (data); - data += 4; + Optional() = default; - if (ch != ByteOrder::bigEndianInt ("MThd")) + Optional (const Value& v) + : value (v), valid (true) {} + + Value value = Value(); + bool valid = false; + }; + + template + struct ReadTrait; + + template <> + struct ReadTrait { static constexpr auto read = ByteOrder::bigEndianInt; }; + + template <> + struct ReadTrait { static constexpr auto read = ByteOrder::bigEndianShort; }; + + template + Optional tryRead (const uint8*& data, size_t& remaining) + { + using Trait = ReadTrait; + constexpr auto size = sizeof (Integral); + + if (remaining < size) + return {}; + + const Optional result { Trait::read (data) }; + + data += size; + remaining -= size; + + return result; + } + + struct HeaderDetails + { + size_t bytesRead = 0; + short timeFormat = 0; + short fileType = 0; + short numberOfTracks = 0; + }; + + static Optional parseMidiHeader (const uint8* const initialData, + const size_t maxSize) + { + auto* data = initialData; + auto remaining = maxSize; + + auto ch = tryRead (data, remaining); + + if (! ch.valid) + return {}; + + if (ch.value != ByteOrder::bigEndianInt ("MThd")) { - bool ok = false; + auto ok = false; - if (ch == ByteOrder::bigEndianInt ("RIFF")) + if (ch.value == ByteOrder::bigEndianInt ("RIFF")) { for (int i = 0; i < 8; ++i) { - ch = ByteOrder::bigEndianInt (data); - data += 4; + ch = tryRead (data, remaining); + + if (! ch.valid) + return {}; - if (ch == ByteOrder::bigEndianInt ("MThd")) + if (ch.value == ByteOrder::bigEndianInt ("MThd")) { ok = true; break; @@ -71,21 +125,37 @@ namespace MidiFileHelpers } if (! ok) - return false; + return {}; } - auto bytesRemaining = ByteOrder::bigEndianInt (data); - data += 4; - fileType = (short) ByteOrder::bigEndianShort (data); - data += 2; - numberOfTracks = (short) ByteOrder::bigEndianShort (data); - data += 2; - timeFormat = (short) ByteOrder::bigEndianShort (data); - data += 2; - bytesRemaining -= 6; - data += bytesRemaining; - - return true; + const auto bytesRemaining = tryRead (data, remaining); + + if (! bytesRemaining.valid || bytesRemaining.value > remaining) + return {}; + + const auto optFileType = tryRead (data, remaining); + + if (! optFileType.valid || 2 < optFileType.value) + return {}; + + const auto optNumTracks = tryRead (data, remaining); + + if (! optNumTracks.valid || (optFileType.value == 0 && optNumTracks.value != 1)) + return {}; + + const auto optTimeFormat = tryRead (data, remaining); + + if (! optTimeFormat.valid) + return {}; + + HeaderDetails result; + + result.fileType = (short) optFileType.value; + result.timeFormat = (short) optTimeFormat.value; + result.numberOfTracks = (short) optNumTracks.value; + result.bytesRead = maxSize - remaining; + + return { result }; } static double convertTicksToSeconds (double time, @@ -149,11 +219,51 @@ namespace MidiFileHelpers } } } + + static MidiMessageSequence readTrack (const uint8* data, int size) + { + double time = 0; + uint8 lastStatusByte = 0; + + MidiMessageSequence result; + + while (size > 0) + { + const auto delay = MidiMessage::readVariableLengthValue (data, (int) size); + + if (! delay.isValid()) + break; + + data += delay.bytesUsed; + size -= delay.bytesUsed; + time += delay.value; + + if (size <= 0) + break; + + int messSize = 0; + const MidiMessage mm (data, size, messSize, lastStatusByte, time); + + if (messSize <= 0) + break; + + size -= messSize; + data += messSize; + + result.addEvent (mm); + + auto firstByte = *(mm.getRawData()); + + if ((firstByte & 0xf0) != 0xf0) + lastStatusByte = firstByte; + } + + return result; + } } //============================================================================== MidiFile::MidiFile() : timeFormat ((short) (unsigned short) 0xe728) {} -MidiFile::~MidiFile() {} MidiFile::MidiFile (const MidiFile& other) : timeFormat (other.timeFormat) { @@ -169,14 +279,14 @@ MidiFile& MidiFile::operator= (const MidiFile& other) } MidiFile::MidiFile (MidiFile&& other) - : tracks (static_cast&&> (other.tracks)), + : tracks (std::move (other.tracks)), timeFormat (other.timeFormat) { } MidiFile& MidiFile::operator= (MidiFile&& other) { - tracks = static_cast&&> (other.tracks); + tracks = std::move (other.tracks); timeFormat = other.timeFormat; return *this; } @@ -245,7 +355,9 @@ double MidiFile::getLastTimestamp() const } //============================================================================== -bool MidiFile::readFrom (InputStream& sourceStream) +bool MidiFile::readFrom (InputStream& sourceStream, + bool createMatchingNoteOffs, + int* fileType) { clear(); MemoryBlock data; @@ -253,77 +365,61 @@ bool MidiFile::readFrom (InputStream& sourceStream) const int maxSensibleMidiFileSize = 200 * 1024 * 1024; // (put a sanity-check on the file size, as midi files are generally small) - if (sourceStream.readIntoMemoryBlock (data, maxSensibleMidiFileSize)) - { - auto size = data.getSize(); - auto d = static_cast (data.getData()); - short fileType, expectedTracks; + if (! sourceStream.readIntoMemoryBlock (data, maxSensibleMidiFileSize)) + return false; - if (size > 16 && MidiFileHelpers::parseMidiHeader (d, timeFormat, fileType, expectedTracks)) - { - size -= (size_t) (d - static_cast (data.getData())); + auto size = data.getSize(); + auto d = static_cast (data.getData()); - int track = 0; + const auto optHeader = MidiFileHelpers::parseMidiHeader (d, size); - while (size > 0 && track < expectedTracks) - { - auto chunkType = (int) ByteOrder::bigEndianInt (d); - d += 4; - auto chunkSize = (int) ByteOrder::bigEndianInt (d); - d += 4; + if (! optHeader.valid) + return false; - if (chunkSize <= 0) - break; + const auto header = optHeader.value; + timeFormat = header.timeFormat; - if (chunkType == (int) ByteOrder::bigEndianInt ("MTrk")) - readNextTrack (d, chunkSize); + d += header.bytesRead; + size -= (size_t) header.bytesRead; - size -= (size_t) chunkSize + 8; - d += chunkSize; - ++track; - } + for (int track = 0; track < header.numberOfTracks; ++track) + { + const auto optChunkType = MidiFileHelpers::tryRead (d, size); - return true; - } - } + if (! optChunkType.valid) + return false; - return false; -} + const auto optChunkSize = MidiFileHelpers::tryRead (d, size); -void MidiFile::readNextTrack (const uint8* data, int size) -{ - double time = 0; - uint8 lastStatusByte = 0; + if (! optChunkSize.valid) + return false; - MidiMessageSequence result; + const auto chunkSize = optChunkSize.value; - while (size > 0) - { - int bytesUsed; - auto delay = MidiMessage::readVariableLengthVal (data, bytesUsed); - data += bytesUsed; - size -= bytesUsed; - time += delay; + if (size < chunkSize) + return false; - int messSize = 0; - const MidiMessage mm (data, size, messSize, lastStatusByte, time); + if (optChunkType.value == ByteOrder::bigEndianInt ("MTrk")) + readNextTrack (d, (int) chunkSize, createMatchingNoteOffs); - if (messSize <= 0) - break; + size -= chunkSize; + d += chunkSize; + } - size -= messSize; - data += messSize; + const auto successful = (size == 0); - result.addEvent (mm); + if (successful && fileType != nullptr) + *fileType = header.fileType; - auto firstByte = *(mm.getRawData()); + return successful; +} - if ((firstByte & 0xf0) != 0xf0) - lastStatusByte = firstByte; - } +void MidiFile::readNextTrack (const uint8* data, int size, bool createMatchingNoteOffs) +{ + auto sequence = MidiFileHelpers::readTrack (data, size); // sort so that we put all the note-offs before note-ons that have the same time - std::stable_sort (result.list.begin(), result.list.end(), + std::stable_sort (sequence.list.begin(), sequence.list.end(), [] (const MidiMessageSequence::MidiEventHolder* a, const MidiMessageSequence::MidiEventHolder* b) { @@ -336,8 +432,10 @@ void MidiFile::readNextTrack (const uint8* data, int size) return a->message.isNoteOff() && b->message.isNoteOn(); }); - addTrack (result); - tracks.getLast()->updateMatchedPairs(); + if (createMatchingNoteOffs) + sequence.updateMatchedPairs(); + + addTrack (sequence); } //============================================================================== @@ -361,7 +459,7 @@ void MidiFile::convertTimestampTicksToSeconds() } //============================================================================== -bool MidiFile::writeTo (OutputStream& out, int midiFileType) +bool MidiFile::writeTo (OutputStream& out, int midiFileType) const { jassert (midiFileType >= 0 && midiFileType <= 2); @@ -379,7 +477,7 @@ bool MidiFile::writeTo (OutputStream& out, int midiFileType) return true; } -bool MidiFile::writeTrack (OutputStream& mainOut, const MidiMessageSequence& ms) +bool MidiFile::writeTrack (OutputStream& mainOut, const MidiMessageSequence& ms) const { MemoryOutputStream out; @@ -440,4 +538,269 @@ bool MidiFile::writeTrack (OutputStream& mainOut, const MidiMessageSequence& ms) return true; } +//============================================================================== +//============================================================================== +#if JUCE_UNIT_TESTS + +struct MidiFileTest : public UnitTest +{ + MidiFileTest() + : UnitTest ("MidiFile", UnitTestCategories::midi) + {} + + void runTest() override + { + beginTest ("ReadTrack respects running status"); + { + const auto sequence = parseSequence ([] (OutputStream& os) + { + MidiFileHelpers::writeVariableLengthInt (os, 100); + writeBytes (os, { 0x90, 0x40, 0x40 }); + MidiFileHelpers::writeVariableLengthInt (os, 200); + writeBytes (os, { 0x40, 0x40 }); + MidiFileHelpers::writeVariableLengthInt (os, 300); + writeBytes (os, { 0xff, 0x2f, 0x00 }); + }); + + expectEquals (sequence.getNumEvents(), 3); + expect (sequence.getEventPointer (0)->message.isNoteOn()); + expect (sequence.getEventPointer (1)->message.isNoteOn()); + expect (sequence.getEventPointer (2)->message.isEndOfTrackMetaEvent()); + } + + beginTest ("ReadTrack returns available messages if input is truncated"); + { + { + const auto sequence = parseSequence ([] (OutputStream& os) + { + // Incomplete delta time + writeBytes (os, { 0xff }); + }); + + expectEquals (sequence.getNumEvents(), 0); + } + + { + const auto sequence = parseSequence ([] (OutputStream& os) + { + // Complete delta with no following event + MidiFileHelpers::writeVariableLengthInt (os, 0xffff); + }); + + expectEquals (sequence.getNumEvents(), 0); + } + + { + const auto sequence = parseSequence ([] (OutputStream& os) + { + // Complete delta with malformed following event + MidiFileHelpers::writeVariableLengthInt (os, 0xffff); + writeBytes (os, { 0x90, 0x40 }); + }); + + expectEquals (sequence.getNumEvents(), 1); + expect (sequence.getEventPointer (0)->message.isNoteOff()); + expectEquals (sequence.getEventPointer (0)->message.getNoteNumber(), 0x40); + expectEquals (sequence.getEventPointer (0)->message.getVelocity(), (uint8) 0x00); + } + } + + beginTest ("Header parsing works"); + { + { + // No data + const auto header = parseHeader ([] (OutputStream&) {}); + expect (! header.valid); + } + + { + // Invalid initial byte + const auto header = parseHeader ([] (OutputStream& os) + { + writeBytes (os, { 0xff }); + }); + + expect (! header.valid); + } + + { + // Type block, but no header data + const auto header = parseHeader ([] (OutputStream& os) + { + writeBytes (os, { 'M', 'T', 'h', 'd' }); + }); + + expect (! header.valid); + } + + { + // We (ll-formed header, but track type is 0 and channels != 1 + const auto header = parseHeader ([] (OutputStream& os) + { + writeBytes (os, { 'M', 'T', 'h', 'd', 0, 0, 0, 6, 0, 0, 0, 16, 0, 1 }); + }); + + expect (! header.valid); + } + + { + // Well-formed header, but track type is 5 + const auto header = parseHeader ([] (OutputStream& os) + { + writeBytes (os, { 'M', 'T', 'h', 'd', 0, 0, 0, 6, 0, 5, 0, 16, 0, 1 }); + }); + + expect (! header.valid); + } + + { + // Well-formed header + const auto header = parseHeader ([] (OutputStream& os) + { + writeBytes (os, { 'M', 'T', 'h', 'd', 0, 0, 0, 6, 0, 1, 0, 16, 0, 1 }); + }); + + expect (header.valid); + + expectEquals (header.value.fileType, (short) 1); + expectEquals (header.value.numberOfTracks, (short) 16); + expectEquals (header.value.timeFormat, (short) 1); + expectEquals ((int) header.value.bytesRead, 14); + } + } + + beginTest ("Read from stream"); + { + { + // Empty input + const auto file = parseFile ([] (OutputStream&) {}); + expect (! file.valid); + } + + { + // Malformed header + const auto file = parseFile ([] (OutputStream& os) + { + writeBytes (os, { 'M', 'T', 'h', 'd' }); + }); + + expect (! file.valid); + } + + { + // Header, no channels + const auto file = parseFile ([] (OutputStream& os) + { + writeBytes (os, { 'M', 'T', 'h', 'd', 0, 0, 0, 6, 0, 1, 0, 0, 0, 1 }); + }); + + expect (file.valid); + expectEquals (file.value.getNumTracks(), 0); + } + + { + // Header, one malformed channel + const auto file = parseFile ([] (OutputStream& os) + { + writeBytes (os, { 'M', 'T', 'h', 'd', 0, 0, 0, 6, 0, 1, 0, 1, 0, 1 }); + writeBytes (os, { 'M', 'T', 'r', '?' }); + }); + + expect (! file.valid); + } + + { + // Header, one channel with malformed message + const auto file = parseFile ([] (OutputStream& os) + { + writeBytes (os, { 'M', 'T', 'h', 'd', 0, 0, 0, 6, 0, 1, 0, 1, 0, 1 }); + writeBytes (os, { 'M', 'T', 'r', 'k', 0, 0, 0, 1, 0xff }); + }); + + expect (file.valid); + expectEquals (file.value.getNumTracks(), 1); + expectEquals (file.value.getTrack (0)->getNumEvents(), 0); + } + + { + // Header, one channel with incorrect length message + const auto file = parseFile ([] (OutputStream& os) + { + writeBytes (os, { 'M', 'T', 'h', 'd', 0, 0, 0, 6, 0, 1, 0, 1, 0, 1 }); + writeBytes (os, { 'M', 'T', 'r', 'k', 0x0f, 0, 0, 0, 0xff }); + }); + + expect (! file.valid); + } + + { + // Header, one channel, all well-formed + const auto file = parseFile ([] (OutputStream& os) + { + writeBytes (os, { 'M', 'T', 'h', 'd', 0, 0, 0, 6, 0, 1, 0, 1, 0, 1 }); + writeBytes (os, { 'M', 'T', 'r', 'k', 0, 0, 0, 4 }); + + MidiFileHelpers::writeVariableLengthInt (os, 0x0f); + writeBytes (os, { 0x80, 0x00, 0x00 }); + }); + + expect (file.valid); + expectEquals (file.value.getNumTracks(), 1); + + auto& track = *file.value.getTrack (0); + expectEquals (track.getNumEvents(), 1); + expect (track.getEventPointer (0)->message.isNoteOff()); + expectEquals (track.getEventPointer (0)->message.getTimeStamp(), (double) 0x0f); + } + } + } + + template + static MidiMessageSequence parseSequence (Fn&& fn) + { + MemoryOutputStream os; + fn (os); + + return MidiFileHelpers::readTrack (reinterpret_cast (os.getData()), + (int) os.getDataSize()); + } + + template + static MidiFileHelpers::Optional parseHeader (Fn&& fn) + { + MemoryOutputStream os; + fn (os); + + return MidiFileHelpers::parseMidiHeader (reinterpret_cast (os.getData()), + os.getDataSize()); + } + + template + static MidiFileHelpers::Optional parseFile (Fn&& fn) + { + MemoryOutputStream os; + fn (os); + + MemoryInputStream is (os.getData(), os.getDataSize(), false); + MidiFile mf; + + int fileType = 0; + + if (mf.readFrom (is, true, &fileType)) + return mf; + + return {}; + } + + static void writeBytes (OutputStream& os, const std::vector& bytes) + { + for (const auto& byte : bytes) + os.writeByte ((char) byte); + } +}; + +static MidiFileTest midiFileTests; + +#endif + } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiFile.h b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiFile.h index 2226b320..40662c26 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiFile.h +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiFile.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -45,9 +45,6 @@ class JUCE_API MidiFile /** Creates an empty MidiFile object. */ MidiFile(); - /** Destructor. */ - ~MidiFile(); - /** Creates a copy of another MidiFile. */ MidiFile (const MidiFile&); @@ -136,7 +133,7 @@ class JUCE_API MidiFile */ void findAllTimeSigEvents (MidiMessageSequence& timeSigEvents) const; - /** Makes a list of all the time-signature meta-events from all tracks in the midi file. + /** Makes a list of all the key-signature meta-events from all tracks in the midi file. @param keySigEvents a list to which all the events will be added */ void findAllKeySigEvents (MidiMessageSequence& keySigEvents) const; @@ -156,16 +153,29 @@ class JUCE_API MidiFile terms of midi ticks. To convert them to seconds, use the convertTimestampTicksToSeconds() method. + @param sourceStream the source stream + @param createMatchingNoteOffs if true, any missing note-offs for previous note-ons will + be automatically added at the end of the file by calling + MidiMessageSequence::updateMatchedPairs on each track. + @param midiFileType if not nullptr, the integer at this address will be set + to 0, 1, or 2 depending on the type of the midi file + @returns true if the stream was read successfully */ - bool readFrom (InputStream& sourceStream); + bool readFrom (InputStream& sourceStream, + bool createMatchingNoteOffs = true, + int* midiFileType = nullptr); /** Writes the midi tracks as a standard midi file. The midiFileType value is written as the file's format type, which can be 0, 1 or 2 - see the midi file spec for more info about that. + + @param destStream the destination stream + @param midiFileType the type of midi file + @returns true if the operation succeeded. */ - bool writeTo (OutputStream& destStream, int midiFileType = 1); + bool writeTo (OutputStream& destStream, int midiFileType = 1) const; /** Converts the timestamp of all the midi events from midi ticks to seconds. @@ -174,14 +184,13 @@ class JUCE_API MidiFile */ void convertTimestampTicksToSeconds(); - private: //============================================================================== OwnedArray tracks; short timeFormat; - void readNextTrack (const uint8*, int size); - bool writeTrack (OutputStream&, const MidiMessageSequence&); + void readNextTrack (const uint8*, int, bool); + bool writeTrack (OutputStream&, const MidiMessageSequence&) const; JUCE_LEAK_DETECTOR (MidiFile) }; diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiKeyboardState.cpp b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiKeyboardState.cpp index 68b8db06..2a34076d 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiKeyboardState.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiKeyboardState.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -28,10 +28,6 @@ MidiKeyboardState::MidiKeyboardState() zerostruct (noteStates); } -MidiKeyboardState::~MidiKeyboardState() -{ -} - //============================================================================== void MidiKeyboardState::reset() { @@ -42,7 +38,7 @@ void MidiKeyboardState::reset() bool MidiKeyboardState::isNoteOn (const int midiChannel, const int n) const noexcept { - jassert (midiChannel >= 0 && midiChannel <= 16); + jassert (midiChannel > 0 && midiChannel <= 16); return isPositiveAndBelow (n, 128) && (noteStates[n] & (1 << (midiChannel - 1))) != 0; @@ -56,7 +52,7 @@ bool MidiKeyboardState::isNoteOnForChannels (const int midiChannelMask, const in void MidiKeyboardState::noteOn (const int midiChannel, const int midiNoteNumber, const float velocity) { - jassert (midiChannel >= 0 && midiChannel <= 16); + jassert (midiChannel > 0 && midiChannel <= 16); jassert (isPositiveAndBelow (midiNoteNumber, 128)); const ScopedLock sl (lock); @@ -75,10 +71,8 @@ void MidiKeyboardState::noteOnInternal (const int midiChannel, const int midiNo { if (isPositiveAndBelow (midiNoteNumber, 128)) { - noteStates [midiNoteNumber] |= (1 << (midiChannel - 1)); - - for (int i = listeners.size(); --i >= 0;) - listeners.getUnchecked(i)->handleNoteOn (this, midiChannel, midiNoteNumber, velocity); + noteStates[midiNoteNumber] = static_cast (noteStates[midiNoteNumber] | (1 << (midiChannel - 1))); + listeners.call ([&] (Listener& l) { l.handleNoteOn (this, midiChannel, midiNoteNumber, velocity); }); } } @@ -100,10 +94,8 @@ void MidiKeyboardState::noteOffInternal (const int midiChannel, const int midiN { if (isNoteOn (midiChannel, midiNoteNumber)) { - noteStates [midiNoteNumber] &= ~(1 << (midiChannel - 1)); - - for (int i = listeners.size(); --i >= 0;) - listeners.getUnchecked(i)->handleNoteOff (this, midiChannel, midiNoteNumber, velocity); + noteStates[midiNoteNumber] = static_cast (noteStates[midiNoteNumber] & ~(1 << (midiChannel - 1))); + listeners.call ([&] (Listener& l) { l.handleNoteOff (this, midiChannel, midiNoteNumber, velocity); }); } } @@ -145,25 +137,20 @@ void MidiKeyboardState::processNextMidiBuffer (MidiBuffer& buffer, const int numSamples, const bool injectIndirectEvents) { - MidiBuffer::Iterator i (buffer); - MidiMessage message; - int time; - const ScopedLock sl (lock); - while (i.getNextEvent (message, time)) - processNextMidiEvent (message); + for (const auto metadata : buffer) + processNextMidiEvent (metadata.getMessage()); if (injectIndirectEvents) { - MidiBuffer::Iterator i2 (eventsToAdd); const int firstEventToAdd = eventsToAdd.getFirstEventTime(); const double scaleFactor = numSamples / (double) (eventsToAdd.getLastEventTime() + 1 - firstEventToAdd); - while (i2.getNextEvent (message, time)) + for (const auto metadata : eventsToAdd) { - const int pos = jlimit (0, numSamples - 1, roundToInt ((time - firstEventToAdd) * scaleFactor)); - buffer.addEvent (message, startSample + pos); + const auto pos = jlimit (0, numSamples - 1, roundToInt ((metadata.samplePosition - firstEventToAdd) * scaleFactor)); + buffer.addEvent (metadata.getMessage(), startSample + pos); } } @@ -171,16 +158,16 @@ void MidiKeyboardState::processNextMidiBuffer (MidiBuffer& buffer, } //============================================================================== -void MidiKeyboardState::addListener (MidiKeyboardStateListener* const listener) +void MidiKeyboardState::addListener (Listener* listener) { const ScopedLock sl (lock); - listeners.addIfNotAlreadyThere (listener); + listeners.add (listener); } -void MidiKeyboardState::removeListener (MidiKeyboardStateListener* const listener) +void MidiKeyboardState::removeListener (Listener* listener) { const ScopedLock sl (lock); - listeners.removeFirstMatchingValue (listener); + listeners.remove (listener); } } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiKeyboardState.h b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiKeyboardState.h index ddbbe2db..35c46fa4 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiKeyboardState.h +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiKeyboardState.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -23,57 +23,12 @@ namespace juce { -class MidiKeyboardState; - - -//============================================================================== -/** - Receives events from a MidiKeyboardState object. - - @see MidiKeyboardState - - @tags{Audio} -*/ -class JUCE_API MidiKeyboardStateListener -{ -public: - //============================================================================== - MidiKeyboardStateListener() noexcept {} - virtual ~MidiKeyboardStateListener() {} - - //============================================================================== - /** Called when one of the MidiKeyboardState's keys is pressed. - - This will be called synchronously when the state is either processing a - buffer in its MidiKeyboardState::processNextMidiBuffer() method, or - when a note is being played with its MidiKeyboardState::noteOn() method. - - Note that this callback could happen from an audio callback thread, so be - careful not to block, and avoid any UI activity in the callback. - */ - virtual void handleNoteOn (MidiKeyboardState* source, - int midiChannel, int midiNoteNumber, float velocity) = 0; - - /** Called when one of the MidiKeyboardState's keys is released. - - This will be called synchronously when the state is either processing a - buffer in its MidiKeyboardState::processNextMidiBuffer() method, or - when a note is being played with its MidiKeyboardState::noteOff() method. - - Note that this callback could happen from an audio callback thread, so be - careful not to block, and avoid any UI activity in the callback. - */ - virtual void handleNoteOff (MidiKeyboardState* source, - int midiChannel, int midiNoteNumber, float velocity) = 0; -}; - - //============================================================================== /** Represents a piano keyboard, keeping track of which keys are currently pressed. This object can parse a stream of midi events, using them to update its idea - of which keys are pressed for each individiual midi channel. + of which keys are pressed for each individual midi channel. When keys go up or down, it can broadcast these events to listener objects. @@ -88,7 +43,6 @@ class JUCE_API MidiKeyboardState public: //============================================================================== MidiKeyboardState(); - ~MidiKeyboardState(); //============================================================================== /** Resets the state of the object. @@ -135,7 +89,7 @@ class JUCE_API MidiKeyboardState It will also trigger a synchronous callback to the listeners to tell them that the key has gone up. - But if the note isn't acutally down for the given channel, this method will in fact do nothing. + But if the note isn't actually down for the given channel, this method will in fact do nothing. */ void noteOff (int midiChannel, int midiNoteNumber, float velocity); @@ -180,27 +134,62 @@ class JUCE_API MidiKeyboardState bool injectIndirectEvents); //============================================================================== + /** Receives events from a MidiKeyboardState object. */ + class JUCE_API Listener + { + public: + //============================================================================== + virtual ~Listener() = default; + + //============================================================================== + /** Called when one of the MidiKeyboardState's keys is pressed. + + This will be called synchronously when the state is either processing a + buffer in its MidiKeyboardState::processNextMidiBuffer() method, or + when a note is being played with its MidiKeyboardState::noteOn() method. + + Note that this callback could happen from an audio callback thread, so be + careful not to block, and avoid any UI activity in the callback. + */ + virtual void handleNoteOn (MidiKeyboardState* source, + int midiChannel, int midiNoteNumber, float velocity) = 0; + + /** Called when one of the MidiKeyboardState's keys is released. + + This will be called synchronously when the state is either processing a + buffer in its MidiKeyboardState::processNextMidiBuffer() method, or + when a note is being played with its MidiKeyboardState::noteOff() method. + + Note that this callback could happen from an audio callback thread, so be + careful not to block, and avoid any UI activity in the callback. + */ + virtual void handleNoteOff (MidiKeyboardState* source, + int midiChannel, int midiNoteNumber, float velocity) = 0; + }; + /** Registers a listener for callbacks when keys go up or down. @see removeListener */ - void addListener (MidiKeyboardStateListener* listener); + void addListener (Listener* listener); /** Deregisters a listener. @see addListener */ - void removeListener (MidiKeyboardStateListener* listener); + void removeListener (Listener* listener); private: //============================================================================== CriticalSection lock; - uint16 noteStates [128]; + std::atomic noteStates[128]; MidiBuffer eventsToAdd; - Array listeners; + ListenerList listeners; - void noteOnInternal (int midiChannel, int midiNoteNumber, float velocity); + void noteOnInternal (int midiChannel, int midiNoteNumber, float velocity); void noteOffInternal (int midiChannel, int midiNoteNumber, float velocity); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiKeyboardState) }; +using MidiKeyboardStateListener = MidiKeyboardState::Listener; + } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.cpp b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.cpp index d1ad9505..1732ae91 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -57,6 +57,31 @@ uint16 MidiMessage::pitchbendToPitchwheelPos (const float pitchbend, } //============================================================================== +MidiMessage::VariableLengthValue MidiMessage::readVariableLengthValue (const uint8* data, int maxBytesToUse) noexcept +{ + uint32 v = 0; + + // The largest allowable variable-length value is 0x0f'ff'ff'ff which is + // represented by the 4-byte stream 0xff 0xff 0xff 0x7f. + // Longer bytestreams risk overflowing a 32-bit signed int. + const auto limit = jmin (maxBytesToUse, 4); + + for (int numBytesUsed = 0; numBytesUsed < limit; ++numBytesUsed) + { + const auto i = data[numBytesUsed]; + v = (v << 7) + (i & 0x7f); + + if (! (i & 0x80)) + return { (int) v, numBytesUsed + 1 }; + } + + // If this is hit, the input was malformed. Either there were not enough + // bytes of input to construct a full value, or no terminating byte was + // found. This implementation only supports variable-length values of up + // to four bytes. + return {}; +} + int MidiMessage::readVariableLengthVal (const uint8* data, int& numBytesUsed) noexcept { numBytesUsed = 0; @@ -224,9 +249,8 @@ MidiMessage::MidiMessage (const void* srcData, int sz, int& numBytesUsed, const } else if (byte == 0xff) { - int n; - const int bytesLeft = readVariableLengthVal (src + 1, n); - size = jmin (sz + 1, n + 2 + bytesLeft); + const auto bytesLeft = readVariableLengthValue (src + 1, sz - 1); + size = jmin (sz + 1, bytesLeft.bytesUsed + 2 + bytesLeft.value); auto dest = allocateSpace (size); *dest = (uint8) byte; @@ -263,11 +287,14 @@ MidiMessage& MidiMessage::operator= (const MidiMessage& other) { if (other.isHeapAllocated()) { - if (isHeapAllocated()) - packedData.allocatedData = static_cast (std::realloc (packedData.allocatedData, (size_t) other.size)); - else - packedData.allocatedData = static_cast (std::malloc ((size_t) other.size)); + auto* newStorage = static_cast (isHeapAllocated() + ? std::realloc (packedData.allocatedData, (size_t) other.size) + : std::malloc ((size_t) other.size)); + if (newStorage == nullptr) + throw std::bad_alloc{}; // The midi message has not been adjusted at this point + + packedData.allocatedData = newStorage; memcpy (packedData.allocatedData, other.packedData.allocatedData, (size_t) other.size); } else @@ -675,7 +702,7 @@ bool MidiMessage::isActiveSense() const noexcept { return *getRawData() == 0x int MidiMessage::getMetaEventType() const noexcept { auto data = getRawData(); - return *data != 0xff ? -1 : data[1]; + return (size < 2 || *data != 0xff) ? -1 : data[1]; } int MidiMessage::getMetaEventLength() const noexcept @@ -684,8 +711,8 @@ int MidiMessage::getMetaEventLength() const noexcept if (*data == 0xff) { - int n; - return jmin (size - 2, readVariableLengthVal (data + 2, n)); + const auto var = readVariableLengthValue (data + 2, size - 2); + return jmax (0, jmin (size - 2 - var.bytesUsed, var.value)); } return 0; @@ -695,10 +722,9 @@ const uint8* MidiMessage::getMetaEventData() const noexcept { jassert (isMetaEvent()); - int n; auto d = getRawData() + 2; - readVariableLengthVal (d, n); - return d + n; + const auto var = readVariableLengthValue (d, size - 2); + return d + var.bytesUsed; } bool MidiMessage::isTrackMetaEvent() const noexcept { return getMetaEventType() == 0; } @@ -1134,4 +1160,172 @@ const char* MidiMessage::getControllerName (const int n) return isPositiveAndBelow (n, numElementsInArray (names)) ? names[n] : nullptr; } +//============================================================================== +//============================================================================== +#if JUCE_UNIT_TESTS + +struct MidiMessageTest : public UnitTest +{ + MidiMessageTest() + : UnitTest ("MidiMessage", UnitTestCategories::midi) + {} + + void runTest() override + { + using std::begin; + using std::end; + + beginTest ("ReadVariableLengthValue should return valid, backward-compatible results"); + { + const std::vector inputs[] + { + { 0x00 }, + { 0x40 }, + { 0x7f }, + { 0x81, 0x00 }, + { 0xc0, 0x00 }, + { 0xff, 0x7f }, + { 0x81, 0x80, 0x00 }, + { 0xc0, 0x80, 0x00 }, + { 0xff, 0xff, 0x7f }, + { 0x81, 0x80, 0x80, 0x00 }, + { 0xc0, 0x80, 0x80, 0x00 }, + { 0xff, 0xff, 0xff, 0x7f } + }; + + const int outputs[] + { + 0x00, + 0x40, + 0x7f, + 0x80, + 0x2000, + 0x3fff, + 0x4000, + 0x100000, + 0x1fffff, + 0x200000, + 0x8000000, + 0xfffffff, + }; + + expectEquals (std::distance (begin (inputs), end (inputs)), + std::distance (begin (outputs), end (outputs))); + + size_t index = 0; + + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") + JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996) + + for (const auto& input : inputs) + { + auto copy = input; + + while (copy.size() < 16) + copy.push_back (0); + + const auto result = MidiMessage::readVariableLengthValue (copy.data(), + (int) copy.size()); + + expect (result.isValid()); + expectEquals (result.value, outputs[index]); + expectEquals (result.bytesUsed, (int) inputs[index].size()); + + int legacyNumUsed = 0; + const auto legacyResult = MidiMessage::readVariableLengthVal (copy.data(), + legacyNumUsed); + + expectEquals (result.value, legacyResult); + expectEquals (result.bytesUsed, legacyNumUsed); + + ++index; + } + + JUCE_END_IGNORE_WARNINGS_GCC_LIKE + JUCE_END_IGNORE_WARNINGS_MSVC + } + + beginTest ("ReadVariableLengthVal should return 0 if input is truncated"); + { + for (size_t i = 0; i != 16; ++i) + { + std::vector input; + input.resize (i, 0xFF); + + const auto result = MidiMessage::readVariableLengthValue (input.data(), + (int) input.size()); + + expect (! result.isValid()); + expectEquals (result.value, 0); + expectEquals (result.bytesUsed, 0); + } + } + + const std::vector metaEvents[] + { + // Format is 0xff, followed by a 'kind' byte, followed by a variable-length + // 'data-length' value, followed by that many data bytes + { 0xff, 0x00, 0x02, 0x00, 0x00 }, // Sequence number + { 0xff, 0x01, 0x00 }, // Text event + { 0xff, 0x02, 0x00 }, // Copyright notice + { 0xff, 0x03, 0x00 }, // Track name + { 0xff, 0x04, 0x00 }, // Instrument name + { 0xff, 0x05, 0x00 }, // Lyric + { 0xff, 0x06, 0x00 }, // Marker + { 0xff, 0x07, 0x00 }, // Cue point + { 0xff, 0x20, 0x01, 0x00 }, // Channel prefix + { 0xff, 0x2f, 0x00 }, // End of track + { 0xff, 0x51, 0x03, 0x01, 0x02, 0x03 }, // Set tempo + { 0xff, 0x54, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05 }, // SMPTE offset + { 0xff, 0x58, 0x04, 0x01, 0x02, 0x03, 0x04 }, // Time signature + { 0xff, 0x59, 0x02, 0x01, 0x02 }, // Key signature + { 0xff, 0x7f, 0x00 }, // Sequencer-specific + }; + + beginTest ("MidiMessage data constructor works for well-formed meta-events"); + { + const auto status = (uint8) 0x90; + + for (const auto& input : metaEvents) + { + int bytesUsed = 0; + const MidiMessage msg (input.data(), (int) input.size(), bytesUsed, status); + + expect (msg.isMetaEvent()); + expectEquals (msg.getMetaEventLength(), (int) input.size() - 3); + expectEquals (msg.getMetaEventType(), (int) input[1]); + } + } + + beginTest ("MidiMessage data constructor works for malformed meta-events"); + { + const auto status = (uint8) 0x90; + + const auto runTest = [&] (const std::vector& input) + { + int bytesUsed = 0; + const MidiMessage msg (input.data(), (int) input.size(), bytesUsed, status); + + expect (msg.isMetaEvent()); + expectEquals (msg.getMetaEventLength(), jmax (0, (int) input.size() - 3)); + expectEquals (msg.getMetaEventType(), input.size() >= 2 ? input[1] : -1); + }; + + runTest ({ 0xff }); + + for (const auto& input : metaEvents) + { + auto copy = input; + copy[2] = 0x40; // Set the size of the message to more bytes than are present + + runTest (copy); + } + } + } +}; + +static MidiMessageTest midiMessageTests; + +#endif + } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.h b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.h index bc766962..0384f553 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.h +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -83,26 +83,27 @@ class JUCE_API MidiMessage complete message, and will return the number of bytes it used. This lets you read a sequence of midi messages from a file or stream. - @param data the data to read from - @param maxBytesToUse the maximum number of bytes it's allowed to read - @param numBytesUsed returns the number of bytes that were actually needed - @param lastStatusByte in a sequence of midi messages, the initial byte - can be dropped from a message if it's the same as the - first byte of the previous message, so this lets you - supply the byte to use if the first byte of the message - has in fact been dropped. - @param timeStamp the time to give the midi message - this value doesn't - use any particular units, so will be application-specific + @param data the data to read from + @param maxBytesToUse the maximum number of bytes it's allowed to read + @param numBytesUsed returns the number of bytes that were actually needed + @param lastStatusByte in a sequence of midi messages, the initial byte + can be dropped from a message if it's the same as the + first byte of the previous message, so this lets you + supply the byte to use if the first byte of the message + has in fact been dropped. + @param timeStamp the time to give the midi message - this value doesn't + use any particular units, so will be application-specific @param sysexHasEmbeddedLength when reading sysexes, this flag indicates whether - to expect the data to begin with a variable-length field - indicating its size + to expect the data to begin with a variable-length + field indicating its size */ MidiMessage (const void* data, int maxBytesToUse, int& numBytesUsed, uint8 lastStatusByte, double timeStamp = 0, bool sysexHasEmbeddedLength = true); - /** Creates an active-sense message. + /** Creates an empty sysex message. + Since the MidiMessage has to contain a valid message, this default constructor just initialises it with an empty sysex message. */ @@ -401,7 +402,7 @@ class JUCE_API MidiMessage /** Returns true if the message is an aftertouch event. For aftertouch events, use the getNoteNumber() method to find out the key - that it applies to, and getAftertouchValue() to find out the amount. Use + that it applies to, and getAfterTouchValue() to find out the amount. Use getChannel() to find out the channel. @see getAftertouchValue, getNoteNumber @@ -856,13 +857,46 @@ class JUCE_API MidiMessage //============================================================================== + #ifndef DOXYGEN /** Reads a midi variable-length integer. - @param data the data to read the number from - @param numBytesUsed on return, this will be set to the number of bytes that were read + The `data` argument indicates the data to read the number from, + and `numBytesUsed` is used as an out-parameter to indicate the number + of bytes that were read. + */ + [[deprecated ("This signature has been deprecated in favour of the safer readVariableLengthValue.")]] + static int readVariableLengthVal (const uint8* data, int& numBytesUsed) noexcept; + #endif + + /** Holds information about a variable-length value which was parsed + from a stream of bytes. + + A valid value requires that `bytesUsed` is greater than 0. */ - static int readVariableLengthVal (const uint8* data, - int& numBytesUsed) noexcept; + struct VariableLengthValue + { + VariableLengthValue() = default; + + VariableLengthValue (int valueIn, int bytesUsedIn) + : value (valueIn), bytesUsed (bytesUsedIn) {} + + bool isValid() const noexcept { return bytesUsed > 0; } + + int value = 0; + int bytesUsed = 0; + }; + + /** Reads a midi variable-length integer, with protection against buffer overflow. + + @param data the data to read the number from + @param maxBytesToUse the number of bytes in the region following `data` + @returns a struct containing the parsed value, and the number + of bytes that were read. If parsing fails, both the + `value` and `bytesUsed` fields will be set to 0 and + `isValid()` will return false + */ + static VariableLengthValue readVariableLengthValue (const uint8* data, + int maxBytesToUse) noexcept; /** Based on the first byte of a short midi message, this uses a lookup table to return the message length (either 1, 2, or 3 bytes). diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp index 5113c16f..c9df3ee3 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -24,8 +24,7 @@ namespace juce { MidiMessageSequence::MidiEventHolder::MidiEventHolder (const MidiMessage& mm) : message (mm) {} -MidiMessageSequence::MidiEventHolder::MidiEventHolder (MidiMessage&& mm) : message (static_cast (mm)) {} -MidiMessageSequence::MidiEventHolder::~MidiEventHolder() {} +MidiMessageSequence::MidiEventHolder::MidiEventHolder (MidiMessage&& mm) : message (std::move (mm)) {} //============================================================================== MidiMessageSequence::MidiMessageSequence() @@ -35,7 +34,14 @@ MidiMessageSequence::MidiMessageSequence() MidiMessageSequence::MidiMessageSequence (const MidiMessageSequence& other) { list.addCopiesOf (other.list); - updateMatchedPairs(); + + for (int i = 0; i < list.size(); ++i) + { + auto noteOffIndex = other.getIndexOfMatchingKeyUp (i); + + if (noteOffIndex >= 0) + list.getUnchecked(i)->noteOffObject = list.getUnchecked (noteOffIndex); + } } MidiMessageSequence& MidiMessageSequence::operator= (const MidiMessageSequence& other) @@ -46,20 +52,16 @@ MidiMessageSequence& MidiMessageSequence::operator= (const MidiMessageSequence& } MidiMessageSequence::MidiMessageSequence (MidiMessageSequence&& other) noexcept - : list (static_cast&&> (other.list)) + : list (std::move (other.list)) { } MidiMessageSequence& MidiMessageSequence::operator= (MidiMessageSequence&& other) noexcept { - list = static_cast&&> (other.list); + list = std::move (other.list); return *this; } -MidiMessageSequence::~MidiMessageSequence() -{ -} - void MidiMessageSequence::swapWith (MidiMessageSequence& other) noexcept { list.swapWith (other.list); @@ -80,22 +82,33 @@ MidiMessageSequence::MidiEventHolder* MidiMessageSequence::getEventPointer (int return list[index]; } -MidiMessageSequence::MidiEventHolder** MidiMessageSequence::begin() const noexcept { return list.begin(); } -MidiMessageSequence::MidiEventHolder** MidiMessageSequence::end() const noexcept { return list.end(); } +MidiMessageSequence::MidiEventHolder** MidiMessageSequence::begin() noexcept { return list.begin(); } +MidiMessageSequence::MidiEventHolder* const* MidiMessageSequence::begin() const noexcept { return list.begin(); } +MidiMessageSequence::MidiEventHolder** MidiMessageSequence::end() noexcept { return list.end(); } +MidiMessageSequence::MidiEventHolder* const* MidiMessageSequence::end() const noexcept { return list.end(); } double MidiMessageSequence::getTimeOfMatchingKeyUp (int index) const noexcept { if (auto* meh = list[index]) - if (meh->noteOffObject != nullptr) - return meh->noteOffObject->message.getTimeStamp(); + if (auto* noteOff = meh->noteOffObject) + return noteOff->message.getTimeStamp(); - return 0.0; + return 0; } int MidiMessageSequence::getIndexOfMatchingKeyUp (int index) const noexcept { - if (auto* meh = list [index]) - return list.indexOf (meh->noteOffObject); + if (auto* meh = list[index]) + { + if (auto* noteOff = meh->noteOffObject) + { + for (int i = index; i < list.size(); ++i) + if (list.getUnchecked(i) == noteOff) + return i; + + jassertfalse; // we've somehow got a pointer to a note-off object that isn't in the sequence + } + } return -1; } @@ -108,8 +121,8 @@ int MidiMessageSequence::getIndexOf (const MidiEventHolder* event) const noexcep int MidiMessageSequence::getNextIndexAtTime (double timeStamp) const noexcept { auto numEvents = list.size(); - int i; + for (i = 0; i < numEvents; ++i) if (list.getUnchecked(i)->message.getTimeStamp() >= timeStamp) break; @@ -130,10 +143,10 @@ double MidiMessageSequence::getEndTime() const noexcept double MidiMessageSequence::getEventTime (const int index) const noexcept { - if (auto* meh = list [index]) + if (auto* meh = list[index]) return meh->message.getTimeStamp(); - return 0.0; + return 0; } //============================================================================== @@ -141,8 +154,8 @@ MidiMessageSequence::MidiEventHolder* MidiMessageSequence::addEvent (MidiEventHo { newEvent->message.addToTimeStamp (timeAdjustment); auto time = newEvent->message.getTimeStamp(); - int i; + for (i = list.size(); --i >= 0;) if (list.getUnchecked(i)->message.getTimeStamp() <= time) break; @@ -158,7 +171,7 @@ MidiMessageSequence::MidiEventHolder* MidiMessageSequence::addEvent (const MidiM MidiMessageSequence::MidiEventHolder* MidiMessageSequence::addEvent (MidiMessage&& newMessage, double timeAdjustment) { - return addEvent (new MidiEventHolder (static_cast (newMessage)), timeAdjustment); + return addEvent (new MidiEventHolder (std::move (newMessage)), timeAdjustment); } void MidiMessageSequence::deleteEvent (int index, bool deleteMatchingNoteUp) @@ -291,48 +304,192 @@ void MidiMessageSequence::deleteSysExMessages() } //============================================================================== -void MidiMessageSequence::createControllerUpdatesForTime (int channelNumber, double time, Array& dest) +class OptionalPitchWheel { - bool doneProg = false; - bool donePitchWheel = false; - bool doneControllers[128] = {}; + int value = 0; + bool valid = false; - for (int i = list.size(); --i >= 0;) +public: + void emit (int channel, Array& out) const + { + if (valid) + out.add (MidiMessage::pitchWheel (channel, value)); + } + + void set (int v) + { + value = v; + valid = true; + } +}; + +class OptionalControllerValues +{ + int values[128]; + +public: + OptionalControllerValues() { - auto& mm = list.getUnchecked(i)->message; + std::fill (std::begin (values), std::end (values), -1); + } - if (mm.isForChannel (channelNumber) && mm.getTimeStamp() <= time) + void emit (int channel, Array& out) const + { + for (auto it = std::begin (values); it != std::end (values); ++it) + if (*it != -1) + out.add (MidiMessage::controllerEvent (channel, (int) std::distance (std::begin (values), it), *it)); + } + + void set (int controller, int value) + { + values[controller] = value; + } +}; + +class OptionalProgramChange +{ + int value = -1, bankLSB = -1, bankMSB = -1; + +public: + void emit (int channel, double time, Array& out) const + { + if (value == -1) + return; + + if (bankLSB != -1 && bankMSB != -1) { - if (mm.isProgramChange() && ! doneProg) - { - doneProg = true; - dest.add (MidiMessage (mm, 0.0)); - } - else if (mm.isPitchWheel() && ! donePitchWheel) + out.add (MidiMessage::controllerEvent (channel, 0x00, bankMSB).withTimeStamp (time)); + out.add (MidiMessage::controllerEvent (channel, 0x20, bankLSB).withTimeStamp (time)); + } + + out.add (MidiMessage::programChange (channel, value).withTimeStamp (time)); + } + + // Returns true if this is a bank number change, and false otherwise. + bool trySetBank (int controller, int v) + { + switch (controller) + { + case 0x00: bankMSB = v; return true; + case 0x20: bankLSB = v; return true; + } + + return false; + } + + void setProgram (int v) { value = v; } +}; + +class ParameterNumberState +{ + enum class Kind { rpn, nrpn }; + + int newestRpnLsb = -1, newestRpnMsb = -1, newestNrpnLsb = -1, newestNrpnMsb = -1; + int lastSentLsb = -1, lastSentMsb = -1; + Kind lastSentKind = Kind::rpn, newestKind = Kind::rpn; + +public: + // If the effective parameter number has changed since the last time this function was called, + // this will emit the current parameter in full (MSB and LSB). + // This should be called before each data message (entry, increment, decrement: 0x06, 0x26, 0x60, 0x61) + // to ensure that the data message operates on the correct parameter number. + void sendIfNecessary (int channel, double time, Array& out) + { + const auto newestMsb = newestKind == Kind::rpn ? newestRpnMsb : newestNrpnMsb; + const auto newestLsb = newestKind == Kind::rpn ? newestRpnLsb : newestNrpnLsb; + + auto lastSent = std::tie (lastSentKind, lastSentMsb, lastSentLsb); + const auto newest = std::tie (newestKind, newestMsb, newestLsb); + + if (lastSent == newest || newestMsb == -1 || newestLsb == -1) + return; + + out.add (MidiMessage::controllerEvent (channel, newestKind == Kind::rpn ? 0x65 : 0x63, newestMsb).withTimeStamp (time)); + out.add (MidiMessage::controllerEvent (channel, newestKind == Kind::rpn ? 0x64 : 0x62, newestLsb).withTimeStamp (time)); + + lastSent = newest; + } + + // Returns true if this is a parameter number change, and false otherwise. + bool trySetProgramNumber (int controller, int value) + { + switch (controller) + { + case 0x65: newestRpnMsb = value; newestKind = Kind::rpn; return true; + case 0x64: newestRpnLsb = value; newestKind = Kind::rpn; return true; + case 0x63: newestNrpnMsb = value; newestKind = Kind::nrpn; return true; + case 0x62: newestNrpnLsb = value; newestKind = Kind::nrpn; return true; + } + + return false; + } +}; + +void MidiMessageSequence::createControllerUpdatesForTime (int channel, double time, Array& dest) +{ + OptionalProgramChange programChange; + OptionalControllerValues controllers; + OptionalPitchWheel pitchWheel; + ParameterNumberState parameterNumberState; + + for (const auto& item : list) + { + const auto& mm = item->message; + + if (! (mm.isForChannel (channel) && mm.getTimeStamp() <= time)) + continue; + + if (mm.isController()) + { + const auto num = mm.getControllerNumber(); + + if (parameterNumberState.trySetProgramNumber (num, mm.getControllerValue())) + continue; + + if (programChange.trySetBank (num, mm.getControllerValue())) + continue; + + constexpr int passthroughs[] { 0x06, 0x26, 0x60, 0x61 }; + + if (std::find (std::begin (passthroughs), std::end (passthroughs), num) != std::end (passthroughs)) { - donePitchWheel = true; - dest.add (MidiMessage (mm, 0.0)); + parameterNumberState.sendIfNecessary (channel, mm.getTimeStamp(), dest); + dest.add (mm); } - else if (mm.isController()) + else { - const int controllerNumber = mm.getControllerNumber(); - jassert (isPositiveAndBelow (controllerNumber, 128)); - - if (! doneControllers[controllerNumber]) - { - doneControllers[controllerNumber] = true; - dest.add (MidiMessage (mm, 0.0)); - } + controllers.set (num, mm.getControllerValue()); } } + else if (mm.isProgramChange()) + { + programChange.setProgram (mm.getProgramChangeNumber()); + } + else if (mm.isPitchWheel()) + { + pitchWheel.set (mm.getPitchWheelValue()); + } } + + pitchWheel.emit (channel, dest); + controllers.emit (channel, dest); + + // Also emits bank change messages if necessary. + programChange.emit (channel, time, dest); + + // Set the parameter number to its final state. + parameterNumberState.sendIfNecessary (channel, time, dest); } +//============================================================================== +//============================================================================== #if JUCE_UNIT_TESTS -struct MidiMessageSequenceTest : public juce::UnitTest +struct MidiMessageSequenceTest : public UnitTest { - MidiMessageSequenceTest() : juce::UnitTest ("MidiMessageSequence") {} + MidiMessageSequenceTest() + : UnitTest ("MidiMessageSequence", UnitTestCategories::midi) + {} void runTest() override { @@ -355,7 +512,7 @@ struct MidiMessageSequenceTest : public juce::UnitTest expectEquals (s.getIndexOfMatchingKeyUp (0), 2); expectEquals (s.getIndexOfMatchingKeyUp (1), 3); - beginTest ("Time & indeces"); + beginTest ("Time & indices"); expectEquals (s.getNextIndexAtTime (0.5), 1); expectEquals (s.getNextIndexAtTime (2.5), 2); expectEquals (s.getNextIndexAtTime (9.0), 4); @@ -379,6 +536,338 @@ struct MidiMessageSequenceTest : public juce::UnitTest expectEquals (s.getNumEvents(), 7); expectEquals (s.getIndexOfMatchingKeyUp (0), -1); // Truncated note, should be no note off expectEquals (s.getTimeOfMatchingKeyUp (1), 5.0); + + struct ControlValue { int control, value; }; + + struct DataEntry + { + int controllerBase, channel, parameter, value; + double time; + + std::array getControlValues() const + { + return { { { controllerBase + 1, (parameter >> 7) & 0x7f }, + { controllerBase + 0, (parameter >> 0) & 0x7f }, + { 0x06, (value >> 7) & 0x7f }, + { 0x26, (value >> 0) & 0x7f } } }; + } + + void addToSequence (MidiMessageSequence& s) const + { + for (const auto& pair : getControlValues()) + s.addEvent (MidiMessage::controllerEvent (channel, pair.control, pair.value), time); + } + + bool matches (const MidiMessage* begin, const MidiMessage* end) const + { + const auto isEqual = [this] (const ControlValue& cv, const MidiMessage& msg) + { + return msg.getTimeStamp() == time + && msg.isController() + && msg.getChannel() == channel + && msg.getControllerNumber() == cv.control + && msg.getControllerValue() == cv.value; + }; + + const auto pairs = getControlValues(); + return std::equal (pairs.begin(), pairs.end(), begin, end, isEqual); + } + }; + + const auto addNrpn = [&] (MidiMessageSequence& seq, int channel, int parameter, int value, double time = 0.0) + { + DataEntry { 0x62, channel, parameter, value, time }.addToSequence (seq); + }; + + const auto addRpn = [&] (MidiMessageSequence& seq, int channel, int parameter, int value, double time = 0.0) + { + DataEntry { 0x64, channel, parameter, value, time }.addToSequence (seq); + }; + + const auto checkNrpn = [&] (const MidiMessage* begin, const MidiMessage* end, int channel, int parameter, int value, double time = 0.0) + { + expect (DataEntry { 0x62, channel, parameter, value, time }.matches (begin, end)); + }; + + const auto checkRpn = [&] (const MidiMessage* begin, const MidiMessage* end, int channel, int parameter, int value, double time = 0.0) + { + expect (DataEntry { 0x64, channel, parameter, value, time }.matches (begin, end)); + }; + + beginTest ("createControllerUpdatesForTime should emit (N)RPN components in the correct order"); + { + const auto channel = 1; + const auto number = 200; + const auto value = 300; + + MidiMessageSequence sequence; + addNrpn (sequence, channel, number, value); + + Array m; + sequence.createControllerUpdatesForTime (channel, 1.0, m); + + checkNrpn (m.begin(), m.end(), channel, number, value); + } + + beginTest ("createControllerUpdatesForTime ignores (N)RPNs after the final requested time"); + { + const auto channel = 2; + const auto number = 123; + const auto value = 456; + + MidiMessageSequence sequence; + addRpn (sequence, channel, number, value, 0.5); + addRpn (sequence, channel, 111, 222, 1.5); + addRpn (sequence, channel, 333, 444, 2.5); + + Array m; + sequence.createControllerUpdatesForTime (channel, 1.0, m); + + checkRpn (m.begin(), std::next (m.begin(), 4), channel, number, value, 0.5); + } + + beginTest ("createControllerUpdatesForTime should emit separate (N)RPN messages when appropriate"); + { + const auto channel = 2; + const auto numberA = 1111; + const auto valueA = 9999; + + const auto numberB = 8888; + const auto valueB = 2222; + + const auto numberC = 7777; + const auto valueC = 3333; + + const auto numberD = 6666; + const auto valueD = 4444; + + const auto time = 0.5; + + MidiMessageSequence sequence; + addRpn (sequence, channel, numberA, valueA, time); + addRpn (sequence, channel, numberB, valueB, time); + addNrpn (sequence, channel, numberC, valueC, time); + addNrpn (sequence, channel, numberD, valueD, time); + + Array m; + sequence.createControllerUpdatesForTime (channel, time * 2, m); + + checkRpn (std::next (m.begin(), 0), std::next (m.begin(), 4), channel, numberA, valueA, time); + checkRpn (std::next (m.begin(), 4), std::next (m.begin(), 8), channel, numberB, valueB, time); + checkNrpn (std::next (m.begin(), 8), std::next (m.begin(), 12), channel, numberC, valueC, time); + checkNrpn (std::next (m.begin(), 12), std::next (m.begin(), 16), channel, numberD, valueD, time); + } + + beginTest ("createControllerUpdatesForTime correctly emits (N)RPN messages on multiple channels"); + { + struct Info { int channel, number, value; }; + + const Info infos[] { { 2, 1111, 9999 }, + { 8, 8888, 2222 }, + { 5, 7777, 3333 }, + { 1, 6666, 4444 } }; + + const auto time = 0.5; + + MidiMessageSequence sequence; + + for (const auto& info : infos) + addRpn (sequence, info.channel, info.number, info.value, time); + + for (const auto& info : infos) + { + Array m; + sequence.createControllerUpdatesForTime (info.channel, time * 2, m); + checkRpn (std::next (m.begin(), 0), std::next (m.begin(), 4), info.channel, info.number, info.value, time); + } + } + + const auto messagesAreEqual = [] (const MidiMessage& a, const MidiMessage& b) + { + return std::equal (a.getRawData(), a.getRawData() + a.getRawDataSize(), + b.getRawData(), b.getRawData() + b.getRawDataSize()); + }; + + beginTest ("createControllerUpdatesForTime sends bank select messages when the next program is in a new bank"); + { + MidiMessageSequence sequence; + + const auto time = 0.0; + const auto channel = 1; + + sequence.addEvent (MidiMessage::programChange (channel, 5), time); + + sequence.addEvent (MidiMessage::controllerEvent (channel, 0x00, 128), time); + sequence.addEvent (MidiMessage::controllerEvent (channel, 0x20, 64), time); + sequence.addEvent (MidiMessage::programChange (channel, 63), time); + + const Array finalEvents { MidiMessage::controllerEvent (channel, 0x00, 50), + MidiMessage::controllerEvent (channel, 0x20, 40), + MidiMessage::programChange (channel, 30) }; + + for (const auto& e : finalEvents) + sequence.addEvent (e); + + Array m; + sequence.createControllerUpdatesForTime (channel, 1.0, m); + + expect (std::equal (m.begin(), m.end(), finalEvents.begin(), finalEvents.end(), messagesAreEqual)); + } + + beginTest ("createControllerUpdatesForTime preserves all Data Increment and Data Decrement messages"); + { + MidiMessageSequence sequence; + + const auto time = 0.0; + const auto channel = 1; + + const Array messages { MidiMessage::controllerEvent (channel, 0x60, 0), + MidiMessage::controllerEvent (channel, 0x06, 100), + MidiMessage::controllerEvent (channel, 0x26, 50), + MidiMessage::controllerEvent (channel, 0x60, 10), + MidiMessage::controllerEvent (channel, 0x61, 10), + MidiMessage::controllerEvent (channel, 0x06, 20), + MidiMessage::controllerEvent (channel, 0x26, 30), + MidiMessage::controllerEvent (channel, 0x61, 10), + MidiMessage::controllerEvent (channel, 0x61, 20) }; + + for (const auto& m : messages) + sequence.addEvent (m, time); + + Array m; + sequence.createControllerUpdatesForTime (channel, 1.0, m); + + expect (std::equal (m.begin(), m.end(), messages.begin(), messages.end(), messagesAreEqual)); + } + + beginTest ("createControllerUpdatesForTime does not emit redundant parameter number changes"); + { + MidiMessageSequence sequence; + + const auto time = 0.0; + const auto channel = 1; + + const Array messages { MidiMessage::controllerEvent (channel, 0x65, 0), + MidiMessage::controllerEvent (channel, 0x64, 100), + MidiMessage::controllerEvent (channel, 0x63, 50), + MidiMessage::controllerEvent (channel, 0x62, 10), + MidiMessage::controllerEvent (channel, 0x06, 10) }; + + for (const auto& m : messages) + sequence.addEvent (m, time); + + Array m; + sequence.createControllerUpdatesForTime (channel, 1.0, m); + + const Array expected { MidiMessage::controllerEvent (channel, 0x63, 50), + MidiMessage::controllerEvent (channel, 0x62, 10), + MidiMessage::controllerEvent (channel, 0x06, 10) }; + + expect (std::equal (m.begin(), m.end(), expected.begin(), expected.end(), messagesAreEqual)); + } + + beginTest ("createControllerUpdatesForTime sets parameter number correctly at end of sequence"); + { + MidiMessageSequence sequence; + + const auto time = 0.0; + const auto channel = 1; + + const Array messages { MidiMessage::controllerEvent (channel, 0x65, 0), + MidiMessage::controllerEvent (channel, 0x64, 100), + MidiMessage::controllerEvent (channel, 0x63, 50), + MidiMessage::controllerEvent (channel, 0x62, 10), + MidiMessage::controllerEvent (channel, 0x06, 10), + MidiMessage::controllerEvent (channel, 0x64, 5) }; + + for (const auto& m : messages) + sequence.addEvent (m, time); + + const auto finalTime = 1.0; + + Array m; + sequence.createControllerUpdatesForTime (channel, finalTime, m); + + const Array expected { MidiMessage::controllerEvent (channel, 0x63, 50), + MidiMessage::controllerEvent (channel, 0x62, 10), + MidiMessage::controllerEvent (channel, 0x06, 10), + // Note: we should send both the MSB and LSB! + MidiMessage::controllerEvent (channel, 0x65, 0).withTimeStamp (finalTime), + MidiMessage::controllerEvent (channel, 0x64, 5).withTimeStamp (finalTime) }; + + expect (std::equal (m.begin(), m.end(), expected.begin(), expected.end(), messagesAreEqual)); + } + + beginTest ("createControllerUpdatesForTime does not emit duplicate parameter number change messages"); + { + MidiMessageSequence sequence; + + const auto time = 0.0; + const auto channel = 1; + + const Array messages { MidiMessage::controllerEvent (channel, 0x65, 1), + MidiMessage::controllerEvent (channel, 0x64, 2), + MidiMessage::controllerEvent (channel, 0x63, 3), + MidiMessage::controllerEvent (channel, 0x62, 4), + MidiMessage::controllerEvent (channel, 0x06, 10), + MidiMessage::controllerEvent (channel, 0x63, 30), + MidiMessage::controllerEvent (channel, 0x62, 40), + MidiMessage::controllerEvent (channel, 0x63, 3), + MidiMessage::controllerEvent (channel, 0x62, 4), + MidiMessage::controllerEvent (channel, 0x60, 5), + MidiMessage::controllerEvent (channel, 0x65, 10) }; + + for (const auto& m : messages) + sequence.addEvent (m, time); + + const auto finalTime = 1.0; + + Array m; + sequence.createControllerUpdatesForTime (channel, finalTime, m); + + const Array expected { MidiMessage::controllerEvent (channel, 0x63, 3), + MidiMessage::controllerEvent (channel, 0x62, 4), + MidiMessage::controllerEvent (channel, 0x06, 10), + // Parameter number is set to (30, 40) then back to (3, 4), + // so there is no need to resend it + MidiMessage::controllerEvent (channel, 0x60, 5), + // Set parameter number to final value + MidiMessage::controllerEvent (channel, 0x65, 10).withTimeStamp (finalTime), + MidiMessage::controllerEvent (channel, 0x64, 2) .withTimeStamp (finalTime) }; + + expect (std::equal (m.begin(), m.end(), expected.begin(), expected.end(), messagesAreEqual)); + } + + beginTest ("createControllerUpdatesForTime emits bank change messages immediately before program change"); + { + MidiMessageSequence sequence; + + const auto time = 0.0; + const auto channel = 1; + + const Array messages { MidiMessage::controllerEvent (channel, 0x00, 1), + MidiMessage::controllerEvent (channel, 0x20, 2), + MidiMessage::controllerEvent (channel, 0x65, 0), + MidiMessage::controllerEvent (channel, 0x64, 0), + MidiMessage::programChange (channel, 5) }; + + for (const auto& m : messages) + sequence.addEvent (m, time); + + const auto finalTime = 1.0; + + Array m; + sequence.createControllerUpdatesForTime (channel, finalTime, m); + + const Array expected { MidiMessage::controllerEvent (channel, 0x00, 1), + MidiMessage::controllerEvent (channel, 0x20, 2), + MidiMessage::programChange (channel, 5), + MidiMessage::controllerEvent (channel, 0x65, 0).withTimeStamp (finalTime), + MidiMessage::controllerEvent (channel, 0x64, 0).withTimeStamp (finalTime) }; + + + expect (std::equal (m.begin(), m.end(), expected.begin(), expected.end(), messagesAreEqual)); + } } }; diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.h b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.h index d4f4f926..698da744 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.h +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -53,9 +53,6 @@ class JUCE_API MidiMessageSequence /** Move assignment operator */ MidiMessageSequence& operator= (MidiMessageSequence&&) noexcept; - /** Destructor. */ - ~MidiMessageSequence(); - //============================================================================== /** Structure used to hold midi events in the sequence. @@ -68,9 +65,6 @@ class JUCE_API MidiMessageSequence { public: //============================================================================== - /** Destructor. */ - ~MidiEventHolder(); - /** The message itself, whose timestamp is used to specify the event's time. */ MidiMessage message; @@ -103,10 +97,16 @@ class JUCE_API MidiMessageSequence MidiEventHolder* getEventPointer (int index) const noexcept; /** Iterator for the list of MidiEventHolders */ - MidiEventHolder** begin() const noexcept; + MidiEventHolder** begin() noexcept; + + /** Iterator for the list of MidiEventHolders */ + MidiEventHolder* const* begin() const noexcept; + + /** Iterator for the list of MidiEventHolders */ + MidiEventHolder** end() noexcept; /** Iterator for the list of MidiEventHolders */ - MidiEventHolder** end() const noexcept; + MidiEventHolder* const* end() 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. @@ -271,6 +271,21 @@ class JUCE_API MidiMessageSequence As well as controllers, it will also recreate the midi program number and pitch bend position. + This function has special handling for the "bank select" and "data entry" + controllers (0x00, 0x20, 0x06, 0x26, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65). + + If the sequence contains multiple bank select and program change messages, + only the bank select messages immediately preceding the final program change + message will be kept. + + All "data increment" and "data decrement" messages will be retained. Some hardware will + ignore the requested increment/decrement values, so retaining all messages is the only + way to ensure compatibility with all hardware. + + "Parameter number" changes will be slightly condensed. Only the parameter number + events immediately preceding each data entry event will be kept. The parameter number + will also be set to its final value at the end of the sequence, if necessary. + @param channelNumber the midi channel to look for, in the range 1 to 16. Controllers for other channels will be ignored. @param time the time at which you want to find out the state - there are diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiRPN.cpp b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiRPN.cpp index 9e2c2df3..24a6c1f8 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiRPN.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiRPN.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -36,7 +36,7 @@ bool MidiRPNDetector::parseControllerMessage (int midiChannel, int controllerValue, MidiRPNMessage& result) noexcept { - jassert (midiChannel >= 1 && midiChannel <= 16); + jassert (midiChannel > 0 && midiChannel <= 16); jassert (controllerNumber >= 0 && controllerNumber < 128); jassert (controllerValue >= 0 && controllerValue < 128); @@ -159,6 +159,7 @@ MidiBuffer MidiRPNGenerator::generate (int midiChannel, return buffer; } + //============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -166,7 +167,9 @@ MidiBuffer MidiRPNGenerator::generate (int midiChannel, class MidiRPNDetectorTests : public UnitTest { public: - MidiRPNDetectorTests() : UnitTest ("MidiRPNDetector class", "MIDI/MPE") {} + MidiRPNDetectorTests() + : UnitTest ("MidiRPNDetector class", UnitTestCategories::midi) + {} void runTest() override { @@ -308,7 +311,9 @@ static MidiRPNDetectorTests MidiRPNDetectorUnitTests; class MidiRPNGeneratorTests : public UnitTest { public: - MidiRPNGeneratorTests() : UnitTest ("MidiRPNGenerator class", "MIDI/MPE") {} + MidiRPNGeneratorTests() + : UnitTest ("MidiRPNGenerator class", UnitTestCategories::midi) + {} void runTest() override { @@ -346,14 +351,13 @@ class MidiRPNGeneratorTests : public UnitTest //============================================================================== void expectContainsRPN (const MidiBuffer& midiBuffer, MidiRPNMessage expected) { - MidiBuffer::Iterator iter (midiBuffer); - MidiMessage midiMessage; MidiRPNMessage result = MidiRPNMessage(); MidiRPNDetector detector; - int samplePosition; // not actually used, so no need to initialise. - while (iter.getNextEvent (midiMessage, samplePosition)) + for (const auto metadata : midiBuffer) { + const auto midiMessage = metadata.getMessage(); + if (detector.parseControllerMessage (midiMessage.getChannel(), midiMessage.getControllerNumber(), midiMessage.getControllerValue(), @@ -371,6 +375,6 @@ class MidiRPNGeneratorTests : public UnitTest static MidiRPNGeneratorTests MidiRPNGeneratorUnitTests; -#endif // JUCE_UNIT_TESTS +#endif } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiRPN.h b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiRPN.h index 94ffc731..dcf0ec47 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiRPN.h +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiRPN.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -142,7 +142,7 @@ class JUCE_API MidiRPNGenerator @param use14BitValue If true (default), the value will have 14-bit precision (two MIDI bytes). If false, instead the value will have - 7-bit presision (a single MIDI byte). + 7-bit precision (a single MIDI byte). */ static MidiBuffer generate (int channel, int parameterNumber, diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMP.h b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMP.h new file mode 100644 index 00000000..e6ce3aff --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMP.h @@ -0,0 +1,47 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#include "../juce_MidiDataConcatenator.h" + +#include "juce_UMPProtocols.h" +#include "juce_UMPUtils.h" +#include "juce_UMPacket.h" +#include "juce_UMPSysEx7.h" +#include "juce_UMPView.h" +#include "juce_UMPIterator.h" +#include "juce_UMPackets.h" +#include "juce_UMPFactory.h" +#include "juce_UMPConversion.h" +#include "juce_UMPMidi1ToBytestreamTranslator.h" +#include "juce_UMPMidi1ToMidi2DefaultTranslator.h" +#include "juce_UMPConverters.h" +#include "juce_UMPDispatcher.h" +#include "juce_UMPReceiver.h" + +#ifndef DOXYGEN + +namespace juce +{ +namespace ump = universal_midi_packets; +} + +#endif diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPConversion.h b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPConversion.h new file mode 100644 index 00000000..86ae3391 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPConversion.h @@ -0,0 +1,330 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#ifndef DOXYGEN + +namespace juce +{ +namespace universal_midi_packets +{ + +/** + Functions to assist conversion of UMP messages to/from other formats, + especially older 'bytestream' formatted MidiMessages. + + @tags{Audio} +*/ +struct Conversion +{ + /** Converts from a MIDI 1 bytestream to MIDI 1 on Universal MIDI Packets. + + `callback` is a function which accepts a single View argument. + */ + template + static void toMidi1 (const MidiMessage& m, PacketCallbackFunction&& callback) + { + const auto* data = m.getRawData(); + const auto firstByte = data[0]; + const auto size = m.getRawDataSize(); + + if (firstByte != 0xf0) + { + const auto mask = [size]() -> uint32_t + { + switch (size) + { + case 0: return 0xff000000; + case 1: return 0xffff0000; + case 2: return 0xffffff00; + case 3: return 0xffffffff; + } + + return 0x00000000; + }(); + + const auto extraByte = (uint8_t) ((((firstByte & 0xf0) == 0xf0) ? 0x1 : 0x2) << 0x4); + const PacketX1 packet { mask & Utils::bytesToWord (extraByte, data[0], data[1], data[2]) }; + callback (View (packet.data())); + return; + } + + const auto numSysExBytes = m.getSysExDataSize(); + const auto numMessages = SysEx7::getNumPacketsRequiredForDataSize ((uint32_t) numSysExBytes); + auto* dataOffset = m.getSysExData(); + + if (numMessages <= 1) + { + const auto packet = Factory::makeSysExIn1Packet (0, (uint8_t) numSysExBytes, dataOffset); + callback (View (packet.data())); + return; + } + + constexpr auto byteIncrement = 6; + + for (auto i = numSysExBytes; i > 0; i -= byteIncrement, dataOffset += byteIncrement) + { + const auto func = [&] + { + if (i == numSysExBytes) + return Factory::makeSysExStart; + + if (i <= byteIncrement) + return Factory::makeSysExEnd; + + return Factory::makeSysExContinue; + }(); + + const auto bytesNow = std::min (byteIncrement, i); + const auto packet = func (0, (uint8_t) bytesNow, dataOffset); + callback (View (packet.data())); + } + } + + /** Converts a MidiMessage to one or more messages in UMP format, using + the MIDI 1.0 Protocol. + + `packets` is an out-param to allow the caller to control + allocation/deallocation. Returning a new Packets object would + require every call to toMidi1 to allocate. With this version, no + allocations will occur, provided that `packets` has adequate reserved + space. + */ + static void toMidi1 (const MidiMessage& m, Packets& packets) + { + toMidi1 (m, [&] (const View& view) { packets.add (view); }); + } + + /** Widens a 7-bit MIDI 1.0 value to a 8-bit MIDI 2.0 value. */ + static uint8_t scaleTo8 (uint8_t word7Bit) + { + const auto shifted = (uint8_t) (word7Bit << 0x1); + const auto repeat = (uint8_t) (word7Bit & 0x3f); + const auto mask = (uint8_t) (word7Bit <= 0x40 ? 0x0 : 0xff); + return (uint8_t) (shifted | ((repeat >> 5) & mask)); + } + + /** Widens a 7-bit MIDI 1.0 value to a 16-bit MIDI 2.0 value. */ + static uint16_t scaleTo16 (uint8_t word7Bit) + { + const auto shifted = (uint16_t) (word7Bit << 0x9); + const auto repeat = (uint16_t) (word7Bit & 0x3f); + const auto mask = (uint16_t) (word7Bit <= 0x40 ? 0x0 : 0xffff); + return (uint16_t) (shifted | (((repeat << 3) | (repeat >> 3)) & mask)); + } + + /** Widens a 14-bit MIDI 1.0 value to a 16-bit MIDI 2.0 value. */ + static uint16_t scaleTo16 (uint16_t word14Bit) + { + const auto shifted = (uint16_t) (word14Bit << 0x2); + const auto repeat = (uint16_t) (word14Bit & 0x1fff); + const auto mask = (uint16_t) (word14Bit <= 0x2000 ? 0x0 : 0xffff); + return (uint16_t) (shifted | ((repeat >> 11) & mask)); + } + + /** Widens a 7-bit MIDI 1.0 value to a 32-bit MIDI 2.0 value. */ + static uint32_t scaleTo32 (uint8_t word7Bit) + { + const auto shifted = (uint32_t) (word7Bit << 0x19); + const auto repeat = (uint32_t) (word7Bit & 0x3f); + const auto mask = (uint32_t) (word7Bit <= 0x40 ? 0x0 : 0xffffffff); + return (uint32_t) (shifted | (((repeat << 19) + | (repeat << 13) + | (repeat << 7) + | (repeat << 1) + | (repeat >> 5)) & mask)); + } + + /** Widens a 14-bit MIDI 1.0 value to a 32-bit MIDI 2.0 value. */ + static uint32_t scaleTo32 (uint16_t word14Bit) + { + const auto shifted = (uint32_t) (word14Bit << 0x12); + const auto repeat = (uint32_t) (word14Bit & 0x1fff); + const auto mask = (uint32_t) (word14Bit <= 0x2000 ? 0x0 : 0xffffffff); + return (uint32_t) (shifted | (((repeat << 5) | (repeat >> 8)) & mask)); + } + + /** Narrows a 16-bit MIDI 2.0 value to a 7-bit MIDI 1.0 value. */ + static uint8_t scaleTo7 (uint8_t word8Bit) { return (uint8_t) (word8Bit >> 1); } + + /** Narrows a 16-bit MIDI 2.0 value to a 7-bit MIDI 1.0 value. */ + static uint8_t scaleTo7 (uint16_t word16Bit) { return (uint8_t) (word16Bit >> 9); } + + /** Narrows a 32-bit MIDI 2.0 value to a 7-bit MIDI 1.0 value. */ + static uint8_t scaleTo7 (uint32_t word32Bit) { return (uint8_t) (word32Bit >> 25); } + + /** Narrows a 32-bit MIDI 2.0 value to a 14-bit MIDI 1.0 value. */ + static uint16_t scaleTo14 (uint16_t word16Bit) { return (uint16_t) (word16Bit >> 2); } + + /** Narrows a 32-bit MIDI 2.0 value to a 14-bit MIDI 1.0 value. */ + static uint16_t scaleTo14 (uint32_t word32Bit) { return (uint16_t) (word32Bit >> 18); } + + /** Converts UMP messages which may include MIDI 2.0 channel voice messages into + equivalent MIDI 1.0 messages (still in UMP format). + + `callback` is a function that accepts a single View argument and will be + called with each converted packet. + + Note that not all MIDI 2.0 messages have MIDI 1.0 equivalents, so such + messages will be ignored. + */ + template + static void midi2ToMidi1DefaultTranslation (const View& v, Callback&& callback) + { + const auto firstWord = v[0]; + + if (Utils::getMessageType (firstWord) != 0x4) + { + callback (v); + return; + } + + const auto status = Utils::getStatus (firstWord); + const auto typeAndGroup = (uint8_t) ((0x2 << 0x4) | Utils::getGroup (firstWord)); + + switch (status) + { + case 0x8: // note off + case 0x9: // note on + case 0xa: // poly pressure + case 0xb: // control change + { + const auto statusAndChannel = (uint8_t) ((firstWord >> 0x10) & 0xff); + const auto byte2 = (uint8_t) ((firstWord >> 0x08) & 0xff); + const auto byte3 = scaleTo7 (v[1]); + + // If this is a note-on, and the scaled byte is 0, + // the scaled velocity should be 1 instead of 0 + const auto needsCorrection = status == 0x9 && byte3 == 0; + const auto correctedByte = (uint8_t) (needsCorrection ? 1 : byte3); + + const auto shouldIgnore = status == 0xb && [&] + { + switch (byte2) + { + case 0: + case 6: + case 32: + case 38: + case 98: + case 99: + case 100: + case 101: + return true; + } + + return false; + }(); + + if (shouldIgnore) + return; + + const PacketX1 packet { Utils::bytesToWord (typeAndGroup, + statusAndChannel, + byte2, + correctedByte) }; + callback (View (packet.data())); + return; + } + + case 0xd: // channel pressure + { + const auto statusAndChannel = (uint8_t) ((firstWord >> 0x10) & 0xff); + const auto byte2 = scaleTo7 (v[1]); + + const PacketX1 packet { Utils::bytesToWord (typeAndGroup, + statusAndChannel, + byte2, + 0) }; + callback (View (packet.data())); + return; + } + + case 0x2: // rpn + case 0x3: // nrpn + { + const auto ccX = (uint8_t) (status == 0x2 ? 101 : 99); + const auto ccY = (uint8_t) (status == 0x2 ? 100 : 98); + const auto statusAndChannel = (uint8_t) ((0xb << 0x4) | Utils::getChannel (firstWord)); + const auto data = scaleTo14 (v[1]); + + const PacketX1 packets[] + { + PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, ccX, (uint8_t) ((firstWord >> 0x8) & 0x7f)) }, + PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, ccY, (uint8_t) ((firstWord >> 0x0) & 0x7f)) }, + PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, 6, (uint8_t) ((data >> 0x7) & 0x7f)) }, + PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, 38, (uint8_t) ((data >> 0x0) & 0x7f)) }, + }; + + for (const auto& packet : packets) + callback (View (packet.data())); + + return; + } + + case 0xc: // program change / bank select + { + if (firstWord & 1) + { + const auto statusAndChannel = (uint8_t) ((0xb << 0x4) | Utils::getChannel (firstWord)); + const auto secondWord = v[1]; + + const PacketX1 packets[] + { + PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, 0, (uint8_t) ((secondWord >> 0x8) & 0x7f)) }, + PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, 32, (uint8_t) ((secondWord >> 0x0) & 0x7f)) }, + }; + + for (const auto& packet : packets) + callback (View (packet.data())); + } + + const auto statusAndChannel = (uint8_t) ((0xc << 0x4) | Utils::getChannel (firstWord)); + const PacketX1 packet { Utils::bytesToWord (typeAndGroup, + statusAndChannel, + (uint8_t) ((v[1] >> 0x18) & 0x7f), + 0) }; + callback (View (packet.data())); + return; + } + + case 0xe: // pitch bend + { + const auto data = scaleTo14 (v[1]); + const auto statusAndChannel = (uint8_t) ((firstWord >> 0x10) & 0xff); + const PacketX1 packet { Utils::bytesToWord (typeAndGroup, + statusAndChannel, + (uint8_t) (data & 0x7f), + (uint8_t) ((data >> 7) & 0x7f)) }; + callback (View (packet.data())); + return; + } + + default: // other message types do not translate + return; + } + } +}; + +} +} + +#endif diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPConverters.h b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPConverters.h new file mode 100644 index 00000000..a0bbee91 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPConverters.h @@ -0,0 +1,169 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#ifndef DOXYGEN + +namespace juce +{ +namespace universal_midi_packets +{ + /** + Allows conversion from bytestream- or Universal MIDI Packet-formatted + messages to MIDI 1.0 messages in UMP format. + + @tags{Audio} + */ + struct ToUMP1Converter + { + template + void convert (const MidiMessage& m, Fn&& fn) + { + Conversion::toMidi1 (m, std::forward (fn)); + } + + template + void convert (const View& v, Fn&& fn) + { + Conversion::midi2ToMidi1DefaultTranslation (v, std::forward (fn)); + } + }; + + /** + Allows conversion from bytestream- or Universal MIDI Packet-formatted + messages to MIDI 2.0 messages in UMP format. + + @tags{Audio} + */ + struct ToUMP2Converter + { + template + void convert (const MidiMessage& m, Fn&& fn) + { + Conversion::toMidi1 (m, [&] (const View& v) + { + translator.dispatch (v, fn); + }); + } + + template + void convert (const View& v, Fn&& fn) + { + translator.dispatch (v, std::forward (fn)); + } + + void reset() + { + translator.reset(); + } + + Midi1ToMidi2DefaultTranslator translator; + }; + + /** + Allows conversion from bytestream- or Universal MIDI Packet-formatted + messages to UMP format. + + The packet protocol can be selected using the constructor parameter. + + @tags{Audio} + */ + class GenericUMPConverter + { + public: + explicit GenericUMPConverter (PacketProtocol m) + : mode (m) {} + + void reset() + { + std::get<1> (converters).reset(); + } + + template + void convert (const MidiMessage& m, Fn&& fn) + { + switch (mode) + { + case PacketProtocol::MIDI_1_0: return std::get<0> (converters).convert (m, std::forward (fn)); + case PacketProtocol::MIDI_2_0: return std::get<1> (converters).convert (m, std::forward (fn)); + } + } + + template + void convert (const View& v, Fn&& fn) + { + switch (mode) + { + case PacketProtocol::MIDI_1_0: return std::get<0> (converters).convert (v, std::forward (fn)); + case PacketProtocol::MIDI_2_0: return std::get<1> (converters).convert (v, std::forward (fn)); + } + } + + template + void convert (Iterator begin, Iterator end, Fn&& fn) + { + std::for_each (begin, end, [&] (const View& v) + { + convert (v, fn); + }); + } + + PacketProtocol getProtocol() const noexcept { return mode; } + + private: + std::tuple converters; + const PacketProtocol mode{}; + }; + + /** + Allows conversion from bytestream- or Universal MIDI Packet-formatted + messages to bytestream format. + + @tags{Audio} + */ + struct ToBytestreamConverter + { + explicit ToBytestreamConverter (int storageSize) + : translator (storageSize) {} + + template + void convert (const MidiMessage& m, Fn&& fn) + { + fn (m); + } + + template + void convert (const View& v, double time, Fn&& fn) + { + Conversion::midi2ToMidi1DefaultTranslation (v, [&] (const View& midi1) + { + translator.dispatch (midi1, time, fn); + }); + } + + void reset() { translator.reset(); } + + Midi1ToBytestreamTranslator translator; + }; +} +} + +#endif diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPDispatcher.h b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPDispatcher.h new file mode 100644 index 00000000..ab1277cc --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPDispatcher.h @@ -0,0 +1,202 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#ifndef DOXYGEN + +namespace juce +{ +namespace universal_midi_packets +{ + +/** + Parses a raw stream of uint32_t, and calls a user-provided callback every time + a full Universal MIDI Packet is encountered. + + @tags{Audio} +*/ +class Dispatcher +{ +public: + /** Clears the dispatcher. */ + void reset() { currentPacketLen = 0; } + + /** Calls `callback` with a View of each packet encountered in the range delimited + by `begin` and `end`. + + If the range ends part-way through a packet, the next call to `dispatch` will + continue from that point in the packet (unless `reset` is called first). + */ + template + void dispatch (const uint32_t* begin, + const uint32_t* end, + double timeStamp, + PacketCallbackFunction&& callback) + { + std::for_each (begin, end, [&] (uint32_t word) + { + nextPacket[currentPacketLen++] = word; + + if (currentPacketLen == Utils::getNumWordsForMessageType (nextPacket.front())) + { + callback (View (nextPacket.data()), timeStamp); + currentPacketLen = 0; + } + }); + } + +private: + std::array nextPacket; + size_t currentPacketLen = 0; +}; + +//============================================================================== +/** + Parses a stream of bytes representing a sequence of bytestream-encoded MIDI 1.0 messages, + converting the messages to UMP format and passing the packets to a user-provided callback + as they become ready. + + @tags{Audio} +*/ +class BytestreamToUMPDispatcher +{ +public: + /** Initialises the dispatcher. + + Channel messages will be converted to the requested protocol format `pp`. + `storageSize` bytes will be allocated to store incomplete messages. + */ + explicit BytestreamToUMPDispatcher (PacketProtocol pp, int storageSize) + : concatenator (storageSize), + converter (pp) + {} + + void reset() + { + concatenator.reset(); + converter.reset(); + } + + /** Calls `callback` with a View of each converted packet as it becomes ready. + + @param begin the first byte in a range of bytes representing bytestream-encoded MIDI messages. + @param end one-past the last byte in a range of bytes representing bytestream-encoded MIDI messages. + @param timestamp a timestamp to apply to the created packets. + @param callback a callback which will be passed a View pointing to each new packet as it becomes ready. + */ + template + void dispatch (const uint8_t* begin, + const uint8_t* end, + double timestamp, + PacketCallbackFunction&& callback) + { + using CallbackPtr = decltype (std::addressof (callback)); + + #if JUCE_MINGW + #define JUCE_MINGW_HIDDEN_VISIBILITY __attribute__ ((visibility ("hidden"))) + #else + #define JUCE_MINGW_HIDDEN_VISIBILITY + #endif + + struct JUCE_MINGW_HIDDEN_VISIBILITY Callback + { + Callback (BytestreamToUMPDispatcher& d, CallbackPtr c) + : dispatch (d), callbackPtr (c) {} + + void handleIncomingMidiMessage (void*, const MidiMessage& msg) const + { + Conversion::toMidi1 (msg, [&] (const View& view) + { + dispatch.converter.convert (view, *callbackPtr); + }); + } + + void handlePartialSysexMessage (void*, const uint8_t*, int, double) const {} + + BytestreamToUMPDispatcher& dispatch; + CallbackPtr callbackPtr = nullptr; + }; + + #undef JUCE_MINGW_HIDDEN_VISIBILITY + + Callback inputCallback { *this, &callback }; + concatenator.pushMidiData (begin, int (end - begin), timestamp, (void*) nullptr, inputCallback); + } + +private: + MidiDataConcatenator concatenator; + GenericUMPConverter converter; +}; + +//============================================================================== +/** + Parses a stream of 32-bit words representing a sequence of UMP-encoded MIDI messages, + converting the messages to MIDI 1.0 bytestream format and passing them to a user-provided + callback as they become ready. + + @tags{Audio} +*/ +class ToBytestreamDispatcher +{ +public: + /** Initialises the dispatcher. + + `storageSize` bytes will be allocated to store incomplete messages. + */ + explicit ToBytestreamDispatcher (int storageSize) + : converter (storageSize) {} + + /** Clears the dispatcher. */ + void reset() + { + dispatcher.reset(); + converter.reset(); + } + + /** Calls `callback` with converted bytestream-formatted MidiMessage whenever + a new message becomes available. + + @param begin the first word in a stream of words representing UMP-encoded MIDI packets. + @param end one-past the last word in a stream of words representing UMP-encoded MIDI packets. + @param timestamp a timestamp to apply to converted messages. + @param callback a callback which will be passed a MidiMessage each time a new message becomes ready. + */ + template + void dispatch (const uint32_t* begin, + const uint32_t* end, + double timestamp, + BytestreamMessageCallback&& callback) + { + dispatcher.dispatch (begin, end, timestamp, [&] (const View& view, double time) + { + converter.convert (view, time, callback); + }); + } + +private: + Dispatcher dispatcher; + ToBytestreamConverter converter; +}; + +} +} + +#endif diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPFactory.h b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPFactory.h new file mode 100644 index 00000000..f1d937d7 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPFactory.h @@ -0,0 +1,538 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#ifndef DOXYGEN + +namespace juce +{ +namespace universal_midi_packets +{ + +/** + This struct holds functions that can be used to create different kinds + of Universal MIDI Packet. + + @tags{Audio} +*/ +struct Factory +{ + /** @internal */ + struct Detail + { + static PacketX1 makeSystem() { return PacketX1{}.withMessageType (1); } + static PacketX1 makeV1() { return PacketX1{}.withMessageType (2); } + static PacketX2 makeV2() { return PacketX2{}.withMessageType (4); } + + static PacketX2 makeSysEx (uint8_t group, + uint8_t status, + uint8_t numBytes, + const uint8_t* data) + { + jassert (numBytes <= 6); + + std::array bytes{{}}; + bytes[0] = (0x3 << 0x4) | group; + bytes[1] = (uint8_t) (status << 0x4) | numBytes; + + std::memcpy (bytes.data() + 2, data, numBytes); + + std::array words; + + size_t index = 0; + + for (auto& word : words) + word = ByteOrder::bigEndianInt (bytes.data() + 4 * index++); + + return PacketX2 { words }; + } + + static PacketX4 makeSysEx8 (uint8_t group, + uint8_t status, + uint8_t numBytes, + uint8_t dataStart, + const uint8_t* data) + { + jassert (numBytes <= 16 - dataStart); + + std::array bytes{{}}; + bytes[0] = (0x5 << 0x4) | group; + bytes[1] = (uint8_t) (status << 0x4) | numBytes; + + std::memcpy (bytes.data() + dataStart, data, numBytes); + + std::array words; + + size_t index = 0; + + for (auto& word : words) + word = ByteOrder::bigEndianInt (bytes.data() + 4 * index++); + + return PacketX4 { words }; + } + }; + + static PacketX1 makeNoop (uint8_t group) + { + return PacketX1{}.withGroup (group); + } + + static PacketX1 makeJRClock (uint8_t group, uint16_t time) + { + return PacketX1 { time }.withStatus (1).withGroup (group); + } + + static PacketX1 makeJRTimestamp (uint8_t group, uint16_t time) + { + return PacketX1 { time }.withStatus (2).withGroup (group); + } + + static PacketX1 makeTimeCode (uint8_t group, uint8_t code) + { + return Detail::makeSystem().withGroup (group) + .withU8<1> (0xf1) + .withU8<2> (code & 0x7f); + } + + static PacketX1 makeSongPositionPointer (uint8_t group, uint16_t pos) + { + return Detail::makeSystem().withGroup (group) + .withU8<1> (0xf2) + .withU8<2> (pos & 0x7f) + .withU8<3> ((pos >> 7) & 0x7f); + } + + static PacketX1 makeSongSelect (uint8_t group, uint8_t song) + { + return Detail::makeSystem().withGroup (group) + .withU8<1> (0xf3) + .withU8<2> (song & 0x7f); + } + + static PacketX1 makeTuneRequest (uint8_t group) + { + return Detail::makeSystem().withGroup (group) + .withU8<1> (0xf6); + } + + static PacketX1 makeTimingClock (uint8_t group) + { + return Detail::makeSystem().withGroup (group) + .withU8<1> (0xf8); + } + + static PacketX1 makeStart (uint8_t group) + { + return Detail::makeSystem().withGroup (group) + .withU8<1> (0xfa); + } + + static PacketX1 makeContinue (uint8_t group) + { + return Detail::makeSystem().withGroup (group) + .withU8<1> (0xfb); + } + + static PacketX1 makeStop (uint8_t group) + { + return Detail::makeSystem().withGroup (group) + .withU8<1> (0xfc); + } + + static PacketX1 makeActiveSensing (uint8_t group) + { + return Detail::makeSystem().withGroup (group) + .withU8<1> (0xfe); + } + + static PacketX1 makeReset (uint8_t group) + { + return Detail::makeSystem().withGroup (group) + .withU8<1> (0xff); + } + + static PacketX1 makeNoteOffV1 (uint8_t group, + uint8_t channel, + uint8_t note, + uint8_t velocity) + { + return Detail::makeV1().withGroup (group) + .withStatus (0x8) + .withChannel (channel) + .withU8<2> (note & 0x7f) + .withU8<3> (velocity & 0x7f); + } + + static PacketX1 makeNoteOnV1 (uint8_t group, + uint8_t channel, + uint8_t note, + uint8_t velocity) + { + return Detail::makeV1().withGroup (group) + .withStatus (0x9) + .withChannel (channel) + .withU8<2> (note & 0x7f) + .withU8<3> (velocity & 0x7f); + } + + static PacketX1 makePolyPressureV1 (uint8_t group, + uint8_t channel, + uint8_t note, + uint8_t pressure) + { + return Detail::makeV1().withGroup (group) + .withStatus (0xa) + .withChannel (channel) + .withU8<2> (note & 0x7f) + .withU8<3> (pressure & 0x7f); + } + + static PacketX1 makeControlChangeV1 (uint8_t group, + uint8_t channel, + uint8_t controller, + uint8_t value) + { + return Detail::makeV1().withGroup (group) + .withStatus (0xb) + .withChannel (channel) + .withU8<2> (controller & 0x7f) + .withU8<3> (value & 0x7f); + } + + static PacketX1 makeProgramChangeV1 (uint8_t group, + uint8_t channel, + uint8_t program) + { + return Detail::makeV1().withGroup (group) + .withStatus (0xc) + .withChannel (channel) + .withU8<2> (program & 0x7f); + } + + static PacketX1 makeChannelPressureV1 (uint8_t group, + uint8_t channel, + uint8_t pressure) + { + return Detail::makeV1().withGroup (group) + .withStatus (0xd) + .withChannel (channel) + .withU8<2> (pressure & 0x7f); + } + + static PacketX1 makePitchBend (uint8_t group, + uint8_t channel, + uint16_t pitchbend) + { + return Detail::makeV1().withGroup (group) + .withStatus (0xe) + .withChannel (channel) + .withU8<2> (pitchbend & 0x7f) + .withU8<3> ((pitchbend >> 7) & 0x7f); + } + + static PacketX2 makeSysExIn1Packet (uint8_t group, + uint8_t numBytes, + const uint8_t* data) + { + return Detail::makeSysEx (group, 0x0, numBytes, data); + } + + static PacketX2 makeSysExStart (uint8_t group, + uint8_t numBytes, + const uint8_t* data) + { + return Detail::makeSysEx (group, 0x1, numBytes, data); + } + + static PacketX2 makeSysExContinue (uint8_t group, + uint8_t numBytes, + const uint8_t* data) + { + return Detail::makeSysEx (group, 0x2, numBytes, data); + } + + static PacketX2 makeSysExEnd (uint8_t group, + uint8_t numBytes, + const uint8_t* data) + { + return Detail::makeSysEx (group, 0x3, numBytes, data); + } + + static PacketX2 makeRegisteredPerNoteControllerV2 (uint8_t group, + uint8_t channel, + uint8_t note, + uint8_t controller, + uint32_t data) + { + return Detail::makeV2().withGroup (group) + .withStatus (0x0) + .withChannel (channel) + .withU8<2> (note & 0x7f) + .withU8<3> (controller & 0x7f) + .withU32<1> (data); + } + + static PacketX2 makeAssignablePerNoteControllerV2 (uint8_t group, + uint8_t channel, + uint8_t note, + uint8_t controller, + uint32_t data) + { + return Detail::makeV2().withGroup (group) + .withStatus (0x1) + .withChannel (channel) + .withU8<2> (note & 0x7f) + .withU8<3> (controller & 0x7f) + .withU32<1> (data); + } + + static PacketX2 makeRegisteredControllerV2 (uint8_t group, + uint8_t channel, + uint8_t bank, + uint8_t index, + uint32_t data) + { + return Detail::makeV2().withGroup (group) + .withStatus (0x2) + .withChannel (channel) + .withU8<2> (bank & 0x7f) + .withU8<3> (index & 0x7f) + .withU32<1> (data); + } + + static PacketX2 makeAssignableControllerV2 (uint8_t group, + uint8_t channel, + uint8_t bank, + uint8_t index, + uint32_t data) + { + return Detail::makeV2().withGroup (group) + .withStatus (0x3) + .withChannel (channel) + .withU8<2> (bank & 0x7f) + .withU8<3> (index & 0x7f) + .withU32<1> (data); + } + + static PacketX2 makeRelativeRegisteredControllerV2 (uint8_t group, + uint8_t channel, + uint8_t bank, + uint8_t index, + uint32_t data) + { + return Detail::makeV2().withGroup (group) + .withStatus (0x4) + .withChannel (channel) + .withU8<2> (bank & 0x7f) + .withU8<3> (index & 0x7f) + .withU32<1> (data); + } + + static PacketX2 makeRelativeAssignableControllerV2 (uint8_t group, + uint8_t channel, + uint8_t bank, + uint8_t index, + uint32_t data) + { + return Detail::makeV2().withGroup (group) + .withStatus (0x5) + .withChannel (channel) + .withU8<2> (bank & 0x7f) + .withU8<3> (index & 0x7f) + .withU32<1> (data); + } + + static PacketX2 makePerNotePitchBendV2 (uint8_t group, + uint8_t channel, + uint8_t note, + uint32_t data) + { + return Detail::makeV2().withGroup (group) + .withStatus (0x6) + .withChannel (channel) + .withU8<2> (note & 0x7f) + .withU32<1> (data); + } + + enum class NoteAttributeKind : uint8_t + { + none = 0x00, + manufacturer = 0x01, + profile = 0x02, + pitch7_9 = 0x03 + }; + + static PacketX2 makeNoteOffV2 (uint8_t group, + uint8_t channel, + uint8_t note, + NoteAttributeKind attribute, + uint16_t velocity, + uint16_t attributeValue) + { + return Detail::makeV2().withGroup (group) + .withStatus (0x8) + .withChannel (channel) + .withU8<2> (note & 0x7f) + .withU8<3> ((uint8_t) attribute) + .withU16<2> (velocity) + .withU16<3> (attributeValue); + } + + static PacketX2 makeNoteOnV2 (uint8_t group, + uint8_t channel, + uint8_t note, + NoteAttributeKind attribute, + uint16_t velocity, + uint16_t attributeValue) + { + return Detail::makeV2().withGroup (group) + .withStatus (0x9) + .withChannel (channel) + .withU8<2> (note & 0x7f) + .withU8<3> ((uint8_t) attribute) + .withU16<2> (velocity) + .withU16<3> (attributeValue); + } + + static PacketX2 makePolyPressureV2 (uint8_t group, + uint8_t channel, + uint8_t note, + uint32_t data) + { + return Detail::makeV2().withGroup (group) + .withStatus (0xa) + .withChannel (channel) + .withU8<2> (note & 0x7f) + .withU32<1> (data); + } + + static PacketX2 makeControlChangeV2 (uint8_t group, + uint8_t channel, + uint8_t controller, + uint32_t data) + { + return Detail::makeV2().withGroup (group) + .withStatus (0xb) + .withChannel (channel) + .withU8<2> (controller & 0x7f) + .withU32<1> (data); + } + + static PacketX2 makeProgramChangeV2 (uint8_t group, + uint8_t channel, + uint8_t optionFlags, + uint8_t program, + uint8_t bankMsb, + uint8_t bankLsb) + { + return Detail::makeV2().withGroup (group) + .withStatus (0xc) + .withChannel (channel) + .withU8<3> (optionFlags) + .withU8<4> (program) + .withU8<6> (bankMsb) + .withU8<7> (bankLsb); + } + + static PacketX2 makeChannelPressureV2 (uint8_t group, + uint8_t channel, + uint32_t data) + { + return Detail::makeV2().withGroup (group) + .withStatus (0xd) + .withChannel (channel) + .withU32<1> (data); + } + + static PacketX2 makePitchBendV2 (uint8_t group, + uint8_t channel, + uint32_t data) + { + return Detail::makeV2().withGroup (group) + .withStatus (0xe) + .withChannel (channel) + .withU32<1> (data); + } + + static PacketX2 makePerNoteManagementV2 (uint8_t group, + uint8_t channel, + uint8_t note, + uint8_t optionFlags) + { + return Detail::makeV2().withGroup (group) + .withStatus (0xf) + .withChannel (channel) + .withU8<2> (note) + .withU8<3> (optionFlags); + } + + + static PacketX4 makeSysEx8in1Packet (uint8_t group, + uint8_t numBytes, + uint8_t streamId, + const uint8_t* data) + { + return Detail::makeSysEx8 (group, 0x0, numBytes, 3, data).withU8<2> (streamId); + } + + static PacketX4 makeSysEx8Start (uint8_t group, + uint8_t numBytes, + uint8_t streamId, + const uint8_t* data) + { + return Detail::makeSysEx8 (group, 0x1, numBytes, 3, data).withU8<2> (streamId); + } + + static PacketX4 makeSysEx8Continue (uint8_t group, + uint8_t numBytes, + uint8_t streamId, + const uint8_t* data) + { + return Detail::makeSysEx8 (group, 0x2, numBytes, 3, data).withU8<2> (streamId); + } + + static PacketX4 makeSysEx8End (uint8_t group, + uint8_t numBytes, + uint8_t streamId, + const uint8_t* data) + { + return Detail::makeSysEx8 (group, 0x3, numBytes, 3, data).withU8<2> (streamId); + } + + static PacketX4 makeMixedDataSetHeader (uint8_t group, + uint8_t dataSetId, + const uint8_t* data) + { + return Detail::makeSysEx8 (group, 0x8, 14, 2, data).withChannel (dataSetId); + } + + static PacketX4 makeDataSetPayload (uint8_t group, + uint8_t dataSetId, + const uint8_t* data) + { + return Detail::makeSysEx8 (group, 0x9, 14, 2, data).withChannel (dataSetId); + } +}; + +} +} + +#endif diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPIterator.h b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPIterator.h new file mode 100644 index 00000000..1800388a --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPIterator.h @@ -0,0 +1,130 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#ifndef DOXYGEN + +namespace juce +{ +namespace universal_midi_packets +{ + +/** + Enables iteration over a collection of Universal MIDI Packets stored as + a contiguous range of 32-bit words. + + This iterator is used by Packets to allow access to the messages + that it contains. + + @tags{Audio} +*/ +class Iterator +{ +public: + /** Creates an invalid (singular) iterator. */ + Iterator() noexcept = default; + + /** Creates an iterator pointing at `ptr`. */ + explicit Iterator (const uint32_t* ptr, size_t bytes) noexcept + : view (ptr) + #if JUCE_DEBUG + , bytesRemaining (bytes) + #endif + { + ignoreUnused (bytes); + } + + using difference_type = std::iterator_traits::difference_type; + using value_type = View; + using reference = const View&; + using pointer = const View*; + using iterator_category = std::forward_iterator_tag; + + /** Moves this iterator to the next packet in the range. */ + Iterator& operator++() noexcept + { + const auto increment = view.size(); + + #if JUCE_DEBUG + // If you hit this, the memory region contained a truncated or otherwise + // malformed Universal MIDI Packet. + // The Iterator can only be used on regions containing complete packets! + jassert (increment <= bytesRemaining); + bytesRemaining -= increment; + #endif + + view = View (view.data() + increment); + return *this; + } + + /** Moves this iterator to the next packet in the range, + returning the value of the iterator before it was + incremented. + */ + Iterator operator++ (int) noexcept + { + auto copy = *this; + ++(*this); + return copy; + } + + /** Returns true if this iterator points to the same address + as another iterator. + */ + bool operator== (const Iterator& other) const noexcept + { + return view == other.view; + } + + /** Returns false if this iterator points to the same address + as another iterator. + */ + bool operator!= (const Iterator& other) const noexcept + { + return ! operator== (other); + } + + /** Returns a reference to a View of the packet currently + pointed-to by this iterator. + + The View can be queried for its size and content. + */ + reference operator*() noexcept { return view; } + + /** Returns a pointer to a View of the packet currently + pointed-to by this iterator. + + The View can be queried for its size and content. + */ + pointer operator->() noexcept { return &view; } + +private: + View view; + + #if JUCE_DEBUG + size_t bytesRemaining = 0; + #endif +}; + +} +} + +#endif diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToBytestreamTranslator.h b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToBytestreamTranslator.h new file mode 100644 index 00000000..514cd017 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToBytestreamTranslator.h @@ -0,0 +1,217 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#ifndef DOXYGEN + +namespace juce +{ +namespace universal_midi_packets +{ + +/** + Parses a raw stream of uint32_t holding a series of Universal MIDI Packets using + the MIDI 1.0 Protocol, converting to plain (non-UMP) MidiMessages. + + @tags{Audio} +*/ +class Midi1ToBytestreamTranslator +{ +public: + /** Ensures that there is room in the internal buffer for a sysex message of at least + `initialBufferSize` bytes. + */ + explicit Midi1ToBytestreamTranslator (int initialBufferSize) + { + pendingSysExData.reserve (size_t (initialBufferSize)); + } + + /** Clears the concatenator. */ + void reset() + { + pendingSysExData.clear(); + pendingSysExTime = 0.0; + } + + /** Converts a Universal MIDI Packet using the MIDI 1.0 Protocol to + an equivalent MidiMessage. Accumulates SysEx packets into a single + MidiMessage, as appropriate. + + @param packet a packet which is using the MIDI 1.0 Protocol. + @param time the timestamp to be applied to these messages. + @param callback a callback which will be called with each converted MidiMessage. + */ + template + void dispatch (const View& packet, double time, MessageCallback&& callback) + { + const auto firstWord = *packet.data(); + + if (! pendingSysExData.empty() && shouldPacketTerminateSysExEarly (firstWord)) + pendingSysExData.clear(); + + switch (packet.size()) + { + case 1: + { + // Utility messages don't translate to bytestream format + if (Utils::getMessageType (firstWord) != 0x00) + callback (fromUmp (PacketX1 { firstWord }, time)); + + break; + } + + case 2: + { + if (Utils::getMessageType (firstWord) == 0x3) + processSysEx (PacketX2 { packet[0], packet[1] }, time, callback); + + break; + } + + case 3: // no 3-word packets in the current spec + case 4: // no 4-word packets translate to bytestream format + default: + break; + } + } + + /** Converts from a Universal MIDI Packet to MIDI 1 bytestream format. + + This is only capable of converting a single Universal MIDI Packet to + an equivalent bytestream MIDI message. This function cannot understand + multi-packet messages, like SysEx7 messages. + + To convert multi-packet messages, use `Midi1ToBytestreamTranslator` + to convert from a UMP MIDI 1.0 stream, or `ToBytestreamDispatcher` + to convert from both MIDI 2.0 and MIDI 1.0. + */ + static MidiMessage fromUmp (const PacketX1& m, double time = 0) + { + const auto word = m.front(); + jassert (Utils::getNumWordsForMessageType (word) == 1); + + const std::array bytes { { uint8_t ((word >> 0x10) & 0xff), + uint8_t ((word >> 0x08) & 0xff), + uint8_t ((word >> 0x00) & 0xff) } }; + const auto numBytes = MidiMessage::getMessageLengthFromFirstByte (bytes.front()); + return MidiMessage (bytes.data(), numBytes, time); + } + +private: + template + void processSysEx (const PacketX2& packet, + double time, + MessageCallback&& callback) + { + switch (getSysEx7Kind (packet[0])) + { + case SysEx7::Kind::complete: + startSysExMessage (time); + pushBytes (packet); + terminateSysExMessage (callback); + break; + + case SysEx7::Kind::begin: + startSysExMessage (time); + pushBytes (packet); + break; + + case SysEx7::Kind::continuation: + if (pendingSysExData.empty()) + break; + + pushBytes (packet); + break; + + case SysEx7::Kind::end: + if (pendingSysExData.empty()) + break; + + pushBytes (packet); + terminateSysExMessage (callback); + break; + } + } + + void pushBytes (const PacketX2& packet) + { + const auto bytes = SysEx7::getDataBytes (packet); + pendingSysExData.insert (pendingSysExData.end(), + bytes.data.begin(), + bytes.data.begin() + bytes.size); + } + + void startSysExMessage (double time) + { + pendingSysExTime = time; + pendingSysExData.push_back (0xf0); + } + + template + void terminateSysExMessage (MessageCallback&& callback) + { + pendingSysExData.push_back (0xf7); + callback (MidiMessage (pendingSysExData.data(), + int (pendingSysExData.size()), + pendingSysExTime)); + pendingSysExData.clear(); + } + + static bool shouldPacketTerminateSysExEarly (uint32_t firstWord) + { + return ! (isSysExContinuation (firstWord) + || isSystemRealTime (firstWord) + || isJROrNOP (firstWord)); + } + + static SysEx7::Kind getSysEx7Kind (uint32_t word) + { + return SysEx7::Kind ((word >> 0x14) & 0xf); + } + + static bool isJROrNOP (uint32_t word) + { + return Utils::getMessageType (word) == 0x0; + } + + static bool isSysExContinuation (uint32_t word) + { + if (Utils::getMessageType (word) != 0x3) + return false; + + const auto kind = getSysEx7Kind (word); + return kind == SysEx7::Kind::continuation || kind == SysEx7::Kind::end; + } + + static bool isSystemRealTime (uint32_t word) + { + return Utils::getMessageType (word) == 0x1 && ((word >> 0x10) & 0xff) >= 0xf8; + } + + std::vector pendingSysExData; + + double pendingSysExTime = 0.0; +}; + +} +} + +#endif diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.cpp b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.cpp new file mode 100644 index 00000000..9da72c34 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.cpp @@ -0,0 +1,195 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ +namespace universal_midi_packets +{ + +PacketX2 Midi1ToMidi2DefaultTranslator::processNoteOnOrOff (const HelperValues helpers) +{ + const auto velocity = helpers.byte2; + const auto needsConversion = (helpers.byte0 >> 0x4) == 0x9 && velocity == 0; + const auto firstByte = needsConversion ? (uint8_t) ((0x8 << 0x4) | (helpers.byte0 & 0xf)) + : helpers.byte0; + + return PacketX2 + { + Utils::bytesToWord (helpers.typeAndGroup, firstByte, helpers.byte1, 0), + (uint32_t) (Conversion::scaleTo16 (velocity) << 0x10) + }; +} + +PacketX2 Midi1ToMidi2DefaultTranslator::processPolyPressure (const HelperValues helpers) +{ + return PacketX2 + { + Utils::bytesToWord (helpers.typeAndGroup, helpers.byte0, helpers.byte1, 0), + Conversion::scaleTo32 (helpers.byte2) + }; +} + +bool Midi1ToMidi2DefaultTranslator::processControlChange (const HelperValues helpers, + PacketX2& packet) +{ + const auto statusAndChannel = helpers.byte0; + const auto cc = helpers.byte1; + + const auto shouldAccumulate = [&] + { + switch (cc) + { + case 6: + case 38: + case 98: + case 99: + case 100: + case 101: + return true; + } + + return false; + }(); + + const auto group = (uint8_t) (helpers.typeAndGroup & 0xf); + const auto channel = (uint8_t) (statusAndChannel & 0xf); + const auto byte = helpers.byte2; + + if (shouldAccumulate) + { + auto& accumulator = groupAccumulators[group][channel]; + + if (accumulator.addByte (cc, byte)) + { + const auto& bytes = accumulator.getBytes(); + const auto bank = bytes[0]; + const auto index = bytes[1]; + const auto msb = bytes[2]; + const auto lsb = bytes[3]; + + const auto value = (uint16_t) (((msb & 0x7f) << 7) | (lsb & 0x7f)); + + const auto newStatus = (uint8_t) (accumulator.getKind() == PnKind::nrpn ? 0x3 : 0x2); + + packet = PacketX2 + { + Utils::bytesToWord (helpers.typeAndGroup, (uint8_t) ((newStatus << 0x4) | channel), bank, index), + Conversion::scaleTo32 (value) + }; + return true; + } + + return false; + } + + if (cc == 0) + { + groupBanks[group][channel].setMsb (byte); + return false; + } + + if (cc == 32) + { + groupBanks[group][channel].setLsb (byte); + return false; + } + + packet = PacketX2 + { + Utils::bytesToWord (helpers.typeAndGroup, statusAndChannel, cc, 0), + Conversion::scaleTo32 (helpers.byte2) + }; + return true; +} + +PacketX2 Midi1ToMidi2DefaultTranslator::processProgramChange (const HelperValues helpers) const +{ + const auto group = (uint8_t) (helpers.typeAndGroup & 0xf); + const auto channel = (uint8_t) (helpers.byte0 & 0xf); + const auto bank = groupBanks[group][channel]; + const auto valid = bank.isValid(); + + return PacketX2 + { + Utils::bytesToWord (helpers.typeAndGroup, helpers.byte0, 0, valid ? 1 : 0), + Utils::bytesToWord (helpers.byte1, 0, valid ? bank.getMsb() : 0, valid ? bank.getLsb() : 0) + }; +} + +PacketX2 Midi1ToMidi2DefaultTranslator::processChannelPressure (const HelperValues helpers) +{ + return PacketX2 + { + Utils::bytesToWord (helpers.typeAndGroup, helpers.byte0, 0, 0), + Conversion::scaleTo32 (helpers.byte1) + }; +} + +PacketX2 Midi1ToMidi2DefaultTranslator::processPitchBend (const HelperValues helpers) +{ + const auto lsb = helpers.byte1; + const auto msb = helpers.byte2; + const auto value = (uint16_t) (msb << 7 | lsb); + + return PacketX2 + { + Utils::bytesToWord (helpers.typeAndGroup, helpers.byte0, 0, 0), + Conversion::scaleTo32 (value) + }; +} + +bool Midi1ToMidi2DefaultTranslator::PnAccumulator::addByte (uint8_t cc, uint8_t byte) +{ + const auto isStart = cc == 99 || cc == 101; + + if (isStart) + { + kind = cc == 99 ? PnKind::nrpn : PnKind::rpn; + index = 0; + } + + bytes[index] = byte; + + const auto shouldContinue = [&] + { + switch (index) + { + case 0: return isStart; + case 1: return kind == PnKind::nrpn ? cc == 98 : cc == 100; + case 2: return cc == 6; + case 3: return cc == 38; + } + + return false; + }(); + + index = shouldContinue ? index + 1 : 0; + + if (index != bytes.size()) + return false; + + index = 0; + return true; +} + +} +} diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.h b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.h new file mode 100644 index 00000000..77e50766 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.h @@ -0,0 +1,191 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#ifndef DOXYGEN + +namespace juce +{ +namespace universal_midi_packets +{ + +/** + Translates a series of MIDI 1 Universal MIDI Packets to corresponding MIDI 2 + packets. + + @tags{Audio} +*/ +class Midi1ToMidi2DefaultTranslator +{ +public: + Midi1ToMidi2DefaultTranslator() = default; + + /** Converts MIDI 1 Universal MIDI Packets to corresponding MIDI 2 packets, + calling `callback` with each converted packet. + + In some cases (such as RPN/NRPN messages) multiple MIDI 1 packets will + convert to a single MIDI 2 packet. In these cases, the translator will + accumulate the full message internally, and send a single callback with + the completed message, once all the individual MIDI 1 packets have been + processed. + */ + template + void dispatch (const View& v, PacketCallback&& callback) + { + const auto firstWord = v[0]; + const auto messageType = Utils::getMessageType (firstWord); + + if (messageType != 0x2) + { + callback (v); + return; + } + + const HelperValues helperValues + { + (uint8_t) ((0x4 << 0x4) | Utils::getGroup (firstWord)), + (uint8_t) ((firstWord >> 0x10) & 0xff), + (uint8_t) ((firstWord >> 0x08) & 0x7f), + (uint8_t) ((firstWord >> 0x00) & 0x7f), + }; + + switch (Utils::getStatus (firstWord)) + { + case 0x8: + case 0x9: + { + const auto packet = processNoteOnOrOff (helperValues); + callback (View (packet.data())); + return; + } + + case 0xa: + { + const auto packet = processPolyPressure (helperValues); + callback (View (packet.data())); + return; + } + + case 0xb: + { + PacketX2 packet; + + if (processControlChange (helperValues, packet)) + callback (View (packet.data())); + + return; + } + + case 0xc: + { + const auto packet = processProgramChange (helperValues); + callback (View (packet.data())); + return; + } + + case 0xd: + { + const auto packet = processChannelPressure (helperValues); + callback (View (packet.data())); + return; + } + + case 0xe: + { + const auto packet = processPitchBend (helperValues); + callback (View (packet.data())); + return; + } + } + } + + void reset() + { + groupAccumulators = {}; + groupBanks = {}; + } + +private: + enum class PnKind { nrpn, rpn }; + + struct HelperValues + { + uint8_t typeAndGroup; + uint8_t byte0; + uint8_t byte1; + uint8_t byte2; + }; + + static PacketX2 processNoteOnOrOff (const HelperValues helpers); + static PacketX2 processPolyPressure (const HelperValues helpers); + + bool processControlChange (const HelperValues helpers, PacketX2& packet); + + PacketX2 processProgramChange (const HelperValues helpers) const; + + static PacketX2 processChannelPressure (const HelperValues helpers); + static PacketX2 processPitchBend (const HelperValues helpers); + + class PnAccumulator + { + public: + bool addByte (uint8_t cc, uint8_t byte); + + const std::array& getBytes() const noexcept { return bytes; } + PnKind getKind() const noexcept { return kind; } + + private: + std::array bytes; + uint8_t index = 0; + PnKind kind = PnKind::nrpn; + }; + + class Bank + { + public: + bool isValid() const noexcept { return ! (msb & 0x80); } + + uint8_t getMsb() const noexcept { return msb & 0x7f; } + uint8_t getLsb() const noexcept { return lsb & 0x7f; } + + void setMsb (uint8_t i) noexcept { msb = i & 0x7f; } + void setLsb (uint8_t i) noexcept { msb &= 0x7f; lsb = i & 0x7f; } + + private: + // We use the top bit to indicate whether this bank is valid. + // After reading the spec, it's not clear how we should determine whether + // there are valid values, so we'll just assume that the bank is valid + // once either the lsb or msb have been written. + uint8_t msb = 0x80; + uint8_t lsb = 0x00; + }; + + using ChannelAccumulators = std::array; + std::array groupAccumulators; + + using ChannelBanks = std::array; + std::array groupBanks; +}; + +} +} + +#endif diff --git a/JuceLibraryCode/modules/juce_core/native/juce_mac_ClangBugWorkaround.h b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPProtocols.h similarity index 60% rename from JuceLibraryCode/modules/juce_core/native/juce_mac_ClangBugWorkaround.h rename to JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPProtocols.h index 3bbee9ae..2e6df208 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_mac_ClangBugWorkaround.h +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPProtocols.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -20,16 +20,29 @@ ============================================================================== */ +#ifndef DOXYGEN -// This hack is a workaround for a bug (?) in Apple's 10.11 SDK headers -// which cause some configurations of Clang to throw out a spurious error.. -#if JUCE_PROJUCER_LIVE_BUILD && (defined (__APPLE_CPP__) || defined(__APPLE_CC__)) - #include - #undef CF_OPTIONS - #define CF_OPTIONS(_type, _name) _type _name; enum +namespace juce +{ +namespace universal_midi_packets +{ + +/** The kinds of MIDI protocol that can be formatted into Universal MIDI Packets. */ +enum class PacketProtocol +{ + MIDI_1_0, + MIDI_2_0, +}; + +/** All kinds of MIDI protocol understood by JUCE. */ +enum class MidiProtocol +{ + bytestream, + UMP_MIDI_1_0, + UMP_MIDI_2_0, +}; + +} +} - // This is a workaround for the Xcode 9 version of NSUUID.h causing some errors - // in the live-build engine. - #define _Nullable - #define _Nonnull #endif diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPReceiver.h b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPReceiver.h new file mode 100644 index 00000000..46785734 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPReceiver.h @@ -0,0 +1,46 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#ifndef DOXYGEN + +namespace juce +{ +namespace universal_midi_packets +{ + +/** + A base class for classes which receive Universal MIDI Packets from an input. + + @tags{Audio} +*/ +struct Receiver +{ + virtual ~Receiver() noexcept = default; + + /** This will be called each time a new packet is ready for processing. */ + virtual void packetReceived (const View& packet, double time) = 0; +}; + +} +} + +#endif diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.cpp b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.cpp new file mode 100644 index 00000000..a5fdf190 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.cpp @@ -0,0 +1,53 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ +namespace universal_midi_packets +{ + +uint32_t SysEx7::getNumPacketsRequiredForDataSize (uint32_t size) +{ + constexpr auto denom = 6; + return (size / denom) + ((size % denom) != 0); +} + +SysEx7::PacketBytes SysEx7::getDataBytes (const PacketX2& packet) +{ + const auto numBytes = Utils::getChannel (packet[0]); + constexpr uint8_t maxBytes = 6; + jassert (numBytes <= maxBytes); + + return + { + { { packet.getU8<2>(), + packet.getU8<3>(), + packet.getU8<4>(), + packet.getU8<5>(), + packet.getU8<6>(), + packet.getU8<7>() } }, + jmin (numBytes, maxBytes) + }; +} + +} +} diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.h b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.h new file mode 100644 index 00000000..be73c172 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.h @@ -0,0 +1,77 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#ifndef DOXYGEN + +namespace juce +{ +namespace universal_midi_packets +{ + +/** + This struct acts as a single-file namespace for Universal MIDI Packet + functionality related to 7-bit SysEx. + + @tags{Audio} +*/ +struct SysEx7 +{ + /** Returns the number of 64-bit packets required to hold a series of + SysEx bytes. + + The number passed to this function should exclude the leading/trailing + SysEx bytes used in an old midi bytestream, as these are not required + when using Universal MIDI Packets. + */ + static uint32_t getNumPacketsRequiredForDataSize (uint32_t); + + /** The different kinds of UMP SysEx-7 message. */ + enum class Kind : uint8_t + { + /** The whole message fits in a single 2-word packet. */ + complete = 0, + + /** The packet begins a SysEx message that will continue in subsequent packets. */ + begin = 1, + + /** The packet is a continuation of an ongoing SysEx message. */ + continuation = 2, + + /** The packet terminates an ongoing SysEx message. */ + end = 3 + }; + + /** Holds the bytes from a single SysEx-7 packet. */ + struct PacketBytes + { + std::array data; + uint8_t size; + }; + + /** Extracts the data bytes from a 64-bit data message. */ + static PacketBytes getDataBytes (const PacketX2& packet); +}; + +} +} + +#endif diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPTests.cpp b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPTests.cpp new file mode 100644 index 00000000..c732a75f --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPTests.cpp @@ -0,0 +1,1018 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ +namespace universal_midi_packets +{ + +constexpr uint8_t operator""_u8 (unsigned long long int i) { return static_cast (i); } +constexpr uint16_t operator""_u16 (unsigned long long int i) { return static_cast (i); } +constexpr uint32_t operator""_u32 (unsigned long long int i) { return static_cast (i); } +constexpr uint64_t operator""_u64 (unsigned long long int i) { return static_cast (i); } + +class UniversalMidiPacketTests : public UnitTest +{ +public: + UniversalMidiPacketTests() + : UnitTest ("Universal MIDI Packet", UnitTestCategories::midi) + { + } + + void runTest() override + { + auto random = getRandom(); + + beginTest ("Short bytestream midi messages can be round-tripped through the UMP converter"); + { + Midi1ToBytestreamTranslator translator (0); + + forEachNonSysExTestMessage (random, [&] (const MidiMessage& m) + { + Packets packets; + Conversion::toMidi1 (m, packets); + expect (packets.size() == 1); + + // Make sure that the message type is correct + expect (Utils::getMessageType (packets.data()[0]) == ((m.getRawData()[0] >> 0x4) == 0xf ? 0x1 : 0x2)); + + translator.dispatch (View {packets.data() }, + 0, + [&] (const MidiMessage& roundTripped) + { + expect (equal (m, roundTripped)); + }); + }); + } + + beginTest ("Bytestream SysEx converts to universal packets"); + { + { + // Zero length message + Packets packets; + Conversion::toMidi1 (createRandomSysEx (random, 0), packets); + expect (packets.size() == 2); + + expect (packets.data()[0] == 0x30000000); + expect (packets.data()[1] == 0x00000000); + } + + { + const auto message = createRandomSysEx (random, 1); + Packets packets; + Conversion::toMidi1 (message, packets); + expect (packets.size() == 2); + + const auto* sysEx = message.getSysExData(); + expect (packets.data()[0] == Utils::bytesToWord (0x30, 0x01, sysEx[0], 0)); + expect (packets.data()[1] == 0x00000000); + } + + { + const auto message = createRandomSysEx (random, 6); + Packets packets; + Conversion::toMidi1 (message, packets); + expect (packets.size() == 2); + + const auto* sysEx = message.getSysExData(); + expect (packets.data()[0] == Utils::bytesToWord (0x30, 0x06, sysEx[0], sysEx[1])); + expect (packets.data()[1] == Utils::bytesToWord (sysEx[2], sysEx[3], sysEx[4], sysEx[5])); + } + + { + const auto message = createRandomSysEx (random, 12); + Packets packets; + Conversion::toMidi1 (message, packets); + expect (packets.size() == 4); + + const auto* sysEx = message.getSysExData(); + expect (packets.data()[0] == Utils::bytesToWord (0x30, 0x16, sysEx[0], sysEx[1])); + expect (packets.data()[1] == Utils::bytesToWord (sysEx[2], sysEx[3], sysEx[4], sysEx[5])); + expect (packets.data()[2] == Utils::bytesToWord (0x30, 0x36, sysEx[6], sysEx[7])); + expect (packets.data()[3] == Utils::bytesToWord (sysEx[8], sysEx[9], sysEx[10], sysEx[11])); + } + + { + const auto message = createRandomSysEx (random, 13); + Packets packets; + Conversion::toMidi1 (message, packets); + expect (packets.size() == 6); + + const auto* sysEx = message.getSysExData(); + expect (packets.data()[0] == Utils::bytesToWord (0x30, 0x16, sysEx[0], sysEx[1])); + expect (packets.data()[1] == Utils::bytesToWord (sysEx[2], sysEx[3], sysEx[4], sysEx[5])); + expect (packets.data()[2] == Utils::bytesToWord (0x30, 0x26, sysEx[6], sysEx[7])); + expect (packets.data()[3] == Utils::bytesToWord (sysEx[8], sysEx[9], sysEx[10], sysEx[11])); + expect (packets.data()[4] == Utils::bytesToWord (0x30, 0x31, sysEx[12], 0)); + expect (packets.data()[5] == 0x00000000); + } + } + + ToBytestreamDispatcher converter (0); + Packets packets; + + const auto checkRoundTrip = [&] (const MidiBuffer& expected) + { + for (const auto meta : expected) + Conversion::toMidi1 (meta.getMessage(), packets); + + MidiBuffer output; + converter.dispatch (packets.data(), + packets.data() + packets.size(), + 0, + [&] (const MidiMessage& roundTripped) + { + output.addEvent (roundTripped, int (roundTripped.getTimeStamp())); + }); + packets.clear(); + + expect (equal (expected, output)); + }; + + beginTest ("Long SysEx bytestream midi messages can be round-tripped through the UMP converter"); + { + for (auto length : { 0, 1, 2, 3, 4, 5, 6, 7, 13, 20, 100, 1000 }) + { + MidiBuffer expected; + expected.addEvent (createRandomSysEx (random, size_t (length)), 0); + checkRoundTrip (expected); + } + } + + beginTest ("UMP SysEx7 messages interspersed with utility messages convert to bytestream"); + { + const auto sysEx = createRandomSysEx (random, 100); + Packets originalPackets; + Conversion::toMidi1 (sysEx, originalPackets); + + Packets modifiedPackets; + + const auto addRandomUtilityUMP = [&] + { + const auto newPacket = createRandomUtilityUMP (random); + modifiedPackets.add (View (newPacket.data())); + }; + + for (const auto& packet : originalPackets) + { + addRandomUtilityUMP(); + modifiedPackets.add (packet); + addRandomUtilityUMP(); + } + + MidiBuffer output; + converter.dispatch (modifiedPackets.data(), + modifiedPackets.data() + modifiedPackets.size(), + 0, + [&] (const MidiMessage& roundTripped) + { + output.addEvent (roundTripped, int (roundTripped.getTimeStamp())); + }); + + // All Utility messages should have been ignored + expect (output.getNumEvents() == 1); + + for (const auto meta : output) + expect (equal (meta.getMessage(), sysEx)); + } + + beginTest ("UMP SysEx7 messages interspersed with System Realtime messages convert to bytestream"); + { + const auto sysEx = createRandomSysEx (random, 200); + Packets originalPackets; + Conversion::toMidi1 (sysEx, originalPackets); + + Packets modifiedPackets; + MidiBuffer realtimeMessages; + + const auto addRandomRealtimeUMP = [&] + { + const auto newPacket = createRandomRealtimeUMP (random); + modifiedPackets.add (View (newPacket.data())); + realtimeMessages.addEvent (Midi1ToBytestreamTranslator::fromUmp (newPacket), 0); + }; + + for (const auto& packet : originalPackets) + { + addRandomRealtimeUMP(); + modifiedPackets.add (packet); + addRandomRealtimeUMP(); + } + + MidiBuffer output; + converter.dispatch (modifiedPackets.data(), + modifiedPackets.data() + modifiedPackets.size(), + 0, + [&] (const MidiMessage& roundTripped) + { + output.addEvent (roundTripped, int (roundTripped.getTimeStamp())); + }); + + const auto numOutputs = output.getNumEvents(); + const auto numInputs = realtimeMessages.getNumEvents(); + expect (numOutputs == numInputs + 1); + + if (numOutputs == numInputs + 1) + { + const auto isMetadataEquivalent = [] (const MidiMessageMetadata& a, + const MidiMessageMetadata& b) + { + return equal (a.getMessage(), b.getMessage()); + }; + + auto it = output.begin(); + + for (const auto meta : realtimeMessages) + { + if (! isMetadataEquivalent (*it, meta)) + { + expect (equal ((*it).getMessage(), sysEx)); + ++it; + } + + expect (isMetadataEquivalent (*it, meta)); + ++it; + } + } + } + + beginTest ("UMP SysEx7 messages interspersed with System Realtime and Utility messages convert to bytestream"); + { + const auto sysEx = createRandomSysEx (random, 300); + Packets originalPackets; + Conversion::toMidi1 (sysEx, originalPackets); + + Packets modifiedPackets; + MidiBuffer realtimeMessages; + + const auto addRandomRealtimeUMP = [&] + { + const auto newPacket = createRandomRealtimeUMP (random); + modifiedPackets.add (View (newPacket.data())); + realtimeMessages.addEvent (Midi1ToBytestreamTranslator::fromUmp (newPacket), 0); + }; + + const auto addRandomUtilityUMP = [&] + { + const auto newPacket = createRandomUtilityUMP (random); + modifiedPackets.add (View (newPacket.data())); + }; + + for (const auto& packet : originalPackets) + { + addRandomRealtimeUMP(); + addRandomUtilityUMP(); + modifiedPackets.add (packet); + addRandomRealtimeUMP(); + addRandomUtilityUMP(); + } + + MidiBuffer output; + converter.dispatch (modifiedPackets.data(), + modifiedPackets.data() + modifiedPackets.size(), + 0, + [&] (const MidiMessage& roundTripped) + { + output.addEvent (roundTripped, int (roundTripped.getTimeStamp())); + }); + + const auto numOutputs = output.getNumEvents(); + const auto numInputs = realtimeMessages.getNumEvents(); + expect (numOutputs == numInputs + 1); + + if (numOutputs == numInputs + 1) + { + const auto isMetadataEquivalent = [] (const MidiMessageMetadata& a, const MidiMessageMetadata& b) + { + return equal (a.getMessage(), b.getMessage()); + }; + + auto it = output.begin(); + + for (const auto meta : realtimeMessages) + { + if (! isMetadataEquivalent (*it, meta)) + { + expect (equal ((*it).getMessage(), sysEx)); + ++it; + } + + expect (isMetadataEquivalent (*it, meta)); + ++it; + } + } + } + + beginTest ("SysEx messages are terminated by non-Utility, non-Realtime messages"); + { + const auto noteOn = [&] + { + MidiBuffer b; + b.addEvent (MidiMessage::noteOn (1, uint8_t (64), uint8_t (64)), 0); + return b; + }(); + + const auto noteOnPackets = [&] + { + Packets p; + + for (const auto meta : noteOn) + Conversion::toMidi1 (meta.getMessage(), p); + + return p; + }(); + + const auto sysEx = createRandomSysEx (random, 300); + + const auto originalPackets = [&] + { + Packets p; + Conversion::toMidi1 (sysEx, p); + return p; + }(); + + const auto modifiedPackets = [&] + { + Packets p; + + const auto insertionPoint = std::next (originalPackets.begin(), 10); + std::for_each (originalPackets.begin(), + insertionPoint, + [&] (const View& view) { p.add (view); }); + + for (const auto& view : noteOnPackets) + p.add (view); + + std::for_each (insertionPoint, + originalPackets.end(), + [&] (const View& view) { p.add (view); }); + + return p; + }(); + + // modifiedPackets now contains some SysEx packets interrupted by a MIDI 1 noteOn + + MidiBuffer output; + + const auto pushToOutput = [&] (const Packets& p) + { + converter.dispatch (p.data(), + p.data() + p.size(), + 0, + [&] (const MidiMessage& roundTripped) + { + output.addEvent (roundTripped, int (roundTripped.getTimeStamp())); + }); + }; + + pushToOutput (modifiedPackets); + + // Interrupted sysEx shouldn't be present + expect (equal (output, noteOn)); + + const auto newSysEx = createRandomSysEx (random, 300); + Packets newSysExPackets; + Conversion::toMidi1 (newSysEx, newSysExPackets); + + // If we push another midi event without interrupting it, + // it should get through without being modified, + // and it shouldn't be affected by the previous (interrupted) sysex. + + output.clear(); + pushToOutput (newSysExPackets); + + expect (output.getNumEvents() == 1); + + for (const auto meta : output) + expect (equal (meta.getMessage(), newSysEx)); + } + + beginTest ("Widening conversions work"); + { + // This is similar to the 'slow' example code from the MIDI 2.0 spec + const auto baselineScale = [] (uint32_t srcVal, uint32_t srcBits, uint32_t dstBits) + { + const auto scaleBits = (uint32_t) (dstBits - srcBits); + + auto bitShiftedValue = (uint32_t) (srcVal << scaleBits); + + const auto srcCenter = (uint32_t) (1 << (srcBits - 1)); + + if (srcVal <= srcCenter) + return bitShiftedValue; + + const auto repeatBits = (uint32_t) (srcBits - 1); + const auto repeatMask = (uint32_t) ((1 << repeatBits) - 1); + + auto repeatValue = (uint32_t) (srcVal & repeatMask); + + if (scaleBits > repeatBits) + repeatValue <<= scaleBits - repeatBits; + else + repeatValue >>= repeatBits - scaleBits; + + while (repeatValue != 0) + { + bitShiftedValue |= repeatValue; + repeatValue >>= repeatBits; + } + + return bitShiftedValue; + }; + + const auto baselineScale7To8 = [&] (uint8_t in) + { + return baselineScale (in, 7, 8); + }; + + const auto baselineScale7To16 = [&] (uint8_t in) + { + return baselineScale (in, 7, 16); + }; + + const auto baselineScale14To16 = [&] (uint16_t in) + { + return baselineScale (in, 14, 16); + }; + + const auto baselineScale7To32 = [&] (uint8_t in) + { + return baselineScale (in, 7, 32); + }; + + const auto baselineScale14To32 = [&] (uint16_t in) + { + return baselineScale (in, 14, 32); + }; + + for (auto i = 0; i != 100; ++i) + { + const auto rand = (uint8_t) random.nextInt (0x80); + expectEquals ((int64_t) Conversion::scaleTo8 (rand), + (int64_t) baselineScale7To8 (rand)); + } + + expectEquals ((int64_t) Conversion::scaleTo16 ((uint8_t) 0x00), (int64_t) 0x0000); + expectEquals ((int64_t) Conversion::scaleTo16 ((uint8_t) 0x0a), (int64_t) 0x1400); + expectEquals ((int64_t) Conversion::scaleTo16 ((uint8_t) 0x40), (int64_t) 0x8000); + expectEquals ((int64_t) Conversion::scaleTo16 ((uint8_t) 0x57), (int64_t) 0xaeba); + expectEquals ((int64_t) Conversion::scaleTo16 ((uint8_t) 0x7f), (int64_t) 0xffff); + + for (auto i = 0; i != 100; ++i) + { + const auto rand = (uint8_t) random.nextInt (0x80); + expectEquals ((int64_t) Conversion::scaleTo16 (rand), + (int64_t) baselineScale7To16 (rand)); + } + + for (auto i = 0; i != 100; ++i) + { + const auto rand = (uint16_t) random.nextInt (0x4000); + expectEquals ((int64_t) Conversion::scaleTo16 (rand), + (int64_t) baselineScale14To16 (rand)); + } + + for (auto i = 0; i != 100; ++i) + { + const auto rand = (uint8_t) random.nextInt (0x80); + expectEquals ((int64_t) Conversion::scaleTo32 (rand), + (int64_t) baselineScale7To32 (rand)); + } + + expectEquals ((int64_t) Conversion::scaleTo32 ((uint16_t) 0x0000), (int64_t) 0x00000000); + expectEquals ((int64_t) Conversion::scaleTo32 ((uint16_t) 0x2000), (int64_t) 0x80000000); + expectEquals ((int64_t) Conversion::scaleTo32 ((uint16_t) 0x3fff), (int64_t) 0xffffffff); + + for (auto i = 0; i != 100; ++i) + { + const auto rand = (uint16_t) random.nextInt (0x4000); + expectEquals ((int64_t) Conversion::scaleTo32 (rand), + (int64_t) baselineScale14To32 (rand)); + } + } + + beginTest ("Round-trip widening/narrowing conversions work"); + { + for (auto i = 0; i != 100; ++i) + { + { + const auto rand = (uint8_t) random.nextInt (0x80); + expectEquals (Conversion::scaleTo7 (Conversion::scaleTo8 (rand)), rand); + } + + { + const auto rand = (uint8_t) random.nextInt (0x80); + expectEquals (Conversion::scaleTo7 (Conversion::scaleTo16 (rand)), rand); + } + + { + const auto rand = (uint8_t) random.nextInt (0x80); + expectEquals (Conversion::scaleTo7 (Conversion::scaleTo32 (rand)), rand); + } + + { + const auto rand = (uint16_t) random.nextInt (0x4000); + expectEquals ((uint64_t) Conversion::scaleTo14 (Conversion::scaleTo16 (rand)), (uint64_t) rand); + } + + { + const auto rand = (uint16_t) random.nextInt (0x4000); + expectEquals ((uint64_t) Conversion::scaleTo14 (Conversion::scaleTo32 (rand)), (uint64_t) rand); + } + } + } + + beginTest ("MIDI 2 -> 1 note on conversions"); + { + { + Packets midi2; + midi2.add (PacketX2 { 0x41946410, 0x12345678 }); + + Packets midi1; + midi1.add (PacketX1 { 0x21946409 }); + + checkMidi2ToMidi1Conversion (midi2, midi1); + } + + { + // If the velocity is close to 0, the output velocity should still be 1 + Packets midi2; + midi2.add (PacketX2 { 0x4295327f, 0x00345678 }); + + Packets midi1; + midi1.add (PacketX1 { 0x22953201 }); + + checkMidi2ToMidi1Conversion (midi2, midi1); + } + } + + beginTest ("MIDI 2 -> 1 note off conversion"); + { + Packets midi2; + midi2.add (PacketX2 { 0x448b0520, 0xfedcba98 }); + + Packets midi1; + midi1.add (PacketX1 { 0x248b057f }); + + checkMidi2ToMidi1Conversion (midi2, midi1); + } + + beginTest ("MIDI 2 -> 1 poly pressure conversion"); + { + Packets midi2; + midi2.add (PacketX2 { 0x49af0520, 0x80dcba98 }); + + Packets midi1; + midi1.add (PacketX1 { 0x29af0540 }); + + checkMidi2ToMidi1Conversion (midi2, midi1); + } + + beginTest ("MIDI 2 -> 1 control change conversion"); + { + Packets midi2; + midi2.add (PacketX2 { 0x49b00520, 0x80dcba98 }); + + Packets midi1; + midi1.add (PacketX1 { 0x29b00540 }); + + checkMidi2ToMidi1Conversion (midi2, midi1); + } + + beginTest ("MIDI 2 -> 1 channel pressure conversion"); + { + Packets midi2; + midi2.add (PacketX2 { 0x40d20520, 0x80dcba98 }); + + Packets midi1; + midi1.add (PacketX1 { 0x20d24000 }); + + checkMidi2ToMidi1Conversion (midi2, midi1); + } + + beginTest ("MIDI 2 -> 1 nrpn rpn conversion"); + { + { + Packets midi2; + midi2.add (PacketX2 { 0x44240123, 0x456789ab }); + + Packets midi1; + midi1.add (PacketX1 { 0x24b46501 }); + midi1.add (PacketX1 { 0x24b46423 }); + midi1.add (PacketX1 { 0x24b40622 }); + midi1.add (PacketX1 { 0x24b42659 }); + + checkMidi2ToMidi1Conversion (midi2, midi1); + } + + { + Packets midi2; + midi2.add (PacketX2 { 0x48347f7f, 0xffffffff }); + + Packets midi1; + midi1.add (PacketX1 { 0x28b4637f }); + midi1.add (PacketX1 { 0x28b4627f }); + midi1.add (PacketX1 { 0x28b4067f }); + midi1.add (PacketX1 { 0x28b4267f }); + + checkMidi2ToMidi1Conversion (midi2, midi1); + } + } + + beginTest ("MIDI 2 -> 1 program change and bank select conversion"); + { + { + // If the bank valid bit is 0, just emit a program change + Packets midi2; + midi2.add (PacketX2 { 0x4cc10000, 0x70004020 }); + + Packets midi1; + midi1.add (PacketX1 { 0x2cc17000 }); + + checkMidi2ToMidi1Conversion (midi2, midi1); + } + + { + // If the bank valid bit is 1, emit bank select control changes and a program change + Packets midi2; + midi2.add (PacketX2 { 0x4bc20001, 0x70004020 }); + + Packets midi1; + midi1.add (PacketX1 { 0x2bb20040 }); + midi1.add (PacketX1 { 0x2bb22020 }); + midi1.add (PacketX1 { 0x2bc27000 }); + + checkMidi2ToMidi1Conversion (midi2, midi1); + } + } + + beginTest ("MIDI 2 -> 1 pitch bend conversion"); + { + Packets midi2; + midi2.add (PacketX2 { 0x4eee0000, 0x12340000 }); + + Packets midi1; + midi1.add (PacketX1 { 0x2eee0d09 }); + + checkMidi2ToMidi1Conversion (midi2, midi1); + } + + beginTest ("MIDI 2 -> 1 messages which don't convert"); + { + const uint8_t opcodes[] { 0x0, 0x1, 0x4, 0x5, 0x6, 0xf }; + + for (const auto opcode : opcodes) + { + Packets midi2; + midi2.add (PacketX2 { Utils::bytesToWord (0x40, (uint8_t) (opcode << 0x4), 0, 0), 0x0 }); + checkMidi2ToMidi1Conversion (midi2, {}); + } + } + + beginTest ("MIDI 2 -> 1 messages which are passed through"); + { + const uint8_t typecodesX1[] { 0x0, 0x1, 0x2 }; + + for (const auto typecode : typecodesX1) + { + Packets p; + p.add (PacketX1 { (uint32_t) ((int64_t) typecode << 0x1c | (random.nextInt64() & 0xffffff)) }); + + checkMidi2ToMidi1Conversion (p, p); + } + + { + Packets p; + p.add (PacketX2 { (uint32_t) (0x3 << 0x1c | (random.nextInt64() & 0xffffff)), + (uint32_t) (random.nextInt64() & 0xffffffff) }); + + checkMidi2ToMidi1Conversion (p, p); + } + + { + Packets p; + p.add (PacketX4 { (uint32_t) (0x5 << 0x1c | (random.nextInt64() & 0xffffff)), + (uint32_t) (random.nextInt64() & 0xffffffff), + (uint32_t) (random.nextInt64() & 0xffffffff), + (uint32_t) (random.nextInt64() & 0xffffffff) }); + + checkMidi2ToMidi1Conversion (p, p); + } + } + + beginTest ("MIDI 2 -> 1 control changes which should be ignored"); + { + const uint8_t CCs[] { 6, 38, 98, 99, 100, 101, 0, 32 }; + + for (const auto cc : CCs) + { + Packets midi2; + midi2.add (PacketX2 { (uint32_t) (0x40b00000 | (cc << 0x8)), 0x00000000 }); + + checkMidi2ToMidi1Conversion (midi2, {}); + } + } + + beginTest ("MIDI 1 -> 2 note on conversions"); + { + { + Packets midi1; + midi1.add (PacketX1 { 0x20904040 }); + + Packets midi2; + midi2.add (PacketX2 { 0x40904000, static_cast (Conversion::scaleTo16 (0x40_u8)) << 0x10 }); + + checkMidi1ToMidi2Conversion (midi1, midi2); + } + + // If velocity is 0, convert to a note-off + { + Packets midi1; + midi1.add (PacketX1 { 0x23935100 }); + + Packets midi2; + midi2.add (PacketX2 { 0x43835100, 0x0 }); + + checkMidi1ToMidi2Conversion (midi1, midi2); + } + } + + beginTest ("MIDI 1 -> 2 note off conversions"); + { + Packets midi1; + midi1.add (PacketX1 { 0x21831020 }); + + Packets midi2; + midi2.add (PacketX2 { 0x41831000, static_cast (Conversion::scaleTo16 (0x20_u8)) << 0x10 }); + + checkMidi1ToMidi2Conversion (midi1, midi2); + } + + beginTest ("MIDI 1 -> 2 poly pressure conversions"); + { + Packets midi1; + midi1.add (PacketX1 { 0x20af7330 }); + + Packets midi2; + midi2.add (PacketX2 { 0x40af7300, Conversion::scaleTo32 (0x30_u8) }); + + checkMidi1ToMidi2Conversion (midi1, midi2); + } + + beginTest ("individual MIDI 1 -> 2 control changes which should be ignored"); + { + const uint8_t CCs[] { 6, 38, 98, 99, 100, 101, 0, 32 }; + + for (const auto cc : CCs) + { + Packets midi1; + midi1.add (PacketX1 { Utils::bytesToWord (0x20, 0xb0, cc, 0x00) }); + + checkMidi1ToMidi2Conversion (midi1, {}); + } + } + + beginTest ("MIDI 1 -> 2 control change conversions"); + { + // normal control change + { + Packets midi1; + midi1.add (PacketX1 { 0x29b1017f }); + + Packets midi2; + midi2.add (PacketX2 { 0x49b10100, Conversion::scaleTo32 (0x7f_u8) }); + + checkMidi1ToMidi2Conversion (midi1, midi2); + } + + // nrpn + { + Packets midi1; + midi1.add (PacketX1 { 0x20b06301 }); + midi1.add (PacketX1 { 0x20b06223 }); + midi1.add (PacketX1 { 0x20b00645 }); + midi1.add (PacketX1 { 0x20b02667 }); + + Packets midi2; + midi2.add (PacketX2 { 0x40300123, Conversion::scaleTo32 (static_cast ((0x45 << 7) | 0x67)) }); + + checkMidi1ToMidi2Conversion (midi1, midi2); + } + + // rpn + { + Packets midi1; + midi1.add (PacketX1 { 0x20b06543 }); + midi1.add (PacketX1 { 0x20b06421 }); + midi1.add (PacketX1 { 0x20b00601 }); + midi1.add (PacketX1 { 0x20b02623 }); + + Packets midi2; + midi2.add (PacketX2 { 0x40204321, Conversion::scaleTo32 (static_cast ((0x01 << 7) | 0x23)) }); + + checkMidi1ToMidi2Conversion (midi1, midi2); + } + } + + beginTest ("MIDI 1 -> MIDI 2 program change and bank select"); + { + Packets midi1; + // program change with bank + midi1.add (PacketX1 { 0x2bb20030 }); + midi1.add (PacketX1 { 0x2bb22010 }); + midi1.add (PacketX1 { 0x2bc24000 }); + // program change without bank (different group and channel) + midi1.add (PacketX1 { 0x20c01000 }); + + Packets midi2; + midi2.add (PacketX2 { 0x4bc20001, 0x40003010 }); + midi2.add (PacketX2 { 0x40c00000, 0x10000000 }); + + checkMidi1ToMidi2Conversion (midi1, midi2); + } + + beginTest ("MIDI 1 -> MIDI 2 channel pressure conversions"); + { + Packets midi1; + midi1.add (PacketX1 { 0x20df3000 }); + + Packets midi2; + midi2.add (PacketX2 { 0x40df0000, Conversion::scaleTo32 (0x30_u8) }); + + checkMidi1ToMidi2Conversion (midi1, midi2); + } + + beginTest ("MIDI 1 -> MIDI 2 pitch bend conversions"); + { + Packets midi1; + midi1.add (PacketX1 { 0x20e74567 }); + + Packets midi2; + midi2.add (PacketX2 { 0x40e70000, Conversion::scaleTo32 (static_cast ((0x67 << 7) | 0x45)) }); + + checkMidi1ToMidi2Conversion (midi1, midi2); + } + } + +private: + static Packets convertMidi2ToMidi1 (const Packets& midi2) + { + Packets r; + + for (const auto& packet : midi2) + Conversion::midi2ToMidi1DefaultTranslation (packet, [&r] (const View& v) { r.add (v); }); + + return r; + } + + static Packets convertMidi1ToMidi2 (const Packets& midi1) + { + Packets r; + Midi1ToMidi2DefaultTranslator translator; + + for (const auto& packet : midi1) + translator.dispatch (packet, [&r] (const View& v) { r.add (v); }); + + return r; + } + + void checkBytestreamConversion (const Packets& actual, const Packets& expected) + { + expectEquals ((int) actual.size(), (int) expected.size()); + + if (actual.size() != expected.size()) + return; + + auto actualPtr = actual.data(); + + std::for_each (expected.data(), + expected.data() + expected.size(), + [&] (const uint32_t word) { expectEquals ((uint64_t) *actualPtr++, (uint64_t) word); }); + } + + void checkMidi2ToMidi1Conversion (const Packets& midi2, const Packets& expected) + { + checkBytestreamConversion (convertMidi2ToMidi1 (midi2), expected); + } + + void checkMidi1ToMidi2Conversion (const Packets& midi1, const Packets& expected) + { + checkBytestreamConversion (convertMidi1ToMidi2 (midi1), expected); + } + + MidiMessage createRandomSysEx (Random& random, size_t sysExBytes) + { + std::vector data; + data.reserve (sysExBytes); + + for (size_t i = 0; i != sysExBytes; ++i) + data.push_back (uint8_t (random.nextInt (0x80))); + + return MidiMessage::createSysExMessage (data.data(), int (data.size())); + } + + PacketX1 createRandomUtilityUMP (Random& random) + { + const auto status = random.nextInt (3); + + return PacketX1 { Utils::bytesToWord (0, + uint8_t (status << 0x4), + uint8_t (status == 0 ? 0 : random.nextInt (0x100)), + uint8_t (status == 0 ? 0 : random.nextInt (0x100))) }; + } + + PacketX1 createRandomRealtimeUMP (Random& random) + { + const auto status = [&] + { + switch (random.nextInt (6)) + { + case 0: return 0xf8; + case 1: return 0xfa; + case 2: return 0xfb; + case 3: return 0xfc; + case 4: return 0xfe; + case 5: return 0xff; + } + + jassertfalse; + return 0x00; + }(); + + return PacketX1 { Utils::bytesToWord (0x10, uint8_t (status), 0x00, 0x00) }; + } + + template + void forEachNonSysExTestMessage (Random& random, Fn&& fn) + { + for (uint16_t counter = 0x80; counter != 0x100; ++counter) + { + const auto firstByte = (uint8_t) counter; + + if (firstByte == 0xf0 || firstByte == 0xf7) + continue; // sysEx is tested separately + + const auto length = MidiMessage::getMessageLengthFromFirstByte (firstByte); + const auto getDataByte = [&] { return uint8_t (random.nextInt (256) & 0x7f); }; + + const auto message = [&] + { + switch (length) + { + case 1: return MidiMessage (firstByte); + case 2: return MidiMessage (firstByte, getDataByte()); + case 3: return MidiMessage (firstByte, getDataByte(), getDataByte()); + } + + return MidiMessage(); + }(); + + fn (message); + } + } + + #if JUCE_WINDOWS && ! JUCE_MINGW + #define JUCE_CHECKED_ITERATOR(msg, size) \ + stdext::checked_array_iterator::type> ((msg), (size_t) (size)) + #else + #define JUCE_CHECKED_ITERATOR(msg, size) (msg) + #endif + + static bool equal (const MidiMessage& a, const MidiMessage& b) noexcept + { + return a.getRawDataSize() == b.getRawDataSize() + && std::equal (a.getRawData(), a.getRawData() + a.getRawDataSize(), + JUCE_CHECKED_ITERATOR (b.getRawData(), b.getRawDataSize())); + } + + #undef JUCE_CHECKED_ITERATOR + + static bool equal (const MidiBuffer& a, const MidiBuffer& b) noexcept + { + return a.data == b.data; + } +}; + +static UniversalMidiPacketTests universalMidiPacketTests; + +} +} diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPUtils.cpp b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPUtils.cpp new file mode 100644 index 00000000..166c4bfa --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPUtils.cpp @@ -0,0 +1,59 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ +namespace universal_midi_packets +{ + +uint32_t Utils::getNumWordsForMessageType (uint32_t mt) +{ + switch (Utils::getMessageType (mt)) + { + case 0x0: + case 0x1: + case 0x2: + case 0x6: + case 0x7: + return 1; + case 0x3: + case 0x4: + case 0x8: + case 0x9: + case 0xa: + return 2; + case 0xb: + case 0xc: + return 3; + case 0x5: + case 0xd: + case 0xe: + case 0xf: + return 4; + } + + jassertfalse; + return 1; +} + +} +} diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPUtils.h b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPUtils.h new file mode 100644 index 00000000..d55d9cb1 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPUtils.h @@ -0,0 +1,117 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#ifndef DOXYGEN + +namespace juce +{ +namespace universal_midi_packets +{ + +/** + Helpful types and functions for interacting with Universal MIDI Packets. + + @tags{Audio} +*/ +struct Utils +{ + /** Joins 4 bytes into a single 32-bit word. */ + static constexpr uint32_t bytesToWord (uint8_t a, uint8_t b, uint8_t c, uint8_t d) + { + return uint32_t (a << 0x18 | b << 0x10 | c << 0x08 | d << 0x00); + } + + /** Returns the expected number of 32-bit words in a Universal MIDI Packet, given + the first word of the packet. + + The result will be between 1 and 4 inclusive. + A result of 1 means that the word is itself a complete packet. + */ + static uint32_t getNumWordsForMessageType (uint32_t); + + /** + Helper functions for setting/getting 4-bit ranges inside a 32-bit word. + */ + template + struct U4 + { + static constexpr uint32_t shift = (uint32_t) 0x1c - Index * 4; + + static constexpr uint32_t set (uint32_t word, uint8_t value) + { + return (word & ~((uint32_t) 0xf << shift)) | (uint32_t) ((value & 0xf) << shift); + } + + static constexpr uint8_t get (uint32_t word) + { + return (uint8_t) ((word >> shift) & 0xf); + } + }; + + /** + Helper functions for setting/getting 8-bit ranges inside a 32-bit word. + */ + template + struct U8 + { + static constexpr uint32_t shift = (uint32_t) 0x18 - Index * 8; + + static constexpr uint32_t set (uint32_t word, uint8_t value) + { + return (word & ~((uint32_t) 0xff << shift)) | (uint32_t) (value << shift); + } + + static constexpr uint8_t get (uint32_t word) + { + return (uint8_t) ((word >> shift) & 0xff); + } + }; + + /** + Helper functions for setting/getting 16-bit ranges inside a 32-bit word. + */ + template + struct U16 + { + static constexpr uint32_t shift = (uint32_t) 0x10 - Index * 16; + + static constexpr uint32_t set (uint32_t word, uint16_t value) + { + return (word & ~((uint32_t) 0xffff << shift)) | (uint32_t) (value << shift); + } + + static constexpr uint16_t get (uint32_t word) + { + return (uint16_t) ((word >> shift) & 0xffff); + } + }; + + static constexpr uint8_t getMessageType (uint32_t w) noexcept { return U4<0>::get (w); } + static constexpr uint8_t getGroup (uint32_t w) noexcept { return U4<1>::get (w); } + static constexpr uint8_t getStatus (uint32_t w) noexcept { return U4<2>::get (w); } + static constexpr uint8_t getChannel (uint32_t w) noexcept { return U4<3>::get (w); } +}; + +} +} + +#endif diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPView.cpp b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPView.cpp new file mode 100644 index 00000000..c5f3db85 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPView.cpp @@ -0,0 +1,35 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ +namespace universal_midi_packets +{ + +uint32_t View::size() const noexcept +{ + jassert (ptr != nullptr); + return Utils::getNumWordsForMessageType (*ptr); +} + +} +} diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPView.h b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPView.h new file mode 100644 index 00000000..3033fc18 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPView.h @@ -0,0 +1,92 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#ifndef DOXYGEN + +namespace juce +{ +namespace universal_midi_packets +{ + +/** + Points to a single Universal MIDI Packet. + + The packet must be well-formed for member functions to work correctly. + + Specifically, the constructor argument must be the beginning of a region of + uint32_t that contains at least `getNumWordsForMessageType(*ddata)` items, + where `data` is the constructor argument. + + NOTE: Instances of this class do not own the memory that they point to! + If you need to store a packet pointed-to by a View for later use, copy + the view contents to a Packets collection, or use the Utils::PacketX types. + + @tags{Audio} +*/ +class View +{ +public: + /** Create an invalid view. */ + View() noexcept = default; + + /** Create a view of the packet starting at address `d`. */ + explicit View (const uint32_t* data) noexcept : ptr (data) {} + + /** Get a pointer to the first word in the Universal MIDI Packet currently + pointed-to by this view. + */ + const uint32_t* data() const noexcept { return ptr; } + + /** Get the number of 32-words (between 1 and 4 inclusive) in the Universal + MIDI Packet currently pointed-to by this view. + */ + uint32_t size() const noexcept; + + /** Get a specific word from this packet. + + Passing an `index` that is greater than or equal to the result of `size` + will cause undefined behaviour. + */ + const uint32_t& operator[] (size_t index) const noexcept { return ptr[index]; } + + /** Get an iterator pointing to the first word in the packet. */ + const uint32_t* begin() const noexcept { return ptr; } + const uint32_t* cbegin() const noexcept { return ptr; } + + /** Get an iterator pointing one-past the last word in the packet. */ + const uint32_t* end() const noexcept { return ptr + size(); } + const uint32_t* cend() const noexcept { return ptr + size(); } + + /** Return true if this view is pointing to the same address as another view. */ + bool operator== (const View& other) const noexcept { return ptr == other.ptr; } + + /** Return false if this view is pointing to the same address as another view. */ + bool operator!= (const View& other) const noexcept { return ! operator== (other); } + +private: + const uint32_t* ptr = nullptr; +}; + +} +} + +#endif diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPacket.h b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPacket.h new file mode 100644 index 00000000..610e3072 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPacket.h @@ -0,0 +1,193 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#ifndef DOXYGEN + +namespace juce +{ +namespace universal_midi_packets +{ + +/** + Holds a single Universal MIDI Packet. + + @tags{Audio} +*/ +template +class Packet +{ +public: + Packet() = default; + + template ::type = 0> + Packet (uint32_t a) + : contents { { a } } + { + jassert (Utils::getNumWordsForMessageType (a) == 1); + } + + template ::type = 0> + Packet (uint32_t a, uint32_t b) + : contents { { a, b } } + { + jassert (Utils::getNumWordsForMessageType (a) == 2); + } + + template ::type = 0> + Packet (uint32_t a, uint32_t b, uint32_t c) + : contents { { a, b, c } } + { + jassert (Utils::getNumWordsForMessageType (a) == 3); + } + + template ::type = 0> + Packet (uint32_t a, uint32_t b, uint32_t c, uint32_t d) + : contents { { a, b, c, d } } + { + jassert (Utils::getNumWordsForMessageType (a) == 4); + } + + template ::type = 0> + explicit Packet (const std::array& fullPacket) + : contents (fullPacket) + { + jassert (Utils::getNumWordsForMessageType (fullPacket.front()) == numWords); + } + + Packet withMessageType (uint8_t type) const noexcept + { + return withU4<0> (type); + } + + Packet withGroup (uint8_t group) const noexcept + { + return withU4<1> (group); + } + + Packet withStatus (uint8_t status) const noexcept + { + return withU4<2> (status); + } + + Packet withChannel (uint8_t channel) const noexcept + { + return withU4<3> (channel); + } + + uint8_t getMessageType() const noexcept { return getU4<0>(); } + + uint8_t getGroup() const noexcept { return getU4<1>(); } + + uint8_t getStatus() const noexcept { return getU4<2>(); } + + uint8_t getChannel() const noexcept { return getU4<3>(); } + + template + Packet withU4 (uint8_t value) const noexcept + { + constexpr auto word = index / 8; + auto copy = *this; + std::get (copy.contents) = Utils::U4::set (copy.template getU32(), value); + return copy; + } + + template + Packet withU8 (uint8_t value) const noexcept + { + constexpr auto word = index / 4; + auto copy = *this; + std::get (copy.contents) = Utils::U8::set (copy.template getU32(), value); + return copy; + } + + template + Packet withU16 (uint16_t value) const noexcept + { + constexpr auto word = index / 2; + auto copy = *this; + std::get (copy.contents) = Utils::U16::set (copy.template getU32(), value); + return copy; + } + + template + Packet withU32 (uint32_t value) const noexcept + { + auto copy = *this; + std::get (copy.contents) = value; + return copy; + } + + template + uint8_t getU4() const noexcept + { + return Utils::U4::get (this->template getU32()); + } + + template + uint8_t getU8() const noexcept + { + return Utils::U8::get (this->template getU32()); + } + + template + uint16_t getU16() const noexcept + { + return Utils::U16::get (this->template getU32()); + } + + template + uint32_t getU32() const noexcept + { + return std::get (contents); + } + + //============================================================================== + using Contents = std::array; + + using const_iterator = typename Contents::const_iterator; + + const_iterator begin() const noexcept { return contents.begin(); } + const_iterator cbegin() const noexcept { return contents.begin(); } + + const_iterator end() const noexcept { return contents.end(); } + const_iterator cend() const noexcept { return contents.end(); } + + const uint32_t* data() const noexcept { return contents.data(); } + + const uint32_t& front() const noexcept { return contents.front(); } + const uint32_t& back() const noexcept { return contents.back(); } + + const uint32_t& operator[] (size_t index) const noexcept { return contents[index]; } + +private: + Contents contents { {} }; +}; + +using PacketX1 = Packet<1>; +using PacketX2 = Packet<2>; +using PacketX3 = Packet<3>; +using PacketX4 = Packet<4>; + +} +} + +#endif diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPackets.h b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPackets.h new file mode 100644 index 00000000..b485b100 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/midi/ump/juce_UMPackets.h @@ -0,0 +1,96 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#ifndef DOXYGEN + +namespace juce +{ +namespace universal_midi_packets +{ + +/** + Holds a collection of Universal MIDI Packets. + + Unlike MidiBuffer, this collection does not store any additional information + (e.g. timestamps) alongside the raw messages. + + If timestamps are required, these can be added to the container in UMP format, + as Jitter Reduction Utility messages. + + @tags{Audio} +*/ +class Packets +{ +public: + /** Adds a single packet to the collection. + + The View must be valid for this to work. If the view + points to a malformed message, or if the view points to a region + too short for the contained message, this call will result in + undefined behaviour. + */ + void add (const View& v) { storage.insert (storage.end(), v.cbegin(), v.cend()); } + + void add (const PacketX1& p) { addImpl (p); } + void add (const PacketX2& p) { addImpl (p); } + void add (const PacketX3& p) { addImpl (p); } + void add (const PacketX4& p) { addImpl (p); } + + /** Pre-allocates space for at least `numWords` 32-bit words in this collection. */ + void reserve (size_t numWords) { storage.reserve (numWords); } + + /** Removes all previously-added packets from this collection. */ + void clear() { storage.clear(); } + + /** Gets an iterator pointing to the first packet in this collection. */ + Iterator cbegin() const noexcept { return Iterator (data(), size()); } + Iterator begin() const noexcept { return cbegin(); } + + /** Gets an iterator pointing one-past the last packet in this collection. */ + Iterator cend() const noexcept { return Iterator (data() + size(), 0); } + Iterator end() const noexcept { return cend(); } + + /** Gets a pointer to the contents of the collection as a range of raw 32-bit words. */ + const uint32_t* data() const noexcept { return storage.data(); } + + /** Returns the number of uint32_t words in storage. + + Note that this is likely to be larger than the number of packets + currently being stored, as some packets span multiple words. + */ + size_t size() const noexcept { return storage.size(); } + +private: + template + void addImpl (const Packet& p) + { + jassert (Utils::getNumWordsForMessageType (p[0]) == numWords); + add (View (p.data())); + } + + std::vector storage; +}; + +} +} + +#endif diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEInstrument.cpp b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEInstrument.cpp index b730f421..7e0a33f9 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEInstrument.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEInstrument.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -27,56 +27,91 @@ namespace { const uint8 noLSBValueReceived = 0xff; const Range allChannels { 1, 17 }; + + template + void mpeInstrumentFill (Range& range, const Value& value) + { + std::fill (std::begin (range), std::end (range), value); + } } //============================================================================== MPEInstrument::MPEInstrument() noexcept { - std::fill_n (lastPressureLowerBitReceivedOnChannel, 16, noLSBValueReceived); - std::fill_n (lastTimbreLowerBitReceivedOnChannel, 16, noLSBValueReceived); - std::fill_n (isMemberChannelSustained, 16, false); + mpeInstrumentFill (lastPressureLowerBitReceivedOnChannel, noLSBValueReceived); + mpeInstrumentFill (lastTimbreLowerBitReceivedOnChannel, noLSBValueReceived); + mpeInstrumentFill (isMemberChannelSustained, false); pitchbendDimension.value = &MPENote::pitchbend; - pressureDimension.value = &MPENote::pressure; - timbreDimension.value = &MPENote::timbre; + pressureDimension.value = &MPENote::pressure; + timbreDimension.value = &MPENote::timbre; - // the default value for pressure is 0, for all other dimension it is centre (= default MPEValue) - std::fill_n (pressureDimension.lastValueReceivedOnChannel, 16, MPEValue::minValue()); + resetLastReceivedValues(); - legacyMode.isEnabled = false; - legacyMode.pitchbendRange = 2; legacyMode.channelRange = allChannels; } -MPEInstrument::~MPEInstrument() +MPEInstrument::MPEInstrument (MPEZoneLayout layout) + : MPEInstrument() { + setZoneLayout (layout); } +MPEInstrument::~MPEInstrument() = default; + //============================================================================== MPEZoneLayout MPEInstrument::getZoneLayout() const noexcept { return zoneLayout; } +void MPEInstrument::resetLastReceivedValues() +{ + struct Defaults + { + MPEDimension& dimension; + MPEValue defaultValue; + }; + + // The default value for pressure is 0, for all other dimensions it is centre + for (const auto& pair : { Defaults { pressureDimension, MPEValue::minValue() }, + Defaults { pitchbendDimension, MPEValue::centreValue() }, + Defaults { timbreDimension, MPEValue::centreValue() } }) + { + mpeInstrumentFill (pair.dimension.lastValueReceivedOnChannel, pair.defaultValue); + } +} + void MPEInstrument::setZoneLayout (MPEZoneLayout newLayout) { releaseAllNotes(); const ScopedLock sl (lock); legacyMode.isEnabled = false; - zoneLayout = newLayout; + + if (zoneLayout != newLayout) + { + zoneLayout = newLayout; + listeners.call ([=] (Listener& l) { l.zoneLayoutChanged(); }); + } } //============================================================================== void MPEInstrument::enableLegacyMode (int pitchbendRange, Range channelRange) { + if (legacyMode.isEnabled) + return; + releaseAllNotes(); const ScopedLock sl (lock); + legacyMode.isEnabled = true; legacyMode.pitchbendRange = pitchbendRange; legacyMode.channelRange = channelRange; + zoneLayout.clearAllZones(); + listeners.call ([=] (Listener& l) { l.zoneLayoutChanged(); }); } bool MPEInstrument::isLegacyModeEnabled() const noexcept @@ -95,7 +130,12 @@ void MPEInstrument::setLegacyModeChannelRange (Range channelRange) releaseAllNotes(); const ScopedLock sl (lock); - legacyMode.channelRange = channelRange; + + if (legacyMode.channelRange != channelRange) + { + legacyMode.channelRange = channelRange; + listeners.call ([=] (Listener& l) { l.zoneLayoutChanged(); }); + } } int MPEInstrument::getLegacyModePitchbendRange() const noexcept @@ -109,7 +149,12 @@ void MPEInstrument::setLegacyModePitchbendRange (int pitchbendRange) releaseAllNotes(); const ScopedLock sl (lock); - legacyMode.pitchbendRange = pitchbendRange; + + if (legacyMode.pitchbendRange != pitchbendRange) + { + legacyMode.pitchbendRange = pitchbendRange; + listeners.call ([=] (Listener& l) { l.zoneLayoutChanged(); }); + } } //============================================================================== @@ -129,12 +174,12 @@ void MPEInstrument::setTimbreTrackingMode (TrackingMode modeToUse) } //============================================================================== -void MPEInstrument::addListener (Listener* const listenerToAdd) noexcept +void MPEInstrument::addListener (Listener* listenerToAdd) { listeners.add (listenerToAdd); } -void MPEInstrument::removeListener (Listener* const listenerToRemove) noexcept +void MPEInstrument::removeListener (Listener* listenerToRemove) { listeners.remove (listenerToRemove); } @@ -151,12 +196,13 @@ void MPEInstrument::processNextMidiEvent (const MidiMessage& message) else if (message.isPitchWheel()) processMidiPitchWheelMessage (message); else if (message.isChannelPressure()) processMidiChannelPressureMessage (message); else if (message.isController()) processMidiControllerMessage (message); + else if (message.isAftertouch()) processMidiAfterTouchMessage (message); } //============================================================================== void MPEInstrument::processMidiNoteOnMessage (const MidiMessage& message) { - // Note: if a note-on with velocity = 0 is used to convey a note-off, + // Note: If a note-on with velocity = 0 is used to convey a note-off, // then the actual note-off velocity is not known. In this case, // the MPE convention is to use note-off velocity = 64. @@ -219,7 +265,7 @@ void MPEInstrument::processMidiResetAllControllersMessage (const MidiMessage& me if (legacyMode.isEnabled && legacyMode.channelRange.contains (message.getChannel())) { - for (auto i = notes.size(); --i >= 0;) + for (int i = notes.size(); --i >= 0;) { auto& note = notes.getReference (i); @@ -237,11 +283,11 @@ void MPEInstrument::processMidiResetAllControllersMessage (const MidiMessage& me auto zone = (message.getChannel() == 1 ? zoneLayout.getLowerZone() : zoneLayout.getUpperZone()); - for (auto i = notes.size(); --i >= 0;) + for (int i = notes.size(); --i >= 0;) { auto& note = notes.getReference (i); - if (zone.isUsingChannelAsMemberChannel (note.midiChannel)) + if (zone.isUsing (note.midiChannel)) { note.keyState = MPENote::off; note.noteOffVelocity = MPEValue::from7BitInt (64); // some reasonable number @@ -252,6 +298,15 @@ void MPEInstrument::processMidiResetAllControllersMessage (const MidiMessage& me } } +void MPEInstrument::processMidiAfterTouchMessage (const MidiMessage& message) +{ + if (! isMasterChannel (message.getChannel())) + return; + + polyAftertouch (message.getChannel(), message.getNoteNumber(), + MPEValue::from7BitInt (message.getAfterTouchValue())); +} + //============================================================================== void MPEInstrument::handlePressureMSB (int midiChannel, int value) noexcept { @@ -284,7 +339,7 @@ void MPEInstrument::noteOn (int midiChannel, int midiNoteNumber, MPEValue midiNoteOnVelocity) { - if (! isMemberChannel (midiChannel)) + if (! isUsingChannel (midiChannel)) return; MPENote newNote (midiChannel, @@ -316,21 +371,23 @@ void MPEInstrument::noteOff (int midiChannel, int midiNoteNumber, MPEValue midiNoteOffVelocity) { - if (notes.isEmpty() || ! isMemberChannel (midiChannel)) - return; - const ScopedLock sl (lock); + if (notes.isEmpty() || ! isUsingChannel (midiChannel)) + return; + if (auto* note = getNotePtr (midiChannel, midiNoteNumber)) { note->keyState = (note->keyState == MPENote::keyDownAndSustained) ? MPENote::sustained : MPENote::off; note->noteOffVelocity = midiNoteOffVelocity; - // last dimension values received for this note should not be re-used for - // any new notes, so reset them: - pressureDimension.lastValueReceivedOnChannel[midiChannel - 1] = MPEValue::minValue(); - pitchbendDimension.lastValueReceivedOnChannel[midiChannel - 1] = MPEValue::centreValue(); - timbreDimension.lastValueReceivedOnChannel[midiChannel - 1] = MPEValue::centreValue(); + // If no more notes are playing on this channel in mpe mode, reset the dimension values + if (! legacyMode.isEnabled && getLastNotePlayedPtr (midiChannel) == nullptr) + { + pressureDimension.lastValueReceivedOnChannel[midiChannel - 1] = MPEValue::minValue(); + pitchbendDimension.lastValueReceivedOnChannel[midiChannel - 1] = MPEValue::centreValue(); + timbreDimension.lastValueReceivedOnChannel[midiChannel - 1] = MPEValue::centreValue(); + } if (note->keyState == MPENote::off) { @@ -363,9 +420,27 @@ void MPEInstrument::timbre (int midiChannel, MPEValue value) updateDimension (midiChannel, timbreDimension, value); } +void MPEInstrument::polyAftertouch (int midiChannel, int midiNoteNumber, MPEValue value) +{ + const ScopedLock sl (lock); + + for (int i = notes.size(); --i >= 0;) + { + auto& note = notes.getReference (i); + + if (note.midiChannel == midiChannel + && note.initialNote == midiNoteNumber + && pressureDimension.getValue (note) != value) + { + pressureDimension.getValue (note) = value; + callListenersDimensionChanged (note, pressureDimension); + } + } +} + MPEValue MPEInstrument::getInitialValueForNewNote (int midiChannel, MPEDimension& dimension) const { - if (getLastNotePlayedPtr (midiChannel) != nullptr) + if (! legacyMode.isEnabled && getLastNotePlayedPtr (midiChannel) != nullptr) return &dimension == &pressureDimension ? MPEValue::minValue() : MPEValue::centreValue(); return dimension.lastValueReceivedOnChannel[midiChannel - 1]; @@ -383,7 +458,7 @@ void MPEInstrument::updateDimension (int midiChannel, MPEDimension& dimension, M { if (dimension.trackingMode == allNotesOnChannel) { - for (auto i = notes.size(); --i >= 0;) + for (int i = notes.size(); --i >= 0;) { auto& note = notes.getReference (i); @@ -412,11 +487,11 @@ void MPEInstrument::updateDimensionMaster (bool isLowerZone, MPEDimension& dimen if (! zone.isActive()) return; - for (auto i = notes.size(); --i >= 0;) + for (int i = notes.size(); --i >= 0;) { auto& note = notes.getReference (i); - if (! zone.isUsingChannelAsMemberChannel (note.midiChannel)) + if (! zone.isUsing (note.midiChannel)) continue; if (&dimension == &pitchbendDimension) @@ -461,17 +536,19 @@ void MPEInstrument::updateNoteTotalPitchbend (MPENote& note) { if (legacyMode.isEnabled) { - note.totalPitchbendInSemitones = note.pitchbend.asSignedFloat() * legacyMode.pitchbendRange; + note.totalPitchbendInSemitones = note.pitchbend.asSignedFloat() * (float) legacyMode.pitchbendRange; } else { auto zone = zoneLayout.getLowerZone(); - if (! zone.isUsingChannelAsMemberChannel (note.midiChannel)) + if (! zone.isActive() || ! zone.isUsing (note.midiChannel)) { - if (zoneLayout.getUpperZone().isUsingChannelAsMemberChannel (note.midiChannel)) + auto upperZone = zoneLayout.getUpperZone(); + + if (upperZone.isActive() && upperZone.isUsing (note.midiChannel)) { - zone = zoneLayout.getUpperZone(); + zone = upperZone; } else { @@ -481,11 +558,14 @@ void MPEInstrument::updateNoteTotalPitchbend (MPENote& note) } } - auto notePitchbendInSemitones = note.pitchbend.asSignedFloat() * zone.perNotePitchbendRange; + auto notePitchbendInSemitones = 0.0f; + + if (zone.isUsingChannelAsMemberChannel (note.midiChannel)) + notePitchbendInSemitones = note.pitchbend.asSignedFloat() * (float) zone.perNotePitchbendRange; auto masterPitchbendInSemitones = pitchbendDimension.lastValueReceivedOnChannel[zone.getMasterChannel() - 1] .asSignedFloat() - * zone.masterPitchbendRange; + * (float) zone.masterPitchbendRange; note.totalPitchbendInSemitones = notePitchbendInSemitones + masterPitchbendInSemitones; } @@ -516,11 +596,11 @@ void MPEInstrument::handleSustainOrSostenuto (int midiChannel, bool isDown, bool auto zone = (midiChannel == 1 ? zoneLayout.getLowerZone() : zoneLayout.getUpperZone()); - for (auto i = notes.size(); --i >= 0;) + for (int i = notes.size(); --i >= 0;) { auto& note = notes.getReference (i); - if (legacyMode.isEnabled ? (note.midiChannel == midiChannel) : zone.isUsingChannelAsMemberChannel (note.midiChannel)) + if (legacyMode.isEnabled ? (note.midiChannel == midiChannel) : zone.isUsing (note.midiChannel)) { if (note.keyState == MPENote::keyDown && isDown) note.keyState = MPENote::keyDownAndSustained; @@ -543,24 +623,26 @@ void MPEInstrument::handleSustainOrSostenuto (int midiChannel, bool isDown, bool if (! isSostenuto) { - if (legacyMode.isEnabled) - { - isMemberChannelSustained[midiChannel - 1] = isDown; - } - else + isMemberChannelSustained[midiChannel - 1] = isDown; + + if (! legacyMode.isEnabled) { if (zone.isLowerZone()) - for (auto i = zone.getFirstMemberChannel(); i <= zone.getLastMemberChannel(); ++i) + { + for (int i = zone.getFirstMemberChannel(); i <= zone.getLastMemberChannel(); ++i) isMemberChannelSustained[i - 1] = isDown; + } else - for (auto i = zone.getFirstMemberChannel(); i >= zone.getLastMemberChannel(); --i) + { + for (int i = zone.getFirstMemberChannel(); i >= zone.getLastMemberChannel(); --i) isMemberChannelSustained[i - 1] = isDown; + } } } } //============================================================================== -bool MPEInstrument::isMemberChannel (int midiChannel) noexcept +bool MPEInstrument::isMemberChannel (int midiChannel) const noexcept { if (legacyMode.isEnabled) return legacyMode.channelRange.contains (midiChannel); @@ -574,8 +656,22 @@ bool MPEInstrument::isMasterChannel (int midiChannel) const noexcept if (legacyMode.isEnabled) return false; - return (midiChannel == 1 || midiChannel == 16); + const auto lowerZone = zoneLayout.getLowerZone(); + const auto upperZone = zoneLayout.getUpperZone(); + + return (lowerZone.isActive() && midiChannel == lowerZone.getMasterChannel()) + || (upperZone.isActive() && midiChannel == upperZone.getMasterChannel()); +} + +bool MPEInstrument::isUsingChannel (int midiChannel) const noexcept +{ + if (legacyMode.isEnabled) + return legacyMode.channelRange.contains (midiChannel); + + return zoneLayout.getLowerZone().isUsing (midiChannel) + || zoneLayout.getUpperZone().isUsing (midiChannel); } + //============================================================================== int MPEInstrument::getNumPlayingNotes() const noexcept { @@ -595,6 +691,17 @@ MPENote MPEInstrument::getNote (int index) const noexcept return notes[index]; } +MPENote MPEInstrument::getNoteWithID (uint16 noteID) const noexcept +{ + const ScopedLock sl (lock); + + for (auto& note : notes) + if (note.noteID == noteID) + return note; + + return {}; +} + //============================================================================== MPENote MPEInstrument::getMostRecentNote (int midiChannel) const noexcept { @@ -658,6 +765,8 @@ MPENote* MPEInstrument::getNotePtr (int midiChannel, TrackingMode mode) noexcept //============================================================================== const MPENote* MPEInstrument::getLastNotePlayedPtr (int midiChannel) const noexcept { + const ScopedLock sl (lock); + for (auto i = notes.size(); --i >= 0;) { auto& note = notes.getReference (i); @@ -679,7 +788,7 @@ MPENote* MPEInstrument::getLastNotePlayedPtr (int midiChannel) noexcept const MPENote* MPEInstrument::getHighestNotePtr (int midiChannel) const noexcept { int initialNoteMax = -1; - MPENote* result = nullptr; + const MPENote* result = nullptr; for (auto i = notes.size(); --i >= 0;) { @@ -705,7 +814,7 @@ MPENote* MPEInstrument::getHighestNotePtr (int midiChannel) noexcept const MPENote* MPEInstrument::getLowestNotePtr (int midiChannel) const noexcept { int initialNoteMin = 128; - MPENote* result = nullptr; + const MPENote* result = nullptr; for (auto i = notes.size(); --i >= 0;) { @@ -744,6 +853,7 @@ void MPEInstrument::releaseAllNotes() notes.clear(); } + //============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -752,7 +862,7 @@ class MPEInstrumentTests : public UnitTest { public: MPEInstrumentTests() - : UnitTest ("MPEInstrument class", "MIDI/MPE") + : UnitTest ("MPEInstrument class", UnitTestCategories::midi) { // using lower and upper MPE zones with the following layout for testing // @@ -763,6 +873,7 @@ class MPEInstrumentTests : public UnitTest testLayout.setUpperZone (6); } + JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6262) void runTest() override { beginTest ("initial zone layout"); @@ -798,12 +909,7 @@ class MPEInstrumentTests : public UnitTest UnitTestInstrument test; test.setZoneLayout (testLayout); - // note-on on master channel - ignore - test.noteOn (1, 60, MPEValue::from7BitInt (100)); - expectEquals (test.getNumPlayingNotes(), 0); - expectEquals (test.noteAddedCallCounter, 0); - - // note-on on any other channel - ignore + // note-on on unused channel - ignore test.noteOn (7, 60, MPEValue::from7BitInt (100)); expectEquals (test.getNumPlayingNotes(), 0); expectEquals (test.noteAddedCallCounter, 0); @@ -819,7 +925,21 @@ class MPEInstrumentTests : public UnitTest expectEquals (test.getNumPlayingNotes(), 0); expectEquals (test.noteReleasedCallCounter, 1); expectHasFinishedNote (test, 3, 60, 33); + + + // note-on on master channel - create new note + test.noteOn (1, 62, MPEValue::from7BitInt (100)); + expectEquals (test.getNumPlayingNotes(), 1); + expectEquals (test.noteAddedCallCounter, 2); + expectNote (test.getNote (1, 62), 100, 0, 8192, 64, MPENote::keyDown); + + // note-off + test.noteOff (1, 62, MPEValue::from7BitInt (33)); + expectEquals (test.getNumPlayingNotes(), 0); + expectEquals (test.noteReleasedCallCounter, 2); + expectHasFinishedNote (test, 1, 62, 33); } + { UnitTestInstrument test; test.setZoneLayout (testLayout); @@ -837,6 +957,7 @@ class MPEInstrumentTests : public UnitTest expectNote (test.getNote (3, 60), 100, 0, 8192, 64, MPENote::keyDown); expectEquals (test.noteReleasedCallCounter, 0); } + { // can have multiple notes on the same channel UnitTestInstrument test; @@ -1187,6 +1308,22 @@ class MPEInstrumentTests : public UnitTest expectNote (test.getNote (3, 60), 100, 78, 8192, 64, MPENote::keyDown); expectNote (test.getNote (3, 61), 100, 77, 8192, 64, MPENote::keyDown); } + + { + UnitTestInstrument test; + test.setZoneLayout (testLayout); + + // master channel will use poly-aftertouch for pressure + test.noteOn (16, 60, MPEValue::from7BitInt (100)); + expectNote (test.getNote (16, 60), 100, 0, 8192, 64, MPENote::keyDown); + test.aftertouch (16, 60, MPEValue::from7BitInt (27)); + expectNote (test.getNote (16, 60), 100, 27, 8192, 64, MPENote::keyDown); + + // member channels will not respond to poly-aftertouch + test.noteOn (3, 60, MPEValue::from7BitInt (100)); + test.aftertouch (3, 60, MPEValue::from7BitInt (50)); + expectNote (test.getNote (3, 60), 100, 0, 8192, 64, MPENote::keyDown); + } } beginTest ("pitchbend"); @@ -1760,12 +1897,8 @@ class MPEInstrumentTests : public UnitTest buffer.addEvents (MPEMessages::setLowerZone (5), 0, -1, 0); buffer.addEvents (MPEMessages::setUpperZone (6), 0, -1, 0); - MidiBuffer::Iterator iter (buffer); - MidiMessage message; - int samplePosition; // not actually used, so no need to initialise. - - while (iter.getNextEvent (message, samplePosition)) - test.processNextMidiEvent (message); + for (const auto metadata : buffer) + test.processNextMidiEvent (metadata.getMessage()); expect (test.getZoneLayout().getLowerZone().isActive()); expect (test.getZoneLayout().getUpperZone().isActive()); @@ -2053,6 +2186,7 @@ class MPEInstrumentTests : public UnitTest } } } + JUCE_END_IGNORE_WARNINGS_MSVC private: //============================================================================== @@ -2062,7 +2196,8 @@ class MPEInstrumentTests : public UnitTest class UnitTestInstrument : public MPEInstrument, private MPEInstrument::Listener { - typedef MPEInstrument Base; + using Base = MPEInstrument; + public: UnitTestInstrument() : noteOnCallCounter (0), noteOffCallCounter (0), pitchbendCallCounter (0), @@ -2141,6 +2276,12 @@ class MPEInstrumentTests : public UnitTest lastSostenutoPedalValueReceived = value; } + void aftertouch (int midiChannel, int midiNoteNumber, MPEValue value) + { + const auto message = juce::MidiMessage::aftertouchChange (midiChannel, midiNoteNumber, value.as7BitInt()); + processNextMidiEvent (message); + } + int noteOnCallCounter, noteOffCallCounter, pitchbendCallCounter, pressureCallCounter, timbreCallCounter, sustainPedalCallCounter, sostenutoPedalCallCounter, noteAddedCallCounter, @@ -2150,7 +2291,7 @@ class MPEInstrumentTests : public UnitTest bool lastSustainPedalValueReceived, lastSostenutoPedalValueReceived; MPEValue lastMPEValueReceived; - ScopedPointer lastNoteFinished; + std::unique_ptr lastNoteFinished; private: //============================================================================== @@ -2206,6 +2347,6 @@ class MPEInstrumentTests : public UnitTest static MPEInstrumentTests MPEInstrumentUnitTests; -#endif // JUCE_UNIT_TESTS +#endif } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEInstrument.h b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEInstrument.h index 4582065d..e4b3cabd 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEInstrument.h +++ b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEInstrument.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -27,7 +27,7 @@ namespace juce /** This class represents an instrument handling MPE. - It has an MPE zone layout and maintans a state of currently + It has an MPE zone layout and maintains a state of currently active (playing) notes and the values of their dimensions of expression. You can trigger and modulate notes: @@ -38,10 +38,8 @@ namespace juce MPE. If you pass it a message, it will know what notes on what channels (if any) should be affected by that message. - The class has a Listener class with the three callbacks MPENoteAdded, - MPENoteChanged, and MPENoteFinished. Implement such a - Listener class to react to note changes and trigger some functionality for - your application that depends on the MPE note state. + The class has a Listener class that can be used to react to note and + state changes and trigger some functionality for your application. For example, you can use this class to write an MPE visualiser. If you want to write a real-time audio synth with MPE functionality, @@ -59,11 +57,14 @@ class JUCE_API MPEInstrument This will construct an MPE instrument with inactive lower and upper zones. - In order to process incoming MIDI, call setZoneLayout, define the layout - via MIDI RPN messages, or set the instrument to legacy mode. + In order to process incoming MIDI messages call setZoneLayout, use the MPEZoneLayout + constructor, define the layout via MIDI RPN messages, or set the instrument to legacy mode. */ MPEInstrument() noexcept; + /** Constructs an MPE instrument with the specified zone layout. */ + MPEInstrument (MPEZoneLayout layout); + /** Destructor. */ virtual ~MPEInstrument(); @@ -90,7 +91,7 @@ class JUCE_API MPEInstrument When in legacy mode, this will return true if the given channel is contained in the current legacy mode channel range; false otherwise. */ - bool isMemberChannel (int midiChannel) noexcept; + bool isMemberChannel (int midiChannel) const noexcept; /** Returns true if the given MIDI channel (1-16) is a master channel (channel 1 or 16). @@ -99,6 +100,14 @@ class JUCE_API MPEInstrument */ bool isMasterChannel (int midiChannel) const noexcept; + /** Returns true if the given MIDI channel (1-16) is used by any of the + MPEInstrument's MPE zones; false otherwise. + + When in legacy mode, this will return true if the given channel is + contained in the current legacy mode channel range; false otherwise. + */ + bool isUsingChannel (int midiChannel) const noexcept; + //============================================================================== /** The MPE note tracking mode. In case there is more than one note playing simultaneously on the same MIDI channel, this determines which of these @@ -177,6 +186,13 @@ class JUCE_API MPEInstrument */ virtual void timbre (int midiChannel, MPEValue value); + /** Request a poly-aftertouch change for a given note number. + + The change will be broadcast to all notes sharing the channel and note + number of the change message. + */ + virtual void polyAftertouch (int midiChannel, int midiNoteNumber, MPEValue value); + /** Request a sustain pedal press or release. If midiChannel is a zone's master channel, this will act on all notes in @@ -214,6 +230,9 @@ class JUCE_API MPEInstrument */ MPENote getNote (int midiChannel, int midiNoteNumber) const noexcept; + /** Returns the note with a given ID. */ + MPENote getNoteWithID (uint16 noteID) const noexcept; + /** Returns the most recent note that is playing on the given midiChannel (this will be the note which has received the most recent note-on without a corresponding note-off), if there is such a note. Otherwise, this returns an @@ -229,8 +248,8 @@ class JUCE_API MPEInstrument MPENote getMostRecentNoteOtherThan (MPENote otherThanThisNote) const noexcept; //============================================================================== - /** Derive from this class to be informed about any changes in the expressive - MIDI notes played by this instrument. + /** Derive from this class to be informed about any changes in the MPE notes played + by this instrument, and any changes to its zone layout. Note: This listener type receives its callbacks immediately, and not via the message thread (so you might be for example in the MIDI thread). @@ -241,17 +260,17 @@ class JUCE_API MPEInstrument { public: /** Destructor. */ - virtual ~Listener() {} + virtual ~Listener() = default; /** Implement this callback to be informed whenever a new expressive MIDI note is triggered. */ - virtual void noteAdded (MPENote newNote) = 0; + virtual void noteAdded (MPENote newNote) { ignoreUnused (newNote); } /** Implement this callback to be informed whenever a currently playing MPE note's pressure value changes. */ - virtual void notePressureChanged (MPENote changedNote) = 0; + virtual void notePressureChanged (MPENote changedNote) { ignoreUnused (changedNote); } /** Implement this callback to be informed whenever a currently playing MPE note's pitchbend value changes. @@ -260,39 +279,46 @@ class JUCE_API MPEInstrument master channel pitchbend event, or if both occur simultaneously. Call MPENote::getFrequencyInHertz to get the effective note frequency. */ - virtual void notePitchbendChanged (MPENote changedNote) = 0; + virtual void notePitchbendChanged (MPENote changedNote) { ignoreUnused (changedNote); } /** Implement this callback to be informed whenever a currently playing MPE note's timbre value changes. */ - virtual void noteTimbreChanged (MPENote changedNote) = 0; + virtual void noteTimbreChanged (MPENote changedNote) { ignoreUnused (changedNote); } /** Implement this callback to be informed whether a currently playing MPE note's key state (whether the key is down and/or the note is sustained) has changed. - Note: if the key state changes to MPENote::off, noteReleased is + Note: If the key state changes to MPENote::off, noteReleased is called instead. */ - virtual void noteKeyStateChanged (MPENote changedNote) = 0; + virtual void noteKeyStateChanged (MPENote changedNote) { ignoreUnused (changedNote); } /** Implement this callback to be informed whenever an MPE note is released (either by a note-off message, or by a sustain/sostenuto pedal release for a note that already received a note-off), and should therefore stop playing. */ - virtual void noteReleased (MPENote finishedNote) = 0; + virtual void noteReleased (MPENote finishedNote) { ignoreUnused (finishedNote); } + + /** Implement this callback to be informed whenever the MPE zone layout + or legacy mode settings of this instrument have been changed. + */ + virtual void zoneLayoutChanged() {} }; //============================================================================== /** Adds a listener. */ - void addListener (Listener* listenerToAdd) noexcept; + void addListener (Listener* listenerToAdd); /** Removes a listener. */ - void removeListener (Listener* listenerToRemove) noexcept; + void removeListener (Listener* listenerToRemove); //============================================================================== - /** Puts the instrument into legacy mode. + /** Puts the instrument into legacy mode. If legacy mode is already enabled this method + does nothing. + As a side effect, this will discard all currently playing notes, and call noteReleased for all of them. @@ -345,15 +371,14 @@ class JUCE_API MPEInstrument struct LegacyMode { - bool isEnabled; + bool isEnabled = false; Range channelRange; - int pitchbendRange; + int pitchbendRange = 2; }; struct MPEDimension { - MPEDimension() noexcept : trackingMode (lastNotePlayedOnChannel) {} - TrackingMode trackingMode; + TrackingMode trackingMode = lastNotePlayedOnChannel; MPEValue lastValueReceivedOnChannel[16]; MPEValue MPENote::* value; MPEValue& getValue (MPENote& note) noexcept { return note.*(value); } @@ -362,6 +387,8 @@ class JUCE_API MPEInstrument LegacyMode legacyMode; MPEDimension pitchbendDimension, pressureDimension, timbreDimension; + void resetLastReceivedValues(); + void updateDimension (int midiChannel, MPEDimension&, MPEValue); void updateDimensionMaster (bool, MPEDimension&, MPEValue); void updateDimensionForNote (MPENote&, MPEDimension&, MPEValue); @@ -374,6 +401,7 @@ class JUCE_API MPEInstrument void processMidiChannelPressureMessage (const MidiMessage&); void processMidiControllerMessage (const MidiMessage&); void processMidiResetAllControllersMessage (const MidiMessage&); + void processMidiAfterTouchMessage (const MidiMessage&); void handlePressureMSB (int midiChannel, int value) noexcept; void handlePressureLSB (int midiChannel, int value) noexcept; void handleTimbreMSB (int midiChannel, int value) noexcept; diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEMessages.cpp b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEMessages.cpp index f6949442..72b86d45 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEMessages.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEMessages.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -106,6 +106,7 @@ MidiBuffer MPEMessages::setZoneLayout (MPEZoneLayout layout) return buffer; } + //============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -113,7 +114,9 @@ MidiBuffer MPEMessages::setZoneLayout (MPEZoneLayout layout) class MPEMessagesTests : public UnitTest { public: - MPEMessagesTests() : UnitTest ("MPEMessages class", "MIDI/MPE") {} + MPEMessagesTests() + : UnitTest ("MPEMessages class", UnitTestCategories::midi) + {} void runTest() override { @@ -213,14 +216,11 @@ class MPEMessagesTests : public UnitTest void extractRawBinaryData (const MidiBuffer& midiBuffer, const uint8* bufferToCopyTo, std::size_t maxBytes) { std::size_t pos = 0; - MidiBuffer::Iterator iter (midiBuffer); - MidiMessage midiMessage; - int samplePosition; // Note: not actually used, so no need to initialise. - while (iter.getNextEvent (midiMessage, samplePosition)) + for (const auto metadata : midiBuffer) { - const uint8* data = midiMessage.getRawData(); - std::size_t dataSize = (std::size_t) midiMessage.getRawDataSize(); + const uint8* data = metadata.data; + std::size_t dataSize = (std::size_t) metadata.numBytes; if (pos + dataSize > maxBytes) return; @@ -233,6 +233,6 @@ class MPEMessagesTests : public UnitTest static MPEMessagesTests MPEMessagesUnitTests; -#endif // JUCE_UNIT_TESTS +#endif } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEMessages.h b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEMessages.h index 133ce3d8..b27abcd3 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEMessages.h +++ b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEMessages.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -35,7 +35,7 @@ namespace juce class instead. You just need to take care to send them to the appropriate per-note MIDI channel. - Note: if you are working with an MPEZoneLayout object inside your app, + Note: If you are working with an MPEZoneLayout object inside your app, you should not use the message sequences provided here. Instead, you should change the zone layout programmatically with the member functions provided in the MPEZoneLayout class itself. You should also make sure that the Expressive @@ -99,7 +99,7 @@ class JUCE_API MPEMessages /** Returns the sequence of MIDI messages that, if sent to an Expressive MIDI device, will reset the whole MPE zone layout of the - device to the laoyut passed in. This will first clear the current lower and upper + device to the layout passed in. This will first clear the current lower and upper zones, then then set the zones contained in the passed-in zone layout, and set their per-note and master pitchbend ranges to their current values. */ diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPENote.cpp b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPENote.cpp index c4c5707c..32cd2988 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPENote.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPENote.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -84,6 +84,7 @@ bool MPENote::operator!= (const MPENote& other) const noexcept return noteID != other.noteID; } + //============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -91,7 +92,9 @@ bool MPENote::operator!= (const MPENote& other) const noexcept class MPENoteTests : public UnitTest { public: - MPENoteTests() : UnitTest ("MPENote class", "MIDI/MPE") {} + MPENoteTests() + : UnitTest ("MPENote class", UnitTestCategories::midi) + {} //============================================================================== void runTest() override @@ -119,6 +122,6 @@ class MPENoteTests : public UnitTest static MPENoteTests MPENoteUnitTests; -#endif // JUCE_UNIT_TESTS +#endif } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPENote.h b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPENote.h index 33d992b4..05a96893 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPENote.h +++ b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPENote.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -115,7 +115,7 @@ struct JUCE_API MPENote */ MPEValue noteOnVelocity { MPEValue::minValue() }; - /** Current per-note pitchbend of the note (in units of MIDI pitchwheel + /** Current per-note pitchbend of the note (in units of MIDI pitchwheel position). This dimension can be modulated while the note sounds. Note: This value is not aware of the currently used pitchbend range, @@ -132,7 +132,7 @@ struct JUCE_API MPENote */ MPEValue pressure { MPEValue::centreValue() }; - /** Inital value of timbre when the note was triggered. + /** Initial value of timbre when the note was triggered. This should never change during the lifetime of an MPENote object. */ MPEValue initialTimbre { MPEValue::centreValue() }; diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiser.cpp b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiser.cpp index ea0028e4..fdd19ba4 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiser.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiser.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -25,12 +25,10 @@ namespace juce MPESynthesiser::MPESynthesiser() { - MPEZoneLayout zoneLayout; - zoneLayout.setLowerZone (15); - setZoneLayout (zoneLayout); } -MPESynthesiser::MPESynthesiser (MPEInstrument* mpeInstrument) : MPESynthesiserBase (mpeInstrument) +MPESynthesiser::MPESynthesiser (MPEInstrument& mpeInstrument) + : MPESynthesiserBase (mpeInstrument) { } @@ -42,13 +40,16 @@ MPESynthesiser::~MPESynthesiser() void MPESynthesiser::startVoice (MPESynthesiserVoice* voice, MPENote noteToStart) { jassert (voice != nullptr); + voice->currentlyPlayingNote = noteToStart; + voice->noteOnTime = lastNoteOnCounter++; voice->noteStarted(); } void MPESynthesiser::stopVoice (MPESynthesiserVoice* voice, MPENote noteToStop, bool allowTailOff) { jassert (voice != nullptr); + voice->currentlyPlayingNote = noteToStop; voice->noteStopped (allowTailOff); } @@ -126,7 +127,7 @@ void MPESynthesiser::noteReleased (MPENote finishedNote) { auto* voice = voices.getUnchecked (i); - if (voice->isCurrentlyPlayingNote(finishedNote)) + if (voice->isCurrentlyPlayingNote (finishedNote)) stopVoice (voice, finishedNote, true); } } @@ -197,7 +198,7 @@ MPESynthesiserVoice* MPESynthesiser::findVoiceToSteal (MPENote noteToStealVoiceF // compilers generating code containing heap allocations.. struct Sorter { - bool operator() (const MPESynthesiserVoice* a, const MPESynthesiserVoice* b) const noexcept { return a->wasStartedBefore (*b); } + bool operator() (const MPESynthesiserVoice* a, const MPESynthesiserVoice* b) const noexcept { return a->noteOnTime < b->noteOnTime; } }; std::sort (usableVoices.begin(), usableVoices.end(), Sorter()); @@ -296,18 +297,29 @@ void MPESynthesiser::reduceNumVoices (const int newNumVoices) void MPESynthesiser::turnOffAllVoices (bool allowTailOff) { - // first turn off all voices (it's more efficient to do this immediately - // rather than to go through the MPEInstrument for this). - for (auto* voice : voices) - voice->noteStopped (allowTailOff); + { + const ScopedLock sl (voicesLock); + + // first turn off all voices (it's more efficient to do this immediately + // rather than to go through the MPEInstrument for this). + for (auto* voice : voices) + { + voice->currentlyPlayingNote.noteOffVelocity = MPEValue::from7BitInt (64); // some reasonable number + voice->currentlyPlayingNote.keyState = MPENote::off; + + voice->noteStopped (allowTailOff); + } + } // finally make sure the MPE Instrument also doesn't have any notes anymore. - instrument->releaseAllNotes(); + instrument.releaseAllNotes(); } //============================================================================== void MPESynthesiser::renderNextSubBlock (AudioBuffer& buffer, int startSample, int numSamples) { + const ScopedLock sl (voicesLock); + for (auto* voice : voices) { if (voice->isActive()) @@ -317,6 +329,8 @@ void MPESynthesiser::renderNextSubBlock (AudioBuffer& buffer, int startSa void MPESynthesiser::renderNextSubBlock (AudioBuffer& buffer, int startSample, int numSamples) { + const ScopedLock sl (voicesLock); + for (auto* voice : voices) { if (voice->isActive()) diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiser.h b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiser.h index d3026937..57862c81 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiser.h +++ b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiser.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -65,14 +65,13 @@ class JUCE_API MPESynthesiser : public MPESynthesiserBase /** Constructor to pass to the synthesiser a custom MPEInstrument object to handle the MPE note state, MIDI channel assignment etc. (in case you need custom logic for this that goes beyond MIDI and MPE). - The synthesiser will take ownership of this object. @see MPESynthesiserBase, MPEInstrument */ - MPESynthesiser (MPEInstrument* instrument); + MPESynthesiser (MPEInstrument& instrumentToUse); /** Destructor. */ - ~MPESynthesiser(); + ~MPESynthesiser() override; //============================================================================== /** Deletes all voices. */ @@ -188,7 +187,7 @@ class JUCE_API MPESynthesiser : public MPESynthesiserBase renderNextBlock(). Do not call it yourself, otherwise the internal MPE note state will become inconsistent. */ - virtual void noteAdded (MPENote newNote) override; + void noteAdded (MPENote newNote) override; /** Stops playing a note. @@ -203,7 +202,7 @@ class JUCE_API MPESynthesiser : public MPESynthesiserBase renderNextBlock(). Do not call it yourself, otherwise the internal MPE note state will become inconsistent. */ - virtual void noteReleased (MPENote finishedNote) override; + void noteReleased (MPENote finishedNote) override; /** Will find any voice that is currently playing changedNote, update its currently playing note, and call its notePressureChanged method. @@ -211,7 +210,7 @@ class JUCE_API MPESynthesiser : public MPESynthesiserBase This method will be called automatically according to the midi data passed into renderNextBlock(). Do not call it yourself. */ - virtual void notePressureChanged (MPENote changedNote) override; + void notePressureChanged (MPENote changedNote) override; /** Will find any voice that is currently playing changedNote, update its currently playing note, and call its notePitchbendChanged method. @@ -219,7 +218,7 @@ class JUCE_API MPESynthesiser : public MPESynthesiserBase This method will be called automatically according to the midi data passed into renderNextBlock(). Do not call it yourself. */ - virtual void notePitchbendChanged (MPENote changedNote) override; + void notePitchbendChanged (MPENote changedNote) override; /** Will find any voice that is currently playing changedNote, update its currently playing note, and call its noteTimbreChanged method. @@ -227,7 +226,7 @@ class JUCE_API MPESynthesiser : public MPESynthesiserBase This method will be called automatically according to the midi data passed into renderNextBlock(). Do not call it yourself. */ - virtual void noteTimbreChanged (MPENote changedNote) override; + void noteTimbreChanged (MPENote changedNote) override; /** Will find any voice that is currently playing changedNote, update its currently playing note, and call its noteKeyStateChanged method. @@ -235,24 +234,24 @@ class JUCE_API MPESynthesiser : public MPESynthesiserBase This method will be called automatically according to the midi data passed into renderNextBlock(). Do not call it yourself. */ - virtual void noteKeyStateChanged (MPENote changedNote) override; + void noteKeyStateChanged (MPENote changedNote) override; //============================================================================== /** This will simply call renderNextBlock for each currently active voice and fill the buffer with the sum. Override this method if you need to do more work to render your audio. */ - virtual void renderNextSubBlock (AudioBuffer& outputAudio, - int startSample, - int numSamples) override; + void renderNextSubBlock (AudioBuffer& outputAudio, + int startSample, + int numSamples) override; /** This will simply call renderNextBlock for each currently active - voice and fill the buffer with the sum. (souble-precision version) + voice and fill the buffer with the sum. (double-precision version) Override this method if you need to do more work to render your audio. */ - virtual void renderNextSubBlock (AudioBuffer& outputAudio, - int startSample, - int numSamples) override; + void renderNextSubBlock (AudioBuffer& outputAudio, + int startSample, + int numSamples) override; //============================================================================== /** Searches through the voices to find one that's not currently playing, and @@ -303,7 +302,8 @@ class JUCE_API MPESynthesiser : public MPESynthesiserBase private: //============================================================================== - bool shouldStealVoices = false; + std::atomic shouldStealVoices { false }; + uint32 lastNoteOnCounter = 0; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MPESynthesiser) }; diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserBase.cpp b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserBase.cpp index 51483f0e..b9631902 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserBase.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserBase.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -24,80 +24,79 @@ namespace juce { MPESynthesiserBase::MPESynthesiserBase() - : instrument (new MPEInstrument) + : instrument (defaultInstrument) { - instrument->addListener (this); + instrument.addListener (this); } -MPESynthesiserBase::MPESynthesiserBase (MPEInstrument* inst) +MPESynthesiserBase::MPESynthesiserBase (MPEInstrument& inst) : instrument (inst) { - jassert (instrument != nullptr); - instrument->addListener (this); + instrument.addListener (this); } //============================================================================== MPEZoneLayout MPESynthesiserBase::getZoneLayout() const noexcept { - return instrument->getZoneLayout(); + return instrument.getZoneLayout(); } void MPESynthesiserBase::setZoneLayout (MPEZoneLayout newLayout) { - instrument->setZoneLayout (newLayout); + instrument.setZoneLayout (newLayout); } //============================================================================== void MPESynthesiserBase::enableLegacyMode (int pitchbendRange, Range channelRange) { - instrument->enableLegacyMode (pitchbendRange, channelRange); + instrument.enableLegacyMode (pitchbendRange, channelRange); } bool MPESynthesiserBase::isLegacyModeEnabled() const noexcept { - return instrument->isLegacyModeEnabled(); + return instrument.isLegacyModeEnabled(); } Range MPESynthesiserBase::getLegacyModeChannelRange() const noexcept { - return instrument->getLegacyModeChannelRange(); + return instrument.getLegacyModeChannelRange(); } void MPESynthesiserBase::setLegacyModeChannelRange (Range channelRange) { - instrument->setLegacyModeChannelRange (channelRange); + instrument.setLegacyModeChannelRange (channelRange); } int MPESynthesiserBase::getLegacyModePitchbendRange() const noexcept { - return instrument->getLegacyModePitchbendRange(); + return instrument.getLegacyModePitchbendRange(); } void MPESynthesiserBase::setLegacyModePitchbendRange (int pitchbendRange) { - instrument->setLegacyModePitchbendRange (pitchbendRange); + instrument.setLegacyModePitchbendRange (pitchbendRange); } //============================================================================== void MPESynthesiserBase::setPressureTrackingMode (TrackingMode modeToUse) { - instrument->setPressureTrackingMode (modeToUse); + instrument.setPressureTrackingMode (modeToUse); } void MPESynthesiserBase::setPitchbendTrackingMode (TrackingMode modeToUse) { - instrument->setPitchbendTrackingMode (modeToUse); + instrument.setPitchbendTrackingMode (modeToUse); } void MPESynthesiserBase::setTimbreTrackingMode (TrackingMode modeToUse) { - instrument->setTimbreTrackingMode (modeToUse); + instrument.setTimbreTrackingMode (modeToUse); } //============================================================================== void MPESynthesiserBase::handleMidiEvent (const MidiMessage& m) { - instrument->processNextMidiEvent (m); + instrument.processNextMidiEvent (m); } //============================================================================== @@ -110,48 +109,32 @@ void MPESynthesiserBase::renderNextBlock (AudioBuffer& outputAudio, // you must set the sample rate before using this! jassert (sampleRate != 0); - MidiBuffer::Iterator midiIterator (inputMidi); - midiIterator.setNextSamplePosition (startSample); - - bool firstEvent = true; - int midiEventPos; - MidiMessage m; - const ScopedLock sl (noteStateLock); - while (numSamples > 0) - { - if (! midiIterator.getNextEvent (m, midiEventPos)) - { - renderNextSubBlock (outputAudio, startSample, numSamples); - return; - } + auto prevSample = startSample; + const auto endSample = startSample + numSamples; - auto samplesToNextMidiMessage = midiEventPos - startSample; + for (auto it = inputMidi.findNextSamplePosition (startSample); it != inputMidi.cend(); ++it) + { + const auto metadata = *it; - if (samplesToNextMidiMessage >= numSamples) - { - renderNextSubBlock (outputAudio, startSample, numSamples); - handleMidiEvent (m); + if (metadata.samplePosition >= endSample) break; - } - if (samplesToNextMidiMessage < ((firstEvent && ! subBlockSubdivisionIsStrict) ? 1 : minimumSubBlockSize)) + const auto smallBlockAllowed = (prevSample == startSample && ! subBlockSubdivisionIsStrict); + const auto thisBlockSize = smallBlockAllowed ? 1 : minimumSubBlockSize; + + if (metadata.samplePosition >= prevSample + thisBlockSize) { - handleMidiEvent (m); - continue; + renderNextSubBlock (outputAudio, prevSample, metadata.samplePosition - prevSample); + prevSample = metadata.samplePosition; } - firstEvent = false; - - renderNextSubBlock (outputAudio, startSample, samplesToNextMidiMessage); - handleMidiEvent (m); - startSample += samplesToNextMidiMessage; - numSamples -= samplesToNextMidiMessage; + handleMidiEvent (metadata.getMessage()); } - while (midiIterator.getNextEvent (m, midiEventPos)) - handleMidiEvent (m); + if (prevSample < endSample) + renderNextSubBlock (outputAudio, prevSample, endSample - prevSample); } // explicit instantiation for supported float types: @@ -164,7 +147,7 @@ void MPESynthesiserBase::setCurrentPlaybackSampleRate (const double newRate) if (sampleRate != newRate) { const ScopedLock sl (noteStateLock); - instrument->releaseAllNotes(); + instrument.releaseAllNotes(); sampleRate = newRate; } } @@ -177,4 +160,216 @@ void MPESynthesiserBase::setMinimumRenderingSubdivisionSize (int numSamples, boo subBlockSubdivisionIsStrict = shouldBeStrict; } +#if JUCE_UNIT_TESTS + +namespace +{ + class MpeSynthesiserBaseTests : public UnitTest + { + enum class CallbackKind { process, midi }; + + struct StartAndLength + { + StartAndLength (int s, int l) : start (s), length (l) {} + + int start = 0; + int length = 0; + + std::tuple tie() const noexcept { return std::tie (start, length); } + + bool operator== (const StartAndLength& other) const noexcept { return tie() == other.tie(); } + bool operator!= (const StartAndLength& other) const noexcept { return tie() != other.tie(); } + + bool operator< (const StartAndLength& other) const noexcept { return tie() < other.tie(); } + }; + + struct Events + { + std::vector blocks; + std::vector messages; + std::vector order; + }; + + class MockSynthesiser : public MPESynthesiserBase + { + public: + Events events; + + void handleMidiEvent (const MidiMessage& m) override + { + events.messages.emplace_back (m); + events.order.emplace_back (CallbackKind::midi); + } + + private: + using MPESynthesiserBase::renderNextSubBlock; + + void renderNextSubBlock (AudioBuffer&, + int startSample, + int numSamples) override + { + events.blocks.push_back ({ startSample, numSamples }); + events.order.emplace_back (CallbackKind::process); + } + }; + + static MidiBuffer makeTestBuffer (const int bufferLength) + { + MidiBuffer result; + + for (int i = 0; i != bufferLength; ++i) + result.addEvent ({}, i); + + return result; + } + + public: + MpeSynthesiserBaseTests() + : UnitTest ("MPE Synthesiser Base", UnitTestCategories::midi) {} + + void runTest() override + { + const auto sumBlockLengths = [] (const std::vector& b) + { + const auto addBlock = [] (int acc, const StartAndLength& info) { return acc + info.length; }; + return std::accumulate (b.begin(), b.end(), 0, addBlock); + }; + + beginTest ("Rendering sparse subblocks works"); + { + const int blockSize = 512; + const auto midi = [&] { MidiBuffer b; b.addEvent ({}, blockSize / 2); return b; }(); + AudioBuffer audio (1, blockSize); + + const auto processEvents = [&] (int start, int length) + { + MockSynthesiser synth; + synth.setMinimumRenderingSubdivisionSize (1, false); + synth.setCurrentPlaybackSampleRate (44100); + synth.renderNextBlock (audio, midi, start, length); + return synth.events; + }; + + { + const auto e = processEvents (0, blockSize); + expect (e.blocks.size() == 2); + expect (e.messages.size() == 1); + expect (std::is_sorted (e.blocks.begin(), e.blocks.end())); + expect (sumBlockLengths (e.blocks) == blockSize); + expect (e.order == std::vector { CallbackKind::process, + CallbackKind::midi, + CallbackKind::process }); + } + } + + beginTest ("Rendering subblocks processes only contained midi events"); + { + const int blockSize = 512; + const auto midi = makeTestBuffer (blockSize); + AudioBuffer audio (1, blockSize); + + const auto processEvents = [&] (int start, int length) + { + MockSynthesiser synth; + synth.setMinimumRenderingSubdivisionSize (1, false); + synth.setCurrentPlaybackSampleRate (44100); + synth.renderNextBlock (audio, midi, start, length); + return synth.events; + }; + + { + const int subBlockLength = 0; + const auto e = processEvents (0, subBlockLength); + expect (e.blocks.size() == 0); + expect (e.messages.size() == 0); + expect (std::is_sorted (e.blocks.begin(), e.blocks.end())); + expect (sumBlockLengths (e.blocks) == subBlockLength); + } + + { + const int subBlockLength = 0; + const auto e = processEvents (1, subBlockLength); + expect (e.blocks.size() == 0); + expect (e.messages.size() == 0); + expect (std::is_sorted (e.blocks.begin(), e.blocks.end())); + expect (sumBlockLengths (e.blocks) == subBlockLength); + } + + { + const int subBlockLength = 1; + const auto e = processEvents (1, subBlockLength); + expect (e.blocks.size() == 1); + expect (e.messages.size() == 1); + expect (std::is_sorted (e.blocks.begin(), e.blocks.end())); + expect (sumBlockLengths (e.blocks) == subBlockLength); + expect (e.order == std::vector { CallbackKind::midi, + CallbackKind::process }); + } + + { + const auto e = processEvents (0, blockSize); + expect (e.blocks.size() == blockSize); + expect (e.messages.size() == blockSize); + expect (std::is_sorted (e.blocks.begin(), e.blocks.end())); + expect (sumBlockLengths (e.blocks) == blockSize); + expect (e.order.front() == CallbackKind::midi); + } + } + + beginTest ("Subblocks respect their minimum size"); + { + const int blockSize = 512; + const auto midi = makeTestBuffer (blockSize); + AudioBuffer audio (1, blockSize); + + const auto blockLengthsAreValid = [] (const std::vector& info, int minLength, bool strict) + { + if (info.size() <= 1) + return true; + + const auto lengthIsValid = [&] (const StartAndLength& s) { return minLength <= s.length; }; + const auto begin = strict ? info.begin() : std::next (info.begin()); + // The final block is allowed to be shorter than the minLength + return std::all_of (begin, std::prev (info.end()), lengthIsValid); + }; + + for (auto strict : { false, true }) + { + for (auto subblockSize : { 1, 16, 32, 64, 1024 }) + { + MockSynthesiser synth; + synth.setMinimumRenderingSubdivisionSize (subblockSize, strict); + synth.setCurrentPlaybackSampleRate (44100); + synth.renderNextBlock (audio, midi, 0, blockSize); + + const auto& e = synth.events; + expectWithinAbsoluteError (float (e.blocks.size()), + std::ceil ((float) blockSize / (float) subblockSize), + 1.0f); + expect (e.messages.size() == blockSize); + expect (std::is_sorted (e.blocks.begin(), e.blocks.end())); + expect (sumBlockLengths (e.blocks) == blockSize); + expect (blockLengthsAreValid (e.blocks, subblockSize, strict)); + } + } + + { + MockSynthesiser synth; + synth.setMinimumRenderingSubdivisionSize (32, true); + synth.setCurrentPlaybackSampleRate (44100); + synth.renderNextBlock (audio, MidiBuffer{}, 0, 16); + + expect (synth.events.blocks == std::vector { { 0, 16 } }); + expect (synth.events.order == std::vector { CallbackKind::process }); + expect (synth.events.messages.empty()); + } + } + } + }; + + MpeSynthesiserBaseTests mpeSynthesiserBaseTests; +} + +#endif + } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserBase.h b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserBase.h index c11c11d0..fd030ef6 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserBase.h +++ b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserBase.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -52,13 +52,12 @@ struct JUCE_API MPESynthesiserBase : public MPEInstrument::Listener /** Constructor. - If you use this constructor, the synthesiser will take ownership of the - provided instrument object, and will use it internally to handle the - MPE note state logic. + If you use this constructor, the synthesiser will use the provided instrument + object to handle the MPE note state logic. This is useful if you want to use an instance of your own class derived from MPEInstrument for the MPE logic. */ - MPESynthesiserBase (MPEInstrument* instrument); + MPESynthesiserBase (MPEInstrument& instrument); //============================================================================== /** Returns the synthesiser's internal MPE zone layout. @@ -88,9 +87,14 @@ struct JUCE_API MPESynthesiserBase : public MPEInstrument::Listener Call this to make sound. This will chop up the AudioBuffer into subBlock pieces separated by events in the MIDI buffer, and then call - processNextSubBlock on each one of them. In between you will get calls + renderNextSubBlock on each one of them. In between you will get calls to noteAdded/Changed/Finished, where you can update parameters that depend on those notes to use for your audio rendering. + + @param outputAudio Buffer into which audio will be rendered + @param inputMidi MIDI events to process + @param startSample The first sample to process in both buffers + @param numSamples The number of samples to process */ template void renderNextBlock (AudioBuffer& outputAudio, @@ -165,7 +169,7 @@ struct JUCE_API MPESynthesiserBase : public MPEInstrument::Listener void setLegacyModePitchbendRange (int pitchbendRange); //============================================================================== - typedef MPEInstrument::TrackingMode TrackingMode; + using TrackingMode = MPEInstrument::TrackingMode; /** Set the MPE tracking mode for the pressure dimension. */ void setPressureTrackingMode (TrackingMode modeToUse); @@ -195,10 +199,12 @@ struct JUCE_API MPESynthesiserBase : public MPEInstrument::Listener protected: //============================================================================== /** @internal */ - ScopedPointer instrument; + MPEInstrument& instrument; private: //============================================================================== + MPEInstrument defaultInstrument { MPEZone (MPEZone::Type::lower, 15) }; + CriticalSection noteStateLock; double sampleRate = 0.0; int minimumSubBlockSize = 32; diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserVoice.cpp b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserVoice.cpp index 5cb03eee..99179f05 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserVoice.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserVoice.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -42,11 +42,6 @@ bool MPESynthesiserVoice::isPlayingButReleased() const noexcept return isActive() && currentlyPlayingNote.keyState == MPENote::off; } -bool MPESynthesiserVoice::wasStartedBefore (const MPESynthesiserVoice& other) const noexcept -{ - return noteStartTime < other.noteStartTime; -} - void MPESynthesiserVoice::clearCurrentNote() noexcept { currentlyPlayingNote = MPENote(); diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserVoice.h b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserVoice.h index f1603d5f..d6ac2454 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserVoice.h +++ b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserVoice.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -156,8 +156,10 @@ class JUCE_API MPESynthesiserVoice */ double getSampleRate() const noexcept { return currentSampleRate; } - /** Returns true if this voice started playing its current note before the other voice did. */ - bool wasStartedBefore (const MPESynthesiserVoice& other) const noexcept; + /** This will be set to an incrementing counter value in MPESynthesiser::startVoice() + and can be used to determine the order in which voices started. + */ + uint32 noteOnTime = 0; protected: //============================================================================== @@ -182,7 +184,6 @@ class JUCE_API MPESynthesiserVoice private: //============================================================================== friend class MPESynthesiser; - uint32 noteStartTime = 0; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MPESynthesiserVoice) }; diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEUtils.cpp b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEUtils.cpp index 18efd66f..4081ad00 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEUtils.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEUtils.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -49,28 +49,28 @@ MPEChannelAssigner::MPEChannelAssigner (Range channelRange) int MPEChannelAssigner::findMidiChannelForNewNote (int noteNumber) noexcept { - if (numChannels == 1) + if (numChannels <= 1) return firstChannel; - for (auto ch = firstChannel; (isLegacy || zone->isLowerZone() ? ch <= lastChannel : ch >= lastChannel); ch += channelIncrement) + for (int ch = firstChannel; (isLegacy || zone->isLowerZone() ? ch <= lastChannel : ch >= lastChannel); ch += channelIncrement) { - if (midiChannels[ch].isFree() && midiChannels[ch].lastNotePlayed == noteNumber) + if (midiChannels[(size_t) ch].isFree() && midiChannels[(size_t) ch].lastNotePlayed == noteNumber) { midiChannelLastAssigned = ch; - midiChannels[ch].notes.add (noteNumber); + midiChannels[(size_t) ch].notes.add (noteNumber); return ch; } } - for (auto ch = midiChannelLastAssigned + channelIncrement; ; ch += channelIncrement) + for (int ch = midiChannelLastAssigned + channelIncrement; ; ch += channelIncrement) { if (ch == lastChannel + channelIncrement) // loop wrap-around ch = firstChannel; - if (midiChannels[ch].isFree()) + if (midiChannels[(size_t) ch].isFree()) { midiChannelLastAssigned = ch; - midiChannels[ch].notes.add (noteNumber); + midiChannels[(size_t) ch].notes.add (noteNumber); return ch; } @@ -79,20 +79,44 @@ int MPEChannelAssigner::findMidiChannelForNewNote (int noteNumber) noexcept } midiChannelLastAssigned = findMidiChannelPlayingClosestNonequalNote (noteNumber); - midiChannels[midiChannelLastAssigned].notes.add (noteNumber); + midiChannels[(size_t) midiChannelLastAssigned].notes.add (noteNumber); return midiChannelLastAssigned; } -void MPEChannelAssigner::noteOff (int noteNumber) +int MPEChannelAssigner::findMidiChannelForExistingNote (int noteNumber) noexcept { - for (auto& ch : midiChannels) + const auto iter = std::find_if (midiChannels.cbegin(), midiChannels.cend(), [&] (auto& ch) { - if (ch.notes.removeAllInstancesOf (noteNumber) > 0) + return std::find (ch.notes.begin(), ch.notes.end(), noteNumber) != ch.notes.end(); + }); + + return iter != midiChannels.cend() ? (int) std::distance (midiChannels.cbegin(), iter) : -1; +} + +void MPEChannelAssigner::noteOff (int noteNumber, int midiChannel) +{ + const auto removeNote = [] (MidiChannel& ch, int noteNum) + { + if (ch.notes.removeAllInstancesOf (noteNum) > 0) { - ch.lastNotePlayed = noteNumber; - return; + ch.lastNotePlayed = noteNum; + return true; } + + return false; + }; + + if (midiChannel >= 0 && midiChannel <= 16) + { + removeNote (midiChannels[(size_t) midiChannel], noteNumber); + return; + } + + for (auto& ch : midiChannels) + { + if (removeNote (ch, noteNumber)) + return; } } @@ -112,9 +136,9 @@ int MPEChannelAssigner::findMidiChannelPlayingClosestNonequalNote (int noteNumbe auto channelWithClosestNote = firstChannel; int closestNoteDistance = 127; - for (auto ch = firstChannel; (isLegacy || zone->isLowerZone() ? ch <= lastChannel : ch >= lastChannel); ch += channelIncrement) + for (int ch = firstChannel; (isLegacy || zone->isLowerZone() ? ch <= lastChannel : ch >= lastChannel); ch += channelIncrement) { - for (auto note : midiChannels[ch].notes) + for (auto note : midiChannels[(size_t) ch].notes) { auto noteDistance = std::abs (note - noteNumber); @@ -255,6 +279,7 @@ void MPEChannelRemapper::zeroArrays() } } + //============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -262,7 +287,7 @@ void MPEChannelRemapper::zeroArrays() struct MPEUtilsUnitTests : public UnitTest { MPEUtilsUnitTests() - : UnitTest ("MPE Utilities", "MIDI/MPE") + : UnitTest ("MPE Utilities", UnitTestCategories::midi) {} void runTest() override @@ -281,24 +306,35 @@ struct MPEUtilsUnitTests : public UnitTest // check that channels are assigned in correct order int noteNum = 60; for (int ch = 2; ch <= 16; ++ch) - expectEquals (channelAssigner.findMidiChannelForNewNote (noteNum++), ch); + { + expectEquals (channelAssigner.findMidiChannelForNewNote (noteNum), ch); + expectEquals (channelAssigner.findMidiChannelForExistingNote (noteNum), ch); + + ++noteNum; + } // check that note-offs are processed channelAssigner.noteOff (60); expectEquals (channelAssigner.findMidiChannelForNewNote (60), 2); + expectEquals (channelAssigner.findMidiChannelForExistingNote (60), 2); channelAssigner.noteOff (61); expectEquals (channelAssigner.findMidiChannelForNewNote (61), 3); + expectEquals (channelAssigner.findMidiChannelForExistingNote (61), 3); // check that assigned channel was last to play note channelAssigner.noteOff (65); channelAssigner.noteOff (66); expectEquals (channelAssigner.findMidiChannelForNewNote (66), 8); expectEquals (channelAssigner.findMidiChannelForNewNote (65), 7); + expectEquals (channelAssigner.findMidiChannelForExistingNote (66), 8); + expectEquals (channelAssigner.findMidiChannelForExistingNote (65), 7); // find closest channel playing nonequal note expectEquals (channelAssigner.findMidiChannelForNewNote (80), 16); expectEquals (channelAssigner.findMidiChannelForNewNote (55), 2); + expectEquals (channelAssigner.findMidiChannelForExistingNote (80), 16); + expectEquals (channelAssigner.findMidiChannelForExistingNote (55), 2); // all notes off channelAssigner.allNotesOff(); @@ -308,10 +344,16 @@ struct MPEUtilsUnitTests : public UnitTest expectEquals (channelAssigner.findMidiChannelForNewNote (65), 7); expectEquals (channelAssigner.findMidiChannelForNewNote (80), 16); expectEquals (channelAssigner.findMidiChannelForNewNote (55), 2); + expectEquals (channelAssigner.findMidiChannelForExistingNote (66), 8); + expectEquals (channelAssigner.findMidiChannelForExistingNote (65), 7); + expectEquals (channelAssigner.findMidiChannelForExistingNote (80), 16); + expectEquals (channelAssigner.findMidiChannelForExistingNote (55), 2); // normal assignment expectEquals (channelAssigner.findMidiChannelForNewNote (101), 3); expectEquals (channelAssigner.findMidiChannelForNewNote (20), 4); + expectEquals (channelAssigner.findMidiChannelForExistingNote (101), 3); + expectEquals (channelAssigner.findMidiChannelForExistingNote (20), 4); } // upper @@ -324,24 +366,35 @@ struct MPEUtilsUnitTests : public UnitTest // check that channels are assigned in correct order int noteNum = 60; for (int ch = 15; ch >= 1; --ch) - expectEquals (channelAssigner.findMidiChannelForNewNote (noteNum++), ch); + { + expectEquals (channelAssigner.findMidiChannelForNewNote (noteNum), ch); + expectEquals (channelAssigner.findMidiChannelForExistingNote (noteNum), ch); + + ++noteNum; + } // check that note-offs are processed channelAssigner.noteOff (60); expectEquals (channelAssigner.findMidiChannelForNewNote (60), 15); + expectEquals (channelAssigner.findMidiChannelForExistingNote (60), 15); channelAssigner.noteOff (61); expectEquals (channelAssigner.findMidiChannelForNewNote (61), 14); + expectEquals (channelAssigner.findMidiChannelForExistingNote (61), 14); // check that assigned channel was last to play note channelAssigner.noteOff (65); channelAssigner.noteOff (66); expectEquals (channelAssigner.findMidiChannelForNewNote (66), 9); expectEquals (channelAssigner.findMidiChannelForNewNote (65), 10); + expectEquals (channelAssigner.findMidiChannelForExistingNote (66), 9); + expectEquals (channelAssigner.findMidiChannelForExistingNote (65), 10); // find closest channel playing nonequal note expectEquals (channelAssigner.findMidiChannelForNewNote (80), 1); expectEquals (channelAssigner.findMidiChannelForNewNote (55), 15); + expectEquals (channelAssigner.findMidiChannelForExistingNote (80), 1); + expectEquals (channelAssigner.findMidiChannelForExistingNote (55), 15); // all notes off channelAssigner.allNotesOff(); @@ -351,10 +404,16 @@ struct MPEUtilsUnitTests : public UnitTest expectEquals (channelAssigner.findMidiChannelForNewNote (65), 10); expectEquals (channelAssigner.findMidiChannelForNewNote (80), 1); expectEquals (channelAssigner.findMidiChannelForNewNote (55), 15); + expectEquals (channelAssigner.findMidiChannelForExistingNote (66), 9); + expectEquals (channelAssigner.findMidiChannelForExistingNote (65), 10); + expectEquals (channelAssigner.findMidiChannelForExistingNote (80), 1); + expectEquals (channelAssigner.findMidiChannelForExistingNote (55), 15); // normal assignment expectEquals (channelAssigner.findMidiChannelForNewNote (101), 14); expectEquals (channelAssigner.findMidiChannelForNewNote (20), 13); + expectEquals (channelAssigner.findMidiChannelForExistingNote (101), 14); + expectEquals (channelAssigner.findMidiChannelForExistingNote (20), 13); } // legacy @@ -364,24 +423,35 @@ struct MPEUtilsUnitTests : public UnitTest // check that channels are assigned in correct order int noteNum = 60; for (int ch = 1; ch <= 16; ++ch) - expectEquals (channelAssigner.findMidiChannelForNewNote (noteNum++), ch); + { + expectEquals (channelAssigner.findMidiChannelForNewNote (noteNum), ch); + expectEquals (channelAssigner.findMidiChannelForExistingNote (noteNum), ch); + + ++noteNum; + } // check that note-offs are processed channelAssigner.noteOff (60); expectEquals (channelAssigner.findMidiChannelForNewNote (60), 1); + expectEquals (channelAssigner.findMidiChannelForExistingNote (60), 1); channelAssigner.noteOff (61); expectEquals (channelAssigner.findMidiChannelForNewNote (61), 2); + expectEquals (channelAssigner.findMidiChannelForExistingNote (61), 2); // check that assigned channel was last to play note channelAssigner.noteOff (65); channelAssigner.noteOff (66); expectEquals (channelAssigner.findMidiChannelForNewNote (66), 7); expectEquals (channelAssigner.findMidiChannelForNewNote (65), 6); + expectEquals (channelAssigner.findMidiChannelForExistingNote (66), 7); + expectEquals (channelAssigner.findMidiChannelForExistingNote (65), 6); // find closest channel playing nonequal note expectEquals (channelAssigner.findMidiChannelForNewNote (80), 16); expectEquals (channelAssigner.findMidiChannelForNewNote (55), 1); + expectEquals (channelAssigner.findMidiChannelForExistingNote (80), 16); + expectEquals (channelAssigner.findMidiChannelForExistingNote (55), 1); // all notes off channelAssigner.allNotesOff(); @@ -391,10 +461,16 @@ struct MPEUtilsUnitTests : public UnitTest expectEquals (channelAssigner.findMidiChannelForNewNote (65), 6); expectEquals (channelAssigner.findMidiChannelForNewNote (80), 16); expectEquals (channelAssigner.findMidiChannelForNewNote (55), 1); + expectEquals (channelAssigner.findMidiChannelForExistingNote (66), 7); + expectEquals (channelAssigner.findMidiChannelForExistingNote (65), 6); + expectEquals (channelAssigner.findMidiChannelForExistingNote (80), 16); + expectEquals (channelAssigner.findMidiChannelForExistingNote (55), 1); // normal assignment expectEquals (channelAssigner.findMidiChannelForNewNote (101), 2); expectEquals (channelAssigner.findMidiChannelForNewNote (20), 3); + expectEquals (channelAssigner.findMidiChannelForExistingNote (101), 2); + expectEquals (channelAssigner.findMidiChannelForExistingNote (20), 3); } } @@ -475,4 +551,5 @@ struct MPEUtilsUnitTests : public UnitTest static MPEUtilsUnitTests MPEUtilsUnitTests; #endif + } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEUtils.h b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEUtils.h index 4bb656c5..be503bfb 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEUtils.h +++ b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEUtils.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -63,17 +63,25 @@ class MPEChannelAssigner */ int findMidiChannelForNewNote (int noteNumber) noexcept; + /** If a note has been added using findMidiChannelForNewNote() this will return the channel + to which it was assigned, otherwise it will return -1. + */ + int findMidiChannelForExistingNote (int initialNoteOnNumber) noexcept; + /** You must call this method for all note-offs that you receive so that this class can keep track of the currently playing notes internally. + + You can specify the channel number the note off happened on. If you don't, it will + look through all channels to find the registered midi note matching the given note number. */ - void noteOff (int noteNumber); + void noteOff (int noteNumber, int midiChannel = -1); /** Call this to clear all currently playing notes. */ void allNotesOff(); private: bool isLegacy = false; - ScopedPointer zone; + std::unique_ptr zone; int channelIncrement, numChannels, firstChannel, lastChannel, midiChannelLastAssigned; //============================================================================== @@ -83,7 +91,7 @@ class MPEChannelAssigner int lastNotePlayed = -1; bool isFree() const noexcept { return notes.isEmpty(); } }; - MidiChannel midiChannels[17]; + std::array midiChannels; //============================================================================== int findMidiChannelPlayingClosestNonequalNote (int noteNumber) noexcept; diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEValue.cpp b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEValue.cpp index b9a07130..9f16fa3a 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEValue.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEValue.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -43,6 +43,18 @@ MPEValue MPEValue::from14BitInt (int value) noexcept return { value }; } +MPEValue MPEValue::fromUnsignedFloat (float value) noexcept +{ + jassert (0.0f <= value && value <= 1.0f); + return { roundToInt (value * 16383.0f) }; +} + +MPEValue MPEValue::fromSignedFloat (float value) noexcept +{ + jassert (-1.0f <= value && value <= 1.0f); + return { roundToInt (((value + 1.0f) * 16383.0f) / 2.0f) }; +} + //============================================================================== MPEValue MPEValue::minValue() noexcept { return MPEValue::from7BitInt (0); } MPEValue MPEValue::centreValue() noexcept { return MPEValue::from7BitInt (64); } @@ -82,6 +94,7 @@ bool MPEValue::operator!= (const MPEValue& other) const noexcept return ! operator== (other); } + //============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -89,7 +102,9 @@ bool MPEValue::operator!= (const MPEValue& other) const noexcept class MPEValueTests : public UnitTest { public: - MPEValueTests() : UnitTest ("MPEValue class", "MIDI/MPE") {} + MPEValueTests() + : UnitTest ("MPEValue class", UnitTestCategories::midi) + {} void runTest() override { @@ -118,26 +133,34 @@ class MPEValueTests : public UnitTest beginTest ("zero/minimum value"); { - expectValuesConsistent (MPEValue::from7BitInt (0), 0, 0, -1.0f, 0.0f); - expectValuesConsistent (MPEValue::from14BitInt (0), 0, 0, -1.0f, 0.0f); + expectValuesConsistent (MPEValue::from7BitInt (0), 0, 0, -1.0f, 0.0f); + expectValuesConsistent (MPEValue::from14BitInt (0), 0, 0, -1.0f, 0.0f); + expectValuesConsistent (MPEValue::fromUnsignedFloat (0.0f), 0, 0, -1.0f, 0.0f); + expectValuesConsistent (MPEValue::fromSignedFloat (-1.0f), 0, 0, -1.0f, 0.0f); } beginTest ("maximum value"); { - expectValuesConsistent (MPEValue::from7BitInt (127), 127, 16383, 1.0f, 1.0f); - expectValuesConsistent (MPEValue::from14BitInt (16383), 127, 16383, 1.0f, 1.0f); + expectValuesConsistent (MPEValue::from7BitInt (127), 127, 16383, 1.0f, 1.0f); + expectValuesConsistent (MPEValue::from14BitInt (16383), 127, 16383, 1.0f, 1.0f); + expectValuesConsistent (MPEValue::fromUnsignedFloat (1.0f), 127, 16383, 1.0f, 1.0f); + expectValuesConsistent (MPEValue::fromSignedFloat (1.0f), 127, 16383, 1.0f, 1.0f); } beginTest ("centre value"); { - expectValuesConsistent (MPEValue::from7BitInt (64), 64, 8192, 0.0f, 0.5f); - expectValuesConsistent (MPEValue::from14BitInt (8192), 64, 8192, 0.0f, 0.5f); + expectValuesConsistent (MPEValue::from7BitInt (64), 64, 8192, 0.0f, 0.5f); + expectValuesConsistent (MPEValue::from14BitInt (8192), 64, 8192, 0.0f, 0.5f); + expectValuesConsistent (MPEValue::fromUnsignedFloat (0.5f), 64, 8192, 0.0f, 0.5f); + expectValuesConsistent (MPEValue::fromSignedFloat (0.0f), 64, 8192, 0.0f, 0.5f); } beginTest ("value halfway between min and centre"); { - expectValuesConsistent (MPEValue::from7BitInt (32), 32, 4096, -0.5f, 0.25f); - expectValuesConsistent (MPEValue::from14BitInt (4096), 32, 4096, -0.5f, 0.25f); + expectValuesConsistent (MPEValue::from7BitInt (32), 32, 4096, -0.5f, 0.25f); + expectValuesConsistent (MPEValue::from14BitInt (4096), 32, 4096, -0.5f, 0.25f); + expectValuesConsistent (MPEValue::fromUnsignedFloat (0.25f), 32, 4096, -0.5f, 0.25f); + expectValuesConsistent (MPEValue::fromSignedFloat (-0.5f), 32, 4096, -0.5f, 0.25f); } } @@ -165,6 +188,6 @@ class MPEValueTests : public UnitTest static MPEValueTests MPEValueUnitTests; -#endif // JUCE_UNIT_TESTS +#endif } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEValue.h b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEValue.h index 242d9c5c..5c05ca00 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEValue.h +++ b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEValue.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -53,6 +53,12 @@ class JUCE_API MPEValue */ static MPEValue from14BitInt (int value) noexcept; + /** Constructs an MPEValue from a float between 0.0f and 1.0f. */ + static MPEValue fromUnsignedFloat (float value) noexcept; + + /** Constructs an MPEValue from a float between -1.0f and 1.0f. */ + static MPEValue fromSignedFloat (float value) noexcept; + /** Constructs an MPEValue corresponding to the centre value. */ static MPEValue centreValue() noexcept; diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp index 7f94dee8..07d41a4c 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -23,7 +23,17 @@ namespace juce { -MPEZoneLayout::MPEZoneLayout() noexcept {} +MPEZoneLayout::MPEZoneLayout (MPEZone lower, MPEZone upper) + : lowerZone (lower), upperZone (upper) +{ +} + +MPEZoneLayout::MPEZoneLayout (MPEZone zone) + : lowerZone (zone.isLowerZone() ? zone : MPEZone()), + upperZone (! zone.isLowerZone() ? zone : MPEZone()) +{ +} + MPEZoneLayout::MPEZoneLayout (const MPEZoneLayout& other) : lowerZone (other.lowerZone), @@ -54,9 +64,9 @@ void MPEZoneLayout::setZone (bool isLower, int numMemberChannels, int perNotePit checkAndLimitZoneParameters (0, 96, masterPitchbendRange); if (isLower) - lowerZone = { true, numMemberChannels, perNotePitchbendRange, masterPitchbendRange }; + lowerZone = { MPEZone::Type::lower, numMemberChannels, perNotePitchbendRange, masterPitchbendRange }; else - upperZone = { false, numMemberChannels, perNotePitchbendRange, masterPitchbendRange }; + upperZone = { MPEZone::Type::upper, numMemberChannels, perNotePitchbendRange, masterPitchbendRange }; if (numMemberChannels > 0) { @@ -86,8 +96,8 @@ void MPEZoneLayout::setUpperZone (int numMemberChannels, int perNotePitchbendRan void MPEZoneLayout::clearAllZones() { - lowerZone = { true, 0 }; - upperZone = { false, 0 }; + lowerZone = { MPEZone::Type::lower, 0 }; + upperZone = { MPEZone::Type::upper, 0 }; sendLayoutChangeMessage(); } @@ -128,7 +138,7 @@ void MPEZoneLayout::processZoneLayoutRpnMessage (MidiRPNMessage rpn) } } -void MPEZoneLayout::updateMasterPitchbend (Zone& zone, int value) +void MPEZoneLayout::updateMasterPitchbend (MPEZone& zone, int value) { if (zone.masterPitchbendRange != value) { @@ -138,7 +148,7 @@ void MPEZoneLayout::updateMasterPitchbend (Zone& zone, int value) } } -void MPEZoneLayout::updatePerNotePitchbendRange (Zone& zone, int value) +void MPEZoneLayout::updatePerNotePitchbendRange (MPEZone& zone, int value) { if (zone.perNotePitchbendRange != value) { @@ -169,12 +179,8 @@ void MPEZoneLayout::processPitchbendRangeRpnMessage (MidiRPNMessage rpn) void MPEZoneLayout::processNextMidiBuffer (const MidiBuffer& buffer) { - MidiBuffer::Iterator iter (buffer); - MidiMessage message; - int samplePosition; // not actually used, so no need to initialise. - - while (iter.getNextEvent (message, samplePosition)) - processNextMidiEvent (message); + for (const auto metadata : buffer) + processNextMidiEvent (metadata.getMessage()); } //============================================================================== @@ -205,6 +211,7 @@ void MPEZoneLayout::checkAndLimitZoneParameters (int minValue, int maxValue, } } + //============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -212,7 +219,9 @@ void MPEZoneLayout::checkAndLimitZoneParameters (int minValue, int maxValue, class MPEZoneLayoutTests : public UnitTest { public: - MPEZoneLayoutTests() : UnitTest ("MPEZoneLayout class", "MIDI/MPE") {} + MPEZoneLayoutTests() + : UnitTest ("MPEZoneLayout class", UnitTestCategories::midi) + {} void runTest() override { @@ -382,6 +391,6 @@ class MPEZoneLayoutTests : public UnitTest static MPEZoneLayoutTests MPEZoneLayoutUnitTests; -#endif // JUCE_UNIT_TESTS +#endif } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.h b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.h index 1414324c..3da24ce7 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.h +++ b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -23,6 +23,83 @@ namespace juce { +//============================================================================== +/** + This struct represents an MPE zone. + + It can either be a lower or an upper zone, where: + - A lower zone encompasses master channel 1 and an arbitrary number of ascending + MIDI channels, increasing from channel 2. + - An upper zone encompasses master channel 16 and an arbitrary number of descending + MIDI channels, decreasing from channel 15. + + It also defines a pitchbend range (in semitones) to be applied for per-note pitchbends and + master pitchbends, respectively. +*/ +struct MPEZone +{ + enum class Type { lower, upper }; + + MPEZone() = default; + MPEZone (const MPEZone& other) = default; + + MPEZone (Type type, int memberChannels = 0, int perNotePitchbend = 48, int masterPitchbend = 2) + : zoneType (type), + numMemberChannels (memberChannels), + perNotePitchbendRange (perNotePitchbend), + masterPitchbendRange (masterPitchbend) + {} + + bool isLowerZone() const noexcept { return zoneType == Type::lower; } + bool isUpperZone() const noexcept { return zoneType == Type::upper; } + + bool isActive() const noexcept { return numMemberChannels > 0; } + + int getMasterChannel() const noexcept { return isLowerZone() ? lowerZoneMasterChannel : upperZoneMasterChannel; } + int getFirstMemberChannel() const noexcept { return isLowerZone() ? lowerZoneMasterChannel + 1 : upperZoneMasterChannel - 1; } + int getLastMemberChannel() const noexcept { return isLowerZone() ? (lowerZoneMasterChannel + numMemberChannels) + : (upperZoneMasterChannel - numMemberChannels); } + + bool isUsingChannelAsMemberChannel (int channel) const noexcept + { + return isLowerZone() ? (lowerZoneMasterChannel < channel && channel <= getLastMemberChannel()) + : (channel < upperZoneMasterChannel && getLastMemberChannel() <= channel); + } + + bool isUsing (int channel) const noexcept + { + return isUsingChannelAsMemberChannel (channel) || channel == getMasterChannel(); + } + + static auto tie (const MPEZone& z) + { + return std::tie (z.zoneType, + z.numMemberChannels, + z.perNotePitchbendRange, + z.masterPitchbendRange); + } + + bool operator== (const MPEZone& other) const + { + return tie (*this) == tie (other); + } + + bool operator!= (const MPEZone& other) const + { + return tie (*this) != tie (other); + } + + //============================================================================== + static constexpr int lowerZoneMasterChannel = 1, + upperZoneMasterChannel = 16; + + Type zoneType = Type::lower; + + int numMemberChannels = 0; + int perNotePitchbendRange = 48; + int masterPitchbendRange = 2; +}; + //============================================================================== /** This class represents the current MPE zone layout of a device capable of handling MPE. @@ -44,90 +121,28 @@ namespace juce class JUCE_API MPEZoneLayout { public: - /** Default constructor. - - This will create a layout with inactive lower and upper zones, representing - a device with MPE mode disabled. + //============================================================================== + /** Creates a layout with inactive upper and lower zones. */ + MPEZoneLayout() = default; - You can set the lower or upper MPE zones using the setZone() method. + /** Creates a layout with the given upper and lower zones. */ + MPEZoneLayout (MPEZone lower, MPEZone upper); - @see setZone - */ - MPEZoneLayout() noexcept; + /** Creates a layout with a single upper or lower zone, leaving the other zone uninitialised. */ + MPEZoneLayout (MPEZone singleZone); - /** Copy constuctor. - This will not copy the listeners registered to the MPEZoneLayout. - */ MPEZoneLayout (const MPEZoneLayout& other); - - /** Copy assignment operator. - This will not copy the listeners registered to the MPEZoneLayout. - */ MPEZoneLayout& operator= (const MPEZoneLayout& other); - //============================================================================== - /** - This struct represents an MPE zone. + bool operator== (const MPEZoneLayout& other) const { return lowerZone == other.lowerZone && upperZone == other.upperZone; } + bool operator!= (const MPEZoneLayout& other) const { return ! operator== (other); } - It can either be a lower or an upper zone, where: - - A lower zone encompasses master channel 1 and an arbitrary number of ascending - MIDI channels, increasing from channel 2. - - An upper zone encompasses master channel 16 and an arbitrary number of descending - MIDI channels, decreasing from channel 15. + //============================================================================== + /** Returns a struct representing the lower MPE zone. */ + MPEZone getLowerZone() const noexcept { return lowerZone; } - It also defines a pitchbend range (in semitones) to be applied for per-note pitchbends and - master pitchbends, respectively. - */ - struct Zone - { - Zone (const Zone& other) noexcept - : numMemberChannels (other.numMemberChannels), - perNotePitchbendRange (other.perNotePitchbendRange), - masterPitchbendRange (other.masterPitchbendRange), - lowerZone (other.lowerZone) - { - } - - bool isLowerZone() const noexcept { return lowerZone; } - bool isUpperZone() const noexcept { return ! lowerZone; } - - bool isActive() const noexcept { return numMemberChannels > 0; } - - int getMasterChannel() const noexcept { return lowerZone ? 1 : 16; } - int getFirstMemberChannel() const noexcept { return lowerZone ? 2 : 15; } - int getLastMemberChannel() const noexcept { return lowerZone ? (1 + numMemberChannels) - : (16 - numMemberChannels); } - - bool isUsingChannelAsMemberChannel (int channel) const noexcept - { - return lowerZone ? (channel > 1 && channel <= 1 + numMemberChannels) - : (channel < 16 && channel >= 16 - numMemberChannels); - } - - bool operator== (const Zone& other) const noexcept { return lowerZone == other.lowerZone - && numMemberChannels == other.numMemberChannels - && perNotePitchbendRange == other.perNotePitchbendRange - && masterPitchbendRange == other.masterPitchbendRange; } - - bool operator!= (const Zone& other) const noexcept { return ! operator== (other); } - - int numMemberChannels; - int perNotePitchbendRange; - int masterPitchbendRange; - - private: - friend class MPEZoneLayout; - - Zone (bool lower, int memberChans = 0, int perNotePb = 48, int masterPb = 2) noexcept - : numMemberChannels (memberChans), - perNotePitchbendRange (perNotePb), - masterPitchbendRange (masterPb), - lowerZone (lower) - { - } - - bool lowerZone; - }; + /** Returns a struct representing the upper MPE zone. */ + MPEZone getUpperZone() const noexcept { return upperZone; } /** Sets the lower zone of this layout. */ void setLowerZone (int numMemberChannels = 0, @@ -139,17 +154,14 @@ class JUCE_API MPEZoneLayout int perNotePitchbendRange = 48, int masterPitchbendRange = 2) noexcept; - /** Returns a struct representing the lower MPE zone. */ - const Zone getLowerZone() const noexcept { return lowerZone; } - - /** Returns a struct representing the upper MPE zone. */ - const Zone getUpperZone() const noexcept { return upperZone; } - /** Clears the lower and upper zones of this layout, making them both inactive and disabling MPE mode. */ void clearAllZones(); + /** Returns true if either of the zones are active. */ + bool isActive() const { return lowerZone.isActive() || upperZone.isActive(); } + //============================================================================== /** Pass incoming MIDI messages to an object of this class if you want the zone layout to properly react to MPE RPN messages like an @@ -185,7 +197,7 @@ class JUCE_API MPEZoneLayout { public: /** Destructor. */ - virtual ~Listener() {} + virtual ~Listener() = default; /** Implement this callback to be notified about any changes to this MPEZoneLayout. Will be called whenever a zone is added, zones are @@ -201,10 +213,14 @@ class JUCE_API MPEZoneLayout /** Removes a listener. */ void removeListener (Listener* const listenerToRemove) noexcept; + #ifndef DOXYGEN + using Zone = MPEZone; + #endif + private: //============================================================================== - Zone lowerZone { true, 0 }; - Zone upperZone { false, 0 }; + MPEZone lowerZone { MPEZone::Type::lower, 0 }; + MPEZone upperZone { MPEZone::Type::upper, 0 }; MidiRPNDetector rpnDetector; ListenerList listeners; @@ -216,8 +232,8 @@ class JUCE_API MPEZoneLayout void processZoneLayoutRpnMessage (MidiRPNMessage); void processPitchbendRangeRpnMessage (MidiRPNMessage); - void updateMasterPitchbend (Zone&, int); - void updatePerNotePitchbendRange (Zone&, int); + void updateMasterPitchbend (MPEZone&, int); + void updatePerNotePitchbendRange (MPEZone&, int); void sendLayoutChangeMessage(); void checkAndLimitZoneParameters (int, int, int&) noexcept; diff --git a/JuceLibraryCode/modules/juce_audio_basics/native/juce_mac_CoreAudioLayouts.h b/JuceLibraryCode/modules/juce_audio_basics/native/juce_mac_CoreAudioLayouts.h index 8fa387a6..9a986dbe 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/native/juce_mac_CoreAudioLayouts.h +++ b/JuceLibraryCode/modules/juce_audio_basics/native/juce_mac_CoreAudioLayouts.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -23,10 +23,140 @@ namespace juce { -#if JUCE_MAC || JUCE_IOS && ! DOXYGEN +#if ! defined (DOXYGEN) && (JUCE_MAC || JUCE_IOS) struct CoreAudioLayouts { + //============================================================================== + struct LayoutTagSpeakerList + { + AudioChannelLayoutTag tag; + AudioChannelSet::ChannelType channelTypes[16]; + }; + + //============================================================================== + // This list has been derived from https://pastebin.com/24dQ4BPJ + // Apple channel labels have been replaced by JUCE channel names + // This means that some layouts will be identical in JUCE but not in CoreAudio + + // In Apple's official definition the following tags exist with the same speaker layout and order + // even when *not* represented in JUCE channels + // kAudioChannelLayoutTag_Binaural = kAudioChannelLayoutTag_Stereo + // kAudioChannelLayoutTag_MPEG_5_0_B = kAudioChannelLayoutTag_Pentagonal + // kAudioChannelLayoutTag_ITU_2_2 = kAudioChannelLayoutTag_Quadraphonic + // kAudioChannelLayoutTag_AudioUnit_6_0 = kAudioChannelLayoutTag_Hexagonal + struct SpeakerLayoutTable : AudioChannelSet // save us some typing + { + template + static constexpr auto getArray (Items... items) + { + return std::array { { items... } }; + } + + static constexpr auto get() + { + using List = LayoutTagSpeakerList; + + return getArray (List { kAudioChannelLayoutTag_Mono, { centre } }, + List { kAudioChannelLayoutTag_Stereo, { left, right } }, + List { kAudioChannelLayoutTag_MPEG_3_0_A, { left, right, centre } }, + List { kAudioChannelLayoutTag_ITU_2_1, { left, right, centreSurround } }, + List { kAudioChannelLayoutTag_MPEG_4_0_A, { left, right, centre, centreSurround } }, + List { kAudioChannelLayoutTag_MPEG_5_0_A, { left, right, centre, leftSurround, rightSurround } }, + List { kAudioChannelLayoutTag_MPEG_5_1_A, { left, right, centre, LFE, leftSurround, rightSurround } }, + List { kAudioChannelLayoutTag_AudioUnit_6_0, { left, right, leftSurround, rightSurround, centre, centreSurround } }, + List { kAudioChannelLayoutTag_MPEG_6_1_A, { left, right, centre, LFE, leftSurround, rightSurround, centreSurround } }, + List { kAudioChannelLayoutTag_DTS_6_0_A, { leftSurroundSide, rightSurroundSide, left, right, leftSurround, rightSurround } }, + List { kAudioChannelLayoutTag_DTS_6_1_A, { leftSurroundSide, rightSurroundSide, left, right, leftSurround, rightSurround, LFE } }, + List { kAudioChannelLayoutTag_AudioUnit_7_0, { left, right, leftSurroundSide, rightSurroundSide, centre, leftSurroundRear, rightSurroundRear } }, + List { kAudioChannelLayoutTag_AudioUnit_7_0_Front, { left, right, leftSurround, rightSurround, centre, leftCentre, rightCentre } }, + List { kAudioChannelLayoutTag_MPEG_7_1_C, { left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear } }, + List { kAudioChannelLayoutTag_MPEG_7_1_A, { left, right, centre, LFE, leftSurround, rightSurround, leftCentre, rightCentre } }, + List { kAudioChannelLayoutTag_Ambisonic_B_Format, { ambisonicW, ambisonicX, ambisonicY, ambisonicZ } }, + List { kAudioChannelLayoutTag_Quadraphonic, { left, right, leftSurround, rightSurround } }, + List { kAudioChannelLayoutTag_Pentagonal, { left, right, leftSurroundRear, rightSurroundRear, centre } }, + List { kAudioChannelLayoutTag_Hexagonal, { left, right, leftSurroundRear, rightSurroundRear, centre, centreSurround } }, + List { kAudioChannelLayoutTag_Octagonal, { left, right, leftSurround, rightSurround, centre, centreSurround, wideLeft, wideRight } }, + + #if defined (MAC_OS_VERSION_11_0) + List { kAudioChannelLayoutTag_Atmos_5_1_4, { left, right, centre, LFE, leftSurround, rightSurround, topFrontLeft, topFrontRight, topRearLeft, topRearRight } }, + List { kAudioChannelLayoutTag_Atmos_7_1_2, { left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topSideLeft, topSideRight } }, + #endif + + #if defined (MAC_OS_X_VERSION_10_15) + List { kAudioChannelLayoutTag_Atmos_5_1_2, { left, right, centre, LFE, leftSurround, rightSurround, topSideLeft, topSideRight } }, + List { kAudioChannelLayoutTag_Atmos_7_1_4, { left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topFrontLeft, topFrontRight, topRearLeft, topRearRight } }, + List { kAudioChannelLayoutTag_Atmos_9_1_6, { left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight } }, + #endif + + // More uncommon layouts... + List { kAudioChannelLayoutTag_StereoHeadphones, { left, right } }, + List { kAudioChannelLayoutTag_MatrixStereo, { left, right } }, + List { kAudioChannelLayoutTag_MidSide, { centre, discreteChannel0 } }, + List { kAudioChannelLayoutTag_XY, { ambisonicX, ambisonicY } }, + List { kAudioChannelLayoutTag_Binaural, { left, right } }, + List { kAudioChannelLayoutTag_Cube, { left, right, leftSurround, rightSurround, topFrontLeft, topFrontRight, topRearLeft, topRearRight } }, + List { kAudioChannelLayoutTag_MPEG_3_0_B, { centre, left, right } }, + List { kAudioChannelLayoutTag_MPEG_4_0_B, { centre, left, right, centreSurround } }, + List { kAudioChannelLayoutTag_MPEG_5_0_B, { left, right, leftSurround, rightSurround, centre } }, + List { kAudioChannelLayoutTag_MPEG_5_0_C, { left, centre, right, leftSurround, rightSurround } }, + List { kAudioChannelLayoutTag_MPEG_5_0_D, { centre, left, right, leftSurround, rightSurround } }, + List { kAudioChannelLayoutTag_MPEG_5_1_B, { left, right, leftSurround, rightSurround, centre, LFE } }, + List { kAudioChannelLayoutTag_MPEG_5_1_C, { left, centre, right, leftSurround, rightSurround, LFE } }, + List { kAudioChannelLayoutTag_MPEG_5_1_D, { centre, left, right, leftSurround, rightSurround, LFE } }, + List { kAudioChannelLayoutTag_MPEG_7_1_B, { centre, leftCentre, rightCentre, left, right, leftSurround, rightSurround, LFE } }, + List { kAudioChannelLayoutTag_Emagic_Default_7_1, { left, right, leftSurround, rightSurround, centre, LFE, leftCentre, rightCentre } }, + List { kAudioChannelLayoutTag_SMPTE_DTV, { left, right, centre, LFE, leftSurround, rightSurround, discreteChannel0 /* leftMatrixTotal */, (ChannelType) (discreteChannel0 + 1) /* rightMatrixTotal */} }, + List { kAudioChannelLayoutTag_ITU_2_2, { left, right, leftSurround, rightSurround } }, + List { kAudioChannelLayoutTag_DVD_4, { left, right, LFE } }, + List { kAudioChannelLayoutTag_DVD_5, { left, right, LFE, centreSurround } }, + List { kAudioChannelLayoutTag_DVD_6, { left, right, LFE, leftSurround, rightSurround } }, + List { kAudioChannelLayoutTag_DVD_10, { left, right, centre, LFE } }, + List { kAudioChannelLayoutTag_DVD_11, { left, right, centre, LFE, centreSurround } }, + List { kAudioChannelLayoutTag_DVD_18, { left, right, leftSurround, rightSurround, LFE } }, + List { kAudioChannelLayoutTag_AAC_6_0, { centre, left, right, leftSurround, rightSurround, centreSurround } }, + List { kAudioChannelLayoutTag_AAC_6_1, { centre, left, right, leftSurround, rightSurround, centreSurround, LFE } }, + List { kAudioChannelLayoutTag_AAC_7_0, { centre, left, right, leftSurround, rightSurround, leftSurroundRear, rightSurroundRear } }, + List { kAudioChannelLayoutTag_AAC_7_1_B, { centre, left, right, leftSurround, rightSurround, leftSurroundRear, rightSurroundRear, LFE } }, + List { kAudioChannelLayoutTag_AAC_7_1_C, { centre, left, right, leftSurround, rightSurround, LFE, topFrontLeft, topFrontRight } }, + List { kAudioChannelLayoutTag_AAC_Octagonal, { centre, left, right, leftSurround, rightSurround, leftSurroundRear, rightSurroundRear, centreSurround } }, + List { kAudioChannelLayoutTag_TMH_10_2_std, { left, right, centre, topFrontCentre, leftSurroundSide, rightSurroundSide, leftSurround, rightSurround, topFrontLeft, topFrontRight, wideLeft, wideRight, topRearCentre, centreSurround, LFE, LFE2 } }, + List { kAudioChannelLayoutTag_AC3_1_0_1, { centre, LFE } }, + List { kAudioChannelLayoutTag_AC3_3_0, { left, centre, right } }, + List { kAudioChannelLayoutTag_AC3_3_1, { left, centre, right, centreSurround } }, + List { kAudioChannelLayoutTag_AC3_3_0_1, { left, centre, right, LFE } }, + List { kAudioChannelLayoutTag_AC3_2_1_1, { left, right, centreSurround, LFE } }, + List { kAudioChannelLayoutTag_AC3_3_1_1, { left, centre, right, centreSurround, LFE } }, + List { kAudioChannelLayoutTag_EAC_6_0_A, { left, centre, right, leftSurround, rightSurround, centreSurround } }, + List { kAudioChannelLayoutTag_EAC_7_0_A, { left, centre, right, leftSurround, rightSurround, leftSurroundRear, rightSurroundRear } }, + List { kAudioChannelLayoutTag_EAC3_6_1_A, { left, centre, right, leftSurround, rightSurround, LFE, centreSurround } }, + List { kAudioChannelLayoutTag_EAC3_6_1_B, { left, centre, right, leftSurround, rightSurround, LFE, centreSurround } }, + List { kAudioChannelLayoutTag_EAC3_6_1_C, { left, centre, right, leftSurround, rightSurround, LFE, topFrontCentre } }, + List { kAudioChannelLayoutTag_EAC3_7_1_A, { left, centre, right, leftSurround, rightSurround, LFE, leftSurroundRear, rightSurroundRear } }, + List { kAudioChannelLayoutTag_EAC3_7_1_B, { left, centre, right, leftSurround, rightSurround, LFE, leftCentre, rightCentre } }, + List { kAudioChannelLayoutTag_EAC3_7_1_C, { left, centre, right, leftSurround, rightSurround, LFE, leftSurroundSide, rightSurroundSide } }, + List { kAudioChannelLayoutTag_EAC3_7_1_D, { left, centre, right, leftSurround, rightSurround, LFE, wideLeft, wideRight } }, + List { kAudioChannelLayoutTag_EAC3_7_1_E, { left, centre, right, leftSurround, rightSurround, LFE, topFrontLeft, topFrontRight } }, + List { kAudioChannelLayoutTag_EAC3_7_1_F, { left, centre, right, leftSurround, rightSurround, LFE, centreSurround, topMiddle } }, + List { kAudioChannelLayoutTag_EAC3_7_1_G, { left, centre, right, leftSurround, rightSurround, LFE, centreSurround, topFrontCentre } }, + List { kAudioChannelLayoutTag_EAC3_7_1_H, { left, centre, right, leftSurround, rightSurround, LFE, centreSurround, topFrontCentre } }, + List { kAudioChannelLayoutTag_DTS_3_1, { centre, left, right, LFE } }, + List { kAudioChannelLayoutTag_DTS_4_1, { centre, left, right, centreSurround, LFE } }, + List { kAudioChannelLayoutTag_DTS_6_0_B, { centre, left, right, leftSurroundRear, rightSurroundRear, centreSurround } }, + List { kAudioChannelLayoutTag_DTS_6_0_C, { centre, centreSurround, left, right, leftSurroundRear, rightSurroundRear } }, + List { kAudioChannelLayoutTag_DTS_6_1_B, { centre, left, right, leftSurroundRear, rightSurroundRear, centreSurround, LFE } }, + List { kAudioChannelLayoutTag_DTS_6_1_C, { centre, centreSurround, left, right, leftSurroundRear, rightSurroundRear, LFE } }, + List { kAudioChannelLayoutTag_DTS_6_1_D, { centre, left, right, leftSurround, rightSurround, LFE, centreSurround } }, + List { kAudioChannelLayoutTag_DTS_7_0, { leftCentre, centre, rightCentre, left, right, leftSurround, rightSurround } }, + List { kAudioChannelLayoutTag_DTS_7_1, { leftCentre, centre, rightCentre, left, right, leftSurround, rightSurround, LFE } }, + List { kAudioChannelLayoutTag_DTS_8_0_A, { leftCentre, rightCentre, left, right, leftSurround, rightSurround, leftSurroundRear, rightSurroundRear } }, + List { kAudioChannelLayoutTag_DTS_8_0_B, { leftCentre, centre, rightCentre, left, right, leftSurround, centreSurround, rightSurround } }, + List { kAudioChannelLayoutTag_DTS_8_1_A, { leftCentre, rightCentre, left, right, leftSurround, rightSurround, leftSurroundRear, rightSurroundRear, LFE } }, + List { kAudioChannelLayoutTag_DTS_8_1_B, { leftCentre, centre, rightCentre, left, right, leftSurround, centreSurround, rightSurround, LFE } }); + } + }; + +public: //============================================================================== enum { @@ -61,16 +191,16 @@ struct CoreAudioLayouts if (set.getAmbisonicOrder() >= 0) return coreAudioHOASN3DLayoutTag | static_cast (set.size()); - for (auto* tbl = SpeakerLayoutTable::get(); tbl->tag != 0; ++tbl) + for (const auto& item : SpeakerLayoutTable::get()) { AudioChannelSet caSet; - for (int i = 0; i < numElementsInArray (tbl->channelTypes) - && tbl->channelTypes[i] != AudioChannelSet::unknown; ++i) - caSet.addChannel (tbl->channelTypes[i]); + for (int i = 0; i < numElementsInArray (item.channelTypes) + && item.channelTypes[i] != AudioChannelSet::unknown; ++i) + caSet.addChannel (item.channelTypes[i]); if (caSet == set) - return tbl->tag; + return item.tag; } return kAudioChannelLayoutTag_DiscreteInOrder | static_cast (set.size()); @@ -121,13 +251,13 @@ struct CoreAudioLayouts Array speakers; - for (auto* tbl = SpeakerLayoutTable::get(); tbl->tag != 0; ++tbl) + for (const auto& item : SpeakerLayoutTable::get()) { - if (tag == tbl->tag) + if (tag == item.tag) { - for (int i = 0; i < numElementsInArray (tbl->channelTypes) - && tbl->channelTypes[i] != AudioChannelSet::unknown; ++i) - speakers.add (tbl->channelTypes[i]); + for (int i = 0; i < numElementsInArray (item.channelTypes) + && item.channelTypes[i] != AudioChannelSet::unknown; ++i) + speakers.add (item.channelTypes[i]); return speakers; } @@ -150,19 +280,12 @@ struct CoreAudioLayouts } private: - //============================================================================== - struct LayoutTagSpeakerList - { - AudioChannelLayoutTag tag; - AudioChannelSet::ChannelType channelTypes[16]; - }; - static Array createKnownCoreAudioTags() { Array tags; - for (auto* tbl = SpeakerLayoutTable::get(); tbl->tag != 0; ++tbl) - tags.addIfNotAlreadyThere (tbl->tag); + for (const auto& item : SpeakerLayoutTable::get()) + tags.addIfNotAlreadyThere (item.tag); for (unsigned order = 0; order <= 5; ++order) tags.addIfNotAlreadyThere (coreAudioHOASN3DLayoutTag | ((order + 1) * (order + 1))); @@ -170,115 +293,6 @@ struct CoreAudioLayouts return tags; } - //============================================================================== - // This list has been derived from https://pastebin.com/24dQ4BPJ - // Apple channel labels have been replaced by JUCE channel names - // This means that some layouts will be identical in JUCE but not in CoreAudio - - // In Apple's official definition the following tags exist with the same speaker layout and order - // even when *not* represented in JUCE channels - // kAudioChannelLayoutTag_Binaural = kAudioChannelLayoutTag_Stereo - // kAudioChannelLayoutTag_MPEG_5_0_B = kAudioChannelLayoutTag_Pentagonal - // kAudioChannelLayoutTag_ITU_2_2 = kAudioChannelLayoutTag_Quadraphonic - // kAudioChannelLayoutTag_AudioUnit_6_0 = kAudioChannelLayoutTag_Hexagonal - struct SpeakerLayoutTable : AudioChannelSet // save us some typing - { - static LayoutTagSpeakerList* get() noexcept - { - static LayoutTagSpeakerList tbl[] = { - // list layouts for which there is a corresponding named AudioChannelSet first - { kAudioChannelLayoutTag_Mono, { centre } }, - { kAudioChannelLayoutTag_Stereo, { left, right } }, - { kAudioChannelLayoutTag_MPEG_3_0_A, { left, right, centre } }, - { kAudioChannelLayoutTag_ITU_2_1, { left, right, centreSurround } }, - { kAudioChannelLayoutTag_MPEG_4_0_A, { left, right, centre, centreSurround } }, - { kAudioChannelLayoutTag_MPEG_5_0_A, { left, right, centre, leftSurround, rightSurround } }, - { kAudioChannelLayoutTag_MPEG_5_1_A, { left, right, centre, LFE, leftSurround, rightSurround } }, - { kAudioChannelLayoutTag_AudioUnit_6_0, { left, right, leftSurround, rightSurround, centre, centreSurround } }, - { kAudioChannelLayoutTag_MPEG_6_1_A, { left, right, centre, LFE, leftSurround, rightSurround, centreSurround } }, - { kAudioChannelLayoutTag_DTS_6_0_A, { leftSurroundSide, rightSurroundSide, left, right, leftSurround, rightSurround } }, - { kAudioChannelLayoutTag_DTS_6_1_A, { leftSurroundSide, rightSurroundSide, left, right, leftSurround, rightSurround, LFE } }, - { kAudioChannelLayoutTag_AudioUnit_7_0, { left, right, leftSurroundSide, rightSurroundSide, centre, leftSurroundRear, rightSurroundRear } }, - { kAudioChannelLayoutTag_AudioUnit_7_0_Front, { left, right, leftSurround, rightSurround, centre, leftCentre, rightCentre } }, - { kAudioChannelLayoutTag_MPEG_7_1_C, { left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear } }, - { kAudioChannelLayoutTag_MPEG_7_1_A, { left, right, centre, LFE, leftSurround, rightSurround, leftCentre, rightCentre } }, - { kAudioChannelLayoutTag_Ambisonic_B_Format, { ambisonicW, ambisonicX, ambisonicY, ambisonicZ } }, - { kAudioChannelLayoutTag_Quadraphonic, { left, right, leftSurround, rightSurround } }, - { kAudioChannelLayoutTag_Pentagonal, { left, right, leftSurroundRear, rightSurroundRear, centre } }, - { kAudioChannelLayoutTag_Hexagonal, { left, right, leftSurroundRear, rightSurroundRear, centre, centreSurround } }, - { kAudioChannelLayoutTag_Octagonal, { left, right, leftSurround, rightSurround, centre, centreSurround, wideLeft, wideRight } }, - - // more uncommon layouts - { kAudioChannelLayoutTag_StereoHeadphones, { left, right } }, - { kAudioChannelLayoutTag_MatrixStereo, { left, right } }, - { kAudioChannelLayoutTag_MidSide, { centre, discreteChannel0 } }, - { kAudioChannelLayoutTag_XY, { ambisonicX, ambisonicY } }, - { kAudioChannelLayoutTag_Binaural, { left, right } }, - { kAudioChannelLayoutTag_Cube, { left, right, leftSurround, rightSurround, topFrontLeft, topFrontRight, topRearLeft, topRearRight } }, - { kAudioChannelLayoutTag_MPEG_3_0_B, { centre, left, right } }, - { kAudioChannelLayoutTag_MPEG_4_0_B, { centre, left, right, centreSurround } }, - { kAudioChannelLayoutTag_MPEG_5_0_B, { left, right, leftSurround, rightSurround, centre } }, - { kAudioChannelLayoutTag_MPEG_5_0_C, { left, centre, right, leftSurround, rightSurround } }, - { kAudioChannelLayoutTag_MPEG_5_0_D, { centre, left, right, leftSurround, rightSurround } }, - { kAudioChannelLayoutTag_MPEG_5_1_B, { left, right, leftSurround, rightSurround, centre, LFE } }, - { kAudioChannelLayoutTag_MPEG_5_1_C, { left, centre, right, leftSurround, rightSurround, LFE } }, - { kAudioChannelLayoutTag_MPEG_5_1_D, { centre, left, right, leftSurround, rightSurround, LFE } }, - { kAudioChannelLayoutTag_MPEG_7_1_B, { centre, leftCentre, rightCentre, left, right, leftSurround, rightSurround, LFE } }, - { kAudioChannelLayoutTag_Emagic_Default_7_1, { left, right, leftSurround, rightSurround, centre, LFE, leftCentre, rightCentre } }, - { kAudioChannelLayoutTag_SMPTE_DTV, { left, right, centre, LFE, leftSurround, rightSurround, discreteChannel0 /* leftMatrixTotal */, (ChannelType) (discreteChannel0 + 1) /* rightMatrixTotal */} }, - { kAudioChannelLayoutTag_ITU_2_2, { left, right, leftSurround, rightSurround } }, - { kAudioChannelLayoutTag_DVD_4, { left, right, LFE } }, - { kAudioChannelLayoutTag_DVD_5, { left, right, LFE, centreSurround } }, - { kAudioChannelLayoutTag_DVD_6, { left, right, LFE, leftSurround, rightSurround } }, - { kAudioChannelLayoutTag_DVD_10, { left, right, centre, LFE } }, - { kAudioChannelLayoutTag_DVD_11, { left, right, centre, LFE, centreSurround } }, - { kAudioChannelLayoutTag_DVD_18, { left, right, leftSurround, rightSurround, LFE } }, - { kAudioChannelLayoutTag_AAC_6_0, { centre, left, right, leftSurround, rightSurround, centreSurround } }, - { kAudioChannelLayoutTag_AAC_6_1, { centre, left, right, leftSurround, rightSurround, centreSurround, LFE } }, - { kAudioChannelLayoutTag_AAC_7_0, { centre, left, right, leftSurround, rightSurround, leftSurroundRear, rightSurroundRear } }, - { kAudioChannelLayoutTag_AAC_7_1_B, { centre, left, right, leftSurround, rightSurround, leftSurroundRear, rightSurroundRear, LFE } }, - { kAudioChannelLayoutTag_AAC_7_1_C, { centre, left, right, leftSurround, rightSurround, LFE, topFrontLeft, topFrontRight } }, - { kAudioChannelLayoutTag_AAC_Octagonal, { centre, left, right, leftSurround, rightSurround, leftSurroundRear, rightSurroundRear, centreSurround } }, - { kAudioChannelLayoutTag_TMH_10_2_std, { left, right, centre, topFrontCentre, leftSurroundSide, rightSurroundSide, leftSurround, rightSurround, topFrontLeft, topFrontRight, wideLeft, wideRight, topRearCentre, centreSurround, LFE, LFE2 } }, - { kAudioChannelLayoutTag_AC3_1_0_1, { centre, LFE } }, - { kAudioChannelLayoutTag_AC3_3_0, { left, centre, right } }, - { kAudioChannelLayoutTag_AC3_3_1, { left, centre, right, centreSurround } }, - { kAudioChannelLayoutTag_AC3_3_0_1, { left, centre, right, LFE } }, - { kAudioChannelLayoutTag_AC3_2_1_1, { left, right, centreSurround, LFE } }, - { kAudioChannelLayoutTag_AC3_3_1_1, { left, centre, right, centreSurround, LFE } }, - { kAudioChannelLayoutTag_EAC_6_0_A, { left, centre, right, leftSurround, rightSurround, centreSurround } }, - { kAudioChannelLayoutTag_EAC_7_0_A, { left, centre, right, leftSurround, rightSurround, leftSurroundRear, rightSurroundRear } }, - { kAudioChannelLayoutTag_EAC3_6_1_A, { left, centre, right, leftSurround, rightSurround, LFE, centreSurround } }, - { kAudioChannelLayoutTag_EAC3_6_1_B, { left, centre, right, leftSurround, rightSurround, LFE, centreSurround } }, - { kAudioChannelLayoutTag_EAC3_6_1_C, { left, centre, right, leftSurround, rightSurround, LFE, topFrontCentre } }, - { kAudioChannelLayoutTag_EAC3_7_1_A, { left, centre, right, leftSurround, rightSurround, LFE, leftSurroundRear, rightSurroundRear } }, - { kAudioChannelLayoutTag_EAC3_7_1_B, { left, centre, right, leftSurround, rightSurround, LFE, leftCentre, rightCentre } }, - { kAudioChannelLayoutTag_EAC3_7_1_C, { left, centre, right, leftSurround, rightSurround, LFE, leftSurroundSide, rightSurroundSide } }, - { kAudioChannelLayoutTag_EAC3_7_1_D, { left, centre, right, leftSurround, rightSurround, LFE, wideLeft, wideRight } }, - { kAudioChannelLayoutTag_EAC3_7_1_E, { left, centre, right, leftSurround, rightSurround, LFE, topFrontLeft, topFrontRight } }, - { kAudioChannelLayoutTag_EAC3_7_1_F, { left, centre, right, leftSurround, rightSurround, LFE, centreSurround, topMiddle } }, - { kAudioChannelLayoutTag_EAC3_7_1_G, { left, centre, right, leftSurround, rightSurround, LFE, centreSurround, topFrontCentre } }, - { kAudioChannelLayoutTag_EAC3_7_1_H, { left, centre, right, leftSurround, rightSurround, LFE, centreSurround, topFrontCentre } }, - { kAudioChannelLayoutTag_DTS_3_1, { centre, left, right, LFE } }, - { kAudioChannelLayoutTag_DTS_4_1, { centre, left, right, centreSurround, LFE } }, - { kAudioChannelLayoutTag_DTS_6_0_B, { centre, left, right, leftSurroundRear, rightSurroundRear, centreSurround } }, - { kAudioChannelLayoutTag_DTS_6_0_C, { centre, centreSurround, left, right, leftSurroundRear, rightSurroundRear } }, - { kAudioChannelLayoutTag_DTS_6_1_B, { centre, left, right, leftSurroundRear, rightSurroundRear, centreSurround, LFE } }, - { kAudioChannelLayoutTag_DTS_6_1_C, { centre, centreSurround, left, right, leftSurroundRear, rightSurroundRear, LFE } }, - { kAudioChannelLayoutTag_DTS_6_1_D, { centre, left, right, leftSurround, rightSurround, LFE, centreSurround } }, - { kAudioChannelLayoutTag_DTS_7_0, { leftCentre, centre, rightCentre, left, right, leftSurround, rightSurround } }, - { kAudioChannelLayoutTag_DTS_7_1, { leftCentre, centre, rightCentre, left, right, leftSurround, rightSurround, LFE } }, - { kAudioChannelLayoutTag_DTS_8_0_A, { leftCentre, rightCentre, left, right, leftSurround, rightSurround, leftSurroundRear, rightSurroundRear } }, - { kAudioChannelLayoutTag_DTS_8_0_B, { leftCentre, centre, rightCentre, left, right, leftSurround, centreSurround, rightSurround } }, - { kAudioChannelLayoutTag_DTS_8_1_A, { leftCentre, rightCentre, left, right, leftSurround, rightSurround, leftSurroundRear, rightSurroundRear, LFE } }, - { kAudioChannelLayoutTag_DTS_8_1_B, { leftCentre, centre, rightCentre, left, right, leftSurround, centreSurround, rightSurround, LFE } }, - { 0, {} } - }; - - return tbl; - } - }; - //============================================================================== static AudioChannelSet::ChannelType getChannelTypeFromAudioChannelLabel (AudioChannelLabel label) noexcept { diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_AudioSource.h b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_AudioSource.h index 9633f67b..0122623b 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_AudioSource.h +++ b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_AudioSource.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -32,9 +32,7 @@ namespace juce struct JUCE_API AudioSourceChannelInfo { /** Creates an uninitialised AudioSourceChannelInfo. */ - AudioSourceChannelInfo() noexcept - { - } + AudioSourceChannelInfo() = default; /** Creates an AudioSourceChannelInfo. */ AudioSourceChannelInfo (AudioBuffer* bufferToUse, @@ -113,18 +111,18 @@ class JUCE_API AudioSource protected: //============================================================================== /** Creates an AudioSource. */ - AudioSource() noexcept {} + AudioSource() = default; public: /** Destructor. */ - virtual ~AudioSource() {} + virtual ~AudioSource() = default; //============================================================================== /** Tells the source to prepare for playing. An AudioSource has two states: prepared and unprepared. - The prepareToPlay() method is guaranteed to be called at least once on an 'unpreprared' + The prepareToPlay() method is guaranteed to be called at least once on an 'unprepared' source to put it into a 'prepared' state before any calls will be made to getNextAudioBlock(). This callback allows the source to initialise any resources it might need when playing. diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_BufferingAudioSource.cpp b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_BufferingAudioSource.cpp index ae33bea0..6b2a198e 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_BufferingAudioSource.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_BufferingAudioSource.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -25,20 +25,14 @@ namespace juce BufferingAudioSource::BufferingAudioSource (PositionableAudioSource* s, TimeSliceThread& thread, - const bool deleteSourceWhenDeleted, - const int bufferSizeSamples, - const int numChannels, + bool deleteSourceWhenDeleted, + int bufferSizeSamples, + int numChannels, bool prefillBufferOnPrepareToPlay) : source (s, deleteSourceWhenDeleted), backgroundThread (thread), numberOfSamplesToBuffer (jmax (1024, bufferSizeSamples)), numberOfChannels (numChannels), - bufferValidStart (0), - bufferValidEnd (0), - nextPlayPos (0), - sampleRate (0), - wasSourceLooping (false), - isPrepared (false), prefillBuffer (prefillBufferOnPrepareToPlay) { jassert (source != nullptr); @@ -55,7 +49,7 @@ BufferingAudioSource::~BufferingAudioSource() //============================================================================== void BufferingAudioSource::prepareToPlay (int samplesPerBlockExpected, double newSampleRate) { - const int bufferSizeNeeded = jmax (samplesPerBlockExpected * 2, numberOfSamplesToBuffer); + auto bufferSizeNeeded = jmax (samplesPerBlockExpected * 2, numberOfSamplesToBuffer); if (newSampleRate != sampleRate || bufferSizeNeeded != buffer.getNumSamples() @@ -71,6 +65,8 @@ void BufferingAudioSource::prepareToPlay (int samplesPerBlockExpected, double ne buffer.setSize (numberOfChannels, bufferSizeNeeded); buffer.clear(); + const ScopedLock sl (bufferRangeLock); + bufferValidStart = 0; bufferValidEnd = 0; @@ -78,6 +74,8 @@ void BufferingAudioSource::prepareToPlay (int samplesPerBlockExpected, double ne do { + const ScopedUnlock ul (bufferRangeLock); + backgroundThread.moveToFrontOfQueue (this); Thread::sleep (5); } @@ -102,94 +100,97 @@ void BufferingAudioSource::releaseResources() void BufferingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info) { - const ScopedLock sl (bufferStartPosLock); - - const int validStart = (int) (jlimit (bufferValidStart, bufferValidEnd, nextPlayPos) - nextPlayPos); - const int validEnd = (int) (jlimit (bufferValidStart, bufferValidEnd, nextPlayPos + info.numSamples) - nextPlayPos); + const auto bufferRange = getValidBufferRange (info.numSamples); - if (validStart == validEnd) + if (bufferRange.isEmpty()) { // total cache miss info.clearActiveBufferRegion(); + return; } - else - { - if (validStart > 0) - info.buffer->clear (info.startSample, validStart); // partial cache miss at start - if (validEnd < info.numSamples) - info.buffer->clear (info.startSample + validEnd, - info.numSamples - validEnd); // partial cache miss at end + const auto validStart = bufferRange.getStart(); + const auto validEnd = bufferRange.getEnd(); - if (validStart < validEnd) + const ScopedLock sl (callbackLock); + + if (validStart > 0) + info.buffer->clear (info.startSample, validStart); // partial cache miss at start + + if (validEnd < info.numSamples) + info.buffer->clear (info.startSample + validEnd, + info.numSamples - validEnd); // partial cache miss at end + + if (validStart < validEnd) + { + for (int chan = jmin (numberOfChannels, info.buffer->getNumChannels()); --chan >= 0;) { - for (int chan = jmin (numberOfChannels, info.buffer->getNumChannels()); --chan >= 0;) + jassert (buffer.getNumSamples() > 0); + + const auto startBufferIndex = (int) ((validStart + nextPlayPos) % buffer.getNumSamples()); + const auto endBufferIndex = (int) ((validEnd + nextPlayPos) % buffer.getNumSamples()); + + if (startBufferIndex < endBufferIndex) { - jassert (buffer.getNumSamples() > 0); - const int startBufferIndex = (int) ((validStart + nextPlayPos) % buffer.getNumSamples()); - const int endBufferIndex = (int) ((validEnd + nextPlayPos) % buffer.getNumSamples()); - - if (startBufferIndex < endBufferIndex) - { - info.buffer->copyFrom (chan, info.startSample + validStart, - buffer, - chan, startBufferIndex, - validEnd - validStart); - } - else - { - const int initialSize = buffer.getNumSamples() - startBufferIndex; - - info.buffer->copyFrom (chan, info.startSample + validStart, - buffer, - chan, startBufferIndex, - initialSize); - - info.buffer->copyFrom (chan, info.startSample + validStart + initialSize, - buffer, - chan, 0, - (validEnd - validStart) - initialSize); - } + info.buffer->copyFrom (chan, info.startSample + validStart, + buffer, + chan, startBufferIndex, + validEnd - validStart); } - } + else + { + const auto initialSize = buffer.getNumSamples() - startBufferIndex; - nextPlayPos += info.numSamples; + info.buffer->copyFrom (chan, info.startSample + validStart, + buffer, + chan, startBufferIndex, + initialSize); + + info.buffer->copyFrom (chan, info.startSample + validStart + initialSize, + buffer, + chan, 0, + (validEnd - validStart) - initialSize); + } + } } + + nextPlayPos += info.numSamples; } -bool BufferingAudioSource::waitForNextAudioBlockReady (const AudioSourceChannelInfo& info, const uint32 timeout) +bool BufferingAudioSource::waitForNextAudioBlockReady (const AudioSourceChannelInfo& info, uint32 timeout) { - if (!source || source->getTotalLength() <= 0) + if (source == nullptr || source->getTotalLength() <= 0) return false; - if (nextPlayPos + info.numSamples < 0) + if ((nextPlayPos + info.numSamples < 0) + || (! isLooping() && nextPlayPos > getTotalLength())) return true; - if (! isLooping() && nextPlayPos > getTotalLength()) - return true; - - uint32 now = Time::getMillisecondCounter(); - const uint32 startTime = now; + const auto startTime = Time::getMillisecondCounter(); + auto now = startTime; - uint32 elapsed = (now >= startTime ? now - startTime - : (std::numeric_limits::max() - startTime) + now); + auto elapsed = (now >= startTime ? now - startTime + : (std::numeric_limits::max() - startTime) + now); while (elapsed <= timeout) { - { - const ScopedLock sl (bufferStartPosLock); + const auto bufferRange = getValidBufferRange (info.numSamples); - const int validStart = static_cast (jlimit (bufferValidStart, bufferValidEnd, nextPlayPos) - nextPlayPos); - const int validEnd = static_cast (jlimit (bufferValidStart, bufferValidEnd, nextPlayPos + info.numSamples) - nextPlayPos); + const auto validStart = bufferRange.getStart(); + const auto validEnd = bufferRange.getEnd(); - if (validStart <= 0 && validStart < validEnd && validEnd >= info.numSamples) - return true; + if (validStart <= 0 + && validStart < validEnd + && validEnd >= info.numSamples) + { + return true; } - - - if (elapsed < timeout && (! bufferReadyEvent.wait (static_cast (timeout - elapsed)))) + if (elapsed < timeout + && ! bufferReadyEvent.wait (static_cast (timeout - elapsed))) + { return false; + } now = Time::getMillisecondCounter(); elapsed = (now >= startTime ? now - startTime @@ -202,25 +203,37 @@ bool BufferingAudioSource::waitForNextAudioBlockReady (const AudioSourceChannelI int64 BufferingAudioSource::getNextReadPosition() const { jassert (source->getTotalLength() > 0); + const auto pos = nextPlayPos.load(); + return (source->isLooping() && nextPlayPos > 0) - ? nextPlayPos % source->getTotalLength() - : nextPlayPos; + ? pos % source->getTotalLength() + : pos; } void BufferingAudioSource::setNextReadPosition (int64 newPosition) { - const ScopedLock sl (bufferStartPosLock); + const ScopedLock sl (bufferRangeLock); nextPlayPos = newPosition; backgroundThread.moveToFrontOfQueue (this); } +Range BufferingAudioSource::getValidBufferRange (int numSamples) const +{ + const ScopedLock sl (bufferRangeLock); + + const auto pos = nextPlayPos.load(); + + return { (int) (jlimit (bufferValidStart, bufferValidEnd, pos) - pos), + (int) (jlimit (bufferValidStart, bufferValidEnd, pos + numSamples) - pos) }; +} + bool BufferingAudioSource::readNextBufferChunk() { int64 newBVS, newBVE, sectionToReadStart, sectionToReadEnd; { - const ScopedLock sl (bufferStartPosLock); + const ScopedLock sl (bufferRangeLock); if (wasSourceLooping != isLooping()) { @@ -229,12 +242,12 @@ bool BufferingAudioSource::readNextBufferChunk() bufferValidEnd = 0; } - newBVS = jmax ((int64) 0, nextPlayPos); + newBVS = jmax ((int64) 0, nextPlayPos.load()); newBVE = newBVS + buffer.getNumSamples() - 4; sectionToReadStart = 0; sectionToReadEnd = 0; - const int maxChunkSize = 2048; + constexpr int maxChunkSize = 2048; if (newBVS < bufferValidStart || newBVS >= bufferValidEnd) { @@ -263,8 +276,9 @@ bool BufferingAudioSource::readNextBufferChunk() return false; jassert (buffer.getNumSamples() > 0); - const int bufferIndexStart = (int) (sectionToReadStart % buffer.getNumSamples()); - const int bufferIndexEnd = (int) (sectionToReadEnd % buffer.getNumSamples()); + + const auto bufferIndexStart = (int) (sectionToReadStart % buffer.getNumSamples()); + const auto bufferIndexEnd = (int) (sectionToReadEnd % buffer.getNumSamples()); if (bufferIndexStart < bufferIndexEnd) { @@ -274,7 +288,7 @@ bool BufferingAudioSource::readNextBufferChunk() } else { - const int initialSize = buffer.getNumSamples() - bufferIndexStart; + const auto initialSize = buffer.getNumSamples() - bufferIndexStart; readBufferSection (sectionToReadStart, initialSize, @@ -286,23 +300,24 @@ bool BufferingAudioSource::readNextBufferChunk() } { - const ScopedLock sl2 (bufferStartPosLock); + const ScopedLock sl2 (bufferRangeLock); bufferValidStart = newBVS; bufferValidEnd = newBVE; } bufferReadyEvent.signal(); - return true; } -void BufferingAudioSource::readBufferSection (const int64 start, const int length, const int bufferOffset) +void BufferingAudioSource::readBufferSection (int64 start, int length, int bufferOffset) { if (source->getNextReadPosition() != start) source->setNextReadPosition (start); AudioSourceChannelInfo info (&buffer, bufferOffset, length); + + const ScopedLock sl (callbackLock); source->getNextAudioBlock (info); } diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_BufferingAudioSource.h b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_BufferingAudioSource.h index bf272969..7bfa24b1 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_BufferingAudioSource.h +++ b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_BufferingAudioSource.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -66,7 +66,7 @@ class JUCE_API BufferingAudioSource : public PositionableAudioSource, The input source may be deleted depending on whether the deleteSourceWhenDeleted flag was set in the constructor. */ - ~BufferingAudioSource(); + ~BufferingAudioSource() override; //============================================================================== /** Implementation of the AudioSource method. */ @@ -98,21 +98,26 @@ class JUCE_API BufferingAudioSource : public PositionableAudioSource, bool waitForNextAudioBlockReady (const AudioSourceChannelInfo& info, const uint32 timeout); private: + //============================================================================== + Range getValidBufferRange (int numSamples) const; + bool readNextBufferChunk(); + void readBufferSection (int64 start, int length, int bufferOffset); + int useTimeSlice() override; + //============================================================================== OptionalScopedPointer source; TimeSliceThread& backgroundThread; int numberOfSamplesToBuffer, numberOfChannels; AudioBuffer buffer; - CriticalSection bufferStartPosLock; + CriticalSection callbackLock, bufferRangeLock; WaitableEvent bufferReadyEvent; - int64 volatile bufferValidStart, bufferValidEnd, nextPlayPos; - double volatile sampleRate; - bool wasSourceLooping, isPrepared, prefillBuffer; - - bool readNextBufferChunk(); - void readBufferSection (int64 start, int length, int bufferOffset); - int useTimeSlice() override; + int64 bufferValidStart = 0, bufferValidEnd = 0; + std::atomic nextPlayPos { 0 }; + double sampleRate = 0; + bool wasSourceLooping = false, isPrepared = false; + const bool prefillBuffer; + //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BufferingAudioSource) }; diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ChannelRemappingAudioSource.cpp b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ChannelRemappingAudioSource.cpp index 3cec2213..85a4bed0 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ChannelRemappingAudioSource.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ChannelRemappingAudioSource.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -145,9 +145,9 @@ void ChannelRemappingAudioSource::getNextAudioBlock (const AudioSourceChannelInf } //============================================================================== -XmlElement* ChannelRemappingAudioSource::createXml() const +std::unique_ptr ChannelRemappingAudioSource::createXml() const { - XmlElement* e = new XmlElement ("MAPPINGS"); + auto e = std::make_unique ("MAPPINGS"); String ins, outs; const ScopedLock sl (lock); diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ChannelRemappingAudioSource.h b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ChannelRemappingAudioSource.h index f46093b2..b226e390 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ChannelRemappingAudioSource.h +++ b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ChannelRemappingAudioSource.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -56,7 +56,7 @@ class ChannelRemappingAudioSource : public AudioSource bool deleteSourceWhenDeleted); /** Destructor. */ - ~ChannelRemappingAudioSource(); + ~ChannelRemappingAudioSource() override; //============================================================================== /** Specifies a number of channels that this audio source must produce from its @@ -112,7 +112,7 @@ class ChannelRemappingAudioSource : public AudioSource /** Returns an XML object to encapsulate the state of the mappings. @see restoreFromXml */ - XmlElement* createXml() const; + std::unique_ptr createXml() const; /** Restores the mappings from an XML object created by createXML(). @see createXml diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_IIRFilterAudioSource.cpp b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_IIRFilterAudioSource.cpp index cbea3b8c..fdc99f1b 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_IIRFilterAudioSource.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_IIRFilterAudioSource.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_IIRFilterAudioSource.h b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_IIRFilterAudioSource.h index 35030c06..5ff22870 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_IIRFilterAudioSource.h +++ b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_IIRFilterAudioSource.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -43,7 +43,7 @@ class JUCE_API IIRFilterAudioSource : public AudioSource bool deleteInputWhenDeleted); /** Destructor. */ - ~IIRFilterAudioSource(); + ~IIRFilterAudioSource() override; //============================================================================== /** Changes the filter to use the same parameters as the one being passed in. */ diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_MemoryAudioSource.cpp b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_MemoryAudioSource.cpp index 6adec044..eb72cc6d 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_MemoryAudioSource.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_MemoryAudioSource.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -24,7 +24,7 @@ namespace juce { MemoryAudioSource::MemoryAudioSource (AudioBuffer& bufferToUse, bool copyMemory, bool shouldLoop) - : isLooping (shouldLoop) + : isCurrentlyLooping (shouldLoop) { if (copyMemory) buffer.makeCopyOf (bufferToUse); @@ -44,12 +44,20 @@ void MemoryAudioSource::releaseResources() {} void MemoryAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) { + if (buffer.getNumSamples() == 0) + { + bufferToFill.clearActiveBufferRegion(); + return; + } + auto& dst = *bufferToFill.buffer; auto channels = jmin (dst.getNumChannels(), buffer.getNumChannels()); - auto max = 0, pos = 0; - auto n = buffer.getNumSamples(), m = bufferToFill.numSamples; + int max = 0, pos = 0; + auto n = buffer.getNumSamples(); + auto m = bufferToFill.numSamples; - for (auto i = position; (i < n || isLooping) && (pos < m); i += max) + int i = position; + for (; (i < n || isCurrentlyLooping) && (pos < m); i += max) { max = jmin (m - pos, n - (i % n)); @@ -65,6 +73,189 @@ void MemoryAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& bufferT if (pos < m) dst.clear (bufferToFill.startSample + pos, m - pos); + + position = i; +} + +//============================================================================== +void MemoryAudioSource::setNextReadPosition (int64 newPosition) +{ + position = (int) newPosition; +} + +int64 MemoryAudioSource::getNextReadPosition() const +{ + return position; +} + +int64 MemoryAudioSource::getTotalLength() const +{ + return buffer.getNumSamples(); +} + +//============================================================================== +bool MemoryAudioSource::isLooping() const +{ + return isCurrentlyLooping; } +void MemoryAudioSource::setLooping (bool shouldLoop) +{ + isCurrentlyLooping = shouldLoop; +} + +//============================================================================== +//============================================================================== +#if JUCE_UNIT_TESTS + +static bool operator== (const AudioBuffer& a, const AudioBuffer& b) +{ + if (a.getNumChannels() != b.getNumChannels()) + return false; + + for (int channel = 0; channel < a.getNumChannels(); ++channel) + { + auto* aPtr = a.getReadPointer (channel); + auto* bPtr = b.getReadPointer (channel); + + if (std::vector (aPtr, aPtr + a.getNumSamples()) + != std::vector (bPtr, bPtr + b.getNumSamples())) + { + return false; + } + } + + return true; +} + +struct MemoryAudioSourceTests : public UnitTest +{ + MemoryAudioSourceTests() : UnitTest ("MemoryAudioSource", UnitTestCategories::audio) {} + + void runTest() override + { + constexpr int blockSize = 512; + AudioBuffer bufferToFill { 2, blockSize }; + AudioSourceChannelInfo channelInfo { bufferToFill }; + + beginTest ("A zero-length buffer produces silence, whether or not looping is enabled"); + { + for (const bool enableLooping : { false, true }) + { + AudioBuffer buffer; + MemoryAudioSource source { buffer, true, false }; + source.setLooping (enableLooping); + source.prepareToPlay (blockSize, 44100.0); + + for (int i = 0; i < 2; ++i) + { + play (source, channelInfo); + expect (isSilent (bufferToFill)); + } + } + } + + beginTest ("A short buffer without looping is played once and followed by silence"); + { + auto buffer = getShortBuffer(); + MemoryAudioSource source { buffer, true, false }; + source.setLooping (false); + source.prepareToPlay (blockSize, 44100.0); + + play (source, channelInfo); + + auto copy = buffer; + copy.setSize (buffer.getNumChannels(), blockSize, true, true, false); + + expect (bufferToFill == copy); + + play (source, channelInfo); + + expect (isSilent (bufferToFill)); + } + + beginTest ("A short buffer with looping is played multiple times"); + { + auto buffer = getShortBuffer(); + MemoryAudioSource source { buffer, true, false }; + source.setLooping (true); + source.prepareToPlay (blockSize, 44100.0); + + play (source, channelInfo); + + for (int sample = 0; sample < buffer.getNumSamples(); ++sample) + expect (bufferToFill.getSample (0, sample + buffer.getNumSamples()) == buffer.getSample (0, sample)); + + expect (! isSilent (bufferToFill)); + } + + beginTest ("A long buffer without looping is played once"); + { + auto buffer = getLongBuffer(); + MemoryAudioSource source { buffer, true, false }; + source.setLooping (false); + source.prepareToPlay (blockSize, 44100.0); + + play (source, channelInfo); + + auto copy = buffer; + copy.setSize (buffer.getNumChannels(), blockSize, true, true, false); + + expect (bufferToFill == copy); + + for (int i = 0; i < 10; ++i) + play (source, channelInfo); + + expect (isSilent (bufferToFill)); + } + + beginTest ("A long buffer with looping is played multiple times"); + { + auto buffer = getLongBuffer(); + MemoryAudioSource source { buffer, true, false }; + source.setLooping (true); + source.prepareToPlay (blockSize, 44100.0); + + for (int i = 0; i < 100; ++i) + { + play (source, channelInfo); + expect (bufferToFill.getSample (0, 0) == buffer.getSample (0, (i * blockSize) % buffer.getNumSamples())); + } + } + } + + static AudioBuffer getTestBuffer (int length) + { + AudioBuffer buffer { 2, length }; + + for (int channel = 0; channel < buffer.getNumChannels(); ++channel) + for (int sample = 0; sample < buffer.getNumSamples(); ++sample) + buffer.setSample (channel, sample, jmap ((float) sample, 0.0f, (float) length, -1.0f, 1.0f)); + + return buffer; + } + + static AudioBuffer getShortBuffer() { return getTestBuffer (5); } + static AudioBuffer getLongBuffer() { return getTestBuffer (1000); } + + static void play (MemoryAudioSource& source, AudioSourceChannelInfo& info) + { + info.clearActiveBufferRegion(); + source.getNextAudioBlock (info); + } + + static bool isSilent (const AudioBuffer& b) + { + for (int channel = 0; channel < b.getNumChannels(); ++channel) + if (b.findMinMax (channel, 0, b.getNumSamples()) != Range{}) + return false; + + return true; + } +}; + +static MemoryAudioSourceTests memoryAudioSourceTests; + +#endif + } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_MemoryAudioSource.h b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_MemoryAudioSource.h index d46bd4f4..414cc65c 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_MemoryAudioSource.h +++ b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_MemoryAudioSource.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -29,7 +29,7 @@ namespace juce @tags{Audio} */ -class JUCE_API MemoryAudioSource : public AudioSource +class JUCE_API MemoryAudioSource : public PositionableAudioSource { public: //============================================================================== @@ -52,11 +52,28 @@ class JUCE_API MemoryAudioSource : public AudioSource /** Implementation of the AudioSource method. */ void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) override; + //============================================================================== + /** Implementation of the PositionableAudioSource method. */ + void setNextReadPosition (int64 newPosition) override; + + /** Implementation of the PositionableAudioSource method. */ + int64 getNextReadPosition() const override; + + /** Implementation of the PositionableAudioSource method. */ + int64 getTotalLength() const override; + + //============================================================================== + /** Implementation of the PositionableAudioSource method. */ + bool isLooping() const override; + + /** Implementation of the PositionableAudioSource method. */ + void setLooping (bool shouldLoop) override; + private: //============================================================================== AudioBuffer buffer; int position = 0; - bool isLooping; + bool isCurrentlyLooping; //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryAudioSource) diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_MixerAudioSource.cpp b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_MixerAudioSource.cpp index ed2918e4..0b4eda89 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_MixerAudioSource.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_MixerAudioSource.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -61,7 +61,7 @@ void MixerAudioSource::removeInputSource (AudioSource* const input) { if (input != nullptr) { - ScopedPointer toDelete; + std::unique_ptr toDelete; { const ScopedLock sl (lock); diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_MixerAudioSource.h b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_MixerAudioSource.h index 8b3e9c27..ed217643 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_MixerAudioSource.h +++ b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_MixerAudioSource.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -41,7 +41,7 @@ class JUCE_API MixerAudioSource : public AudioSource MixerAudioSource(); /** Destructor. */ - ~MixerAudioSource(); + ~MixerAudioSource() override; //============================================================================== /** Adds an input source to the mixer. diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_PositionableAudioSource.h b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_PositionableAudioSource.h index 610d2c5a..2ec17d05 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_PositionableAudioSource.h +++ b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_PositionableAudioSource.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -40,11 +40,11 @@ class JUCE_API PositionableAudioSource : public AudioSource protected: //============================================================================== /** Creates the PositionableAudioSource. */ - PositionableAudioSource() noexcept {} + PositionableAudioSource() = default; public: /** Destructor */ - ~PositionableAudioSource() {} + ~PositionableAudioSource() override = default; //============================================================================== /** Tells the stream to move to a new position. diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp index 13770713..90af1de2 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -27,11 +27,6 @@ ResamplingAudioSource::ResamplingAudioSource (AudioSource* const inputSource, const bool deleteInputWhenDeleted, const int channels) : input (inputSource, deleteInputWhenDeleted), - ratio (1.0), - lastRatio (1.0), - bufferPos (0), - sampsInBuffer (0), - subSampleOffset (0), numChannels (channels) { jassert (input != nullptr); @@ -67,6 +62,8 @@ void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected, double s void ResamplingAudioSource::flushBuffers() { + const ScopedLock sl (callbackLock); + buffer.clear(); bufferPos = 0; sampsInBuffer = 0; @@ -82,10 +79,12 @@ void ResamplingAudioSource::releaseResources() void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info) { + const ScopedLock sl (callbackLock); + double localRatio; { - const SpinLock::ScopedLockType sl (ratioLock); + const SpinLock::ScopedLockType ratioSl (ratioLock); localRatio = ratio; } diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.h b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.h index 0ff3fae6..58f9d436 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.h +++ b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -47,7 +47,7 @@ class JUCE_API ResamplingAudioSource : public AudioSource int numChannels = 2); /** Destructor. */ - ~ResamplingAudioSource(); + ~ResamplingAudioSource() override; /** Changes the resampling ratio. @@ -76,12 +76,13 @@ class JUCE_API ResamplingAudioSource : public AudioSource private: //============================================================================== OptionalScopedPointer input; - double ratio, lastRatio; + double ratio = 1.0, lastRatio = 1.0; AudioBuffer buffer; - int bufferPos, sampsInBuffer; - double subSampleOffset; + int bufferPos = 0, sampsInBuffer = 0; + double subSampleOffset = 0.0; double coefficients[6]; SpinLock ratioLock; + CriticalSection callbackLock; const int numChannels; HeapBlock destBuffers; HeapBlock srcBuffers; diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ReverbAudioSource.cpp b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ReverbAudioSource.cpp index dd4e7ab0..2cd1c256 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ReverbAudioSource.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ReverbAudioSource.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ReverbAudioSource.h b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ReverbAudioSource.h index ddddb546..07fc8dc2 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ReverbAudioSource.h +++ b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ReverbAudioSource.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -44,7 +44,7 @@ class JUCE_API ReverbAudioSource : public AudioSource bool deleteInputWhenDeleted); /** Destructor. */ - ~ReverbAudioSource(); + ~ReverbAudioSource() override; //============================================================================== /** Returns the parameters from the reverb. */ @@ -66,7 +66,7 @@ class JUCE_API ReverbAudioSource : public AudioSource CriticalSection lock; OptionalScopedPointer input; Reverb reverb; - volatile bool bypass; + std::atomic bypass; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ReverbAudioSource) }; diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ToneGeneratorAudioSource.cpp b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ToneGeneratorAudioSource.cpp index 1707db7c..f3695cc7 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ToneGeneratorAudioSource.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ToneGeneratorAudioSource.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ToneGeneratorAudioSource.h b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ToneGeneratorAudioSource.h index ea1da6af..92adec66 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ToneGeneratorAudioSource.h +++ b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ToneGeneratorAudioSource.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -38,7 +38,7 @@ class JUCE_API ToneGeneratorAudioSource : public AudioSource ToneGeneratorAudioSource(); /** Destructor. */ - ~ToneGeneratorAudioSource(); + ~ToneGeneratorAudioSource() override; //============================================================================== /** Sets the signal's amplitude. */ diff --git a/JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp b/JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp index fa047d14..388d9d26 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -163,18 +163,15 @@ void Synthesiser::processNextBlock (AudioBuffer& outputAudio, jassert (sampleRate != 0); const int targetChannels = outputAudio.getNumChannels(); - MidiBuffer::Iterator midiIterator (midiData); - midiIterator.setNextSamplePosition (startSample); + auto midiIterator = midiData.findNextSamplePosition (startSample); bool firstEvent = true; - int midiEventPos; - MidiMessage m; const ScopedLock sl (lock); - while (numSamples > 0) + for (; numSamples > 0; ++midiIterator) { - if (! midiIterator.getNextEvent (m, midiEventPos)) + if (midiIterator == midiData.cend()) { if (targetChannels > 0) renderVoices (outputAudio, startSample, numSamples); @@ -182,20 +179,21 @@ void Synthesiser::processNextBlock (AudioBuffer& outputAudio, return; } - const int samplesToNextMidiMessage = midiEventPos - startSample; + const auto metadata = *midiIterator; + const int samplesToNextMidiMessage = metadata.samplePosition - startSample; if (samplesToNextMidiMessage >= numSamples) { if (targetChannels > 0) renderVoices (outputAudio, startSample, numSamples); - handleMidiEvent (m); + handleMidiEvent (metadata.getMessage()); break; } if (samplesToNextMidiMessage < ((firstEvent && ! subBlockSubdivisionIsStrict) ? 1 : minimumSubBlockSize)) { - handleMidiEvent (m); + handleMidiEvent (metadata.getMessage()); continue; } @@ -204,19 +202,32 @@ void Synthesiser::processNextBlock (AudioBuffer& outputAudio, if (targetChannels > 0) renderVoices (outputAudio, startSample, samplesToNextMidiMessage); - handleMidiEvent (m); + handleMidiEvent (metadata.getMessage()); startSample += samplesToNextMidiMessage; numSamples -= samplesToNextMidiMessage; } - while (midiIterator.getNextEvent (m, midiEventPos)) - handleMidiEvent (m); + std::for_each (midiIterator, + midiData.cend(), + [&] (const MidiMessageMetadata& meta) { handleMidiEvent (meta.getMessage()); }); } // explicit template instantiation template void Synthesiser::processNextBlock (AudioBuffer&, const MidiBuffer&, int, int); template void Synthesiser::processNextBlock (AudioBuffer&, const MidiBuffer&, int, int); +void Synthesiser::renderNextBlock (AudioBuffer& outputAudio, const MidiBuffer& inputMidi, + int startSample, int numSamples) +{ + processNextBlock (outputAudio, inputMidi, startSample, numSamples); +} + +void Synthesiser::renderNextBlock (AudioBuffer& outputAudio, const MidiBuffer& inputMidi, + int startSample, int numSamples) +{ + processNextBlock (outputAudio, inputMidi, startSample, numSamples); +} + void Synthesiser::renderVoices (AudioBuffer& buffer, int startSample, int numSamples) { for (auto* voice : voices) @@ -323,7 +334,7 @@ void Synthesiser::stopVoice (SynthesiserVoice* voice, float velocity, const bool 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)); + jassert (allowTailOff || (voice->getCurrentlyPlayingNote() < 0 && voice->getCurrentlyPlayingSound() == nullptr)); } void Synthesiser::noteOff (const int midiChannel, @@ -338,7 +349,7 @@ void Synthesiser::noteOff (const int midiChannel, if (voice->getCurrentlyPlayingNote() == midiNoteNumber && voice->isPlayingChannel (midiChannel)) { - if (SynthesiserSound* const sound = voice->getCurrentlyPlayingSound()) + if (auto sound = voice->getCurrentlyPlayingSound()) { if (sound->appliesToNote (midiNoteNumber) && sound->appliesToChannel (midiChannel)) diff --git a/JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h b/JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h index c056896e..53d69006 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h +++ b/JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -46,7 +46,7 @@ class JUCE_API SynthesiserSound : public ReferenceCountedObject public: /** Destructor. */ - virtual ~SynthesiserSound(); + ~SynthesiserSound() override; //============================================================================== /** Returns true if this sound should be played when a given midi note is pressed. @@ -64,7 +64,7 @@ class JUCE_API SynthesiserSound : public ReferenceCountedObject virtual bool appliesToChannel (int midiChannel) = 0; /** The class is reference-counted, so this is a handy pointer class for it. */ - typedef ReferenceCountedObjectPtr Ptr; + using Ptr = ReferenceCountedObjectPtr; private: @@ -274,11 +274,6 @@ class JUCE_API SynthesiserVoice AudioBuffer tempBuffer; - #if JUCE_CATCH_DEPRECATED_CODE_MISUSE - // Note the new parameters for this method. - virtual int stopNote (bool) { return 0; } - #endif - JUCE_LEAK_DETECTOR (SynthesiserVoice) }; @@ -352,7 +347,7 @@ class JUCE_API Synthesiser int getNumSounds() const noexcept { return sounds.size(); } /** Returns one of the sounds. */ - SynthesiserSound* getSound (int index) const noexcept { return sounds [index]; } + SynthesiserSound::Ptr getSound (int index) const noexcept { return sounds[index]; } /** Adds a new sound to the synthesiser. @@ -525,21 +520,15 @@ class JUCE_API Synthesiser both to the audio output buffer and the midi input buffer, so any midi events with timestamps outside the specified region will be ignored. */ - inline void renderNextBlock (AudioBuffer& outputAudio, - const MidiBuffer& inputMidi, - int startSample, - int numSamples) - { - processNextBlock (outputAudio, inputMidi, startSample, numSamples); - } + void renderNextBlock (AudioBuffer& outputAudio, + const MidiBuffer& inputMidi, + int startSample, + int numSamples); - inline void renderNextBlock (AudioBuffer& outputAudio, - const MidiBuffer& inputMidi, - int startSample, - int numSamples) - { - processNextBlock (outputAudio, inputMidi, startSample, numSamples); - } + void renderNextBlock (AudioBuffer& outputAudio, + const MidiBuffer& inputMidi, + 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. @@ -632,12 +621,6 @@ class JUCE_API Synthesiser private: //============================================================================== - template - void processNextBlock (AudioBuffer& outputAudio, - const MidiBuffer& inputMidi, - int startSample, - int numSamples); - //============================================================================== double sampleRate = 0; uint32 lastNoteOnCounter = 0; int minimumSubBlockSize = 32; @@ -645,13 +628,8 @@ class JUCE_API Synthesiser bool shouldStealNotes = true; BigInteger sustainPedalsDown; - #if JUCE_CATCH_DEPRECATED_CODE_MISUSE - // 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 + template + void processNextBlock (AudioBuffer&, const MidiBuffer&, int startSample, int numSamples); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Synthesiser) }; diff --git a/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_ADSR.h b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_ADSR.h new file mode 100644 index 00000000..52d47c8e --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_ADSR.h @@ -0,0 +1,270 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +//============================================================================== +/** + A very simple ADSR envelope class. + + To use it, call setSampleRate() with the current sample rate and give it some parameters + with setParameters() then call getNextSample() to get the envelope value to be applied + to each audio sample or applyEnvelopeToBuffer() to apply the envelope to a whole buffer. + + @tags{Audio} +*/ +class JUCE_API ADSR +{ +public: + //============================================================================== + ADSR() + { + recalculateRates(); + } + + //============================================================================== + /** + Holds the parameters being used by an ADSR object. + + @tags{Audio} + */ + struct JUCE_API Parameters + { + Parameters() = default; + + Parameters (float attackTimeSeconds, + float decayTimeSeconds, + float sustainLevel, + float releaseTimeSeconds) + : attack (attackTimeSeconds), + decay (decayTimeSeconds), + sustain (sustainLevel), + release (releaseTimeSeconds) + { + } + + float attack = 0.1f, decay = 0.1f, sustain = 1.0f, release = 0.1f; + }; + + /** Sets the parameters that will be used by an ADSR object. + + You must have called setSampleRate() with the correct sample rate before + this otherwise the values may be incorrect! + + @see getParameters + */ + void setParameters (const Parameters& newParameters) + { + // need to call setSampleRate() first! + jassert (sampleRate > 0.0); + + parameters = newParameters; + recalculateRates(); + } + + /** Returns the parameters currently being used by an ADSR object. + + @see setParameters + */ + const Parameters& getParameters() const noexcept { return parameters; } + + /** Returns true if the envelope is in its attack, decay, sustain or release stage. */ + bool isActive() const noexcept { return state != State::idle; } + + //============================================================================== + /** Sets the sample rate that will be used for the envelope. + + This must be called before the getNextSample() or setParameters() methods. + */ + void setSampleRate (double newSampleRate) noexcept + { + jassert (newSampleRate > 0.0); + sampleRate = newSampleRate; + } + + //============================================================================== + /** Resets the envelope to an idle state. */ + void reset() noexcept + { + envelopeVal = 0.0f; + state = State::idle; + } + + /** Starts the attack phase of the envelope. */ + void noteOn() noexcept + { + if (attackRate > 0.0f) + { + state = State::attack; + } + else if (decayRate > 0.0f) + { + envelopeVal = 1.0f; + state = State::decay; + } + else + { + envelopeVal = parameters.sustain; + state = State::sustain; + } + } + + /** Starts the release phase of the envelope. */ + void noteOff() noexcept + { + if (state != State::idle) + { + if (parameters.release > 0.0f) + { + releaseRate = (float) (envelopeVal / (parameters.release * sampleRate)); + state = State::release; + } + else + { + reset(); + } + } + } + + //============================================================================== + /** Returns the next sample value for an ADSR object. + + @see applyEnvelopeToBuffer + */ + float getNextSample() noexcept + { + if (state == State::idle) + return 0.0f; + + if (state == State::attack) + { + envelopeVal += attackRate; + + if (envelopeVal >= 1.0f) + { + envelopeVal = 1.0f; + goToNextState(); + } + } + else if (state == State::decay) + { + envelopeVal -= decayRate; + + if (envelopeVal <= parameters.sustain) + { + envelopeVal = parameters.sustain; + goToNextState(); + } + } + else if (state == State::sustain) + { + envelopeVal = parameters.sustain; + } + else if (state == State::release) + { + envelopeVal -= releaseRate; + + if (envelopeVal <= 0.0f) + goToNextState(); + } + + return envelopeVal; + } + + /** This method will conveniently apply the next numSamples number of envelope values + to an AudioBuffer. + + @see getNextSample + */ + template + void applyEnvelopeToBuffer (AudioBuffer& buffer, int startSample, int numSamples) + { + jassert (startSample + numSamples <= buffer.getNumSamples()); + + if (state == State::idle) + { + buffer.clear (startSample, numSamples); + return; + } + + if (state == State::sustain) + { + buffer.applyGain (startSample, numSamples, parameters.sustain); + return; + } + + auto numChannels = buffer.getNumChannels(); + + while (--numSamples >= 0) + { + auto env = getNextSample(); + + for (int i = 0; i < numChannels; ++i) + buffer.getWritePointer (i)[startSample] *= env; + + ++startSample; + } + } + +private: + //============================================================================== + void recalculateRates() noexcept + { + auto getRate = [] (float distance, float timeInSeconds, double sr) + { + return timeInSeconds > 0.0f ? (float) (distance / (timeInSeconds * sr)) : -1.0f; + }; + + attackRate = getRate (1.0f, parameters.attack, sampleRate); + decayRate = getRate (1.0f - parameters.sustain, parameters.decay, sampleRate); + releaseRate = getRate (parameters.sustain, parameters.release, sampleRate); + + if ((state == State::attack && attackRate <= 0.0f) + || (state == State::decay && (decayRate <= 0.0f || envelopeVal <= parameters.sustain)) + || (state == State::release && releaseRate <= 0.0f)) + { + goToNextState(); + } + } + + void goToNextState() noexcept + { + if (state == State::attack) + state = (decayRate > 0.0f ? State::decay : State::sustain); + else if (state == State::decay) + state = State::sustain; + else if (state == State::release) + reset(); + } + + //============================================================================== + enum class State { idle, attack, decay, sustain, release }; + + State state = State::idle; + Parameters parameters; + + double sampleRate = 44100.0; + float envelopeVal = 0.0f, attackRate = 0.0f, decayRate = 0.0f, releaseRate = 0.0f; +}; + +} // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_ADSR_test.cpp b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_ADSR_test.cpp new file mode 100644 index 00000000..deff9312 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_ADSR_test.cpp @@ -0,0 +1,257 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +struct ADSRTests : public UnitTest +{ + ADSRTests() : UnitTest ("ADSR", UnitTestCategories::audio) {} + + void runTest() override + { + constexpr double sampleRate = 44100.0; + const ADSR::Parameters parameters { 0.1f, 0.1f, 0.5f, 0.1f }; + + ADSR adsr; + adsr.setSampleRate (sampleRate); + adsr.setParameters (parameters); + + beginTest ("Idle"); + { + adsr.reset(); + + expect (! adsr.isActive()); + expectEquals (adsr.getNextSample(), 0.0f); + } + + beginTest ("Attack"); + { + adsr.reset(); + + adsr.noteOn(); + expect (adsr.isActive()); + + auto buffer = getTestBuffer (sampleRate, parameters.attack); + adsr.applyEnvelopeToBuffer (buffer, 0, buffer.getNumSamples()); + + expect (isIncreasing (buffer)); + } + + beginTest ("Decay"); + { + adsr.reset(); + + adsr.noteOn(); + advanceADSR (adsr, roundToInt (parameters.attack * sampleRate)); + + auto buffer = getTestBuffer (sampleRate, parameters.decay); + adsr.applyEnvelopeToBuffer (buffer, 0, buffer.getNumSamples()); + + expect (isDecreasing (buffer)); + } + + beginTest ("Sustain"); + { + adsr.reset(); + + adsr.noteOn(); + advanceADSR (adsr, roundToInt ((parameters.attack + parameters.decay + 0.01) * sampleRate)); + + auto random = getRandom(); + + for (int numTests = 0; numTests < 100; ++numTests) + { + const auto sustainLevel = random.nextFloat(); + const auto sustainLength = jmax (0.1f, random.nextFloat()); + + adsr.setParameters ({ parameters.attack, parameters.decay, sustainLevel, parameters.release }); + + auto buffer = getTestBuffer (sampleRate, sustainLength); + adsr.applyEnvelopeToBuffer (buffer, 0, buffer.getNumSamples()); + + expect (isSustained (buffer, sustainLevel)); + } + } + + beginTest ("Release"); + { + adsr.reset(); + + adsr.noteOn(); + advanceADSR (adsr, roundToInt ((parameters.attack + parameters.decay) * sampleRate)); + adsr.noteOff(); + + auto buffer = getTestBuffer (sampleRate, parameters.release); + adsr.applyEnvelopeToBuffer (buffer, 0, buffer.getNumSamples()); + + expect (isDecreasing (buffer)); + } + + beginTest ("Zero-length attack jumps to decay"); + { + adsr.reset(); + adsr.setParameters ({ 0.0f, parameters.decay, parameters.sustain, parameters.release }); + + adsr.noteOn(); + + auto buffer = getTestBuffer (sampleRate, parameters.decay); + adsr.applyEnvelopeToBuffer (buffer, 0, buffer.getNumSamples()); + + expect (isDecreasing (buffer)); + } + + beginTest ("Zero-length decay jumps to sustain"); + { + adsr.reset(); + adsr.setParameters ({ parameters.attack, 0.0f, parameters.sustain, parameters.release }); + + adsr.noteOn(); + advanceADSR (adsr, roundToInt (parameters.attack * sampleRate)); + adsr.getNextSample(); + + expectEquals (adsr.getNextSample(), parameters.sustain); + + auto buffer = getTestBuffer (sampleRate, 1); + adsr.applyEnvelopeToBuffer (buffer, 0, buffer.getNumSamples()); + + expect (isSustained (buffer, parameters.sustain)); + } + + beginTest ("Zero-length attack and decay jumps to sustain"); + { + adsr.reset(); + adsr.setParameters ({ 0.0f, 0.0f, parameters.sustain, parameters.release }); + + adsr.noteOn(); + + expectEquals (adsr.getNextSample(), parameters.sustain); + + auto buffer = getTestBuffer (sampleRate, 1); + adsr.applyEnvelopeToBuffer (buffer, 0, buffer.getNumSamples()); + + expect (isSustained (buffer, parameters.sustain)); + } + + beginTest ("Zero-length attack and decay releases correctly"); + { + adsr.reset(); + adsr.setParameters ({ 0.0f, 0.0f, parameters.sustain, parameters.release }); + + adsr.noteOn(); + adsr.noteOff(); + + auto buffer = getTestBuffer (sampleRate, parameters.release); + adsr.applyEnvelopeToBuffer (buffer, 0, buffer.getNumSamples()); + + expect (isDecreasing (buffer)); + } + + beginTest ("Zero-length release resets to idle"); + { + adsr.reset(); + adsr.setParameters ({ parameters.attack, parameters.decay, parameters.sustain, 0.0f }); + + adsr.noteOn(); + advanceADSR (adsr, roundToInt ((parameters.attack + parameters.decay) * sampleRate)); + adsr.noteOff(); + + expect (! adsr.isActive()); + } + } + + static void advanceADSR (ADSR& adsr, int numSamplesToAdvance) + { + while (--numSamplesToAdvance >= 0) + adsr.getNextSample(); + } + + static AudioBuffer getTestBuffer (double sampleRate, float lengthInSeconds) + { + AudioBuffer buffer { 2, roundToInt (lengthInSeconds * sampleRate) }; + + for (int channel = 0; channel < buffer.getNumChannels(); ++channel) + for (int sample = 0; sample < buffer.getNumSamples(); ++sample) + buffer.setSample (channel, sample, 1.0f); + + return buffer; + } + + static bool isIncreasing (const AudioBuffer& b) + { + jassert (b.getNumChannels() > 0 && b.getNumSamples() > 0); + + for (int channel = 0; channel < b.getNumChannels(); ++channel) + { + float previousSample = -1.0f; + + for (int sample = 0; sample < b.getNumSamples(); ++sample) + { + const auto currentSample = b.getSample (channel, sample); + + if (currentSample <= previousSample) + return false; + + previousSample = currentSample; + } + } + + return true; + } + + static bool isDecreasing (const AudioBuffer& b) + { + jassert (b.getNumChannels() > 0 && b.getNumSamples() > 0); + + for (int channel = 0; channel < b.getNumChannels(); ++channel) + { + float previousSample = std::numeric_limits::max(); + + for (int sample = 0; sample < b.getNumSamples(); ++sample) + { + const auto currentSample = b.getSample (channel, sample); + + if (currentSample >= previousSample) + return false; + + previousSample = currentSample; + } + } + + return true; + } + + static bool isSustained (const AudioBuffer& b, float sustainLevel) + { + jassert (b.getNumChannels() > 0 && b.getNumSamples() > 0); + + for (int channel = 0; channel < b.getNumChannels(); ++channel) + if (b.findMinMax (channel, 0, b.getNumSamples()) != Range { sustainLevel, sustainLevel }) + return false; + + return true; + } +}; + +static ADSRTests adsrTests; + +} // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/effects/juce_Decibels.h b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_Decibels.h similarity index 95% rename from JuceLibraryCode/modules/juce_audio_basics/effects/juce_Decibels.h rename to JuceLibraryCode/modules/juce_audio_basics/utilities/juce_Decibels.h index f1aa5ebd..601b30c0 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/effects/juce_Decibels.h +++ b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_Decibels.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. diff --git a/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_GenericInterpolator.h b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_GenericInterpolator.h new file mode 100644 index 00000000..1a8ac8f9 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_GenericInterpolator.h @@ -0,0 +1,500 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + By using JUCE, you agree to the terms of both the JUCE 6 End-User License + Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020). + + End User License Agreement: www.juce.com/juce-6-licence + Privacy Policy: www.juce.com/juce-privacy-policy + + Or: You may also use this code under the terms of the GPL v3 (see + www.gnu.org/licenses). + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +/** + An interpolator base class for resampling streams of floats. + + Note that the resamplers are stateful, so when there's a break in the continuity + of the input stream you're feeding it, you should call reset() before feeding + it any new data. And like with any other stateful filter, if you're resampling + multiple channels, make sure each one uses its own interpolator object. + + @see LagrangeInterpolator, CatmullRomInterpolator, WindowedSincInterpolator, + LinearInterpolator, ZeroOrderHoldInterpolator + + @tags{Audio} +*/ +template +class JUCE_API GenericInterpolator +{ +public: + GenericInterpolator() noexcept { reset(); } + + GenericInterpolator (GenericInterpolator&&) noexcept = default; + GenericInterpolator& operator= (GenericInterpolator&&) noexcept = default; + + /** Returns the latency of the interpolation algorithm in isolation. + + In the context of resampling the total latency of a process using + the interpolator is the base latency divided by the speed ratio. + */ + static constexpr float getBaseLatency() noexcept + { + return InterpolatorTraits::algorithmicLatency; + } + + /** Resets the state of the interpolator. + + Call this when there's a break in the continuity of the input data stream. + */ + void reset() noexcept + { + indexBuffer = 0; + subSamplePos = 1.0; + std::fill (std::begin (lastInputSamples), std::end (lastInputSamples), 0.0f); + } + + /** Resamples a stream of samples. + + @param speedRatio the number of input samples to use for each output sample + @param inputSamples the source data to read from. This must contain at + least (speedRatio * numOutputSamplesToProduce) samples. + @param outputSamples the buffer to write the results into + @param numOutputSamplesToProduce the number of output samples that should be created + + @returns the actual number of input samples that were used + */ + int process (double speedRatio, + const float* inputSamples, + float* outputSamples, + int numOutputSamplesToProduce) noexcept + { + return interpolate (speedRatio, inputSamples, outputSamples, numOutputSamplesToProduce); + } + + /** Resamples a stream of samples. + + @param speedRatio the number of input samples to use for each output sample + @param inputSamples the source data to read from. This must contain at + least (speedRatio * numOutputSamplesToProduce) samples. + @param outputSamples the buffer to write the results into + @param numOutputSamplesToProduce the number of output samples that should be created + @param numInputSamplesAvailable the number of available input samples. If it needs more samples + than available, it either wraps back for wrapAround samples, or + it feeds zeroes + @param wrapAround if the stream exceeds available samples, it wraps back for + wrapAround samples. If wrapAround is set to 0, it will feed zeroes. + + @returns the actual number of input samples that were used + */ + int process (double speedRatio, + const float* inputSamples, + float* outputSamples, + int numOutputSamplesToProduce, + int numInputSamplesAvailable, + int wrapAround) noexcept + { + return interpolate (speedRatio, inputSamples, outputSamples, + numOutputSamplesToProduce, numInputSamplesAvailable, wrapAround); + } + + /** Resamples a stream of samples, adding the results to the output data + with a gain. + + @param speedRatio the number of input samples to use for each output sample + @param inputSamples the source data to read from. This must contain at + least (speedRatio * numOutputSamplesToProduce) samples. + @param outputSamples the buffer to write the results to - the result values will be added + to any pre-existing data in this buffer after being multiplied by + the gain factor + @param numOutputSamplesToProduce the number of output samples that should be created + @param gain a gain factor to multiply the resulting samples by before + adding them to the destination buffer + + @returns the actual number of input samples that were used + */ + int processAdding (double speedRatio, + const float* inputSamples, + float* outputSamples, + int numOutputSamplesToProduce, + float gain) noexcept + { + return interpolateAdding (speedRatio, inputSamples, outputSamples, numOutputSamplesToProduce, gain); + } + + /** Resamples a stream of samples, adding the results to the output data + with a gain. + + @param speedRatio the number of input samples to use for each output sample + @param inputSamples the source data to read from. This must contain at + least (speedRatio * numOutputSamplesToProduce) samples. + @param outputSamples the buffer to write the results to - the result values will be added + to any pre-existing data in this buffer after being multiplied by + the gain factor + @param numOutputSamplesToProduce the number of output samples that should be created + @param numInputSamplesAvailable the number of available input samples. If it needs more samples + than available, it either wraps back for wrapAround samples, or + it feeds zeroes + @param wrapAround if the stream exceeds available samples, it wraps back for + wrapAround samples. If wrapAround is set to 0, it will feed zeroes. + @param gain a gain factor to multiply the resulting samples by before + adding them to the destination buffer + + @returns the actual number of input samples that were used + */ + int processAdding (double speedRatio, + const float* inputSamples, + float* outputSamples, + int numOutputSamplesToProduce, + int numInputSamplesAvailable, + int wrapAround, + float gain) noexcept + { + return interpolateAdding (speedRatio, inputSamples, outputSamples, + numOutputSamplesToProduce, numInputSamplesAvailable, wrapAround, gain); + } + +private: + //============================================================================== + forcedinline void pushInterpolationSample (float newValue) noexcept + { + lastInputSamples[indexBuffer] = newValue; + + if (++indexBuffer == memorySize) + indexBuffer = 0; + } + + forcedinline void pushInterpolationSamples (const float* input, + int numOutputSamplesToProduce) noexcept + { + if (numOutputSamplesToProduce >= memorySize) + { + const auto* const offsetInput = input + (numOutputSamplesToProduce - memorySize); + + for (int i = 0; i < memorySize; ++i) + pushInterpolationSample (offsetInput[i]); + } + else + { + for (int i = 0; i < numOutputSamplesToProduce; ++i) + pushInterpolationSample (input[i]); + } + } + + forcedinline void pushInterpolationSamples (const float* input, + int numOutputSamplesToProduce, + int numInputSamplesAvailable, + int wrapAround) noexcept + { + if (numOutputSamplesToProduce >= memorySize) + { + if (numInputSamplesAvailable >= memorySize) + { + pushInterpolationSamples (input, + numOutputSamplesToProduce); + } + else + { + pushInterpolationSamples (input + ((numOutputSamplesToProduce - numInputSamplesAvailable) - 1), + numInputSamplesAvailable); + + if (wrapAround > 0) + { + numOutputSamplesToProduce -= wrapAround; + + pushInterpolationSamples (input + ((numOutputSamplesToProduce - (memorySize - numInputSamplesAvailable)) - 1), + memorySize - numInputSamplesAvailable); + } + else + { + for (int i = numInputSamplesAvailable; i < memorySize; ++i) + pushInterpolationSample (0.0f); + } + } + } + else + { + if (numOutputSamplesToProduce > numInputSamplesAvailable) + { + for (int i = 0; i < numInputSamplesAvailable; ++i) + pushInterpolationSample (input[i]); + + const auto extraSamples = numOutputSamplesToProduce - numInputSamplesAvailable; + + if (wrapAround > 0) + { + const auto* const offsetInput = input + (numInputSamplesAvailable - wrapAround); + + for (int i = 0; i < extraSamples; ++i) + pushInterpolationSample (offsetInput[i]); + } + else + { + for (int i = 0; i < extraSamples; ++i) + pushInterpolationSample (0.0f); + } + } + else + { + for (int i = 0; i < numOutputSamplesToProduce; ++i) + pushInterpolationSample (input[i]); + } + } + } + + //============================================================================== + int interpolate (double speedRatio, + const float* input, + float* output, + int numOutputSamplesToProduce) noexcept + { + auto pos = subSamplePos; + int numUsed = 0; + + while (numOutputSamplesToProduce > 0) + { + while (pos >= 1.0) + { + pushInterpolationSample (input[numUsed++]); + pos -= 1.0; + } + + *output++ = InterpolatorTraits::valueAtOffset (lastInputSamples, (float) pos, indexBuffer); + pos += speedRatio; + --numOutputSamplesToProduce; + } + + subSamplePos = pos; + return numUsed; + } + + int interpolate (double speedRatio, + const float* input, float* output, + int numOutputSamplesToProduce, + int numInputSamplesAvailable, + int wrap) noexcept + { + auto originalIn = input; + auto pos = subSamplePos; + bool exceeded = false; + + if (speedRatio < 1.0) + { + for (int i = numOutputSamplesToProduce; --i >= 0;) + { + if (pos >= 1.0) + { + if (exceeded) + { + pushInterpolationSample (0.0f); + } + else + { + pushInterpolationSample (*input++); + + if (--numInputSamplesAvailable <= 0) + { + if (wrap > 0) + { + input -= wrap; + numInputSamplesAvailable += wrap; + } + else + { + exceeded = true; + } + } + } + + pos -= 1.0; + } + + *output++ = InterpolatorTraits::valueAtOffset (lastInputSamples, (float) pos, indexBuffer); + pos += speedRatio; + } + } + else + { + for (int i = numOutputSamplesToProduce; --i >= 0;) + { + while (pos < speedRatio) + { + if (exceeded) + { + pushInterpolationSample (0); + } + else + { + pushInterpolationSample (*input++); + + if (--numInputSamplesAvailable <= 0) + { + if (wrap > 0) + { + input -= wrap; + numInputSamplesAvailable += wrap; + } + else + { + exceeded = true; + } + } + } + + pos += 1.0; + } + + pos -= speedRatio; + *output++ = InterpolatorTraits::valueAtOffset (lastInputSamples, jmax (0.0f, 1.0f - (float) pos), indexBuffer); + } + } + + subSamplePos = pos; + + if (wrap == 0) + return (int) (input - originalIn); + + return ((int) (input - originalIn) + wrap) % wrap; + } + + int interpolateAdding (double speedRatio, + const float* input, + float* output, + int numOutputSamplesToProduce, + int numInputSamplesAvailable, + int wrap, + float gain) noexcept + { + auto originalIn = input; + auto pos = subSamplePos; + bool exceeded = false; + + if (speedRatio < 1.0) + { + for (int i = numOutputSamplesToProduce; --i >= 0;) + { + if (pos >= 1.0) + { + if (exceeded) + { + pushInterpolationSample (0.0); + } + else + { + pushInterpolationSample (*input++); + + if (--numInputSamplesAvailable <= 0) + { + if (wrap > 0) + { + input -= wrap; + numInputSamplesAvailable += wrap; + } + else + { + numInputSamplesAvailable = true; + } + } + } + + pos -= 1.0; + } + + *output++ += gain * InterpolatorTraits::valueAtOffset (lastInputSamples, (float) pos, indexBuffer); + pos += speedRatio; + } + } + else + { + for (int i = numOutputSamplesToProduce; --i >= 0;) + { + while (pos < speedRatio) + { + if (exceeded) + { + pushInterpolationSample (0.0); + } + else + { + pushInterpolationSample (*input++); + + if (--numInputSamplesAvailable <= 0) + { + if (wrap > 0) + { + input -= wrap; + numInputSamplesAvailable += wrap; + } + else + { + exceeded = true; + } + } + } + + pos += 1.0; + } + + pos -= speedRatio; + *output++ += gain * InterpolatorTraits::valueAtOffset (lastInputSamples, jmax (0.0f, 1.0f - (float) pos), indexBuffer); + } + } + + subSamplePos = pos; + + if (wrap == 0) + return (int) (input - originalIn); + + return ((int) (input - originalIn) + wrap) % wrap; + } + + int interpolateAdding (double speedRatio, + const float* input, + float* output, + int numOutputSamplesToProduce, + float gain) noexcept + { + auto pos = subSamplePos; + int numUsed = 0; + + while (numOutputSamplesToProduce > 0) + { + while (pos >= 1.0) + { + pushInterpolationSample (input[numUsed++]); + pos -= 1.0; + } + + *output++ += gain * InterpolatorTraits::valueAtOffset (lastInputSamples, (float) pos, indexBuffer); + pos += speedRatio; + --numOutputSamplesToProduce; + } + + subSamplePos = pos; + return numUsed; + } + + //============================================================================== + float lastInputSamples[(size_t) memorySize]; + double subSamplePos = 1.0; + int indexBuffer = 0; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GenericInterpolator) +}; + +} // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/effects/juce_IIRFilter.cpp b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_IIRFilter.cpp similarity index 88% rename from JuceLibraryCode/modules/juce_audio_basics/effects/juce_IIRFilter.cpp rename to JuceLibraryCode/modules/juce_audio_basics/utilities/juce_IIRFilter.cpp index 392ccfc1..fae0c9f9 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/effects/juce_IIRFilter.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_IIRFilter.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -258,42 +258,42 @@ IIRCoefficients IIRCoefficients::makePeakFilter (double sampleRate, } //============================================================================== -IIRFilter::IIRFilter() noexcept -{ -} +template +IIRFilterBase::IIRFilterBase() noexcept = default; -IIRFilter::IIRFilter (const IIRFilter& other) noexcept : active (other.active) +template +IIRFilterBase::IIRFilterBase (const IIRFilterBase& other) noexcept : active (other.active) { - const SpinLock::ScopedLockType sl (other.processLock); + const typename Mutex::ScopedLockType sl (other.processLock); coefficients = other.coefficients; } -IIRFilter::~IIRFilter() noexcept -{ -} - //============================================================================== -void IIRFilter::makeInactive() noexcept +template +void IIRFilterBase::makeInactive() noexcept { - const SpinLock::ScopedLockType sl (processLock); + const typename Mutex::ScopedLockType sl (processLock); active = false; } -void IIRFilter::setCoefficients (const IIRCoefficients& newCoefficients) noexcept +template +void IIRFilterBase::setCoefficients (const IIRCoefficients& newCoefficients) noexcept { - const SpinLock::ScopedLockType sl (processLock); + const typename Mutex::ScopedLockType sl (processLock); coefficients = newCoefficients; active = true; } //============================================================================== -void IIRFilter::reset() noexcept +template +void IIRFilterBase::reset() noexcept { - const SpinLock::ScopedLockType sl (processLock); + const typename Mutex::ScopedLockType sl (processLock); v1 = v2 = 0.0; } -float IIRFilter::processSingleSampleRaw (float in) noexcept +template +float IIRFilterBase::processSingleSampleRaw (float in) noexcept { auto out = coefficients.coefficients[0] * in + v1; @@ -305,9 +305,10 @@ float IIRFilter::processSingleSampleRaw (float in) noexcept return out; } -void IIRFilter::processSamples (float* const samples, const int numSamples) noexcept +template +void IIRFilterBase::processSamples (float* const samples, const int numSamples) noexcept { - const SpinLock::ScopedLockType sl (processLock); + const typename Mutex::ScopedLockType sl (processLock); if (active) { @@ -333,4 +334,7 @@ void IIRFilter::processSamples (float* const samples, const int numSamples) noex } } +template class IIRFilterBase; +template class IIRFilterBase; + } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/effects/juce_IIRFilter.h b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_IIRFilter.h similarity index 82% rename from JuceLibraryCode/modules/juce_audio_basics/effects/juce_IIRFilter.h rename to JuceLibraryCode/modules/juce_audio_basics/utilities/juce_IIRFilter.h index 3b6e8cf5..9f6dcc04 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/effects/juce_IIRFilter.h +++ b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_IIRFilter.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -153,7 +153,8 @@ class JUCE_API IIRCoefficients @tags{Audio} */ -class JUCE_API IIRFilter +template +class JUCE_API IIRFilterBase { public: //============================================================================== @@ -163,13 +164,10 @@ class JUCE_API IIRFilter you process with it. Use the setCoefficients() method to turn it into the type of filter needed. */ - IIRFilter() noexcept; + IIRFilterBase() noexcept; /** Creates a copy of another filter. */ - IIRFilter (const IIRFilter&) noexcept; - - /** Destructor. */ - ~IIRFilter() noexcept; + IIRFilterBase (const IIRFilterBase&) noexcept; //============================================================================== /** Clears the filter so that any incoming data passes through unchanged. */ @@ -202,7 +200,7 @@ class JUCE_API IIRFilter protected: //============================================================================== - SpinLock processLock; + Mutex processLock; IIRCoefficients coefficients; float v1 = 0, v2 = 0; bool active = false; @@ -214,4 +212,43 @@ class JUCE_API IIRFilter JUCE_LEAK_DETECTOR (IIRFilter) }; +/** + An IIR filter that can perform low, high, or band-pass filtering on an + audio signal, and which attempts to implement basic thread-safety. + + This class synchronises calls to some of its member functions, making it + safe (although not necessarily real-time-safe) to reset the filter or + apply new coefficients while the filter is processing on another thread. + In most cases this style of internal locking should not be used, and you + should attempt to provide thread-safety at a higher level in your program. + If you can guarantee that calls to the filter will be synchronised externally, + you could consider switching to SingleThreadedIIRFilter instead. + + @see SingleThreadedIIRFilter, IIRCoefficient, IIRFilterAudioSource + + @tags{Audio} +*/ +class IIRFilter : public IIRFilterBase +{ +public: + using IIRFilterBase::IIRFilterBase; +}; + +/** + An IIR filter that can perform low, high, or band-pass filtering on an + audio signal, with no thread-safety guarantees. + + You should use this class if you need an IIR filter, and don't plan to + call its member functions from multiple threads at once. + + @see IIRFilter, IIRCoefficient, IIRFilterAudioSource + + @tags{Audio} +*/ +class SingleThreadedIIRFilter : public IIRFilterBase +{ +public: + using IIRFilterBase::IIRFilterBase; +}; + } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_Interpolators.cpp b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_Interpolators.cpp new file mode 100644 index 00000000..6302f320 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_Interpolators.cpp @@ -0,0 +1,191 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + By using JUCE, you agree to the terms of both the JUCE 6 End-User License + Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020). + + End User License Agreement: www.juce.com/juce-6-licence + Privacy Policy: www.juce.com/juce-privacy-policy + + Or: You may also use this code under the terms of the GPL v3 (see + www.gnu.org/licenses). + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +#if JUCE_UNIT_TESTS + +class InterpolatorTests : public UnitTest +{ +public: + InterpolatorTests() + : UnitTest ("InterpolatorTests", UnitTestCategories::audio) + { + } + +private: + template + void runInterplatorTests (const String& interpolatorName) + { + auto createGaussian = [] (std::vector& destination, float scale, float centreInSamples, float width) + { + for (size_t i = 0; i < destination.size(); ++i) + { + auto x = (((float) i) - centreInSamples) * width; + destination[i] = std::exp (-(x * x)); + } + + FloatVectorOperations::multiply (destination.data(), scale, (int) destination.size()); + }; + + auto findGaussianPeak = [] (const std::vector& input) -> float + { + auto max = std::max_element (std::begin (input), std::end (input)); + auto maxPrev = max - 1; + jassert (maxPrev >= std::begin (input)); + auto maxNext = max + 1; + jassert (maxNext < std::end (input)); + auto quadraticMaxLoc = (*maxPrev - *maxNext) / (2.0f * ((*maxNext + *maxPrev) - (2.0f * *max))); + return quadraticMaxLoc + (float) std::distance (std::begin (input), max); + }; + + auto expectAllElementsWithin = [this] (const std::vector& v1, const std::vector& v2, float tolerance) + { + expectEquals ((int) v1.size(), (int) v2.size()); + + for (size_t i = 0; i < v1.size(); ++i) + expectWithinAbsoluteError (v1[i], v2[i], tolerance); + }; + + InterpolatorType interpolator; + + constexpr size_t inputSize = 1001; + static_assert (inputSize > 800 + InterpolatorType::getBaseLatency(), + "The test InterpolatorTests input buffer is too small"); + + std::vector input (inputSize); + constexpr auto inputGaussianMidpoint = (float) (inputSize - 1) / 2.0f; + constexpr auto inputGaussianValueAtEnds = 0.000001f; + const auto inputGaussianWidth = std::sqrt (-std::log (inputGaussianValueAtEnds)) / inputGaussianMidpoint; + + createGaussian (input, 1.0f, inputGaussianMidpoint, inputGaussianWidth); + + for (auto speedRatio : { 0.4, 0.8263, 1.0, 1.05, 1.2384, 1.6 }) + { + const auto expectedGaussianMidpoint = (inputGaussianMidpoint + InterpolatorType::getBaseLatency()) / (float) speedRatio; + const auto expectedGaussianWidth = inputGaussianWidth * (float) speedRatio; + + const auto outputBufferSize = (size_t) std::floor ((float) input.size() / speedRatio); + + for (int numBlocks : { 1, 5 }) + { + const auto inputBlockSize = (float) input.size() / (float) numBlocks; + const auto outputBlockSize = (int) std::floor (inputBlockSize / speedRatio); + + std::vector output (outputBufferSize, std::numeric_limits::min()); + + beginTest (interpolatorName + " process " + String (numBlocks) + " blocks ratio " + String (speedRatio)); + + interpolator.reset(); + + { + auto* inputPtr = input.data(); + auto* outputPtr = output.data(); + + for (int i = 0; i < numBlocks; ++i) + { + auto numInputSamplesRead = interpolator.process (speedRatio, inputPtr, outputPtr, outputBlockSize); + inputPtr += numInputSamplesRead; + outputPtr += outputBlockSize; + } + } + + expectWithinAbsoluteError (findGaussianPeak (output), expectedGaussianMidpoint, 0.1f); + + std::vector expectedOutput (output.size()); + createGaussian (expectedOutput, 1.0f, expectedGaussianMidpoint, expectedGaussianWidth); + + expectAllElementsWithin (output, expectedOutput, 0.02f); + + beginTest (interpolatorName + " process adding " + String (numBlocks) + " blocks ratio " + String (speedRatio)); + + interpolator.reset(); + + constexpr float addingGain = 0.7384f; + + { + auto* inputPtr = input.data(); + auto* outputPtr = output.data(); + + for (int i = 0; i < numBlocks; ++i) + { + auto numInputSamplesRead = interpolator.processAdding (speedRatio, inputPtr, outputPtr, outputBlockSize, addingGain); + inputPtr += numInputSamplesRead; + outputPtr += outputBlockSize; + } + } + + expectWithinAbsoluteError (findGaussianPeak (output), expectedGaussianMidpoint, 0.1f); + + std::vector additionalOutput (output.size()); + createGaussian (additionalOutput, addingGain, expectedGaussianMidpoint, expectedGaussianWidth); + FloatVectorOperations::add (expectedOutput.data(), additionalOutput.data(), (int) additionalOutput.size()); + + expectAllElementsWithin (output, expectedOutput, 0.02f); + } + + beginTest (interpolatorName + " process wrap 0 ratio " + String (speedRatio)); + + std::vector doubleLengthOutput (2 * outputBufferSize, std::numeric_limits::min()); + + interpolator.reset(); + interpolator.process (speedRatio, input.data(), doubleLengthOutput.data(), (int) doubleLengthOutput.size(), + (int) input.size(), 0); + + std::vector expectedDoubleLengthOutput (doubleLengthOutput.size()); + createGaussian (expectedDoubleLengthOutput, 1.0f, expectedGaussianMidpoint, expectedGaussianWidth); + + expectAllElementsWithin (doubleLengthOutput, expectedDoubleLengthOutput, 0.02f); + + beginTest (interpolatorName + " process wrap double ratio " + String (speedRatio)); + + interpolator.reset(); + interpolator.process (speedRatio, input.data(), doubleLengthOutput.data(), (int) doubleLengthOutput.size(), + (int) input.size(), (int) input.size()); + + std::vector secondGaussian (doubleLengthOutput.size()); + createGaussian (secondGaussian, 1.0f, expectedGaussianMidpoint + (float) outputBufferSize, expectedGaussianWidth); + FloatVectorOperations::add (expectedDoubleLengthOutput.data(), secondGaussian.data(), (int) expectedDoubleLengthOutput.size()); + + expectAllElementsWithin (doubleLengthOutput, expectedDoubleLengthOutput, 0.02f); + } + } + +public: + void runTest() override + { + runInterplatorTests ("WindowedSincInterpolator"); + runInterplatorTests ("LagrangeInterpolator"); + runInterplatorTests ("CatmullRomInterpolator"); + runInterplatorTests ("LinearInterpolator"); + } +}; + +static InterpolatorTests interpolatorTests; + +#endif + +} // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_Interpolators.h b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_Interpolators.h new file mode 100644 index 00000000..cdd2c875 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_Interpolators.h @@ -0,0 +1,245 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + By using JUCE, you agree to the terms of both the JUCE 6 End-User License + Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020). + + End User License Agreement: www.juce.com/juce-6-licence + Privacy Policy: www.juce.com/juce-privacy-policy + + Or: You may also use this code under the terms of the GPL v3 (see + www.gnu.org/licenses). + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +/** + A collection of different interpolators for resampling streams of floats. + + @see GenericInterpolator, WindowedSincInterpolator, LagrangeInterpolator, + CatmullRomInterpolator, LinearInterpolator, ZeroOrderHoldInterpolator + + @tags{Audio} +*/ +class Interpolators +{ +private: + struct WindowedSincTraits + { + static constexpr float algorithmicLatency = 100.0f; + + static forcedinline float windowedSinc (float firstFrac, int index) noexcept + { + auto index2 = index + 1; + auto frac = firstFrac; + + auto value1 = lookupTable[index]; + auto value2 = lookupTable[index2]; + + return value1 + (frac * (value2 - value1)); + } + + static forcedinline float valueAtOffset (const float* const inputs, const float offset, int indexBuffer) noexcept + { + const int numCrossings = 100; + const float floatCrossings = (float) numCrossings; + float result = 0.0f; + + auto samplePosition = indexBuffer; + float firstFrac = 0.0f; + float lastSincPosition = -1.0f; + int index = 0, sign = -1; + + for (int i = -numCrossings; i <= numCrossings; ++i) + { + auto sincPosition = (1.0f - offset) + (float) i; + + if (i == -numCrossings || (sincPosition >= 0 && lastSincPosition < 0)) + { + auto indexFloat = (sincPosition >= 0.f ? sincPosition : -sincPosition) * 100.0f; + auto indexFloored = std::floor (indexFloat); + index = (int) indexFloored; + firstFrac = indexFloat - indexFloored; + sign = (sincPosition < 0 ? -1 : 1); + } + + if (sincPosition == 0.0f) + result += inputs[samplePosition]; + else if (sincPosition < floatCrossings && sincPosition > -floatCrossings) + result += inputs[samplePosition] * windowedSinc (firstFrac, index); + + if (++samplePosition == numCrossings * 2) + samplePosition = 0; + + lastSincPosition = sincPosition; + index += 100 * sign; + } + + return result; + } + + static const float lookupTable[10001]; + }; + + struct LagrangeTraits + { + static constexpr float algorithmicLatency = 2.0f; + + static float valueAtOffset (const float*, float, int) noexcept; + }; + + struct CatmullRomTraits + { + //============================================================================== + static constexpr float algorithmicLatency = 2.0f; + + static forcedinline float valueAtOffset (const float* const inputs, const float offset, int index) noexcept + { + auto y0 = inputs[index]; if (++index == 4) index = 0; + auto y1 = inputs[index]; if (++index == 4) index = 0; + auto y2 = inputs[index]; if (++index == 4) index = 0; + auto y3 = inputs[index]; + + auto halfY0 = 0.5f * y0; + auto halfY3 = 0.5f * y3; + + return y1 + offset * ((0.5f * y2 - halfY0) + + (offset * (((y0 + 2.0f * y2) - (halfY3 + 2.5f * y1)) + + (offset * ((halfY3 + 1.5f * y1) - (halfY0 + 1.5f * y2)))))); + } + }; + + struct LinearTraits + { + static constexpr float algorithmicLatency = 1.0f; + + static forcedinline float valueAtOffset (const float* const inputs, const float offset, int index) noexcept + { + auto y0 = inputs[index]; + auto y1 = inputs[index == 0 ? 1 : 0]; + + return y1 * offset + y0 * (1.0f - offset); + } + }; + + struct ZeroOrderHoldTraits + { + static constexpr float algorithmicLatency = 0.0f; + + static forcedinline float valueAtOffset (const float* const inputs, const float, int) noexcept + { + return inputs[0]; + } + }; + +public: + using WindowedSinc = GenericInterpolator; + using Lagrange = GenericInterpolator; + using CatmullRom = GenericInterpolator; + using Linear = GenericInterpolator; + using ZeroOrderHold = GenericInterpolator; +}; + +//============================================================================== +/** + An interpolator for resampling a stream of floats using high order windowed + (hann) sinc interpolation, recommended for high quality resampling. + + Note that the resampler is stateful, so when there's a break in the continuity + of the input stream you're feeding it, you should call reset() before feeding + it any new data. And like with any other stateful filter, if you're resampling + multiple channels, make sure each one uses its own LinearInterpolator object. + + @see GenericInterpolator + + @see LagrangeInterpolator, CatmullRomInterpolator, LinearInterpolator, + ZeroOrderHoldInterpolator + + @tags{Audio} +*/ +using WindowedSincInterpolator = Interpolators::WindowedSinc; + +/** + An interpolator for resampling a stream of floats using 4-point lagrange interpolation. + + Note that the resampler is stateful, so when there's a break in the continuity + of the input stream you're feeding it, you should call reset() before feeding + it any new data. And like with any other stateful filter, if you're resampling + multiple channels, make sure each one uses its own LagrangeInterpolator object. + + @see GenericInterpolator + + @see CatmullRomInterpolator, WindowedSincInterpolator, LinearInterpolator, + ZeroOrderHoldInterpolator + + @tags{Audio} +*/ +using LagrangeInterpolator = Interpolators::Lagrange; + +/** + An interpolator for resampling a stream of floats using Catmull-Rom interpolation. + + Note that the resampler is stateful, so when there's a break in the continuity + of the input stream you're feeding it, you should call reset() before feeding + it any new data. And like with any other stateful filter, if you're resampling + multiple channels, make sure each one uses its own CatmullRomInterpolator object. + + @see GenericInterpolator + + @see LagrangeInterpolator, WindowedSincInterpolator, LinearInterpolator, + ZeroOrderHoldInterpolator + + @tags{Audio} +*/ +using CatmullRomInterpolator = Interpolators::CatmullRom; + +/** + An interpolator for resampling a stream of floats using linear interpolation. + + Note that the resampler is stateful, so when there's a break in the continuity + of the input stream you're feeding it, you should call reset() before feeding + it any new data. And like with any other stateful filter, if you're resampling + multiple channels, make sure each one uses its own LinearInterpolator object. + + @see GenericInterpolator + + @see LagrangeInterpolator, CatmullRomInterpolator, WindowedSincInterpolator, + ZeroOrderHoldInterpolator + + @tags{Audio} +*/ +using LinearInterpolator = Interpolators::Linear; + +/** + An interpolator for resampling a stream of floats using zero order hold + interpolation. + + Note that the resampler is stateful, so when there's a break in the continuity + of the input stream you're feeding it, you should call reset() before feeding + it any new data. And like with any other stateful filter, if you're resampling + multiple channels, make sure each one uses its own ZeroOrderHoldInterpolator + object. + + @see GenericInterpolator + + @see LagrangeInterpolator, CatmullRomInterpolator, WindowedSincInterpolator, + LinearInterpolator + + @tags{Audio} +*/ +using ZeroOrderHoldInterpolator = Interpolators::ZeroOrderHold; + +} // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_LagrangeInterpolator.cpp b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_LagrangeInterpolator.cpp new file mode 100644 index 00000000..c1d2809c --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_LagrangeInterpolator.cpp @@ -0,0 +1,62 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +template +struct LagrangeResampleHelper +{ + static forcedinline void calc (float& a, float b) noexcept { a *= b * (1.0f / k); } +}; + +template <> +struct LagrangeResampleHelper<0> +{ + static forcedinline void calc (float&, float) noexcept {} +}; + +template +static float calcCoefficient (float input, float offset) noexcept +{ + LagrangeResampleHelper<0 - k>::calc (input, -2.0f - offset); + LagrangeResampleHelper<1 - k>::calc (input, -1.0f - offset); + LagrangeResampleHelper<2 - k>::calc (input, 0.0f - offset); + LagrangeResampleHelper<3 - k>::calc (input, 1.0f - offset); + LagrangeResampleHelper<4 - k>::calc (input, 2.0f - offset); + return input; +} + +float Interpolators::LagrangeTraits::valueAtOffset (const float* inputs, float offset, int index) noexcept +{ + float result = 0.0f; + + result += calcCoefficient<0> (inputs[index], offset); if (++index == 5) index = 0; + result += calcCoefficient<1> (inputs[index], offset); if (++index == 5) index = 0; + result += calcCoefficient<2> (inputs[index], offset); if (++index == 5) index = 0; + result += calcCoefficient<3> (inputs[index], offset); if (++index == 5) index = 0; + result += calcCoefficient<4> (inputs[index], offset); + + return result; +} + +} // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/effects/juce_Reverb.h b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_Reverb.h similarity index 84% rename from JuceLibraryCode/modules/juce_audio_basics/effects/juce_Reverb.h rename to JuceLibraryCode/modules/juce_audio_basics/utilities/juce_Reverb.h index aabcad87..a1a78b90 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/effects/juce_Reverb.h +++ b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_Reverb.h @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -49,22 +49,13 @@ class Reverb /** Holds the parameters being used by a Reverb object. */ struct Parameters { - Parameters() noexcept - : roomSize (0.5f), - damping (0.5f), - wetLevel (0.33f), - dryLevel (0.4f), - width (1.0f), - freezeMode (0) - {} - - float roomSize; /**< Room size, 0 to 1.0, where 1.0 is big, 0 is small. */ - float damping; /**< Damping, 0 to 1.0, where 0 is not damped, 1.0 is fully damped. */ - float wetLevel; /**< Wet level, 0 to 1.0 */ - float dryLevel; /**< Dry level, 0 to 1.0 */ - float width; /**< Reverb width, 0 to 1.0, where 1.0 is very wide. */ - float freezeMode; /**< Freeze mode - values < 0.5 are "normal" mode, values > 0.5 - put the reverb into a continuous feedback loop. */ + float roomSize = 0.5f; /**< Room size, 0 to 1.0, where 1.0 is big, 0 is small. */ + float damping = 0.5f; /**< Damping, 0 to 1.0, where 0 is not damped, 1.0 is fully damped. */ + float wetLevel = 0.33f; /**< Wet level, 0 to 1.0 */ + float dryLevel = 0.4f; /**< Dry level, 0 to 1.0 */ + float width = 1.0f; /**< Reverb width, 0 to 1.0, where 1.0 is very wide. */ + float freezeMode = 0.0f; /**< Freeze mode - values < 0.5 are "normal" mode, values > 0.5 + put the reverb into a continuous feedback loop. */ }; //============================================================================== @@ -81,9 +72,9 @@ class Reverb const float dryScaleFactor = 2.0f; const float wet = newParams.wetLevel * wetScaleFactor; - dryGain.setValue (newParams.dryLevel * dryScaleFactor); - wetGain1.setValue (0.5f * wet * (1.0f + newParams.width)); - wetGain2.setValue (0.5f * wet * (1.0f - newParams.width)); + dryGain.setTargetValue (newParams.dryLevel * dryScaleFactor); + wetGain1.setTargetValue (0.5f * wet * (1.0f + newParams.width)); + wetGain2.setTargetValue (0.5f * wet * (1.0f - newParams.width)); gain = isFrozen (newParams.freezeMode) ? 0.0f : 0.015f; parameters = newParams; @@ -140,6 +131,7 @@ class Reverb /** Applies the reverb to two stereo channels of audio data. */ void processStereo (float* const left, float* const right, const int numSamples) noexcept { + JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6011) jassert (left != nullptr && right != nullptr); for (int i = 0; i < numSamples; ++i) @@ -169,11 +161,13 @@ class Reverb left[i] = outL * wet1 + outR * wet2 + left[i] * dry; right[i] = outR * wet1 + outL * wet2 + right[i] * dry; } + JUCE_END_IGNORE_WARNINGS_MSVC } /** Applies the reverb to a single mono channel of audio data. */ void processMono (float* const samples, const int numSamples) noexcept { + JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6011) jassert (samples != nullptr); for (int i = 0; i < numSamples; ++i) @@ -195,6 +189,7 @@ class Reverb samples[i] = output * wet1 + samples[i] * dry; } + JUCE_END_IGNORE_WARNINGS_MSVC } private: @@ -216,15 +211,15 @@ class Reverb void setDamping (const float dampingToUse, const float roomSizeToUse) noexcept { - damping.setValue (dampingToUse); - feedback.setValue (roomSizeToUse); + damping.setTargetValue (dampingToUse); + feedback.setTargetValue (roomSizeToUse); } //============================================================================== class CombFilter { public: - CombFilter() noexcept : bufferSize (0), bufferIndex (0), last (0) {} + CombFilter() noexcept {} void setSize (const int size) { @@ -259,8 +254,8 @@ class Reverb private: HeapBlock buffer; - int bufferSize, bufferIndex; - float last; + int bufferSize = 0, bufferIndex = 0; + float last = 0.0f; JUCE_DECLARE_NON_COPYABLE (CombFilter) }; @@ -269,7 +264,7 @@ class Reverb class AllPassFilter { public: - AllPassFilter() noexcept : bufferSize (0), bufferIndex (0) {} + AllPassFilter() noexcept {} void setSize (const int size) { @@ -300,7 +295,7 @@ class Reverb private: HeapBlock buffer; - int bufferSize, bufferIndex; + int bufferSize = 0, bufferIndex = 0; JUCE_DECLARE_NON_COPYABLE (AllPassFilter) }; @@ -314,7 +309,7 @@ class Reverb CombFilter comb [numChannels][numCombs]; AllPassFilter allPass [numChannels][numAllPasses]; - LinearSmoothedValue damping, feedback, dryGain, wetGain1, wetGain2; + SmoothedValue damping, feedback, dryGain, wetGain1, wetGain2; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Reverb) }; diff --git a/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_SmoothedValue.cpp b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_SmoothedValue.cpp new file mode 100644 index 00000000..cb581633 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_SmoothedValue.cpp @@ -0,0 +1,92 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +#if JUCE_UNIT_TESTS + +static CommonSmoothedValueTests > commonLinearSmoothedValueTests; +static CommonSmoothedValueTests > commonMultiplicativeSmoothedValueTests; + +class SmoothedValueTests : public UnitTest +{ +public: + SmoothedValueTests() + : UnitTest ("SmoothedValueTests", UnitTestCategories::smoothedValues) + {} + + void runTest() override + { + beginTest ("Linear moving target"); + { + SmoothedValue sv; + + sv.reset (12); + float initialValue = 0.0f; + sv.setCurrentAndTargetValue (initialValue); + sv.setTargetValue (1.0f); + + auto delta = sv.getNextValue() - initialValue; + + sv.skip (6); + + auto newInitialValue = sv.getCurrentValue(); + sv.setTargetValue (newInitialValue + 2.0f); + auto doubleDelta = sv.getNextValue() - newInitialValue; + + expectWithinAbsoluteError (doubleDelta, delta * 2.0f, 1.0e-7f); + } + + beginTest ("Multiplicative curve"); + { + SmoothedValue sv; + + auto numSamples = 12; + AudioBuffer values (2, numSamples + 1); + + sv.reset (numSamples); + sv.setCurrentAndTargetValue (1.0); + sv.setTargetValue (2.0f); + + values.setSample (0, 0, sv.getCurrentValue()); + + for (int i = 1; i < values.getNumSamples(); ++i) + values.setSample (0, i, sv.getNextValue()); + + sv.setTargetValue (1.0f); + values.setSample (1, values.getNumSamples() - 1, sv.getCurrentValue()); + + for (int i = values.getNumSamples() - 2; i >= 0 ; --i) + values.setSample (1, i, sv.getNextValue()); + + for (int i = 0; i < values.getNumSamples(); ++i) + expectWithinAbsoluteError (values.getSample (0, i), values.getSample (1, i), 1.0e-9); + } + } +}; + +static SmoothedValueTests smoothedValueTests; + +#endif + +} // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_SmoothedValue.h b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_SmoothedValue.h new file mode 100644 index 00000000..1757966f --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_SmoothedValue.h @@ -0,0 +1,629 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +//============================================================================== +/** + A base class for the smoothed value classes. + + This class is used to provide common functionality to the SmoothedValue and + dsp::LogRampedValue classes. + + @tags{Audio} +*/ +template +class SmoothedValueBase +{ +private: + //============================================================================== + template struct FloatTypeHelper; + + template