From 30aebf46edd30276d4a20796ebf68fe3b4e2632e Mon Sep 17 00:00:00 2001 From: Geert Bevin Date: Wed, 9 Sep 2020 11:27:44 -0400 Subject: [PATCH] Updated to JUCE v6.0.1. Added NRPN, RPN and 14-bit CC MIDI features. --- Builds/LinuxMakefile/Makefile | 22 +- Builds/MacOSX/receivemidi.entitlements | 6 + .../receivemidi.xcodeproj/project.pbxproj | 43 +- .../receivemidi_ConsoleApp.vcxproj | 242 +- .../receivemidi_ConsoleApp.vcxproj.filters | 426 +- Builds/VisualStudio2015/resources.rc | 2 + JuceLibraryCode/AppConfig.h | 28 +- JuceLibraryCode/JuceHeader.h | 9 + .../audio_play_head/juce_AudioPlayHead.h | 2 +- .../buffers/juce_AudioChannelSet.cpp | 79 +- .../buffers/juce_AudioChannelSet.h | 4 +- .../buffers/juce_AudioDataConverters.cpp | 19 +- .../buffers/juce_AudioDataConverters.h | 76 +- .../buffers/juce_AudioProcessLoadMeasurer.cpp | 16 +- .../buffers/juce_AudioProcessLoadMeasurer.h | 20 +- .../buffers/juce_AudioSampleBuffer.h | 72 +- .../buffers/juce_FloatVectorOperations.cpp | 9 +- .../buffers/juce_FloatVectorOperations.h | 2 +- .../juce_audio_basics/juce_audio_basics.cpp | 5 +- .../juce_audio_basics/juce_audio_basics.h | 29 +- .../juce_audio_basics/juce_audio_basics.mm | 2 +- .../midi/juce_MidiBuffer.cpp | 167 +- .../juce_audio_basics/midi/juce_MidiBuffer.h | 149 +- .../juce_audio_basics/midi/juce_MidiFile.cpp | 11 +- .../juce_audio_basics/midi/juce_MidiFile.h | 2 +- .../midi/juce_MidiKeyboardState.cpp | 37 +- .../midi/juce_MidiKeyboardState.h | 96 +- .../midi/juce_MidiMessage.cpp | 2 +- .../juce_audio_basics/midi/juce_MidiMessage.h | 2 +- .../midi/juce_MidiMessageSequence.cpp | 19 +- .../midi/juce_MidiMessageSequence.h | 12 +- .../juce_audio_basics/midi/juce_MidiRPN.cpp | 20 +- .../juce_audio_basics/midi/juce_MidiRPN.h | 4 +- .../mpe/juce_MPEInstrument.cpp | 158 +- .../mpe/juce_MPEInstrument.h | 34 +- .../mpe/juce_MPEMessages.cpp | 18 +- .../juce_audio_basics/mpe/juce_MPEMessages.h | 4 +- .../juce_audio_basics/mpe/juce_MPENote.cpp | 9 +- .../juce_audio_basics/mpe/juce_MPENote.h | 2 +- .../mpe/juce_MPESynthesiser.cpp | 18 +- .../mpe/juce_MPESynthesiser.h | 6 +- .../mpe/juce_MPESynthesiserBase.cpp | 260 +- .../mpe/juce_MPESynthesiserBase.h | 9 +- .../mpe/juce_MPESynthesiserVoice.cpp | 2 +- .../mpe/juce_MPESynthesiserVoice.h | 2 +- .../juce_audio_basics/mpe/juce_MPEUtils.cpp | 32 +- .../juce_audio_basics/mpe/juce_MPEUtils.h | 7 +- .../juce_audio_basics/mpe/juce_MPEValue.cpp | 9 +- .../juce_audio_basics/mpe/juce_MPEValue.h | 2 +- .../mpe/juce_MPEZoneLayout.cpp | 17 +- .../mpe/juce_MPEZoneLayout.h | 7 +- .../native/juce_mac_CoreAudioLayouts.h | 2 +- .../sources/juce_AudioSource.h | 4 +- .../sources/juce_BufferingAudioSource.cpp | 2 +- .../sources/juce_BufferingAudioSource.h | 2 +- .../juce_ChannelRemappingAudioSource.cpp | 6 +- .../juce_ChannelRemappingAudioSource.h | 4 +- .../sources/juce_IIRFilterAudioSource.cpp | 2 +- .../sources/juce_IIRFilterAudioSource.h | 2 +- .../sources/juce_MemoryAudioSource.cpp | 33 +- .../sources/juce_MemoryAudioSource.h | 23 +- .../sources/juce_MixerAudioSource.cpp | 2 +- .../sources/juce_MixerAudioSource.h | 2 +- .../sources/juce_PositionableAudioSource.h | 2 +- .../sources/juce_ResamplingAudioSource.cpp | 13 +- .../sources/juce_ResamplingAudioSource.h | 9 +- .../sources/juce_ReverbAudioSource.cpp | 2 +- .../sources/juce_ReverbAudioSource.h | 2 +- .../sources/juce_ToneGeneratorAudioSource.cpp | 2 +- .../sources/juce_ToneGeneratorAudioSource.h | 2 +- .../synthesisers/juce_Synthesiser.cpp | 25 +- .../synthesisers/juce_Synthesiser.h | 7 +- .../juce_audio_basics/utilities/juce_ADSR.h | 50 +- .../utilities/juce_CatmullRomInterpolator.cpp | 75 - .../utilities/juce_CatmullRomInterpolator.h | 143 - .../utilities/juce_Decibels.h | 2 +- .../utilities/juce_GenericInterpolator.h | 500 + .../utilities/juce_IIRFilter.cpp | 2 +- .../utilities/juce_IIRFilter.h | 2 +- .../utilities/juce_Interpolators.cpp | 191 + .../utilities/juce_Interpolators.h | 245 + .../utilities/juce_LagrangeInterpolator.cpp | 441 +- .../utilities/juce_LagrangeInterpolator.h | 143 - .../juce_audio_basics/utilities/juce_Reverb.h | 2 +- .../utilities/juce_SmoothedValue.cpp | 4 +- .../utilities/juce_SmoothedValue.h | 22 +- .../juce_WindowedSincInterpolator.cpp | 10033 ++++++++++++++++ .../audio_io/juce_AudioDeviceManager.cpp | 379 +- .../audio_io/juce_AudioDeviceManager.h | 93 +- .../audio_io/juce_AudioIODevice.cpp | 2 +- .../audio_io/juce_AudioIODevice.h | 2 +- .../audio_io/juce_AudioIODeviceType.cpp | 2 +- .../audio_io/juce_AudioIODeviceType.h | 2 +- .../audio_io/juce_SystemAudioVolume.h | 2 +- .../juce_audio_devices/juce_audio_devices.cpp | 38 +- .../juce_audio_devices/juce_audio_devices.h | 58 +- .../juce_audio_devices/juce_audio_devices.mm | 2 +- ...ce_MidiOutput.cpp => juce_MidiDevices.cpp} | 35 +- .../midi_io/juce_MidiDevices.h | 378 + .../midi_io/juce_MidiInput.h | 180 - .../midi_io/juce_MidiMessageCollector.cpp | 44 +- .../midi_io/juce_MidiMessageCollector.h | 14 +- .../midi_io/juce_MidiOutput.h | 145 - .../{roli => rmsl}/juce/JuceMidiSupport.java | 121 +- .../native/juce_MidiDataConcatenator.h | 7 +- .../native/juce_android_Audio.cpp | 18 +- ...juce_android_HighPerformanceAudioHelpers.h | 131 + .../native/juce_android_Midi.cpp | 909 +- .../native/juce_android_Oboe.cpp | 387 +- .../native/juce_android_OpenSL.cpp | 289 +- .../native/juce_ios_Audio.cpp | 10 +- .../native/juce_ios_Audio.h | 2 +- .../native/juce_linux_ALSA.cpp | 14 +- .../native/juce_linux_Bela.cpp | 256 +- .../native/juce_linux_JackAudio.cpp | 8 +- .../native/juce_linux_Midi.cpp | 270 +- .../native/juce_mac_CoreAudio.cpp | 68 +- .../native/juce_mac_CoreMidi.cpp | 558 +- .../native/juce_win32_ASIO.cpp | 48 +- .../native/juce_win32_DirectSound.cpp | 25 +- .../native/juce_win32_Midi.cpp | 557 +- .../native/juce_win32_WASAPI.cpp | 195 +- .../native/oboe/CMakeLists.txt | 91 + .../juce_audio_devices/native/oboe/LICENSE | 202 + .../native/oboe/include/oboe/AudioStream.h | 543 + .../oboe/include/oboe/AudioStreamBase.h | 202 + .../oboe/include/oboe/AudioStreamBuilder.h | 438 + .../oboe/include/oboe/AudioStreamCallback.h | 123 + .../native/oboe/include/oboe/Definitions.h | 519 + .../native/oboe/include/oboe/LatencyTuner.h | 118 + .../native/oboe/include/oboe/Oboe.h | 37 + .../oboe/include/oboe/ResultWithValue.h | 155 + .../oboe/include/oboe/StabilizedCallback.h | 75 + .../native/oboe/include/oboe/Utilities.h | 87 + .../native/oboe/include/oboe/Version.h | 92 + .../juce_audio_devices/native/oboe/readme.md | 10 + .../native/oboe/src/aaudio/AAudioLoader.cpp | 348 + .../native/oboe/src/aaudio/AAudioLoader.h | 229 + .../oboe/src/aaudio/AudioStreamAAudio.cpp | 643 + .../oboe/src/aaudio/AudioStreamAAudio.h | 123 + .../native/oboe/src/common/AudioClock.h | 75 + .../oboe/src/common/AudioSourceCaller.cpp | 38 + .../oboe/src/common/AudioSourceCaller.h | 83 + .../native/oboe/src/common/AudioStream.cpp | 211 + .../oboe/src/common/AudioStreamBuilder.cpp | 201 + .../src/common/DataConversionFlowGraph.cpp | 215 + .../oboe/src/common/DataConversionFlowGraph.h | 84 + .../oboe/src/common/FilterAudioStream.cpp | 92 + .../oboe/src/common/FilterAudioStream.h | 214 + .../oboe/src/common/FixedBlockAdapter.cpp | 38 + .../oboe/src/common/FixedBlockAdapter.h | 67 + .../oboe/src/common/FixedBlockReader.cpp | 73 + .../native/oboe/src/common/FixedBlockReader.h | 60 + .../oboe/src/common/FixedBlockWriter.cpp | 73 + .../native/oboe/src/common/FixedBlockWriter.h | 54 + .../native/oboe/src/common/LatencyTuner.cpp | 102 + .../native/oboe/src/common/MonotonicCounter.h | 112 + .../native/oboe/src/common/OboeDebug.h | 41 + .../native/oboe/src/common/QuirksManager.cpp | 138 + .../native/oboe/src/common/QuirksManager.h | 110 + .../oboe/src/common/SourceFloatCaller.cpp | 30 + .../oboe/src/common/SourceFloatCaller.h | 44 + .../oboe/src/common/SourceI16Caller.cpp | 47 + .../native/oboe/src/common/SourceI16Caller.h | 48 + .../oboe/src/common/StabilizedCallback.cpp | 112 + .../native/oboe/src/common/Trace.cpp | 75 + .../native/oboe/src/common/Trace.h | 31 + .../native/oboe/src/common/Utilities.cpp | 305 + .../native/oboe/src/common/Version.cpp | 28 + .../native/oboe/src/fifo/FifoBuffer.cpp | 182 + .../native/oboe/src/fifo/FifoBuffer.h | 99 + .../native/oboe/src/fifo/FifoController.cpp | 31 + .../native/oboe/src/fifo/FifoController.h | 61 + .../oboe/src/fifo/FifoControllerBase.cpp | 71 + .../native/oboe/src/fifo/FifoControllerBase.h | 93 + .../oboe/src/fifo/FifoControllerIndirect.cpp | 31 + .../oboe/src/fifo/FifoControllerIndirect.h | 64 + .../native/oboe/src/flowgraph/ClipToRange.cpp | 38 + .../native/oboe/src/flowgraph/ClipToRange.h | 68 + .../oboe/src/flowgraph/FlowGraphNode.cpp | 111 + .../native/oboe/src/flowgraph/FlowGraphNode.h | 422 + .../src/flowgraph/ManyToMultiConverter.cpp | 47 + .../oboe/src/flowgraph/ManyToMultiConverter.h | 49 + .../src/flowgraph/MonoToMultiConverter.cpp | 43 + .../oboe/src/flowgraph/MonoToMultiConverter.h | 49 + .../native/oboe/src/flowgraph/RampLinear.cpp | 77 + .../native/oboe/src/flowgraph/RampLinear.h | 96 + .../src/flowgraph/SampleRateConverter.cpp | 64 + .../oboe/src/flowgraph/SampleRateConverter.h | 56 + .../native/oboe/src/flowgraph/SinkFloat.cpp | 50 + .../native/oboe/src/flowgraph/SinkFloat.h | 44 + .../native/oboe/src/flowgraph/SinkI16.cpp | 58 + .../native/oboe/src/flowgraph/SinkI16.h | 43 + .../native/oboe/src/flowgraph/SinkI24.cpp | 67 + .../native/oboe/src/flowgraph/SinkI24.h | 44 + .../native/oboe/src/flowgraph/SourceFloat.cpp | 43 + .../native/oboe/src/flowgraph/SourceFloat.h | 43 + .../native/oboe/src/flowgraph/SourceI16.cpp | 54 + .../native/oboe/src/flowgraph/SourceI16.h | 42 + .../native/oboe/src/flowgraph/SourceI24.cpp | 65 + .../native/oboe/src/flowgraph/SourceI24.h | 43 + .../resampler/HyperbolicCosineWindow.h | 68 + .../src/flowgraph/resampler/IntegerRatio.cpp | 50 + .../src/flowgraph/resampler/IntegerRatio.h | 52 + .../src/flowgraph/resampler/KaiserWindow.h | 87 + .../flowgraph/resampler/LinearResampler.cpp | 42 + .../src/flowgraph/resampler/LinearResampler.h | 44 + .../resampler/MultiChannelResampler.cpp | 171 + .../resampler/MultiChannelResampler.h | 271 + .../resampler/PolyphaseResampler.cpp | 61 + .../flowgraph/resampler/PolyphaseResampler.h | 51 + .../resampler/PolyphaseResamplerMono.cpp | 62 + .../resampler/PolyphaseResamplerMono.h | 39 + .../resampler/PolyphaseResamplerStereo.cpp | 78 + .../resampler/PolyphaseResamplerStereo.h | 39 + .../src/flowgraph/resampler/SincResampler.cpp | 76 + .../src/flowgraph/resampler/SincResampler.h | 47 + .../resampler/SincResamplerStereo.cpp | 80 + .../flowgraph/resampler/SincResamplerStereo.h | 39 + .../src/opensles/AudioInputStreamOpenSLES.cpp | 352 + .../src/opensles/AudioInputStreamOpenSLES.h | 65 + .../opensles/AudioOutputStreamOpenSLES.cpp | 448 + .../src/opensles/AudioOutputStreamOpenSLES.h | 77 + .../oboe/src/opensles/AudioStreamBuffered.cpp | 266 + .../oboe/src/opensles/AudioStreamBuffered.h | 92 + .../oboe/src/opensles/AudioStreamOpenSLES.cpp | 396 + .../oboe/src/opensles/AudioStreamOpenSLES.h | 132 + .../oboe/src/opensles/EngineOpenSLES.cpp | 101 + .../native/oboe/src/opensles/EngineOpenSLES.h | 65 + .../oboe/src/opensles/OpenSLESUtilities.cpp | 93 + .../oboe/src/opensles/OpenSLESUtilities.h | 44 + .../oboe/src/opensles/OutputMixerOpenSLES.cpp | 74 + .../oboe/src/opensles/OutputMixerOpenSLES.h | 58 + .../sources/juce_AudioSourcePlayer.cpp | 12 +- .../sources/juce_AudioSourcePlayer.h | 5 +- .../sources/juce_AudioTransportSource.cpp | 7 +- .../sources/juce_AudioTransportSource.h | 4 +- .../containers/juce_AbstractFifo.cpp | 7 +- .../juce_core/containers/juce_AbstractFifo.h | 2 +- .../modules/juce_core/containers/juce_Array.h | 59 +- .../containers/juce_ArrayAllocationBase.h | 2 +- .../juce_core/containers/juce_ArrayBase.cpp | 6 +- .../juce_core/containers/juce_ArrayBase.h | 36 +- .../containers/juce_DynamicObject.cpp | 2 +- .../juce_core/containers/juce_DynamicObject.h | 4 +- .../containers/juce_ElementComparator.h | 2 +- .../juce_core/containers/juce_HashMap.h | 6 +- .../containers/juce_HashMap_test.cpp | 6 +- .../containers/juce_LinkedListPointer.h | 2 +- .../juce_core/containers/juce_ListenerList.h | 2 +- .../containers/juce_NamedValueSet.cpp | 23 +- .../juce_core/containers/juce_NamedValueSet.h | 24 +- .../juce_core/containers/juce_OwnedArray.cpp | 68 +- .../juce_core/containers/juce_OwnedArray.h | 166 +- .../juce_core/containers/juce_PropertySet.cpp | 43 +- .../juce_core/containers/juce_PropertySet.h | 18 +- .../containers/juce_ReferenceCountedArray.cpp | 69 +- .../containers/juce_ReferenceCountedArray.h | 89 +- .../containers/juce_ScopedValueSetter.h | 2 +- .../juce_core/containers/juce_SortedSet.h | 35 +- .../juce_core/containers/juce_SparseSet.cpp | 6 +- .../juce_core/containers/juce_SparseSet.h | 2 +- .../juce_core/containers/juce_Variant.cpp | 8 +- .../juce_core/containers/juce_Variant.h | 9 +- .../files/juce_DirectoryIterator.cpp | 12 +- .../juce_core/files/juce_DirectoryIterator.h | 24 +- .../modules/juce_core/files/juce_File.cpp | 103 +- .../modules/juce_core/files/juce_File.h | 19 +- .../juce_core/files/juce_FileFilter.cpp | 2 +- .../modules/juce_core/files/juce_FileFilter.h | 2 +- .../juce_core/files/juce_FileInputStream.cpp | 111 +- .../juce_core/files/juce_FileInputStream.h | 2 +- .../juce_core/files/juce_FileOutputStream.cpp | 7 +- .../juce_core/files/juce_FileOutputStream.h | 2 +- .../juce_core/files/juce_FileSearchPath.cpp | 2 +- .../juce_core/files/juce_FileSearchPath.h | 2 +- .../juce_core/files/juce_MemoryMappedFile.h | 2 +- .../files/juce_RangedDirectoryIterator.cpp | 77 + .../files/juce_RangedDirectoryIterator.h | 181 + .../juce_core/files/juce_TemporaryFile.cpp | 2 +- .../juce_core/files/juce_TemporaryFile.h | 2 +- .../files/juce_WildcardFileFilter.cpp | 2 +- .../juce_core/files/juce_WildcardFileFilter.h | 4 +- .../juce_core/javascript/juce_JSON.cpp | 355 +- .../modules/juce_core/javascript/juce_JSON.h | 2 +- .../juce_core/javascript/juce_Javascript.cpp | 25 +- .../juce_core/javascript/juce_Javascript.h | 2 +- .../modules/juce_core/juce_core.cpp | 89 +- JuceLibraryCode/modules/juce_core/juce_core.h | 79 +- .../modules/juce_core/juce_core.mm | 2 +- .../juce_core/logging/juce_FileLogger.cpp | 2 +- .../juce_core/logging/juce_FileLogger.h | 4 +- .../modules/juce_core/logging/juce_Logger.cpp | 2 +- .../modules/juce_core/logging/juce_Logger.h | 2 +- .../juce_core/maths/juce_BigInteger.cpp | 15 +- .../modules/juce_core/maths/juce_BigInteger.h | 2 +- .../juce_core/maths/juce_Expression.cpp | 4 +- .../modules/juce_core/maths/juce_Expression.h | 2 +- .../juce_core/maths/juce_MathsFunctions.h | 134 +- .../juce_core/maths/juce_NormalisableRange.h | 55 +- .../modules/juce_core/maths/juce_Random.cpp | 14 +- .../modules/juce_core/maths/juce_Random.h | 2 +- .../modules/juce_core/maths/juce_Range.h | 52 +- .../maths/juce_StatisticsAccumulator.h | 2 +- .../juce_core/memory/juce_AllocationHooks.cpp | 104 + .../juce_core/memory/juce_AllocationHooks.h | 73 + .../modules/juce_core/memory/juce_Atomic.h | 2 +- .../modules/juce_core/memory/juce_ByteOrder.h | 62 +- .../memory/juce_ContainerDeletePolicy.h | 8 +- .../modules/juce_core/memory/juce_HeapBlock.h | 2 +- .../juce_HeavyweightLeakedObjectDetector.h | 14 +- .../memory/juce_LeakedObjectDetector.h | 4 +- .../modules/juce_core/memory/juce_Memory.h | 4 +- .../juce_core/memory/juce_MemoryBlock.cpp | 6 +- .../juce_core/memory/juce_MemoryBlock.h | 27 +- .../memory/juce_OptionalScopedPointer.h | 72 +- .../memory/juce_ReferenceCountedObject.h | 13 +- .../juce_core/memory/juce_ScopedPointer.h | 109 +- .../memory/juce_SharedResourcePointer.h | 8 +- .../modules/juce_core/memory/juce_Singleton.h | 2 +- .../juce_core/memory/juce_WeakReference.h | 9 +- .../misc/juce_ConsoleApplication.cpp | 181 +- .../juce_core/misc/juce_ConsoleApplication.h | 59 +- .../modules/juce_core/misc/juce_Result.cpp | 2 +- .../modules/juce_core/misc/juce_Result.h | 2 +- .../misc/juce_RuntimePermissions.cpp | 2 +- .../juce_core/misc/juce_RuntimePermissions.h | 2 +- .../juce_core/misc/juce_StdFunctionCompat.cpp | 282 - .../juce_core/misc/juce_StdFunctionCompat.h | 206 - .../modules/juce_core/misc/juce_Uuid.cpp | 2 +- .../modules/juce_core/misc/juce_Uuid.h | 2 +- .../juce_core/misc/juce_WindowsRegistry.h | 4 +- .../modules/juce_core/native/java/README.txt | 25 +- .../{roli => rmsl}/juce/FragmentOverlay.java | 24 +- .../{roli => rmsl}/juce/JuceHTTPStream.java | 24 +- .../com/rmsl/juce/JuceInvocationHandler.java | 60 + .../javacore/app/com/rmsl/juce/JuceApp.java | 37 + .../javacore/app/com/roli/juce/JuceApp.java | 15 - .../javacore/init/com/rmsl/juce/Java.java | 35 + .../javacore/init/com/roli/juce/Java.java | 13 - .../native/juce_BasicNativeHeaders.h | 22 +- .../juce_core/native/juce_android_Files.cpp | 19 +- .../native/juce_android_JNIHelpers.cpp | 202 +- .../native/juce_android_JNIHelpers.h | 97 +- .../juce_core/native/juce_android_Misc.cpp | 17 +- .../juce_core/native/juce_android_Network.cpp | 389 +- .../juce_android_RuntimePermissions.cpp | 6 +- .../native/juce_android_SystemStats.cpp | 8 +- .../juce_core/native/juce_android_Threads.cpp | 8 +- .../juce_core/native/juce_curl_Network.cpp | 4 +- .../native/juce_linux_CommonFile.cpp | 2 +- .../juce_core/native/juce_linux_Files.cpp | 8 +- .../juce_core/native/juce_linux_Network.cpp | 86 +- .../native/juce_linux_SystemStats.cpp | 52 +- .../juce_core/native/juce_linux_Threads.cpp | 12 +- .../native/juce_mac_ClangBugWorkaround.h | 14 +- .../juce_core/native/juce_mac_Files.mm | 25 +- .../juce_core/native/juce_mac_Network.mm | 43 +- .../juce_core/native/juce_mac_Strings.mm | 2 +- .../juce_core/native/juce_mac_SystemStats.mm | 27 +- .../juce_core/native/juce_mac_Threads.mm | 18 +- .../juce_core/native/juce_osx_ObjCHelpers.h | 62 +- .../juce_core/native/juce_posix_IPAddress.h | 2 +- .../juce_core/native/juce_posix_NamedPipe.cpp | 13 +- .../juce_core/native/juce_posix_SharedCode.h | 192 +- .../juce_core/native/juce_win32_ComSmartPtr.h | 6 +- .../juce_core/native/juce_win32_Files.cpp | 89 +- .../juce_core/native/juce_win32_Network.cpp | 66 +- .../juce_core/native/juce_win32_Registry.cpp | 34 +- .../native/juce_win32_SystemStats.cpp | 148 +- .../juce_core/native/juce_win32_Threads.cpp | 91 +- .../juce_core/network/juce_IPAddress.cpp | 17 +- .../juce_core/network/juce_IPAddress.h | 2 +- .../juce_core/network/juce_MACAddress.cpp | 2 +- .../juce_core/network/juce_MACAddress.h | 2 +- .../juce_core/network/juce_NamedPipe.cpp | 16 +- .../juce_core/network/juce_NamedPipe.h | 2 +- .../modules/juce_core/network/juce_Socket.cpp | 297 +- .../modules/juce_core/network/juce_Socket.h | 74 +- .../modules/juce_core/network/juce_URL.cpp | 202 +- .../modules/juce_core/network/juce_URL.h | 68 +- .../juce_core/network/juce_WebInputStream.cpp | 2 +- .../juce_core/network/juce_WebInputStream.h | 6 +- .../streams/juce_BufferedInputStream.cpp | 8 +- .../streams/juce_BufferedInputStream.h | 2 +- .../streams/juce_FileInputSource.cpp | 6 +- .../juce_core/streams/juce_FileInputSource.h | 2 +- .../juce_core/streams/juce_InputSource.h | 2 +- .../juce_core/streams/juce_InputStream.cpp | 22 +- .../juce_core/streams/juce_InputStream.h | 4 +- .../streams/juce_MemoryInputStream.cpp | 24 +- .../streams/juce_MemoryInputStream.h | 9 +- .../streams/juce_MemoryOutputStream.cpp | 2 +- .../streams/juce_MemoryOutputStream.h | 4 +- .../juce_core/streams/juce_OutputStream.cpp | 19 +- .../juce_core/streams/juce_OutputStream.h | 2 +- .../streams/juce_SubregionStream.cpp | 6 +- .../juce_core/streams/juce_SubregionStream.h | 2 +- .../juce_core/streams/juce_URLInputSource.cpp | 6 +- .../juce_core/streams/juce_URLInputSource.h | 2 +- .../juce_core/system/juce_CompilerSupport.h | 37 +- .../juce_core/system/juce_CompilerWarnings.h | 200 + .../juce_core/system/juce_PlatformDefs.h | 26 +- .../juce_core/system/juce_StandardHeader.h | 47 +- .../juce_core/system/juce_SystemStats.cpp | 12 +- .../juce_core/system/juce_SystemStats.h | 6 +- .../juce_core/system/juce_TargetPlatform.h | 21 +- .../modules/juce_core/text/juce_Base64.cpp | 6 +- .../modules/juce_core/text/juce_Base64.h | 2 +- .../juce_core/text/juce_CharPointer_ASCII.h | 4 +- .../juce_core/text/juce_CharPointer_UTF16.h | 2 +- .../juce_core/text/juce_CharPointer_UTF32.h | 4 +- .../juce_core/text/juce_CharPointer_UTF8.h | 34 +- .../text/juce_CharacterFunctions.cpp | 17 +- .../juce_core/text/juce_CharacterFunctions.h | 35 +- .../juce_core/text/juce_Identifier.cpp | 2 +- .../modules/juce_core/text/juce_Identifier.h | 2 +- .../juce_core/text/juce_LocalisedStrings.cpp | 2 +- .../juce_core/text/juce_LocalisedStrings.h | 4 +- .../modules/juce_core/text/juce_NewLine.h | 2 +- .../modules/juce_core/text/juce_String.cpp | 187 +- .../modules/juce_core/text/juce_String.h | 67 +- .../juce_core/text/juce_StringArray.cpp | 4 +- .../modules/juce_core/text/juce_StringArray.h | 17 +- .../juce_core/text/juce_StringPairArray.cpp | 4 +- .../juce_core/text/juce_StringPairArray.h | 2 +- .../juce_core/text/juce_StringPool.cpp | 2 +- .../modules/juce_core/text/juce_StringPool.h | 2 +- .../modules/juce_core/text/juce_StringRef.h | 18 +- .../modules/juce_core/text/juce_TextDiff.cpp | 7 +- .../modules/juce_core/text/juce_TextDiff.h | 2 +- .../juce_core/threads/juce_ChildProcess.cpp | 12 +- .../juce_core/threads/juce_ChildProcess.h | 2 +- .../juce_core/threads/juce_CriticalSection.h | 2 +- .../juce_core/threads/juce_DynamicLibrary.h | 2 +- .../threads/juce_HighResolutionTimer.cpp | 2 +- .../threads/juce_HighResolutionTimer.h | 2 +- .../juce_core/threads/juce_InterProcessLock.h | 2 +- .../modules/juce_core/threads/juce_Process.h | 4 +- .../juce_core/threads/juce_ReadWriteLock.cpp | 39 +- .../juce_core/threads/juce_ReadWriteLock.h | 4 +- .../juce_core/threads/juce_ScopedLock.h | 2 +- .../juce_core/threads/juce_ScopedReadLock.h | 2 +- .../juce_core/threads/juce_ScopedWriteLock.h | 2 +- .../modules/juce_core/threads/juce_SpinLock.h | 5 +- .../modules/juce_core/threads/juce_Thread.cpp | 16 +- .../modules/juce_core/threads/juce_Thread.h | 6 +- .../juce_core/threads/juce_ThreadLocalValue.h | 2 +- .../juce_core/threads/juce_ThreadPool.cpp | 3 +- .../juce_core/threads/juce_ThreadPool.h | 4 +- .../threads/juce_TimeSliceThread.cpp | 2 +- .../juce_core/threads/juce_TimeSliceThread.h | 4 +- .../juce_core/threads/juce_WaitableEvent.cpp | 70 + .../juce_core/threads/juce_WaitableEvent.h | 30 +- .../time/juce_PerformanceCounter.cpp | 9 +- .../juce_core/time/juce_PerformanceCounter.h | 2 +- .../juce_core/time/juce_RelativeTime.cpp | 129 +- .../juce_core/time/juce_RelativeTime.h | 9 +- .../modules/juce_core/time/juce_Time.cpp | 43 +- .../modules/juce_core/time/juce_Time.h | 2 +- .../juce_core/unit_tests/juce_UnitTest.cpp | 14 +- .../juce_core/unit_tests/juce_UnitTest.h | 19 +- .../unit_tests/juce_UnitTestCategories.h | 54 + .../juce_core/xml/juce_XmlDocument.cpp | 49 +- .../modules/juce_core/xml/juce_XmlDocument.h | 56 +- .../modules/juce_core/xml/juce_XmlElement.cpp | 257 +- .../modules/juce_core/xml/juce_XmlElement.h | 132 +- .../zip/juce_GZIPCompressorOutputStream.cpp | 10 +- .../zip/juce_GZIPCompressorOutputStream.h | 2 +- .../zip/juce_GZIPDecompressorInputStream.cpp | 45 +- .../zip/juce_GZIPDecompressorInputStream.h | 2 +- .../modules/juce_core/zip/juce_ZipFile.cpp | 38 +- .../modules/juce_core/zip/juce_ZipFile.h | 8 +- .../juce_ApplicationProperties.cpp | 11 +- .../juce_ApplicationProperties.h | 11 +- .../app_properties/juce_PropertiesFile.cpp | 62 +- .../app_properties/juce_PropertiesFile.h | 11 +- .../juce_data_structures.cpp | 11 +- .../juce_data_structures.h | 30 +- .../juce_data_structures.mm | 11 +- .../undomanager/juce_UndoManager.cpp | 13 +- .../undomanager/juce_UndoManager.h | 11 +- .../undomanager/juce_UndoableAction.h | 11 +- .../values/juce_CachedValue.cpp | 15 +- .../values/juce_CachedValue.h | 15 +- .../values/juce_Value.cpp | 11 +- .../juce_data_structures/values/juce_Value.h | 11 +- .../values/juce_ValueTree.cpp | 63 +- .../values/juce_ValueTree.h | 34 +- .../values/juce_ValueTreeSynchroniser.cpp | 16 +- .../values/juce_ValueTreeSynchroniser.h | 12 +- .../values/juce_ValueWithDefault.cpp | 15 +- .../values/juce_ValueWithDefault.h | 15 +- .../broadcasters/juce_ActionBroadcaster.cpp | 4 +- .../broadcasters/juce_ActionBroadcaster.h | 2 +- .../broadcasters/juce_ActionListener.h | 2 +- .../broadcasters/juce_AsyncUpdater.cpp | 2 +- .../broadcasters/juce_AsyncUpdater.h | 2 +- .../broadcasters/juce_ChangeBroadcaster.cpp | 7 +- .../broadcasters/juce_ChangeBroadcaster.h | 4 +- .../broadcasters/juce_ChangeListener.h | 9 +- .../juce_ConnectedChildProcess.cpp | 4 +- .../interprocess/juce_ConnectedChildProcess.h | 2 +- .../juce_InterprocessConnection.cpp | 4 +- .../juce_InterprocessConnection.h | 4 +- .../juce_InterprocessConnectionServer.cpp | 2 +- .../juce_InterprocessConnectionServer.h | 2 +- .../juce_NetworkServiceDiscovery.cpp | 34 +- .../juce_NetworkServiceDiscovery.h | 14 +- .../modules/juce_events/juce_events.cpp | 13 +- .../modules/juce_events/juce_events.h | 25 +- .../modules/juce_events/juce_events.mm | 2 +- .../messages/juce_ApplicationBase.cpp | 6 +- .../messages/juce_ApplicationBase.h | 13 +- .../messages/juce_CallbackMessage.h | 2 +- .../messages/juce_DeletedAtShutdown.cpp | 15 +- .../messages/juce_DeletedAtShutdown.h | 2 +- .../messages/juce_Initialisation.h | 2 +- .../juce_events/messages/juce_Message.h | 2 +- .../messages/juce_MessageListener.cpp | 4 +- .../messages/juce_MessageListener.h | 2 +- .../messages/juce_MessageManager.cpp | 24 +- .../messages/juce_MessageManager.h | 39 +- .../juce_MountedVolumeListChangeDetector.h | 2 +- .../messages/juce_NotificationType.h | 2 +- .../native/juce_android_Messaging.cpp | 10 +- .../native/juce_ios_MessageManager.mm | 2 +- .../juce_events/native/juce_linux_EventLoop.h | 47 +- .../native/juce_linux_Messaging.cpp | 278 +- .../native/juce_mac_MessageManager.mm | 21 +- .../native/juce_osx_MessageQueue.h | 2 +- .../native/juce_win32_HiddenMessageWindow.h | 11 +- .../native/juce_win32_Messaging.cpp | 297 +- .../native/juce_win32_WinRTWrapper.cpp | 2 +- .../native/juce_win32_WinRTWrapper.h | 3 +- .../juce_events/timers/juce_MultiTimer.cpp | 2 +- .../juce_events/timers/juce_MultiTimer.h | 2 +- .../modules/juce_events/timers/juce_Timer.cpp | 10 +- .../modules/juce_events/timers/juce_Timer.h | 2 +- JuceLibraryCode/modules/juce_osc/juce_osc.cpp | 11 +- JuceLibraryCode/modules/juce_osc/juce_osc.h | 30 +- .../modules/juce_osc/osc/juce_OSCAddress.cpp | 27 +- .../modules/juce_osc/osc/juce_OSCAddress.h | 13 +- .../modules/juce_osc/osc/juce_OSCArgument.cpp | 18 +- .../modules/juce_osc/osc/juce_OSCArgument.h | 11 +- .../modules/juce_osc/osc/juce_OSCBundle.cpp | 23 +- .../modules/juce_osc/osc/juce_OSCBundle.h | 23 +- .../modules/juce_osc/osc/juce_OSCMessage.cpp | 32 +- .../modules/juce_osc/osc/juce_OSCMessage.h | 25 +- .../modules/juce_osc/osc/juce_OSCReceiver.cpp | 31 +- .../modules/juce_osc/osc/juce_OSCReceiver.h | 11 +- .../modules/juce_osc/osc/juce_OSCSender.cpp | 25 +- .../modules/juce_osc/osc/juce_OSCSender.h | 11 +- .../modules/juce_osc/osc/juce_OSCTimeTag.cpp | 27 +- .../modules/juce_osc/osc/juce_OSCTimeTag.h | 13 +- .../modules/juce_osc/osc/juce_OSCTypes.cpp | 11 +- .../modules/juce_osc/osc/juce_OSCTypes.h | 11 +- Source/Main.cpp | 232 +- Source/MidiRPN.cpp | 121 + Source/MidiRPN.h | 116 + receivemidi.jucer | 8 +- 561 files changed, 34855 insertions(+), 7670 deletions(-) create mode 100644 Builds/MacOSX/receivemidi.entitlements delete mode 100644 JuceLibraryCode/modules/juce_audio_basics/utilities/juce_CatmullRomInterpolator.cpp delete mode 100644 JuceLibraryCode/modules/juce_audio_basics/utilities/juce_CatmullRomInterpolator.h create mode 100644 JuceLibraryCode/modules/juce_audio_basics/utilities/juce_GenericInterpolator.h create mode 100644 JuceLibraryCode/modules/juce_audio_basics/utilities/juce_Interpolators.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_basics/utilities/juce_Interpolators.h delete mode 100644 JuceLibraryCode/modules/juce_audio_basics/utilities/juce_LagrangeInterpolator.h create mode 100644 JuceLibraryCode/modules/juce_audio_basics/utilities/juce_WindowedSincInterpolator.cpp rename JuceLibraryCode/modules/juce_audio_devices/midi_io/{juce_MidiOutput.cpp => juce_MidiDevices.cpp} (81%) create mode 100644 JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiDevices.h delete mode 100644 JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiInput.h delete mode 100644 JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiOutput.h rename JuceLibraryCode/modules/juce_audio_devices/native/java/app/com/{roli => rmsl}/juce/JuceMidiSupport.java (91%) create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/juce_android_HighPerformanceAudioHelpers.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/CMakeLists.txt create mode 100755 JuceLibraryCode/modules/juce_audio_devices/native/oboe/LICENSE create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/AudioStream.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/AudioStreamBase.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/AudioStreamBuilder.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/AudioStreamCallback.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/Definitions.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/LatencyTuner.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/Oboe.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/ResultWithValue.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/StabilizedCallback.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/Utilities.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/Version.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/readme.md create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/aaudio/AAudioLoader.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/aaudio/AAudioLoader.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/aaudio/AudioStreamAAudio.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/aaudio/AudioStreamAAudio.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/AudioClock.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/AudioSourceCaller.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/AudioSourceCaller.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/AudioStream.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/AudioStreamBuilder.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/DataConversionFlowGraph.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/DataConversionFlowGraph.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FilterAudioStream.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FilterAudioStream.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockAdapter.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockAdapter.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockReader.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockReader.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockWriter.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockWriter.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/LatencyTuner.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/MonotonicCounter.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/OboeDebug.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/QuirksManager.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/QuirksManager.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/SourceFloatCaller.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/SourceFloatCaller.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/SourceI16Caller.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/SourceI16Caller.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/StabilizedCallback.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/Trace.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/Trace.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/Utilities.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/Version.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoBuffer.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoBuffer.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoController.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoController.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoControllerBase.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoControllerBase.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoControllerIndirect.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoControllerIndirect.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/ClipToRange.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/ClipToRange.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/FlowGraphNode.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/FlowGraphNode.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/ManyToMultiConverter.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/ManyToMultiConverter.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/MonoToMultiConverter.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/MonoToMultiConverter.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/RampLinear.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/RampLinear.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SampleRateConverter.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SampleRateConverter.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkFloat.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkFloat.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkI16.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkI16.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkI24.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkI24.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceFloat.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceFloat.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceI16.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceI16.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceI24.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceI24.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/HyperbolicCosineWindow.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/IntegerRatio.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/IntegerRatio.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/KaiserWindow.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/LinearResampler.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/LinearResampler.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/MultiChannelResampler.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/MultiChannelResampler.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResampler.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResampler.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResamplerMono.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResamplerMono.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResamplerStereo.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResamplerStereo.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/SincResampler.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/SincResampler.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/SincResamplerStereo.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/SincResamplerStereo.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioInputStreamOpenSLES.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioInputStreamOpenSLES.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioOutputStreamOpenSLES.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioOutputStreamOpenSLES.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioStreamBuffered.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioStreamBuffered.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioStreamOpenSLES.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioStreamOpenSLES.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/EngineOpenSLES.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/EngineOpenSLES.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/OpenSLESUtilities.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/OpenSLESUtilities.h create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/OutputMixerOpenSLES.cpp create mode 100644 JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/OutputMixerOpenSLES.h create mode 100644 JuceLibraryCode/modules/juce_core/files/juce_RangedDirectoryIterator.cpp create mode 100644 JuceLibraryCode/modules/juce_core/files/juce_RangedDirectoryIterator.h create mode 100644 JuceLibraryCode/modules/juce_core/memory/juce_AllocationHooks.cpp create mode 100644 JuceLibraryCode/modules/juce_core/memory/juce_AllocationHooks.h delete mode 100644 JuceLibraryCode/modules/juce_core/misc/juce_StdFunctionCompat.cpp delete mode 100644 JuceLibraryCode/modules/juce_core/misc/juce_StdFunctionCompat.h rename JuceLibraryCode/modules/juce_core/native/java/app/com/{roli => rmsl}/juce/FragmentOverlay.java (64%) rename JuceLibraryCode/modules/juce_core/native/java/app/com/{roli => rmsl}/juce/JuceHTTPStream.java (93%) create mode 100644 JuceLibraryCode/modules/juce_core/native/java/app/com/rmsl/juce/JuceInvocationHandler.java create mode 100644 JuceLibraryCode/modules/juce_core/native/javacore/app/com/rmsl/juce/JuceApp.java delete mode 100644 JuceLibraryCode/modules/juce_core/native/javacore/app/com/roli/juce/JuceApp.java create mode 100644 JuceLibraryCode/modules/juce_core/native/javacore/init/com/rmsl/juce/Java.java delete mode 100644 JuceLibraryCode/modules/juce_core/native/javacore/init/com/roli/juce/Java.java create mode 100644 JuceLibraryCode/modules/juce_core/system/juce_CompilerWarnings.h create mode 100644 JuceLibraryCode/modules/juce_core/threads/juce_WaitableEvent.cpp create mode 100644 JuceLibraryCode/modules/juce_core/unit_tests/juce_UnitTestCategories.h create mode 100644 Source/MidiRPN.cpp create mode 100644 Source/MidiRPN.h diff --git a/Builds/LinuxMakefile/Makefile b/Builds/LinuxMakefile/Makefile index d3d813e..5ebdaf0 100644 --- a/Builds/LinuxMakefile/Makefile +++ b/Builds/LinuxMakefile/Makefile @@ -32,16 +32,16 @@ ifeq ($(CONFIG),Debug) JUCE_OUTDIR := build ifeq ($(TARGET_ARCH),) - TARGET_ARCH := -march=native + TARGET_ARCH := endif - JUCE_CPPFLAGS := $(DEPFLAGS) -DLINUX=1 -DDEBUG=1 -D_DEBUG=1 -DJUCER_LINUX_MAKE_6D53C8B4=1 -DJUCE_APP_VERSION=1.1.0 -DJUCE_APP_VERSION_HEX=0x10100 $(shell pkg-config --cflags alsa libcurl) -pthread -I../../JuceLibraryCode -I../../JuceLibraryCode/modules $(CPPFLAGS) - JUCE_CPPFLAGS_CONSOLEAPP := -DJucePlugin_Build_VST=0 -DJucePlugin_Build_VST3=0 -DJucePlugin_Build_AU=0 -DJucePlugin_Build_AUv3=0 -DJucePlugin_Build_RTAS=0 -DJucePlugin_Build_AAX=0 -DJucePlugin_Build_Standalone=0 -DJucePlugin_Build_Unity=0 + JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DDEBUG=1" "-D_DEBUG=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.1.0" "-DJUCE_APP_VERSION_HEX=0x10100" $(shell pkg-config --cflags alsa) -pthread -I../../JuceLibraryCode -I../../JuceLibraryCode/modules $(CPPFLAGS) + JUCE_CPPFLAGS_CONSOLEAPP := "-DJucePlugin_Build_VST=0" "-DJucePlugin_Build_VST3=0" "-DJucePlugin_Build_AU=0" "-DJucePlugin_Build_AUv3=0" "-DJucePlugin_Build_RTAS=0" "-DJucePlugin_Build_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" JUCE_TARGET_CONSOLEAPP := receivemidi JUCE_CFLAGS += $(JUCE_CPPFLAGS) $(TARGET_ARCH) -g -ggdb -O0 $(CFLAGS) JUCE_CXXFLAGS += $(JUCE_CFLAGS) -std=c++14 $(CXXFLAGS) - JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell pkg-config --libs alsa libcurl) -ldl -lpthread -lrt $(LDFLAGS) + JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell pkg-config --libs alsa) -fvisibility=hidden -lrt -ldl -lpthread $(LDFLAGS) CLEANCMD = rm -rf $(JUCE_OUTDIR)/$(TARGET) $(JUCE_OBJDIR) endif @@ -56,19 +56,20 @@ ifeq ($(CONFIG),Release) TARGET_ARCH := endif - JUCE_CPPFLAGS := $(DEPFLAGS) -DLINUX=1 -DNDEBUG=1 -DJUCER_LINUX_MAKE_6D53C8B4=1 -DJUCE_APP_VERSION=1.1.0 -DJUCE_APP_VERSION_HEX=0x10100 $(shell pkg-config --cflags alsa libcurl) -pthread -I../../JuceLibraryCode -I../../JuceLibraryCode/modules $(CPPFLAGS) - JUCE_CPPFLAGS_CONSOLEAPP := -DJucePlugin_Build_VST=0 -DJucePlugin_Build_VST3=0 -DJucePlugin_Build_AU=0 -DJucePlugin_Build_AUv3=0 -DJucePlugin_Build_RTAS=0 -DJucePlugin_Build_AAX=0 -DJucePlugin_Build_Standalone=0 -DJucePlugin_Build_Unity=0 + JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DNDEBUG=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.1.0" "-DJUCE_APP_VERSION_HEX=0x10100" $(shell pkg-config --cflags alsa) -pthread -I../../JuceLibraryCode -I../../JuceLibraryCode/modules $(CPPFLAGS) + JUCE_CPPFLAGS_CONSOLEAPP := "-DJucePlugin_Build_VST=0" "-DJucePlugin_Build_VST3=0" "-DJucePlugin_Build_AU=0" "-DJucePlugin_Build_AUv3=0" "-DJucePlugin_Build_RTAS=0" "-DJucePlugin_Build_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" JUCE_TARGET_CONSOLEAPP := receivemidi JUCE_CFLAGS += $(JUCE_CPPFLAGS) $(TARGET_ARCH) -O3 $(CFLAGS) JUCE_CXXFLAGS += $(JUCE_CFLAGS) -std=c++14 $(CXXFLAGS) - JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell pkg-config --libs alsa libcurl) -fvisibility=hidden -ldl -lpthread -lrt $(LDFLAGS) + JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell pkg-config --libs alsa) -fvisibility=hidden -lrt -ldl -lpthread $(LDFLAGS) CLEANCMD = rm -rf $(JUCE_OUTDIR)/$(TARGET) $(JUCE_OBJDIR) endif OBJECTS_CONSOLEAPP := \ $(JUCE_OBJDIR)/Main_90ebc5c2.o \ + $(JUCE_OBJDIR)/MidiRPN_a0a26bf0.o \ $(JUCE_OBJDIR)/ScriptMidiMessageClass_6b9b1366.o \ $(JUCE_OBJDIR)/ScriptOscClass_a57c652d.o \ $(JUCE_OBJDIR)/ScriptUtilClass_492e64ec.o \ @@ -85,7 +86,7 @@ all : $(JUCE_OUTDIR)/$(JUCE_TARGET_CONSOLEAPP) $(JUCE_OUTDIR)/$(JUCE_TARGET_CONSOLEAPP) : $(OBJECTS_CONSOLEAPP) $(RESOURCES) @command -v pkg-config >/dev/null 2>&1 || { echo >&2 "pkg-config not installed. Please, install it."; exit 1; } - @pkg-config --print-errors alsa libcurl + @pkg-config --print-errors alsa @echo Linking "receivemidi - ConsoleApp" -$(V_AT)mkdir -p $(JUCE_BINDIR) -$(V_AT)mkdir -p $(JUCE_LIBDIR) @@ -97,6 +98,11 @@ $(JUCE_OBJDIR)/Main_90ebc5c2.o: ../../Source/Main.cpp @echo "Compiling Main.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" +$(JUCE_OBJDIR)/MidiRPN_a0a26bf0.o: ../../Source/MidiRPN.cpp + -$(V_AT)mkdir -p $(JUCE_OBJDIR) + @echo "Compiling MidiRPN.cpp" + $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" + $(JUCE_OBJDIR)/ScriptMidiMessageClass_6b9b1366.o: ../../Source/ScriptMidiMessageClass.cpp -$(V_AT)mkdir -p $(JUCE_OBJDIR) @echo "Compiling ScriptMidiMessageClass.cpp" diff --git a/Builds/MacOSX/receivemidi.entitlements b/Builds/MacOSX/receivemidi.entitlements new file mode 100644 index 0000000..6631ffa --- /dev/null +++ b/Builds/MacOSX/receivemidi.entitlements @@ -0,0 +1,6 @@ + + + + + + diff --git a/Builds/MacOSX/receivemidi.xcodeproj/project.pbxproj b/Builds/MacOSX/receivemidi.xcodeproj/project.pbxproj index e782e35..0a623db 100644 --- a/Builds/MacOSX/receivemidi.xcodeproj/project.pbxproj +++ b/Builds/MacOSX/receivemidi.xcodeproj/project.pbxproj @@ -41,6 +41,10 @@ isa = PBXBuildFile; fileRef = B2451D1DBA700503A8FEDC18; }; + 6EA0E7FEF85943B1DFF916B3 = { + isa = PBXBuildFile; + fileRef = 533259100534FB3D63540B5C; + }; 733F39336A3BA81575DD317E = { isa = PBXBuildFile; fileRef = 3973848B1FB155637755C9F9; @@ -126,6 +130,13 @@ path = "../../JuceLibraryCode/include_juce_osc.cpp"; sourceTree = "SOURCE_ROOT"; }; + 533259100534FB3D63540B5C = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = MidiRPN.cpp; + path = ../../Source/MidiRPN.cpp; + sourceTree = "SOURCE_ROOT"; + }; 5D3F4C219DB9D465708B6231 = { isa = PBXFileReference; lastKnownFileType = wrapper.framework; @@ -182,6 +193,13 @@ path = receivemidi; sourceTree = "BUILT_PRODUCTS_DIR"; }; + 97C0FA3EF81821C75C9D8CFD = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = MidiRPN.h; + path = ../../Source/MidiRPN.h; + sourceTree = "SOURCE_ROOT"; + }; 9CD2954B59A33B0796DD0778 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; @@ -284,6 +302,8 @@ isa = PBXGroup; children = ( B2451D1DBA700503A8FEDC18, + 533259100534FB3D63540B5C, + 97C0FA3EF81821C75C9D8CFD, 3973848B1FB155637755C9F9, C70C6063AC097C5848BB449E, 7113DF850C738FF287669BA9, @@ -378,6 +398,7 @@ CLANG_CXX_LANGUAGE_STANDARD = "c++14"; 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; @@ -405,7 +426,7 @@ "$(inherited)", ); INSTALL_PATH = "/usr/bin"; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_BUNDLE_IDENTIFIER = com.uwyn.receivemidi; PRODUCT_NAME = "receivemidi"; USE_HEADERMAP = NO; @@ -418,6 +439,7 @@ CLANG_CXX_LANGUAGE_STANDARD = "c++14"; 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; @@ -438,7 +460,6 @@ "JucePlugin_Build_Standalone=0", "JucePlugin_Build_Unity=0", ); - GCC_SYMBOLS_PRIVATE_EXTERN = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ( "../../JuceLibraryCode", @@ -447,7 +468,7 @@ ); INSTALL_PATH = "/usr/bin"; LLVM_LTO = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_BUNDLE_IDENTIFIER = com.uwyn.receivemidi; PRODUCT_NAME = "receivemidi"; USE_HEADERMAP = NO; @@ -476,13 +497,15 @@ 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 = 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; @@ -495,6 +518,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "receivemidi"; + SDKROOT = macosx; WARNING_CFLAGS = "-Wreorder"; ZERO_LINK = NO; }; @@ -522,12 +546,15 @@ 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; @@ -539,15 +566,12 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; PRODUCT_NAME = "receivemidi"; + SDKROOT = macosx; WARNING_CFLAGS = "-Wreorder"; ZERO_LINK = NO; }; name = Release; }; - 051CE20F6F4544DC5B59EC97 = { - isa = PBXTargetDependency; - target = DBA0A682EFBA8D17289648F9; - }; 9B7F79ECBA6BB3FD7D9F4A1B = { isa = XCConfigurationList; buildConfigurations = ( @@ -579,6 +603,7 @@ buildActionMask = 2147483647; files = ( 2BA07F2CF2B004870E08CD28, + 6EA0E7FEF85943B1DFF916B3, 733F39336A3BA81575DD317E, 39B2279B8530BBC87FA033F9, 141F7CB00D1F92A017A030DD, @@ -622,7 +647,7 @@ 6323F87A9BE44E1C4257AD90 = { isa = PBXProject; buildConfigurationList = 9B7F79ECBA6BB3FD7D9F4A1B; - attributes = { LastUpgradeCheck = 0930; ORGANIZATIONNAME = "Uwyn"; }; + attributes = { LastUpgradeCheck = 1100; ORGANIZATIONNAME = "Uwyn"; }; compatibilityVersion = "Xcode 3.2"; hasScannedForEncodings = 0; mainGroup = CA1CE00FEEC53FB42E8CDD06; diff --git a/Builds/VisualStudio2015/receivemidi_ConsoleApp.vcxproj b/Builds/VisualStudio2015/receivemidi_ConsoleApp.vcxproj index 9ac184a..ece219c 100644 --- a/Builds/VisualStudio2015/receivemidi_ConsoleApp.vcxproj +++ b/Builds/VisualStudio2015/receivemidi_ConsoleApp.vcxproj @@ -141,6 +141,7 @@ + @@ -234,12 +235,18 @@ true + + true + true true + + true + true @@ -252,12 +259,162 @@ 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 @@ -360,6 +517,9 @@ true + + true + true @@ -387,6 +547,9 @@ true + + true + true @@ -552,6 +715,9 @@ true + + true + true @@ -731,6 +897,7 @@ + @@ -770,25 +937,86 @@ + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - @@ -813,6 +1041,7 @@ + @@ -826,6 +1055,7 @@ + @@ -869,6 +1099,7 @@ + @@ -908,6 +1139,7 @@ + @@ -925,7 +1157,6 @@ - @@ -936,7 +1167,6 @@ - @@ -962,7 +1192,6 @@ - @@ -972,11 +1201,12 @@ - + + diff --git a/Builds/VisualStudio2015/receivemidi_ConsoleApp.vcxproj.filters b/Builds/VisualStudio2015/receivemidi_ConsoleApp.vcxproj.filters index 8382fce..29bba6c 100644 --- a/Builds/VisualStudio2015/receivemidi_ConsoleApp.vcxproj.filters +++ b/Builds/VisualStudio2015/receivemidi_ConsoleApp.vcxproj.filters @@ -41,6 +41,36 @@ {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} @@ -157,6 +187,9 @@ receivemidi\Source + + receivemidi\Source + receivemidi\Source @@ -256,12 +289,18 @@ 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 @@ -277,12 +316,162 @@ JUCE Modules\juce_audio_devices\audio_io + + 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\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\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\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 @@ -388,6 +577,9 @@ JUCE Modules\juce_core\files + + JUCE Modules\juce_core\files + JUCE Modules\juce_core\files @@ -415,6 +607,9 @@ JUCE Modules\juce_core\maths + + JUCE Modules\juce_core\memory + JUCE Modules\juce_core\memory @@ -595,6 +790,9 @@ JUCE Modules\juce_core\threads + + JUCE Modules\juce_core\threads + JUCE Modules\juce_core\time @@ -801,6 +999,9 @@ + + receivemidi\Source + receivemidi\Source @@ -918,9 +1119,15 @@ 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 @@ -933,9 +1140,6 @@ JUCE Modules\juce_audio_basics - - JUCE Modules\juce_audio_basics - JUCE Modules\juce_audio_devices\audio_io @@ -948,6 +1152,9 @@ JUCE Modules\juce_audio_devices\audio_io + + JUCE Modules\juce_audio_devices\midi_io + JUCE Modules\juce_audio_devices\midi_io @@ -957,6 +1164,186 @@ 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\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\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 @@ -972,9 +1359,6 @@ JUCE Modules\juce_audio_devices - - JUCE Modules\juce_audio_devices - JUCE Modules\juce_core\containers @@ -1047,6 +1431,9 @@ JUCE Modules\juce_core\files + + JUCE Modules\juce_core\files + JUCE Modules\juce_core\files @@ -1086,6 +1473,9 @@ JUCE Modules\juce_core\maths + + JUCE Modules\juce_core\memory + JUCE Modules\juce_core\memory @@ -1215,6 +1605,9 @@ JUCE Modules\juce_core\system + + JUCE Modules\juce_core\system + JUCE Modules\juce_core\system @@ -1332,6 +1725,9 @@ JUCE Modules\juce_core\unit_tests + + JUCE Modules\juce_core\unit_tests + JUCE Modules\juce_core\xml @@ -1383,9 +1779,6 @@ JUCE Modules\juce_core - - JUCE Modules\juce_core - JUCE Modules\juce_data_structures\app_properties @@ -1416,9 +1809,6 @@ JUCE Modules\juce_data_structures - - JUCE Modules\juce_data_structures - JUCE Modules\juce_events\broadcasters @@ -1494,9 +1884,6 @@ JUCE Modules\juce_events - - JUCE Modules\juce_events - JUCE Modules\juce_osc\osc @@ -1524,9 +1911,6 @@ JUCE Modules\juce_osc - - JUCE Modules\juce_osc - JUCE Library Code @@ -1535,6 +1919,12 @@ + + JUCE Modules\juce_audio_devices\native\oboe + + + JUCE Modules\juce_audio_devices\native\oboe + JUCE Modules\juce_core\native\java diff --git a/Builds/VisualStudio2015/resources.rc b/Builds/VisualStudio2015/resources.rc index 2b24994..f923b8b 100644 --- a/Builds/VisualStudio2015/resources.rc +++ b/Builds/VisualStudio2015/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 f6888ac..aa93314 100644 --- a/JuceLibraryCode/AppConfig.h +++ b/JuceLibraryCode/AppConfig.h @@ -21,12 +21,12 @@ /* ============================================================================== - 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 ============================================================================== */ @@ -37,14 +37,12 @@ #define JUCE_DISPLAY_SPLASH_SCREEN 1 #endif -#ifndef JUCE_REPORT_APP_USAGE - #define JUCE_REPORT_APP_USAGE 1 -#endif - // END SECTION A #define JUCE_USE_DARK_SPLASH_SCREEN 1 +#define JUCE_PROJUCER_VERSION 0x60001 + //============================================================================== #define JUCE_MODULE_AVAILABLE_juce_audio_basics 1 #define JUCE_MODULE_AVAILABLE_juce_audio_devices 1 @@ -91,7 +89,11 @@ #endif #ifndef JUCE_USE_ANDROID_OBOE - //#define JUCE_USE_ANDROID_OBOE 0 + //#define JUCE_USE_ANDROID_OBOE 1 +#endif + +#ifndef JUCE_USE_OBOE_STABILIZED_CALLBACK + //#define JUCE_USE_OBOE_STABILIZED_CALLBACK 0 #endif #ifndef JUCE_USE_ANDROID_OPENSLES @@ -134,22 +136,26 @@ #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 + //============================================================================== // 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 //============================================================================== diff --git a/JuceLibraryCode/JuceHeader.h b/JuceLibraryCode/JuceHeader.h index 7d982b8..6517389 100644 --- a/JuceLibraryCode/JuceHeader.h +++ b/JuceLibraryCode/JuceHeader.h @@ -22,6 +22,15 @@ #include +#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 from the AppConfig.h file. + */ + #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. 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 25ebba1..13d6082 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. diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp index 766e112..157da8a 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. @@ -87,15 +87,38 @@ String AudioChannelSet::getChannelTypeName (AudioChannelSet::ChannelType type) 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: return NEEDS_TRANS("Discrete channel"); + case discreteChannel0: + case unknown: default: break; } @@ -148,16 +171,40 @@ String AudioChannelSet::getAbbreviatedChannelTypeName (AudioChannelSet::ChannelT 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; } @@ -216,6 +263,26 @@ AudioChannelSet::ChannelType AudioChannelSet::getChannelTypeFromAbbreviation (co 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; @@ -557,12 +624,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 { @@ -645,6 +717,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 9d0f99e..9392c98 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. @@ -369,7 +369,7 @@ class JUCE_API AudioChannelSet bottomFrontCentre = 63, /**< Bottom Front Centre (Bfc) */ bottomFrontRight = 64, /**< Bottom Front Right (Bfr) */ - proxymityLeft = 65, /**< Proximity Left (Pl) */ + proximityLeft = 65, /**< Proximity Left (Pl) */ proximityRight = 66, /**< Proximity Right (Pr) */ bottomSideLeft = 67, /**< Bottom Side Left (Bsl) */ diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp index c8052d5..dfc4e1c 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. @@ -319,7 +319,7 @@ void AudioDataConverters::convertInt32LEToFloat (const void* source, float* dest { for (int i = 0; i < numSamples; ++i) { - dest[i] = scale * (int) ByteOrder::swapIfBigEndian (*reinterpret_cast (intData)); + dest[i] = scale * (float) ByteOrder::swapIfBigEndian (*reinterpret_cast (intData)); intData += srcBytesPerSample; } } @@ -330,7 +330,7 @@ void AudioDataConverters::convertInt32LEToFloat (const void* source, float* dest for (int i = numSamples; --i >= 0;) { intData -= srcBytesPerSample; - dest[i] = scale * (int) ByteOrder::swapIfBigEndian (*reinterpret_cast (intData)); + dest[i] = scale * (float) ByteOrder::swapIfBigEndian (*reinterpret_cast (intData)); } } } @@ -344,7 +344,7 @@ void AudioDataConverters::convertInt32BEToFloat (const void* source, float* dest { for (int i = 0; i < numSamples; ++i) { - dest[i] = scale * (int) ByteOrder::swapIfLittleEndian (*reinterpret_cast (intData)); + dest[i] = scale * (float) ByteOrder::swapIfLittleEndian (*reinterpret_cast (intData)); intData += srcBytesPerSample; } } @@ -355,7 +355,7 @@ void AudioDataConverters::convertInt32BEToFloat (const void* source, float* dest for (int i = numSamples; --i >= 0;) { intData -= srcBytesPerSample; - dest[i] = scale * (int) ByteOrder::swapIfLittleEndian (*reinterpret_cast (intData)); + dest[i] = scale * (float) ByteOrder::swapIfLittleEndian (*reinterpret_cast (intData)); } } } @@ -460,13 +460,16 @@ void AudioDataConverters::deinterleaveSamples (const float* source, float** dest } +//============================================================================== //============================================================================== #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 @@ -480,7 +483,9 @@ class AudioConversionTests : public UnitTest 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); diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h index 4ddca07..ddcaa79 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()); } @@ -284,7 +284,7 @@ class JUCE_API AudioData 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 }; }; @@ -309,7 +309,7 @@ class JUCE_API AudioData { public: using VoidType = void; - static inline void* toVoidPtr (VoidType* v) noexcept { return v; } + static void* toVoidPtr (VoidType* v) noexcept { return v; } enum { isConst = 0 }; }; @@ -317,7 +317,7 @@ class JUCE_API AudioData { public: using VoidType = const void; - static inline void* toVoidPtr (VoidType* v) noexcept { return const_cast (v); } + 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 */ diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.cpp b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.cpp index 1e6c91f..05f3045 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.cpp @@ -2,20 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). + 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 diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.h b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.h index 1814e96..d6c729e 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.h +++ b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.h @@ -2,20 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). + 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 @@ -31,6 +27,8 @@ 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 { @@ -68,6 +66,8 @@ class JUCE_API AudioProcessLoadMeasurer myCallback->doTheCallback(); } @endcode + + @tags{Audio} */ struct JUCE_API ScopedTimer { diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h index 2aa19a5..9b501e6 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) @@ -180,7 +227,7 @@ class AudioBuffer size (other.size), allocatedBytes (other.allocatedBytes), allocatedData (std::move (other.allocatedData)), - isClear (other.isClear) + isClear (other.isClear.load()) { if (numChannels < (int) numElementsInArray (preallocatedChannelSpace)) { @@ -206,7 +253,7 @@ class AudioBuffer size = other.size; allocatedBytes = other.allocatedBytes; allocatedData = std::move (other.allocatedData); - isClear = other.isClear; + isClear = other.isClear.load(); if (numChannels < (int) numElementsInArray (preallocatedChannelSpace)) { @@ -340,7 +387,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; @@ -1071,12 +1118,23 @@ class AudioBuffer Type** channels; HeapBlock allocatedData; Type* preallocatedChannelSpace[32]; - bool isClear = false; + std::atomic isClear { false }; void allocateData() { + #if ! JUCE_PROJUCER_LIVE_BUILD && (! 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()); diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp index ec0afca..cca0d26 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,7 +30,7 @@ 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; } @@ -1139,6 +1139,7 @@ ScopedNoDenormals::~ScopedNoDenormals() noexcept #endif } + //============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -1146,7 +1147,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 b43c820..c0bb4e4 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. diff --git a/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.cpp b/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.cpp index 74cfe45..1c60327 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. @@ -59,7 +59,8 @@ #include "buffers/juce_AudioProcessLoadMeasurer.cpp" #include "utilities/juce_IIRFilter.cpp" #include "utilities/juce_LagrangeInterpolator.cpp" -#include "utilities/juce_CatmullRomInterpolator.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" diff --git a/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.h b/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.h index 0f09d2f..8ca25ea 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,27 @@ ============================================================================== */ + /******************************************************************************* 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.4.3 - 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.0.1 + 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 - dependencies: juce_core - OSXFrameworks: Accelerate - iOSFrameworks: Accelerate + dependencies: juce_core + OSXFrameworks: Accelerate + iOSFrameworks: Accelerate END_JUCE_MODULE_DECLARATION @@ -87,8 +88,8 @@ #include "buffers/juce_AudioProcessLoadMeasurer.h" #include "utilities/juce_Decibels.h" #include "utilities/juce_IIRFilter.h" -#include "utilities/juce_LagrangeInterpolator.h" -#include "utilities/juce_CatmullRomInterpolator.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" diff --git a/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.mm b/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.mm index c52bbb3..eaf23ed 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 803b126..6100741 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,58 +25,53 @@ 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) + + if (byte == 0xff) { if (maxBytes == 1) - { - size = 1; - } - else - { - int n; - const int bytesLeft = MidiMessage::readVariableLengthVal (data + 1, n); - size = jmin (maxBytes, n + 2 + bytesLeft); - } - } - else if (byte >= 0x80) - { - size = jmin (maxBytes, MidiMessage::getMessageLengthFromFirstByte ((uint8) byte)); + return 1; + + int n; + auto bytesLeft = MidiMessage::readVariableLengthVal (data + 1, n); + return jmin (maxBytes, n + 2 + bytesLeft); } - 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); @@ -86,17 +81,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); @@ -107,61 +112,59 @@ 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())); } -void MidiBuffer::addEvent (const MidiMessage& m, const int sampleNumber) +void MidiBuffer::addEvent (const MidiMessage& m, int sampleNumber) { addEvent (m.getRawData(), m.getRawDataSize(), sampleNumber); } -void MidiBuffer::addEvent (const void* const newData, const int maxBytes, const int sampleNumber) +void 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) { - const size_t newItemSize = (size_t) numBytes + sizeof (int32) + sizeof (uint16); - const int offset = (int) (MidiBufferHelpers::findEventAfter (data.begin(), data.end(), sampleNumber) - data.begin()); + auto newItemSize = (size_t) numBytes + sizeof (int32) + sizeof (uint16); + auto offset = (int) (MidiBufferHelpers::findEventAfter (data.begin(), data.end(), sampleNumber) - data.begin()); data.insertMultiple (offset, 0, (int) newItemSize); - uint8* const d = data.begin() + offset; + auto* d = data.begin() + offset; writeUnaligned (d, sampleNumber); - writeUnaligned (d + 4, static_cast (numBytes)); - memcpy (d + 6, newData, (size_t) numBytes); + d += sizeof (int32); + writeUnaligned (d, static_cast (numBytes)); + d += sizeof (uint16); + memcpy (d, newData, (size_t) numBytes); } } 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; @@ -177,11 +180,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); @@ -190,47 +193,47 @@ int MidiBuffer::getLastEventTime() const noexcept } } +MidiBufferIterator MidiBuffer::findNextSamplePosition (int samplePosition) const noexcept +{ + return std::find_if (cbegin(), cend(), [&] (const MidiMessageMetadata& metadata) noexcept + { + return metadata.samplePosition >= samplePosition; + }); +} + //============================================================================== MidiBuffer::Iterator::Iterator (const MidiBuffer& b) noexcept - : buffer (b), data (b.data.begin()) + : buffer (b), iterator (b.data.begin()) { } -MidiBuffer::Iterator::~Iterator() noexcept{} +MidiBuffer::Iterator::~Iterator() noexcept {} -void MidiBuffer::Iterator::setNextSamplePosition (const int samplePosition) noexcept +void MidiBuffer::Iterator::setNextSamplePosition (int samplePosition) noexcept { - data = buffer.data.begin(); - const uint8* const dataEnd = buffer.data.end(); - - while (data < dataEnd && MidiBufferHelpers::getEventTime (data) < samplePosition) - data += MidiBufferHelpers::getEventTotalSize (data); + 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; } diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiBuffer.h b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiBuffer.h index b478ade..01d4f69 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,7 +184,7 @@ 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 */ void addEvent (const MidiMessage& midiMessage, int sampleNumber); @@ -109,7 +202,7 @@ 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 */ void addEvent (const void* rawMidiData, int maxBytesOfMidiData, @@ -158,6 +251,23 @@ 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; + //============================================================================== /** Used to iterate through the events in a MidiBuffer. @@ -171,15 +281,14 @@ class JUCE_API MidiBuffer { public: //============================================================================== - /** Creates an Iterator for this MidiBuffer. */ - Iterator (const MidiBuffer&) noexcept; + /** Creates an Iterator for this MidiBuffer. + This class has been deprecated in favour of MidiBufferIterator. + */ + JUCE_DEPRECATED (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; @@ -221,7 +330,7 @@ class JUCE_API MidiBuffer private: //============================================================================== const MidiBuffer& buffer; - const uint8* data; + MidiBufferIterator iterator; }; /** The raw data holding this buffer. diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiFile.cpp b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiFile.cpp index 1c21b12..30c75b9 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. @@ -262,25 +262,26 @@ bool MidiFile::readFrom (InputStream& sourceStream, bool createMatchingNoteOffs) if (size > 16 && MidiFileHelpers::parseMidiHeader (d, timeFormat, fileType, expectedTracks)) { size -= (size_t) (d - static_cast (data.getData())); - int track = 0; - while (size > 0 && track < expectedTracks) + for (;;) { auto chunkType = (int) ByteOrder::bigEndianInt (d); d += 4; auto chunkSize = (int) ByteOrder::bigEndianInt (d); d += 4; - if (chunkSize <= 0) + if (chunkSize <= 0 || (size_t) chunkSize > size) break; if (chunkType == (int) ByteOrder::bigEndianInt ("MTrk")) readNextTrack (d, chunkSize, createMatchingNoteOffs); + if (++track >= expectedTracks) + break; + size -= (size_t) chunkSize + 8; d += chunkSize; - ++track; } return true; diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiFile.h b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiFile.h index 323523e..f964e42 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. diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiKeyboardState.cpp b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiKeyboardState.cpp index 6c5a3df..2c9f6fb 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. @@ -75,10 +75,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 +98,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 +141,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 +162,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 99f6ffd..64665a7 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() = default; - virtual ~MidiKeyboardStateListener() = 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; -}; - - //============================================================================== /** 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. @@ -135,7 +90,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 +135,62 @@ class JUCE_API MidiKeyboardState bool injectIndirectEvents); //============================================================================== + /** Receives events from a MidiKeyboardState object. */ + class 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 89de06a..5b78b6c 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. diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.h b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.h index c0fc47a..87b2efb 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. diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp index 1c7eb7d..5a14806 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. @@ -87,8 +87,10 @@ 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 { @@ -344,11 +346,16 @@ void MidiMessageSequence::createControllerUpdatesForTime (int channelNumber, dou } } + +//============================================================================== +//============================================================================== #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 { @@ -371,7 +378,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); diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.h b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.h index 5992acb..6cef1e7 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. @@ -103,10 +103,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** end() const noexcept; + MidiEventHolder* const* begin() const noexcept; + + /** Iterator for the list of MidiEventHolders */ + MidiEventHolder** end() noexcept; + + /** Iterator for the list of MidiEventHolders */ + 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. diff --git a/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiRPN.cpp b/JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiRPN.cpp index 820103f..46fa007 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. @@ -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 eb85435..d6f1731 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/mpe/juce_MPEInstrument.cpp b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEInstrument.cpp index af508d8..796007e 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. @@ -151,6 +151,7 @@ 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); } //============================================================================== @@ -241,7 +242,7 @@ void MPEInstrument::processMidiResetAllControllersMessage (const MidiMessage& me { 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 +253,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 +294,7 @@ void MPEInstrument::noteOn (int midiChannel, int midiNoteNumber, MPEValue midiNoteOnVelocity) { - if (! isMemberChannel (midiChannel)) + if (! isUsingChannel (midiChannel)) return; MPENote newNote (midiChannel, @@ -316,7 +326,7 @@ void MPEInstrument::noteOff (int midiChannel, int midiNoteNumber, MPEValue midiNoteOffVelocity) { - if (notes.isEmpty() || ! isMemberChannel (midiChannel)) + if (notes.isEmpty() || ! isUsingChannel (midiChannel)) return; const ScopedLock sl (lock); @@ -326,11 +336,13 @@ void MPEInstrument::noteOff (int midiChannel, 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 +375,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 (auto 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]; @@ -416,7 +446,7 @@ void MPEInstrument::updateDimensionMaster (bool isLowerZone, MPEDimension& dimen { auto& note = notes.getReference (i); - if (! zone.isUsingChannelAsMemberChannel (note.midiChannel)) + if (! zone.isUsing (note.midiChannel)) continue; if (&dimension == &pitchbendDimension) @@ -461,17 +491,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 +513,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; } @@ -520,7 +555,7 @@ void MPEInstrument::handleSustainOrSostenuto (int midiChannel, bool isDown, bool { 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,11 +578,9 @@ 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) @@ -560,7 +593,7 @@ void MPEInstrument::handleSustainOrSostenuto (int midiChannel, bool isDown, bool } //============================================================================== -bool MPEInstrument::isMemberChannel (int midiChannel) noexcept +bool MPEInstrument::isMemberChannel (int midiChannel) const noexcept { if (legacyMode.isEnabled) return legacyMode.channelRange.contains (midiChannel); @@ -574,8 +607,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 { @@ -679,7 +726,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 +752,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 +791,7 @@ void MPEInstrument::releaseAllNotes() notes.clear(); } + //============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -752,7 +800,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 // @@ -798,12 +846,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 +862,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 +894,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 +1245,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 +1834,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()); @@ -2142,6 +2212,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, @@ -2207,6 +2283,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 6e675cc..6572754 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: @@ -90,7 +90,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 +99,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 +185,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 @@ -246,12 +261,12 @@ class JUCE_API MPEInstrument /** 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,12 +275,12 @@ 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 @@ -274,14 +289,14 @@ class JUCE_API MPEInstrument 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); } }; //============================================================================== @@ -373,6 +388,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 2e3ab94..cda2250 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 21f8998..99b63cf 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. @@ -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 4954a89..1d7c32e 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 0f27351..67495b7 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. diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiser.cpp b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiser.cpp index f1ac277..35241c8 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. @@ -299,10 +299,14 @@ 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->noteStopped (allowTailOff); + } // finally make sure the MPE Instrument also doesn't have any notes anymore. instrument->releaseAllNotes(); @@ -311,6 +315,8 @@ void MPESynthesiser::turnOffAllVoices (bool allowTailOff) //============================================================================== void MPESynthesiser::renderNextSubBlock (AudioBuffer& buffer, int startSample, int numSamples) { + const ScopedLock sl (voicesLock); + for (auto* voice : voices) { if (voice->isActive()) @@ -320,6 +326,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 d091969..652dd7f 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. @@ -69,7 +69,7 @@ class JUCE_API MPESynthesiser : public MPESynthesiserBase @see MPESynthesiserBase, MPEInstrument */ - MPESynthesiser (MPEInstrument* instrument); + MPESynthesiser (MPEInstrument* instrumentToUse); /** Destructor. */ ~MPESynthesiser() override; @@ -247,7 +247,7 @@ class JUCE_API MPESynthesiser : public MPESynthesiserBase 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. */ void renderNextSubBlock (AudioBuffer& outputAudio, diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserBase.cpp b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserBase.cpp index 0a61dfc..e00bf7b 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. @@ -110,48 +110,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: @@ -177,4 +161,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 fc6723c..a7978db 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. @@ -88,9 +88,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, diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserVoice.cpp b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserVoice.cpp index 54fc02b..a7b6e22 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. diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserVoice.h b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPESynthesiserVoice.h index 93b8975..15bcb72 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. diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEUtils.cpp b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEUtils.cpp index 265bbd6..7e8194f 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,7 +49,7 @@ 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) @@ -84,15 +84,29 @@ int MPEChannelAssigner::findMidiChannelForNewNote (int noteNumber) noexcept return midiChannelLastAssigned; } -void MPEChannelAssigner::noteOff (int noteNumber) +void MPEChannelAssigner::noteOff (int noteNumber, int midiChannel) { - for (auto& ch : midiChannels) + const auto removeNote = [] (MidiChannel& ch, int noteNum) { - if (ch.notes.removeAllInstancesOf (noteNumber) > 0) + if (ch.notes.removeAllInstancesOf (noteNum) > 0) { - ch.lastNotePlayed = noteNumber; - return; + ch.lastNotePlayed = noteNum; + return true; } + + return false; + }; + + if (midiChannel >= 0 && midiChannel < 17) + { + removeNote (midiChannels[midiChannel], noteNumber); + return; + } + + for (auto& ch : midiChannels) + { + if (removeNote (ch, noteNumber)) + return; } } @@ -255,6 +269,7 @@ void MPEChannelRemapper::zeroArrays() } } + //============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -262,7 +277,7 @@ void MPEChannelRemapper::zeroArrays() struct MPEUtilsUnitTests : public UnitTest { MPEUtilsUnitTests() - : UnitTest ("MPE Utilities", "MIDI/MPE") + : UnitTest ("MPE Utilities", UnitTestCategories::midi) {} void runTest() override @@ -475,4 +490,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 e006db8..6fcdafe 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. @@ -65,8 +65,11 @@ class MPEChannelAssigner /** 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(); diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEValue.cpp b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEValue.cpp index 282e00a..622dc89 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. @@ -82,6 +82,7 @@ bool MPEValue::operator!= (const MPEValue& other) const noexcept return ! operator== (other); } + //============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -89,7 +90,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 { @@ -165,6 +168,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 ad9d272..1d9b826 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. diff --git a/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp b/JuceLibraryCode/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp index 6c9acc8..597f2f7 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. @@ -169,12 +169,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 +201,7 @@ void MPEZoneLayout::checkAndLimitZoneParameters (int minValue, int maxValue, } } + //============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -212,7 +209,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 +381,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 7fd69c9..9a49c2a 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. @@ -98,6 +98,11 @@ class JUCE_API MPEZoneLayout : (channel < 16 && channel >= 16 - numMemberChannels); } + bool isUsing (int channel) const noexcept + { + return isUsingChannelAsMemberChannel (channel) || channel == getMasterChannel(); + } + bool operator== (const Zone& other) const noexcept { return lowerZone == other.lowerZone && numMemberChannels == other.numMemberChannels && perNotePitchbendRange == other.perNotePitchbendRange 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 798197d..c91d7d9 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. diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_AudioSource.h b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_AudioSource.h index 93b94e9..060c312 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. @@ -122,7 +122,7 @@ class JUCE_API AudioSource 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 5dd781b..5e1a536 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. diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_BufferingAudioSource.h b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_BufferingAudioSource.h index 7ac13d0..e94410f 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. diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ChannelRemappingAudioSource.cpp b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ChannelRemappingAudioSource.cpp index 0c49eda..647a518 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 e09cd11..9886fb4 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. @@ -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 dc4ac46..598c324 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 7b2f320..bee2808 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. diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_MemoryAudioSource.cpp b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_MemoryAudioSource.cpp index ac0aa22..ac83376 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); @@ -50,7 +50,7 @@ void MemoryAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& bufferT auto n = buffer.getNumSamples(), m = bufferToFill.numSamples; int i; - for (i = position; (i < n || isLooping) && (pos < m); i += max) + for (i = position; (i < n || isCurrentlyLooping) && (pos < m); i += max) { max = jmin (m - pos, n - (i % n)); @@ -70,4 +70,31 @@ void MemoryAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& bufferT position = (i % n); } +//============================================================================== +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; +} + } // 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 b898682..aaeeb74 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 5d33d92..20678ec 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. diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_MixerAudioSource.h b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_MixerAudioSource.h index 635a519..1ce8f2c 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. diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_PositionableAudioSource.h b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_PositionableAudioSource.h index d9667b9..3061844 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. diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp index d5d499c..585aa25 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 65888d9..7753127 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. @@ -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 51c1216..268eadc 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 0de651c..a3c2fb0 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. diff --git a/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ToneGeneratorAudioSource.cpp b/JuceLibraryCode/modules/juce_audio_basics/sources/juce_ToneGeneratorAudioSource.cpp index 54c8321..b8d792a 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 5a03167..d679b9a 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. diff --git a/JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp b/JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp index 414bcf4..d29aeae 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,13 +202,14 @@ 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 diff --git a/JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h b/JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h index b9d16ed..218cfe6 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. @@ -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) }; diff --git a/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_ADSR.h b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_ADSR.h index b7b2348..bfac36d 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_ADSR.h +++ b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_ADSR.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. @@ -30,6 +30,8 @@ namespace juce 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 ADSR { @@ -42,7 +44,11 @@ class ADSR } //============================================================================== - /** Holds the parameters being used by an ADSR object. */ + /** + Holds the parameters being used by an ADSR object. + + @tags{Audio} + */ struct Parameters { /** Attack time in seconds. */ @@ -71,6 +77,9 @@ class ADSR sustainLevel = newParameters.sustain; calculateRates (newParameters); + + if (currentState != State::idle) + checkCurrentState(); } /** Returns the parameters currently being used by an ADSR object. @@ -104,9 +113,19 @@ class ADSR /** Starts the attack phase of the envelope. */ void noteOn() { - if (attackRate > 0.0f) currentState = State::attack; - else if (decayRate > 0.0f) currentState = State::decay; - else currentState = State::sustain; + if (attackRate > 0.0f) + { + currentState = State::attack; + } + else if (decayRate > 0.0f) + { + envelopeVal = 1.0f; + currentState = State::decay; + } + else + { + currentState = State::sustain; + } } /** Starts the release phase of the envelope. */ @@ -114,10 +133,15 @@ class ADSR { if (currentState != State::idle) { - if (releaseRate > 0.0f) + if (currentParameters.release > 0.0f) + { + releaseRate = static_cast (envelopeVal / (currentParameters.release * sr)); currentState = State::release; + } else + { reset(); + } } } @@ -202,7 +226,13 @@ class ADSR attackRate = (parameters.attack > 0.0f ? static_cast (1.0f / (parameters.attack * sr)) : -1.0f); decayRate = (parameters.decay > 0.0f ? static_cast ((1.0f - sustainLevel) / (parameters.decay * sr)) : -1.0f); - releaseRate = (parameters.release > 0.0f ? static_cast (sustainLevel / (parameters.release * sr)) : -1.0f); + } + + void checkCurrentState() + { + if (currentState == State::attack && attackRate <= 0.0f) currentState = decayRate > 0.0f ? State::decay : State::sustain; + else if (currentState == State::decay && decayRate <= 0.0f) currentState = State::sustain; + else if (currentState == State::release && releaseRate <= 0.0f) reset(); } //============================================================================== @@ -212,11 +242,7 @@ class ADSR Parameters currentParameters; double sr = 0.0; - - float envelopeVal = 0.0f; - - float sustainLevel = 0.0f; - float attackRate = 0.0f, decayRate = 0.0f, releaseRate = 0.0f; + float envelopeVal = 0.0f, sustainLevel = 0.0f, attackRate = 0.0f, decayRate = 0.0f, releaseRate = 0.0f; }; } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_CatmullRomInterpolator.cpp b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_CatmullRomInterpolator.cpp deleted file mode 100644 index dbe986c..0000000 --- a/JuceLibraryCode/modules/juce_audio_basics/utilities/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/utilities/juce_CatmullRomInterpolator.h b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_CatmullRomInterpolator.h deleted file mode 100644 index bf40cf2..0000000 --- a/JuceLibraryCode/modules/juce_audio_basics/utilities/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/utilities/juce_Decibels.h b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_Decibels.h index 999ec55..adb492b 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/utilities/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 0000000..ab01b5a --- /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 ((float) pos); + 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/utilities/juce_IIRFilter.cpp b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_IIRFilter.cpp index 3938a6b..29a408f 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/utilities/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. diff --git a/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_IIRFilter.h b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_IIRFilter.h index 5eed4e2..60b8596 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/utilities/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. 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 0000000..ffd6ba7 --- /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 0000000..8068249 --- /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 index 16af330..52d3ab5 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_LagrangeInterpolator.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_LagrangeInterpolator.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,381 +23,6 @@ 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; - - if (wrap == 0) - return (int) (in - originalIn); - - 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; - - if (wrap == 0) - return (int) (in - originalIn); - - 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 { @@ -410,58 +35,28 @@ 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); +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; } -int LagrangeInterpolator::process (double actualRatio, const float* in, float* out, int numOut) noexcept +float Interpolators::LagrangeTraits::valueAtOffset (const float* inputs, float offset, int index) noexcept { - return interpolate (lastInputSamples, subSamplePos, actualRatio, in, out, numOut); -} + float result = 0.0f; -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); -} + 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); -int LagrangeInterpolator::processAdding (double actualRatio, const float* in, float* out, int numOut, float gain) noexcept -{ - return interpolateAdding (lastInputSamples, subSamplePos, actualRatio, in, out, numOut, gain); + return result; } } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_LagrangeInterpolator.h b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_LagrangeInterpolator.h deleted file mode 100644 index 4aee2c5..0000000 --- a/JuceLibraryCode/modules/juce_audio_basics/utilities/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/utilities/juce_Reverb.h b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_Reverb.h index b88c7f7..56ca89a 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/utilities/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. diff --git a/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_SmoothedValue.cpp b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_SmoothedValue.cpp index 08b8c8a..2383cdb 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_SmoothedValue.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_SmoothedValue.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2018 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -32,7 +32,7 @@ class SmoothedValueTests : public UnitTest { public: SmoothedValueTests() - : UnitTest ("SmoothedValueTests", "SmoothedValues") + : UnitTest ("SmoothedValueTests", UnitTestCategories::smoothedValues) {} void runTest() override diff --git a/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_SmoothedValue.h b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_SmoothedValue.h index dfff4fa..f1c0a16 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_SmoothedValue.h +++ b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_SmoothedValue.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. @@ -179,10 +179,18 @@ class SmoothedValueBase */ namespace ValueSmoothingTypes { - /** Used to indicate a linear smoothing between values. */ + /** + Used to indicate a linear smoothing between values. + + @tags{Audio} + */ struct Linear {}; - /** Used to indicate a smoothing between multiplicative values. */ + /** + Used to indicate a smoothing between multiplicative values. + + @tags{Audio} + */ struct Multiplicative {}; } @@ -361,7 +369,7 @@ class SmoothedValue : public SmoothedValueBase MultiplicativeVoid setStepSize() { - step = std::exp ((std::log (std::abs (this->target)) - std::log (std::abs (this->currentValue))) / this->countdown); + step = std::exp ((std::log (std::abs (this->target)) - std::log (std::abs (this->currentValue))) / (FloatType) this->countdown); } //============================================================================== @@ -408,7 +416,7 @@ class CommonSmoothedValueTests : public UnitTest { public: CommonSmoothedValueTests() - : UnitTest ("CommonSmoothedValueTests", "SmoothedValues") + : UnitTest ("CommonSmoothedValueTests", UnitTestCategories::smoothedValues) {} void runTest() override @@ -514,8 +522,8 @@ class CommonSmoothedValueTests : public UnitTest return result; }; - auto compareData = [this](const AudioBuffer& test, - const AudioBuffer& reference) + auto compareData = [this] (const AudioBuffer& test, + const AudioBuffer& reference) { for (int i = 0; i < test.getNumSamples(); ++i) expectWithinAbsoluteError (test.getSample (0, i), diff --git a/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_WindowedSincInterpolator.cpp b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_WindowedSincInterpolator.cpp new file mode 100644 index 0000000..bd77ed1 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_basics/utilities/juce_WindowedSincInterpolator.cpp @@ -0,0 +1,10033 @@ +/* + ============================================================================== + + 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 +{ + +const float Interpolators::WindowedSincTraits::lookupTable[] { + 1.000000000000000000e+00f, + 9.998321499902942389e-01f, + 9.993287014045605376e-01f, + 9.984899584999463729e-01f, + 9.973164281284172539e-01f, + 9.958088193720359138e-01f, + 9.939680430327538785e-01f, + 9.917952109771142055e-01f, + 9.892916353363806481e-01f, + 9.864588275627174108e-01f, + 9.832984973421626806e-01f, + 9.798125513652424790e-01f, + 9.760030919561943907e-01f, + 9.718724155618675420e-01f, + 9.674230111014888722e-01f, + 9.626575581785837832e-01f, + 9.575789251564525983e-01f, + 9.521901670987075184e-01f, + 9.464945235764864462e-01f, + 9.404954163440536474e-01f, + 9.341964468846075675e-01f, + 9.276013938282199334e-01f, + 9.207142102439148657e-01f, + 9.135390208080165220e-01f, + 9.060801188509671755e-01f, + 8.983419632849326542e-01f, + 8.903291754145852277e-01f, + 8.820465356335611684e-01f, + 8.734989800091675916e-01f, + 8.646915967580026674e-01f, + 8.556296226152392270e-01f, + 8.463184391004026086e-01f, + 8.367635686825474206e-01f, + 8.269706708478274937e-01f, + 8.169455380725142435e-01f, + 8.066940917045994919e-01f, + 7.962223777571848515e-01f, + 7.855365626169290572e-01f, + 7.746429286708844675e-01f, + 7.635478698551215748e-01f, + 7.522578871285925395e-01f, + 7.407795838757467166e-01f, + 7.291196612414603262e-01f, + 7.172849134018910444e-01f, + 7.052822227749226958e-01f, + 6.931185551739007522e-01f, + 6.808009549084045320e-01f, + 6.683365398358420695e-01f, + 6.557324963676841589e-01f, + 6.429960744341879364e-01f, + 6.301345824114912286e-01f, + 6.171553820149802139e-01f, + 6.040658831628585856e-01f, + 5.908735388138642852e-01f, + 5.775858397830959667e-01f, + 5.642103095399239043e-01f, + 5.507544989919713752e-01f, + 5.372259812591544392e-01f, + 5.236323464417774742e-01f, + 5.099811963866732745e-01f, + 4.962801394553849055e-01f, + 4.825367852983662442e-01f, + 4.687587396391774686e-01f, + 4.549535990726381041e-01f, + 4.411289458808779762e-01f, + 4.272923428712149252e-01f, + 4.134513282397586642e-01f, + 3.996134104646188456e-01f, + 3.857860632325655903e-01f, + 3.719767204029549301e-01f, + 3.581927710127054132e-01f, + 3.444415543260631041e-01f, + 3.307303549328605707e-01f, + 3.170663978989262666e-01f, + 3.034568439722529765e-01f, + 2.899087848484924179e-01f, + 2.764292384992768636e-01f, + 2.630251445668272403e-01f, + 2.497033598282397682e-01f, + 2.364706537327855851e-01f, + 2.233337040154965702e-01f, + 2.102990923902373910e-01f, + 1.973733003254070084e-01f, + 1.845627049053287227e-01f, + 1.718735747803255554e-01f, + 1.593120662083951089e-01f, + 1.468842191913231343e-01f, + 1.345959537079954305e-01f, + 1.224530660475812854e-01f, + 1.104612252451845633e-01f, + 9.862596962246501786e-02f, + 8.695270343564839854e-02f, + 7.544669363325365308e-02f, + 6.411306672577052335e-02f, + 5.295680576943356810e-02f, + 4.198274746613558234e-02f, + 3.119557938143482229e-02f, + 2.059983728250635790e-02f, + 1.019990259779169663e-02f, + 3.897210076277699062e-17f, + -9.995804885990083877e-03f, + -1.978360764887690526e-02f, + -2.935966712899029663e-02f, + -3.872040732740943125e-02f, + -4.786241918501666498e-02f, + -5.678246223045373131e-02f, + -6.547746609606562573e-02f, + -7.394453190101335505e-02f, + -8.218093350085642346e-02f, + -9.018411860300616645e-02f, + -9.795170974756001181e-02f, + -1.054815051531433207e-01f, + -1.127714794274846111e-01f, + -1.198197841425640842e-01f, + -1.266247482742862418e-01f, + -1.331848785067307750e-01f, + -1.394988594011491723e-01f, + -1.455655534299787057e-01f, + -1.513840008762573630e-01f, + -1.569534195989277237e-01f, + -1.622732046646232218e-01f, + -1.673429278466408709e-01f, + -1.721623369919041413e-01f, + -1.767313552568272883e-01f, + -1.810500802130950160e-01f, + -1.851187828244720002e-01f, + -1.889379062958614630e-01f, + -1.925080647959259983e-01f, + -1.958300420546892351e-01f, + -1.989047898376287982e-01f, + -2.017334262978687787e-01f, + -2.043172342081740200e-01f, + -2.066576590745419495e-01f, + -2.087563071332755593e-01f, + -2.106149432335147065e-01f, + -2.122354886072851110e-01f, + -2.136200185292154441e-01f, + -2.147707598681500851e-01f, + -2.156900885329726125e-01f, + -2.163805268150296168e-01f, + -2.168447406296239166e-01f, + -2.170855366591212532e-01f, + -2.171058594002854003e-01f, + -2.169087881185291500e-01f, + -2.164975337118347498e-01f, + -2.158754354871634251e-01f, + -2.150459578522372073e-01f, + -2.140126869256352149e-01f, + -2.127793270682061255e-01f, + -2.113496973388519218e-01f, + -2.097277278777923137e-01f, + -2.079174562204673671e-01f, + -2.059230235452841895e-01f, + -2.037486708584572426e-01f, + -2.013987351192330633e-01f, + -1.988776453088292318e-01f, + -1.961899184464536705e-01f, + -1.933401555558005303e-01f, + -1.903330375854543621e-01f, + -1.871733212866534823e-01f, + -1.838658350518955764e-01f, + -1.804154747178837448e-01f, + -1.768271993363320083e-01f, + -1.731060269161642517e-01f, + -1.692570301406509103e-01f, + -1.652853320630413847e-01f, + -1.611961017842489241e-01f, + -1.569945501161558454e-01f, + -1.526859252341015438e-01f, + -1.482755083221153625e-01f, + -1.437686092144501160e-01f, + -1.391705620369629026e-01f, + -1.344867208518796264e-01f, + -1.297224553094619426e-01f, + -1.248831463100814054e-01f, + -1.199741816801844635e-01f, + -1.150009518656041618e-01f, + -1.099688456456556773e-01f, + -1.048832458714182708e-01f, + -9.974952523157622208e-02f, + -9.457304204915860379e-02f, + -8.935913611247510435e-02f, + -8.411312454351556334e-02f, + -7.884029770702483120e-02f, + -7.354591516343182700e-02f, + -6.823520166875686466e-02f, + -6.291334322457314832e-02f, + -5.758548318104762115e-02f, + -5.225671839602590713e-02f, + -4.693209545307914371e-02f, + -4.161660694135679156e-02f, + -3.631518780004174690e-02f, + -3.103271173013015527e-02f, + -2.577398767619723877e-02f, + -2.054375638074063329e-02f, + -1.534668701362280202e-02f, + -1.018737387906320201e-02f, + -5.070333202553640312e-03f, + -3.894325756689964161e-17f, + 5.019274968688979509e-03f, + 9.983228159422152803e-03f, + 1.488768611509041877e-02f, + 1.972856824609843865e-02f, + 2.450188951836063458e-02f, + 2.920376304695326483e-02f, + 3.383040259369500535e-02f, + 3.837812496701634851e-02f, + 4.284335232256628045e-02f, + 4.722261436309905386e-02f, + 5.151255043626536828e-02f, + 5.570991152903332494e-02f, + 5.981156215754928479e-02f, + 6.381448215134405411e-02f, + 6.771576833088721603e-02f, + 7.151263607757946117e-02f, + 7.520242079537053925e-02f, + 7.878257926329076954e-02f, + 8.225069087826682168e-02f, + 8.560445878770081563e-02f, + 8.884171091137989251e-02f, + 9.196040085238070538e-02f, + 9.495860869672850813e-02f, + 9.783454170166935859e-02f, + 1.005865348725034220e-01f, + 1.032130514280261008e-01f, + 1.057126831547209184e-01f, + 1.080841506499338051e-01f, + 1.103263034543625065e-01f, + 1.124381200742803483e-01f, + 1.144187078940081537e-01f, + 1.162673029792436336e-01f, + 1.179832697719408463e-01f, + 1.195661006775294716e-01f, + 1.210154155453490032e-01f, + 1.223309610432607719e-01f, + 1.235126099274892336e-01f, + 1.245603602088281303e-01f, + 1.254743342164319486e-01f, + 1.262547775604956901e-01f, + 1.269020579952085670e-01f, + 1.274166641834456049e-01f, + 1.277992043647412090e-01f, + 1.280504049281650791e-01f, + 1.281711088917953933e-01f, + 1.281622742905593748e-01f, + 1.280249724742810735e-01f, + 1.277603863178479460e-01f, + 1.273698083454741226e-01f, + 1.268546387711058931e-01f, + 1.262163834570771692e-01f, + 1.254566517931865743e-01f, + 1.245771544984256851e-01f, + 1.235797013476476885e-01f, + 1.224661988255190126e-01f, + 1.212386477101517479e-01f, + 1.198991405888646528e-01f, + 1.184498593085685503e-01f, + 1.168930723633207630e-01f, + 1.152311322216329759e-01f, + 1.134664725961638115e-01f, + 1.116016056584608895e-01f, + 1.096391192014578575e-01f, + 1.075816737524645378e-01f, + 1.054319996394198350e-01f, + 1.031928940132054995e-01f, + 1.008672178288464866e-01f, + 9.845789278844846448e-02f, + 9.596789824874003838e-02f, + 9.340026809611248759e-02f, + 9.075808759205977738e-02f, + 8.804449019193870407e-02f, + 8.526265433997994025e-02f, + 8.241580024348756084e-02f, + 7.950718662917011237e-02f, + 7.654010748455197799e-02f, + 7.351788878741070954e-02f, + 7.044388522618756643e-02f, + 6.732147691431115966e-02f, + 6.415406610136678567e-02f, + 6.094507388403559711e-02f, + 5.769793691971696753e-02f, + 5.441610414572558424e-02f, + 5.110303350694805208e-02f, + 4.776218869481312773e-02f, + 4.439703590041457065e-02f, + 4.101104058459904139e-02f, + 3.760766426780321608e-02f, + 3.419036134239462205e-02f, + 3.076257591024030361e-02f, + 2.732773864819467574e-02f, + 2.388926370415486722e-02f, + 2.045054562630352346e-02f, + 1.701495632810792399e-02f, + 1.358584209160797196e-02f, + 1.016652061148060233e-02f, + 6.760278082314462311e-03f, + 3.370366331490179130e-03f, + 3.889521720231377172e-17f, + -3.347646226505052690e-03f, + -6.669440334209695946e-03f, + -9.962295642995425485e-03f, + -1.322317341155379231e-02f, + -1.644908538369398501e-02f, + -1.963709627384800302e-02f, + -2.278432618984587571e-02f, + -2.588795299108807499e-02f, + -2.894521458031795724e-02f, + -3.195341112725825355e-02f, + -3.490990722244410177e-02f, + -3.781213395966125795e-02f, + -4.065759094545921132e-02f, + -4.344384823429099651e-02f, + -4.616854818789777049e-02f, + -4.882940725763235124e-02f, + -5.142421768849166769e-02f, + -5.395084914370364831e-02f, + -5.640725024878998073e-02f, + -5.879145005410169045e-02f, + -6.110155941490798270e-02f, + -6.333577228818905447e-02f, + -6.549236694536995917e-02f, + -6.756970710030717198e-02f, + -6.956624295191975171e-02f, + -7.148051214093797956e-02f, + -7.331114062032219325e-02f, + -7.505684343898266775e-02f, + -7.671642543851386886e-02f, + -7.828878186273431627e-02f, + -7.977289887990460238e-02f, + -8.116785401757553586e-02f, + -8.247281651009769066e-02f, + -8.368704755890117586e-02f, + -8.480990050573701533e-02f, + -8.584082091914502222e-02f, + -8.677934659449468291e-02f, + -8.762510746802033845e-02f, + -8.837782544534880658e-02f, + -8.903731414509374886e-02f, + -8.960347855816586105e-02f, + -9.007631462352130858e-02f, + -9.045590872114415981e-02f, + -9.074243708313121937e-02f, + -9.093616512381758055e-02f, + -9.103744668995188138e-02f, + -9.104672323199845818e-02f, + -9.096452289771120303e-02f, + -9.079145954918992067e-02f, + -9.052823170469484482e-02f, + -9.017562140655861758e-02f, + -8.973449301659575106e-02f, + -8.920579194047170701e-02f, + -8.859054328255137889e-02f, + -8.788985043280389542e-02f, + -8.710489358739707810e-02f, + -8.623692820466778708e-02f, + -8.528728339820713933e-02f, + -8.425736026884980689e-02f, + -8.314863017740434237e-02f, + -8.196263296000964871e-02f, + -8.070097508804566222e-02f, + -7.936532777456997700e-02f, + -7.795742502929374484e-02f, + -7.647906166414730755e-02f, + -7.493209125152387740e-02f, + -7.331842403732392877e-02f, + -7.164002481095702035e-02f, + -6.989891073448464831e-02f, + -6.809714913312167606e-02f, + -6.623685524933471680e-02f, + -6.432018996280304546e-02f, + -6.234935747852995286e-02f, + -6.032660298541026728e-02f, + -5.825421028757805930e-02f, + -5.613449941087523404e-02f, + -5.396982418679260179e-02f, + -5.176256981624846598e-02f, + -4.951515041557684460e-02f, + -4.723000654710355489e-02f, + -4.490960273669408059e-02f, + -4.255642498066016660e-02f, + -4.017297824440700660e-02f, + -3.776178395520819048e-02f, + -3.532537749148359496e-02f, + -3.286630567095341626e-02f, + -3.038712424003185350e-02f, + -2.789039536681189174e-02f, + -2.537868513997948439e-02f, + -2.285456107598123413e-02f, + -2.032058963675330288e-02f, + -1.777933376029512333e-02f, + -1.523335040635749593e-02f, + -1.268518811948355154e-02f, + -1.013738461162063884e-02f, + -7.592464366493653291e-03f, + -5.052936267896138492e-03f, + -2.521291254032028643e-03f, + -3.882802707905923401e-17f, + 2.508489369517248428e-03f, + 5.001753535334178304e-03f, + 7.477396204630696805e-03f, + 9.933050295659225093e-03f, + 1.236638008438947431e-02f, + 1.477508331123026167e-02f, + 1.715689324600980226e-02f, + 1.950958070945080572e-02f, + 2.183095604941610521e-02f, + 2.411887107025306037e-02f, + 2.637122091361803269e-02f, + 2.858594588921111249e-02f, + 3.076103325390444967e-02f, + 3.289451893780558772e-02f, + 3.498448921585006754e-02f, + 3.702908232357217388e-02f, + 3.902649001576798810e-02f, + 4.097495906681519057e-02f, + 4.287279271148002058e-02f, + 4.471835202509810703e-02f, + 4.651005724208144565e-02f, + 4.824638901176293154e-02f, + 4.992588959065285409e-02f, + 5.154716397024793756e-02f, + 5.310888093959532930e-02f, + 5.460977408187722010e-02f, + 5.604864270435185730e-02f, + 5.742435270104698924e-02f, + 5.873583734766929521e-02f, + 5.998209802826119652e-02f, + 6.116220489320042114e-02f, + 6.227529744820328728e-02f, + 6.332058507406373993e-02f, + 6.429734747692100738e-02f, + 6.520493506891764102e-02f, + 6.604276927917780704e-02f, + 6.681034279509827367e-02f, + 6.750721973401248299e-02f, + 6.813303574535393980e-02f, + 6.868749804350914034e-02f, + 6.917038537161544764e-02f, + 6.958154789662478190e-02f, + 6.992090703601620827e-02f, + 7.018845521660418973e-02f, + 7.038425556595274968e-02f, + 7.050844153696640693e-02f, + 7.056121646629046062e-02f, + 7.054285306721332083e-02f, + 7.045369285782319968e-02f, + 7.029414552522963988e-02f, + 7.006468822671796381e-02f, + 6.976586482876150075e-02f, + 6.939828508487122516e-02f, + 6.896262375331772831e-02f, + 6.845961965581227882e-02f, + 6.789007467828668541e-02f, + 6.725485271496202400e-02f, + 6.655487855694536270e-02f, + 6.579113672664134438e-02f, + 6.496467025931394745e-02f, + 6.407657943317585092e-02f, + 6.312802044942868174e-02f, + 6.212020406372047165e-02f, + 6.105439417052395401e-02f, + 5.993190634198172773e-02f, + 5.875410632280082118e-02f, + 5.752240848281407054e-02f, + 5.623827422886059496e-02f, + 5.490321037767217222e-02f, + 5.351876749147910922e-02f, + 5.208653817808057279e-02f, + 5.060815535715459945e-02f, + 4.908529049460156474e-02f, + 4.751965180674513900e-02f, + 4.591298243623419262e-02f, + 4.426705860150847993e-02f, + 4.258368772170978422e-02f, + 4.086470651893956557e-02f, + 3.911197909977250781e-02f, + 3.732739501795391546e-02f, + 3.551286732021802228e-02f, + 3.367033057717121886e-02f, + 3.180173890119344232e-02f, + 2.990906395331716441e-02f, + 2.799429294104273033e-02f, + 2.605942660905504957e-02f, + 2.410647722480178945e-02f, + 2.213746656089659454e-02f, + 2.015442387629913859e-02f, + 1.815938389822458268e-02f, + 1.615438480672493765e-02f, + 1.414146622387316317e-02f, + 1.212266720947206833e-02f, + 1.010002426519698848e-02f, + 8.075569349063350597e-03f, + 6.051327902095616530e-03f, + 4.029316889058113388e-03f, + 2.011542855081033601e-03f, + 3.874175350567572650e-17f, + -2.003331727797961342e-03f, + -3.996488516257723500e-03f, + -5.977524551525892349e-03f, + -7.944513855095518967e-03f, + -9.895552094544582400e-03f, + -1.182875836621732034e-02f, + -1.374227694822771975e-02f, + -1.563427902220560287e-02f, + -1.750296436223446397e-02f, + -1.934656298946970526e-02f, + -2.116333679096629727e-02f, + -2.295158110128149576e-02f, + -2.470962624546017145e-02f, + -2.643583904205206586e-02f, + -2.812862426485629452e-02f, + -2.978642606212655863e-02f, + -3.140772933202141265e-02f, + -3.299106105312992615e-02f, + -3.453499156894547506e-02f, + -3.603813582521487452e-02f, + -3.749915455913428036e-02f, + -3.891675543941802012e-02f, + -4.028969415631109691e-02f, + -4.161677546067264061e-02f, + -4.289685415130901208e-02f, + -4.412883600978426135e-02f, + -4.531167868199265092e-02f, + -4.644439250583275169e-02f, + -4.752604128436910269e-02f, + -4.855574300393437209e-02f, + -4.953267049666788130e-02f, + -5.045605204704892155e-02f, + -5.132517194203765898e-02f, + -5.213937096448940933e-02f, + -5.289804682956641274e-02f, + -5.360065456392785338e-02f, + -5.424670682753111178e-02f, + -5.483577417793748798e-02f, + -5.536748527706834150e-02f, + -5.584152704041558252e-02f, + -5.625764472876377403e-02f, + -5.661564198253816321e-02f, + -5.691538079894768037e-02f, + -5.715678145214542205e-02f, + -5.733982235668498573e-02f, + -5.746453987460405782e-02f, + -5.753102806651958639e-02f, + -5.753943838717312520e-02f, + -5.748997932591520116e-02f, + -5.738291599267093812e-02f, + -5.721856964997878298e-02f, + -5.699731719174516015e-02f, + -5.671959056940642507e-02f, + -5.638587616623912807e-02f, + -5.599671412060634040e-02f, + -5.555269759897443066e-02f, + -5.505447201958245385e-02f, + -5.450273422768755344e-02f, + -5.389823162335748846e-02f, + -5.324176124282154615e-02f, + -5.253416879443297688e-02f, + -5.177634765033799907e-02f, + -5.096923779498445384e-02f, + -5.011382473164045781e-02f, + -4.921113834813311411e-02f, + -4.826225174304939192e-02f, + -4.726828001367859577e-02f, + -4.623037900700535663e-02f, + -4.514974403509764561e-02f, + -4.402760855626140085e-02f, + -4.286524282336175162e-02f, + -4.166395250074144546e-02f, + -4.042507725118998224e-02f, + -3.914998929443946202e-02f, + -3.784009193869437848e-02f, + -3.649681808671064592e-02f, + -3.512162871797221836e-02f, + -3.371601134852347803e-02f, + -3.228147847003334792e-02f, + -3.081956596968622730e-02f, + -2.933183153250423780e-02f, + -2.781985302771665045e-02f, + -2.628522688080791453e-02f, + -2.472956643287790510e-02f, + -2.315450028896036058e-02f, + -2.156167065694567300e-02f, + -1.995273167876449386e-02f, + -1.832934775548567333e-02f, + -1.669319186798288307e-02f, + -1.504594389482788452e-02f, + -1.338928892906133400e-02f, + -1.172491559548742221e-02f, + -1.005451437013836664e-02f, + -8.379775903540833196e-03f, + -6.702389349412756978e-03f, + -5.024040700403363362e-03f, + -3.346411132483765802e-03f, + -1.671175359577019423e-03f, + -3.863648162376423474e-17f, + 1.665458043716377392e-03f, + 3.323553190096430274e-03f, + 4.972652767551836474e-03f, + 6.611138585273553490e-03f, + 8.237408484711907647e-03f, + 9.849877870182622078e-03f, + 1.144698121717139215e-02f, + 1.302717355693413029e-02f, + 1.458893193601275978e-02f, + 1.613075684932130729e-02f, + 1.765117364548211831e-02f, + 1.914873390312786527e-02f, + 2.062201677691140322e-02f, + 2.206963031200360678e-02f, + 2.349021272589388309e-02f, + 2.488243365633890924e-02f, + 2.624499537434637694e-02f, + 2.757663396111778922e-02f, + 2.887612044790845850e-02f, + 3.014226191780771530e-02f, + 3.137390256847804454e-02f, + 3.256992473493734719e-02f, + 3.372924987150486414e-02f, + 3.485083949207803955e-02f, + 3.593369606795079885e-02f, + 3.697686388242336919e-02f, + 3.797942984150279311e-02f, + 3.894052424003760504e-02f, + 3.985932148267041369e-02f, + 4.073504075904751942e-02f, + 4.156694667276145810e-02f, + 4.235434982355489736e-02f, + 4.309660734236082924e-02f, + 4.379312337879810030e-02f, + 4.444334954079259131e-02f, + 4.504678528604074556e-02f, + 4.560297826507851010e-02f, + 4.611152461576945721e-02f, + 4.657206920907153852e-02f, + 4.698430584599172510e-02f, + 4.734797740568404828e-02f, + 4.766287594469555827e-02f, + 4.792884274741274209e-02f, + 4.814576832780684268e-02f, + 4.831359238262550315e-02f, + 4.843230369622460174e-02f, + 4.850193999728014821e-02f, + 4.852258776766780329e-02f, + 4.849438200384208891e-02f, + 4.841750593109390294e-02f, + 4.829219067110925023e-02f, + 4.811871486329679509e-02f, + 4.789740424039561073e-02f, + 4.762863115891774468e-02f, + 4.731281408502291397e-02f, + 4.695041703646362502e-02f, + 4.654194898128217323e-02f, + 4.608796319397825969e-02f, + 4.558905656990844268e-02f, + 4.504586889871579902e-02f, + 4.445908209762516189e-02f, + 4.382941940547854798e-02f, + 4.315764453841920700e-02f, + 4.244456080816757376e-02f, + 4.169101020386845047e-02f, + 4.089787243851888271e-02f, + 4.006606396102018602e-02f, + 3.919653693492577279e-02f, + 3.829027818498920155e-02f, + 3.734830811264253092e-02f, + 3.637167958156230230e-02f, + 3.536147677450902915e-02f, + 3.431881402264831682e-02f, + 3.324483460858414924e-02f, + 3.214070954436337030e-02f, + 3.100763632572139938e-02f, + 2.984683766386852025e-02f, + 2.865956019612891231e-02f, + 2.744707317676135447e-02f, + 2.621066714931024125e-02f, + 2.495165260184606035e-02f, + 2.367135860646735895e-02f, + 2.237113144445156826e-02f, + 2.105233321844750261e-02f, + 1.971634045311482925e-02f, + 1.836454268561935055e-02f, + 1.699834104740382407e-02f, + 1.561914683865467043e-02f, + 1.422838009688787327e-02f, + 1.282746816108333576e-02f, + 1.141784423279322037e-02f, + 1.000094593564865818e-02f, + 8.578213874691159244e-03f, + 7.151090196945879447e-03f, + 5.721017154652988448e-03f, + 4.289435672562395829e-03f, + 2.857783920694851112e-03f, + 1.427495893958731022e-03f, + 3.851231532396259107e-17f, + -1.423282343340041833e-03f, + -2.840938099612009063e-03f, + -4.251563993045895384e-03f, + -5.653767874212517128e-03f, + -7.046170070757393038e-03f, + -8.427404721911885624e-03f, + -9.796121095514335672e-03f, + -1.115098488629330704e-02f, + -1.249067949418276348e-02f, + -1.381390728146736184e-02f, + -1.511939080757592098e-02f, + -1.640587404037048558e-02f, + -1.767212354279941791e-02f, + -1.891692963381457968e-02f, + -2.013910752248064540e-02f, + -2.133749841423027843e-02f, + -2.251097058825281272e-02f, + -2.365842044503514013e-02f, + -2.477877352310193029e-02f, + -2.587098548403953327e-02f, + -2.693404306491827341e-02f, + -2.796696499726556220e-02f, + -2.896880289177323695e-02f, + -2.993864208796185450e-02f, + -3.087560246806111269e-02f, + -3.177883923439979441e-02f, + -3.264754364963919769e-02f, + -3.348094373922329975e-02f, + -3.427830495545182432e-02f, + -3.503893080263100618e-02f, + -3.576216342278743660e-02f, + -3.644738414147634387e-02f, + -3.709401397325490235e-02f, + -3.770151408643012542e-02f, + -3.826938622673421719e-02f, + -3.879717309962135707e-02f, + -3.928445871091951203e-02f, + -3.973086866561512109e-02f, + -4.013607042458825630e-02f, + -4.049977351915948903e-02f, + -4.082172972334963124e-02f, + -4.110173318379706925e-02f, + -4.133962050731876392e-02f, + -4.153527080614199951e-02f, + -4.168860570087641604e-02f, + -4.179958928133744450e-02f, + -4.186822802537215615e-02f, + -4.189457067588118339e-02f, + -4.187870807626980357e-02f, + -4.182077296460211258e-02f, + -4.172093972677210633e-02f, + -4.157942410904505448e-02f, + -4.139648289036141487e-02f, + -4.117241351483449247e-02f, + -4.090755368491114791e-02f, + -4.060228091570139419e-02f, + -4.025701205102193148e-02f, + -3.987220274173181034e-02f, + -3.944834688697711200e-02f, + -3.898597603899465330e-02f, + -3.848565877215900932e-02f, + -3.794800001699184799e-02f, + -3.737364035988401112e-02f, + -3.676325530931268126e-02f, + -3.611755452936806637e-02f, + -3.543728104143289981e-02f, + -3.472321039488834166e-02f, + -3.397614980774645715e-02f, + -3.319693727813939621e-02f, + -3.238644066761971890e-02f, + -3.154555675725123631e-02f, + -3.067521027749671447e-02f, + -2.977635291292965100e-02f, + -2.884996228281870578e-02f, + -2.789704089865994302e-02f, + -2.691861509974309216e-02f, + -2.591573396786606143e-02f, + -2.488946822232386211e-02f, + -2.384090909631557051e-02f, + -2.277116719593108921e-02f, + -2.168137134289090454e-02f, + -2.057266740222485346e-02f, + -1.944621709609118537e-02f, + -1.830319680494362292e-02f, + -1.714479635726702186e-02f, + -1.597221780910678887e-02f, + -1.478667421462878662e-02f, + -1.358938838894852355e-02f, + -1.238159166447296011e-02f, + -1.116452264200503558e-02f, + -9.939425937859529617e-03f, + -8.707550928239674026e-03f, + -7.470150492127149849e-03f, + -6.228479753931915469e-03f, + -4.983794827149027815e-03f, + -3.737351560261789520e-03f, + -2.490404286130025371e-03f, + -1.244204576092051940e-03f, + -3.836937714341790683e-17f, + 1.240967106592762116e-03f, + 2.477460866896080867e-03f, + 3.708253077802783210e-03f, + 4.932124414085086068e-03f, + 6.147865620704987162e-03f, + 7.354278692082365058e-03f, + 8.550178037189383809e-03f, + 9.734391629351839964e-03f, + 1.090576213965407243e-02f, + 1.206314805286936957e-02f, + 1.320542476485127813e-02f, + 1.433148566034425815e-02f, + 1.544024317019840505e-02f, + 1.653062980698680531e-02f, + 1.760159917805776894e-02f, + 1.865212697506991868e-02f, + 1.968121193909236344e-02f, + 2.068787680036934112e-02f, + 2.167116919188432494e-02f, + 2.263016253588231996e-02f, + 2.356395690253657721e-02f, + 2.447167983997980412e-02f, + 2.535248717494724760e-02f, + 2.620556378330855113e-02f, + 2.703012432980111263e-02f, + 2.782541397630681687e-02f, + 2.859070905804561927e-02f, + 2.932531772709678214e-02f, + 3.002858056268817993e-02f, + 3.069987114772966194e-02f, + 3.133859661110379585e-02f, + 3.194419813525677804e-02f, + 3.251615142867379793e-02f, + 3.305396716285353975e-02f, + 3.355719137343705916e-02f, + 3.402540582517922518e-02f, + 3.445822834048845734e-02f, + 3.485531309129908523e-02f, + 3.521635085407364557e-02f, + 3.554106922777330868e-02f, + 3.582923281466892512e-02f, + 3.608064336390364585e-02f, + 3.629513987775428302e-02f, + 3.647259868057688842e-02f, + 3.661293345045708858e-02f, + 3.671609521362455969e-02f, + 3.678207230172601816e-02f, + 3.681089027208912096e-02f, + 3.680261179114461406e-02f, + 3.675733648121128072e-02f, + 3.667520073088332416e-02f, + 3.655637746929544379e-02f, + 3.640107590457612730e-02f, + 3.620954122683402165e-02f, + 3.598205427605740553e-02f, + 3.571893117533903733e-02f, + 3.542052292987402790e-02f, + 3.508721499220928547e-02f, + 3.471942679425710915e-02f, + 3.431761124661530937e-02f, + 3.388225420576965186e-02f, + 3.341387390978267646e-02f, + 3.291302038310394557e-02f, + 3.238027481116542705e-02f, + 3.181624888545521446e-02f, + 3.122158411978745787e-02f, + 3.059695113851780904e-02f, + 2.994304893747514948e-02f, + 2.926060411840791450e-02f, + 2.855037009776879506e-02f, + 2.781312629068145512e-02f, + 2.704967727096032129e-02f, + 2.626085190807075573e-02f, + 2.544750248194389483e-02f, + 2.461050377657450841e-02f, + 2.375075215335195958e-02f, + 2.286916460509363230e-02f, + 2.196667779176278423e-02f, + 2.104424705887289471e-02f, + 2.010284543959429265e-02f, + 1.914346264158977087e-02f, + 1.816710401962278246e-02f, + 1.717478953499241082e-02f, + 1.616755270285690979e-02f, + 1.514643952852146903e-02f, + 1.411250743377312315e-02f, + 1.306682417434898782e-02f, + 1.201046674963833320e-02f, + 1.094452030571538628e-02f, + 9.870077032812075643e-03f, + 8.788235058334580366e-03f, + 7.700097336538626325e-03f, + 6.606770535970839416e-03f, + 5.509363925787424780e-03f, + 4.408988262061687424e-03f, + 3.306754675183733866e-03f, + 2.203773559457802150e-03f, + 1.101153465996373331e-03f, + 3.820780814485725242e-17f, + -1.098585276486098786e-03f, + -2.193505935265162299e-03f, + -3.283671765059895803e-03f, + -4.367999845902193791e-03f, + -5.445415613796268477e-03f, + -6.514853914614496255e-03f, + -7.575260046206469533e-03f, + -8.625590787711353430e-03f, + -9.664815415077104843e-03f, + -1.069191670181151264e-02f, + -1.170589190400125879e-02f, + -1.270575372865473569e-02f, + -1.369053128444692319e-02f, + -1.465927101395613288e-02f, + -1.561103760651160084e-02f, + -1.654491489078413133e-02f, + -1.746000670628177626e-02f, + -1.835543775292705626e-02f, + -1.923035441792335376e-02f, + -2.008392557913836474e-02f, + -2.091534338425668146e-02f, + -2.172382400498286056e-02f, + -2.250860836560024739e-02f, + -2.326896284521650510e-02f, + -2.400417995305826127e-02f, + -2.471357897620288582e-02f, + -2.539650659916279848e-02f, + -2.605233749477112518e-02f, + -2.668047488584292248e-02f, + -2.728035107711810139e-02f, + -2.785142795702474916e-02f, + -2.839319746882786391e-02f, + -2.890518205076497357e-02f, + -2.938693504479734583e-02f, + -2.983804107364120342e-02f, + -3.025811638577266885e-02f, + -3.064680916813381298e-02f, + -3.100379982630099840e-02f, + -3.132880123190676103e-02f, + -3.162155893714221899e-02f, + -3.188185135619839294e-02f, + -3.210948991353843734e-02f, + -3.230431915892578026e-02f, + -3.246621684916723566e-02f, + -3.259509399656147777e-02f, + -3.269089488407847521e-02f, + -3.275359704732655475e-02f, + -3.278321122339819538e-02f, + -3.277978126671703824e-02f, + -3.274338403204220954e-02f, + -3.267412922481752885e-02f, + -3.257215921908560019e-02f, + -3.243764884321845982e-02f, + -3.227080513374773474e-02f, + -3.207186705760879664e-02f, + -3.184110520314317044e-02f, + -3.157882144023508447e-02f, + -3.128534854998637343e-02f, + -3.096104982436503894e-02f, + -3.060631863628960475e-02f, + -3.022157798064227172e-02f, + -2.980727998672943677e-02f, + -2.936390540273656549e-02f, + -2.889196305275088666e-02f, + -2.839198926695188710e-02f, + -2.786454728559313240e-02f, + -2.731022663742679185e-02f, + -2.672964249324305541e-02f, + -2.612343499522145479e-02f, + -2.549226856281475509e-02f, + -2.483683117590470071e-02f, + -2.415783363599420183e-02f, + -2.345600880621569531e-02f, + -2.273211083096061610e-02f, + -2.198691433594817182e-02f, + -2.122121360957183317e-02f, + -2.043582176638020914e-02f, + -1.963156989356096283e-02f, + -1.880930618131524887e-02f, + -1.796989503802343471e-02f, + -1.711421619111335238e-02f, + -1.624316377455840843e-02f, + -1.535764540394315113e-02f, + -1.445858124004167390e-02f, + -1.354690304186740787e-02f, + -1.262355321016035703e-02f, + -1.168948382228147259e-02f, + -1.074565565949768715e-02f, + -9.793037227638747358e-03f, + -8.832603772118776536e-03f, + -7.865336288311713595e-03f, + -6.892220528280442078e-03f, + -5.914246004853488010e-03f, + -4.932404994047567826e-03f, + -3.947691536835270382e-03f, + -2.961100441250685226e-03f, + -1.973626285828549223e-03f, + -9.862624253675238758e-04f, + -3.802776777737574016e-17f, + 9.841730514465974952e-04f, + 1.965272972826986615e-03f, + 2.942321165824257449e-03f, + 3.914345157906578068e-03f, + 4.880379562147291184e-03f, + 5.839467027964861424e-03f, + 6.790659181857343525e-03f, + 7.733017557214086520e-03f, + 8.665614512298646516e-03f, + 9.587534135515569239e-03f, + 1.049787313708307364e-02f, + 1.139574172625059875e-02f, + 1.228026447321984953e-02f, + 1.315058115493771343e-02f, + 1.400584758395503719e-02f, + 1.484523641955660424e-02f, + 1.566793796039387537e-02f, + 1.647316091786455577e-02f, + 1.726013316951060736e-02f, + 1.802810249172396087e-02f, + 1.877633727107054853e-02f, + 1.950412719356916028e-02f, + 2.021078391128274671e-02f, + 2.089564168560189075e-02f, + 2.155805800663082583e-02f, + 2.219741418810250791e-02f, + 2.281311593728354431e-02f, + 2.340459389934918671e-02f, + 2.397130417573897082e-02f, + 2.451272881602797882e-02f, + 2.502837628287757701e-02f, + 2.551778188965732330e-02f, + 2.598050821035589528e-02f, + 2.641614546142960138e-02f, + 2.682431185526281195e-02f, + 2.720465392494783932e-02f, + 2.755684682011533618e-02f, + 2.788059457358115292e-02f, + 2.817563033860144908e-02f, + 2.844171659655807607e-02f, + 2.867864533492812257e-02f, + 2.888623819541892568e-02f, + 2.906434659218049346e-02f, + 2.921285180003846058e-02f, + 2.933166501271905480e-02f, + 2.942072737106802074e-02f, + 2.948000996129596790e-02f, + 2.950951378331144459e-02f, + 2.950926968923310578e-02f, + 2.947933829220211049e-02f, + 2.941980984564465662e-02f, + 2.933080409316416587e-02f, + 2.921247008927130642e-02f, + 2.906498599118855983e-02f, + 2.888855882199470315e-02f, + 2.868342420540245102e-02f, + 2.844984607248968178e-02f, + 2.818811634073307634e-02f, + 2.789855456571845721e-02f, + 2.758150756593012731e-02f, + 2.723734902104646763e-02f, + 2.686647904419447314e-02f, + 2.646932372864202465e-02f, + 2.604633466943028636e-02f, + 2.559798846047255452e-02f, + 2.512478616767030437e-02f, + 2.462725277861903608e-02f, + 2.410593662949834029e-02f, + 2.356140880976381052e-02f, + 2.299426254527723104e-02f, + 2.240511256053460618e-02f, + 2.179459442066713701e-02f, + 2.116336385391225788e-02f, + 2.051209605527045191e-02f, + 1.984148497207598519e-02f, + 1.915224257223392679e-02f, + 1.844509809588383564e-02f, + 1.772079729127159706e-02f, + 1.698010163562099079e-02f, + 1.622378754181329208e-02f, + 1.545264555169341587e-02f, + 1.466747951683269359e-02f, + 1.386910576759178837e-02f, + 1.305835227133488388e-02f, + 1.223605778065572393e-02f, + 1.140307097248631669e-02f, + 1.056024957896441879e-02f, + 9.708459510942056905e-03f, + 8.848573975026030602e-03f, + 7.981472585042176035e-03f, + 7.108040468822868913e-03f, + 6.229167371217365738e-03f, + 5.345746754226499142e-03f, + 4.458674895167382204e-03f, + 3.568849983769900418e-03f, + 2.677171219111589007e-03f, + 1.784537907287459457e-03f, + 8.918485607199820456e-04f, + 1.375963414501481870e-16f, + -8.901135408467832598e-04f, + -1.777601304782279023e-03f, + -2.661576896985846409e-03f, + -3.541159164019371322e-03f, + -4.415473066061055551e-03f, + -5.283650541348036689e-03f, + -6.144831361984745034e-03f, + -6.998163980273221924e-03f, + -7.842806364743631908e-03f, + -8.677926825066678909e-03f, + -9.502704825047591716e-03f, + -1.031633178291084009e-02f, + -1.111801185810167188e-02f, + -1.190696272384546804e-02f, + -1.268241632471873645e-02f, + -1.344361961850560477e-02f, + -1.418983530162710137e-02f, + -1.492034251745096018e-02f, + -1.563443754680784656e-02f, + -1.633143448005669809e-02f, + -1.701066587006366121e-02f, + -1.767148336547917642e-02f, + -1.831325832371670168e-02f, + -1.893538240305999570e-02f, + -1.953726813334768359e-02f, + -2.011834946470413346e-02f, + -2.067808229381145821e-02f, + -2.121594496723701664e-02f, + -2.173143876136030342e-02f, + -2.222408833845995052e-02f, + -2.269344217855321158e-02f, + -2.313907298660076647e-02f, + -2.356057807471537494e-02f, + -2.395757971904149269e-02f, + -2.432972549099499809e-02f, + -2.467668856258116092e-02f, + -2.499816798553347250e-02f, + -2.529388894404376378e-02f, + -2.556360298088074245e-02f, + -2.580708819671996904e-02f, + -2.602414942253634608e-02f, + -2.621461836493719708e-02f, + -2.637835372434049752e-02f, + -2.651524128593106544e-02f, + -2.662519398335435120e-02f, + -2.670815193513444846e-02f, + -2.676408245383069331e-02f, + -2.679298002797401990e-02f, + -2.679486627685148323e-02f, + -2.676978987823442138e-02f, + -2.671782646917223933e-02f, + -2.663907852000062249e-02f, + -2.653367518173962297e-02f, + -2.640177210708273547e-02f, + -2.624355124520492619e-02f, + -2.605922061064226344e-02f, + -2.584901402652179520e-02f, + -2.561319084244592648e-02f, + -2.535203562735873287e-02f, + -2.506585783774740658e-02f, + -2.475499146155598143e-02f, + -2.441979463821075669e-02f, + -2.406064925518100819e-02f, + -2.367796052152183056e-02f, + -2.327215651886596973e-02f, + -2.284368773035500011e-02f, + -2.239302654802176329e-02f, + -2.192066675915328375e-02f, + -2.142712301218852727e-02f, + -2.091293026271947089e-02f, + -2.037864320018679606e-02f, + -1.982483565587724039e-02f, + -1.925209999284902343e-02f, + -1.866104647842747183e-02f, + -1.805230263992868914e-02f, + -1.742651260428690341e-02f, + -1.678433642227292188e-02f, + -1.612644937800953443e-02f, + -1.545354128449657159e-02f, + -1.476631576587938456e-02f, + -1.406548952719811375e-02f, + -1.335179161237267514e-02f, + -1.262596265118436090e-02f, + -1.188875409602925537e-02f, + -1.114092744922038150e-02f, + -1.038325348163284326e-02f, + -9.616511443484248786e-03f, + -8.841488268055055361e-03f, + -8.058977769158835736e-03f, + -7.269779833172840267e-03f, + -6.474699606447542784e-03f, + -5.674546678917565326e-03f, + -4.870134264732259473e-03f, + -4.062278380735639960e-03f, + -3.251797023616004832e-03f, + -2.439509346553158861e-03f, + -1.626234836185142018e-03f, + -8.127924907184056955e-04f, + -3.761300170173902632e-17f, + 8.113270716327609542e-04f, + 1.620376098912416430e-03f, + 2.426338204803805097e-03f, + 3.228409064469819033e-03f, + 4.025789703243586731e-03f, + 4.817687287821219300e-03f, + 5.603315909897037261e-03f, + 6.381897361469502858e-03f, + 7.152661901059502447e-03f, + 7.914849010088072581e-03f, + 8.667708138679361060e-03f, + 9.410499440156691597e-03f, + 1.014249449352174620e-02f, + 1.086297701321397788e-02f, + 1.157124354546169333e-02f, + 1.226660415055517636e-02f, + 1.294838307038302834e-02f, + 1.361591938058873304e-02f, + 1.426856762672633859e-02f, + 1.490569844380274823e-02f, + 1.552669915862028849e-02f, + 1.613097437434502304e-02f, + 1.671794653674912173e-02f, + 1.728705648159101563e-02f, + 1.783776396262254024e-02f, + 1.836954815972504512e-02f, + 1.888190816670458697e-02f, + 1.937436345829177120e-02f, + 1.984645433591701591e-02f, + 2.029774235185137846e-02f, + 2.072781071132718048e-02f, + 2.113626465227521484e-02f, + 2.152273180233675934e-02f, + 2.188686251283411544e-02f, + 2.222833016940416184e-02f, + 2.254683147902725865e-02f, + 2.284208673320283281e-02f, + 2.311384004705211576e-02f, + 2.336185957414964667e-02f, + 2.358593769691042299e-02f, + 2.378589119238579130e-02f, + 2.396156137334416389e-02f, + 2.411281420453805294e-02f, + 2.423954039408468888e-02f, + 2.434165545991162638e-02f, + 2.441909977124352010e-02f, + 2.447183856513244701e-02f, + 2.449986193805772303e-02f, + 2.450318481264677009e-02f, + 2.448184687959331640e-02f, + 2.443591251487354371e-02f, + 2.436547067238563694e-02f, + 2.427063475216228658e-02f, + 2.415154244432998407e-02f, + 2.400835554901284072e-02f, + 2.384125977240247538e-02f, + 2.365046449923850422e-02f, + 2.343620254196809860e-02f, + 2.319872986687494115e-02f, + 2.293832529749150265e-02f, + 2.265529019562997209e-02f, + 2.234994812038883921e-02f, + 2.202264446551434676e-02f, + 2.167374607551639937e-02f, + 2.130364084095871455e-02f, + 2.091273727336449839e-02f, + 2.050146406019705617e-02f, + 2.007026960039413541e-02f, + 1.961962152095459225e-02f, + 1.915000617509209774e-02f, + 1.866192812249098040e-02f, + 1.815590959221258585e-02f, + 1.763248992881976882e-02f, + 1.709222502230338045e-02f, + 1.653568672240555287e-02f, + 1.596346223795577085e-02f, + 1.537615352184286931e-02f, + 1.477437664226473150e-02f, + 1.415876114090650062e-02f, + 1.352994937871285740e-02f, + 1.288859586992923897e-02f, + 1.223536660509748700e-02f, + 1.157093836370297682e-02f, + 1.089599801717802338e-02f, + 1.021124182297453685e-02f, + 9.517374710428586071e-03f, + 8.815109559144568979e-03f, + 8.105166470632777995e-03f, + 7.388272033942047505e-03f, + 6.665158586030823715e-03f, + 5.936563467627156351e-03f, + 5.203228275329005968e-03f, + 4.465898110698729960e-03f, + 3.725320827109799334e-03f, + 2.982246275101344511e-03f, + 2.237425547001025122e-03f, + 1.491610221569002930e-03f, + 7.455516094238633746e-04f, + -4.603360121389620097e-17f, + -7.442960892099980894e-04f, + -1.486590660381493286e-03f, + -2.226140979308201089e-03f, + -2.962208314840183033e-03f, + -3.694058673076393295e-03f, + -4.420963525583790008e-03f, + -5.142200530928310413e-03f, + -5.857054248801788626e-03f, + -6.564816846046666980e-03f, + -7.264788793882578921e-03f, + -7.956279555653332503e-03f, + -8.638608264420137572e-03f, + -9.311104389740483545e-03f, + -9.973108392984011278e-03f, + -1.062397237054689761e-02f, + -1.126306068434249248e-02f, + -1.188975057895664926e-02f, + -1.250343278487292369e-02f, + -1.310351210718740250e-02f, + -1.368940799924666003e-02f, + -1.426055512066000397e-02f, + -1.481640387915378679e-02f, + -1.535642095575079358e-02f, + -1.588008981277712686e-02f, + -1.638691118421688533e-02f, + -1.687640354795164402e-02f, + -1.734810357944292433e-02f, + -1.780156658643218884e-02f, + -1.823636692425711220e-02f, + -1.865209839139694153e-02f, + -1.904837460488604042e-02f, + -1.942482935525157578e-02f, + -1.978111694065281395e-02f, + -2.011691247992323031e-02f, + -2.043191220423512186e-02f, + -2.072583372713042438e-02f, + -2.099841629268202337e-02f, + -2.124942100157323904e-02f, + -2.147863101490525214e-02f, + -2.168585173556427867e-02f, + -2.187091096700358173e-02f, + -2.203365904931835206e-02f, + -2.217396897251361007e-02f, + -2.229173646688911367e-02f, + -2.238688007048804385e-02f, + -2.245934117357874585e-02f, + -2.250908404016256636e-02f, + -2.253609580652320837e-02f, + -2.254038645685636430e-02f, + -2.252198877604117550e-02f, + -2.248095827963758273e-02f, + -2.241737312121652378e-02f, + -2.233133397715249616e-02f, + -2.222296390902992261e-02f, + -2.209240820383755882e-02f, + -2.193983419214646027e-02f, + -2.176543104448896288e-02f, + -2.156940954617817680e-02f, + -2.135200185082751848e-02f, + -2.111346121285143443e-02f, + -2.085406169924960626e-02f, + -2.057409788099558851e-02f, + -2.027388450437186615e-02f, + -1.995375614261341718e-02f, + -1.961406682823892828e-02f, + -1.925518966646928148e-02f, + -1.887751643015150166e-02f, + -1.848145713662151246e-02f, + -1.806743960696060095e-02f, + -1.763590900811298073e-02f, + -1.718732737835180352e-02f, + -1.672217313659431215e-02f, + -1.624094057608432493e-02f, + -1.574413934297350451e-02f, + -1.523229390034704089e-02f, + -1.470594297825480838e-02f, + -1.416563901031964515e-02f, + -1.361194755751050575e-02f, + -1.304544671967466062e-02f, + -1.246672653544142993e-02f, + -1.187638837111369521e-02f, + -1.127504429917872836e-02f, + -1.066331646707572613e-02f, + -1.004183645686986676e-02f, + -9.411244636485087758e-03f, + -8.772189503162801036e-03f, + -8.125327019812878665e-03f, + -7.471319944934195698e-03f, + -6.810837156787309839e-03f, + -6.144552972502608131e-03f, + -5.473146462815121210e-03f, + -4.797300763120759294e-03f, + -4.117702381546011793e-03f, + -3.435040504733359156e-03f, + -2.750006302037344939e-03f, + -2.063292228833295185e-03f, + -1.375591329636196821e-03f, + -6.875965417295367256e-04f, + -3.712671580871972529e-17f, + 6.865076563281155998e-04f, + 1.371237974366756743e-03f, + 2.053505374957837522e-03f, + 2.732627836105371629e-03f, + 3.407927571765508035e-03f, + 4.078731705322887272e-03f, + 4.744372937087731369e-03f, + 5.404190205152949872e-03f, + 6.057529338961288590e-03f, + 6.703743704936756392e-03f, + 7.342194843549852169e-03f, + 7.972253097187404283e-03f, + 8.593298228216065052e-03f, + 9.204720026634211766e-03f, + 9.805918906718476616e-03f, + 1.039630649208695898e-02f, + 1.097530618860973091e-02f, + 1.154235374461037682e-02f, + 1.209689779782041619e-02f, + 1.263840040855540407e-02f, + 1.316633757860326444e-02f, + 1.368019975532520915e-02f, + 1.417949232048846230e-02f, + 1.466373606336292788e-02f, + 1.513246763763515662e-02f, + 1.558524000170355243e-02f, + 1.602162284194235189e-02f, + 1.644120297853483154e-02f, + 1.684358475349722120e-02f, + 1.722839040053121898e-02f, + 1.759526039636302719e-02f, + 1.794385379324603749e-02f, + 1.827384853232209144e-02f, + 1.858494173755794940e-02f, + 1.887684998999094102e-02f, + 1.914930958204142525e-02f, + 1.940207675166573387e-02f, + 1.963492789614775663e-02f, + 1.984765976534554055e-02f, + 2.004008963423044992e-02f, + 2.021205545457873884e-02f, + 2.036341598569508388e-02f, + 2.049405090406888896e-02f, + 2.060386089188653500e-02f, + 2.069276770434292853e-02f, + 2.076071421571710346e-02f, + 2.080766444419874725e-02f, + 2.083360355547297926e-02f, + 2.083853784509219140e-02f, + 2.082249469968529276e-02f, + 2.078552253707531203e-02f, + 2.072769072539770024e-02f, + 2.064908948133232364e-02f, + 2.054982974758300454e-02f, + 2.043004304975895233e-02f, + 2.028988133283307627e-02f, + 2.012951677737172956e-02f, + 1.994914159575129214e-02f, + 1.974896780859568615e-02f, + 1.952922700168944689e-02f, + 1.929017006363938427e-02f, + 1.903206690457660832e-02f, + 1.875520615621007955e-02f, + 1.845989485356032758e-02f, + 1.814645809871968940e-02f, + 1.781523870700396292e-02f, + 1.746659683587628575e-02f, + 1.710090959704086561e-02f, + 1.671857065212146304e-02f, + 1.631998979235366534e-02f, + 1.590559250273780936e-02f, + 1.547581951111101986e-02f, + 1.503112632261381296e-02f, + 1.457198274004087128e-02f, + 1.409887237057541251e-02f, + 1.361229211942506165e-02f, + 1.311275167088374154e-02f, + 1.260077295736035038e-02f, + 1.207688961692321428e-02f, + 1.154164643992243444e-02f, + 1.099559880526047861e-02f, + 1.043931210689104556e-02f, + 9.873361171136581238e-03f, + 9.298329665421793330e-03f, + 8.714809499028142170e-03f, + 8.123400216482846645e-03f, + 7.524708384200954649e-03f, + 6.919346971004516206e-03f, + 6.307934723150263913e-03f, + 5.691095534499056308e-03f, + 5.069457812466930842e-03f, + 4.443653840398907248e-03f, + 3.814319137009273761e-03f, + 3.182091813536080255e-03f, + 2.547611929256090018e-03f, + 1.911520846010968415e-03f, + 1.274460582389453983e-03f, + 6.370731682176064472e-04f, + 1.081397080984820549e-16f, + -6.361188020413131080e-04f, + -1.270645034688974500e-03f, + -1.902943049573664223e-03f, + -2.532380387505061333e-03f, + -3.158328408659244208e-03f, + -3.780162917995376869e-03f, + -4.397264785285395425e-03f, + -5.009020559139008844e-03f, + -5.614823074421015914e-03f, + -6.214072052459541223e-03f, + -6.806174693455702487e-03f, + -7.390546260511059347e-03f, + -7.966610654700514993e-03f, + -8.533800980628097194e-03f, + -9.091560101911401459e-03f, + -9.639341186054086255e-03f, + -1.017660823817454450e-02f, + -1.070283662307290606e-02f, + -1.121751357513068974e-02f, + -1.172013869554890987e-02f, + -1.221022443644520679e-02f, + -1.268729657134461120e-02f, + -1.315089465161116758e-02f, + -1.360057244838422906e-02f, + -1.403589837959812528e-02f, + -1.445645592167801516e-02f, + -1.486184400552278267e-02f, + -1.525167739639943926e-02f, + -1.562558705739423154e-02f, + -1.598322049607744932e-02f, + -1.632424209406116086e-02f, + -1.664833341914373141e-02f, + -1.695519351975287997e-02f, + -1.724453920141957169e-02f, + -1.751610528503054487e-02f, + -1.776964484662796329e-02f, + -1.800492943854209438e-02f, + -1.822174929166297391e-02f, + -1.841991349867593691e-02f, + -1.859925017810457049e-02f, + -1.875960661902498217e-02f, + -1.890084940633438015e-02f, + -1.902286452647648438e-02f, + -1.912555745354639625e-02f, + -1.920885321571724064e-02f, + -1.927269644195031550e-02f, + -1.931705138897083646e-02f, + -1.934190194851057379e-02f, + -1.934725163483910423e-02f, + -1.933312355262460300e-02f, + -1.929956034518492611e-02f, + -1.924662412320928689e-02f, + -1.917439637405042932e-02f, + -1.908297785170610245e-02f, + -1.897248844762847511e-02f, + -1.884306704251837231e-02f, + -1.869487133928060194e-02f, + -1.852807767733529593e-02f, + -1.834288082849799481e-02f, + -1.813949377465985668e-02f, + -1.791814746751756518e-02f, + -1.767909057061923042e-02f, + -1.742258918401042023e-02f, + -1.714892655178226061e-02f, + -1.685840275283847015e-02f, + -1.655133437521590783e-02f, + -1.622805417430966263e-02f, + -1.588891071536682048e-02f, + -1.553426800063207637e-02f, + -1.516450508153929268e-02f, + -1.478001565636058098e-02f, + -1.438120765373634632e-02f, + -1.396850280252506793e-02f, + -1.354233618842332412e-02f, + -1.310315579781915797e-02f, + -1.265142204935544926e-02f, + -1.218760731368947504e-02f, + -1.171219542194896698e-02f, + -1.122568116339099642e-02f, + -1.072856977278602644e-02f, + -1.022137640805312678e-02f, + -9.704625618685933791e-03f, + -9.178850805514197561e-03f, + -8.644593672357078762e-03f, + -8.102403670126549079e-03f, + -7.552837433952721592e-03f, + -6.996458213902527305e-03f, + -6.433835299872929167e-03f, + -5.865543441244903435e-03f, + -5.292162261885334160e-03f, + -4.714275671091273240e-03f, + -4.132471271074346537e-03f, + -3.547339761581234756e-03f, + -2.959474342255256820e-03f, + -2.369470113338262643e-03f, + -1.777923475318417051e-03f, + -1.185431528126037071e-03f, + -5.925914704819672469e-04f, + -3.657082924657467151e-17f, + 5.917472853565048079e-04f, + 1.182056483865000056e-03f, + 1.770335984084810870e-03f, + 2.355997055758636289e-03f, + 2.938454436983550105e-03f, + 3.517126917070770645e-03f, + 4.091437914513436185e-03f, + 4.660816049491952121e-03f, + 5.224695710346304901e-03f, + 5.782517613461616614e-03f, + 6.333729356008878375e-03f, + 6.877785961000690458e-03f, + 7.414150414123792977e-03f, + 7.942294191823096386e-03f, + 8.461697780117830373e-03f, + 8.971851183644980604e-03f, + 9.472254424431190978e-03f, + 9.962418029908697709e-03f, + 1.044186350969892804e-02f, + 1.091012382070481734e-02f, + 1.136674382005683007e-02f, + 1.181128070548041059e-02f, + 1.224330444265740725e-02f, + 1.266239817917228644e-02f, + 1.306815864464697975e-02f, + 1.346019653668105442e-02f, + 1.383813689223166964e-02f, + 1.420161944407984794e-02f, + 1.455029896204724192e-02f, + 1.488384557864121625e-02f, + 1.520194509882482302e-02f, + 1.550429929362267742e-02f, + 1.579062617728919579e-02f, + 1.606066026778677283e-02f, + 1.631415283033408117e-02f, + 1.655087210380375498e-02f, + 1.677060350976731021e-02f, + 1.697314984400075458e-02f, + 1.715833145028389933e-02f, + 1.732598637634284386e-02f, + 1.747597051180499114e-02f, + 1.760815770805244929e-02f, + 1.772243987987905459e-02f, + 1.781872708887428242e-02f, + 1.789694760847562044e-02f, + 1.795704797064969285e-02f, + 1.799899299418070836e-02f, + 1.802276579456344244e-02f, + 1.802836777551610967e-02f, + 1.801581860214731406e-02f, + 1.798515615582916075e-02f, + 1.793643647084725012e-02f, + 1.786973365291627536e-02f, + 1.778513977966790505e-02f, + 1.768276478323590681e-02f, + 1.756273631508084576e-02f, + 1.742519959321422313e-02f, + 1.727031723200050592e-02f, + 1.709826905473061168e-02f, + 1.690925188917933447e-02f, + 1.670347934637539389e-02f, + 1.648118158282851561e-02f, + 1.624260504647542444e-02f, + 1.598801220662182665e-02f, + 1.571768126817298800e-02f, + 1.543190587046214431e-02f, + 1.513099477099881518e-02f, + 1.481527151447596842e-02f, + 1.448507408738769486e-02f, + 1.414075455862428936e-02f, + 1.378267870642391028e-02f, + 1.341122563207439514e-02f, + 1.302678736077021032e-02f, + 1.262976843004335811e-02f, + 1.222058546619729687e-02f, + 1.179966674918666268e-02f, + 1.136745176639336087e-02f, + 1.092439075576322714e-02f, + 1.047094423877575897e-02f, + 1.000758254372885632e-02f, + 9.534785319831791742e-03f, + 9.053041042603243369e-03f, + 8.562846511087114296e-03f, + 8.064706337396969349e-03f, + 7.559132429115091208e-03f, + 7.046643465073196971e-03f, + 6.527764365051815301e-03f, + 6.003025753936333010e-03f, + 5.472963420876755282e-03f, + 4.938117773999208156e-03f, + 4.399033291224269636e-03f, + 3.856257967746062627e-03f, + 3.310342760733056815e-03f, + 2.761841031809351716e-03f, + 2.211307987882755663e-03f, + 1.659300120877342261e-03f, + 1.106374646939666147e-03f, + 5.530889456780919066e-04f, + -2.562212629853384453e-17f, + -5.523361628926795478e-04f, + -1.103365028790336249e-03f, + -1.652534151487132074e-03f, + -2.199293704964780296e-03f, + -2.743097032196961139e-03f, + -3.283401190029548548e-03f, + -3.819667489593037233e-03f, + -4.351362031714790628e-03f, + -4.877956236795205104e-03f, + -5.398927368629055645e-03f, + -5.913759051650750720e-03f, + -6.421941781095417100e-03f, + -6.922973425571511859e-03f, + -7.416359721553146198e-03f, + -7.901614759304937882e-03f, + -8.378261459764673943e-03f, + -8.845832041915659832e-03f, + -9.303868480194682489e-03f, + -9.751922951488184790e-03f, + -1.018955827128389773e-02f, + -1.061634831855159944e-02f, + -1.103187844894640973e-02f, + -1.143574589593108516e-02f, + -1.182756015943418025e-02f, + -1.220694338166910739e-02f, + -1.257353070975459307e-02f, + -1.292697064479079137e-02f, + -1.326692537705756285e-02f, + -1.359307110701880525e-02f, + -1.390509835182837141e-02f, + -1.420271223705014962e-02f, + -1.448563277331862270e-02f, + -1.475359511768305730e-02f, + -1.500634981939290638e-02f, + -1.524366304989917265e-02f, + -1.546531681686134224e-02f, + -1.567110916196697012e-02f, + -1.586085434238630049e-02f, + -1.603438299570249595e-02f, + -1.619154228817324542e-02f, + -1.633219604619749049e-02f, + -1.645622487087768787e-02f, + -1.656352623558475859e-02f, + -1.665401456645098158e-02f, + -1.672762130573241662e-02f, + -1.678429495799975413e-02f, + -1.682400111913467597e-02f, + -1.684672248812496553e-02f, + -1.685245886166945525e-02f, + -1.684122711162113276e-02f, + -1.681306114531371312e-02f, + -1.676801184883415854e-02f, + -1.670614701332074833e-02f, + -1.662755124438308404e-02f, + -1.653232585475732791e-02f, + -1.642058874032645624e-02f, + -1.629247423965218475e-02f, + -1.614813297718115451e-02f, + -1.598773169030448180e-02f, + -1.581145304046532168e-02f, + -1.561949540852535824e-02f, + -1.541207267461631135e-02f, + -1.518941398271757108e-02f, + -1.495176349021716013e-02f, + -1.469938010272622657e-02f, + -1.443253719443338481e-02f, + -1.415152231429803349e-02f, + -1.385663687839711923e-02f, + -1.354819584875125403e-02f, + -1.322652739897053030e-02f, + -1.289197256707447573e-02f, + -1.254488489584905733e-02f, + -1.218563006111956712e-02f, + -1.181458548832869243e-02f, + -1.143213995781868463e-02f, + -1.103869319922974775e-02f, + -1.063465547543513724e-02f, + -1.022044715644565907e-02f, + -9.796498283722697084e-03f, + -9.363248125350869672e-03f, + -8.921144722528617441e-03f, + -8.470644427841999072e-03f, + -8.012211435799141551e-03f, + -7.546317306102053729e-03f, + -7.073440480148323294e-03f, + -6.594065791253660332e-03f, + -6.108683969096916598e-03f, + -5.617791138891340720e-03f, + -5.121888315793346122e-03f, + -4.621480895060380706e-03f, + -4.117078138476948368e-03f, + -3.609192657567809014e-03f, + -3.098339894123382839e-03f, + -2.585037598558611194e-03f, + -2.069805306636893476e-03f, + -1.553163815081216479e-03f, + -1.035634656603983328e-03f, + -5.177395748811913952e-04f, + -3.594753584560424697e-17f, + 5.170634750964393008e-04f, + 1.032931616641648070e-03f, + 1.547087070033249757e-03f, + 2.059014877257667187e-03f, + 2.568202991233530484e-03f, + 3.074142786564025911e-03f, + 3.576329566188138527e-03f, + 4.074263063429547048e-03f, + 4.567447938941549164e-03f, + 5.055394272060948803e-03f, + 5.537618046079833753e-03f, + 6.013641626959552108e-03f, + 6.482994235012814500e-03f, + 6.945212409090805589e-03f, + 7.399840462817311795e-03f, + 7.846430932424257321e-03f, + 8.284545015748243785e-03f, + 8.713753001960018382e-03f, + 9.133634691605685765e-03f, + 9.543779806553546671e-03f, + 9.943788389443802139e-03f, + 1.033327119225793331e-02f, + 1.071185005362884461e-02f, + 1.107915826452845684e-02f, + 1.143484092198099322e-02f, + 1.177855527046098826e-02f, + 1.210997103065078462e-02f, + 1.242877071524243864e-02f, + 1.273464993148456723e-02f, + 1.302731767018629021e-02f, + 1.330649658090683578e-02f, + 1.357192323307192076e-02f, + 1.382334836277147004e-02f, + 1.406053710501154602e-02f, + 1.428326921120452730e-02f, + 1.449133925169799296e-02f, + 1.468455680315914995e-02f, + 1.486274662064523792e-02f, + 1.502574879420732167e-02f, + 1.517341888988939583e-02f, + 1.530562807500203924e-02f, + 1.542226322756440338e-02f, + 1.552322702982500066e-02f, + 1.560843804578798157e-02f, + 1.567783078268716879e-02f, + 1.573135573636695247e-02f, + 1.576897942054480972e-02f, + 1.579068437994683369e-02f, + 1.579646918732351482e-02f, + 1.578634842436942021e-02f, + 1.576035264658639731e-02f, + 1.571852833214611861e-02f, + 1.566093781482364236e-02f, + 1.558765920108961048e-02f, + 1.549878627146459784e-02f, + 1.539442836625458041e-02f, + 1.527471025580193729e-02f, + 1.513977199540266459e-02f, + 1.498976876505400853e-02f, + 1.482487069421324286e-02f, + 1.464526267176276438e-02f, + 1.445114414139052512e-02f, + 1.424272888261022586e-02f, + 1.402024477765924718e-02f, + 1.378393356452596412e-02f, + 1.353405057637283200e-02f, + 1.327086446763305755e-02f, + 1.299465692707358656e-02f, + 1.270572237812851030e-02f, + 1.240436766682034841e-02f, + 1.209091173759783630e-02f, + 1.176568529743146629e-02f, + 1.142903046851825692e-02f, + 1.108130042995956500e-02f, + 1.072285904878491486e-02f, + 1.035408050070699311e-02f, + 9.975348881000042217e-03f, + 9.587057805905971689e-03f, + 9.189610004980062336e-03f, + 8.783416904796481281e-03f, + 8.368898204444107092e-03f, + 7.946481443246316417e-03f, + 7.516601561152745289e-03f, + 7.079700452249429281e-03f, + 6.636226511847269707e-03f, + 6.186634177609999508e-03f, + 5.731383465191587125e-03f, + 5.270939498854294337e-03f, + 4.805772037546594995e-03f, + 4.336354996921345552e-03f, + 3.863165967780911834e-03f, + 3.386685731435247395e-03f, + 2.907397772465186801e-03f, + 2.425787789381585267e-03f, + 1.942343203677738541e-03f, + 1.457552667765169528e-03f, + 9.719055722931030025e-04f, + 4.858915533437137995e-04f, + 8.998451329969168033e-17f, + -4.852804372203572384e-04f, + -9.694623365727714258e-04f, + -1.452059993443630213e-03f, + -1.932589906371710072e-03f, + -2.410571260246647390e-03f, + -2.885526406203937043e-03f, + -3.356981337736776681e-03f, + -3.824466162554774652e-03f, + -4.287515569716226875e-03f, + -4.745669291575628328e-03f, + -5.198472560085647988e-03f, + -5.645476557004205746e-03f, + -6.086238857560498199e-03f, + -6.520323867144547751e-03f, + -6.947303250588880534e-03f, + -7.366756353621596760e-03f, + -7.778270616075868595e-03f, + -8.181441976453041054e-03f, + -8.575875267442242128e-03f, + -8.961184602012178466e-03f, + -9.336993749696280778e-03f, + -9.702936502709572433e-03f, + -1.005865703153830532e-02f, + -1.040381022966105004e-02f, + -1.073806204706719697e-02f, + -1.106108981225218876e-02f, + -1.137258254238081648e-02f, + -1.167224124132068379e-02f, + -1.195977918526302392e-02f, + -1.223492219565827481e-02f, + -1.249740889920878534e-02f, + -1.274699097467286470e-02f, + -1.298343338624937185e-02f, + -1.320651460332445369e-02f, + -1.341602680637729757e-02f, + -1.361177607885452785e-02f, + -1.379358258483857035e-02f, + -1.396128073234834122e-02f, + -1.411471932212687332e-02f, + -1.425376168178382232e-02f, + -1.437828578517633127e-02f, + -1.448818435692682781e-02f, + -1.458336496199062575e-02f, + -1.466375008020243120e-02f, + -1.472927716574510063e-02f, + -1.477989869149929497e-02f, + -1.481558217824864229e-02f, + -1.483631020872940888e-02f, + -1.484208042652921528e-02f, + -1.483290551985472217e-02f, + -1.480881319020316278e-02f, + -1.476984610598764888e-02f, + -1.471606184118155226e-02f, + -1.464753279906179893e-02f, + -1.456434612114611976e-02f, + -1.446660358143379496e-02f, + -1.435442146607433973e-02f, + -1.422793043860267476e-02f, + -1.408727539089408773e-02f, + -1.393261528000593226e-02f, + -1.376412295108748671e-02f, + -1.358198494655285873e-02f, + -1.338640130172517699e-02f, + -1.317758532717458811e-02f, + -1.295576337798411137e-02f, + -1.272117461019173744e-02f, + -1.247407072466863269e-02f, + -1.221471569870679480e-02f, + -1.194338550559997762e-02f, + -1.166036782251413627e-02f, + -1.136596172695676817e-02f, + -1.106047738216157407e-02f, + -1.074423571171940345e-02f, + -1.041756806379570341e-02f, + -1.008081586528326509e-02f, + -9.734330266250949479e-03f, + -9.378471775056540852e-03f, + -9.013609884502808353e-03f, + -8.640122689421677812e-03f, + -8.258396496082181723e-03f, + -7.868825423824252902e-03f, + -7.471810999326916093e-03f, + -7.067761743930141109e-03f, + -6.657092754429278468e-03f, + -6.240225277775035030e-03f, + -5.817586280110769240e-03f, + -5.389608010588473400e-03f, + -4.956727560406810548e-03f, + -4.519386417521461217e-03f, + -4.078030017478383173e-03f, + -3.633107290827413370e-03f, + -3.185070207573783597e-03f, + -2.734373319130519765e-03f, + -2.281473298231648152e-03f, + -1.826828477275332062e-03f, + -1.370898385557953137e-03f, + -9.141432858685172996e-04f, + -4.570237109078288933e-04f, + -3.525929546010641032e-17f, + 4.564681634404971059e-04f, + 9.119222132217494076e-04f, + 1.365905160004667876e-03f, + 1.817962048792683442e-03f, + 2.267640413821652746e-03f, + 2.714490730398470830e-03f, + 3.158066863236440400e-03f, + 3.597926510843086571e-03f, + 4.033631645515631595e-03f, + 4.464748948511986122e-03f, + 4.890850239961540627e-03f, + 5.311512903093372658e-03f, + 5.726320302360849920e-03f, + 6.134862195051104215e-03f, + 6.536735135972274353e-03f, + 6.931542874822234357e-03f, + 7.318896745846920765e-03f, + 7.698416049407258259e-03f, + 8.069728425079554859e-03f, + 8.432470215927469551e-03f, + 8.786286823586514014e-03f, + 9.130833053819266409e-03f, + 9.465773452203021798e-03f, + 9.790782629625502387e-03f, + 1.010554557727417341e-02f, + 1.040975797081422800e-02f, + 1.070312646346415798e-02f, + 1.098536896768670043e-02f, + 1.125621492522658335e-02f, + 1.151540556523688447e-02f, + 1.176269415025001618e-02f, + 1.199784620976064760e-02f, + 1.222063976119941615e-02f, + 1.243086551809268608e-02f, + 1.262832708521319930e-02f, + 1.281284114054117608e-02f, + 1.298423760386959412e-02f, + 1.314235979189961462e-02f, + 1.328706455968696638e-02f, + 1.341822242831278503e-02f, + 1.353571769866840878e-02f, + 1.363944855125505048e-02f, + 1.372932713191544682e-02f, + 1.380527962342858322e-02f, + 1.386724630291150812e-02f, + 1.391518158498825965e-02f, + 1.394905405069915734e-02f, + 1.396884646213872837e-02f, + 1.397455576282423569e-02f, + 1.396619306381172501e-02f, + 1.394378361559041324e-02f, + 1.390736676580064946e-02f, + 1.385699590283483162e-02f, + 1.379273838539456926e-02f, + 1.371467545809203735e-02f, + 1.362290215319624312e-02f, + 1.351752717864009370e-02f, + 1.339867279241668298e-02f, + 1.326647466350721130e-02f, + 1.312108171949675703e-02f, + 1.296265598104565965e-02f, + 1.279137238340016282e-02f, + 1.260741858513507452e-02f, + 1.241099476433735194e-02f, + 1.220231340244982976e-02f, + 1.198159905600587605e-02f, + 1.174908811650030374e-02f, + 1.150502855865119002e-02f, + 1.124967967731822956e-02f, + 1.098331181335730246e-02f, + 1.070620606869824784e-02f, + 1.041865401094608894e-02f, + 1.012095736781302990e-02f, + 9.813427711702541953e-03f, + 9.496386134773091015e-03f, + 9.170162914817906255e-03f, + 8.835097172309763769e-03f, + 8.491536518964717603e-03f, + 8.139836698186228570e-03f, + 7.780361217764370299e-03f, + 7.413480975203700848e-03f, + 7.039573876068914819e-03f, + 6.659024445737531453e-03f, + 6.272223434958205251e-03f, + 5.879567419619150664e-03f, + 5.481458395132861143e-03f, + 5.078303365855517913e-03f, + 4.670513929954199853e-03f, + 4.258505860148748337e-03f, + 3.842698680752674144e-03f, + 3.423515241440691897e-03f, + 3.001381288178317595e-03f, + 2.576725031746534850e-03f, + 2.149976714294795244e-03f, + 1.721568174367767547e-03f, + 1.291932410834989269e-03f, + 8.615031461717679489e-04f, + 4.307143895238358311e-04f, + -1.330885637378024658e-17f, + -4.302067493707025154e-04f, + -8.594736065816692546e-04f, + -1.287369774051150230e-03f, + -1.713466340056074740e-03f, + -2.137336707761578608e-03f, + -2.558557021419832853e-03f, + -2.976706589314977430e-03f, + -3.391368303029395053e-03f, + -3.802129052617245642e-03f, + -4.208580137271933364e-03f, + -4.610317671079266870e-03f, + -5.006942983457264747e-03f, + -5.398063013881818258e-03f, + -5.783290700513624497e-03f, + -6.162245362338608992e-03f, + -6.534553074447273235e-03f, + -6.899847036085403514e-03f, + -7.257767931111701668e-03f, + -7.607964280510494219e-03f, + -7.950092786617034279e-03f, + -8.283818668712937539e-03f, + -8.608815989672613522e-03f, + -8.924767973335575449e-03f, + -9.231367312302321895e-03f, + -9.528316465851647404e-03f, + -9.815327947693202118e-03f, + -1.009212460327926254e-02f, + -1.035843987640591192e-02f, + -1.061401806485215774e-02f, + -1.085861456480968767e-02f, + -1.109199610387191955e-02f, + -1.131394096236322706e-02f, + -1.152423918279525498e-02f, + -1.172269276725893851e-02f, + -1.190911586256368677e-02f, + -1.208333493295382470e-02f, + -1.224518892024368394e-02f, + -1.239452939122312469e-02f, + -1.253122067220243524e-02f, + -1.265513997057455924e-02f, + -1.276617748328832784e-02f, + -1.286423649213934428e-02f, + -1.294923344579684485e-02f, + -1.302109802850088746e-02f, + -1.307977321537517543e-02f, + -1.312521531431613646e-02f, + -1.315739399443144331e-02f, + -1.317629230101505927e-02f, + -1.318190665705944176e-02f, + -1.317424685131877472e-02f, + -1.315333601295100296e-02f, + -1.311921057277957818e-02f, + -1.307192021122943054e-02f, + -1.301152779300470720e-02f, + -1.293810928858945414e-02f, + -1.285175368266549059e-02f, + -1.275256286955382679e-02f, + -1.264065153580123772e-02f, + -1.251614703004294733e-02f, + -1.237918922028838700e-02f, + -1.222993033878752925e-02f, + -1.206853481464722870e-02f, + -1.189517909438159854e-02f, + -1.171005145058865056e-02f, + -1.151335177896088170e-02f, + -1.130529138384659196e-02f, + -1.108609275258971849e-02f, + -1.085598931889009827e-02f, + -1.061522521543183453e-02f, + -1.036405501604320198e-02f, + -1.010274346765773629e-02f, + -9.831565212357994479e-03f, + -9.550804499793438818e-03f, + -9.260754890270634504e-03f, + -8.961718948827171807e-03f, + -8.654007930606116492e-03f, + -8.337941457855730515e-03f, + -8.013847188892069678e-03f, + -7.682060479362260927e-03f, + -7.342924036161159809e-03f, + -6.996787564356483392e-03f, + -6.644007407482657376e-03f, + -6.284946181578719530e-03f, + -5.919972403337297497e-03f, + -5.549460112752437578e-03f, + -5.173788490645978184e-03f, + -4.793341471466837367e-03f, + -4.408507351756223852e-03f, + -4.019678394675591307e-03f, + -3.627250431002364273e-03f, + -3.231622456996959773e-03f, + -2.833196229547020346e-03f, + -2.432375859003425757e-03f, + -2.029567400113351655e-03f, + -1.625178441472032017e-03f, + -1.219617693898372018e-03f, + -8.132945781564861155e-04f, + -4.066188124353766527e-04f, + -1.255183464083940188e-16f, + 4.061527825679167288e-04f, + 8.114313961304521613e-04f, + 1.215429048341218040e-03f, + 1.617740701170319395e-03f, + 2.017963476201877198e-03f, + 2.415697057295686061e-03f, + 2.810544090212879591e-03f, + 3.202110578810242990e-03f, + 3.590006277401872493e-03f, + 3.973845078907196904e-03f, + 4.353245398391843331e-03f, + 4.727830551627599208e-03f, + 5.097229128292139061e-03f, + 5.461075359441391712e-03f, + 5.819009478893136939e-03f, + 6.170678078162634105e-03f, + 6.515734454602445554e-03f, + 6.853838952405788033e-03f, + 7.184659296134813210e-03f, + 7.507870916452765928e-03f, + 7.823157267734456854e-03f, + 8.130210137252638636e-03f, + 8.428729945633239504e-03f, + 8.718426038289772001e-03f, + 8.999016967555456201e-03f, + 9.270230765236708165e-03f, + 9.531805205328850242e-03f, + 9.783488056638036182e-03f, + 1.002503732506817256e-02f, + 1.025622148534208536e-02f, + 1.047681970193385138e-02f, + 1.068662203900417294e-02f, + 1.088542965913968583e-02f, + 1.107305501070874297e-02f, + 1.124932200365959603e-02f, + 1.141406617359526365e-02f, + 1.156713483397583953e-02f, + 1.170838721630671625e-02f, + 1.183769459818636779e-02f, + 1.195494041909911376e-02f, + 1.206002038384902317e-02f, + 1.215284255354657367e-02f, + 1.223332742406933564e-02f, + 1.230140799193264051e-02f, + 1.235702980751857485e-02f, + 1.240015101562292471e-02f, + 1.243074238329506739e-02f, + 1.244878731495606579e-02f, + 1.245428185479465800e-02f, + 1.244723467645303394e-02f, + 1.242766706002694684e-02f, + 1.239561285641773217e-02f, + 1.235111843908625294e-02f, + 1.229424264327155618e-02f, + 1.222505669274922754e-02f, + 1.214364411421739454e-02f, + 1.205010063941019949e-02f, + 1.194453409505086793e-02f, + 1.182706428076905555e-02f, + 1.169782283511792108e-02f, + 1.155695308984023249e-02f, + 1.140460991254168763e-02f, + 1.124095953794393248e-02f, + 1.106617938789930186e-02f, + 1.088045788035994950e-02f, + 1.068399422750770586e-02f, + 1.047699822325738259e-02f, + 1.025969002036108101e-02f, + 1.003229989734856151e-02f, + 9.795068015547647028e-03f, + 9.548244166444083345e-03f, + 9.292087509640511306e-03f, + 9.026866301692599431e-03f, + 8.752857616103554630e-03f, + 8.470347054767179973e-03f, + 8.179628451162134981e-03f, + 7.881003565601285565e-03f, + 7.574781772854489656e-03f, + 7.261279742466121394e-03f, + 6.940821112095421283e-03f, + 6.613736154219424825e-03f, + 6.280361436535699012e-03f, + 5.941039476420039225e-03f, + 5.596118389785657496e-03f, + 5.245951534708952028e-03f, + 4.890897150183600751e-03f, + 4.531317990370226784e-03f, + 4.167580954717115850e-03f, + 3.800056714327025055e-03f, + 3.429119334948160357e-03f, + 3.055145896976142229e-03f, + 2.678516112847336220e-03f, + 2.299611942215314033e-03f, + 1.918817205297107184e-03f, + 1.536517194780740196e-03f, + 1.153098286686640977e-03f, + 7.689475505726472288e-04f, + 3.844523594784173275e-04f, + 7.713589460388476895e-17f, + -3.840227171148354263e-04f, + -7.672298454569775623e-04f, + -1.149236690145042554e-03f, + -1.529660193323781423e-03f, + -1.908119317586332020e-03f, + -2.284235426939436406e-03f, + -2.657632664926935610e-03f, + -3.027938329540865066e-03f, + -3.394783244538977351e-03f, + -3.757802126807970565e-03f, + -4.116633949400874508e-03f, + -4.470922299891161820e-03f, + -4.820315733689854894e-03f, + -5.164468121973136636e-03f, + -5.503038993878216732e-03f, + -5.835693872631364174e-03f, + -6.162104605273097113e-03f, + -6.481949685660806648e-03f, + -6.794914570427616589e-03f, + -7.100691987590134792e-03f, + -7.398982237502254970e-03f, + -7.689493485860325432e-03f, + -7.971942048476048787e-03f, + -8.246052667536663341e-03f, + -8.511558779087890353e-03f, + -8.768202771477389898e-03f, + -9.015736234510263528e-03f, + -9.253920199077345435e-03f, + -9.482525367023937612e-03f, + -9.701332331039827506e-03f, + -9.910131784361380508e-03f, + -1.010872472008433366e-02f, + -1.029692261989997165e-02f, + -1.047454763207558877e-02f, + -1.064143273851355688e-02f, + -1.079742191073151426e-02f, + -1.094237025462001418e-02f, + -1.107614414384500319e-02f, + -1.119862134177232113e-02f, + -1.130969111180511570e-02f, + -1.140925431603640253e-02f, + -1.149722350212928346e-02f, + -1.157352297835191959e-02f, + -1.163808887670370745e-02f, + -1.169086920408306425e-02f, + -1.173182388145829064e-02f, + -1.176092477101533564e-02f, + -1.177815569126870569e-02f, + -1.178351242013314648e-02f, + -1.177700268596670700e-02f, + -1.175864614660714416e-02f, + -1.172847435643616099e-02f, + -1.168653072151761875e-02f, + -1.163287044286803393e-02f, + -1.156756044792955386e-02f, + -1.149067931032693446e-02f, + -1.140231715800252288e-02f, + -1.130257556983401725e-02f, + -1.119156746085197413e-02f, + -1.106941695618434904e-02f, + -1.093625925386791653e-02f, + -1.079224047667651058e-02f, + -1.063751751312634955e-02f, + -1.047225784783175143e-02f, + -1.029663938139156396e-02f, + -1.011085024000046503e-02f, + -9.915088574987292874e-03f, + -9.709562352492116799e-03f, + -9.494489133505876546e-03f, + -9.270095844503068935e-03f, + -9.036618538908790590e-03f, + -8.794302149650478143e-03f, + -8.543400233051267126e-03f, + -8.284174704334627132e-03f, + -8.016895565012135613e-03f, + -7.741840622440153072e-03f, + -7.459295201834709003e-03f, + -7.169551851041272746e-03f, + -6.872910038367072844e-03f, + -6.569675843783693604e-03f, + -6.260161643820879619e-03f, + -5.944685790473217164e-03f, + -5.623572284449645554e-03f, + -5.297150443101252340e-03f, + -4.965754563364804634e-03f, + -4.629723580069068818e-03f, + -4.289400719951269245e-03f, + -3.945133151734599684e-03f, + -3.597271632626723118e-03f, + -3.246170151593960954e-03f, + -2.892185569777141942e-03f, + -2.535677258412258675e-03f, + -2.177006734621175950e-03f, + -1.816537295443911102e-03f, + -1.454633650479946480e-03f, + -1.091661553510198676e-03f, + -7.279874334719225624e-04f, + -3.639780251556599890e-04f, + -3.369908401361916715e-17f, + 3.635804026494091068e-04f, + 7.263977434430309238e-04f, + 1.088087749724279355e-03f, + 1.448287680655482423e-03f, + 1.806636690402828576e-03f, + 2.162776189022377980e-03f, + 2.516350200682577424e-03f, + 2.867005718868611067e-03f, + 3.214393058213963015e-03f, + 3.558166202608354332e-03f, + 3.897983149238446517e-03f, + 4.233506248216929377e-03f, + 4.564402537464701606e-03f, + 4.890344072516150664e-03f, + 5.211008250917694221e-03f, + 5.526078130903779376e-03f, + 5.835242744032488431e-03f, + 6.138197401474478412e-03f, + 6.434643993655418670e-03f, + 6.724291282955277560e-03f, + 7.006855189179749324e-03f, + 7.282059067523997259e-03f, + 7.549633978756757104e-03f, + 7.809318951363577316e-03f, + 8.060861235391183002e-03f, + 8.304016547750365032e-03f, + 8.538549308736993748e-03f, + 8.764232869544244173e-03f, + 8.980849730547869544e-03f, + 9.188191750152601561e-03f, + 9.386060344002900707e-03f, + 9.574266674365642868e-03f, + 9.752631829506541034e-03f, + 9.920986992890266226e-03f, + 1.007917360204479626e-02f, + 1.022704349694264145e-02f, + 1.036445905775955530e-02f, + 1.049129333188454291e-02f, + 1.060743015006561894e-02f, + 1.071276423158474926e-02f, + 1.080720127836987295e-02f, + 1.089065805795989307e-02f, + 1.096306247525190812e-02f, + 1.102435363297093844e-02f, + 1.107448188081278095e-02f, + 1.111340885322339295e-02f, + 1.114110749578882571e-02f, + 1.115756208022166719e-02f, + 1.116276820794095091e-02f, + 1.115673280225443556e-02f, + 1.113947408916339532e-02f, + 1.111102156682138194e-02f, + 1.107141596369005596e-02f, + 1.102070918544608043e-02f, + 1.095896425070500523e-02f, + 1.088625521563825124e-02f, + 1.080266708757151098e-02f, + 1.070829572766292780e-02f, + 1.060324774277076644e-02f, + 1.048764036663119362e-02f, + 1.036160133047638564e-02f, + 1.022526872323565802e-02f, + 1.007879084146987361e-02f, + 9.922326029202397854e-03f, + 9.756042507818011092e-03f, + 9.580118196210777107e-03f, + 9.394740521373458678e-03f, + 9.200106219628658571e-03f, + 8.996421128710744425e-03f, + 8.783899970919039138e-03f, + 8.562766127568535030e-03f, + 8.333251404975441923e-03f, + 8.095595792220260448e-03f, + 7.850047210942715306e-03f, + 7.596861257427847160e-03f, + 7.336300937249773911e-03f, + 7.068636392749921664e-03f, + 6.794144623630500764e-03f, + 6.513109200950242123e-03f, + 6.225819974820153910e-03f, + 5.932572776096196529e-03f, + 5.633669112378537902e-03f, + 5.329415858627153425e-03f, + 5.020124942711203311e-03f, + 4.706113026214525825e-03f, + 4.387701180821052503e-03f, + 4.065214560613866247e-03f, + 3.738982070617613389e-03f, + 3.409336031925057006e-03f, + 3.076611843746769430e-03f, + 2.741147642725723539e-03f, + 2.403283959864889810e-03f, + 2.063363375414229133e-03f, + 1.721730172063813159e-03f, + 1.378729986799676023e-03f, + 1.034709461766141576e-03f, + 6.900158944939007019e-04f, + 3.449968878405673157e-04f, + 0.000000000000000000e+00f, + -3.446276050693368302e-04f, + -6.885395064473497171e-04f, + -1.031390373933058213e-03f, + -1.372836314259132063e-03f, + -1.712535215489931510e-03f, + -2.050147089260192981e-03f, + -2.385334410513898287e-03f, + -2.717762454401503706e-03f, + -3.047099630002055894e-03f, + -3.373017810537275608e-03f, + -3.695192659748559091e-03f, + -4.013303954115152519e-03f, + -4.327035900590155311e-03f, + -4.636077449543945204e-03f, + -4.940122602601876300e-03f, + -5.238870715073626685e-03f, + -5.532026792676994140e-03f, + -5.819301782261442936e-03f, + -6.100412856246560135e-03f, + -6.375083690498107615e-03f, + -6.643044735364164385e-03f, + -6.904033479612515893e-03f, + -7.157794707005572452e-03f, + -7.404080745267220716e-03f, + -7.642651707196129220e-03f, + -7.873275723692764461e-03f, + -8.095729168475295640e-03f, + -8.309796874264679251e-03f, + -8.515272340233715279e-03f, + -8.711957930518144516e-03f, + -8.899665063600716020e-03f, + -9.078214392388751081e-03f, + -9.247435974810619408e-03f, + -9.407169434773821060e-03f, + -9.557264113329744237e-03f, + -9.697579209904895123e-03f, + -9.827983913467562213e-03f, + -9.948357523507136632e-03f, + -1.005858956071708186e-02f, + -1.015857986727966046e-02f, + -1.024823869666328068e-02f, + -1.032748679285360252e-02f, + -1.039625545894891021e-02f, + -1.045448661506321979e-02f, + -1.050213284548926623e-02f, + -1.053915743508587223e-02f, + -1.056553439486431802e-02f, + -1.058124847675941289e-02f, + -1.058629517758200196e-02f, + -1.058068073216014530e-02f, + -1.056442209568751386e-02f, + -1.053754691530808460e-02f, + -1.050009349097712034e-02f, + -1.045211072564902234e-02f, + -1.039365806485362080e-02f, + -1.032480542573286329e-02f, + -1.024563311561991173e-02f, + -1.015623174025468214e-02f, + -1.005670210173764852e-02f, + -9.947155086336527396e-03f, + -9.827711542269031153e-03f, + -9.698502147594538492e-03f, + -9.559667268359363368e-03f, + -9.411356807146858960e-03f, + -9.253730042196249908e-03f, + -9.086955457261344099e-03f, + -8.911210562389308004e-03f, + -8.726681705811039844e-03f, + -8.533563877139486997e-03f, + -8.332060502084964390e-03f, + -8.122383228901621996e-03f, + -7.904751706788885890e-03f, + -7.679393356479695225e-03f, + -7.446543133253041326e-03f, + -7.206443282618896044e-03f, + -6.959343088928202255e-03f, + -6.705498617166942392e-03f, + -6.445172448203926978e-03f, + -6.178633407762102944e-03f, + -5.906156289395311614e-03f, + -5.628021571754467968e-03f, + -5.344515130431467045e-03f, + -5.055927944681215189e-03f, + -4.762555799315829584e-03f, + -4.464698982081711544e-03f, + -4.162661976823887194e-03f, + -3.856753152753953674e-03f, + -3.547284450136960633e-03f, + -3.234571062715784710e-03f, + -2.918931117198290178e-03f, + -2.600685350131433544e-03f, + -2.280156782488628776e-03f, + -1.957670392303650399e-03f, + -1.633552785677109664e-03f, + -1.308131866494795974e-03f, + -9.817365051840280538e-04f, + -6.546962068479288350e-04f, + -3.273407791097072712e-04f, + 4.043570989833329463e-17f, + 3.269967137754016561e-04f, + 6.533206378577746144e-04f, + 9.786440702132328823e-04f, + 1.302640659735354979e-03f, + 1.624985733145793004e-03f, + 1.945356619862989578e-03f, + 2.263432974515657958e-03f, + 2.578897096781404205e-03f, + 2.891434248225943724e-03f, + 3.200732965834694743e-03f, + 3.506485371918194750e-03f, + 3.808387480088745985e-03f, + 4.106139497000982005e-03f, + 4.399446119558816405e-03f, + 4.688016827295758519e-03f, + 4.971566169637211575e-03f, + 5.249814047762459135e-03f, + 5.522485990789751178e-03f, + 5.789313426009380474e-03f, + 6.050033942903848549e-03f, + 6.304391550690290578e-03f, + 6.552136929139138963e-03f, + 6.793027672418951342e-03f, + 7.026828525731477169e-03f, + 7.253311614507366133e-03f, + 7.472256665937161355e-03f, + 7.683451222625906421e-03f, + 7.886690848162170725e-03f, + 8.081779324404252465e-03f, + 8.268528840294541229e-03f, + 8.446760172019297450e-03f, + 8.616302854343038317e-03f, + 8.776995342953978693e-03f, + 8.928685167666237238e-03f, + 9.071229076335495314e-03f, + 9.204493169351136636e-03f, + 9.328353024581554839e-03f, + 9.442693812655188201e-03f, + 9.547410402472212773e-03f, + 9.642407456851329745e-03f, + 9.727599518224548311e-03f, + 9.802911084305539202e-03f, + 9.868276673664756402e-03f, + 9.923640881156430005e-03f, + 9.968958423152556383e-03f, + 1.000419417254796474e-02f, + 1.002932318351319220e-02f, + 1.004433070597993659e-02f, + 1.004921218985568680e-02f, + 1.004397327897390071e-02f, + 1.002862979479642036e-02f, + 1.000320770989520693e-02f, + 9.967743111250705959e-03f, + 9.922282153414410666e-03f, + 9.866881001593018341e-03f, + 9.801605764722259168e-03f, + 9.726532418607795535e-03f, + 9.641746719220965420e-03f, + 9.547344106246909851e-03f, + 9.443429596991709252e-03f, + 9.330117670766156779e-03f, + 9.207532143871193647e-03f, + 9.075806035321471940e-03f, + 8.935081423451458893e-03f, + 8.785509293556969038e-03f, + 8.627249376736262007e-03f, + 8.460469980100025419e-03f, + 8.285347808531550937e-03f, + 8.102067778184653124e-03f, + 7.910822821914111069e-03f, + 7.711813686845882775e-03f, + 7.505248724294873164e-03f, + 7.291343672252590877e-03f, + 7.070321430670069122e-03f, + 6.842411829768484458e-03f, + 6.607851391620159567e-03f, + 6.366883085243799263e-03f, + 6.119756075469458441e-03f, + 5.866725465831302069e-03f, + 5.608052035751829104e-03f, + 5.344001972290637024e-03f, + 5.074846596729006530e-03f, + 4.800862086276046561e-03f, + 4.522329191175403912e-03f, + 4.239532947506496723e-03f, + 3.952762385971762653e-03f, + 3.662310236965878128e-03f, + 3.368472632229732935e-03f, + 3.071548803391624394e-03f, + 2.771840777700751261e-03f, + 2.469653071265261093e-03f, + 2.165292380101938724e-03f, + 1.859067269314046813e-03f, + 1.551287860709699411e-03f, + 1.242265519177247843e-03f, + 9.323125381350914204e-04f, + 6.217418243711637623e-04f, + 3.108665825923342669e-04f, + 6.717146213127583512e-17f, + -3.105450687918437651e-04f, + -6.204564161774286978e-04f, + -9.294227950051989944e-04f, + -1.237134230733572199e-03f, + -1.543282331983834290e-03f, + -1.847560599181306829e-03f, + -2.149664730972687243e-03f, + -2.449292928118728188e-03f, + -2.746146194552807982e-03f, + -3.039928635312416725e-03f, + -3.330347751041712323e-03f, + -3.617114728774667616e-03f, + -3.899944728711154593e-03f, + -4.178557166699342108e-03f, + -4.452675992145861683e-03f, + -4.722029961080219732e-03f, + -4.986352904100606331e-03f, + -5.245383988940638745e-03f, + -5.498867977395256908e-03f, + -5.746555476355140642e-03f, + -5.988203182702574526e-03f, + -6.223574121828233212e-03f, + -6.452437879537288590e-03f, + -6.674570827115577747e-03f, + -6.889756339339682574e-03f, + -7.097785005216259401e-03f, + -7.298454831247235333e-03f, + -7.491571437024912607e-03f, + -7.676948242966399882e-03f, + -7.854406650007556001e-03f, + -8.023776211084653054e-03f, + -8.184894794238147323e-03f, + -8.337608737184420971e-03f, + -8.481772993207853037e-03f, + -8.617251268236572961e-03f, + -8.743916148971660543e-03f, + -8.861649221950897853e-03f, + -8.970341183436947655e-03f, + -9.069891940027947907e-03f, + -9.160210699899310610e-03f, + -9.241216054595012552e-03f, + -9.312836051294730300e-03f, + -9.375008255495077131e-03f, + -9.427679804050792534e-03f, + -9.470807448532998427e-03f, + -9.504357588870533669e-03f, + -9.528306297250627166e-03f, + -9.542639332264922503e-03f, + -9.547352143296350749e-03f, + -9.542449865152758184e-03f, + -9.527947302962450418e-03f, + -9.503868907356978132e-03f, + -9.470248739975935248e-03f, + -9.427130429338478543e-03f, + -9.374567117135889846e-03f, + -9.312621395008722006e-03f, + -9.241365231882207529e-03f, + -9.160879891942457637e-03f, + -9.071255843345765041e-03f, + -8.972592657761846446e-03f, + -8.864998900862054027e-03f, + -8.748592013871738307e-03f, + -8.623498186314530051e-03f, + -8.489852220086737886e-03f, + -8.347797385005961690e-03f, + -8.197485265989208972e-03f, + -8.039075602022388231e-03f, + -7.872736117090798832e-03f, + -7.698642343250202899e-03f, + -7.516977436023509172e-03f, + -7.327931982316876480e-03f, + -7.131703801056546270e-03f, + -6.928497736752988953e-03f, + -6.718525446209536699e-03f, + -6.502005178594330234e-03f, + -6.279161549105892817e-03f, + -6.050225306465603983e-03f, + -5.815433094476260209e-03f, + -5.575027207895101936e-03f, + -5.329255342869666442e-03f, + -5.078370342195653343e-03f, + -4.822629935656748412e-03f, + -4.562296475713070905e-03f, + -4.297636668809446704e-03f, + -4.028921302576533685e-03f, + -3.756424969205551280e-03f, + -3.480425785277831575e-03f, + -3.201205108333276313e-03f, + -2.919047250469300383e-03f, + -2.634239189257616548e-03f, + -2.347070276275515198e-03f, + -2.057831943546030353e-03f, + -1.766817408183218516e-03f, + -1.474321375543928428e-03f, + -1.180639741184265909e-03f, + -8.860692919223937727e-04f, + -5.909074063099545391e-04f, + -2.954517548118973532e-04f, + -3.191480037364917763e-17f, + 2.951505029420960018e-04f, + 5.897030050987488040e-04f, + 8.833616617872707506e-04f, + 1.175831829311610932e-03f, + 1.466820360203527135e-03f, + 1.756035896659971941e-03f, + 2.043189161879899619e-03f, + 2.327993249011680189e-03f, + 2.610163907422230218e-03f, + 2.889419826001986703e-03f, + 3.165482913225662470e-03f, + 3.438078573687941564e-03f, + 3.706935980840707877e-03f, + 3.971788345662486015e-03f, + 4.232373180990945533e-03f, + 4.488432561260610569e-03f, + 4.739713377386114979e-03f, + 4.985967586540838471e-03f, + 5.226952456585757904e-03f, + 5.462430804905994176e-03f, + 5.692171231422111718e-03f, + 5.915948345547154125e-03f, + 6.133542986866762428e-03f, + 6.344742439328332831e-03f, + 6.549340638727800534e-03f, + 6.747138373295004030e-03f, + 6.937943477180526231e-03f, + 7.121571016657480234e-03f, + 7.297843468859207573e-03f, + 7.466590892878511958e-03f, + 7.627651093066531961e-03f, + 7.780869774372829901e-03f, + 7.926100689579733752e-03f, + 8.063205778290625028e-03f, + 8.192055297540449046e-03f, + 8.312527943906498212e-03f, + 8.424510967003927958e-03f, + 8.527900274261378949e-03f, + 8.622600526880391109e-03f, + 8.708525226889919993e-03f, + 8.785596795218742969e-03f, + 8.853746640715155422e-03f, + 8.912915220054325877e-03f, + 8.963052088482293539e-03f, + 9.004115941354405919e-03f, + 9.036074646436131896e-03f, + 9.058905266942841872e-03f, + 9.072594075305043249e-03f, + 9.077136557654227889e-03f, + 9.072537409034447248e-03f, + 9.058810519353838187e-03f, + 9.035978950099398527e-03f, + 9.004074901847999857e-03f, + 8.963139672615380235e-03f, + 8.913223607094592979e-03f, + 8.854386036843783780e-03f, + 8.786695211493011221e-03f, + 8.710228221048086500e-03f, + 8.625070909378744488e-03f, + 8.531317778987176914e-03f, + 8.429071887160986820e-03f, + 8.318444733624745513e-03f, + 8.199556139810507127e-03f, + 8.072534119878281914e-03f, + 7.937514743624142846e-03f, + 7.794641991421518389e-03f, + 7.644067601350621258e-03f, + 7.485950908677277416e-03f, + 7.320458677849650715e-03f, + 7.147764927190735675e-03f, + 6.968050746469218841e-03f, + 6.781504107540342781e-03f, + 6.588319668252944766e-03f, + 6.388698569828255708e-03f, + 6.182848227920212554e-03f, + 5.970982117573007432e-03f, + 5.753319552299874899e-03f, + 5.530085457510665325e-03f, + 5.301510138520690307e-03f, + 5.067829043382217347e-03f, + 4.829282520779390811e-03f, + 4.586115573237751521e-03f, + 4.338577605899722467e-03f, + 4.086922171123733884e-03f, + 3.831406709168724920e-03f, + 3.572292285227009461e-03f, + 3.309843323076701056e-03f, + 3.044327335621568181e-03f, + 2.776014652595465773e-03f, + 2.505178145706950243e-03f, + 2.232092951502079141e-03f, + 1.957036192228632423e-03f, + 1.680286694983667639e-03f, + 1.402124709426648972e-03f, + 1.122831624348555194e-03f, + 8.426896833769130903e-04f, + 5.619817001094690135e-04f, + 2.809907729590478470e-04f, + 0.000000000000000000e+00f, + -2.807078058981391780e-04f, + -5.608504013647517628e-04f, + -8.401463959614267896e-04f, + -1.118315534473937048e-03f, + -1.395078977776910336e-03f, + -1.670159581991349264e-03f, + -1.943282175656975462e-03f, + -2.214173834640201406e-03f, + -2.482564154505302687e-03f, + -2.748185520076693727e-03f, + -3.010773371923358872e-03f, + -3.270066469502342678e-03f, + -3.525807150696843618e-03f, + -3.777741587494939240e-03f, + -4.025620037552721069e-03f, + -4.269197091394013634e-03f, + -4.508231915003397400e-03f, + -4.742488487571064684e-03f, + -4.971735834156138824e-03f, + -5.195748253041122811e-03f, + -5.414305537549929381e-03f, + -5.627193192117104295e-03f, + -5.834202642391930586e-03f, + -6.035131439175642903e-03f, + -6.229783455990234309e-03f, + -6.417969080087524217e-03f, + -6.599505396713676100e-03f, + -6.774216366448439740e-03f, + -6.941932995450164623e-03f, + -7.102493498440299972e-03f, + -7.255743454271620582e-03f, + -7.401535953931983637e-03f, + -7.539731740839664825e-03f, + -7.670199343300234535e-03f, + -7.792815198996800620e-03f, + -7.907463771397596833e-03f, + -8.014037657972214804e-03f, + -8.112437690114479572e-03f, + -8.202573024681410890e-03f, + -8.284361227063144831e-03f, + -8.357728345709419457e-03f, + -8.422608978046395439e-03f, + -8.478946327725278564e-03f, + -8.526692253154843221e-03f, + -8.565807307276868815e-03f, + -8.596260768553768902e-03f, + -8.618030663145858153e-03f, + -8.631103778264705498e-03f, + -8.635475666698075314e-03f, + -8.631150642510639071e-03f, + -8.618141767933615305e-03f, + -8.596470831465410564e-03f, + -8.566168317214016212e-03f, + -8.527273365520683310e-03f, + -8.479833724913378445e-03f, + -8.423905695446994024e-03f, + -8.359554063495495263e-03f, + -8.286852028071115678e-03f, + -8.205881118751968267e-03f, + -8.116731105309984984e-03f, + -8.019499899138108831e-03f, + -7.914293446583613167e-03f, + -7.801225614304001070e-03f, + -7.680418066767507809e-03f, + -7.552000136030336853e-03f, + -7.416108683929066407e-03f, + -7.272887956833709935e-03f, + -7.122489433116511483e-03f, + -6.965071663495360846e-03f, + -6.800800104421189651e-03f, + -6.629846944682925639e-03f, + -6.452390925411476304e-03f, + -6.268617153670886545e-03f, + -6.078716909829352984e-03f, + -5.882887448911673298e-03f, + -5.681331796138239937e-03f, + -5.474258536861224822e-03f, + -5.261881601117059278e-03f, + -5.044420043014674268e-03f, + -4.822097815188827914e-03f, + -4.595143538549655710e-03f, + -4.363790267563028361e-03f, + -4.128275251306491068e-03f, + -3.888839690540101934e-03f, + -3.645728491045435640e-03f, + -3.399190013480753690e-03f, + -3.149475820010231263e-03f, + -2.896840417964342308e-03f, + -2.641541000791211135e-03f, + -2.383837186564273774e-03f, + -2.123990754310813977e-03f, + -1.862265378427587111e-03f, + -1.598926361455722204e-03f, + -1.334240365481033667e-03f, + -1.068475142436885140e-03f, + -8.018992635760308074e-04f, + -5.347818483891565765e-04f, + -2.673922932415280962e-04f, + -9.079959879021497232e-17f, + 2.671258950737993680e-04f, + 5.337167918945780664e-04f, + 7.995048963151187319e-04f, + 1.064223488808225876e-03f, + 1.327607191801307438e-03f, + 1.589392235393608270e-03f, + 1.849316721191365896e-03f, + 2.107120883999156515e-03f, + 2.362547351101621299e-03f, + 2.615341398882998439e-03f, + 2.865251206523531432e-03f, + 3.112028106524595324e-03f, + 3.355426831810707448e-03f, + 3.595205759164358736e-03f, + 3.831127148753331844e-03f, + 4.062957379511429948e-03f, + 4.290467180140932618e-03f, + 4.513431855509694376e-03f, + 4.731631508217054409e-03f, + 4.944851255114078407e-03f, + 5.152881438560737853e-03f, + 5.355517832217622683e-03f, + 5.552561841166678107e-03f, + 5.743820696166867384e-03f, + 5.929107641855835276e-03f, + 6.108242118712046975e-03f, + 6.281049938603144346e-03f, + 6.447363453748070593e-03f, + 6.607021718930415448e-03f, + 6.759870646807101223e-03f, + 6.905763156161545159e-03f, + 7.044559312960290212e-03f, + 7.176126464077911202e-03f, + 7.300339363562619553e-03f, + 7.417080291323936703e-03f, + 7.526239164128890706e-03f, + 7.627713638804527879e-03f, + 7.721409207549118775e-03f, + 7.807239285264657921e-03f, + 7.885125288831035251e-03f, + 7.954996708249086751e-03f, + 8.016791169590116797e-03f, + 8.070454489695856257e-03f, + 8.115940722582272102e-03f, + 8.153212197509116660e-03f, + 8.182239548684301991e-03f, + 8.203001736582492612e-03f, + 8.215486060864016227e-03f, + 8.219688164889776480e-03f, + 8.215612031835866150e-03f, + 8.203269972420074163e-03f, + 8.182682604260985149e-03f, + 8.153878822898639675e-03f, + 8.116895764514334491e-03f, + 8.071778760395010785e-03f, + 8.018581283196542925e-03f, + 7.957364885067841689e-03f, + 7.888199127706180952e-03f, + 7.811161504422274408e-03f, + 7.726337354300897436e-03f, + 7.633819768552089179e-03f, + 7.533709489153867997e-03f, + 7.426114799896956116e-03f, + 7.311151409948320190e-03f, + 7.188942330057568331e-03f, + 7.059617741539236935e-03f, + 6.923314858168461497e-03f, + 6.780177781137243509e-03f, + 6.630357347223709771e-03f, + 6.474010970332770391e-03f, + 6.311302476576784518e-03f, + 6.142401933065200215e-03f, + 5.967485470584375090e-03f, + 5.786735100350979578e-03f, + 5.600338525028452849e-03f, + 5.408488944204285429e-03f, + 5.211384854526987694e-03f, + 5.009229844711029882e-03f, + 4.802232385620449663e-03f, + 4.590605615646119360e-03f, + 4.374567121599736569e-03f, + 4.154338715345936607e-03f, + 3.930146206405986734e-03f, + 3.702219170760879478e-03f, + 3.470790716094145426e-03f, + 3.236097243712496643e-03f, + 2.998378207386371425e-03f, + 2.757875869357837798e-03f, + 2.514835053763304993e-03f, + 2.269502897720573724e-03f, + 2.022128600335697159e-03f, + 1.772963169880989280e-03f, + 1.522259169403208240e-03f, + 1.270270461017685608e-03f, + 1.017251949147536440e-03f, + 7.634593229678904650e-04f, + 5.091487983134088255e-04f, + 2.545768593114422170e-04f, + 5.893834195817279027e-17f, + -2.543255338102004309e-04f, + -5.081440021684953965e-04f, + -7.612004278544677463e-04f, + -1.013240852227075906e-03f, + -1.264012589796192692e-03f, + -1.513264481263194719e-03f, + -1.760747144774524840e-03f, + -2.006213225141300748e-03f, + -2.249417640770990170e-03f, + -2.490117828070589987e-03f, + -2.728073983073443527e-03f, + -2.963049300051106942e-03f, + -3.194810206873958253e-03f, + -3.423126596884991813e-03f, + -3.647772057057938316e-03f, + -3.868524092214752682e-03f, + -4.085164345078219975e-03f, + -4.297478811945374191e-03f, + -4.505258053766428641e-03f, + -4.708297402422947572e-03f, + -4.906397162001897849e-03f, + -5.099362804867554194e-03f, + -5.287005162340526442e-03f, + -5.469140609795000892e-03f, + -5.645591245996113387e-03f, + -5.816185066500464615e-03f, + -5.980756130952048950e-03f, + -6.139144724111944909e-03f, + -6.291197510464445995e-03f, + -6.436767682251153498e-03f, + -6.575715100791147336e-03f, + -6.707906430950256842e-03f, + -6.833215268632009988e-03f, + -6.951522261168058443e-03f, + -7.062715220494850468e-03f, + -7.166689229008634497e-03f, + -7.263346738000107591e-03f, + -7.352597658577248937e-03f, + -7.434359444991439289e-03f, + -7.508557170290937506e-03f, + -7.575123594233416392e-03f, + -7.633999223396016783e-03f, + -7.685132363431001340e-03f, + -7.728479163421451623e-03f, + -7.764003652300489888e-03f, + -7.791677767305085246e-03f, + -7.811481374443590177e-03f, + -7.823402280964399449e-03f, + -7.827436239820800487e-03f, + -7.823586946135632075e-03f, + -7.811866025676963803e-03f, + -7.792293015364394268e-03f, + -7.764895335833248320e-03f, + -7.729708256092200462e-03f, + -7.686774850317674296e-03f, + -7.636145946835978977e-03f, + -7.577880069352489409e-03f, + -7.512043370494353445e-03f, + -7.438709557741495296e-03f, + -7.357959811827293611e-03f, + -7.269882697699128586e-03f, + -7.174574068135403972e-03f, + -7.072136960122816021e-03f, + -6.962681484106240416e-03f, + -6.846324706228426420e-03f, + -6.723190523685911024e-03f, + -6.593409533333032847e-03f, + -6.457118893672204353e-03f, + -6.314462180376954545e-03f, + -6.165589235498591079e-03f, + -6.010656010514694655e-03f, + -5.849824403383760418e-03f, + -5.683262089774722935e-03f, + -5.511142348648704649e-03f, + -5.333643882371955774e-03f, + -5.150950631548067808e-03f, + -4.963251584760376527e-03f, + -4.770740583420043056e-03f, + -4.573616121923121738e-03f, + -4.372081143319735304e-03f, + -4.166342830707624179e-03f, + -3.956612394562757443e-03f, + -3.743104856225459159e-03f, + -3.526038827764110296e-03f, + -3.305636288440114059e-03f, + -3.082122358004176291e-03f, + -2.855725067054290869e-03f, + -2.626675124688376134e-03f, + -2.395205683690529615e-03f, + -2.161552103486554573e-03f, + -1.925951711112042913e-03f, + -1.688643560434465851e-03f, + -1.449868189872311657e-03f, + -1.209867378858563115e-03f, + -9.688839032931976462e-04f, + -7.271612902323416720e-04f, + -4.849435720621983882e-04f, + -2.424750404039046129e-04f, + -2.993458375907816894e-17f, + 2.422374771728505677e-04f, + 4.839937973155881718e-04f, + 7.250260894964933667e-04f, + 9.650924493755287268e-04f, + 1.203952181715645022e-03f, + 1.441366041441651457e-03f, + 1.677096473002762708e-03f, + 1.910907847800708860e-03f, + 2.142566699447316300e-03f, + 2.371841956615023273e-03f, + 2.598505173249376302e-03f, + 2.822330755915376365e-03f, + 3.043096188049002060e-03f, + 3.260582250895563590e-03f, + 3.474573240909645862e-03f, + 3.684857183408437892e-03f, + 3.891226042261025642e-03f, + 4.093475925410680442e-03f, + 4.291407286024813764e-03f, + 4.484825119075430515e-03f, + 4.673539153157502297e-03f, + 4.857364037355267616e-03f, + 5.036119522974105353e-03f, + 5.209630639960896592e-03f, + 5.377727867838498661e-03f, + 5.540247300990066084e-03f, + 5.697030808130492709e-03f, + 5.847926185810888196e-03f, + 5.992787305808217578e-03f, + 6.131474256255946623e-03f, + 6.263853476381850416e-03f, + 6.389797884721984053e-03f, + 6.509187000688825345e-03f, + 6.621907059378241700e-03f, + 6.727851119505293652e-03f, + 6.826919164367567169e-03f, + 6.919018195741605953e-03f, + 7.004062320623680518e-03f, + 7.081972830736373535e-03f, + 7.152678274725585150e-03f, + 7.216114522985169963e-03f, + 7.272224825048948307e-03f, + 7.320959859500953196e-03f, + 7.362277776360223042e-03f, + 7.396144231905143855e-03f, + 7.422532415909789162e-03f, + 7.441423071271871179e-03f, + 7.452804506020377015e-03f, + 7.456672597697913858e-03f, + 7.453030790120977571e-03f, + 7.441890082528809791e-03f, + 7.423269011139091954e-03f, + 7.397193623136587293e-03f, + 7.363697443128093892e-03f, + 7.322821432105069799e-03f, + 7.274613938962194541e-03f, + 7.219130644628227352e-03f, + 7.156434498872478629e-03f, + 7.086595649857397282e-03f, + 7.009691366515777115e-03f, + 6.925805953836947082e-03f, + 6.835030661154887534e-03f, + 6.737463583536625229e-03f, + 6.633209556377676723e-03f, + 6.522380043316587661e-03f, + 6.405093017587785986e-03f, + 6.281472836939533053e-03f, + 6.151650112247645033e-03f, + 6.015761569964638532e-03f, + 5.873949908548246022e-03f, + 5.726363649019010349e-03f, + 5.573156979804561387e-03f, + 5.414489596030440909e-03f, + 5.250526533426200064e-03f, + 5.081437997018541791e-03f, + 4.907399184788277351e-03f, + 4.728590106474792054e-03f, + 4.545195397714440512e-03f, + 4.357404129703668430e-03f, + 4.165409614584718312e-03f, + 3.969409206751546570e-03f, + 3.769604100281869798e-03f, + 3.566199122702250202e-03f, + 3.359402525296319511e-03f, + 3.149425770172853845e-03f, + 2.936483314308355533e-03f, + 2.720792390786955402e-03f, + 2.502572787458282825e-03f, + 2.282046623241240982e-03f, + 2.059438122297536054e-03f, + 1.834973386307630792e-03f, + 1.608880165078690333e-03f, + 1.381387625716168745e-03f, + 1.152726120594538663e-03f, + 9.231269543609431621e-04f, + 6.928221502061572470e-04f, + 4.620442156413446209e-04f, + 2.310259080137343159e-04f, + 0.000000000000000000e+00f, + -2.308009546876257196e-04f, + -4.611448551480424674e-04f, + -6.908002864531671621e-04f, + -9.195367518942560445e-04f, + -1.147124904077175120e-03f, + -1.373336774636224914e-03f, + -1.597946002337608667e-03f, + -1.820728059342699347e-03f, + -2.041460475406135615e-03f, + -2.259923059786094965e-03f, + -2.475898120643176686e-03f, + -2.689170681712491420e-03f, + -2.899528696030911467e-03f, + -3.106763256509465377e-03f, + -3.310668803139505106e-03f, + -3.511043326630707874e-03f, + -3.707688568276315544e-03f, + -3.900410215849520103e-03f, + -4.089018095338427944e-03f, + -4.273326358329034881e-03f, + -4.453153664852741063e-03f, + -4.628323361519555770e-03f, + -4.798663654760284072e-03f, + -4.964007779010489244e-03f, + -5.124194159669920833e-03f, + -5.279066570679284004e-03f, + -5.428474286561691883e-03f, + -5.572272228779376162e-03f, + -5.710321106265994241e-03f, + -5.842487549997011850e-03f, + -5.968644241469281582e-03f, + -6.088670034966893116e-03f, + -6.202450073495178670e-03f, + -6.309875898273007572e-03f, + -6.410845551679807824e-03f, + -6.505263673558881257e-03f, + -6.593041590787944613e-03f, + -6.674097400032071199e-03f, + -6.748356043603334110e-03f, + -6.815749378356467103e-03f, + -6.876216237559267495e-03f, + -6.929702485681070272e-03f, + -6.976161066051603243e-03f, + -7.015552041349363589e-03f, + -7.047842626885069371e-03f, + -7.073007216654443596e-03f, + -7.091027402140489926e-03f, + -7.101891983853740598e-03f, + -7.105596975605809294e-03f, + -7.102145601518914352e-03f, + -7.091548285781580294e-03f, + -7.073822635167690588e-03f, + -7.048993414343677349e-03f, + -7.017092513995498021e-03f, + -6.978158911814610725e-03f, + -6.932238626389115345e-03f, + -6.879384664053103844e-03f, + -6.819656958754997597e-03f, + -6.753122305011623888e-03f, + -6.679854284022603873e-03f, + -6.599933183026034100e-03f, + -6.513445907982721647e-03f, + -6.420485889683830161e-03f, + -6.321152983382738975e-03f, + -6.215553362058191117e-03f, + -6.103799403422135138e-03f, + -5.986009570792679216e-03f, + -5.862308287957658688e-03f, + -5.732825808160025433e-03f, + -5.597698077343937588e-03f, + -5.457066591803097846e-03f, + -5.311078250381432928e-03f, + -5.159885201379617314e-03f, + -5.003644684325990639e-03f, + -4.842518866777322309e-03f, + -4.676674676317842463e-03f, + -4.506283627929590085e-03f, + -4.331521646914106120e-03f, + -4.152568887545756218e-03f, + -3.969609547645198966e-03f, + -3.782831679262896318e-03f, + -3.592426995666025014e-03f, + -3.398590674828782209e-03f, + -3.201521159624679935e-03f, + -3.001419954927217991e-03f, + -2.798491421825367344e-03f, + -2.592942569162944196e-03f, + -2.384982842615481630e-03f, + -2.174823911519171114e-03f, + -1.962679453667881199e-03f, + -1.748764938296653790e-03f, + -1.533297407473102874e-03f, + -1.316495256117520629e-03f, + -1.098578010873439530e-03f, + -8.797661080547270916e-04f, + -6.602806708906880156e-04f, + -4.403432862964624440e-04f, + -2.201757813928862664e-04f, + 2.040351603294562245e-17f, + 2.199624206685035094e-04f, + 4.394902728878673139e-04f, + 6.583630006562409291e-04f, + 8.763609210572648189e-04f, + 1.093265444530637075e-03f, + 1.308859293828115375e-03f, + 1.522926721436776171e-03f, + 1.735253725253141800e-03f, + 1.945628262290407520e-03f, + 2.153840460208438813e-03f, + 2.359682826453400172e-03f, + 2.562950454799774267e-03f, + 2.763441229090153693e-03f, + 2.960956023969243955e-03f, + 3.155298902413077380e-03f, + 3.346277309858471712e-03f, + 3.533702264740658325e-03f, + 3.717388545249705484e-03f, + 3.897154872122122679e-03f, + 4.072824087288320731e-03f, + 4.244223328198080784e-03f, + 4.411184197655197183e-03f, + 4.573542928992711636e-03f, + 4.731140546427802310e-03f, + 4.883823020440311580e-03f, + 5.031441418021543807e-03f, + 5.173852047649186298e-03f, + 5.310916598845810341e-03f, + 5.442502276186440141e-03f, + 5.568481927626215550e-03f, + 5.688734167023349123e-03f, + 5.803143490740288873e-03f, + 5.911600388211953397e-03f, + 6.014001446374228968e-03f, + 6.110249447855176444e-03f, + 6.200253462834825341e-03f, + 6.283928934487773878e-03f, + 6.361197757929115161e-03f, + 6.431988352589909121e-03f, + 6.496235727955871307e-03f, + 6.553881542609762793e-03f, + 6.604874156524493181e-03f, + 6.649168676560485158e-03f, + 6.686726995128343919e-03f, + 6.717517821984657529e-03f, + 6.741516709135119897e-03f, + 6.758706068827057510e-03f, + 6.769075184619558622e-03f, + 6.772620215526905380e-03f, + 6.769344193237896226e-03f, + 6.759257012420358431e-03f, + 6.742375414127462462e-03f, + 6.718722962329050537e-03f, + 6.688330013598418541e-03f, + 6.651233679991463629e-03f, + 6.607477785162285504e-03f, + 6.557112813765961223e-03f, + 6.500195854205608435e-03f, + 6.436790534788347680e-03f, + 6.366966953360074857e-03f, + 6.290801600496780284e-03f, + 6.208377276335759996e-03f, + 6.119783001136048020e-03f, + 6.025113919665214118e-03f, + 5.924471199513612826e-03f, + 5.817961923445152776e-03f, + 5.705698975897815182e-03f, + 5.587800923754974829e-03f, + 5.464391891511682919e-03f, + 5.335601430968130686e-03f, + 5.201564385586319485e-03f, + 5.062420749651009438e-03f, + 4.918315522382780622e-03f, + 4.769398557154420036e-03f, + 4.615824405966431621e-03f, + 4.457752159344428866e-03f, + 4.295345281821967565e-03f, + 4.128771443180331673e-03f, + 3.958202345618636216e-03f, + 3.783813547031247577e-03f, + 3.605784280576109987e-03f, + 3.424297270716869252e-03f, + 3.239538545929211699e-03f, + 3.051697248262471695e-03f, + 2.860965439950404268e-03f, + 2.667537907270099533e-03f, + 2.471611961848510855e-03f, + 2.273387239617670301e-03f, + 2.073065497626217380e-03f, + 1.870850408910636978e-03f, + 1.666947355636944159e-03f, + 1.461563220720618573e-03f, + 1.254906178138427263e-03f, + 1.047185482141736864e-03f, + 8.386112555867926812e-04f, + 6.293942775949764364e-04f, + 4.197457707565461658e-04f, + 2.098771880941680316e-04f, + 5.182902902306673378e-17f, + -2.096745186397723764e-04f, + -4.189355009176130525e-04f, + -6.275726997620592390e-04f, + -8.353766989667140222e-04f, + -1.042139123179063390e-03f, + -1.247652846640042714e-03f, + -1.451712200463105501e-03f, + -1.654113178248326063e-03f, + -1.854653639823899535e-03f, + -2.053133512912701415e-03f, + -2.249354992523720179e-03f, + -2.443122737868256775e-03f, + -2.634244066605816777e-03f, + -2.822529146228016077e-03f, + -3.007791182387730897e-03f, + -3.189846603989948855e-03f, + -3.368515244858865266e-03f, + -3.543620521803565997e-03f, + -3.714989608904360665e-03f, + -3.882453607850389066e-03f, + -4.045847714158852700e-03f, + -4.205011379113398479e-03f, + -4.359788467263430063e-03f, + -4.510027409328340973e-03f, + -4.655581350359307320e-03f, + -4.796308293012311458e-03f, + -4.932071235793691541e-03f, + -5.062738306144363987e-03f, + -5.188182888232652744e-03f, + -5.308283745332808071e-03f, + -5.422925136671735008e-03f, + -5.531996928630324509e-03f, + -5.635394700194489362e-03f, + -5.733019842553966489e-03f, + -5.824779652754896557e-03f, + -5.910587421317968493e-03f, + -5.990362513738736391e-03f, + -6.064030445795148827e-03f, + -6.131522952591644815e-03f, + -6.192778051276466925e-03f, + -6.247740097375581447e-03f, + -6.296359834692139695e-03f, + -6.338594438727926730e-03f, + -6.374407553588771515e-03f, + -6.403769322343668378e-03f, + -6.426656410812841419e-03f, + -6.443052024767408938e-03f, + -6.452945920529682723e-03f, + -6.456334408969627466e-03f, + -6.453220352899971361e-03f, + -6.443613157878890461e-03f, + -6.427528756435856722e-03f, + -6.404989585742853347e-03f, + -6.376024558759821499e-03f, + -6.340669028889607886e-03f, + -6.298964748184136819e-03f, + -6.250959819150409338e-03f, + -6.196708640210494418e-03f, + -6.136271844877025546e-03f, + -6.069716234711278365e-03f, + -5.997114706136989597e-03f, + -5.918546171190292200e-03f, + -5.834095472290020540e-03f, + -5.743853291122007730e-03f, + -5.647916051732237638e-03f, + -5.546385817934258548e-03f, + -5.439370185137868373e-03f, + -5.326982166714451343e-03f, + -5.209340075018284791e-03f, + -5.086567397188134117e-03f, + -4.958792665860112768e-03f, + -4.826149324926455597e-03f, + -4.688775590479438843e-03f, + -4.546814307086526931e-03f, + -4.400412799544136007e-03f, + -4.249722720265064653e-03f, + -4.094899892456855747e-03f, + -3.936104149252287777e-03f, + -3.773499168959473186e-03f, + -3.607252306599120252e-03f, + -3.437534421903807366e-03f, + -3.264519703955130747e-03f, + -3.088385492637782913e-03f, + -2.909312097094693232e-03f, + -2.727482611368168587e-03f, + -2.543082727414555134e-03f, + -2.356300545685272984e-03f, + -2.167326383463741464e-03f, + -1.976352581158412423e-03f, + -1.783573306742843468e-03f, + -1.589184358546649181e-03f, + -1.393382966593760411e-03f, + -1.196367592691694598e-03f, + -9.983377294733853085e-04f, + -7.994936985940647280e-04f, + -6.000364482887320626e-04f, + -4.001673504937983648e-04f, + -2.000879977366511349e-04f, + -2.778966336884198701e-17f, + 1.998952182369787911e-04f, + 3.993966205749271080e-04f, + 5.983037606844037121e-04f, + 7.964169835089038611e-04f, + 9.935376254762236150e-04f, + 1.189468213520454305e-03f, + 1.384012662713176006e-03f, + 1.576976472307146200e-03f, + 1.768166919997466715e-03f, + 1.957393254204812128e-03f, + 2.144466884189903406e-03f, + 2.329201567810756240e-03f, + 2.511413596733711156e-03f, + 2.690921978917853227e-03f, + 2.867548618186650019e-03f, + 3.041118490714745520e-03f, + 3.211459818250186199e-03f, + 3.378404237904315821e-03f, + 3.541786968339587227e-03f, + 3.701446972192292979e-03f, + 3.857227114570970297e-03f, + 4.008974317473392411e-03f, + 4.156539709971333353e-03f, + 4.299778774016645676e-03f, + 4.438551485724410994e-03f, + 4.572722451997321066e-03f, + 4.702161042356552134e-03f, + 4.826741515851794284e-03f, + 4.946343142927884552e-03f, + 5.060850322128870871e-03f, + 5.170152691528663233e-03f, + 5.274145234779758183e-03f, + 5.372728381679093071e-03f, + 5.465808103155446809e-03f, + 5.553296000587267314e-03f, + 5.635109389366979755e-03f, + 5.711171376633489283e-03f, + 5.781410933099281717e-03f, + 5.845762958906964256e-03f, + 5.904168343452670387e-03f, + 5.956574019124233517e-03f, + 6.002933008903923832e-03f, + 6.043204467795012733e-03f, + 6.077353718035662794e-03f, + 6.105352278070978224e-03f, + 6.127177885260168266e-03f, + 6.142814512301600360e-03f, + 6.152252377365692929e-03f, + 6.155487947931146189e-03f, + 6.152523938326903176e-03f, + 6.143369300988309016e-03f, + 6.128039211442289080e-03f, + 6.106555047042762537e-03f, + 6.078944359483547284e-03f, + 6.045240841122706543e-03f, + 6.005484285157759554e-03f, + 5.959720539698134222e-03f, + 5.908001455786886062e-03f, + 5.850384829429483569e-03f, + 5.786934337694401610e-03f, + 5.717719468954846757e-03f, + 5.642815447348050774e-03f, + 5.562303151533275723e-03f, + 5.476269027836244349e-03f, + 5.384804997872509429e-03f, + 5.288008360747798245e-03f, + 5.185981689939928203e-03f, + 5.078832724969969611e-03f, + 4.966674257977718963e-03f, + 4.849624015320279195e-03f, + 4.727804534317043249e-03f, + 4.601343035271158316e-03f, + 4.470371288899312352e-03f, + 4.335025479308940791e-03f, + 4.195446062664641082e-03f, + 4.051777621689569946e-03f, + 3.904168716153416478e-03f, + 3.752771729500774690e-03f, + 3.597742711777335116e-03f, + 3.439241219017221893e-03f, + 3.277430149254536695e-03f, + 3.112475575329156242e-03f, + 2.944546574657440699e-03f, + 2.773815056141443278e-03f, + 2.600455584395403811e-03f, + 2.424645201466829776e-03f, + 2.246563246236072363e-03f, + 2.066391171676635035e-03f, + 1.884312360164382659e-03f, + 1.700511937020543225e-03f, + 1.515176582480621701e-03f, + 1.328494342278832389e-03f, + 1.140654437039362876e-03f, + 9.518470706689883707e-04f, + 7.622632379441338004e-04f, + 5.720945314859912732e-04f, + 3.815329483207086005e-04f, + 1.907706962172203138e-04f, + 0.000000000000000000e+00f, + -1.905870919690720166e-04f, + -3.807989009460705778e-04f, + -5.704443104011880719e-04f, + -7.593329578651235225e-04f, + -9.472754258310465579e-04f, + -1.134083431521770496e-03f, + -1.319570015332951216e-03f, + -1.503549727762363468e-03f, + -1.685838814639319377e-03f, + -1.866255400470208034e-03f, + -2.044619669715354044e-03f, + -2.220754045819160229e-03f, + -2.394483367813274831e-03f, + -2.565635064319175124e-03f, + -2.734039324775422008e-03f, + -2.899529267722648820e-03f, + -3.061941105977069883e-03f, + -3.221114308530460043e-03f, + -3.376891759017279938e-03f, + -3.529119910591425012e-03f, + -3.677648937060845960e-03f, + -3.822332880132129837e-03f, + -3.963029792618880109e-03f, + -4.099601877475613464e-03f, + -4.231915622519577709e-03f, + -4.359841930709697395e-03f, + -4.483256245856345398e-03f, + -4.602038673638307598e-03f, + -4.716074097811356024e-03f, + -4.825252291494681184e-03f, + -4.929468023428436492e-03f, + -5.028621159100716588e-03f, + -5.122616756646161500e-03f, + -5.211365157425208207e-03f, + -5.294782071198274320e-03f, + -5.372788655813301971e-03f, + -5.445311591332913613e-03f, + -5.512283148530877468e-03f, + -5.573641251695150671e-03f, + -5.629329535678900300e-03f, + -5.679297397148663600e-03f, + -5.723500039982650292e-03f, + -5.761898514779588421e-03f, + -5.794459752444061987e-03f, + -5.821156591819873563e-03f, + -5.841967801349767786e-03f, + -5.856878094745045400e-03f, + -5.865878140655318707e-03f, + -5.868964566334378651e-03f, + -5.866139955304165016e-03f, + -5.857412839025080524e-03f, + -5.842797682586693166e-03f, + -5.822314864439076185e-03f, + -5.795990650190794430e-03f, + -5.763857160505719661e-03f, + -5.725952333136686070e-03f, + -5.682319879139611715e-03f, + -5.633009233318153446e-03f, + -5.578075498953882598e-03f, + -5.517579386883428826e-03f, + -5.451587148989341623e-03f, + -5.380170506176684860e-03f, + -5.303406570913458962e-03f, + -5.221377764418140034e-03f, + -5.134171728582574354e-03f, + -5.041881232723846064e-03f, + -4.944604075264455272e-03f, + -4.842442980444399032e-03f, + -4.735505490173459210e-03f, + -4.623903851138305189e-03f, + -4.507754897281265882e-03f, + -4.387179927774727435e-03f, + -4.262304580617813123e-03f, + -4.133258701986374309e-03f, + -4.000176211472765767e-03f, + -3.863194963354634262e-03f, + -3.722456604035540191e-03f, + -3.578106425806113627e-03f, + -3.430293217074662122e-03f, + -3.279169109222944672e-03f, + -3.124889420243918709e-03f, + -2.967612495321265455e-03f, + -2.807499544515807202e-03f, + -2.644714477722959114e-03f, + -2.479423737071674658e-03f, + -2.311796126935456146e-03f, + -2.142002641728153745e-03f, + -1.970216291661061950e-03f, + -1.796611926638601179e-03f, + -1.621366058471044799e-03f, + -1.444656681584796090e-03f, + -1.266663092413158409e-03f, + -1.087565707650077398e-03f, + -9.075458815500990310e-04f, + -7.267857224613794324e-04f, + -5.454679087747773278e-04f, + -3.637755044768799673e-04f, + -1.818917744922234167e-04f, + -6.738072953108251659e-17f, + 1.817167060868667974e-04f, + 3.630755832968266678e-04f, + 5.438944072423667351e-04f, + 7.239916725462016735e-04f, + 9.031867748685456793e-04f, + 1.081300191851528036e-03f, + 1.258153662800393048e-03f, + 1.433570366922595502e-03f, + 1.607375099944760447e-03f, + 1.779394448933648617e-03f, + 1.949456965144877449e-03f, + 2.117393334728095468e-03f, + 2.283036547119419220e-03f, + 2.446222060952827054e-03f, + 2.606787967325983370e-03f, + 2.764575150259260348e-03f, + 2.919427444189183745e-03f, + 3.071191788339645758e-03f, + 3.219718377819110952e-03f, + 3.364860811295488155e-03f, + 3.506476235101599771e-03f, + 3.644425483631654871e-03f, + 3.778573215889237825e-03f, + 3.908788048053789092e-03f, + 4.034942681936477468e-03f, + 4.156914029198645506e-03f, + 4.274583331213595815e-03f, + 4.387836274453780008e-03f, + 4.496563101292173729e-03f, + 4.600658716111065936e-03f, + 4.700022786615127950e-03f, + 4.794559840251754780e-03f, + 4.884179355646818196e-03f, + 4.968795848967465581e-03f, + 5.048328955131142076e-03f, + 5.122703503783020661e-03f, + 5.191849589970850935e-03f, + 5.255702639451336616e-03f, + 5.314203468567116513e-03f, + 5.367298338639234223e-03f, + 5.414939004826021217e-03f, + 5.457082759404304449e-03f, + 5.493692469434578556e-03f, + 5.524736608777790041e-03f, + 5.550189284437050813e-03f, + 5.570030257202884111e-03f, + 5.584244956587067731e-03f, + 5.592824490035200498e-03f, + 5.595765646414466166e-03f, + 5.593070893778484716e-03f, + 5.584748371416978392e-03f, + 5.570811876203813663e-03f, + 5.551280843262597353e-03f, + 5.526180320974835580e-03f, + 5.495540940361090358e-03f, + 5.459398878871563054e-03f, + 5.417795818627875980e-03f, + 5.370778899163226178e-03f, + 5.318400664714218601e-03f, + 5.260719006122124147e-03f, + 5.197797097407722174e-03f, + 5.129703327088560444e-03f, + 5.056511224312396427e-03f, + 4.978299379887104678e-03f, + 4.895151362290443668e-03f, + 4.807155628749874669e-03f, + 4.714405431485941232e-03f, + 4.616998719219183103e-03f, + 4.515038034043206486e-03f, + 4.408630403773131437e-03f, + 4.297887229881802197e-03f, + 4.182924171140340805e-03f, + 4.063861023085189352e-03f, + 3.940821593436607748e-03f, + 3.813933573597338717e-03f, + 3.683328406365983000e-03f, + 3.549141150000212786e-03f, + 3.411510338771623577e-03f, + 3.270577840155389476e-03f, + 3.126488708801145999e-03f, + 2.979391037436725231e-03f, + 2.829435804855929236e-03f, + 2.676776721147767438e-03f, + 2.521570070325003087e-03f, + 2.363974550512310240e-03f, + 2.204151111858506946e-03f, + 2.042262792337711051e-03f, + 1.878474551605653284e-03f, + 1.712953103082745163e-03f, + 1.545866744432049548e-03f, + 1.377385186606322909e-03f, + 1.207679381635921347e-03f, + 1.036921349334177364e-03f, + 8.652840030934819777e-04f, + 6.929409749502218625e-04f, + 5.200664400946462904e-04f, + 3.468349410021595147e-04f, + 1.734212113648546741e-04f, + 4.550251594910668594e-17f, + -1.732541050876819561e-04f, + -3.461668523119788257e-04f, + -5.185645016036600878e-04f, + -6.902739988253162214e-04f, + -8.611231493274518678e-04f, + -1.030940790473021396e-03f, + -1.199556962955737344e-03f, + -1.366803080743145661e-03f, + -1.532512099472770496e-03f, + -1.696518683134078977e-03f, + -1.858659368870755474e-03f, + -2.018772729737835104e-03f, + -2.176699535252429873e-03f, + -2.332282909579588056e-03f, + -2.485368487193882845e-03f, + -2.635804565865009202e-03f, + -2.783442256814043243e-03f, + -2.928135631893509418e-03f, + -3.069741867644090218e-03f, + -3.208121386087987512e-03f, + -3.343137992118676207e-03f, + -3.474659007352662483e-03f, + -3.602555400312496166e-03f, + -3.726701912812024550e-03f, + -3.846977182422010779e-03f, + -3.963263860895238633e-03f, + -4.075448728436278055e-03f, + -4.183422803705368759e-03f, + -4.287081449448809645e-03f, + -4.386324473654241302e-03f, + -4.481056226133709602e-03f, + -4.571185690440540857e-03f, + -4.656626571033325307e-03f, + -4.737297375602708346e-03f, + -4.813121492483313744e-03f, + -4.884027263077780033e-03f, + -4.949948049224051072e-03f, + -5.010822295443905297e-03f, + -5.066593586014279949e-03f, + -5.117210696809050205e-03f, + -5.162627641864468188e-03f, + -5.202803714625973616e-03f, + -5.237703523840436977e-03f, + -5.267297024062328296e-03f, + -5.291559540748885272e-03f, + -5.310471789923680921e-03f, + -5.324019892394351271e-03f, + -5.332195382515387931e-03f, + -5.334995211492236412e-03f, + -5.332421745228884194e-03f, + -5.324482756726165410e-03f, + -5.311191413043757879e-03f, + -5.292566256844271830e-03f, + -5.268631182543137906e-03f, + -5.239415407093645990e-03f, + -5.204953435441478891e-03f, + -5.165285020688987344e-03f, + -5.120455119014034190e-03f, + -5.070513839394155328e-03f, + -5.015516388191593698e-03f, + -4.955523008659636248e-03f, + -4.890598915436772734e-03f, + -4.820814224098224007e-03f, + -4.746243875842361994e-03f, + -4.666967557390416105e-03f, + -4.583069616186550947e-03f, + -4.494638970986890303e-03f, + -4.401769017932832123e-03f, + -4.304557532207274433e-03f, + -4.203106565376605631e-03f, + -4.097522338526705075e-03f, + -3.987915131304275475e-03f, + -3.874399166978647214e-03f, + -3.757092493644813031e-03f, + -3.636116861689554780e-03f, + -3.511597597648849663e-03f, + -3.383663474586599915e-03f, + -3.252446579127917913e-03f, + -3.118082175285466148e-03f, + -2.980708565217376257e-03f, + -2.840466947061273412e-03f, + -2.697501269989864385e-03f, + -2.551958086636046431e-03f, + -2.403986403039817116e-03f, + -2.253737526269895732e-03f, + -2.101364909875016573e-03f, + -1.947023997324411840e-03f, + -1.790872063594110223e-03f, + -1.633068055064607060e-03f, + -1.473772427887728434e-03f, + -1.313146984991218642e-03f, + -1.151354711883460216e-03f, + -9.885596114266794344e-04f, + -8.249265377453095672e-04f, + -6.606210294368872974e-04f, + -4.958091422553860149e-04f, + -3.306572814353150912e-04f, + -1.653320338249910076e-04f, + -2.551386587880797004e-17f, + 1.651723734761380335e-04f, + 3.300189614740527827e-04f, + 4.943741272349469777e-04f, + 6.580728886553833265e-04f, + 8.209510837512715370e-04f, + 9.828455351376394825e-04f, + 1.143594213357676742e-03f, + 1.303036398898462693e-03f, + 1.461012842732159695e-03f, + 1.617365925221177182e-03f, + 1.771939813229538550e-03f, + 1.924580615284706168e-03f, + 2.075136534633631631e-03f, + 2.223458020043932865e-03f, + 2.369397914196333301e-03f, + 2.512811599526118631e-03f, + 2.653557141365132238e-03f, + 2.791495428245575894e-03f, + 2.926490309225380886e-03f, + 3.058408728100418372e-03f, + 3.187120854371934629e-03f, + 3.312500210839413109e-03f, + 3.434423797694213451e-03f, + 3.552772212992939740e-03f, + 3.667429769391414990e-03f, + 3.778284607026904680e-03f, + 3.885228802437357565e-03f, + 3.988158473412363458e-03f, + 4.086973879674651519e-03f, + 4.181579519293593741e-03f, + 4.271884220739164024e-03f, + 4.357801230486726615e-03f, + 4.439248296089245809e-03f, + 4.516147744637950996e-03f, + 4.588426556536215166e-03f, + 4.656016434517300413e-03f, + 4.718853867841324261e-03f, + 4.776880191610652533e-03f, + 4.830041641149988331e-03f, + 4.878289401399377341e-03f, + 4.921579651277259264e-03f, + 4.959873602972050821e-03f, + 4.993137536128673497e-03f, + 5.021342826899958915e-03f, + 5.044465971838839151e-03f, + 5.062488606612373584e-03f, + 5.075397519523472574e-03f, + 5.083184659832008616e-03f, + 5.085847140871759681e-03f, + 5.083387237965185726e-03f, + 5.075812381143095242e-03f, + 5.063135142681596430e-03f, + 5.045373219473861526e-03f, + 5.022549410259432613e-03f, + 4.994691587739028341e-03f, + 4.961832665607723673e-03f, + 4.924010560544767219e-03f, + 4.881268149203150074e-03f, + 4.833653220246830577e-03f, + 4.781218421489157218e-03f, + 4.724021202189871739e-03f, + 4.662123750573998575e-03f, + 4.595592926639679825e-03f, + 4.524500190327651952e-03f, + 4.448921525128770975e-03f, + 4.368937357210857936e-03f, + 4.284632470151218328e-03f, + 4.196095915364042757e-03f, + 4.103420918317851433e-03f, + 4.006704780641143562e-03f, + 3.906048778218370893e-03f, + 3.801558055383750991e-03f, + 3.693341515321936323e-03f, + 3.581511706790642402e-03f, + 3.466184707282398206e-03f, + 3.347480002746349489e-03f, + 3.225520363994377124e-03f, + 3.100431719920501098e-03f, + 2.972343027662367743e-03f, + 2.841386139839377056e-03f, + 2.707695669005051858e-03f, + 2.571408849450755249e-03f, + 2.432665396503416125e-03f, + 2.291607363462537170e-03f, + 2.148378996320580991e-03f, + 2.003126586416237656e-03f, + 1.855998321172221827e-03f, + 1.707144133066539190e-03f, + 1.556715546994994403e-03f, + 1.404865526175997237e-03f, + 1.251748316758327694e-03f, + 1.097519291286103453e-03f, + 9.423347911819565052e-04f, + 7.863519684062989651e-04f, + 6.297286264551491203e-04f, + 4.726230608546003620e-04f, + 3.151938993142525320e-04f, + 1.575999417021628837e-04f, + 7.784442283331923853e-17f, + -1.574472615986340432e-04f, + -3.145834862862096032e-04f, + -4.712507837750268031e-04f, + -6.272918888083930770e-04f, + -7.825503188873347447e-04f, + -9.368705310580024981e-04f, + -1.090098077600495973e-03f, + -1.242079760465078378e-03f, + -1.392663784299297746e-03f, + -1.541699907915918119e-03f, + -1.689039594049394563e-03f, + -1.834536157250591781e-03f, + -1.978044909775040876e-03f, + -2.119423305318431615e-03f, + -2.258531080456323715e-03f, + -2.395230393648445800e-03f, + -2.529385961670430668e-03f, + -2.660865193337756500e-03f, + -2.789538320388635587e-03f, + -2.915278525399034055e-03f, + -3.037962066602765791e-03f, + -3.157468399492973938e-03f, + -3.273680295087870538e-03f, + -3.386483954743054609e-03f, + -3.495769121399434042e-03f, + -3.601429187156589447e-03f, + -3.703361297068739032e-03f, + -3.801466449061457163e-03f, + -3.895649589871598342e-03f, + -3.985819706919274674e-03f, + -4.071889916022448409e-03f, + -4.153777544869190555e-03f, + -4.231404212169127994e-03f, + -4.304695902407762974e-03f, + -4.373583036132095911e-03f, + -4.438000535702448651e-03f, + -4.497887886447530723e-03f, + -4.553189193166368338e-03f, + -4.603853231924096880e-03f, + -4.649833497094323954e-03f, + -4.691088243605770480e-03f, + -4.727580524354188865e-03f, + -4.759278222747725245e-03f, + -4.786154080356886005e-03f, + -4.808185719646517267e-03f, + -4.825355661771149086e-03f, + -4.837651339421160553e-03f, + -4.845065104711230967e-03f, + -4.847594232107986685e-03f, + -4.845240916398877579e-03f, + -4.838012265708960952e-03f, + -4.825920289577491362e-03f, + -4.808981882111157055e-03f, + -4.787218800235539494e-03f, + -4.760657637071705889e-03f, + -4.729329790469200510e-03f, + -4.693271426731996689e-03f, + -4.652523439578401879e-03f, + -4.607131404381258066e-03f, + -4.557145527738585764e-03f, + -4.502620592430119431e-03f, + -4.443615897820203317e-03f, + -4.380195195770275780e-03f, + -4.312426622131352791e-03f, + -4.240382623888087031e-03f, + -4.164139882033739311e-03f, + -4.083779230256361775e-03f, + -3.999385569522737396e-03f, + -3.911047778650672546e-03f, + -3.818858620962382270e-03f, + -3.722914647117278510e-03f, + -3.623316094226521674e-03f, + -3.520166781352995246e-03f, + -3.413574001506695325e-03f, + -3.303648410246657133e-03f, + -3.190503911006380925e-03f, + -3.074257537259608274e-03f, + -2.955029331648956637e-03f, + -2.832942222203055620e-03f, + -2.708121895767779796e-03f, + -2.580696668782614736e-03f, + -2.450797355535883071e-03f, + -2.318557134031954108e-03f, + -2.184111409608732648e-03f, + -2.047597676446088772e-03f, + -1.909155377104432803e-03f, + -1.768925760238825853e-03f, + -1.627051736631422978e-03f, + -1.483677733692766133e-03f, + -1.338949548574867041e-03f, + -1.193014200049233526e-03f, + -1.046019779297893606e-03f, + -8.981152997709223890e-04f, + -7.494505462600843963e-04f, + -6.001759233424719181e-04f, + -4.504423033485727233e-04f, + -3.004008740059210055e-04f, + -1.502029859132318287e-04f, + 0.000000000000000000e+00f, + 1.500568648773128620e-04f, + 2.998166840477804458e-04f, + 4.491289786934320964e-04f, + 5.978438669215414185e-04f, + 7.458122140882831198e-04f, + 8.928857822246706166e-04f, + 1.038917378413064868e-03f, + 1.183761001968396554e-03f, + 1.327271990275858586e-03f, + 1.469307163138363920e-03f, + 1.609724965492229879e-03f, + 1.748385608347759190e-03f, + 1.885151207813307852e-03f, + 2.019885922067833454e-03f, + 2.152456086142171161e-03f, + 2.282730344379329916e-03f, + 2.410579780439001552e-03f, + 2.535878044720715069e-03f, + 2.658501479078634582e-03f, + 2.778329238704075124e-03f, + 2.895243411057801981e-03f, + 3.009129131734148907e-03f, + 3.119874697142386698e-03f, + 3.227371673896960082e-03f, + 3.331515004807996620e-03f, + 3.432203111369802693e-03f, + 3.529337992646119828e-03f, + 3.622825320457822695e-03f, + 3.712574530779899368e-03f, + 3.798498911258710829e-03f, + 3.880515684766671931e-03f, + 3.958546088913222558e-03f, + 4.032515451435444119e-03f, + 4.102353261397662619e-03f, + 4.167993236131739207e-03f, + 4.229373383854271966e-03f, + 4.286436061903056705e-03f, + 4.339128030537392315e-03f, + 4.387400502253299348e-03f, + 4.431209186566910548e-03f, + 4.470514330227219786e-03f, + 4.505280752820716751e-03f, + 4.535477877737257441e-03f, + 4.561079758469966522e-03f, + 4.582065100227887371e-03f, + 4.598417276843720300e-03f, + 4.610124342964186731e-03f, + 4.617179041515659735e-03f, + 4.619578806441900290e-03f, + 4.617325760715732842e-03f, + 4.610426709631436880e-03f, + 4.598893129389029603e-03f, + 4.582741150986642878e-03f, + 4.561991539441702728e-03f, + 4.536669668366456049e-03f, + 4.506805489927790190e-03f, + 4.472433500226501331e-03f, + 4.433592700134834745e-03f, + 4.390326551636334652e-03f, + 4.342682929716723365e-03f, + 4.290714069857965926e-03f, + 4.234476511192970805e-03f, + 4.174031035382547508e-03f, + 4.109442601280248290e-03f, + 4.040780275454714486e-03f, + 3.968117158643618379e-03f, + 3.891530308217908476e-03f, + 3.811100656737222755e-03f, + 3.726912926682747658e-03f, + 3.639055541457847723e-03f, + 3.547620532748325950e-03f, + 3.452703444340344142e-03f, + 3.354403232495308754e-03f, + 3.252822162986789261e-03f, + 3.148065704904799266e-03f, + 3.040242421338187288e-03f, + 2.929463857049219994e-03f, + 2.815844423254667064e-03f, + 2.699501279633036762e-03f, + 2.580554213680439322e-03f, + 2.459125517537331940e-03f, + 2.335339862413496597e-03f, + 2.209324170741059669e-03f, + 2.081207486184459728e-03f, + 1.951120841642063749e-03f, + 1.819197125372980488e-03f, + 1.685570945387657215e-03f, + 1.550378492237483022e-03f, + 1.413757400346775340e-03f, + 1.275846608024381462e-03f, + 1.136786216300893085e-03f, + 9.967173467317232399e-04f, + 8.557819983114523963e-04f, + 7.141229036455263310e-04f, + 5.718833845226121287e-04f, + 4.292072070347436501e-04f, + 2.862384363927389136e-04f, + 1.431212915810999909e-04f, + 3.976073045763746639e-17f, + -1.429813477578194541e-04f, + -2.856789428524072441e-04f, + -4.279494027150967353e-04f, + -5.696499149979476154e-04f, + -7.106383808068707187e-04f, + -8.507735570776003928e-04f, + -9.899151979507884221e-04f, + -1.127924195003721704e-03f, + -1.264662716200822120e-03f, + -1.399994343423132705e-03f, + -1.533784208438585678e-03f, + -1.665899127179875554e-03f, + -1.796207732195136955e-03f, + -1.924580603139482322e-03f, + -2.050890395178425665e-03f, + -2.175011965176371249e-03f, + -2.296822495544894628e-03f, + -2.416201615627299338e-03f, + -2.533031520501645515e-03f, + -2.647197087084067826e-03f, + -2.758585987417253894e-03f, + -2.867088799034697190e-03f, + -2.972599112290812313e-03f, + -3.075013634552971071e-03f, + -3.174232291152105818e-03f, + -3.270158322995199603e-03f, + -3.362698380743715538e-03f, + -3.451762615465765304e-03f, + -3.537264765675776721e-03f, + -3.619122240676629892e-03f, + -3.697256200123399950e-03f, + -3.771591629733630612e-03f, + -3.842057413070905456e-03f, + -3.908586399332766859e-03f, + -3.971115467079878135e-03f, + -4.029585583845121145e-03f, + -4.083941861567453452e-03f, + -4.134133607797787699e-03f, + -4.180114372630844115e-03f, + -4.221841991318395042e-03f, + -4.259278622526630094e-03f, + -4.292390782202119143e-03f, + -4.321149373017542893e-03f, + -4.345529709371441680e-03f, + -4.365511537920943770e-03f, + -4.381079053631709713e-03f, + -4.392220911332943636e-03f, + -4.398930232770211640e-03f, + -4.401204609153669053e-03f, + -4.399046099203249988e-03f, + -4.392461222697331344e-03f, + -4.381460949535757529e-03f, + -4.366060684332634563e-03f, + -4.346280246558699781e-03f, + -4.322143846257833419e-03f, + -4.293680055366262162e-03f, + -4.260921774667682412e-03f, + -4.223906196422148006e-03f, + -4.182674762710170135e-03f, + -4.137273119538274584e-03f, + -4.087751066756856698e-03f, + -4.034162503844153022e-03f, + -3.976565371615301513e-03f, + -3.915021589919383607e-03f, + -3.849596991390978259e-03f, + -3.780361251326535416e-03f, + -3.707387813760094821e-03f, + -3.630753813817203315e-03f, + -3.550539996427677474e-03f, + -3.466830631483622076e-03f, + -3.379713425530830959e-03f, + -3.289279430087042790e-03f, + -3.195622946681347856e-03f, + -3.098841428714084380e-03f, + -2.999035380240086535e-03f, + -2.896308251778681887e-03f, + -2.790766333258949596e-03f, + -2.682518644211763417e-03f, + -2.571676821320250696e-03f, + -2.458355003445216510e-03f, + -2.342669714244821622e-03f, + -2.224739742507099091e-03f, + -2.104686020319705697e-03f, + -1.982631499200445194e-03f, + -1.858701024317035294e-03f, + -1.733021206922603788e-03f, + -1.605720295138181623e-03f, + -1.476928043214278908e-03f, + -1.346775579404299638e-03f, + -1.215395272583683463e-03f, + -1.082920597750686208e-03f, + -9.494860005465256434e-04f, + -8.152267609301555324e-04f, + -6.802788561468293017e-04f, + -5.447788231302409367e-04f, + -4.088636204751821168e-04f, + -2.726704901212254279e-04f, + -1.363368188880890964e-04f, + -8.417792963206818356e-17f, + 1.362027052598085422e-04f, + 2.721343056259442508e-04f, + 4.076582175196397572e-04f, + 5.426384021722333592e-04f, + 6.769395020654857481e-04f, + 8.104269765506644935e-04f, + 9.429672365128469180e-04f, + 1.074427777944659190e-03f, + 1.204677314294974296e-03f, + 1.333585907462621518e-03f, + 1.461025097303440606e-03f, + 1.586868029520704633e-03f, + 1.710989581813802214e-03f, + 1.833266488158666763e-03f, + 1.953577461096326229e-03f, + 2.071803311908859517e-03f, + 2.187827068564226606e-03f, + 2.301534091313028798e-03f, + 2.412812185822113195e-03f, + 2.521551713735463440e-03f, + 2.627645700551932938e-03f, + 2.730989940714999460e-03f, + 2.831483099809944254e-03f, + 2.929026813770171413e-03f, + 3.023525784994855574e-03f, + 3.114887875283365529e-03f, + 3.203024195497624661e-03f, + 3.287849191864475069e-03f, + 3.369280728833792034e-03f, + 3.447240168413722491e-03f, + 3.521652445905853156e-03f, + 3.592446141966990254e-03f, + 3.659553550929970766e-03f, + 3.722910745317228355e-03f, + 3.782457636486660606e-03f, + 3.838138031351646592e-03f, + 3.889899685123011756e-03f, + 3.937694350023167832e-03f, + 3.981477819927187536e-03f, + 4.021209970890143003e-03f, + 4.056854797524065380e-03f, + 4.088380445191790516e-03f, + 4.115759237989136295e-03f, + 4.138967702491964246e-03f, + 4.157986587248014773e-03f, + 4.172800877997954669e-03f, + 4.183399808614909378e-03f, + 4.189776867755429235e-03f, + 4.191929801219356974e-03f, + 4.189860610020690324e-03f, + 4.183575544175400195e-03f, + 4.173085092216739442e-03f, + 4.158403966452908773e-03f, + 4.139551083985980491e-03f, + 4.116549543515387807e-03f, + 4.089426597953691074e-03f, + 4.058213622886065394e-03f, + 4.022946080909405378e-03f, + 3.983663481891361151e-03f, + 3.940409339192868857e-03f, + 3.893231121902388826e-03f, + 3.842180203134375367e-03f, + 3.787311804446883475e-03f, + 3.728684936439468408e-03f, + 3.666362335593461707e-03f, + 3.600410397423470070e-03f, + 3.530899106009756632e-03f, + 3.457901959986858006e-03f, + 3.381495895065876871e-03f, + 3.301761203172812187e-03f, + 3.218781448286551963e-03f, + 3.132643379065020751e-03f, + 3.043436838351391838e-03f, + 2.951254669653231681e-03f, + 2.856192620692367314e-03f, + 2.758349244126263259e-03f, + 2.657825795542260918e-03f, + 2.554726128830706305e-03f, + 2.449156589045835622e-03f, + 2.341225902863081770e-03f, + 2.231045066746887174e-03f, + 2.118727232942822086e-03f, + 2.004387593412520346e-03f, + 1.888143261828470910e-03f, + 1.770113153750305698e-03f, + 1.650417865105977249e-03f, + 1.529179549100039177e-03f, + 1.406521791675539998e-03f, + 1.282569485656734343e-03f, + 1.157448703700234525e-03f, + 1.031286570183274475e-03f, + 9.042111321594720934e-04f, + 7.763512295141050895e-04f, + 6.478363644484194097e-04f, + 5.187965704260827501e-04f, + 3.893622807153351221e-04f, + 2.596641966575497277e-04f, + 1.298331557961695734e-04f, + 0.000000000000000000e+00f, + -1.297045562884773494e-04f, + -2.591500575455231805e-04f, + -3.882064382682380425e-04f, + -5.167441535531211438e-04f, + -6.446343090221472215e-04f, + -7.717487899651593111e-04f, + -8.979603895682745050e-04f, + -1.023142936102136233e-03f, + -1.147171418941898315e-03f, + -1.269922113292209966e-03f, + -1.391272703494883479e-03f, + -1.511102404795431394e-03f, + -1.629292083446334978e-03f, + -1.745724375030405316e-03f, + -1.860283800883534306e-03f, + -1.972856882504857214e-03f, + -2.083332253837852453e-03f, + -2.191600771314119924e-03f, + -2.297555621549458339e-03f, + -2.401092426587344512e-03f, + -2.502109346584675646e-03f, + -2.600507179840733183e-03f, + -2.696189460070382710e-03f, + -2.789062550825482587e-03f, + -2.879035736973885838e-03f, + -2.966021313145917292e-03f, + -3.049934669061640530e-03f, + -3.130694371657468528e-03f, + -3.208222243931873989e-03f, + -3.282443440433375874e-03f, + -3.353286519319528813e-03f, + -3.420683510916569352e-03f, + -3.484569982714951809e-03f, + -3.544885100737864888e-03f, + -3.601571687225699116e-03f, + -3.654576274581390269e-03f, + -3.703849155525655665e-03f, + -3.749344429416276783e-03f, + -3.791020044687998507e-03f, + -3.828837837374106986e-03f, + -3.862763565674989016e-03f, + -3.892766940542859502e-03f, + -3.918821652255656887e-03f, + -3.940905392957132734e-03f, + -3.958999875144887486e-03f, + -3.973090846091481033e-03f, + -3.983168098188016350e-03f, + -3.989225475204148490e-03f, + -3.991260874462022705e-03f, + -3.989276244926093229e-03f, + -3.983277581214771101e-03f, + -3.973274913544052635e-03f, + -3.959282293617159831e-03f, + -3.941317776478633732e-03f, + -3.919403398354929027e-03f, + -3.893565150507910695e-03f, + -3.863832949131735649e-03f, + -3.830240601327010268e-03f, + -3.792825767190527789e-03f, + -3.751629918062933215e-03f, + -3.706698290979619330e-03f, + -3.658079839375025927e-03f, + -3.605827180092993720e-03f, + -3.549996536761576733e-03f, + -3.490647679591208329e-03f, + -3.427843861661717968e-03f, + -3.361651751765054510e-03f, + -3.292141363875685824e-03f, + -3.219385983321982822e-03f, + -3.143462089736679104e-03f, + -3.064449276867864478e-03f, + -2.982430169333176711e-03f, + -2.897490336404670141e-03f, + -2.809718202914781877e-03f, + -2.719204957374711431e-03f, + -2.626044457401114501e-03f, + -2.530333132549811032e-03f, + -2.432169884655409342e-03f, + -2.331655985780983504e-03f, + -2.228894973881932924e-03f, + -2.123992546292832913e-03f, + -2.017056451144963979e-03f, + -1.908196376826750383e-03f, + -1.797523839601251243e-03f, + -1.685152069494012198e-03f, + -1.571195894568736418e-03f, + -1.455771623709985587e-03f, + -1.338996928029888246e-03f, + -1.220990721022854842e-03f, + -1.101873037586910105e-03f, + -9.817649120378681756e-04f, + -8.607882552375694957e-04f, + -7.390657309618451016e-04f, + -6.167206316344765651e-04f, + -4.938767535509734369e-04f, + -3.706582717193119820e-04f, + -2.471896144450557429e-04f, + -1.235953377853419590e-04f, + -4.959890100963354769e-17f, + 1.234719638747178042e-04f, + 2.466963672028767455e-04f, + 3.695493965506171539e-04f, + 4.919077359883478268e-04f, + 6.136486907666624611e-04f, + 7.346503102443730469e-04f, + 8.547915099445561275e-04f, + 9.739521926155840070e-04f, + 1.092013368178181270e-03f, + 1.208857272437798046e-03f, + 1.324367484443061309e-03f, + 1.438429042375458577e-03f, + 1.550928557853214172e-03f, + 1.661754328537675893e-03f, + 1.770796448927353453e-03f, + 1.877946919233882935e-03f, + 1.983099752229050636e-03f, + 2.086151077959072422e-03f, + 2.186999246221175627e-03f, + 2.285544926703325219e-03f, + 2.381691206687666998e-03f, + 2.475343686220975951e-03f, + 2.566410570660377331e-03f, + 2.654802760502929671e-03f, + 2.740433938410591005e-03f, + 2.823220653347242176e-03f, + 2.903082401745072944e-03f, + 2.979941705620986828e-03f, + 3.053724187568778933e-03f, + 3.124358642553495477e-03f, + 3.191777106439702780e-03f, + 3.255914921186875855e-03f, + 3.316710796650810048e-03f, + 3.374106868931566437e-03f, + 3.428048755212193075e-03f, + 3.478485605037506118e-03f, + 3.525370147984284441e-03f, + 3.568658737678078504e-03f, + 3.608311392117048363e-03f, + 3.644291830264629207e-03f, + 3.676567504879116322e-03f, + 3.705109631549780621e-03f, + 3.729893213914910709e-03f, + 3.750897065039809040e-03f, + 3.768103824936940016e-03f, + 3.781499974214817122e-03f, + 3.791075843845443261e-03f, + 3.796825621044523733e-03f, + 3.798747351262270894e-03f, + 3.796842936286857866e-03f, + 3.791118128466208596e-03f, + 3.781582521057830042e-03f, + 3.768249534720393822e-03f, + 3.751136400164309208e-03f, + 3.730264136982911188e-03f, + 3.705657528689156911e-03f, + 3.677345093986788237e-03f, + 3.645359054308939216e-03f, + 3.609735297660244310e-03f, + 3.570513338802807409e-03f, + 3.527736275829614857e-03f, + 3.481450743173182798e-03f, + 3.431706861099539409e-03f, + 3.378558181742752180e-03f, + 3.322061631737472948e-03f, + 3.262277451510458420e-03f, + 3.199269131295992552e-03f, + 3.133103343942434792e-03f, + 3.063849874581625003e-03f, + 2.991581547234064588e-03f, + 2.916374148427355699e-03f, + 2.838306347908428270e-03f, + 2.757459616531154987e-03f, + 2.673918141405439829e-03f, + 2.587768738396670036e-03f, + 2.499100762065002874e-03f, + 2.408006013138405590e-03f, + 2.314578643615823259e-03f, + 2.218915059596944257e-03f, + 2.121113821939972673e-03f, + 2.021275544848643961e-03f, + 1.919502792494091415e-03f, + 1.815899973775997930e-03f, + 1.710573235331645401e-03f, + 1.603630352903246976e-03f, + 1.495180621172954036e-03f, + 1.385334742178912079e-03f, + 1.274204712426525677e-03f, + 1.161903708809525985e-03f, + 1.048545973456544876e-03f, + 9.342466976205273310e-04f, + 8.191219047299183901e-04f, + 7.032883327184241478e-04f, + 5.868633157534830069e-04f, + 4.699646654841184022e-04f, + 3.527105519262883665e-04f, + 2.352193841077147634e-04f, + 1.176096905914035935e-04f, + -1.816279043680416122e-17f, + -1.174912783408097822e-04f, + -2.347459735184355596e-04f, + -3.516462717890174536e-04f, + -4.680748348545702049e-04f, + -5.839149175424285850e-04f, + -6.990504847680064412e-04f, + -8.133663276656900908e-04f, + -9.267481787707859599e-04f, + -1.039082826136560620e-03f, + -1.150258226274457644e-03f, + -1.260163615803283491e-03f, + -1.368689621697415744e-03f, + -1.475728370022750873e-03f, + -1.581173593054908304e-03f, + -1.684920734670451118e-03f, + -1.786867053909769803e-03f, + -1.886911726606242201e-03f, + -1.984955944983589262e-03f, + -2.080903015122214511e-03f, + -2.174658452197730102e-03f, + -2.266130073399595744e-03f, + -2.355228088437774474e-03f, + -2.441865187547984182e-03f, + -2.525956626910913581e-03f, + -2.607420311401180066e-03f, + -2.686176874584755934e-03f, + -2.762149755888469640e-03f, + -2.835265274865544395e-03f, + -2.905452702486107687e-03f, + -2.972644329382842596e-03f, + -3.036775530987343309e-03f, + -3.097784829494083791e-03f, + -3.155613952592319516e-03f, + -3.210207888911055518e-03f, + -3.261514940123977010e-03f, + -3.309486769664863031e-03f, + -3.354078448008697769e-03f, + -3.395248494475826620e-03f, + -3.432958915520433179e-03f, + -3.467175239468593684e-03f, + -3.497866547674528641e-03f, + -3.525005502067194568e-03f, + -3.548568369062852102e-03f, + -3.568535039823742677e-03f, + -3.584889046845683540e-03f, + -3.597617576861870340e-03f, + -3.606711480053335483e-03f, + -3.612165275560820770e-03f, + -3.613977153296067668e-03f, + -3.612148972054406073e-03f, + -3.606686253934421674e-03f, + -3.597598175073908090e-03f, + -3.584897552715274240e-03f, + -3.568600828617066786e-03f, + -3.548728048831968108e-03f, + -3.525302839875490025e-03f, + -3.498352381312806562e-03f, + -3.467907374795066184e-03f, + -3.434002009579821546e-03f, + -3.396673924574244215e-03f, + -3.355964166942346574e-03f, + -3.311917147321609932e-03f, + -3.264580591697720767e-03f, + -3.214005489989122874e-03f, + -3.160246041396339717e-03f, + -3.103359596574423087e-03f, + -3.043406596690569153e-03f, + -2.980450509430481246e-03f, + -2.914557762021494861e-03f, + -2.845797671343432839e-03f, + -2.774242371199536934e-03f, + -2.699966736824086378e-03f, + -2.623048306706114718e-03f, + -2.543567201809550458e-03f, + -2.461606042274317591e-03f, + -2.377249861685521663e-03f, + -2.290586018998170062e-03f, + -2.201704108209648781e-03f, + -2.110695865872344850e-03f, + -2.017655076542951807e-03f, + -1.922677476264368895e-03f, + -1.825860654179994359e-03f, + -1.727303952382239390e-03f, + -1.627108364096408778e-03f, + -1.525376430304876962e-03f, + -1.422212134918130876e-03f, + -1.317720798598115244e-03f, + -1.212008971343053179e-03f, + -1.105184323943502606e-03f, + -9.973555384197396820e-04f, + -8.886321975514789584e-04f, + -7.791246736123785127e-04f, + -6.689440164231939519e-04f, + -5.582018408351800513e-04f, + -4.470102137591960715e-04f, + -3.354815408535864675e-04f, + -2.237284529868988829e-04f, + -1.118636925881364959e-04f, + -2.071470033548900873e-17f, + 1.117500000493719706e-04f, + 2.232739117441697070e-04f, + 3.344596811326808606e-04f, + 4.451957086194700233e-04f, + 5.553709608865004844e-04f, + 6.648750821302810846e-04f, + 7.735985045027994698e-04f, + 8.814325576476730742e-04f, + 9.882695772205538597e-04f, + 1.094003012286658312e-03f, + 1.198527531486872971e-03f, + 1.301739127868568706e-03f, + 1.403535222275920568e-03f, + 1.503814765196793968e-03f, + 1.602478336965568358e-03f, + 1.699428246223005749e-03f, + 1.794568626535442959e-03f, + 1.887805531077050170e-03f, + 1.979047025283286153e-03f, + 2.068203277383505716e-03f, + 2.155186646722974993e-03f, + 2.239911769789048289e-03f, + 2.322295643856428504e-03f, + 2.402257708169032186e-03f, + 2.479719922580636039e-03f, + 2.554606843576476966e-03f, + 2.626845697602746450e-03f, + 2.696366451631782273e-03f, + 2.763101880895990278e-03f, + 2.826987633724481735e-03f, + 2.887962293419586799e-03f, + 2.945967437115027624e-03f, + 3.000947691558917239e-03f, + 3.052850785768143008e-03f, + 3.101627600505197247e-03f, + 3.147232214530348154e-03f, + 3.189621947585512783e-03f, + 3.228757400070635542e-03f, + 3.264602489375515067e-03f, + 3.297124482833800954e-03f, + 3.326294027269616291e-03f, + 3.352085175110586929e-03f, + 3.374475407044334914e-03f, + 3.393445651198981165e-03f, + 3.408980298832289899e-03f, + 3.421067216516832533e-03f, + 3.429697754812713849e-03f, + 3.434866753422505335e-03f, + 3.436572542826982733e-03f, + 3.434816942403465419e-03f, + 3.429605255032289191e-03f, + 3.420946258200424379e-03f, + 3.408852191614762661e-03f, + 3.393338741341164321e-03f, + 3.374425020488695717e-03f, + 3.352133546462037709e-03f, + 3.326490214808674843e-03f, + 3.297524269690380733e-03f, + 3.265268271012441645e-03f, + 3.229758058246862303e-03f, + 3.191032710989869740e-03f, + 3.149134506296154788e-03f, + 3.104108872836428955e-03f, + 3.056004341927853838e-03f, + 3.004872495489709604e-03f, + 2.950767910979716115e-03f, + 2.893748103369611722e-03f, + 2.833873464221980509e-03f, + 2.771207197931811923e-03f, + 2.705815255200260967e-03f, + 2.637766263811031336e-03f, + 2.567131456780837821e-03f, + 2.493984597959450489e-03f, + 2.418401905157508119e-03f, + 2.340461970880830869e-03f, + 2.260245680754550089e-03f, + 2.177836129720765214e-03f, + 2.093318536097558535e-03f, + 2.006780153586758438e-03f, + 1.918310181321814228e-03f, + 1.827999672049080305e-03f, + 1.735941438535555485e-03f, + 1.642229958299797413e-03f, + 1.546961276764474095e-03f, + 1.450232908928234844e-03f, + 1.352143739658173346e-03f, + 1.252793922705604940e-03f, + 1.152284778546037915e-03f, + 1.050718691150112800e-03f, + 9.481990037877905493e-04f, + 8.448299139744811252e-04f, + 7.407163676634808108e-04f, + 6.359639527935932865e-04f, + 5.306787922987215612e-04f, + 4.249674366892458523e-04f, + 3.189367563120465432e-04f, + 2.126938333988559937e-04f, + 1.063458540127559251e-04f, + 5.580875061456703527e-17f, + -1.062366589427715403e-04f, + -2.122572729776368709e-04f, + -3.179553195023174803e-04f, + -4.232247100881988380e-04f, + -5.279598968701624921e-04f, + -6.320559782838149239e-04f, + -7.354088040427114292e-04f, + -8.379150792517338136e-04f, + -9.394724675511614224e-04f, + -1.039979693190289578e-03f, + -1.139336641928036893e-03f, + -1.237444460659308312e-03f, + -1.334205655669700157e-03f, + -1.429524189420069849e-03f, + -1.523305575764726449e-03f, + -1.615456973509339471e-03f, + -1.705887278216311432e-03f, + -1.794507212166710506e-03f, + -1.881229412389207739e-03f, + -1.965968516670845660e-03f, + -2.048641247464260805e-03f, + -2.129166493608392920e-03f, + -2.207465389784019332e-03f, + -2.283461393625221911e-03f, + -2.357080360412389282e-03f, + -2.428250615272878506e-03f, + -2.496903022820505004e-03f, + -2.562971054165676978e-03f, + -2.626390851230865024e-03f, + -2.687101288310514684e-03f, + -2.745044030815619023e-03f, + -2.800163591146226632e-03f, + -2.852407381639556275e-03f, + -2.901725764542836122e-03f, + -2.948072098963223399e-03f, + -2.991402784751522655e-03f, + -3.031677303277889764e-03f, + -3.068858255062130534e-03f, + -3.102911394223503531e-03f, + -3.133805659718869735e-03f, + -3.161513203341241758e-03f, + -3.186009414453190580e-03f, + -3.207272941434331694e-03f, + -3.225285709824096680e-03f, + -3.240032937145292686e-03f, + -3.251503144396590377e-03f, + -3.259688164206146245e-03f, + -3.264583145641404907e-03f, + -3.266186555673606436e-03f, + -3.264500177299172780e-03f, + -3.259529104323136660e-03f, + -3.251281732813429259e-03f, + -3.239769749237986739e-03f, + -3.225008115300036140e-03f, + -3.207015049490388476e-03f, + -3.185812005378460370e-03f, + -3.161423646667512952e-03f, + -3.133877819042292512e-03f, + -3.103205518841122348e-03f, + -3.069440858586877912e-03f, + -3.032621029414926759e-03f, + -2.992786260439455476e-03f, + -2.949979775101472298e-03f, + -2.904247744546611422e-03f, + -2.855639238081619617e-03f, + -2.804206170763586491e-03f, + -2.750003248176786843e-03f, + -2.693087908455917955e-03f, + -2.633520261617509212e-03f, + -2.571363026262532200e-03f, + -2.506681463717044551e-03f, + -2.439543309680427315e-03f, + -2.370018703451564571e-03f, + -2.298180114807654630e-03f, + -2.224102268611033526e-03f, + -2.147862067223294154e-03f, + -2.069538510805925442e-03f, + -1.989212615590480685e-03f, + -1.906967330203344566e-03f, + -1.822887450130181207e-03f, + -1.737059530408692877e-03f, + -1.649571796640214366e-03f, + -1.560514054410137245e-03f, + -1.469977597210741713e-03f, + -1.378055112961429048e-03f, + -1.284840589220490525e-03f, + -1.190429217186597059e-03f, + -1.094917294586464536e-03f, + -9.984021275502952091e-04f, + -9.009819315715012801e-04f, + -8.027557316540494606e-04f, + -7.038232617473004970e-04f, + -6.042848635718732616e-04f, + -5.042413849374186366e-04f, + -4.037940776560225800e-04f, + -3.030444951553179869e-04f, + -2.020943898931319878e-04f, + -1.010456106780149166e-04f, + 0.000000000000000000e+00f, + 1.009407085266458343e-04f, + 2.016749925046095251e-04f, + 3.021016427750876994e-04f, + 4.021198650188813296e-04f, + 5.016293808337416761e-04f, + 6.005305281877486908e-04f, + 6.987243611467527623e-04f, + 7.961127487778794053e-04f, + 8.925984731294979088e-04f, + 9.880853261891541211e-04f, + 1.082478205724416668e-03f, + 1.175683209910467547e-03f, + 1.267607730649530483e-03f, + 1.358160545491613001e-03f, + 1.447251908062810368e-03f, + 1.534793636914284342e-03f, + 1.620699202701525671e-03f, + 1.704883813609845864e-03f, + 1.787264498941020874e-03f, + 1.867760190778164960e-03f, + 1.946291803649916963e-03f, + 2.022782312115050697e-03f, + 2.097156826190940942e-03f, + 2.169342664553446445e-03f, + 2.239269425435684406e-03f, + 2.306869055157482768e-03f, + 2.372075914217887990e-03f, + 2.434826840887931946e-03f, + 2.495061212241576985e-03f, + 2.552721002565519828e-03f, + 2.607750839092839740e-03f, + 2.660098055006482071e-03f, + 2.709712739661699482e-03f, + 2.756547785980618080e-03f, + 2.800558934973623130e-03f, + 2.841704817345394509e-03f, + 2.879946992147500422e-03f, + 2.915249982440988770e-03f, + 2.947581307936787947e-03f, + 2.976911514583215936e-03f, + 3.003214201075224757e-03f, + 3.026466042260897698e-03f, + 3.046646809425394842e-03f, + 3.063739387434716906e-03f, + 3.077729788725812928e-03f, + 3.088607164131847160e-03f, + 3.096363810535085210e-03f, + 3.100995175343106407e-03f, + 3.102499857787075627e-03f, + 3.100879607044029155e-03f, + 3.096139317188489372e-03f, + 3.088287018981677665e-03f, + 3.077333868510032794e-03f, + 3.063294132687598148e-03f, + 3.046185171640329852e-03f, + 3.026027417993118994e-03f, + 3.002844353083898229e-03f, + 2.976662480131725321e-03f, + 2.947511294389127540e-03f, + 2.915423250312139825e-03f, + 2.880433725783904282e-03f, + 2.842580983431017543e-03f, + 2.801906129074849608e-03f, + 2.758453067362536676e-03f, + 2.712268454625132129e-03f, + 2.663401649013388741e-03f, + 2.611904657964648872e-03f, + 2.557832083055883686e-03f, + 2.501241062301404455e-03f, + 2.442191209956580140e-03f, + 2.380744553889864272e-03f, + 2.316965470589540683e-03f, + 2.250920617872494492e-03f, + 2.182678865366110329e-03f, + 2.112311222834577142e-03f, + 2.039890766424525773e-03f, + 1.965492562907071757e-03f, + 1.889193591993552652e-03f, + 1.811072666805763759e-03f, + 1.731210352583364151e-03f, + 1.649688883710983146e-03f, + 1.566592079150942642e-03f, + 1.482005256369143794e-03f, + 1.396015143841002710e-03f, + 1.308709792228250146e-03f, + 1.220178484316535592e-03f, + 1.130511643807194247e-03f, + 1.039800743054220596e-03f, + 9.481382098429354081e-04f, + 8.556173333027085976e-04f, + 7.623321690519257836e-04f, + 6.683774436695268453e-04f, + 5.738484585908526416e-04f, + 4.788409935259931006e-04f, + 3.834512094969080875e-04f, + 2.877755515921519335e-04f, + 1.919106515382334099e-04f, + 9.595323018441329955e-05f, + 2.961728936009675573e-17f, + -9.585243231666533902e-05f, + -1.915076630217971002e-04f, + -2.868695882022341873e-04f, + -3.818425002487855048e-04f, + -4.763311838281015891e-04f, + -5.702410112587507447e-04f, + -6.634780371952385403e-04f, + -7.559490925245654922e-04f, + -8.475618773830773632e-04f, + -9.382250532000561190e-04f, + -1.027848333675624067e-03f, + -1.116342574603918251e-03f, + -1.203619862451413194e-03f, + -1.289593601602254461e-03f, + -1.374178600184431222e-03f, + -1.457291154392131340e-03f, + -1.538849131220664879e-03f, + -1.618772049531532397e-03f, + -1.696981159369096662e-03f, + -1.773399519450076641e-03f, + -1.847952072749128047e-03f, + -1.920565720107696725e-03f, + -1.991169391792951045e-03f, + -2.059694116937665648e-03f, + -2.126073090792308593e-03f, + -2.190241739725098773e-03f, + -2.252137783906322643e-03f, + -2.311701297615694015e-03f, + -2.368874767115570264e-03f, + -2.423603146033716672e-03f, + -2.475833908202009024e-03f, + -2.525517097901476115e-03f, + -2.572605377465290739e-03f, + -2.617054072194128448e-03f, + -2.658821212542411203e-03f, + -2.697867573534989526e-03f, + -2.734156711378059063e-03f, + -2.767654997229715939e-03f, + -2.798331648100023990e-03f, + -2.826158754851514684e-03f, + -2.851111307275881745e-03f, + -2.873167216223860253e-03f, + -2.892307332769767248e-03f, + -2.908515464394205354e-03f, + -2.921778388171670463e-03f, + -2.932085860953250172e-03f, + -2.939430626537135362e-03f, + -2.943808419822793298e-03f, + -2.945217967948095782e-03f, + -2.943660988411156160e-03f, + -2.939142184182125771e-03f, + -2.931669235812944720e-03f, + -2.921252790556253757e-03f, + -2.907906448507473381e-03f, + -2.891646745787318507e-03f, + -2.872493134784635110e-03f, + -2.850467961482642393e-03f, + -2.825596439894601745e-03f, + -2.797906623637558873e-03f, + -2.767429374675792631e-03f, + -2.734198329268788634e-03f, + -2.698249861160541534e-03f, + -2.659623042050382122e-03f, + -2.618359599388156086e-03f, + -2.574503871538993439e-03f, + -2.528102760365492311e-03f, + -2.479205681277817097e-03f, + -2.427864510805224571e-03f, + -2.374133531743618380e-03f, + -2.318069375937653262e-03f, + -2.259730964756961977e-03f, + -2.199179447329721766e-03f, + -2.136478136597202548e-03f, + -2.071692443256429803e-03f, + -2.004889807660292528e-03f, + -1.936139629744864461e-03f, + -1.865513197057068430e-03f, + -1.793083610957797377e-03f, + -1.718925711075672356e-03f, + -1.643115998089900122e-03f, + -1.565732554922428339e-03f, + -1.486854966419205639e-03f, + -1.406564237604140694e-03f, + -1.324942710588779184e-03f, + -1.242073980223971008e-03f, + -1.158042808578502083e-03f, + -1.072935038332762650e-03f, + -9.868375051760999109e-04f, + -8.998379492968846009e-04f, + -8.120249260550908496e-04f, + -7.234877159284703501e-04f, + -6.343162338246114773e-04f, + -5.446009378495034713e-04f, + -4.544327376257831556e-04f, + -3.639029022542405989e-04f, + -2.731029680102384292e-04f, + -1.821246458690281339e-04f, + -9.105972895404852794e-05f, + 2.249668800172135414e-17f, + 9.096286107495146821e-05f, + 1.817373693953476012e-04f, + 2.722323270597744641e-04f, + 3.623569146858229449e-04f, + 4.520207824765948832e-04f, + 5.411341407166387263e-04f, + 6.296078496082298161e-04f, + 7.173535083574583433e-04f, + 8.042835434204669747e-04f, + 8.903112958232611450e-04f, + 9.753511074673767468e-04f, + 1.059318406334858621e-03f, + 1.142129790509272816e-03f, + 1.223703110928572564e-03f, + 1.303957552787602704e-03f, + 1.382813715509965393e-03f, + 1.460193691210495345e-03f, + 1.536021141570667560e-03f, + 1.610221373050487641e-03f, + 1.682721410364203859e-03f, + 1.753450068146556471e-03f, + 1.822338020740059362e-03f, + 1.889317870034044975e-03f, + 1.954324211290346669e-03f, + 2.017293696890905524e-03f, + 2.078165097944757213e-03f, + 2.136879363695696771e-03f, + 2.193379678672519300e-03f, + 2.247611517526280130e-03f, + 2.299522697502668928e-03f, + 2.349063428498731048e-03f, + 2.396186360655621055e-03f, + 2.440846629443004217e-03f, + 2.483001898191590853e-03f, + 2.522612398034211525e-03f, + 2.559640965217286051e-03f, + 2.594053075748732184e-03f, + 2.625816877349718484e-03f, + 2.654903218680989673e-03f, + 2.681285675817290850e-03f, + 2.704940575946320012e-03f, + 2.725847018271134597e-03f, + 2.743986892097757119e-03f, + 2.759344892093201339e-03f, + 2.771908530701254220e-03f, + 2.781668147706524256e-03f, + 2.788616916940388039e-03f, + 2.792750850124972248e-03f, + 2.794068797854331460e-03f, + 2.792572447715026187e-03f, + 2.788266319550961395e-03f, + 2.781157757880268772e-03f, + 2.771256921475067844e-03f, + 2.758576770117475430e-03f, + 2.743133048548284346e-03f, + 2.724944267627588904e-03f, + 2.704031682729127542e-03f, + 2.680419269393146536e-03f, + 2.654133696265428919e-03f, + 2.625204295352332774e-03f, + 2.593663029624824687e-03f, + 2.559544458007235838e-03f, + 2.522885697788194298e-03f, + 2.483726384495194266e-03f, + 2.442108629274998555e-03f, + 2.398076973826478078e-03f, + 2.351678342933034675e-03f, + 2.302961994645597293e-03f, + 2.251979468168421438e-03f, + 2.198784529503366135e-03f, + 2.143433114908959661e-03f, + 2.085983272233949380e-03f, + 2.026495100187157301e-03f, + 1.965030685606198105e-03f, + 1.901654038790769660e-03f, + 1.836431026968307709e-03f, + 1.769429305960019570e-03f, + 1.700718250118553624e-03f, + 1.630368880610306992e-03f, + 1.558453792115264015e-03f, + 1.485047078020867951e-03f, + 1.410224254186159386e-03f, + 1.334062181355563604e-03f, + 1.256638986300702377e-03f, + 1.178033981771610395e-03f, + 1.098327585339919834e-03f, + 1.017601237215742414e-03f, + 9.359373171227939204e-04f, + 8.534190603167809844e-04f, + 7.701304728322726310e-04f, + 6.861562460439943638e-04f, + 6.015816706295592760e-04f, + 5.164925500217144947e-04f, + 4.309751134365081789e-04f, + 3.451159285661133287e-04f, + 2.590018140253294793e-04f, + 1.727197516388577871e-04f, + 8.635679865857319275e-05f, + 0.000000000000000000e+00f, + -8.626369941502123060e-05f, + -1.723475421202091517e-04f, + -2.581650452840001070e-04f, + -3.436300875175078229e-04f, + -4.286569952255241947e-04f, + -5.131606284134141056e-04f, + -5.970564658633488713e-04f, + -6.802606895961190543e-04f, + -7.626902685335093437e-04f, + -8.442630412771376771e-04f, + -9.248977979226647274e-04f, + -1.004514360827295531e-03f, + -1.083033664249621842e-03f, + -1.160377832784585195e-03f, + -1.236470258513610188e-03f, + -1.311235676795854824e-03f, + -1.384600240623468786e-03f, + -1.456491593469362491e-03f, + -1.526838940554491693e-03f, + -1.595573118465392530e-03f, + -1.662626663052574382e-03f, + -1.727933875544430866e-03f, + -1.791430886811391570e-03f, + -1.853055719717038941e-03f, + -1.912748349496546643e-03f, + -1.970450762103117051e-03f, + -2.026107010465434590e-03f, + -2.079663268602624775e-03f, + -2.131067883544039959e-03f, + -2.180271425003505598e-03f, + -2.227226732761336536e-03f, + -2.271888961708070937e-03f, + -2.314215624507658369e-03f, + -2.354166631838931854e-03f, + -2.391704330178351379e-03f, + -2.426793537088085383e-03f, + -2.459401573976375491e-03f, + -2.489498296300512482e-03f, + -2.517056121184375189e-03f, + -2.542050052425464269e-03f, + -2.564457702869174776e-03f, + -2.584259314130737690e-03f, + -2.601437773647668344e-03f, + -2.615978629048301869e-03f, + -2.627870099825200655e-03f, + -2.637103086304351703e-03f, + -2.643671175903983435e-03f, + -2.647570646679886421e-03f, + -2.648800468156370640e-03f, + -2.647362299445082338e-03f, + -2.643260484656465709e-03f, + -2.636502045611470533e-03f, + -2.627096671863705067e-03f, + -2.615056708045107071e-03f, + -2.600397138550693873e-03f, + -2.583135569580662441e-03f, + -2.563292208561044304e-03f, + -2.540889840966167532e-03f, + -2.515953804569251093e-03f, + -2.488511961150026430e-03f, + -2.458594665690286458e-03f, + -2.426234733091499601e-03f, + -2.391467402450208560e-03f, + -2.354330298930778966e-03f, + -2.314863393275341449e-03f, + -2.273108958995205108e-03f, + -2.229111527288808303e-03f, + -2.182917839734724828e-03f, + -2.134576798809103074e-03f, + -2.084139416280047803e-03f, + -2.031658759533671622e-03f, + -1.977189895887380630e-03f, + -1.920789834949013144e-03f, + -1.862517469082529712e-03f, + -1.802433512041404706e-03f, + -1.740600435833956081e-03f, + -1.677082405886637763e-03f, + -1.611945214571482154e-03f, + -1.545256213167279678e-03f, + -1.477084242324090734e-03f, + -1.407499561103702770e-03f, + -1.336573774667974704e-03f, + -1.264379760689891439e-03f, + -1.190991594563459415e-03f, + -1.116484473487968287e-03f, + -1.040934639504879694e-03f, + -9.644193015667102938e-04f, + -8.870165567158059617e-04f, + -8.088053104554945427e-04f, + -7.298651963925226931e-04f, + -6.502764952346872223e-04f, + -5.701200532242376492e-04f, + -4.894772000905328905e-04f, + -4.084296666057908869e-04f, + -3.270595018261514210e-04f, + -2.454489901024086416e-04f, + -1.636805679449392656e-04f, + -8.183674082536929162e-05f, + -3.536521155687695770e-17f, + 8.174726056185484973e-05f, + 1.633228270606075061e-04f, + 2.446447484770642063e-04f, + 3.256314188286605011e-04f, + 4.062016589873803664e-04f, + 4.862747979789591962e-04f, + 5.657707536813316989e-04f, + 6.446101128410288350e-04f, + 7.227142103289445341e-04f, + 8.000052075557968854e-04f, + 8.764061699685609655e-04f, + 9.518411435521427575e-04f, + 1.026235230259113333e-03f, + 1.099514662293880982e-03f, + 1.171606875175669731e-03f, + 1.242440579510656730e-03f, + 1.311945831400333469e-03f, + 1.380054101417801157e-03f, + 1.446698342082995128e-03f, + 1.511813053771716119e-03f, + 1.575334348993146514e-03f, + 1.637200014972404940e-03f, + 1.697349574477985271e-03f, + 1.755724344834148822e-03f, + 1.812267495060354474e-03f, + 1.866924101083174007e-03f, + 1.919641198966668804e-03f, + 1.970367836109312640e-03f, + 2.019055120359112502e-03f, + 2.065656266998848294e-03f, + 2.110126643557067375e-03f, + 2.152423812401290867e-03f, + 2.192507571073842951e-03f, + 2.230339990331663483e-03f, + 2.265885449854030363e-03f, + 2.299110671585404518e-03f, + 2.329984750682085725e-03f, + 2.358479184033766222e-03f, + 2.384567896334751410e-03f, + 2.408227263680306953e-03f, + 2.429436134667956135e-03f, + 2.448175848984440826e-03f, + 2.464430253462965986e-03f, + 2.478185715597053772e-03f, + 2.489431134500083229e-03f, + 2.498157949302601787e-03f, + 2.504360144981462345e-03f, + 2.508034255617927130e-03f, + 2.509179365084111650e-03f, + 2.507797105160097621e-03f, + 2.503891651086268943e-03f, + 2.497469714558282327e-03f, + 2.488540534174480279e-03f, + 2.477115863348166615e-03f, + 2.463209955699809280e-03f, + 2.446839547946541571e-03f, + 2.428023840308957040e-03f, + 2.406784474457862241e-03f, + 2.383145509025629081e-03f, + 2.357133392709743602e-03f, + 2.328776934998069703e-03f, + 2.298107274548326535e-03f, + 2.265157845255661752e-03f, + 2.229964340045592890e-03f, + 2.192564672431069738e-03f, + 2.152998935874733330e-03f, + 2.111309361000000308e-03f, + 2.067540270696137036e-03f, + 2.021738033165410009e-03f, + 1.973951012961244755e-03f, + 1.924229520069206407e-03f, + 1.872625757084688284e-03f, + 1.819193764541884861e-03f, + 1.763989364451496421e-03f, + 1.707070102106509864e-03f, + 1.648495186215746637e-03f, + 1.588325427427724965e-03f, + 1.526623175309085347e-03f, + 1.463452253841756060e-03f, + 1.398877895506348739e-03f, + 1.332966674019096277e-03f, + 1.265786435792502209e-03f, + 1.197406230189095033e-03f, + 1.127896238640391496e-03f, + 1.057327702704293892e-03f, + 9.857728511335100193e-04f, + 9.133048260301522472e-04f, + 8.399976081621432457e-04f, + 7.659259415173617783e-04f, + 6.911652571721143201e-04f, + 6.157915965516007339e-04f, + 5.398815341610210556e-04f, + 4.635120998645952885e-04f, + 3.867607007918734689e-04f, + 3.097050429510698013e-04f, + 2.324230526274301040e-04f, + 1.549927976471593514e-04f, + 7.749240858556649941e-05f, + 0.000000000000000000e+00f, + -7.740640823447261787e-05f, + -1.546489694066701043e-04f, + -2.316500881890203695e-04f, + -3.083324985177912040e-04f, + -3.846193410553054690e-04f, + -4.604342401558712806e-04f, + -5.357013802596746321e-04f, + -6.103455816376617384e-04f, + -6.842923754112235652e-04f, + -7.574680777731551771e-04f, + -8.297998633349399841e-04f, + -9.012158375281924391e-04f, + -9.716451079872685803e-04f, + -1.041017854843918943e-03f, + -1.109265399862380090e-03f, + -1.176320274348555822e-03f, + -1.242116285764278049e-03f, + -1.306588582982534663e-03f, + -1.369673720118763302e-03f, + -1.431309718874978175e-03f, + -1.491436129336623072e-03f, + -1.549994089162047605e-03f, + -1.606926381106289162e-03f, + -1.662177488824047355e-03f, + -1.715693650896988340e-03f, + -1.767422913032514007e-03f, + -1.817315178384378135e-03f, + -1.865322255945725321e-03f, + -1.911397906968511154e-03f, + -1.955497889364013041e-03f, + -1.997580000042790960e-03f, + -2.037604115153256439e-03f, + -2.075532228180405718e-03f, + -2.111328485869323496e-03f, + -2.144959221939368461e-03f, + -2.176392988557203194e-03f, + -2.205600585540104519e-03f, + -2.232555087262260568e-03f, + -2.257231867239448825e-03f, + -2.279608620370068926e-03f, + -2.299665382812773017e-03f, + -2.317384549483214162e-03f, + -2.332750889154779940e-03f, + -2.345751557151114393e-03f, + -2.356376105620029086e-03f, + -2.364616491381328796e-03f, + -2.370467081343168980e-03f, + -2.373924655484415357e-03f, + -2.374988407402560224e-03f, + -2.373659942429402498e-03f, + -2.369943273319134042e-03f, + -2.363844813515844894e-03f, + -2.355373368009962363e-03f, + -2.344540121795531118e-03f, + -2.331358625942570734e-03f, + -2.315844781301389533e-03f, + -2.298016819857692100e-03f, + -2.277895283760072130e-03f, + -2.255503002043453362e-03f, + -2.230865065074793489e-03f, + -2.204008796749007838e-03f, + -2.174963724465795757e-03f, + -2.143761546920198904e-03f, + -2.110436099741713409e-03f, + -2.075023319018890790e-03f, + -2.037561202748555591e-03f, + -1.998089770251173809e-03f, + -1.956651019594995121e-03f, + -1.913288883074297899e-03f, + -1.868049180789196646e-03f, + -1.820979572375211594e-03f, + -1.772129506933642308e-03f, + -1.721550171215585189e-03f, + -1.669294436113043234e-03f, + -1.615416801513268677e-03f, + -1.559973339574200445e-03f, + -1.503021636479029855e-03f, + -1.444620732731039447e-03f, + -1.384831062049924873e-03f, + -1.323714388933566266e-03f, + -1.261333744948669490e-03f, + -1.197753363816366759e-03f, + -1.133038615360030133e-03f, + -1.067255938382161932e-03f, + -1.000472772539666867e-03f, + -9.327574892878164135e-04f, + -8.641793219624978621e-04f, + -7.948082950727303935e-04f, + -7.247151528757850725e-04f, + -6.539712873074342899e-04f, + -5.826486653404457788e-04f, + -5.108197558453200652e-04f, + -4.385574560281823480e-04f, + -3.659350175192179139e-04f, + -2.930259721875476224e-04f, + -2.199040577568145362e-04f, + -1.466431432977234172e-04f, + -7.331715467149604577e-05f, + -1.583863635030426600e-17f, + 7.323450476167464791e-05f, + 1.463127100768226222e-04f, + 2.191612068271459025e-04f, + 2.917068999868720029e-04f, + 3.638770818979462419e-04f, + 4.355995050724186771e-04f, + 5.068024544486168575e-04f, + 5.774148190301226381e-04f, + 6.473661628350382271e-04f, + 7.165867950855838104e-04f, + 7.850078395671508278e-04f, + 8.525613030890458839e-04f, + 9.191801429783286312e-04f, + 9.847983335396156852e-04f, + 1.049350931415344917e-03f, + 1.112774139782065014e-03f, + 1.175005371319211289e-03f, + 1.235983309887723515e-03f, + 1.295647970858855580e-03f, + 1.353940760033357088e-03f, + 1.410804531092786597e-03f, + 1.466183641527706851e-03f, + 1.520024006987588487e-03f, + 1.572273153999021768e-03f, + 1.622880271001914641e-03f, + 1.671796257653338251e-03f, + 1.718973772351856891e-03f, + 1.764367277935770294e-03f, + 1.807933085512109829e-03f, + 1.849629396373906774e-03f, + 1.889416341965344378e-03f, + 1.927256021857423661e-03f, + 1.963112539697747360e-03f, + 1.996952037100198536e-03f, + 2.028742725443338692e-03f, + 2.058454915547453749e-03f, + 2.086061045202587064e-03f, + 2.111535704522703519e-03f, + 2.134855659102633321e-03f, + 2.155999870956868715e-03f, + 2.174949517221738769e-03f, + 2.191688006604752131e-03f, + 2.206200993566935931e-03f, + 2.218476390226378162e-03f, + 2.228504375973802080e-03f, + 2.236277404792865950e-03f, + 2.241790210280533453e-03f, + 2.245039808364943448e-03f, + 2.246025497720799922e-03f, + 2.244748857884364644e-03f, + 2.241213745072582770e-03f, + 2.235426285713204824e-03f, + 2.227394867694926922e-03f, + 2.217130129349095119e-03f, + 2.204644946176507331e-03f, + 2.189954415335300473e-03f, + 2.173075837908174709e-03f, + 2.154028698969212043e-03f, + 2.132834645472967295e-03f, + 2.109517461990493593e-03f, + 2.084103044319416103e-03f, + 2.056619370996764975e-03f, + 2.027096472745798170e-03f, + 1.995566399890039318e-03f, + 1.962063187769620600e-03f, + 1.926622820196907150e-03f, + 1.889283190990552431e-03f, + 1.850084063629192947e-03f, + 1.809067029067121680e-03f, + 1.766275461756697642e-03f, + 1.721754473924256863e-03f, + 1.675550868146924400e-03f, + 1.627713088280349860e-03f, + 1.578291168789072458e-03f, + 1.527336682531643414e-03f, + 1.474902687055531115e-03f, + 1.421043669457084475e-03f, + 1.365815489864515746e-03f, + 1.309275323601538730e-03f, + 1.251481602091836709e-03f, + 1.192493952565831317e-03f, + 1.132373136630967277e-03f, + 1.071180987769143524e-03f, + 1.008980347826006095e-03f, + 9.458350025562797456e-04f, + 8.818096162916508503e-04f, + 8.169696657985963404e-04f, + 7.513813733923349223e-04f, + 6.851116393769219248e-04f, + 6.182279738784716289e-04f, + 5.507984281427341774e-04f, + 4.828915253653128263e-04f, + 4.145761911257870138e-04f, + 3.459216834955630552e-04f, + 2.769975228912344525e-04f, + 2.078734217432808354e-04f, + 1.386192140517258974e-04f, + 6.930478490043769405e-05f, + 3.850678557016620008e-17f, + -6.922536466905694359e-05f, + -1.383016930421246003e-04f, + -2.071595989147220697e-04f, + -2.757299955756169576e-04f, + -3.439441650576845872e-04f, + -4.117338269385969812e-04f, + -4.790312066215028815e-04f, + -5.457691030282071530e-04f, + -6.118809556363564821e-04f, + -6.773009107949520824e-04f, + -7.419638872516609194e-04f, + -8.058056408262444324e-04f, + -8.687628281669950792e-04f, + -9.307730695263674928e-04f, + -9.917750104935054486e-04f, + -1.051708382622899233e-03f, + -1.110514062899539038e-03f, + -1.168134131981801499e-03f, + -1.224511931164258289e-03f, + -1.279592118005431134e-03f, + -1.333320720565457380e-03f, + -1.385645190200188951e-03f, + -1.436514452861111955e-03f, + -1.485878958850318310e-03f, + -1.533690730982715860e-03f, + -1.579903411108077825e-03f, + -1.624472304948763358e-03f, + -1.667354425209425627e-03f, + -1.708508532916933748e-03f, + -1.747895176951601770e-03f, + -1.785476731731549735e-03f, + -1.821217433014094391e-03f, + -1.855083411780856367e-03f, + -1.887042726174312105e-03f, + -1.917065391455589646e-03f, + -1.945123407956183582e-03f, + -1.971190786997232842e-03f, + -1.995243574752887921e-03f, + -2.017259874035835007e-03f, + -2.037219863985523585e-03f, + -2.055105817641905350e-03f, + -2.070902117388888439e-03f, + -2.084595268254915961e-03f, + -2.096173909059424311e-03f, + -2.105628821396557989e-03f, + -2.112952936449467856e-03f, + -2.118141339630974854e-03f, + -2.121191273048350125e-03f, + -2.122102135792170319e-03f, + -2.120875482051600824e-03f, + -2.117515017060413347e-03f, + -2.112026590880362788e-03f, + -2.104418190030685459e-03f, + -2.094699926974599290e-03f, + -2.082884027475962168e-03f, + -2.068984815841183947e-03f, + -2.053018698063778860e-03f, + -2.035004142890892240e-03f, + -2.014961660833440929e-03f, + -1.992913781143200273e-03f, + -1.968885026782406667e-03f, + -1.942901887413728572e-03f, + -1.914992790439534482e-03f, + -1.885188070122604002e-03f, + -1.853519934820884200e-03f, + -1.820022432372197857e-03f, + -1.784731413665374862e-03f, + -1.747684494436782749e-03f, + -1.708921015333154415e-03f, + -1.668482000282380450e-03f, + -1.626410113216474832e-03f, + -1.582749613192508320e-03f, + -1.537546307957996655e-03f, + -1.490847506009852948e-03f, + -1.442701967196525136e-03f, + -1.393159851915445457e-03f, + -1.342272668957837298e-03f, + -1.290093222055339146e-03f, + -1.236675555184266412e-03f, + -1.182074896683267323e-03f, + -1.126347602242422363e-03f, + -1.069551096823031762e-03f, + -1.011743815566986619e-03f, + -9.529851437568570560e-04f, + -8.933353558887932458e-04f, + -8.328555539196910067e-04f, + -7.716076047526932357e-04f, + -7.096540770239413622e-04f, + -6.470581772568036877e-04f, + -5.838836854464510024e-04f, + -5.201948901420694023e-04f, + -4.560565230917139183e-04f, + -3.915336935171430800e-04f, + -3.266918220842130881e-04f, + -2.615965746362512961e-04f, + -1.963137957579778382e-04f, + -1.309094422360982627e-04f, + -6.544951648425400908e-05f, + 0.000000000000000000e+00f, + 6.537321308021720669e-05f, + 1.306043822607082607e-04f, + 1.956279867336831537e-04f, + 2.603787911287086792e-04f, + 3.247919108976276181e-04f, + 3.888028772701663366e-04f, + 4.523477017143444248e-04f, + 5.153629398383980818e-04f, + 5.777857546699370411e-04f, + 6.395539792487880222e-04f, + 7.006061784722651719e-04f, + 7.608817101308743870e-04f, + 8.203207850733748325e-04f, + 8.788645264429036270e-04f, + 9.364550279239102458e-04f, + 9.930354109440190161e-04f, + 1.048549880772794290e-03f, + 1.102943781463442676e-03f, + 1.156163649582898304e-03f, + 1.208157266677142242e-03f, + 1.258873710421226384e-03f, + 1.308263404403530459e-03f, + 1.356278166495282879e-03f, + 1.402871255759119157e-03f, + 1.447997417850374223e-03f, + 1.491612928867637770e-03f, + 1.533675637609531331e-03f, + 1.574145006197766577e-03f, + 1.612982149027046997e-03f, + 1.650149870004234296e-03f, + 1.685612698041884239e-03f, + 1.719336920772085442e-03f, + 1.751290616448417667e-03f, + 1.781443684006613678e-03f, + 1.809767871255424246e-03f, + 1.836236801171283600e-03f, + 1.860825996272981193e-03f, + 1.883512901053582605e-03f, + 1.904276902449677372e-03f, + 1.923099348328973467e-03f, + 1.939963563980765578e-03f, + 1.954854866594344254e-03f, + 1.967760577713456756e-03f, + 1.978670033656380715e-03f, + 1.987574593893788513e-03f, + 1.994467647378149553e-03f, + 1.999344616820692734e-03f, + 2.002202960914168783e-03f, + 2.003042174501439791e-03f, + 2.001863786692200525e-03f, + 1.998671356932133197e-03f, + 1.993470469030853877e-03f, + 1.986268723157068750e-03f, + 1.977075725811386266e-03f, + 1.965903077789286045e-03f, + 1.952764360148673750e-03f, + 1.937675118198656623e-03f, + 1.920652843527819766e-03f, + 1.901716954092479844e-03f, + 1.880888772387422731e-03f, + 1.858191501723117835e-03f, + 1.833650200635677813e-03f, + 1.807291755457605693e-03f, + 1.779144851079101806e-03f, + 1.749239939931425750e-03f, + 1.717609209225661468e-03f, + 1.684286546482327823e-03f, + 1.649307503388023569e-03f, + 1.612709258017795862e-03f, + 1.574530575463451180e-03f, + 1.534811766908859409e-03f, + 1.493594647195765511e-03f, + 1.450922490924287005e-03f, + 1.406839987134609086e-03f, + 1.361393192616601943e-03f, + 1.314629483896238502e-03f, + 1.266597507949261160e-03f, + 1.217347131692460890e-03f, + 1.166929390305300809e-03f, + 1.115396434435750447e-03f, + 1.062801476344078485e-03f, + 1.009198735040490926e-03f, + 9.546433804735578524e-04f, + 8.991914768259076738e-04f, + 8.428999249761178706e-04f, + 7.858264041852376820e-04f, + 7.280293130684387321e-04f, + 6.695677099108536621e-04f, + 6.105012523900892442e-04f, + 5.508901367652243143e-04f, + 4.907950365958332764e-04f, + 4.302770410520321762e-04f, + 3.693975928787344835e-04f, + 3.082184260775406768e-04f, + 2.468015033684312445e-04f, + 1.852089534950353614e-04f, + 1.235030084373483811e-04f, + 6.174594059430125743e-05f, + 2.096293806310516030e-17f, + -6.167264836248043244e-05f, + -1.232099870881719884e-04f, + -1.845502086537135426e-04f, + -2.456317774361367959e-04f, + -3.063934913834511463e-04f, + -3.667745432764744212e-04f, + -4.267145815201261821e-04f, + -4.861537704029955404e-04f, + -5.450328497660459227e-04f, + -6.032931940205293235e-04f, + -6.608768704559289274e-04f, + -7.177266967809564115e-04f, + -7.737862978399837359e-04f, + -8.290001614485750878e-04f, + -8.833136932931055871e-04f, + -9.366732708404333684e-04f, + -9.890262962043143858e-04f, + -1.040321247916032189e-03f, + -1.090507731549242732e-03f, + -1.139536529148920665e-03f, + -1.187359647415603143e-03f, + -1.233930364598734937e-03f, + -1.279203276052626528e-03f, + -1.323134338411260068e-03f, + -1.365680912338360217e-03f, + -1.406801803812153832e-03f, + -1.446457303904537337e-03f, + -1.484609227016050938e-03f, + -1.521220947530623618e-03f, + -1.556257434854668676e-03f, + -1.589685286806867721e-03f, + -1.621472761327541912e-03f, + -1.651589806477331930e-03f, + -1.680008088696766707e-03f, + -1.706701019300830170e-03f, + -1.731643779183499347e-03f, + -1.754813341709760346e-03f, + -1.776188493773842719e-03f, + -1.795749855005169008e-03f, + -1.813479895104255042e-03f, + -1.829362949293911016e-03f, + -1.843385231871876419e-03f, + -1.855534847853930556e-03f, + -1.865801802697809961e-03f, + -1.874178010100366288e-03f, + -1.880657297862605663e-03f, + -1.885235411818870100e-03f, + -1.887910017828480034e-03f, + -1.888680701830295272e-03f, + -1.887548967962307056e-03f, + -1.884518234750538193e-03f, + -1.879593829373407774e-03f, + -1.872782980009604853e-03f, + -1.864094806279484534e-03f, + -1.853540307791953041e-03f, + -1.841132350810590528e-03f, + -1.826885653054665781e-03f, + -1.810816766652771246e-03f, + -1.792944059268252940e-03f, + -1.773287693417722457e-03f, + -1.751869604005822220e-03f, + -1.728713474100759947e-03f, + -1.703844708977252705e-03f, + -1.677290408455194264e-03f, + -1.649079337563943938e-03f, + -1.619241895563655999e-03f, + -1.587810083356924057e-03f, + -1.554817469325785705e-03f, + -1.520299153629931172e-03f, + -1.484291731004316970e-03f, + -1.446833252095214512e-03f, + -1.407963183375834622e-03f, + -1.367722365683123140e-03f, + -1.326152971419345067e-03f, + -1.283298460463622734e-03f, + -1.239203534838731165e-03f, + -1.193914092180647360e-03f, + -1.147477178059556511e-03f, + -1.099940937201084957e-03f, + -1.051354563658511796e-03f, + -1.001768249987922176e-03f, + -9.512331354778615728e-04f, + -8.998012534875231673e-04f, + -8.475254779470752691e-04f, + -7.944594690758058310e-04f, + -7.406576183728511139e-04f, + -6.861749929372944591e-04f, + -6.310672791747117981e-04f, + -5.753907259474574801e-04f, + -5.192020872264638655e-04f, + -4.625585643030877768e-04f, + -4.055177476203069577e-04f, + -3.481375582814421167e-04f, + -2.904761892961940780e-04f, + -2.325920466240080111e-04f, + -1.745436900735062170e-04f, + -1.163897741181921285e-04f, + -5.818898868865390200e-05f, + -3.951477669352645278e-17f, + 5.811860852513058267e-05f, + 1.161083951789106388e-04f, + 1.739111186764226750e-04f, + 2.314687965911455317e-04f, + 2.887237634590489712e-04f, + 3.456187284925843007e-04f, + 4.020968328478077619e-04f, + 4.581017063869804681e-04f, + 5.135775238795969085e-04f, + 5.684690605867797827e-04f, + 6.227217471732920040e-04f, + 6.762817238922043568e-04f, + 7.290958939893588033e-04f, + 7.811119762742447376e-04f, + 8.322785568051721625e-04f, + 8.825451396379117895e-04f, + 9.318621965879654058e-04f, + 9.801812159573458638e-04f, + 1.027454750177579689e-03f, + 1.073636462323048543e-03f, + 1.118681171448473750e-03f, + 1.162544896706745696e-03f, + 1.205184900203477068e-03f, + 1.246559728547386213e-03f, + 1.286629253055807933e-03f, + 1.325354708576141497e-03f, + 1.362698730886437387e-03f, + 1.398625392638811350e-03f, + 1.433100237810905602e-03f, + 1.466090314633128333e-03f, + 1.497564206959974605e-03f, + 1.527492064055464794e-03f, + 1.555845628765160742e-03f, + 1.582598264047852974e-03f, + 1.607724977842486065e-03f, + 1.631202446246891868e-03f, + 1.653009034987472543e-03f, + 1.673124819160033650e-03f, + 1.691531601223876481e-03f, + 1.708212927233296189e-03f, + 1.723154101292263601e-03f, + 1.736342198219845579e-03f, + 1.747766074415657220e-03f, + 1.757416376916791541e-03f, + 1.765285550639219018e-03f, + 1.771367843798416159e-03f, + 1.775659311506234831e-03f, + 1.778157817542435270e-03f, + 1.778863034301330324e-03f, + 1.777776440915891046e-03f, + 1.774901319563383737e-03f, + 1.770242749958432374e-03f, + 1.763807602041371232e-03f, + 1.755604526871366649e-03f, + 1.745643945735682106e-03f, + 1.733938037488337493e-03f, + 1.720500724132964119e-03f, + 1.705347654666533944e-03f, + 1.688496187202536726e-03f, + 1.669965369393517111e-03f, + 1.649775917174820059e-03f, + 1.627950191853253523e-03f, + 1.604512175565338738e-03f, + 1.579487445132431861e-03f, + 1.552903144340421785e-03f, + 1.524787954674487571e-03f, + 1.495172064539795074e-03f, + 1.464087137001309370e-03f, + 1.431566276076835656e-03f, + 1.397643991619413597e-03f, + 1.362356162825694014e-03f, + 1.325740000408985944e-03f, + 1.287834007477042493e-03f, + 1.248677939155022100e-03f, + 1.208312760996174511e-03f, + 1.166780606223920529e-03f, + 1.124124731849302948e-03f, + 1.080389473709662384e-03f, + 1.035620200475557496e-03f, + 9.898632666728486313e-04f, + 9.431659647690965754e-04f, + 8.955764763732448116e-04f, + 8.471438225995464935e-04f, + 7.979178136459807611e-04f, + 7.479489976393288025e-04f, + 6.972886087997711303e-04f, + 6.459885149773112378e-04f, + 5.941011646141058575e-04f, + 5.416795331870154695e-04f, + 4.887770691848273815e-04f, + 4.354476396749826271e-04f, + 3.817454755153243395e-04f, + 3.277251162670002699e-04f, + 2.734413548635745875e-04f, + 2.189491820928326409e-04f, + 1.643037309479273775e-04f, + 1.095602209032437102e-04f, + 5.477390217168007973e-05f, + 0.000000000000000000e+00f, + -5.470634094252695156e-05f, + -1.092901120256077629e-04f, + -1.636964959141602542e-04f, + -2.178709215633056469e-04f, + -2.717591188977905368e-04f, + -3.253071731207118249e-04f, + -3.784615785968173970e-04f, + -4.311692922574608179e-04f, + -4.833777864735189634e-04f, + -5.350351013432206020e-04f, + -5.860898963437366797e-04f, + -6.364915012948296367e-04f, + -6.861899665835708047e-04f, + -7.351361126015605119e-04f, + -7.832815783443825139e-04f, + -8.305788691267564604e-04f, + -8.769814033650232248e-04f, + -9.224435583820854738e-04f, + -9.669207151891035966e-04f, + -1.010369302200565247e-03f, + -1.052746837839338510e-03f, + -1.094011971990893574e-03f, + -1.134124526265950332e-03f, + -1.173045533032109934e-03f, + -1.210737273177340265e-03f, + -1.247163312568430474e-03f, + -1.282288537169006893e-03f, + -1.316079186783988613e-03f, + -1.348502887397804448e-03f, + -1.379528682075299327e-03f, + -1.409127060396503806e-03f, + -1.437269986396952099e-03f, + -1.463930924987541645e-03f, + -1.489084866828790932e-03f, + -1.512708351636820334e-03f, + -1.534779489899245307e-03f, + -1.555277982980894256e-03f, + -1.574185141601471948e-03f, + -1.591483902668316052e-03f, + -1.607158844449279840e-03f, + -1.621196200072613954e-03f, + -1.633583869342330195e-03f, + -1.644311428859175465e-03f, + -1.653370140439019498e-03f, + -1.660752957822507871e-03f, + -1.666454531671149753e-03f, + -1.670471212846983723e-03f, + -1.672801053974688886e-03f, + -1.673443809286669515e-03f, + -1.672400932753375074e-03f, + -1.669675574502914881e-03f, + -1.665272575535695033e-03f, + -1.659198460741494619e-03f, + -1.651461430228174168e-03f, + -1.642071348972851856e-03f, + -1.631039734807969606e-03f, + -1.618379744756649665e-03f, + -1.604106159732930550e-03f, + -1.588235367624443381e-03f, + -1.570785344776701219e-03f, + -1.551775635899458553e-03f, + -1.531227332417528422e-03f, + -1.509163049289567434e-03f, + -1.485606900320671090e-03f, + -1.460584471994783983e-03f, + -1.434122795855729757e-03f, + -1.406250319466170913e-03f, + -1.376996875975918010e-03f, + -1.346393652331567652e-03f, + -1.314473156161391357e-03f, + -1.281269181370805988e-03f, + -1.246816772484174701e-03f, + -1.211152187770746713e-03f, + -1.174312861193657241e-03f, + -1.136337363221307049e-03f, + -1.097265360542288778e-03f, + -1.057137574726171045e-03f, + -1.015995739872469503e-03f, + -9.738825592923504131e-04f, + -9.308416612674603454e-04f, + -8.869175539322839185e-04f, + -8.421555793258690996e-04f, + -7.966018666606091347e-04f, + -7.503032848565528582e-04f, + -7.033073943892899100e-04f, + -6.556623985011526476e-04f, + -6.074170938261656567e-04f, + -5.586208204781806371e-04f, + -5.093234116545103949e-04f, + -4.595751428051017724e-04f, + -4.094266804203762987e-04f, + -3.589290304887579673e-04f, + -3.081334866766899275e-04f, + -2.570915782841462450e-04f, + -2.058550180275716367e-04f, + -1.544756497035134832e-04f, + -1.030053957862678347e-04f, + -5.149620501158499536e-05f, + -2.384103929205831118e-17f, + 5.143137502784089743e-05f, + 1.027462063910287337e-04f, + 1.538929628910742572e-04f, + 2.048203475057252935e-04f, + 2.554773487812054080e-04f, + 3.058132918724349066e-04f, + 3.557778891797814462e-04f, + 4.053212905313948854e-04f, + 4.543941328619231237e-04f, + 5.029475893377426772e-04f, + 5.509334178794880440e-04f, + 5.983040090345575221e-04f, + 6.450124331513995514e-04f, + 6.910124868096819382e-04f, + 7.362587384591508678e-04f, + 7.807065732238670707e-04f, + 8.243122368263766566e-04f, + 8.670328785894033810e-04f, + 9.088265934721979824e-04f, + 9.496524631011158801e-04f, + 9.894705957539746879e-04f, + 1.028242165258874252e-03f, + 1.065929448770301484e-03f, + 1.102495863385499807e-03f, + 1.137906001565360849e-03f, + 1.172125665326259570e-03f, + 1.205121899169577957e-03f, + 1.236863021717049538e-03f, + 1.267318656022278301e-03f, + 1.296459758529015880e-03f, + 1.324258646649080235e-03f, + 1.350689024933432675e-03f, + 1.375726009812287777e-03f, + 1.399346152880900310e-03f, + 1.421527462709165374e-03f, + 1.442249425155372978e-03f, + 1.461493022165247842e-03f, + 1.479240749039111274e-03f, + 1.495476630152138510e-03f, + 1.510186233113277763e-03f, + 1.523356681351052851e-03f, + 1.534976665115079944e-03f, + 1.545036450884612481e-03f, + 1.553527889176402723e-03f, + 1.560444420746071904e-03f, + 1.565781081178877019e-03f, + 1.569534503867175447e-03f, + 1.571702921373700117e-03f, + 1.572286165181262111e-03f, + 1.571285663831225405e-03f, + 1.568704439454675749e-03f, + 1.564547102701767346e-03f, + 1.558819846076479193e-03f, + 1.551530435685405255e-03f, + 1.542688201411057929e-03f, + 1.532304025521471613e-03f, + 1.520390329729599246e-03f, + 1.506961060717611732e-03f, + 1.492031674142519585e-03f, + 1.475619117141234709e-03f, + 1.457741809354577093e-03f, + 1.438419622491405236e-03f, + 1.417673858455001249e-03f, + 1.395527226055938864e-03f, + 1.372003816336560527e-03f, + 1.347129076533619364e-03f, + 1.320929782707246439e-03f, + 1.293434011065339607e-03f, + 1.264671108014265698e-03f, + 1.234671658967309224e-03f, + 1.203467455944029225e-03f, + 1.171091463995042447e-03f, + 1.137577786487074328e-03f, + 1.102961629284945943e-03f, + 1.067279263868331236e-03f, + 1.030567989421257843e-03f, + 9.928660939341588630e-04f, + 9.542128143592528474e-04f, + 9.146482958600143324e-04f, + 8.742135501974977914e-04f, + 8.329504132961628631e-04f, + 7.909015020336008844e-04f, + 7.481101702980445106e-04f, + 7.046204643591989737e-04f, + 6.604770775986386951e-04f, + 6.157253046455315841e-04f, + 5.704109949650640419e-04f, + 5.245805059471973005e-04f, + 4.782806555435268323e-04f, + 4.315586745004174507e-04f, + 3.844621582371941467e-04f, + 3.370390184187921768e-04f, + 2.893374342713311603e-04f, + 2.414058036903930554e-04f, + 1.932926941919554573e-04f, + 1.450467937548224429e-04f, + 9.671686160493662174e-05f, + 4.835167899075133784e-05f, + 0.000000000000000000e+00f, + -4.828949753345398863e-05f, + -9.646826098282474608e-05f, + -1.444879116922577944e-04f, + -1.923002935030318679e-04f, + -2.398575209931877504e-04f, + -2.871120273819045897e-04f, + -3.340166120515270496e-04f, + -3.805244876394365660e-04f, + -4.265893266524579085e-04f, + -4.721653075582231689e-04f, + -5.172071603070152717e-04f, + -5.616702112394265662e-04f, + -6.055104273346537417e-04f, + -6.486844597567101994e-04f, + -6.911496866543188596e-04f, + -7.328642551735467438e-04f, + -7.737871226406448826e-04f, + -8.138780968755867382e-04f, + -8.530978755963916508e-04f, + -8.914080848753665014e-04f, + -9.287713166103488344e-04f, + -9.651511649741133930e-04f, + -1.000512261806224762e-03f, + -1.034820310913592929e-03f, + -1.068042121246285314e-03f, + -1.100145638916268705e-03f, + -1.131099978028938862e-03f, + -1.160875450297352155e-03f, + -1.189443593411230841e-03f, + -1.216777198133303000e-03f, + -1.242850334097847032e-03f, + -1.267638374286776453e-03f, + -1.291118018160179043e-03f, + -1.313267313420094689e-03f, + -1.334065676387146760e-03f, + -1.353493910971104207e-03f, + -1.371534226218442407e-03f, + -1.388170252420803863e-03f, + -1.403387055769956442e-03f, + -1.417171151546464019e-03f, + -1.429510515830663278e-03f, + -1.440394595726007159e-03f, + -1.449814318086319878e-03f, + -1.457762096740287039e-03f, + -1.464231838207676094e-03f, + -1.469218945903567495e-03f, + -1.472720322828254208e-03f, + -1.474734372742105958e-03f, + -1.475260999826186192e-03f, + -1.474301606830856525e-03f, + -1.471859091716282196e-03f, + -1.467937842790105170e-03f, + -1.462543732349215952e-03f, + -1.455684108833884020e-03f, + -1.447367787504157772e-03f, + -1.437605039649846777e-03f, + -1.426407580346835237e-03f, + -1.413788554773978299e-03f, + -1.399762523106214953e-03f, + -1.384345444001102527e-03f, + -1.367554656697077568e-03f, + -1.349408861743359471e-03f, + -1.329928100382799265e-03f, + -1.309133732610135619e-03f, + -1.287048413929449148e-03f, + -1.263696070835965916e-03f, + -1.239101875048799527e-03f, + -1.213292216521904285e-03f, + -1.186294675262172631e-03f, + -1.158137991984896625e-03f, + -1.128852037637259912e-03f, + -1.098467781822281067e-03f, + -1.067017260156693896e-03f, + -1.034533540596639092e-03f, + -1.001050688766642752e-03f, + -9.666037323284525605e-04f, + -9.312286244263419952e-04f, + -8.949622062474039356e-04f, + -8.578421687353971186e-04f, + -8.199070134983350812e-04f, + -7.811960129497022435e-04f, + -7.417491697247534464e-04f, + -7.016071754140860680e-04f, + -6.608113686563731959e-04f, + -6.194036926336412294e-04f, + -5.774266520130750657e-04f, + -5.349232693788336665e-04f, + -4.919370411988257261e-04f, + -4.485118933715837031e-04f, + -4.046921363984502134e-04f, + -3.605224202266125153e-04f, + -3.160476888090664981e-04f, + -2.713131344280844096e-04f, + -2.263641518278198237e-04f, + -1.812462922031631745e-04f, + -1.360052170909635560e-04f, + -9.068665221087721649e-05f, + -4.533634130168751519e-05f, + -1.119205495635177410e-17f, + 4.527673019179228291e-05f, + 9.044832780293992876e-05f, + 1.354694371103048339e-04f, + 1.802949136270320799e-04f, + 2.248798693188531084e-04f, + 2.691797175024917524e-04f, + 3.131502173809525350e-04f, + 3.567475181720213820e-04f, + 3.999282027853717433e-04f, + 4.426493310053094079e-04f, + 4.848684821356317727e-04f, + 5.265437970650557525e-04f, + 5.676340197111919006e-04f, + 6.080985378017700815e-04f, + 6.478974229535403896e-04f, + 6.869914700090091119e-04f, + 7.253422355920121755e-04f, + 7.629120758449196762e-04f, + 7.996641833101642005e-04f, + 8.355626229197331365e-04f, + 8.705723670581514643e-04f, + 9.046593296642918905e-04f, + 9.377903993392572779e-04f, + 9.699334714277904395e-04f, + 1.001057479042750638e-03f, + 1.031132423002631329e-03f, + 1.060129400652862165e-03f, + 1.088020633543997301e-03f, + 1.114779493940055944e-03f, + 1.140380530131902001e-03f, + 1.164799490531472428e-03f, + 1.188013346524613607e-03f, + 1.210000314060736106e-03f, + 1.230739873959466437e-03f, + 1.250212790915166154e-03f, + 1.268401131182280697e-03f, + 1.285288278925214404e-03f, + 1.300858951217885064e-03f, + 1.315099211679921550e-03f, + 1.327996482737379275e-03f, + 1.339539556497333726e-03f, + 1.349718604227470977e-03f, + 1.358525184432789320e-03f, + 1.365952249523105658e-03f, + 1.371994151066654273e-03f, + 1.376646643626202498e-03f, + 1.379906887175804363e-03f, + 1.381773448097536276e-03f, + 1.382246298759191167e-03f, + 1.381326815675158054e-03f, + 1.379017776254279782e-03f, + 1.375323354139781646e-03f, + 1.370249113147892998e-03f, + 1.363801999813117269e-03f, + 1.355990334549495588e-03f, + 1.346823801438608650e-03f, + 1.336313436656531026e-03f, + 1.324471615553049963e-03f, + 1.311312038398147750e-03f, + 1.296849714811698206e-03f, + 1.281100946894079716e-03f, + 1.264083311076190895e-03f, + 1.245815638708950906e-03f, + 1.226317995413717370e-03f, + 1.205611659215808989e-03f, + 1.183719097484903357e-03f, + 1.160663942707366959e-03f, + 1.136470967116147033e-03f, + 1.111166056205482996e-03f, + 1.084776181158849176e-03f, + 1.057329370218964941e-03f, + 1.028854679030497465e-03f, + 9.993821599864546878e-04f, + 9.689428306109160735e-04f, + 9.375686410107936589e-04f, + 9.052924404308006949e-04f, + 8.721479429470286020e-04f, + 8.381696923342349089e-04f, + 8.033930261436254697e-04f, + 7.678540390285455838e-04f, + 7.315895453557641741e-04f, + 6.946370411414883386e-04f, + 6.570346653508382520e-04f, + 6.188211606008807691e-04f, + 5.800358333080047517e-04f, + 5.407185133199405181e-04f, + 5.009095130741225872e-04f, + 4.606495863245328032e-04f, + 4.199798864786004988e-04f, + 3.789419245869958758e-04f, + 3.375775270294791236e-04f, + 2.959287929392034368e-04f, + 2.540380514093228668e-04f, + 2.119478185249197815e-04f, + 1.697007542644115945e-04f, + 1.273396193133593797e-04f, + 8.490723183468631443e-05f, + 4.244642423929934338e-05f, + 2.489132717092975244e-17f, + -4.238930944730621606e-05f, + -8.467888767193799395e-05f, + -1.268262760429604032e-04f, + -1.687892163075062216e-04f, + -2.105256929093874817e-04f, + -2.519939750065616508e-04f, + -2.931526581448565673e-04f, + -3.339607055468352646e-04f, + -3.743774889740940815e-04f, + -4.143628291230573081e-04f, + -4.538770355138195783e-04f, + -4.928809458321817922e-04f, + -5.313359646865749471e-04f, + -5.692041017412580173e-04f, + -6.064480091878560880e-04f, + -6.430310185189792816e-04f, + -6.789171765674388570e-04f, + -7.140712807754315923e-04f, + -7.484589136597800171e-04f, + -7.820464764390349256e-04f, + -8.148012217900297898e-04f, + -8.466912857015470575e-04f, + -8.776857183947638259e-04f, + -9.077545142802680937e-04f, + -9.368686409224388084e-04f, + -9.650000669841776822e-04f, + -9.921217891239340544e-04f, + -1.018207857820698729e-03f, + -1.043233402101169816e-03f, + -1.067174653146455267e-03f, + -1.090008966755562705e-03f, + -1.111714844644859455e-03f, + -1.132271954563242268e-03f, + -1.151661149204728438e-03f, + -1.169864483900832875e-03f, + -1.186865233076385287e-03f, + -1.202647905454177829e-03f, + -1.217198257994649147e-03f, + -1.230503308558112416e-03f, + -1.242551347278776424e-03f, + -1.253331946640669171e-03f, + -1.262835970246984230e-03f, + -1.271055580275981447e-03f, + -1.277984243617538056e-03f, + -1.283616736686040089e-03f, + -1.287949148906458816e-03f, + -1.290978884872014988e-03f, + -1.292704665172990245e-03f, + -1.293126525897621585e-03f, + -1.292245816807471729e-03f, + -1.290065198190826342e-03f, + -1.286588636399150143e-03f, + -1.281821398072865732e-03f, + -1.275770043064026376e-03f, + -1.268442416064888972e-03f, + -1.259847636952461181e-03f, + -1.249996089860607850e-03f, + -1.238899410992382174e-03f, + -1.226570475186708736e-03f, + -1.213023381254520064e-03f, + -1.198273436100851744e-03f, + -1.182337137650689993e-03f, + -1.165232156597218035e-03f, + -1.146977316992536366e-03f, + -1.127592575702190524e-03f, + -1.107099000745486849e-03f, + -1.085518748545065719e-03f, + -1.062875040110370555e-03f, + -1.039192136180123365e-03f, + -1.014495311350580541e-03f, + -9.888108272168318318e-04f, + -9.621659045558878355e-04f, + -9.345886945805340160e-04f, + -9.061082492943768954e-04f, + -8.767544909794978232e-04f, + -8.465581808478967385e-04f, + -8.155508868906216624e-04f, + -7.837649509569552704e-04f, + -7.512334550985514227e-04f, + -7.179901872135618750e-04f, + -6.840696060258972568e-04f, + -6.495068054360894584e-04f, + -6.143374782808354653e-04f, + -5.785978795380620956e-04f, + -5.423247890156327302e-04f, + -5.055554735623122827e-04f, + -4.683276488392193763e-04f, + -4.306794406911591301e-04f, + -3.926493461576842912e-04f, + -3.542761941630523837e-04f, + -3.155991059257000266e-04f, + -2.766574551271435236e-04f, + -2.374908278813562743e-04f, + -1.981389825446179249e-04f, + -1.586418094068897395e-04f, + -1.190392903058594805e-04f, + -7.937145820385292140e-05f, + -3.967835676875259741e-05f, + 0.000000000000000000e+00f, + 3.962366806029014220e-05f, + 7.915281349029238485e-05f, + 1.185477524848153186e-04f, + 1.577689911456342596e-04f, + 1.967772650253714708e-04f, + 2.355335783858113143e-04f, + 2.739992431308870902e-04f, + 3.121359173761859267e-04f, + 3.499056436162521094e-04f, + 3.872708864514444720e-04f, + 4.241945698375216493e-04f, + 4.606401138207244462e-04f, + 4.965714707217308132e-04f, + 5.319531607333346764e-04f, + 5.667503068964558190e-04f, + 6.009286694197791883e-04f, + 6.344546793099163770e-04f, + 6.672954712786205531e-04f, + 6.994189158952225562e-04f, + 7.307936509524349481e-04f, + 7.613891120155314102e-04f, + 7.911755621249407519e-04f, + 8.201241206232327396e-04f, + 8.482067910791271214e-04f, + 8.753964882812977381e-04f, + 9.016670642761047145e-04f, + 9.269933334240764138e-04f, + 9.513510964518079316e-04f, + 9.747171634758099818e-04f, + 9.970693759769062425e-04f, + 1.018386627704094679e-03f, + 1.038648884488686591e-03f, + 1.057837202950029669e-03f, + 1.075933748075338925e-03f, + 1.092921809657792587e-03f, + 1.108785817577722472e-03f, + 1.123511355912956439e-03f, + 1.137085175865973829e-03f, + 1.149495207496349907e-03f, + 1.160730570248186353e-03f, + 1.170781582263828594e-03f, + 1.179639768475975034e-03f, + 1.187297867471814568e-03f, + 1.193749837123847697e-03f, + 1.198990858983596747e-03f, + 1.203017341435374133e-03f, + 1.205826921608644554e-03f, + 1.207418466048858175e-03f, + 1.207792070147742499e-03f, + 1.206949056335355347e-03f, + 1.204891971037466616e-03f, + 1.201624580403049501e-03f, + 1.197151864807891562e-03f, + 1.191480012141583498e-03f, + 1.184616409886339811e-03f, + 1.176569635997314197e-03f, + 1.167349448595342331e-03f, + 1.156966774484061893e-03f, + 1.145433696504678973e-03f, + 1.132763439742820021e-03f, + 1.118970356602857433e-03f, + 1.104069910766385543e-03f, + 1.088078660052710107e-03f, + 1.071014238199964868e-03f, + 1.052895335586819490e-03f, + 1.033741678915853354e-03f, + 1.013574009880266035e-03f, + 9.924140628370767443e-04f, + 9.702845415105564161e-04f, + 9.472090947510056159e-04f, + 9.232122913743140771e-04f, + 8.983195941091211278e-04f, + 8.725573326793036348e-04f, + 8.459526760497619287e-04f, + 8.185336038648948062e-04f, + 7.903288771097757327e-04f, + 7.613680080244982808e-04f, + 7.316812293033188221e-04f, + 7.012994626104158578e-04f, + 6.702542864450650520e-04f, + 6.385779033898540073e-04f, + 6.063031067753177393e-04f, + 5.734632467957093789e-04f, + 5.400921961110872679e-04f, + 5.062243149706446149e-04f, + 4.718944158933642270e-04f, + 4.371377279425392405e-04f, + 4.019898606301749847e-04f, + 3.664867674887073131e-04f, + 3.306647093468514844e-04f, + 2.945602173475719322e-04f, + 2.582100557452125193e-04f, + 2.216511845199241977e-04f, + 1.849207218476427064e-04f, + 1.480559064630949787e-04f, + 1.110940599542368509e-04f, + 7.407254902655125068e-05f, + 3.702874777472067589e-05f, + 1.371254292486084993e-17f, + -3.697641838836769948e-05f, + -7.386333685080383616e-05f, + -1.106237275354719183e-04f, + -1.472207424002393370e-04f, + -1.836177501005376326e-04f, + -2.197783726069668013e-04f, + -2.556665215157765151e-04f, + -2.912464340157351313e-04f, + -3.264827084761888032e-04f, + -3.613403396206332991e-04f, + -3.957847532506383946e-04f, + -4.297818404862966193e-04f, + -4.632979914890506846e-04f, + -4.963001286333401738e-04f, + -5.287557390949833508e-04f, + -5.606329068237270391e-04f, + -5.919003438689767176e-04f, + -6.225274210275311962e-04f, + -6.524841977839308848e-04f, + -6.817414515139428016e-04f, + -7.102707059225399746e-04f, + -7.380442586892487162e-04f, + -7.650352082938549928e-04f, + -7.912174799963587243e-04f, + -8.165658509465838124e-04f, + -8.410559743992581695e-04f, + -8.646644030108421603e-04f, + -8.873686111969257854e-04f, + -9.091470165279773525e-04f, + -9.299790001438900484e-04f, + -9.498449261678874270e-04f, + -9.687261601014614341e-04f, + -9.866050861835819630e-04f, + -1.003465123697943424e-03f, + -1.019290742213164363e-03f, + -1.034067475742384131e-03f, + -1.047781935809330650e-03f, + -1.060421823409143580e-03f, + -1.071975939853697006e-03f, + -1.082434196491879799e-03f, + -1.091787623296736802e-03f, + -1.100028376312290647e-03f, + -1.107149743954318269e-03f, + -1.113146152160276754e-03f, + -1.118013168384754657e-03f, + -1.121747504438212967e-03f, + -1.124347018167691677e-03f, + -1.125810713979439898e-03f, + -1.126138742204658245e-03f, + -1.125332397310586279e-03f, + -1.123394114960401657e-03f, + -1.120327467926549893e-03f, + -1.116137160863255560e-03f, + -1.110829023945101137e-03f, + -1.104410005379749494e-03f, + -1.096888162803940974e-03f, + -1.088272653573009452e-03f, + -1.078573723955405161e-03f, + -1.067802697244547546e-03f, + -1.055971960801616169e-03f, + -1.043094952043956310e-03f, + -1.029186143394582309e-03f, + -1.014261026209532400e-03f, + -9.983360937008427163e-04f, + -9.814288228736027086e-04f, + -9.635576554969104172e-04f, + -9.447419781291415113e-04f, + -9.250021012192831361e-04f, + -9.043592373064512696e-04f, + -8.828354783409939847e-04f, + -8.604537721515002468e-04f, + -8.372378980823497055e-04f, + -8.132124418277322840e-04f, + -7.884027694888517653e-04f, + -7.628350008812852896e-04f, + -7.365359821204960078e-04f, + -7.095332575148247155e-04f, + -6.818550407942288718e-04f, + -6.535301857058335630e-04f, + -6.245881560060952261e-04f, + -5.950589948810114296e-04f, + -5.649732938262623386e-04f, + -5.343621610190059943e-04f, + -5.032571892141756960e-04f, + -4.716904231986256981e-04f, + -4.396943268360438742e-04f, + -4.073017497369382724e-04f, + -3.745458935874993508e-04f, + -3.414602781722681792e-04f, + -3.080787071247825435e-04f, + -2.744352334413967037e-04f, + -2.405641247936734649e-04f, + -2.064998286741144789e-04f, + -1.722769374108738480e-04f, + -1.379301530872341895e-04f, + -1.034942524008109811e-04f, + -6.900405149830530008e-05f, + -3.449437082158992495e-05f, + 0.000000000000000000e+00f, + 3.444433717537312282e-05f, + 6.880401766040344078e-05f, + 1.030445539143494854e-04f, + 1.371316284694892038e-04f, + 1.710311282792226217e-04f, + 2.047091788099896501e-04f, + 2.381321778435391604e-04f, + 2.712668289555900309e-04f, + 3.040801746373052975e-04f, + 3.365396290272290244e-04f, + 3.686130102209533182e-04f, + 4.002685721262641268e-04f, + 4.314750358328316138e-04f, + 4.622016204652085376e-04f, + 4.924180734885345943e-04f, + 5.220947004376862242e-04f, + 5.512023940402758712e-04f, + 5.797126627053133911e-04f, + 6.075976583493116747e-04f, + 6.348302035331886400e-04f, + 6.613838178833868642e-04f, + 6.872327437713459134e-04f, + 7.123519712269649109e-04f, + 7.367172620617903596e-04f, + 7.603051731785161974e-04f, + 7.830930790451201724e-04f, + 8.050591933112499331e-04f, + 8.261825895472138482e-04f, + 8.464432210854224304e-04f, + 8.658219399455064280e-04f, + 8.843005148257124162e-04f, + 9.018616481435636715e-04f, + 9.184889921098693746e-04f, + 9.341671638215605540e-04f, + 9.488817593593959444e-04f, + 9.626193668776509334e-04f, + 9.753675786743276274e-04f, + 9.871150022309649764e-04f, + 9.978512702125698873e-04f, + 1.007567049418917103e-03f, + 1.016254048679934505e-03f, + 1.023905025688631211e-03f, + 1.030513792766163958e-03f, + 1.036075221554958858e-03f, + 1.040585246636590612e-03f, + 1.044040868072351400e-03f, + 1.046440152865581131e-03f, + 1.047782235345830204e-03f, + 1.048067316476006608e-03f, + 1.047296662084868128e-03f, + 1.045472600028134798e-03f, + 1.042598516282698499e-03f, + 1.038678849979428548e-03f, + 1.033719087381135097e-03f, + 1.027725754813292765e-03f, + 1.020706410556256006e-03f, + 1.012669635708591783e-03f, + 1.003625024032280683e-03f, + 9.935831707915917296e-04f, + 9.825556605982765750e-04f, + 9.705550542768091827e-04f, + 9.575948747645024592e-04f, + 9.436895920619294822e-04f, + 9.288546072504160834e-04f, + 9.131062355939434513e-04f, + 8.964616887440624146e-04f, + 8.789390560668727381e-04f, + 8.605572851122642768e-04f, + 8.413361612465680012e-04f, + 8.212962864701133696e-04f, + 8.004590574423870028e-04f, + 7.788466427383010891e-04f, + 7.564819593593443900e-04f, + 7.333886485245473975e-04f, + 7.095910507669888961e-04f, + 6.851141803613563976e-04f, + 6.599836991102931479e-04f, + 6.342258895159663982e-04f, + 6.078676273653686388e-04f, + 5.809363537579391706e-04f, + 5.534600466042048465e-04f, + 5.254671916251264134e-04f, + 4.969867528824211626e-04f, + 4.680481428698100464e-04f, + 4.386811921962611408e-04f, + 4.089161188926386807e-04f, + 3.787834973728029320e-04f, + 3.483142270813974271e-04f, + 3.175395008601156806e-04f, + 2.864907730651890965e-04f, + 2.551997274681527816e-04f, + 2.236982449728073510e-04f, + 1.920183711814943037e-04f, + 1.601922838431261954e-04f, + 1.282522602162407851e-04f, + 9.623064438038904595e-05f, + 6.415981452841493812e-05f, + 3.207215027289962711e-05f, + 0.000000000000000000e+00f, + -3.202435169696419165e-05f, + -6.396871647107672993e-05f, + -9.580103453013783627e-05f, + -1.274894067670554485e-04f, + -1.590021266806003833e-04f, + -1.903077120544014096e-04f, + -2.213749363623242509e-04f, + -2.521728598694509757e-04f, + -2.826708603974881218e-04f, + -3.128386637238008165e-04f, + -3.426463735844534645e-04f, + -3.720645012513128301e-04f, + -4.010639946537739552e-04f, + -4.296162670168992745e-04f, + -4.576932249873889727e-04f, + -4.852672962200506594e-04f, + -5.123114563973639067e-04f, + -5.387992556561681809e-04f, + -5.647048443954880668e-04f, + -5.900029984401524482e-04f, + -6.146691435362195647e-04f, + -6.386793791542513593e-04f, + -6.620105015772862009e-04f, + -6.846400262516423845e-04f, + -7.065462093789202968e-04f, + -7.277080687284316705e-04f, + -7.481054036504530087e-04f, + -7.677188142710961042e-04f, + -7.865297198508461448e-04f, + -8.045203762893993540e-04f, + -8.216738927602709611e-04f, + -8.379742474599812278e-04f, + -8.534063024570928127e-04f, + -8.679558176273523317e-04f, + -8.816094636625075804e-04f, + -8.943548341408386320e-04f, + -9.061804566487988806e-04f, + -9.170758029437478922e-04f, + -9.270312981492120604e-04f, + -9.360383289747114437e-04f, + -9.440892509532578013e-04f, + -9.511773946908641834e-04f, + -9.572970711231403289e-04f, + -9.624435757751192066e-04f, + -9.666131920216366113e-04f, + -9.698031933463969285e-04f, + -9.720118445989208052e-04f, + -9.732384022497203710e-04f, + -9.734831136448424821e-04f, + -9.727472152621121065e-04f, + -9.710329299722829204e-04f, + -9.683434633094111085e-04f, + -9.646829987556522013e-04f, + -9.600566920467877531e-04f, + -9.544706645056394391e-04f, + -9.479319954115860043e-04f, + -9.404487134153821952e-04f, + -9.320297870093062660e-04f, + -9.226851140636999115e-04f, + -9.124255104419481694e-04f, + -9.012626977066420320e-04f, + -8.892092899308199835e-04f, + -8.762787796288336881e-04f, + -8.624855228225505183e-04f, + -8.478447232590492723e-04f, + -8.323724157971091513e-04f, + -8.160854489806475048e-04f, + -7.990014668176755822e-04f, + -7.811388897844821115e-04f, + -7.625168950755145496e-04f, + -7.431553961197853112e-04f, + -7.230750213856750215e-04f, + -7.022970924967909898e-04f, + -6.808436016816696431e-04f, + -6.587371885813887371e-04f, + -6.360011164391399848e-04f, + -6.126592476972289288e-04f, + -5.887360190265250072e-04f, + -5.642564158146420091e-04f, + -5.392459461393457349e-04f, + -5.137306142544784474e-04f, + -4.877368936155090711e-04f, + -4.612916994728182745e-04f, + -4.344223610612315406e-04f, + -4.071565934140700962e-04f, + -3.795224688310699706e-04f, + -3.515483880292340994e-04f, + -3.232630510065746267e-04f, + -2.946954276481456654e-04f, + -2.658747281046207941e-04f, + -2.368303729738942764e-04f, + -2.075919633156370829e-04f, + -1.781892505295539549e-04f, + -1.486521061281701210e-04f, + -1.190104914343625921e-04f, + -8.929442723454692366e-05f, + -5.953396341846094902e-05f, + -2.975914863569874771e-05f, + -1.469383061752921166e-17f, + 2.971352712842046073e-05f, + 5.935156925200977569e-05f, + 8.888438470625297655e-05f, + 1.182823834615285115e-04f, + 1.475161567260801273e-04f, + 1.765565063211114430e-04f, + 2.053744737984555227e-04f, + 2.339413692715925134e-04f, + 2.622287999318306112e-04f, + 2.902086982211098056e-04f, + 3.178533496333097114e-04f, + 3.451354201170366942e-04f, + 3.720279830524620595e-04f, + 3.985045457759202716e-04f, + 4.245390756258103919e-04f, + 4.501060254847104552e-04f, + 4.751803587924769172e-04f, + 4.997375740056823846e-04f, + 5.237537284800026236e-04f, + 5.472054617520811680e-04f, + 5.700700181981503386e-04f, + 5.923252690478518056e-04f, + 6.139497337318547063e-04f, + 6.349226005425641405e-04f, + 6.552237465884745531e-04f, + 6.748337570230266303e-04f, + 6.937339435292449487e-04f, + 7.119063620434466517e-04f, + 7.293338297005069531e-04f, + 7.459999409853247188e-04f, + 7.618890830752056463e-04f, + 7.769864503587980151e-04f, + 7.912780581184908910e-04f, + 8.047507553635035353e-04f, + 8.173922368022044829e-04f, + 8.291910539426864280e-04f, + 8.401366253119868770e-04f, + 8.502192457848813112e-04f, + 8.594300950141066115e-04f, + 8.677612449551008961e-04f, + 8.752056664789573028e-04f, + 8.817572350682475763e-04f, + 8.874107355915474612e-04f, + 8.921618661531745048e-04f, + 8.960072410156486164e-04f, + 8.989443925934634261e-04f, + 9.009717725175072972e-04f, + 9.020887517705425190e-04f, + 9.022956198950072941e-04f, + 9.015935832754222229e-04f, + 8.999847624985231375e-04f, + 8.974721887952514209e-04f, + 8.940597995695863213e-04f, + 8.897524330201562462e-04f, + 8.845558218614805405e-04f, + 8.784765861525543331e-04f, + 8.715222252413793759e-04f, + 8.637011088350353069e-04f, + 8.550224672055297846e-04f, + 8.454963805427627172e-04f, + 8.351337674665857812e-04f, + 8.239463727109863026e-04f, + 8.119467539939648334e-04f, + 7.991482680876762579e-04f, + 7.855650561042518912e-04f, + 7.712120280131833138e-04f, + 7.561048464071653402e-04f, + 7.402599095340949053e-04f, + 7.236943336132475825e-04f, + 7.064259344547092496e-04f, + 6.884732084018442772e-04f, + 6.698553126167958562e-04f, + 6.505920447301977031e-04f, + 6.307038218764186291e-04f, + 6.102116591367832835e-04f, + 5.891371474128742191e-04f, + 5.675024307539662440e-04f, + 5.453301831613886286e-04f, + 5.226435848948802945e-04f, + 4.994662983050689653e-04f, + 4.758224432173879066e-04f, + 4.517365718931811943e-04f, + 4.272336435935402852e-04f, + 4.023389987724907877e-04f, + 3.770783329259057943e-04f, + 3.514776701234272852e-04f, + 3.255633362501970246e-04f, + 2.993619319860350001e-04f, + 2.729003055499868075e-04f, + 2.462055252376792419e-04f, + 2.193048517797492180e-04f, + 1.922257105497324930e-04f, + 1.649956636492767566e-04f, + 1.376423818992599316e-04f, + 1.101936167654500256e-04f, + 8.267717224668583544e-05f, + 5.512087675440251894e-05f, + 2.755255501160192006e-05f, + 0.000000000000000000e+00f, + -2.750905501689023422e-05f, + -5.494696436636345655e-05f, + -8.228619770668268139e-05f, + -1.094993676073878112e-04f, + -1.365592569419782647e-04f, + -1.634388460653853027e-04f, + -1.901113397495802181e-04f, + -2.165501938502928923e-04f, + -2.427291416781312899e-04f, + -2.686222200484022333e-04f, + -2.942037949834695591e-04f, + -3.194485870425304262e-04f, + -3.443316962534629451e-04f, + -3.688286266226424733e-04f, + -3.929153101984506676e-04f, + -4.165681306646761548e-04f, + -4.397639464411628790e-04f, + -4.624801132689337598e-04f, + -4.846945062576402791e-04f, + -5.063855413743057745e-04f, + -5.275321963523644251e-04f, + -5.481140310006175909e-04f, + -5.681112068929672181e-04f, + -5.875045064196726674e-04f, + -6.062753511821435647e-04f, + -6.244058197136283239e-04f, + -6.418786645088341578e-04f, + -6.586773283467862658e-04f, + -6.747859598912580702e-04f, + -6.901894285541135439e-04f, + -7.048733386080151741e-04f, + -7.188240425351924510e-04f, + -7.320286536001779053e-04f, + -7.444750576348447895e-04f, + -7.561519240253451084e-04f, + -7.670487158910010940e-04f, + -7.771556994460668971e-04f, + -7.864639525364079805e-04f, + -7.949653723436894259e-04f, + -8.026526822505372595e-04f, + -8.095194378612496173e-04f, + -8.155600321732297967e-04f, + -8.207696998952141061e-04f, + -8.251445209094316778e-04f, + -8.286814228754654961e-04f, + -8.313781829745840735e-04f, + -8.332334287941438105e-04f, + -8.342466383525489566e-04f, + -8.344181392661235552e-04f, + -8.337491070600727781e-04f, + -8.322415626266423810e-04f, + -8.298983688343719274e-04f, + -8.267232262932451212e-04f, + -8.227206682813439833e-04f, + -8.178960548394521293e-04f, + -8.122555660409656268e-04f, + -8.058061944451279162e-04f, + -7.985557367425892995e-04f, + -7.905127846029615362e-04f, + -7.816867147349541335e-04f, + -7.720876781703026525e-04f, + -7.617265887835813565e-04f, + -7.506151110607858345e-04f, + -7.387656471301075898e-04f, + -7.261913230692261566e-04f, + -7.129059745042091046e-04f, + -6.989241315155087344e-04f, + -6.842610028674840552e-04f, + -6.689324595785751861e-04f, + -6.529550178495424672e-04f, + -6.363458213682250285e-04f, + -6.191226230095402778e-04f, + -6.013037659503773147e-04f, + -5.829081642191303019e-04f, + -5.639552827005720349e-04f, + -5.444651166170623056e-04f, + -5.244581705078699748e-04f, + -5.039554367282136470e-04f, + -4.829783734907900630e-04f, + -4.615488824727865158e-04f, + -4.396892860113637874e-04f, + -4.174223039115742672e-04f, + -3.947710298905243330e-04f, + -3.717589076824774933e-04f, + -3.484097068291740662e-04f, + -3.247474981805008798e-04f, + -3.007966291308984577e-04f, + -2.765816986165605708e-04f, + -2.521275318992345573e-04f, + -2.274591551626225019e-04f, + -2.026017699469456171e-04f, + -1.775807274479320418e-04f, + -1.524215027065971577e-04f, + -1.271496687156270196e-04f, + -1.017908704690000349e-04f, + -7.637079898086366356e-05f, + -5.091516530030798363e-05f, + -2.544967454785041741e-05f, + 0.000000000000000000e+00f, + 2.540824275175630965e-05f, + 5.074952154213560791e-05f, + 7.599841324713188062e-05f, + 1.011296292473662763e-04f, + 1.261180407145145923e-04f, + 1.509387036954135824e-04f, + 1.755668839686425260e-04f, + 1.999780816492812915e-04f, + 2.241480555170535154e-04f, + 2.480528470440098191e-04f, + 2.716688040976286797e-04f, + 2.949726042963528197e-04f, + 3.179412779943405166e-04f, + 3.405522308726428231e-04f, + 3.627832661150276234e-04f, + 3.846126061465318354e-04f, + 4.060189139133383055e-04f, + 4.269813136835948837e-04f, + 4.474794113487838955e-04f, + 4.674933142057642490e-04f, + 4.870036502007597822e-04f, + 5.059915866164069404e-04f, + 5.244388481841380598e-04f, + 5.423277346042669565e-04f, + 5.596411374573758216e-04f, + 5.763625564908231172e-04f, + 5.924761152646927393e-04f, + 6.079665761428002836e-04f, + 6.228193546145188893e-04f, + 6.370205329341033923e-04f, + 6.505568730647005556e-04f, + 6.634158289153857567e-04f, + 6.755855578598123036e-04f, + 6.870549315261518814e-04f, + 6.978135458484613016e-04f, + 7.078517303707442540e-04f, + 7.171605567954273622e-04f, + 7.257318467687813622e-04f, + 7.335581788968564615e-04f, + 7.406328949860011826e-04f, + 7.469501055028914937e-04f, + 7.525046942499604482e-04f, + 7.572923222527377452e-04f, + 7.613094308564032336e-04f, + 7.645532440298472834e-04f, + 7.670217698761347402e-04f, + 7.687138013491711264e-04f, + 7.696289161771383436e-04f, + 7.697674759941319994e-04f, + 7.691306246821071795e-04f, + 7.677202859261749368e-04f, + 7.655391599869575776e-04f, + 7.625907196945825228e-04f, + 7.588792056696464167e-04f, + 7.544096207772237267e-04f, + 7.491877238207874951e-04f, + 7.432200224837051672e-04f, + 7.365137655266115572e-04f, + 7.290769342498153649e-04f, + 7.209182332305319723e-04f, + 7.120470803455674876e-04f, + 7.024735960906073294e-04f, + 6.922085922080986782e-04f, + 6.812635596364262705e-04f, + 6.696506557935362697e-04f, + 6.573826912090139371e-04f, + 6.444731155192746008e-04f, + 6.309360028408991924e-04f, + 6.167860365379857716e-04f, + 6.020384934000156665e-04f, + 5.867092272469688922e-04f, + 5.708146519793728339e-04f, + 5.543717240911742901e-04f, + 5.373979246641968867e-04f, + 5.199112408629773122e-04f, + 5.019301469495465393e-04f, + 4.834735848383831772e-04f, + 4.645609442115968056e-04f, + 4.452120422152791297e-04f, + 4.254471027583006421e-04f, + 4.052867354349356968e-04f, + 3.847519140935204570e-04f, + 3.638639550730222647e-04f, + 3.426444951302156034e-04f, + 3.211154690804265380e-04f, + 2.992990871745817845e-04f, + 2.772178122359930490e-04f, + 2.548943365805551777e-04f, + 2.323515587436648325e-04f, + 2.096125600378590220e-04f, + 1.867005809653108641e-04f, + 1.636389975088607706e-04f, + 1.404512973260482907e-04f, + 1.171610558701005774e-04f, + 9.379191246244331451e-05f, + 7.036754634058427660e-05f, + 4.691165270578145734e-05f, + 2.344791879487271815e-05f, + 1.447139493247874122e-17f, + -2.340850393945113271e-05f, + -4.675407264888852574e-05f, + -7.001328871061514335e-05f, + -9.316286111268942802e-05f, + -1.161796485306134486e-04f, + -1.390406824191185795e-04f, + -1.617231898906969537e-04f, + -1.842046163583829115e-04f, + -2.064626479199869254e-04f, + -2.284752334619991466e-04f, + -2.502206064611250252e-04f, + -2.716773064617690556e-04f, + -2.928242002086798895e-04f, + -3.136405024138114671e-04f, + -3.341057961368736713e-04f, + -3.542000527599929792e-04f, + -3.739036515368039746e-04f, + -3.931973986967992316e-04f, + -4.120625460867281776e-04f, + -4.304808093307158469e-04f, + -4.484343854917819923e-04f, + -4.659059702174845512e-04f, + -4.828787743535818602e-04f, + -4.993365400096493739e-04f, + -5.152635560612082175e-04f, + -5.306446730741198057e-04f, + -5.454653176364612647e-04f, + -5.597115060851909612e-04f, + -5.733698576140564907e-04f, + -5.864276067510603525e-04f, + -5.988726151936528234e-04f, + -6.106933829909588687e-04f, + -6.218790590626611069e-04f, + -6.324194510452570833e-04f, + -6.423050344567614702e-04f, + -6.515269611716821042e-04f, + -6.600770671990646883e-04f, + -6.679478797567967160e-04f, + -6.751326236362062069e-04f, + -6.816252268518211213e-04f, + -6.874203255717539112e-04f, + -6.925132683248836490e-04f, + -6.969001194819386376e-04f, + -7.005776620080852567e-04f, + -7.035433994855702167e-04f, + -7.057955574054943209e-04f, + -7.073330837287954750e-04f, + -7.081556487170125340e-04f, + -7.082636440342657963e-04f, + -7.076581811226278617e-04f, + -7.063410888537339193e-04f, + -7.043149104602236445e-04f, + -7.015828997513892445e-04f, + -6.981490166179902005e-04f, + -6.940179218320851728e-04f, + -6.891949711482260339e-04f, + -6.836862087132502142e-04f, + -6.774983597924347884e-04f, + -6.706388228206039545e-04f, + -6.631156607872861451e-04f, + -6.549375919657807231e-04f, + -6.461139799966924375e-04f, + -6.366548233369270175e-04f, + -6.265707440859499865e-04f, + -6.158729762017194510e-04f, + -6.045733531191070480e-04f, + -5.926842947843961179e-04f, + -5.802187941200323941e-04f, + -5.671904029341022849e-04f, + -5.536132172898791236e-04f, + -5.395018623509823539e-04f, + -5.248714767185811651e-04f, + -5.097376962770673765e-04f, + -4.941166375654838707e-04f, + -4.780248806924582670e-04f, + -4.614794518122551344e-04f, + -4.444978051810356389e-04f, + -4.270978048115207926e-04f, + -4.092977057456325968e-04f, + -3.911161349647420196e-04f, + -3.725720719571632062e-04f, + -3.536848289632427730e-04f, + -3.344740309187047944e-04f, + -3.149595951167335258e-04f, + -2.951617106099559715e-04f, + -2.751008173737486736e-04f, + -2.547975852520000407e-04f, + -2.342728927071314657e-04f, + -2.135478053963316245e-04f, + -1.926435545956132946e-04f, + -1.715815154940239279e-04f, + -1.503831853799458774e-04f, + -1.290701617419976258e-04f, + -1.076641203064520068e-04f, + -8.618679303362720165e-05f, + -6.465994609572296963e-05f, + -4.310535785803166131e-05f, + -2.154479688593094298e-05f, + 0.000000000000000000e+00f, + 2.150734959899484319e-05f, + 4.295564411312584395e-05f, + 6.432337281627700971e-05f, + 8.558914358778801847e-05f, + 1.067317042889163222e-04f, + 1.277299639610350547e-04f, + 1.485630138241603702e-04f, + 1.692101480553038985e-04f, + 1.896508843258684759e-04f, + 2.098649840776009373e-04f, + 2.298324725174021228e-04f, + 2.495336583111203762e-04f, + 2.689491529567958729e-04f, + 2.880598898186698250e-04f, + 3.068471428031533201e-04f, + 3.252925446583616268e-04f, + 3.433781048797137779e-04f, + 3.610862272039176181e-04f, + 3.783997266745809350e-04f, + 3.953018462627122791e-04f, + 4.117762730263829513e-04f, + 4.278071537938969346e-04f, + 4.433791103553099983e-04f, + 4.584772541480976356e-04f, + 4.730872004228363326e-04f, + 4.871950818755382503e-04f, + 5.007875617336743747e-04f, + 5.138518462839280912e-04f, + 5.263756968296791783e-04f, + 5.383474410673522387e-04f, + 5.497559838709404180e-04f, + 5.605908174750933934e-04f, + 5.708420310473718206e-04f, + 5.805003196410431958e-04f, + 5.895569925205944436e-04f, + 5.980039808525682747e-04f, + 6.058338447549957298e-04f, + 6.130397796995799755e-04f, + 6.196156222612016684e-04f, + 6.255558552100400158e-04f, + 6.308556119424503159e-04f, + 6.355106802471486953e-04f, + 6.395175054041730848e-04f, + 6.428731926145374613e-04f, + 6.455755087594301040e-04f, + 6.476228834882815982e-04f, + 6.490144096357687228e-04f, + 6.497498429685649897e-04f, + 6.498296012632502226e-04f, + 6.492547627174425229e-04f, + 6.480270636970132886e-04f, + 6.461488958227519508e-04f, + 6.436233024006336820e-04f, + 6.404539742004272803e-04f, + 6.366452445880759490e-04f, + 6.322020840178591873e-04f, + 6.271300938911197539e-04f, + 6.214354997887679231e-04f, + 6.151251440855713855e-04f, + 6.082064779547860164e-04f, + 6.006875527722377360e-04f, + 5.925770109296073186e-04f, + 5.838840760673158665e-04f, + 5.746185427377923640e-04f, + 5.647907655106131422e-04f, + 5.544116475315949552e-04f, + 5.434926285482021132e-04f, + 5.320456724144572097e-04f, + 5.200832540887690824e-04f, + 5.076183461388823585e-04f, + 4.946644047682729551e-04f, + 4.812353553790131599e-04f, + 4.673455776866451889e-04f, + 4.530098904026903664e-04f, + 4.382435355011193574e-04f, + 4.230621620855109567e-04f, + 4.074818098737383954e-04f, + 3.915188923177147684e-04f, + 3.751901793757405701e-04f, + 3.585127799555410831e-04f, + 3.415041240464490179e-04f, + 3.241819445590930424e-04f, + 3.065642588915733278e-04f, + 2.886693502413833915e-04f, + 2.705157486821331970e-04f, + 2.521222120247453859e-04f, + 2.335077064829918579e-04f, + 2.146913871629504706e-04f, + 1.956925783966609658e-04f, + 1.765307539399361904e-04f, + 1.572255170548387095e-04f, + 1.377965804968402466e-04f, + 1.182637464271945108e-04f, + 9.864688627111849629e-05f, + 7.896592054191218808e-05f, + 5.924079865161975436e-05f, + 3.949147872881094546e-05f, + 1.973790746354780164e-05f, + 0.000000000000000000e+00f, + -1.970238010284559686e-05f, + -3.934944082275756825e-05f, + -5.892148151755434546e-05f, + -7.839891264075306743e-05f, + -9.776227530943462282e-05f, + -1.169922607052078226e-04f, + -1.360697292888009540e-04f, + -1.549757298090502554e-04f, + -1.736915180877542444e-04f, + -1.921985755616629511e-04f, + -2.104786275631484471e-04f, + -2.285136613218662050e-04f, + -2.462859436695555878e-04f, + -2.637780384304916933e-04f, + -2.809728234808804288e-04f, + -2.978535074603023448e-04f, + -3.144036461191332854e-04f, + -3.306071582858338361e-04f, + -3.464483414389500442e-04f, + -3.619118868686585066e-04f, + -3.769828944131547489e-04f, + -3.916468867560180043e-04f, + -4.058898232707585751e-04f, + -4.196981133992728607e-04f, + -4.330586295517413042e-04f, + -4.459587195157615211e-04f, + -4.583862183627433859e-04f, + -4.703294598410216135e-04f, + -4.817772872445234334e-04f, + -4.927190637473565383e-04f, + -5.031446821946852560e-04f, + -5.130445743409007284e-04f, + -5.224097195269496782e-04f, + -5.312316527889542495e-04f, + -5.395024723908887479e-04f, + -5.472148467749195742e-04f, + -5.543620209233284749e-04f, + -5.609378221266176105e-04f, + -5.669366651531786106e-04f, + -5.723535568162687118e-04f, + -5.771840999348496837e-04f, + -5.814244966853034362e-04f, + -5.850715513418501545e-04f, + -5.881226724039281687e-04f, + -5.905758741095224786e-04f, + -5.924297773340420807e-04f, + -5.936836098749646720e-04f, + -5.943372061230182968e-04f, + -5.943910061214307226e-04f, + -5.938460540152537288e-04f, + -5.927039958934639209e-04f, + -5.909670770271131714e-04f, + -5.886381385074528462e-04f, + -5.857206132884568801e-04f, + -5.822185216389217429e-04f, + -5.781364660097343096e-04f, + -5.734796253225910197e-04f, + -5.682537486870293739e-04f, + -5.624651485531170217e-04f, + -5.561206933077393524e-04f, + -5.492277993230843978e-04f, + -5.417944224662266713e-04f, + -5.338290490794490428e-04f, + -5.253406864414295312e-04f, + -5.163388527197619636e-04f, + -5.068335664260176796e-04f, + -4.968353353848055896e-04f, + -4.863551452290165310e-04f, + -4.754044474335747460e-04f, + -4.639951469007321709e-04f, + -4.521395891103186892e-04f, + -4.398505468486206245e-04f, + -4.271412065301010948e-04f, + -4.140251541266666644e-04f, + -4.005163607192301599e-04f, + -3.866291676868795061e-04f, + -3.723782715496072680e-04f, + -3.577787084799967311e-04f, + -3.428458385006848889e-04f, + -3.275953293837695238e-04f, + -3.120431402691025606e-04f, + -2.962055050186841124e-04f, + -2.800989153242122590e-04f, + -2.637401035854408898e-04f, + -2.471460255771968360e-04f, + -2.303338429226980228e-04f, + -2.133209053914711568e-04f, + -1.961247330399053007e-04f, + -1.787629982130247515e-04f, + -1.612535074256399813e-04f, + -1.436141831415453836e-04f, + -1.258630454695097874e-04f, + -1.080181937944321024e-04f, + -9.009778836248835666e-05f, + -7.212003183910606612e-05f, + -5.410315085817400264e-05f, + -3.606537758129155149e-05f, + -1.802493128582126862e-05f, + -1.334841303324302416e-17f, + 1.799127779618168215e-05f, + 3.593083138609340919e-05f, + 5.380067592915723640e-05f, + 7.158293045321104055e-05f, + 8.925983570849392351e-05f, + 1.068137718653035880e-04f, + 1.242272760380188604e-04f, + 1.414830596179534239e-04f, + 1.585640253977377951e-04f, + 1.754532844705931341e-04f, + 1.921341728876877549e-04f, + 2.085902680570638303e-04f, + 2.248054048683053446e-04f, + 2.407636915270301768e-04f, + 2.564495250836037240e-04f, + 2.718476066412367303e-04f, + 2.869429562284523142e-04f, + 3.017209273216939929e-04f, + 3.161672210038205064e-04f, + 3.302678997451251666e-04f, + 3.440094007935225488e-04f, + 3.573785491609914131e-04f, + 3.703625701941320385e-04f, + 3.829491017167877117e-04f, + 3.951262057331397641e-04f, + 4.068823796806154101e-04f, + 4.182065672215850910e-04f, + 4.290881685642916978e-04f, + 4.395170503031860959e-04f, + 4.494835547696116843e-04f, + 4.589785088844519070e-04f, + 4.679932325046681232e-04f, + 4.765195462561217800e-04f, + 4.845497788459313506e-04f, + 4.920767738478327470e-04f, + 4.990938959546221661e-04f, + 5.055950366925160639e-04f, + 5.115746195925331957e-04f, + 5.170276048147706216e-04f, + 5.219494932218531839e-04f, + 5.263363298985630810e-04f, + 5.301847071150910407e-04f, + 5.334917667319233727e-04f, + 5.362552020450717756e-04f, + 5.384732590707796192e-04f, + 5.401447372694501321e-04f, + 5.412689897091851800e-04f, + 5.418459226697609071e-04f, + 5.418759946885404492e-04f, + 5.413602150503207117e-04f, + 5.403001417237128035e-04f, + 5.386978787471504403e-04f, + 5.365560730682539118e-04f, + 5.338779108407521986e-04f, + 5.306671131837313420e-04f, + 5.269279314085348852e-04f, + 5.226651417191434303e-04f, + 5.178840393923420668e-04f, + 5.125904324446496933e-04f, + 5.067906347932736285e-04f, + 5.004914589190106924e-04f, + 4.937002080395005770e-04f, + 4.864246678015905052e-04f, + 4.786730975021753222e-04f, + 4.704542208472601629e-04f, + 4.617772162595178012e-04f, + 4.526517067449197353e-04f, + 4.430877493295452938e-04f, + 4.330958240781504313e-04f, + 4.226868227062654973e-04f, + 4.118720367981569454e-04f, + 4.006631456434114435e-04f, + 3.890722037049972786e-04f, + 3.771116277322665187e-04f, + 3.647941835326885492e-04f, + 3.521329724160614195e-04f, + 3.391414173259668587e-04f, + 3.258332486726308631e-04f, + 3.122224898823369732e-04f, + 2.983234426785867904e-04f, + 2.841506721102148633e-04f, + 2.697189913421606591e-04f, + 2.550434462248571854e-04f, + 2.401392996580377489e-04f, + 2.250220157652570890e-04f, + 2.097072438956290921e-04f, + 1.942108024690222747e-04f, + 1.785486626815674697e-04f, + 1.627369320880489372e-04f, + 1.467918380782401184e-04f, + 1.307297112638300613e-04f, + 1.145669687930290083e-04f, + 9.832009760999397456e-05f, + 8.200563767584910741e-05f, + 6.564016516846416676e-05f, + 4.924027567815219766e-05f, + 3.282256741602081771e-05f, + 1.640362445206236378e-05f, + 0.000000000000000000e+00f, + -1.637180023455527615e-05f, + -3.269533462575305538e-05f, + -4.895424210242561722e-05f, + -6.513225850968472699e-05f, + -8.121323284108457146e-05f, + -9.718114332507469882e-05f, + -1.130201133496294995e-04f, + -1.287144272095247152e-04f, + -1.442485456605490041e-04f, + -1.596071212651732553e-04f, + -1.747750135148174182e-04f, + -1.897373037137282015e-04f, + -2.044793096097578128e-04f, + -2.189865997580020041e-04f, + -2.332450076030689249e-04f, + -2.472406452664517324e-04f, + -2.609599170254186065e-04f, + -2.743895324706472098e-04f, + -2.875165193297870496e-04f, + -3.003282359445427004e-04f, + -3.128123833895385809e-04f, + -3.249570172213065876e-04f, + -3.367505588461240803e-04f, + -3.481818064961628547e-04f, + -3.592399458034899098e-04f, + -3.699145599619731075e-04f, + -3.801956394677196631e-04f, + -3.900735914289291096e-04f, + -3.995392484366653077e-04f, + -4.085838769884034077e-04f, + -4.171991854566158182e-04f, + -4.253773315953880327e-04f, + -4.331109295782838197e-04f, + -4.403930565612024142e-04f, + -4.472172587646578920e-04f, + -4.535775570701503011e-04f, + -4.594684521259947778e-04f, + -4.648849289583206301e-04f, + -4.698224610836477188e-04f, + -4.742770141197898636e-04f, + -4.782450488924013302e-04f, + -4.817235240350806647e-04f, + -4.847098980813407910e-04f, + -4.872021310473242527e-04f, + -4.891986855046963432e-04f, + -4.906985271436078684e-04f, + -4.917011248261453924e-04f, + -4.922064501312485964e-04f, + -4.922149763925275263e-04f, + -4.917276772309548717e-04f, + -4.907460245849183233e-04f, + -4.892719862405896280e-04f, + -4.873080228661261920e-04f, + -4.848570845536456569e-04f, + -4.819226068734645927e-04f, + -4.785085064455284654e-04f, + -4.746191760334893435e-04f, + -4.702594791673116756e-04f, + -4.654347443007680212e-04f, + -4.601507585106936983e-04f, + -4.544137607452196142e-04f, + -4.482304346287416166e-04f, + -4.416079008317367900e-04f, + -4.345537090140839465e-04f, + -4.270758293507777911e-04f, + -4.191826436494728442e-04f, + -4.108829360697150140e-04f, + -4.021858834539161960e-04f, + -3.931010452806725248e-04f, + -3.836383532514024155e-04f, + -3.738081005214428367e-04f, + -3.636209305872444616e-04f, + -3.530878258416693307e-04f, + -3.422200958094793414e-04f, + -3.310293650756770912e-04f, + -3.195275609193634256e-04f, + -3.077269006664550737e-04f, + -2.956398787743567697e-04f, + -2.832792536622980853e-04f, + -2.706580343011211979e-04f, + -2.577894665766888188e-04f, + -2.446870194409517208e-04f, + -2.313643708652139079e-04f, + -2.178353936102799936e-04f, + -2.041141408280510209e-04f, + -1.902148315096290467e-04f, + -1.761518357948250199e-04f, + -1.619396601583952301e-04f, + -1.475929324880076194e-04f, + -1.331263870693465308e-04f, + -1.185548494938537772e-04f, + -1.038932215042936427e-04f, + -8.915646579370446799e-05f, + -7.435959077332714683e-05f, + -5.951763532474445284e-05f, + -4.464565355180115499e-05f, + -2.975869954784884257e-05f, + -1.487181219344128483e-05f, + 0.000000000000000000e+00f, + 1.484177398541613872e-05f, + 2.963860719904158576e-05f, + 4.437567248797690006e-05f, + 5.903823293163951847e-05f, + 7.361165654203178363e-05f, + 8.808143082849284827e-05f, + 1.024331772123446792e-04f, + 1.166526652770380289e-04f, + 1.307258268399512900e-04f, + 1.446387698318426075e-04f, + 1.583777919701953075e-04f, + 1.719293942132778794e-04f, + 1.852802939815504897e-04f, + 1.984174381336592573e-04f, + 2.113280156841942253e-04f, + 2.239994702510968052e-04f, + 2.364195122205586396e-04f, + 2.485761306175752138e-04f, + 2.604576046709465229e-04f, + 2.720525150615433867e-04f, + 2.833497548429932469e-04f, + 2.943385400246083098e-04f, + 3.050084198064263339e-04f, + 3.153492864566233744e-04f, + 3.253513848222112969e-04f, + 3.350053214640939868e-04f, + 3.443020734077864120e-04f, + 3.532329965021145852e-04f, + 3.617898333778522433e-04f, + 3.699647209993159932e-04f, + 3.777501978020017677e-04f, + 3.851392104098344126e-04f, + 3.921251199262121398e-04f, + 3.987017077932429100e-04f, + 4.048631812141973915e-04f, + 4.106041781344828734e-04f, + 4.159197717771173663e-04f, + 4.208054747289555891e-04f, + 4.252572425744124453e-04f, + 4.292714770740190195e-04f, + 4.328450288854669421e-04f, + 4.359751998253025848e-04f, + 4.386597446699808871e-04f, + 4.408968724953503567e-04f, + 4.426852475541531284e-04f, + 4.440239896916363025e-04f, + 4.449126742997511793e-04f, + 4.453513318109698395e-04f, + 4.453404467331309718e-04f, + 4.448809562272690614e-04f, + 4.439742482307769997e-04f, + 4.426221591287388775e-04f, + 4.408269709767168466e-04f, + 4.385914082787080990e-04f, + 4.359186343244749818e-04f, + 4.328122470908071003e-04f, + 4.292762747118040057e-04f, + 4.253151705236267433e-04f, + 4.209338076896006566e-04f, + 4.161374734119831350e-04f, + 4.109318627370653408e-04f, + 4.053230719607911351e-04f, + 3.993175916422970020e-04f, + 3.929222992332770761e-04f, + 3.861444513314888326e-04f, + 3.789916755669021876e-04f, + 3.714719621295073122e-04f, + 3.635936549481525153e-04f, + 3.553654425299459119e-04f, + 3.467963484702393361e-04f, + 3.378957216435445662e-04f, + 3.286732260858342197e-04f, + 3.191388305792130522e-04f, + 3.093027979500185209e-04f, + 2.991756740919330917e-04f, + 2.887682767254974537e-04f, + 2.780916839063471402e-04f, + 2.671572222938670333e-04f, + 2.559764551930417240e-04f, + 2.445611703817801011e-04f, + 2.329233677365916448e-04f, + 2.210752466696249048e-04f, + 2.090291933900031019e-04f, + 1.967977680028590282e-04f, + 1.843936914593410459e-04f, + 1.718298323712722203e-04f, + 1.591191937038941441e-04f, + 1.462748993604876967e-04f, + 1.333101806727993762e-04f, + 1.202383628109180238e-04f, + 1.070728511266315022e-04f, + 9.382711744432409014e-05f, + 8.051468631319089826e-05f, + 6.714912123485984206e-05f, + 5.374401088052293570e-05f, + 4.031295531131948081e-05f, + 2.686955221609669864e-05f, + 1.342738318029786585e-05f, + 0.000000000000000000e+00f, + -1.339908894537428966e-05f, + -2.675643224788563980e-05f, + -4.005864893978847017e-05f, + -5.329244186287420863e-05f, + -6.644461092502548262e-05f, + -7.950206623069222111e-05f, + -9.245184107248077213e-05f, + -1.052811047708897691e-04f, + -1.179771753494133872e-04f, + -1.305275320327536741e-04f, + -1.429198275556728382e-04f, + -1.551419002705676728e-04f, + -1.671817860417565296e-04f, + -1.790277299150954120e-04f, + -1.906681975514930251e-04f, + -2.020918864131418622e-04f, + -2.132877366918702598e-04f, + -2.242449419689906455e-04f, + -2.349529595963345725e-04f, + -2.454015207887385404e-04f, + -2.555806404182784557e-04f, + -2.654806265008874768e-04f, + -2.750920893665808145e-04f, + -2.844059505045345624e-04f, + -2.934134510748270851e-04f, + -3.021061600789069551e-04f, + -3.104759821811575835e-04f, + -3.185151651745712952e-04f, + -3.262163070835866359e-04f, + -3.335723628976332462e-04f, + -3.405766509294967594e-04f, + -3.472228587927296962e-04f, + -3.535050489929618660e-04f, + -3.594176641281607277e-04f, + -3.649555316935231171e-04f, + -3.701138684869255359e-04f, + -3.748882846112615666e-04f, + -3.792747870705806133e-04f, + -3.832697829571900684e-04f, + -3.868700822273337075e-04f, + -3.900729000635904330e-04f, + -3.928758588224299966e-04f, + -3.952769895658223660e-04f, + -3.972747331762911953e-04f, + -3.988679410551167681e-04f, + -4.000558754039121919e-04f, + -4.008382090901287695e-04f, + -4.012150250975650445e-04f, + -4.011868155632819922e-04f, + -4.007544804028019764e-04f, + -3.999193255258539845e-04f, + -3.986830606453539640e-04f, + -3.970477966826979296e-04f, + -3.950160427728647184e-04f, + -3.925907028732052292e-04f, + -3.897750719802241096e-04f, + -3.865728319589897214e-04f, + -3.829880469902513843e-04f, + -3.790251586406653394e-04f, + -3.746889805619719256e-04f, + -3.699846928252342087e-04f, + -3.649178358966703251e-04f, + -3.594943042620016315e-04f, + -3.537203397064425225e-04f, + -3.476025242579046902e-04f, + -3.411477728013451389e-04f, + -3.343633253723441497e-04f, + -3.272567391384403391e-04f, + -3.198358800770878963e-04f, + -3.121089143591786099e-04f, + -3.040842994476012479e-04f, + -2.957707749203746634e-04f, + -2.871773530283563362e-04f, + -2.783133089975229658e-04f, + -2.691881710862687534e-04f, + -2.598117104082893068e-04f, + -2.501939305319653465e-04f, + -2.403450568670490101e-04f, + -2.302755258500093155e-04f, + -2.199959739394581452e-04f, + -2.095172264330585757e-04f, + -1.988502861177488868e-04f, + -1.880063217650495839e-04f, + -1.769966564835590396e-04f, + -1.658327559405899988e-04f, + -1.545262164652106557e-04f, + -1.430887530451063164e-04f, + -1.315321872294559114e-04f, + -1.198684349503653277e-04f, + -1.081094942754574683e-04f, + -9.626743310399233169e-05f, + -8.435437681917366869e-05f, + -7.238249590935302358e-05f, + -6.036399357051934749e-05f, + -4.831109330284252872e-05f, + -3.623602651371357099e-05f, + -2.415102013999141309e-05f, + -1.206828430174254195e-05f, + 0.000000000000000000e+00f, + 1.204169312897504154e-05f, + 2.404470899092571738e-05f, + 3.599702712991723069e-05f, + 4.788670473170228393e-05f, + 5.970188852229866780e-05f, + 7.143082654988841410e-05f, + 8.306187983826528306e-05f, + 9.458353390051201588e-05f, + 1.059844101013897441e-04f, + 1.172532768573817302e-04f, + 1.283790606632529297e-04f, + 1.393508569345262404e-04f, + 1.501579406552106444e-04f, + 1.607897768203369465e-04f, + 1.712360306633601821e-04f, + 1.814865776584426626e-04f, + 1.915315132879176962e-04f, + 2.013611625657108102e-04f, + 2.109660893075433882e-04f, + 2.203371051389893943e-04f, + 2.294652782330296192e-04f, + 2.383419417686963803e-04f, + 2.469587021029656941e-04f, + 2.553074466481195588e-04f, + 2.633803514474035304e-04f, + 2.711698884419244454e-04f, + 2.786688324219942182e-04f, + 2.858702676567446673e-04f, + 2.927675941959327296e-04f, + 2.993545338382966954e-04f, + 3.056251357610912951e-04f, + 3.115737818059637109e-04f, + 3.171951914164931581e-04f, + 3.224844262232151398e-04f, + 3.274368942722000880e-04f, + 3.320483538937818360e-04f, + 3.363149172082760107e-04f, + 3.402330532659012994e-04f, + 3.437995908186134266e-04f, + 3.470117207218301322e-04f, + 3.498669979643943373e-04f, + 3.523633433256204432e-04f, + 3.544990446585373207e-04f, + 3.562727577988377661e-04f, + 3.576835070995022250e-04f, + 3.587306855913434921e-04f, + 3.594140547701693143e-04f, + 3.597337440115922912e-04f, + 3.596902496149280318e-04f, + 3.592844334779736470e-04f, + 3.585175214048202355e-04f, + 3.573911010492562368e-04f, + 3.559071194966300722e-04f, + 3.540678804874658795e-04f, + 3.518760412864115083e-04f, + 3.493346092005057690e-04f, + 3.464469377510762094e-04f, + 3.432167225039049318e-04f, + 3.396479965626749342e-04f, + 3.357451257309863640e-04f, + 3.315128033486363182e-04f, + 3.269560448080700604e-04f, + 3.220801817572939820e-04f, + 3.168908559958683816e-04f, + 3.113940130707873932e-04f, + 3.055958955794286277e-04f, + 2.995030361870785703e-04f, + 2.931222503666503615e-04f, + 2.864606288686135879e-04f, + 2.795255299294358681e-04f, + 2.723245712269062205e-04f, + 2.648656215911465348e-04f, + 2.571567924801972712e-04f, + 2.492064292294373924e-04f, + 2.410231020841035532e-04f, + 2.326155970245017573e-04f, + 2.239929063938051238e-04f, + 2.151642193382072939e-04f, + 2.061389120696203742e-04f, + 1.969265379611917521e-04f, + 1.875368174860041030e-04f, + 1.779796280096115294e-04f, + 1.682649934469443648e-04f, + 1.584030737944329339e-04f, + 1.484041545483235042e-04f, + 1.382786360200012393e-04f, + 1.280370225594695995e-04f, + 1.176899116981768777e-04f, + 1.072479832222307631e-04f, + 9.672198818729011848e-05f, + 8.612273788649634355e-05f, + 7.546109278254378857e-05f, + 6.474795141533576512e-05f, + 5.399423929640585659e-05f, + 4.321089780154245503e-05f, + 3.240887307268698056e-05f, + 2.159910494042194029e-05f, + 1.079251587830625557e-05f, + 0.000000000000000000e+00f, + -1.076758788963704548e-05f, + -2.149944317856241301e-05f, + -3.218482225573323713e-05f, + -4.281305323283309065e-05f, + -5.337354656864646082e-05f, + -6.385580558576757243e-05f, + -7.424943686907754835e-05f, + -8.454416053583386234e-05f, + -9.472982036711456591e-05f, + -1.047963937908457071e-04f, + -1.147340017065515562e-04f, + -1.245329181421548671e-04f, + -1.341835797335974307e-04f, + -1.436765950179864047e-04f, + -1.530027535312186607e-04f, + -1.621530347014577759e-04f, + -1.711186165298485740e-04f, + -1.798908840500873269e-04f, + -1.884614375589472831e-04f, + -1.968221006098050266e-04f, + -2.049649277617257863e-04f, + -2.128822120766777921e-04f, + -2.205664923580282378e-04f, + -2.280105601234851175e-04f, + -2.352074663059836263e-04f, + -2.421505276765508960e-04f, + -2.488333329829885750e-04f, + -2.552497487991398626e-04f, + -2.613939250791943547e-04f, + -2.672603004122885910e-04f, + -2.728436069726557201e-04f, + -2.781388751610882780e-04f, + -2.831414379336380212e-04f, + -2.878469348139965243e-04f, + -2.922513155861687336e-04f, + -2.963508436644055012e-04f, + -3.001420991378207152e-04f, + -3.036219814873026852e-04f, + -3.067877119727112443e-04f, + -3.096368356887807777e-04f, + -3.121672232883608046e-04f, + -3.143770723720249469e-04f, + -3.162649085434524054e-04f, + -3.178295861302663341e-04f, + -3.190702885703869526e-04f, + -3.199865284642772981e-04f, + -3.205781472938346467e-04f, + -3.208453148089736979e-04f, + -3.207885280832979214e-04f, + -3.204086102406083158e-04f, + -3.197067088542942777e-04f, + -3.186842940220061915e-04f, + -3.173431561183079385e-04f, + -3.156854032283730655e-04f, + -3.137134582660339763e-04f, + -3.114300557798812749e-04f, + -3.088382384513568856e-04f, + -3.059413532891418143e-04f, + -3.027430475243637962e-04f, + -2.992472642115744834e-04f, + -2.954582375405406932e-04f, + -2.913804878643640249e-04f, + -2.870188164496020400e-04f, + -2.823782999543770502e-04f, + -2.774642846407175700e-04f, + -2.722823803275761204e-04f, + -2.668384540913915862e-04f, + -2.611386237210131574e-04f, + -2.551892509343225957e-04f, + -2.489969343639438274e-04f, + -2.425685023197270455e-04f, + -2.359110053357878537e-04f, + -2.290317085103517163e-04f, + -2.219380836464229334e-04f, + -2.146378012019111564e-04f, + -2.071387220576676933e-04f, + -1.994488891124380440e-04f, + -1.915765187133722193e-04f, + -1.835299919314087671e-04f, + -1.753178456905652674e-04f, + -1.669487637607092330e-04f, + -1.584315676229787050e-04f, + -1.497752072176369788e-04f, + -1.409887515839194623e-04f, + -1.320813794016571026e-04f, + -1.230623694444957564e-04f, + -1.139410909545171644e-04f, + -1.047269939484425535e-04f, + -9.542959946509581922e-05f, + -8.605848976438549571e-05f, + -7.662329848777562182e-05f, + -6.713370079033298594e-05f, + -5.759940345433426073e-05f, + -4.803013499474702882e-05f, + -3.843563576630159076e-05f, + -2.882564808243503731e-05f, + -1.920990635599448016e-05f, + -9.598127271662273025e-06f, + 0.000000000000000000e+00f, + 9.574823537103811872e-06f, + 1.911673833977519833e-05f, + 2.861619593263633836e-05f, + 3.806371388693437398e-05f, + 4.744988525275912425e-05f, + 5.676538789203427777e-05f, + 6.600099370314859348e-05f, + 7.514757772787978142e-05f, + 8.419612713200058348e-05f, + 9.313775005050625494e-05f, + 1.019636842889295287e-04f, + 1.106653058722401322e-04f, + 1.192341374330203445e-04f, + 1.276618564308877656e-04f, + 1.359403031950059157e-04f, + 1.440614887822626452e-04f, + 1.520176026433699178e-04f, + 1.598010200896498841e-04f, + 1.674043095534119953e-04f, + 1.748202396351221399e-04f, + 1.820417859305353066e-04f, + 1.890621376316773902e-04f, + 1.958747038953250451e-04f, + 2.024731199731614757e-04f, + 2.088512530979652713e-04f, + 2.150032081205004760e-04f, + 2.209233328918379412e-04f, + 2.266062233865404583e-04f, + 2.320467285618302712e-04f, + 2.372399549487279324e-04f, + 2.421812709709947786e-04f, + 2.468663109882154221e-04f, + 2.512909790595921756e-04f, + 2.554514524253027516e-04f, + 2.593441847026279235e-04f, + 2.629659087941870811e-04f, + 2.663136395061924231e-04f, + 2.693846758746589278e-04f, + 2.721766031979693879e-04f, + 2.746872947744395253e-04f, + 2.769149133438811154e-04f, + 2.788579122323372257e-04f, + 2.805150361996677278e-04f, + 2.818853219897804355e-04f, + 2.829680985836939208e-04f, + 2.837629871559238016e-04f, + 2.842699007349416287e-04f, + 2.844890435688079782e-04f, + 2.844209101973068656e-04f, + 2.840662842322885578e-04f, + 2.834262368481505552e-04f, + 2.825021249847073845e-04f, + 2.812955892649861810e-04f, + 2.798085516307519159e-04f, + 2.780432126988811935e-04f, + 2.760020488419260187e-04f, + 2.736878089965273718e-04f, + 2.711035112035945611e-04f, + 2.682524388844043702e-04f, + 2.651381368570786159e-04f, + 2.617644070980710701e-04f, + 2.581353042536924927e-04f, + 2.542551309067299522e-04f, + 2.501284326036580432e-04f, + 2.457599926480392495e-04f, + 2.411548266659954384e-04f, + 2.363181769497842621e-04f, + 2.312555065858830860e-04f, + 2.259724933739240289e-04f, + 2.204750235432793924e-04f, + 2.147691852741365984e-04f, + 2.088612620301268357e-04f, + 2.027577257097531386e-04f, + 1.964652296239523634e-04f, + 1.899906013075300696e-04f, + 1.833408351718813763e-04f, + 1.765230850071902420e-04f, + 1.695446563417966825e-04f, + 1.624129986670188350e-04f, + 1.551356975356094168e-04f, + 1.477204665421056229e-04f, + 1.401751391936988090e-04f, + 1.325076606798998916e-04f, + 1.247260795497873826e-04f, + 1.168385393054425164e-04f, + 1.088532699203247078e-04f, + 1.007785792914005370e-04f, + 9.262284463377021455e-05f, + 8.439450382689701034e-05f, + 7.610204672104689636e-05f, + 6.775400641307872908e-05f, + 5.935895050042970316e-05f, + 5.092547232225660091e-05f, + 4.246218219656006581e-05f, + 3.397769866242637815e-05f, + 2.548063973595517562e-05f, + 1.697961418894217532e-05f, + 8.483212859017624744e-06f, + 0.000000000000000000e+00f, + -8.461495318869855788e-06f, + -1.689278775621859074e-05f, + -2.528544417573815790e-05f, + -3.363109204902172219e-05f, + -4.192142777555209638e-05f, + -5.014822491167240422e-05f, + -5.830334230039153014e-05f, + -6.637873209411312210e-05f, + -7.436644766219583183e-05f, + -8.225865137590645756e-05f, + -9.004762226295531552e-05f, + -9.772576352426085543e-05f, + -1.052856099056577086e-04f, + -1.127198349174101543e-04f, + -1.200212578946849995e-04f, + -1.271828508920051467e-04f, + -1.341977454053923206e-04f, + -1.410592389156038187e-04f, + -1.477608012463634826e-04f, + -1.542960807315748824e-04f, + -1.606589101858277410e-04f, + -1.668433126724388452e-04f, + -1.728435070639570102e-04f, + -1.786539133898150888e-04f, + -1.842691579663201804e-04f, + -1.896840783043778154e-04f, + -1.948937277903842115e-04f, + -1.998933801363103201e-04f, + -2.046785335949608540e-04f, + -2.092449149366440572e-04f, + -2.135884831840112908e-04f, + -2.177054331017576675e-04f, + -2.215921984383175921e-04f, + -2.252454549169022465e-04f, + -2.286621229734833933e-04f, + -2.318393702396226929e-04f, + -2.347746137681952429e-04f, + -2.374655220005397348e-04f, + -2.399100164736049493e-04f, + -2.421062732660711372e-04f, + -2.440527241826416158e-04f, + -2.457480576760017301e-04f, + -2.471912195061305153e-04f, + -2.483814131370483272e-04f, + -2.493180998712305895e-04f, + -2.500009987222372404e-04f, + -2.504300860263741746e-04f, + -2.506055947944560284e-04f, + -2.505280138049976969e-04f, + -2.501980864404289577e-04f, + -2.496168092681825537e-04f, + -2.487854303687649961e-04f, + -2.477054474131509354e-04f, + -2.463786054921205315e-04f, + -2.448068947003734946e-04f, + -2.429925474785403472e-04f, + -2.409380357163841445e-04f, + -2.386460676207832049e-04f, + -2.361195843522810752e-04f, + -2.333617564342224063e-04f, + -2.303759799387175490e-04f, + -2.271658724538751066e-04f, + -2.237352688370258271e-04f, + -2.200882167587254817e-04f, + -2.162289720426820811e-04f, + -2.121619938068343967e-04f, + -2.078919394110624542e-04f, + -2.034236592171233195e-04f, + -1.987621911667231361e-04f, + -1.939127551835801355e-04f, + -1.888807474057235954e-04f, + -1.836717342542969276e-04f, + -1.782914463453192841e-04f, + -1.727457722510192901e-04f, + -1.670407521174195056e-04f, + -1.611825711451174772e-04f, + -1.551775529402107034e-04f, + -1.490321527423956686e-04f, + -1.427529505375406372e-04f, + -1.363466440619829170e-04f, + -1.298200417059508136e-04f, + -1.231800553235984548e-04f, + -1.164336929571301011e-04f, + -1.095880514828144936e-04f, + -1.026503091863229081e-04f, + -9.562771827530503561e-05f, + -8.852759733689483329e-05f, + -8.135732374798783709e-05f, + -7.412432604604385269e-05f, + -6.683607626845965535e-05f, + -5.950008226812831386e-05f, + -5.212388001323979862e-05f, + -4.471502587911416735e-05f, + -3.728108893993130443e-05f, + -2.982964326820167396e-05f, + -2.236826024970074687e-05f, + -1.490450092183243395e-05f, + -7.445908342878064974e-06f, + 0.000000000000000000e+00f, + 7.425739736475704763e-06f, + 1.482386710490919136e-05f, + 2.218698638297385948e-05f, + 2.950775724944274754e-05f, + 3.677890207012403487e-05f, + 4.399321310054077095e-05f, + 5.114355959833892794e-05f, + 5.822289483842819512e-05f, + 6.522426302397340788e-05f, + 7.214080608657170231e-05f, + 7.896577036881257869e-05f, + 8.569251318300049464e-05f, + 9.231450923951847092e-05f, + 9.882535693872643605e-05f, + 1.052187845203471448e-04f, + 1.114886560645364380e-04f, + 1.176289773387779070e-04f, + 1.236339014852947521e-04f, + 1.294977345434665896e-04f, + 1.352149408021485982e-04f, + 1.407801479768994418e-04f, + 1.461881522073272849e-04f, + 1.514339228700169496e-04f, + 1.565126072024935349e-04f, + 1.614195347342348315e-04f, + 1.661502215206463087e-04f, + 1.707003741761581588e-04f, + 1.750658937030649676e-04f, + 1.792428791126197800e-04f, + 1.832276308353748221e-04f, + 1.870166539177443887e-04f, + 1.906066610022775826e-04f, + 1.939945750890921376e-04f, + 1.971775320762906734e-04f, + 2.001528830773817175e-04f, + 2.029181965139526369e-04f, + 2.054712599821023459e-04f, + 2.078100818912826861e-04f, + 2.099328928746136498e-04f, + 2.118381469697695253e-04f, + 2.135245225699071707e-04f, + 2.149909231442836445e-04f, + 2.162364777284813886e-04f, + 2.172605411843266446e-04f, + 2.180626942299304465e-04f, + 2.186427432404015815e-04f, + 2.190007198200883928e-04f, + 2.191368801473969510e-04f, + 2.190517040934920065e-04f, + 2.187458941163810658e-04f, + 2.182203739321322280e-04f, + 2.174762869651921987e-04f, + 2.165149945799773028e-04f, + 2.153380740961488441e-04f, + 2.139473165901802359e-04f, + 2.123447244860358321e-04f, + 2.105325089380130263e-04f, + 2.085130870089506230e-04f, + 2.062890786472634959e-04f, + 2.038633034664208931e-04f, + 2.012387773306926119e-04f, + 1.984187087511740796e-04f, + 1.954064950962511793e-04f, + 1.922057186209438458e-04f, + 1.888201423195703249e-04f, + 1.852537056065179267e-04f, + 1.815105198299485519e-04f, + 1.775948636234848943e-04f, + 1.735111781010148112e-04f, + 1.692640619000253591e-04f, + 1.648582660788071937e-04f, + 1.602986888732223973e-04f, + 1.555903703187100698e-04f, + 1.507384867433899029e-04f, + 1.457483451382290192e-04f, + 1.406253774102959029e-04f, + 1.353751345253480795e-04f, + 1.300032805459848623e-04f, + 1.245155865716643785e-04f, + 1.189179245871088876e-04f, + 1.132162612255646118e-04f, + 1.074166514535061193e-04f, + 1.015252321834391158e-04f, + 9.554821582143662340e-05f, + 8.949188375630919609e-05f, + 8.336257979698908499e-05f, + 7.716670356510142823e-05f, + 7.091070384951115571e-05f, + 6.460107192972675580e-05f, + 5.824433487497955288e-05f, + 5.184704882602284872e-05f, + 4.541579226631734119e-05f, + 3.895715928963878430e-05f, + 3.247775287090116139e-05f, + 2.598417814704357540e-05f, + 1.948303571479631031e-05f, + 1.298091495202827620e-05f, + 6.484387369576324119e-06f, + 0.000000000000000000e+00f, + -6.465731169933958513e-06f, + -1.290632771657884088e-05f, + -1.931535523998722761e-05f, + -2.568642976144864805e-05f, + -3.201322405145375435e-05f, + -3.828947388208588727e-05f, + -4.450898419751903002e-05f, + -5.066563519664518423e-05f, + -5.675338832188378036e-05f, + -6.276629214833436183e-05f, + -6.869848816762920277e-05f, + -7.454421646074183764e-05f, + -8.029782125450870081e-05f, + -8.595375635638307819e-05f, + -9.150659046230223595e-05f, + -9.695101233261035672e-05f, + -1.022818358312054416e-04f, + -1.074940048230266600e-04f, + -1.125825979255044379e-04f, + -1.175428331093993729e-04f, + -1.223700721448543901e-04f, + -1.270598248885527321e-04f, + -1.316077534080812585e-04f, + -1.360096759398110458e-04f, + -1.402615706766127137e-04f, + -1.443595793822601773e-04f, + -1.483000108290968150e-04f, + -1.520793440561845624e-04f, + -1.556942314450015955e-04f, + -1.591415016101448729e-04f, + -1.624181621026041017e-04f, + -1.655214019234404826e-04f, + -1.684485938457612995e-04f, + -1.711972965433097588e-04f, + -1.737652565239656850e-04f, + -1.761504098667907340e-04f, + -1.783508837614152301e-04f, + -1.803649978487851233e-04f, + -1.821912653624264543e-04f, + -1.838283940697296227e-04f, + -1.852752870127996935e-04f, + -1.865310430487398998e-04f, + -1.875949571893940915e-04f, + -1.884665207407716647e-04f, + -1.891454212426279299e-04f, + -1.896315422087889631e-04f, + -1.899249626691283926e-04f, + -1.900259565141956190e-04f, + -1.899349916437565312e-04f, + -1.896527289206770522e-04f, + -1.891800209317994808e-04f, + -1.885179105576068514e-04f, + -1.876676293527271906e-04f, + -1.866305957394497354e-04f, + -1.854084130166551892e-04f, + -1.840028671867227714e-04f, + -1.824159246031662005e-04f, + -1.806497294418971144e-04f, + -1.787066009992514435e-04f, + -1.765890308199928246e-04f, + -1.742996796587417414e-04f, + -1.718413742784095856e-04f, + -1.692171040893801167e-04f, + -1.664300176333031469e-04f, + -1.634834189156041844e-04f, + -1.603807635908042269e-04f, + -1.571256550050320762e-04f, + -1.537218401001562711e-04f, + -1.501732051841159817e-04f, + -1.464837715721702366e-04f, + -1.426576911038343165e-04f, + -1.386992415405413062e-04f, + -1.346128218489411334e-04f, + -1.304029473750683709e-04f, + -1.260742449145932711e-04f, + -1.216314476844448554e-04f, + -1.170793902013302941e-04f, + -1.124230030725036544e-04f, + -1.076673077044100317e-04f, + -1.028174109349222682e-04f, + -9.787849959470351147e-05f, + -9.285583500357369501e-05f, + -8.775474740762446567e-05f, + -8.258063036294733172e-05f, + -7.733893507179906781e-05f, + -7.203516467725131118e-05f, + -6.667486852207986337e-05f, + -6.126363637798329517e-05f, + -5.580709265104459485e-05f, + -5.031089056941896167e-05f, + -4.478070635923045353e-05f, + -3.922223341459007002e-05f, + -3.364117646783503998e-05f, + -2.804324576573561864e-05f, + -2.243415125772841104e-05f, + -1.681959680200483478e-05f, + -1.120527439532200600e-05f, + -5.596858432283831980e-06f, + 0.000000000000000000e+00f, + 5.579678786350002526e-06f, + 1.113659040131433947e-05f, + 1.666518747469618845e-05f, + 2.215996829939644689e-05f, + 2.761548227605910744e-05f, + 3.302633528924318619e-05f, + 3.838719500969946610e-05f, + 4.369279611777013815e-05f, + 4.893794544267782349e-05f, + 5.411752701278543923e-05f, + 5.922650701192542296e-05f, + 6.425993863709400348e-05f, + 6.921296685271543028e-05f, + 7.408083303713561935e-05f, + 7.885887951679374148e-05f, + 8.354255398385457916e-05f, + 8.812741379313725198e-05f, + 9.260913013432653981e-05f, + 9.698349207564205016e-05f, + 1.012464104751122735e-04f, + 1.053939217560361348e-04f, + 1.094221915430763865e-04f, + 1.133275181557522266e-04f, + 1.171063359561930271e-04f, + 1.207552185482215309e-04f, + 1.242708818248938415e-04f, + 1.276501868619005589e-04f, + 1.308901426543747110e-04f, + 1.339879086947369589e-04f, + 1.369407973894841402e-04f, + 1.397462763129272100e-04f, + 1.424019702960989549e-04f, + 1.449056633492160203e-04f, + 1.472553004161910543e-04f, + 1.494489889600180950e-04f, + 1.514850003778564957e-04f, + 1.533617712449332308e-04f, + 1.550779043865114734e-04f, + 1.566321697773859439e-04f, + 1.580235052684658486e-04f, + 1.592510171403173336e-04f, + 1.603139804835744661e-04f, + 1.612118394063934590e-04f, + 1.619442070692711196e-04f, + 1.625108655477295867e-04f, + 1.629117655235336551e-04f, + 1.631470258052963916e-04f, + 1.632169326794885361e-04f, + 1.631219390930484540e-04f, + 1.628626636689312806e-04f, + 1.624398895561451970e-04f, + 1.618545631159456772e-04f, + 1.611077924460503359e-04f, + 1.602008457448726990e-04f, + 1.591351495179624102e-04f, + 1.579122866289444445e-04f, + 1.565339941974661477e-04f, + 1.550021613467485204e-04f, + 1.533188268035131036e-04f, + 1.514861763532199430e-04f, + 1.495065401536325306e-04f, + 1.473823899099098260e-04f, + 1.451163359145451060e-04f, + 1.427111239555983182e-04f, + 1.401696320967573881e-04f, + 1.374948673329850774e-04f, + 1.346899621254734052e-04f, + 1.317581708198773619e-04f, + 1.287028659518289764e-04f, + 1.255275344438603485e-04f, + 1.222357736979611648e-04f, + 1.188312875880578206e-04f, + 1.153178823568962413e-04f, + 1.116994624217160199e-04f, + 1.079800260933631265e-04f, + 1.041636612134171070e-04f, + 1.002545407141449194e-04f, + 9.625691810593006150e-05f, + 9.217512289710953982e-05f, + 8.801355595103532931e-05f, + 8.377668478539886923e-05f, + 7.946903881866790591e-05f, + 7.509520456875234419e-05f, + 7.065982080891584666e-05f, + 6.616757368602117870e-05f, + 6.162319180617105993e-05f, + 5.703144129297408308e-05f, + 5.239712082341619980e-05f, + 4.772505664658922863e-05f, + 4.302009759036991954e-05f, + 3.828711006119116657e-05f, + 3.353097304204050925e-05f, + 2.875657309374543029e-05f, + 2.396879936476407346e-05f, + 1.917253861437825900e-05f, + 1.437267025445376776e-05f, + 9.574061414716567378e-06f, + 4.781562036525325622e-06f, + 0.000000000000000000e+00f, + -4.765823710467572352e-06f, + -9.511139797770952161e-06f, + -1.423121539568319248e-05f, + -1.892135876000095219e-05f, + -2.357692390252032815e-05f, + -2.819331516332007593e-05f, + -3.276599171692918774e-05f, + -3.729047200786769084e-05f, + -4.176233811142703061e-05f, + -4.617724001535500485e-05f, + -5.053089981838045005e-05f, + -5.481911584154466779e-05f, + -5.903776664846981624e-05f, + -6.318281497064232792e-05f, + -6.725031153416303120e-05f, + -7.123639878426539594e-05f, + -7.513731450417200934e-05f, + -7.894939532493793865e-05f, + -8.266908012303817257e-05f, + -8.629291330264409008e-05f, + -8.981754795950380526e-05f, + -9.323974892372517958e-05f, + -9.655639567864357899e-05f, + -9.976448515324246556e-05f, + -1.028611343856743177e-04f, + -1.058435830556215613e-04f, + -1.087091958832444314e-04f, + -1.114554648928591494e-04f, + -1.140800115393030879e-04f, + -1.165805886954139077e-04f, + -1.189550824989598954e-04f, + -1.212015140576370412e-04f, + -1.233180410108325074e-04f, + -1.253029589470822374e-04f, + -1.271547026761611632e-04f, + -1.288718473550913872e-04f, + -1.304531094673266076e-04f, + -1.318973476546234471e-04f, + -1.332035634012388348e-04f, + -1.343709015702383085e-04f, + -1.353986507918701350e-04f, + -1.362862437040613826e-04f, + -1.370332570453443202e-04f, + -1.376394116005415203e-04f, + -1.381045719998066825e-04f, + -1.384287463716805618e-04f, + -1.386120858510235900e-04f, + -1.386548839427931658e-04f, + -1.385575757428196932e-04f, + -1.383207370168273054e-04f, + -1.379450831391416433e-04f, + -1.374314678926119766e-04f, + -1.367808821314652607e-04f, + -1.359944523088843157e-04f, + -1.350734388713058730e-04f, + -1.340192345214945692e-04f, + -1.328333623526271043e-04f, + -1.315174738557150504e-04f, + -1.300733468028466666e-04f, + -1.285028830087897415e-04f, + -1.268081059737171702e-04f, + -1.249911584097946639e-04f, + -1.230542996545981637e-04f, + -1.209999029743675174e-04f, + -1.188304527602330177e-04f, + -1.165485416206351921e-04f, + -1.141568673732511950e-04f, + -1.116582299398947146e-04f, + -1.090555281478102406e-04f, + -1.063517564410224357e-04f, + -1.035500015053626303e-04f, + -1.006534388109464010e-04f, + -9.766532907587492868e-05f, + -9.458901465512266783e-05f, + -9.142791585846299308e-05f, + -8.818552720148400341e-05f, + -8.486541359380171191e-05f, + -8.147120646848431092e-05f, + -7.800659985692548243e-05f, + -7.447534641334087790e-05f, + -7.088125339309563760e-05f, + -6.722817858922308187e-05f, + -6.352002623131395697e-05f, + -5.976074285119170978e-05f, + -5.595431311967590562e-05f, + -5.210475565880340852e-05f, + -4.821611883387434797e-05f, + -4.429247652966449879e-05f, + -4.033792391527355533e-05f, + -3.635657320185136960e-05f, + -3.235254939766243925e-05f, + -2.832998606480489144e-05f, + -2.429302108193049522e-05f, + -2.024579241723850257e-05f, + -1.619243391613931063e-05f, + -1.213707110770494373e-05f, + -8.083817034238642389e-06f, + -4.036768108108601457e-06f, + 0.000000000000000000e+00f, + 4.022436437324076239e-06f, + 8.026519205701394352e-06f, + 1.200825915466515436e-05f, + 1.596370392708562708e-05f, + 1.988894185342372352e-05f, + 2.378010579081847397e-05f, + 2.763337690325799793e-05f, + 3.144498837921355557e-05f, + 3.521122908304340009e-05f, + 3.892844713680019853e-05f, + 4.259305342891470467e-05f, + 4.620152504646010591e-05f, + 4.975040862773826440e-05f, + 5.323632363207353587e-05f, + 5.665596552365893460e-05f, + 6.000610886662674704e-05f, + 6.328361032838766603e-05f, + 6.648541158852724214e-05f, + 6.960854215060292317e-05f, + 7.265012205430279883e-05f, + 7.560736448556652138e-05f, + 7.847757828228031152e-05f, + 8.125817033344999527e-05f, + 8.394664786969736913e-05f, + 8.654062064313692193e-05f, + 8.903780299482053388e-05f, + 9.143601580795497152e-05f, + 9.373318834539185970e-05f, + 9.592735996986403448e-05f, + 9.801668174559524367e-05f, + 9.999941792013674572e-05f, + 1.018739472852775956e-04f, + 1.036387644160876654e-04f, + 1.052924807872517206e-04f, + 1.068338257660048085e-04f, + 1.082616474810422510e-04f, + 1.095749135670224514e-04f, + 1.107727117842931974e-04f, + 1.118542505136681491e-04f, + 1.128188591261970936e-04f, + 1.136659882279879026e-04f, + 1.143952097802875201e-04f, + 1.150062170951232128e-04f, + 1.154988247069874726e-04f, + 1.158729681211121310e-04f, + 1.161287034390441527e-04f, + 1.162662068623534605e-04f, + 1.162857740754014629e-04f, + 1.161878195082552873e-04f, + 1.159728754809229666e-04f, + 1.156415912302182657e-04f, + 1.151947318206731616e-04f, + 1.146331769410351999e-04f, + 1.139579195879890020e-04f, + 1.131700646388664324e-04f, + 1.122708273152050117e-04f, + 1.112615315391279159e-04f, + 1.101436081846065776e-04f, + 1.089185932257956109e-04f, + 1.075881257847022211e-04f, + 1.061539460805467204e-04f, + 1.046178932833044002e-04f, + 1.029819032739389583e-04f, + 1.012480063139884254e-04f, + 9.941832462721362205e-05f, + 9.749506989611064225e-05f, + 9.548054067616838824e-05f, + 9.337711973079915206e-05f, + 9.118727129001866780e-05f, + 8.891353823589849862e-05f, + 8.655853921798483167e-05f, + 8.412496570189726970e-05f, + 8.161557895436345137e-05f, + 7.903320696801201077e-05f, + 7.638074132934370719e-05f, + 7.366113403320848053e-05f, + 7.087739424737539320e-05f, + 6.803258503057929422e-05f, + 6.512982000765911157e-05f, + 6.217226000532499622e-05f, + 5.916310965216279986e-05f, + 5.610561394646146512e-05f, + 5.300305479558382887e-05f, + 4.985874753042966284e-05f, + 4.667603739873827257e-05f, + 4.345829604087496334e-05f, + 4.020891795178530215e-05f, + 3.693131693280893166e-05f, + 3.362892253699031918e-05f, + 3.030517651164982165e-05f, + 2.696352924175526110e-05f, + 2.360743619783213642e-05f, + 2.024035439200125525e-05f, + 1.686573884576587145e-05f, + 1.348703907309045250e-05f, + 1.010769558241483277e-05f, + 6.731136401002770680e-06f, + 3.360773625198592391e-06f, + 0.000000000000000000e+00f, + -3.347814468650473784e-06f, + -6.679325865479849946e-06f, + -9.991219678161110501e-06f, + -1.328021406688385974e-05f, + -1.654306308815880257e-05f, + -1.977655986962290348e-05f, + -2.297753973280750991e-05f, + -2.614288326084785529e-05f, + -2.926951930822502027e-05f, + -3.235442794958472064e-05f, + -3.539464336494777658e-05f, + -3.838725665850617859e-05f, + -4.132941860839394398e-05f, + -4.421834234486570842e-05f, + -4.705130595439784442e-05f, + -4.982565500735158521e-05f, + -5.253880500681173683e-05f, + -5.518824375649152762e-05f, + -5.777153364550003561e-05f, + -6.028631384797333815e-05f, + -6.273030243562301752e-05f, + -6.510129840139457593e-05f, + -6.739718359242333320e-05f, + -6.961592455074339493e-05f, + -7.175557426013427060e-05f, + -7.381427379772556206e-05f, + -7.579025388895909592e-05f, + -7.768183636476383978e-05f, + -7.948743551975573677e-05f, + -8.120555937048918389e-05f, + -8.283481081280139394e-05f, + -8.437388867751212612e-05f, + -8.582158868373181084e-05f, + -8.717680428922131703e-05f, + -8.843852743731167663e-05f, + -8.960584920002047696e-05f, + -9.067796031711479563e-05f, + -9.165415163093462887e-05f, + -9.253381441698060807e-05f, + -9.331644061029057509e-05f, + -9.400162292779464348e-05f, + -9.458905488691879318e-05f, + -9.507853072082816524e-05f, + -9.546994519078202349e-05f, + -9.576329329621814776e-05f, + -9.595866988323466294e-05f, + -9.605626915229089865e-05f, + -9.605638406600895262e-05f, + -9.595940565808516048e-05f, + -9.576582224440011919e-05f, + -9.547621853752977987e-05f, + -9.509127466593055836e-05f, + -9.461176509920040452e-05f, + -9.403855748086969134e-05f, + -9.337261137029724230e-05f, + -9.261497689531161055e-05f, + -9.176679331735186228e-05f, + -9.082928751089830238e-05f, + -8.980377235912744038e-05f, + -8.869164506774372268e-05f, + -8.749438539906182540e-05f, + -8.621355382846783715e-05f, + -8.485078962544303713e-05f, + -8.340780886146616484e-05f, + -8.188640234708234958e-05f, + -8.028843350057289605e-05f, + -7.861583615068542543e-05f, + -7.687061227593963936e-05f, + -7.505482968307974337e-05f, + -7.317061962734104652e-05f, + -7.122017437715785402e-05f, + -6.920574472607888617e-05f, + -6.712963745464778354e-05f, + -6.499421274506274500e-05f, + -6.280188155146197997e-05f, + -6.055510292871261671e-05f, + -5.825638132264141731e-05f, + -5.590826382463881251e-05f, + -5.351333739358024485e-05f, + -5.107422604809699472e-05f, + -4.859358803218347312e-05f, + -4.607411295717206477e-05f, + -4.351851892309470621e-05f, + -4.092954962253340614e-05f, + -3.830997142993496893e-05f, + -3.566257047950555911e-05f, + -3.299014973471602795e-05f, + -3.029552605247514392e-05f, + -2.758152724501864632e-05f, + -2.485098914252425363e-05f, + -2.210675265954265012e-05f, + -1.935166086816063607e-05f, + -1.658855608095106957e-05f, + -1.382027694664882434e-05f, + -1.104965556150336744e-05f, + -8.279514599188903814e-06f, + -5.512664462229372086e-06f, + -2.751900457687248369e-06f, + 0.000000000000000000e+00f, + 2.740280156290214512e-06f, + 5.466206651186378539e-06f, + 8.175072218564196470e-06f, + 1.086419834758086399e-05f, + 1.353093790349696553e-05f, + 1.617267770547626131e-05f, + 1.878684105880902989e-05f, + 2.137089023916455868e-05f, + 2.392232892650095790e-05f, + 2.643870458635503993e-05f, + 2.891761079620682311e-05f, + 3.135668951483809152e-05f, + 3.375363329250938944e-05f, + 3.610618741995035084e-05f, + 3.841215201419369719e-05f, + 4.066938403936110963e-05f, + 4.287579926060773578e-05f, + 4.502937412942688007e-05f, + 4.712814759873801425e-05f, + 4.917022286611355612e-05f, + 5.115376904367083672e-05f, + 5.307702275320218851e-05f, + 5.493828964523271308e-05f, + 5.673594584069856022e-05f, + 5.846843929414990829e-05f, + 6.013429107736878215e-05f, + 6.173209658237591092e-05f, + 6.326052664298879500e-05f, + 6.471832857406342385e-05f, + 6.610432712770806260e-05f, + 6.741742536584356324e-05f, + 6.865660544852231900e-05f, + 6.982092933759627743e-05f, + 7.090953941532209665e-05f, + 7.192165901764468636e-05f, + 7.285659288195965404e-05f, + 7.371372750925019328e-05f, + 7.449253144060441825e-05f, + 7.519255544814984439e-05f, + 7.581343264061586552e-05f, + 7.635487848374452387e-05f, + 7.681669073589902474e-05f, + 7.719874929929503027e-05f, + 7.750101598737158502e-05f, + 7.772353420888149114e-05f, + 7.786642856940284227e-05f, + 7.792990439101760668e-05f, + 7.791424715101048608e-05f, + 7.781982184050777879e-05f, + 7.764707224406404028e-05f, + 7.739652014127399414e-05f, + 7.706876443157189042e-05f, + 7.666448018344928735e-05f, + 7.618441760939247533e-05f, + 7.562940096792763350e-05f, + 7.500032739420971781e-05f, + 7.429816566067238063e-05f, + 7.352395486933000228e-05f, + 7.267880307736313862e-05f, + 7.176388585770229430e-05f, + 7.078044479637946680e-05f, + 6.972978592846818902e-05f, + 6.861327811449984264e-05f, + 6.743235135927742136e-05f, + 6.618849507510502698e-05f, + 6.488325629143087644e-05f, + 6.351823781301141390e-05f, + 6.209509632871848778e-05f, + 6.061554047316198814e-05f, + 5.908132884331902243e-05f, + 5.749426797245979628e-05f, + 5.585621026359582951e-05f, + 5.416905188480572637e-05f, + 5.243473062876452025e-05f, + 5.065522373885282526e-05f, + 4.883254570422391761e-05f, + 4.696874602629149840e-05f, + 4.506590695899598622e-05f, + 4.312614122539617790e-05f, + 4.115158971296881845e-05f, + 3.914441915014531378e-05f, + 3.710681976655663884e-05f, + 3.504100293947658921e-05f, + 3.294919882896850676e-05f, + 3.083365400421063813e-05f, + 2.869662906354593466e-05f, + 2.654039625068195532e-05f, + 2.436723706957190895e-05f, + 2.217943990043698863e-05f, + 1.997929761939633796e-05f, + 1.776910522413144273e-05f, + 1.555115746807415747e-05f, + 1.332774650545313544e-05f, + 1.110115954964658368e-05f, + 8.873676547184104307e-06f, + 6.647567869740949601e-06f, + 4.425092026438055660e-06f, + 2.208493398703637141e-06f, + 0.000000000000000000e+00f, + -2.198178737447286155e-06f, + -4.383854146707416475e-06f, + -6.554860478846427014e-06f, + -8.709057022211050465e-06f, + -1.084433018625070958e-05f, + -1.295859554782643898e-05f, + -1.504979985813177589e-05f, + -1.711592300826502171e-05f, + -1.915497995162542054e-05f, + -2.116502258133142226e-05f, + -2.314414156091539193e-05f, + -2.509046810662869737e-05f, + -2.700217571967648383e-05f, + -2.887748186688327340e-05f, + -3.071464960822724050e-05f, + -3.251198916982059171e-05f, + -3.426785946094130863e-05f, + -3.598066953382340031e-05f, + -3.764887998489755495e-05f, + -3.927100429636594712e-05f, + -4.084561011694002843e-05f, + -4.237132048071104532e-05f, + -4.384681496316908579e-05f, + -4.527083077345597480e-05f, + -4.664216378202475170e-05f, + -4.795966948291004048e-05f, + -4.922226388992814933e-05f, + -5.042892436618977834e-05f, + -5.157869038634893284e-05f, + -5.267066423112145597e-05f, + -5.370401161365963874e-05f, + -5.467796223744639814e-05f, + -5.559181028545831532e-05f, + -5.644491484037703408e-05f, + -5.723670023577102494e-05f, + -5.796665633817722128e-05f, + -5.863433876011653090e-05f, + -5.923936900414046228e-05f, + -5.978143453809256339e-05f, + -6.026028880180132370e-05f, + -6.067575114554413853e-05f, + -6.102770670064889110e-05f, + -6.131610618268607763e-05f, + -6.154096562777286157e-05f, + -6.170236606257552899e-05f, + -6.180045310866599611e-05f, + -6.183543652194144397e-05f, + -6.180758966790510722e-05f, + -6.171724893364212428e-05f, + -6.156481307740533954e-05f, + -6.135074251677746099e-05f, + -6.107555855644340075e-05f, + -6.073984255665435130e-05f, + -6.034423504353361045e-05f, + -5.988943476241735355e-05f, + -5.937619767549151724e-05f, + -5.880533590502611506e-05f, + -5.817771662356323390e-05f, + -5.749426089246688652e-05f, + -5.675594245028995661e-05f, + -5.596378645244941432e-05f, + -5.511886816375996041e-05f, + -5.422231160540798414e-05f, + -5.327528815799189400e-05f, + -5.227901512228311736e-05f, + -5.123475423943163698e-05f, + -5.014381017231689294e-05f, + -4.900752894983425071e-05f, + -4.782729637590838818e-05f, + -4.660453640505390237e-05f, + -4.534070948633992719e-05f, + -4.403731087762476868e-05f, + -4.269586893198487468e-05f, + -4.131794335821765057e-05f, + -3.990512345738859756e-05f, + -3.845902633734535553e-05f, + -3.698129510720333325e-05f, + -3.547359705373742065e-05f, + -3.393762180168319212e-05f, + -3.237507945996893324e-05f, + -3.078769875582971604e-05f, + -2.917722515883962726e-05f, + -2.754541899685784069e-05f, + -2.589405356588684348e-05f, + -2.422491323584912912e-05f, + -2.253979155425681131e-05f, + -2.084048934980605179e-05f, + -1.912881283781196876e-05f, + -1.740657172949882254e-05f, + -1.567557734707370159e-05f, + -1.393764074653252662e-05f, + -1.219457085009355482e-05f, + -1.044817259020866579e-05f, + -8.700245066967668165e-06f, + -6.952579720797126885e-06f, + -5.206958522265940783e-06f, + -3.465152180804485261e-06f, + -1.728918374115329284e-06f, + 0.000000000000000000e+00f, + 1.719876547628855035e-06f, + 3.429003076962415618e-06f, + 5.125691268998652680e-06f, + 6.808274319193801364e-06f, + 8.475108548458095382e-06f, + 1.012457498199488445e-05f, + 1.175508089444992680e-05f, + 1.336506131998390598e-05f, + 1.495298052582536945e-05f, + 1.651733344796259886e-05f, + 1.805664708766448577e-05f, + 1.956948186756530129e-05f, + 2.105443294611633769e-05f, + 2.251013148919803211e-05f, + 2.393524589783997623e-05f, + 2.532848299093816370e-05f, + 2.668858914198573803e-05f, + 2.801435136885023771e-05f, + 2.930459837571368657e-05f, + 3.055820154629149815e-05f, + 3.177407588758812874e-05f, + 3.295118092341596186e-05f, + 3.408852153701416018e-05f, + 3.518514876214479022e-05f, + 3.624016052209482158e-05f, + 3.725270231609142734e-05f, + 3.822196785265903228e-05f, + 3.914719962953973575e-05f, + 4.002768945985303464e-05f, + 4.086277894419950948e-05f, + 4.165185988850534184e-05f, + 4.239437466744202404e-05f, + 4.308981653332471270e-05f, + 4.373772987044972097e-05f, + 4.433771039486739487e-05f, + 4.488940529969052062e-05f, + 4.539251334604474478e-05f, + 4.584678489985638750e-05f, + 4.625202191471458748e-05f, + 4.660807786111483166e-05f, + 4.691485760241596739e-05f, + 4.717231721794196576e-05f, + 4.738046377366677880e-05f, + 4.753935504100859647e-05f, + 4.764909916429116248e-05f, + 4.770985427749255010e-05f, + 4.772182807094424499e-05f, + 4.768527730869501094e-05f, + 4.760050729730926094e-05f, + 4.746787130690479115e-05f, + 4.728776994528908763e-05f, + 4.706065048609898603e-05f, + 4.678700615188301687e-05f, + 4.646737535312531160e-05f, + 4.610234088422814617e-05f, + 4.569252907753687694e-05f, + 4.523860891650402077e-05f, + 4.474129110914775088e-05f, + 4.420132712297902665e-05f, + 4.361950818261826370e-05f, + 4.299666423135587823e-05f, + 4.233366285792369062e-05f, + 4.163140818980473975e-05f, + 4.089083975440875428e-05f, + 4.011293130948711432e-05f, + 3.929868964417050821e-05f, + 3.844915335206358214e-05f, + 3.756539157780807174e-05f, + 3.664850273859330111e-05f, + 3.569961322208241148e-05f, + 3.471987606224959691e-05f, + 3.371046959463910820e-05f, + 3.267259609256267485e-05f, + 3.160748038579001628e-05f, + 3.051636846325336133e-05f, + 2.940052606132795206e-05f, + 2.826123723927484845e-05f, + 2.709980294337047645e-05f, + 2.591753956132967314e-05f, + 2.471577746857528420e-05f, + 2.349585956792650177e-05f, + 2.225913982430233876e-05f, + 2.100698179596996784e-05f, + 1.974075716392971998e-05f, + 1.846184426098673837e-05f, + 1.717162660205524496e-05f, + 1.587149141723013810e-05f, + 1.456282818918089089e-05f, + 1.324702719634344427e-05f, + 1.192547806344194722e-05f, + 1.059956832081574480e-05f, + 9.270681974018148597e-06f, + 7.940198085143243810e-06f, + 6.609489367292647408e-06f, + 5.279920793626897963e-06f, + 3.952848222338136709e-06f, + 2.629617038940430149e-06f, + 1.311560817197689786e-06f, + 0.000000000000000000e+00f, + -1.303759398535709597e-06f, + -2.598427068487143802e-06f, + -3.882729655845572457e-06f, + -5.155411989361711008e-06f, + -6.415238281346936499e-06f, + -7.660993301316896363e-06f, + -8.891483521387926858e-06f, + -1.010553823239075562e-05f, + -1.130201062965311224e-05f, + -1.247977886752223057e-05f, + -1.363774708165704589e-05f, + -1.477484637820374348e-05f, + -1.589003578899699857e-05f, + -1.698230319197812681e-05f, + -1.805066619602823882e-05f, + -1.909417298952157264e-05f, + -2.011190315188001194e-05f, + -2.110296842749134194e-05f, + -2.206651346138940222e-05f, + -2.300171649612773008e-05f, + -2.390779002935145109e-05f, + -2.478398143156065395e-05f, + -2.562957352368102888e-05f, + -2.644388511403268635e-05f, + -2.722627149437084187e-05f, + -2.797612489471199853e-05f, + -2.869287489668749573e-05f, + -2.937598880525030119e-05f, + -3.002497197854884801e-05f, + -3.063936811588928184e-05f, + -3.121875950370617492e-05f, + -3.176276721952791073e-05f, + -3.227105129396500970e-05f, + -3.274331083079011072e-05f, + -3.317928408523108317e-05f, + -3.357874850062376207e-05f, + -3.394152070364435874e-05f, + -3.426745645835545690e-05f, + -3.455645057935714278e-05f, + -3.480843680437391041e-05f, + -3.502338762665158155e-05f, + -3.520131408756888464e-05f, + -3.534226552992613248e-05f, + -3.544632931239619902e-05f, + -3.551363048567052514e-05f, + -3.554433143086765164e-05f, + -3.553863146080914930e-05f, + -3.549676638480726685e-05f, + -3.541900803763526229e-05f, + -3.530566377340024634e-05f, + -3.515707592505213643e-05f, + -3.497362123031461193e-05f, + -3.475571022484123395e-05f, + -3.450378660343666126e-05f, + -3.421832655021186221e-05f, + -3.389983803856685431e-05f, + -3.354886010192489469e-05f, + -3.316596207616956312e-05f, + -3.275174281475231333e-05f, + -3.230682987747619881e-05f, + -3.183187869396395209e-05f, + -3.132757170286612567e-05f, + -3.079461746785293406e-05f, + -3.023374977148131389e-05f, + -2.964572668803002056e-05f, + -2.903132963641206598e-05f, + -2.839136241429471749e-05f, + -2.772665021457329989e-05f, + -2.703803862533824987e-05f, + -2.632639261451207689e-05f, + -2.559259550032325886e-05f, + -2.483754790880125541e-05f, + -2.406216671948075119e-05f, + -2.326738400050288322e-05f, + -2.245414593433224767e-05f, + -2.162341173525594566e-05f, + -2.077615255991108366e-05f, + -1.991335041200381325e-05f, + -1.903599704245014085e-05f, + -1.814509284612314400e-05f, + -1.724164575641496121e-05f, + -1.632667013878813598e-05f, + -1.540118568453151252e-05f, + -1.446621630586251739e-05f, + -1.352278903357414166e-05f, + -1.257193291837421751e-05f, + -1.161467793707110403e-05f, + -1.065205390473139910e-05f, + -9.685089393960801953e-06f, + -8.714810662380517595e-06f, + -7.742240589422758301e-06f, + -6.768397623508250075e-06f, + -5.794294740669309052e-06f, + -4.820938415660515435e-06f, + -3.849327606567640099e-06f, + -2.880452753939940837e-06f, + -1.915294795392051711e-06f, + -9.548241966549667941e-07f, + 0.000000000000000000e+00f, + 9.482311090557935979e-07f, + 1.888935715883699196e-06f, + 2.821194570845099363e-06f, + 3.744103462554891212e-06f, + 4.656774069485003328e-06f, + 5.558334789141776895e-06f, + 6.447931544071930670e-06f, + 7.324728563978056132e-06f, + 8.187909143270469283e-06f, + 9.036676373374730734e-06f, + 9.870253849204916702e-06f, + 1.068788634918657437e-05f, + 1.148884048828036910e-05f, + 1.227240534347507200e-05f, + 1.303789305126774333e-05f, + 1.378463937664554480e-05f, + 1.451200425317579174e-05f, + 1.521937229378508572e-05f, + 1.590615327188085737e-05f, + 1.657178257248893217e-05f, + 1.721572161311536899e-05f, + 1.783745823408358416e-05f, + 1.843650705811206880e-05f, + 1.901240981896380926e-05f, + 1.956473565900515327e-05f, + 2.009308139556312985e-05f, + 2.059707175598756487e-05f, + 2.107635958138817672e-05f, + 2.153062599901698230e-05f, + 2.195958056332863746e-05f, + 2.236296136575796357e-05f, + 2.274053511332031568e-05f, + 2.309209717614148783e-05f, + 2.341747160407918292e-05f, + 2.371651111261625155e-05f, + 2.398909703825292155e-05f, + 2.423513926363566866e-05f, + 2.445457611271804443e-05f, + 2.464737421625526288e-05f, + 2.481352834797943618e-05f, + 2.495306123182613461e-05f, + 2.506602332061461824e-05f, + 2.515249254661017629e-05f, + 2.521257404442358010e-05f, + 2.524639984673718367e-05f, + 2.525412855336374039e-05f, + 2.523594497417534085e-05f, + 2.519205974646584022e-05f, + 2.512270892732973375e-05f, + 2.502815356166727978e-05f, + 2.490867922644573402e-05f, + 2.476459555187455187e-05f, + 2.459623572016065511e-05f, + 2.440395594254615678e-05f, + 2.418813491533502720e-05f, + 2.394917325564173359e-05f, + 2.368749291761338170e-05f, + 2.340353658988623544e-05f, + 2.309776707505748077e-05f, + 2.277066665197028110e-05f, + 2.242273642161569420e-05f, + 2.205449563747421783e-05f, + 2.166648102113158283e-05f, + 2.125924606400766132e-05f, + 2.083336031605244481e-05f, + 2.038940866226966761e-05f, + 1.992799058793915062e-05f, + 1.944971943340819870e-05f, + 1.895522163933315886e-05f, + 1.844513598326477953e-05f, + 1.792011280845339264e-05f, + 1.738081324577142443e-05f, + 1.682790842964813208e-05f, + 1.626207870890487679e-05f, + 1.568401285338399734e-05f, + 1.509440725727218157e-05f, + 1.449396513998789486e-05f, + 1.388339574554209775e-05f, + 1.326341354123314987e-05f, + 1.263473741656307925e-05f, + 1.199808988324299363e-05f, + 1.135419627714907315e-05f, + 1.070378396308057514e-05f, + 1.004758154317770732e-05f, + 9.386318069818621378e-06f, + 8.720722263832011000e-06f, + 8.051521738837318949e-06f, + 7.379442232510721810e-06f, + 6.705206845569983647e-06f, + 6.029535289243417829e-06f, + 5.353143142001254931e-06f, + 4.676741116269359137e-06f, + 4.001034335873452788e-06f, + 3.326721624913985331e-06f, + 2.654494808772660456e-06f, + 1.985038027915242428e-06f, + 1.319027065167622758e-06f, + 6.571286870779092537e-07f, + 0.000000000000000000e+00f, + -6.517121785112947791e-07f, + -1.297371932417118936e-06f, + -1.936354843466996782e-06f, + -2.568048570502482838e-06f, + -3.191853411264083243e-06f, + -3.807182846237992518e-06f, + -4.413464064061555844e-06f, + -5.010138468054313338e-06f, + -5.596662163456622115e-06f, + -6.172506424989349086e-06f, + -6.737158144353800846e-06f, + -7.290120257347119171e-06f, + -7.830912150263285036e-06f, + -8.359070045291263937e-06f, + -8.874147364643450859e-06f, + -9.375715073171476542e-06f, + -9.863361999259346438e-06f, + -1.033669513378841540e-05f, + -1.079533990703045404e-05f, + -1.123894044331291381e-05f, + -1.166715979335118242e-05f, + -1.207968014415581310e-05f, + -1.247620300645970784e-05f, + -1.285644937961374137e-05f, + -1.322015989395755990e-05f, + -1.356709493066716393e-05f, + -1.389703471911742539e-05f, + -1.420977941183009213e-05f, + -1.450514913708843372e-05f, + -1.478298402933197354e-05f, + -1.504314423747151812e-05f, + -1.528550991127199633e-05f, + -1.550998116600103277e-05f, + -1.571647802553678724e-05f, + -1.590494034416860253e-05f, + -1.607532770733858182e-05f, + -1.622761931159687079e-05f, + -1.636181382406056196e-05f, + -1.647792922169452577e-05f, + -1.657600261074252277e-05f, + -1.665609002666740320e-05f, + -1.671826621496820962e-05f, + -1.676262439326730422e-05f, + -1.678927599507833507e-05f, + -1.679835039567758540e-05f, + -1.678999462052671192e-05f, + -1.676437303670283319e-05f, + -1.672166702781419629e-05f, + -1.666207465288855371e-05f, + -1.658581028974159263e-05f, + -1.649310426334120225e-05f, + -1.638420245970092517e-05f, + -1.625936592584267462e-05f, + -1.611887045638726128e-05f, + -1.596300616733423785e-05f, + -1.579207705761010350e-05f, + -1.560640055896726747e-05f, + -1.540630707483150961e-05f, + -1.519213950869398463e-05f, + -1.496425278266009707e-05f, + -1.472301334677091966e-05f, + -1.446879867971653761e-05f, + -1.420199678156508936e-05f, + -1.392300565914552601e-05f, + -1.363223280470680123e-05f, + -1.333009466849801069e-05f, + -1.301701612590346651e-05f, + -1.269342993977575572e-05f, + -1.235977621860146935e-05f, + -1.201650187114281883e-05f, + -1.166406005819747346e-05f, + -1.130290964210320150e-05f, + -1.093351463463301477e-05f, + -1.055634364390535124e-05f, + -1.017186932094184607e-05f, + -9.780567806489146604e-06f, + -9.382918178734033738e-06f, + -8.979401902509168731e-06f, + -8.570502280611855256e-06f, + -8.156703907820469213e-06f, + -7.738492128206995299e-06f, + -7.316352496326938200e-06f, + -6.890770242859669408e-06f, + -6.462229745260318158e-06f, + -6.031214003986479169e-06f, + -5.598204124829813786e-06f, + -5.163678807894833656e-06f, + -4.728113843739430985e-06f, + -4.291981617188459184e-06f, + -3.855750619313580188e-06f, + -3.419884968058363287e-06f, + -2.984843937987475483e-06f, + -2.551081499598767520e-06f, + -2.119045868650204413e-06f, + -1.689179065920102918e-06f, + -1.261916487812816974e-06f, + -8.376864881983608732e-07f, + -4.169099718748218678e-07f, + 0.000000000000000000e+00f, + 4.126385921509365552e-07f, + 8.206095647815305072e-07f, + 1.223525630207122030e-06f, + 1.621008796236126059e-06f, + 2.012690696024970467e-06f, + 2.398212904138698659e-06f, + 2.777227238591446030e-06f, + 3.149396048634148933e-06f, + 3.514392488089205312e-06f, + 3.871900774045785298e-06f, + 4.221616430751789221e-06f, + 4.563246518543961347e-06f, + 4.896509847698758431e-06f, + 5.221137177081410397e-06f, + 5.536871397505274410e-06f, + 5.843467699721675325e-06f, + 6.140693726988073073e-06f, + 6.428329712173628339e-06f, + 6.706168599377329854e-06f, + 6.974016150064908968e-06f, + 7.231691033732799246e-06f, + 7.479024903134298036e-06f, + 7.715862454119090782e-06f, + 7.942061470155300043e-06f, + 8.157492851613173758e-06f, + 8.362040629923898268e-06f, + 8.555601966717204414e-06f, + 8.738087138086968224e-06f, + 8.909419504128689090e-06f, + 9.069535463915167161e-06f, + 9.218384396096766158e-06f, + 9.355928585322825753e-06f, + 9.482143134692021052e-06f, + 9.597015864467235791e-06f, + 9.700547197287537744e-06f, + 9.792750030137629163e-06f, + 9.873649593339112619e-06f, + 9.943283296844531363e-06f, + 1.000170056413215178e-05f, + 1.004896265399734296e-05f, + 1.008514247056514156e-05f, + 1.011032436185004009e-05f, + 1.012460390719635526e-05f, + 1.012808769395258744e-05f, + 1.012089308373725277e-05f, + 1.010314796865800678e-05f, + 1.007499051786728413e-05f, + 1.003656891483040004e-05f, + 9.988041085702172294e-06f, + 9.929574419209254656e-06f, + 9.861345478440398626e-06f, + 9.783539704959164481e-06f, + 9.696351115651413914e-06f, + 9.599981992730900805e-06f, + 9.494642567327615031e-06f, + 9.380550697087179814e-06f, + 9.257931538216254041e-06f, + 9.127017212404176378e-06f, + 8.988046469065492662e-06f, + 8.841264343334779069e-06f, + 8.686921810258770176e-06f, + 8.525275435626184639e-06f, + 8.356587023873447459e-06f, + 8.181123263510028723e-06f, + 7.999155370499712271e-06f, + 7.810958730038508927e-06f, + 7.616812537163261916e-06f, + 7.416999436624914182e-06f, + 7.211805162456990385e-06f, + 7.001518177666605594e-06f, + 6.786429314468350961e-06f, + 6.566831415485732412e-06f, + 6.343018976325844570e-06f, + 6.115287789940895410e-06f, + 5.883934593178742717e-06f, + 5.649256715913496299e-06f, + 5.411551733154688679e-06f, + 5.171117120509288493e-06f, + 4.928249913373739521e-06f, + 4.683246370226741163e-06f, + 4.436401640376830997e-06f, + 4.188009436517276560e-06f, + 3.938361712429462095e-06f, + 3.687748346167128183e-06f, + 3.436456829041018457e-06f, + 3.184771960722456336e-06f, + 2.932975550760869950e-06f, + 2.681346126811560784e-06f, + 2.430158649854029301e-06f, + 2.179684236669581299e-06f, + 1.930189889838635696e-06f, + 1.681938235501949860e-06f, + 1.435187269127313838e-06f, + 1.190190109498106053e-06f, + 9.471947611406282867e-07f, + 7.064438853882597620e-07f, + 4.681745802695258113e-07f, + 2.326181693934783062e-07f, + 0.000000000000000000e+00f, + -2.294607496822518279e-07f, + -4.555512536303946545e-07f, + -6.780652116471304469e-07f, + -8.968030132995199105e-07f, + -1.111571892074599649e-06f, + -1.322186069669318649e-06f, + -1.528466890336115189e-06f, + -1.730242945231773840e-06f, + -1.927350186716386900e-06f, + -2.119632032570274826e-06f, + -2.306939460105835373e-06f, + -2.489131090168029246e-06f, + -2.666073261019773634e-06f, + -2.837640092136482743e-06f, + -3.003713537930782497e-06f, + -3.164183431450152543e-06f, + -3.318947518098628411e-06f, + -3.467911479445268386e-06f, + -3.610988947198002060e-06f, + -3.748101507421474508e-06f, + -3.879178695106657928e-06f, + -4.004157979193569750e-06f, + -4.122984738168565981e-06f, + -4.235612226366478793e-06f, + -4.342001531119113841e-06f, + -4.442121520894592501e-06f, + -4.535948784595755533e-06f, + -4.623467562178467021e-06f, + -4.704669666773933905e-06f, + -4.779554398499982279e-06f, + -4.848128450155944567e-06f, + -4.910405805006164935e-06f, + -4.966407626865209352e-06f, + -5.016162142699305776e-06f, + -5.059704517976509766e-06f, + -5.097076724993110270e-06f, + -5.128327404419833975e-06f, + -5.153511720311018673e-06f, + -5.172691208831328023e-06f, + -5.185933620952477709e-06f, + -5.193312759386582571e-06f, + -5.194908310018822646e-06f, + -5.190805668113285727e-06f, + -5.181095759564734449e-06f, + -5.165874857474497392e-06f, + -5.145244394333831128e-06f, + -5.119310770095809750e-06f, + -5.088185156423761042e-06f, + -5.051983297406574915e-06f, + -5.010825307025710792e-06f, + -4.964835463670194371e-06f, + -4.914142001988321737e-06f, + -4.858876902370465571e-06f, + -4.799175678352467995e-06f, + -4.735177162236423786e-06f, + -4.667023289215640662e-06f, + -4.594858880296614592e-06f, + -4.518831424306328092e-06f, + -4.439090859272008081e-06f, + -4.355789353459791187e-06f, + -4.269081086352130785e-06f, + -4.179122029845473253e-06f, + -4.086069729946137843e-06f, + -3.990083089234567233e-06f, + -3.891322150369041671e-06f, + -3.789947880894861469e-06f, + -3.686121959618365274e-06f, + -3.580006564802584169e-06f, + -3.471764164435954700e-06f, + -3.361557308819947231e-06f, + -3.249548425715061173e-06f, + -3.135899618280506402e-06f, + -3.020772466037677946e-06f, + -2.904327829076243898e-06f, + -2.786725655720860965e-06f, + -2.668124793866750565e-06f, + -2.548682806187309839e-06f, + -2.428555789406447020e-06f, + -2.307898197824789105e-06f, + -2.186862671278643330e-06f, + -2.065599867705792124e-06f, + -1.944258300480321568e-06f, + -1.822984180674020067e-06f, + -1.701921264393156922e-06f, + -1.581210705329814697e-06f, + -1.460990912660235641e-06f, + -1.341397414412057306e-06f, + -1.222562726419054144e-06f, + -1.104616226963808055e-06f, + -9.876840372108532818e-07f, + -8.718889075168336299e-07f, + -7.573501096980523593e-07f, + -6.441833353263205178e-07f, + -5.325006001176824594e-07f, + -4.224101544649153790e-07f, + -3.140164001606101186e-07f, + -2.074198133468546951e-07f, + -1.027168737185703904e-07f, + 0.000000000000000000e+00f, + 1.006425082962560188e-07f, + 1.991265228250998696e-07f, + 2.953721320865672257e-07f, + 3.893036808413146083e-07f, + 4.808498032861632466e-07f, + 5.699434500219715067e-07f, + 6.565219088541263631e-07f, + 7.405268194708413983e-07f, + 8.219041820579037521e-07f, + 9.006043599106572324e-07f, + 9.765820761143821518e-07f, + 1.049796404370967154e-06f, + 1.120210754056259219e-06f, + 1.187792849601788622e-06f, + 1.252514704296207476e-06f, + 1.314352588615897804e-06f, + 1.373286993192450102e-06f, + 1.429302586538256487e-06f, + 1.482388167650501341e-06f, + 1.532536613626721034e-06f, + 1.579744822422699780e-06f, + 1.624013650897105724e-06f, + 1.665347848284486069e-06f, + 1.703755985248906983e-06f, + 1.739250378670976522e-06f, + 1.771847012329051112e-06f, + 1.801565453633872846e-06f, + 1.828428766587697603e-06f, + 1.852463421131862093e-06f, + 1.873699199062873253e-06f, + 1.892169096686314783e-06f, + 1.907909224391436775e-06f, + 1.920958703325515738e-06f, + 1.931359559352847449e-06f, + 1.939156614480256200e-06f, + 1.944397375938704227e-06f, + 1.947131923107859303e-06f, + 1.947412792470748310e-06f, + 1.945294860790306117e-06f, + 1.940835226696380303e-06f, + 1.934093090874000321e-06f, + 1.925129635041577493e-06f, + 1.914007899911128539e-06f, + 1.900792662316812488e-06f, + 1.885550311703490783e-06f, + 1.868348726157043199e-06f, + 1.849257148168054309e-06f, + 1.828346060309234932e-06f, + 1.805687061008333849e-06f, + 1.781352740599210893e-06f, + 1.755416557827082551e-06f, + 1.727952716981022353e-06f, + 1.699036045830707816e-06f, + 1.668741874531441462e-06f, + 1.637145915666299804e-06f, + 1.604324145587388401e-06f, + 1.570352687212907484e-06f, + 1.535307694438660471e-06f, + 1.499265238310532749e-06f, + 1.462301195107119339e-06f, + 1.424491136473709433e-06f, + 1.385910221746217664e-06f, + 1.346633092594916054e-06f, + 1.306733770119299951e-06f, + 1.266285554515691827e-06f, + 1.225360927433250136e-06f, + 1.184031457134546194e-06f, + 1.142367706564255042e-06f, + 1.100439144428898935e-06f, + 1.058314059384136389e-06f, + 1.016059477418145401e-06f, + 9.737410825169423452e-07f, + 9.314231406881861787e-07f, + 8.891684274188879932e-07f, + 8.470381586302859329e-07f, + 8.050919251930470272e-07f, + 7.633876310564211735e-07f, + 7.219814350382115897e-07f, + 6.809276963207535929e-07f, + 6.402789236869417325e-07f, + 6.000857285259880680e-07f, + 5.603967816352038095e-07f, + 5.212587738328753669e-07f, + 4.827163803963257315e-07f, + 4.448122293282582582e-07f, + 4.075868734547717757e-07f, + 3.710787663445438682e-07f, + 3.353242420407537163e-07f, + 3.003574985858815201e-07f, + 2.662105853160385845e-07f, + 2.329133938960602585e-07f, + 2.004936530600967300e-07f, + 1.689769270175546171e-07f, + 1.383866174786039171e-07f, + 1.087439692488582841e-07f, + 8.006807933651531888e-08f, + 5.237590951157132493e-08f, + 2.568230225109257904e-08f, + 0.000000000000000000e+00f, + -2.466033232770569548e-08f, + -4.829008168683121073e-08f, + -7.088265816141993268e-08f, + -9.243346323606733125e-08f, + -1.129398551695146863e-07f, + -1.324011115659184628e-07f, + -1.508183892432858115e-07f, + -1.681946815011221211e-07f, + -1.845347728928822297e-07f, + -1.998451916121546072e-07f, + -2.141341596039432244e-07f, + -2.274115405148332402e-07f, + -2.396887855988568836e-07f, + -2.509788776975187057e-07f, + -2.612962734148978839e-07f, + -2.706568436096965910e-07f, + -2.790778123294188281e-07f, + -2.865776943115482094e-07f, + -2.931762311773865084e-07f, + -2.988943264486187393e-07f, + -3.037539795124567178e-07f, + -3.077782186659332945e-07f, + -3.109910333676799518e-07f, + -3.134173058274048922e-07f, + -3.150827420621620873e-07f, + -3.160138025468559683e-07f, + -3.162376325911064067e-07f, + -3.157819925664867536e-07f, + -3.146751881132046538e-07f, + -3.129460004522320042e-07f, + -3.106236169256348513e-07f, + -3.077375618915215213e-07f, + -3.043176280902072482e-07f, + -3.003938086063936412e-07f, + -2.959962295410709180e-07f, + -2.911550835096173451e-07f, + -2.859005640803434774e-07f, + -2.802628012618049063e-07f, + -2.742717981466135591e-07f, + -2.679573688192066510e-07f, + -2.613490776251264430e-07f, + -2.544761799041636744e-07f, + -2.473675642799770811e-07f, + -2.400516965988118414e-07f, + -2.325565656058897010e-07f, + -2.249096304424925012e-07f, + -2.171377700460247078e-07f, + -2.092672345282480135e-07f, + -2.013235986056343617e-07f, + -1.933317171473633572e-07f, + -1.853156829093616031e-07f, + -1.772987865099094365e-07f, + -1.693034787059287238e-07f, + -1.613513350178359175e-07f, + -1.534630227503889525e-07f, + -1.456582704530633583e-07f, + -1.379558398535355063e-07f, + -1.303735002995515733e-07f, + -1.229280057368551819e-07f, + -1.156350742435759375e-07f, + -1.085093701420685361e-07f, + -1.015644887007500715e-07f, + -9.481294343366335435e-08f, + -8.826615600362021996e-08f, + -8.193444872566309993e-08f, + -7.582703966755611925e-08f, + -6.995204033572834065e-08f, + -6.431645593190529234e-08f, + -5.892618816136430419e-08f, + -5.378604056816772665e-08f, + -4.889972636892558379e-08f, + -4.426987875170946693e-08f, + -3.989806360360980105e-08f, + -3.578479462389621212e-08f, + -3.192955077725143908e-08f, + -2.833079603795987602e-08f, + -2.498600136841822765e-08f, + -2.189166887745841221e-08f, + -1.904335809309968632e-08f, + -1.643571428675994097e-08f, + -1.406249877778086397e-08f, + -1.191662114752070737e-08f, + -9.990173286071856191e-09f, + -8.274465192170869078e-09f, + -6.760062445140820835e-09f, + -5.436825263828806997e-09f, + -4.293949063640696908e-09f, + -3.320006422643590005e-09f, + -2.502990363837817991e-09f, + -1.830358857702062856e-09f, + -1.289080449029138733e-09f, + -8.656809086711142593e-10f, + -5.462908092693271412e-10f, + -3.166939230097100569e-10f, + -1.623763376571505723e-10f, + -6.857618579388846575e-11f, + -2.033388168720926172e-11f, + -2.542758678303834900e-12f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f, + 0.000000000000000000e+00f +}; + +} // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp index 78410dd..e914d16 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.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. @@ -105,7 +105,7 @@ void AudioDeviceManager::createDeviceTypesIfNeeded() createAudioDeviceTypes (types); for (auto* t : types) - addAudioDeviceType (t); + addAudioDeviceType (std::unique_ptr (t)); types.clear (false); @@ -124,27 +124,36 @@ void AudioDeviceManager::audioDeviceListChanged() { if (currentAudioDevice != nullptr) { - auto isCurrentDeviceStillAvailable = [&] + auto currentDeviceStillAvailable = [&] { - for (auto* dt : availableDeviceTypes) - if (currentAudioDevice->getTypeName() == dt->getTypeName()) - for (auto& dn : dt->getDeviceNames()) - if (currentAudioDevice->getName() == dn) + auto currentTypeName = currentAudioDevice->getTypeName(); + auto currentDeviceName = currentAudioDevice->getName(); + + for (auto* deviceType : availableDeviceTypes) + { + if (currentTypeName == deviceType->getTypeName()) + { + for (auto& deviceName : deviceType->getDeviceNames (true)) + if (currentDeviceName == deviceName) + return true; + + for (auto& deviceName : deviceType->getDeviceNames (false)) + if (currentDeviceName == deviceName) return true; + } + } return false; - }; + }(); - if (! isCurrentDeviceStillAvailable()) + if (! currentDeviceStillAvailable) { closeAudioDevice(); - std::unique_ptr e (createStateXml()); - - if (e == nullptr) - initialiseDefault (preferredDeviceName, ¤tSetup); - else + if (auto e = createStateXml()) initialiseFromXML (*e, true, preferredDeviceName, ¤tSetup); + else + initialiseDefault (preferredDeviceName, ¤tSetup); } if (currentAudioDevice != nullptr) @@ -174,23 +183,40 @@ void AudioDeviceManager::createAudioDeviceTypes (OwnedArray& addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_ASIO()); addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_CoreAudio()); addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_iOSAudio()); + addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Bela()); addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_ALSA()); addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_JACK()); - addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Bela()); addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Oboe()); addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_OpenSLES()); addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Android()); } -void AudioDeviceManager::addAudioDeviceType (AudioIODeviceType* newDeviceType) +void AudioDeviceManager::addAudioDeviceType (std::unique_ptr newDeviceType) { if (newDeviceType != nullptr) { jassert (lastDeviceTypeConfigs.size() == availableDeviceTypes.size()); - availableDeviceTypes.add (newDeviceType); + + availableDeviceTypes.add (newDeviceType.release()); lastDeviceTypeConfigs.add (new AudioDeviceSetup()); - newDeviceType->addListener (callbackHandler.get()); + availableDeviceTypes.getLast()->addListener (callbackHandler.get()); + } +} + +void AudioDeviceManager::removeAudioDeviceType (AudioIODeviceType* deviceTypeToRemove) +{ + if (deviceTypeToRemove != nullptr) + { + jassert (lastDeviceTypeConfigs.size() == availableDeviceTypes.size()); + + auto index = availableDeviceTypes.indexOf (deviceTypeToRemove); + + if (auto removed = std::unique_ptr (availableDeviceTypes.removeAndReturn (index))) + { + removed->removeListener (callbackHandler.get()); + lastDeviceTypeConfigs.remove (index, true); + } } } @@ -306,19 +332,66 @@ String AudioDeviceManager::initialiseFromXML (const XmlElement& xml, error = setAudioDeviceSetup (setup, true); - midiInsFromXml.clear(); + if (error.isNotEmpty() && selectDefaultDeviceOnFailure) + error = initialise (numInputChansNeeded, numOutputChansNeeded, nullptr, false, preferredDefaultDeviceName); + + midiDeviceInfosFromXml.clear(); + enabledMidiInputs.clear(); forEachXmlChildElementWithTagName (xml, c, "MIDIINPUT") - midiInsFromXml.add (c->getStringAttribute ("name")); + midiDeviceInfosFromXml.add ({ c->getStringAttribute ("name"), c->getStringAttribute ("identifier") }); + + auto isIdentifierAvailable = [] (const Array& available, const String& identifier) + { + for (auto& device : available) + if (device.identifier == identifier) + return true; - for (auto& m : MidiInput::getDevices()) - setMidiInputEnabled (m, midiInsFromXml.contains (m)); + return false; + }; - if (error.isNotEmpty() && selectDefaultDeviceOnFailure) - error = initialise (numInputChansNeeded, numOutputChansNeeded, - nullptr, false, preferredDefaultDeviceName); + auto getUpdatedIdentifierForName = [&] (const Array& available, const String& name) -> String + { + for (auto& device : available) + if (device.name == name) + return device.identifier; + + return {}; + }; + + auto inputs = MidiInput::getAvailableDevices(); + + for (auto& info : midiDeviceInfosFromXml) + { + if (isIdentifierAvailable (inputs, info.identifier)) + { + setMidiInputDeviceEnabled (info.identifier, true); + } + else + { + auto identifier = getUpdatedIdentifierForName (inputs, info.name); + + if (identifier.isNotEmpty()) + setMidiInputDeviceEnabled (identifier, true); + } + } + + MidiDeviceInfo defaultOutputDeviceInfo (xml.getStringAttribute ("defaultMidiOutput"), + xml.getStringAttribute ("defaultMidiOutputDevice")); - setDefaultMidiOutput (xml.getStringAttribute ("defaultMidiOutput")); + auto outputs = MidiOutput::getAvailableDevices(); + + if (isIdentifierAvailable (outputs, defaultOutputDeviceInfo.identifier)) + { + setDefaultMidiOutputDevice (defaultOutputDeviceInfo.identifier); + } + else + { + auto identifier = getUpdatedIdentifierForName (outputs, defaultOutputDeviceInfo.name); + + if (identifier.isNotEmpty()) + setDefaultMidiOutputDevice (identifier); + } return error; } @@ -336,17 +409,20 @@ void AudioDeviceManager::insertDefaultDeviceNames (AudioDeviceSetup& setup) cons { if (auto* type = getCurrentDeviceTypeObject()) { - if (setup.outputDeviceName.isEmpty()) + if (numOutputChansNeeded > 0 && setup.outputDeviceName.isEmpty()) setup.outputDeviceName = type->getDeviceNames (false) [type->getDefaultDeviceIndex (false)]; - if (setup.inputDeviceName.isEmpty()) + if (numInputChansNeeded > 0 && setup.inputDeviceName.isEmpty()) setup.inputDeviceName = type->getDeviceNames (true) [type->getDefaultDeviceIndex (true)]; } } -XmlElement* AudioDeviceManager::createStateXml() const +std::unique_ptr AudioDeviceManager::createStateXml() const { - return createCopyIfNotNull (lastExplicitSettings.get()); + if (lastExplicitSettings != nullptr) + return std::make_unique (*lastExplicitSettings); + + return {}; } //============================================================================== @@ -439,28 +515,37 @@ AudioIODeviceType* AudioDeviceManager::getCurrentDeviceTypeObject() const return availableDeviceTypes.getFirst(); } +static void updateSetupChannels (AudioDeviceManager::AudioDeviceSetup& setup, int defaultNumIns, int defaultNumOuts) +{ + auto updateChannels = [] (const String& deviceName, BigInteger& channels, int defaultNumChannels) + { + if (deviceName.isEmpty()) + { + channels.clear(); + } + else if (defaultNumChannels != -1) + { + channels.clear(); + channels.setRange (0, defaultNumChannels, true); + } + }; + + updateChannels (setup.inputDeviceName, setup.inputChannels, setup.useDefaultInputChannels ? defaultNumIns : -1); + updateChannels (setup.outputDeviceName, setup.outputChannels, setup.useDefaultOutputChannels ? defaultNumOuts : -1); +} + String AudioDeviceManager::setAudioDeviceSetup (const AudioDeviceSetup& newSetup, bool treatAsChosenDevice) { jassert (&newSetup != ¤tSetup); // this will have no effect - if (newSetup == currentSetup && currentAudioDevice != nullptr) - return {}; - - if (! (newSetup == currentSetup)) + if (newSetup != currentSetup) sendChangeMessage(); + else if (currentAudioDevice != nullptr) + return {}; - stopDevice(); - - if (! newSetup.useDefaultInputChannels) - numInputChansNeeded = newSetup.inputChannels.countNumberOfSetBits(); - - if (! newSetup.useDefaultOutputChannels) - numOutputChansNeeded = newSetup.outputChannels.countNumberOfSetBits(); - - auto* type = getCurrentDeviceTypeObject(); - - if (type == nullptr) + if (getCurrentDeviceTypeObject() == nullptr + || (newSetup.inputDeviceName.isEmpty() && newSetup.outputDeviceName.isEmpty())) { deleteCurrentDevice(); @@ -470,6 +555,8 @@ String AudioDeviceManager::setAudioDeviceSetup (const AudioDeviceSetup& newSetup return {}; } + stopDevice(); + String error; if (currentSetup.inputDeviceName != newSetup.inputDeviceName @@ -479,6 +566,8 @@ String AudioDeviceManager::setAudioDeviceSetup (const AudioDeviceSetup& newSetup deleteCurrentDevice(); scanDevicesIfNeeded(); + auto* type = getCurrentDeviceTypeObject(); + if (newSetup.outputDeviceName.isNotEmpty() && ! deviceListContains (type, false, newSetup.outputDeviceName)) return "No such device: " + newSetup.outputDeviceName; @@ -499,32 +588,16 @@ String AudioDeviceManager::setAudioDeviceSetup (const AudioDeviceSetup& newSetup deleteCurrentDevice(); return error; } - - if (newSetup.useDefaultInputChannels) - { - inputChannels.clear(); - inputChannels.setRange (0, numInputChansNeeded, true); - } - - if (newSetup.useDefaultOutputChannels) - { - outputChannels.clear(); - outputChannels.setRange (0, numOutputChansNeeded, true); - } - - if (newSetup.inputDeviceName.isEmpty()) inputChannels.clear(); - if (newSetup.outputDeviceName.isEmpty()) outputChannels.clear(); } - if (! newSetup.useDefaultInputChannels) - inputChannels = newSetup.inputChannels; + currentSetup = newSetup; - if (! newSetup.useDefaultOutputChannels) - outputChannels = newSetup.outputChannels; + if (! currentSetup.useDefaultInputChannels) numInputChansNeeded = currentSetup.inputChannels.countNumberOfSetBits(); + if (! currentSetup.useDefaultOutputChannels) numOutputChansNeeded = currentSetup.outputChannels.countNumberOfSetBits(); - currentSetup = newSetup; + updateSetupChannels (currentSetup, numInputChansNeeded, numOutputChansNeeded); - if (inputChannels.isZero() && outputChannels.isZero()) + if (currentSetup.inputChannels.isZero() && currentSetup.outputChannels.isZero()) { if (treatAsChosenDevice) updateXml(); @@ -532,11 +605,11 @@ String AudioDeviceManager::setAudioDeviceSetup (const AudioDeviceSetup& newSetup return {}; } - currentSetup.sampleRate = chooseBestSampleRate (newSetup.sampleRate); - currentSetup.bufferSize = chooseBestBufferSize (newSetup.bufferSize); + currentSetup.sampleRate = chooseBestSampleRate (currentSetup.sampleRate); + currentSetup.bufferSize = chooseBestBufferSize (currentSetup.bufferSize); - error = currentAudioDevice->open (inputChannels, - outputChannels, + error = currentAudioDevice->open (currentSetup.inputChannels, + currentSetup.outputChannels, currentSetup.sampleRate, currentSetup.bufferSize); @@ -662,24 +735,37 @@ void AudioDeviceManager::updateXml() lastExplicitSettings->setAttribute ("audioDeviceOutChans", currentSetup.outputChannels.toString (2)); } - for (int i = 0; i < enabledMidiInputs.size(); ++i) - lastExplicitSettings->createNewChildElement ("MIDIINPUT") - ->setAttribute ("name", enabledMidiInputs[i]->getName()); + for (auto& input : enabledMidiInputs) + { + auto* child = lastExplicitSettings->createNewChildElement ("MIDIINPUT"); - if (midiInsFromXml.size() > 0) + child->setAttribute ("name", input->getName()); + child->setAttribute ("identifier", input->getIdentifier()); + } + + if (midiDeviceInfosFromXml.size() > 0) { // Add any midi devices that have been enabled before, but which aren't currently // open because the device has been disconnected. - const StringArray availableMidiDevices (MidiInput::getDevices()); + auto availableMidiDevices = MidiInput::getAvailableDevices(); - for (int i = 0; i < midiInsFromXml.size(); ++i) - if (! availableMidiDevices.contains (midiInsFromXml[i], true)) - lastExplicitSettings->createNewChildElement ("MIDIINPUT") - ->setAttribute ("name", midiInsFromXml[i]); + for (auto& d : midiDeviceInfosFromXml) + { + if (! availableMidiDevices.contains (d)) + { + auto* child = lastExplicitSettings->createNewChildElement ("MIDIINPUT"); + + child->setAttribute ("name", d.name); + child->setAttribute ("identifier", d.identifier); + } + } } - if (defaultMidiOutputName.isNotEmpty()) - lastExplicitSettings->setAttribute ("defaultMidiOutput", defaultMidiOutputName); + if (defaultMidiOutputDeviceInfo != MidiDeviceInfo()) + { + lastExplicitSettings->setAttribute ("defaultMidiOutput", defaultMidiOutputDeviceInfo.name); + lastExplicitSettings->setAttribute ("defaultMidiOutputDevice", defaultMidiOutputDeviceInfo.identifier); + } } //============================================================================== @@ -756,7 +842,7 @@ void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelDat else { for (int i = 0; i < numOutputChannels; ++i) - zeromem (outputChannelData[i], sizeof (float) * (size_t) numSamples); + zeromem (outputChannelData[i], (size_t) numSamples * sizeof (float)); } if (testSound != nullptr) @@ -816,28 +902,23 @@ double AudioDeviceManager::getCpuUsage() const } //============================================================================== -void AudioDeviceManager::setMidiInputEnabled (const String& name, const bool enabled) +void AudioDeviceManager::setMidiInputDeviceEnabled (const String& identifier, bool enabled) { - if (enabled != isMidiInputEnabled (name)) + if (enabled != isMidiInputDeviceEnabled (identifier)) { if (enabled) { - auto index = MidiInput::getDevices().indexOf (name); - - if (index >= 0) + if (auto midiIn = MidiInput::openDevice (identifier, callbackHandler.get())) { - if (auto* midiIn = MidiInput::openDevice (index, callbackHandler.get())) - { - enabledMidiInputs.add (midiIn); - midiIn->start(); - } + enabledMidiInputs.push_back (std::move (midiIn)); + enabledMidiInputs.back()->start(); } } else { - for (int i = enabledMidiInputs.size(); --i >= 0;) - if (enabledMidiInputs[i]->getName() == name) - enabledMidiInputs.remove (i); + auto removePredicate = [identifier] (const std::unique_ptr& in) { return in->getIdentifier() == identifier; }; + enabledMidiInputs.erase (std::remove_if (std::begin (enabledMidiInputs), std::end (enabledMidiInputs), removePredicate), + std::end (enabledMidiInputs)); } updateXml(); @@ -845,37 +926,33 @@ void AudioDeviceManager::setMidiInputEnabled (const String& name, const bool ena } } -bool AudioDeviceManager::isMidiInputEnabled (const String& name) const +bool AudioDeviceManager::isMidiInputDeviceEnabled (const String& identifier) const { - for (auto* mi : enabledMidiInputs) - if (mi->getName() == name) + for (auto& mi : enabledMidiInputs) + if (mi->getIdentifier() == identifier) return true; return false; } -void AudioDeviceManager::addMidiInputCallback (const String& name, MidiInputCallback* callbackToAdd) +void AudioDeviceManager::addMidiInputDeviceCallback (const String& identifier, MidiInputCallback* callbackToAdd) { - removeMidiInputCallback (name, callbackToAdd); + removeMidiInputDeviceCallback (identifier, callbackToAdd); - if (name.isEmpty() || isMidiInputEnabled (name)) + if (identifier.isEmpty() || isMidiInputDeviceEnabled (identifier)) { const ScopedLock sl (midiCallbackLock); - - MidiCallbackInfo mc; - mc.deviceName = name; - mc.callback = callbackToAdd; - midiCallbacks.add (mc); + midiCallbacks.add ({ identifier, callbackToAdd }); } } -void AudioDeviceManager::removeMidiInputCallback (const String& name, MidiInputCallback* callbackToRemove) +void AudioDeviceManager::removeMidiInputDeviceCallback (const String& identifier, MidiInputCallback* callbackToRemove) { for (int i = midiCallbacks.size(); --i >= 0;) { - auto& mc = midiCallbacks.getReference(i); + auto& mc = midiCallbacks.getReference (i); - if (mc.callback == callbackToRemove && mc.deviceName == name) + if (mc.callback == callbackToRemove && mc.deviceIdentifier == identifier) { const ScopedLock sl (midiCallbackLock); midiCallbacks.remove (i); @@ -890,15 +967,15 @@ void AudioDeviceManager::handleIncomingMidiMessageInt (MidiInput* source, const const ScopedLock sl (midiCallbackLock); for (auto& mc : midiCallbacks) - if (mc.deviceName.isEmpty() || mc.deviceName == source->getName()) + if (mc.deviceIdentifier.isEmpty() || mc.deviceIdentifier == source->getIdentifier()) mc.callback->handleIncomingMidiMessage (source, message); } } //============================================================================== -void AudioDeviceManager::setDefaultMidiOutput (const String& deviceName) +void AudioDeviceManager::setDefaultMidiOutputDevice (const String& identifier) { - if (defaultMidiOutputName != deviceName) + if (defaultMidiOutputDeviceInfo.identifier != identifier) { Array oldCallbacks; @@ -909,13 +986,17 @@ void AudioDeviceManager::setDefaultMidiOutput (const String& deviceName) if (currentAudioDevice != nullptr) for (int i = oldCallbacks.size(); --i >= 0;) - oldCallbacks.getUnchecked(i)->audioDeviceStopped(); + oldCallbacks.getUnchecked (i)->audioDeviceStopped(); defaultMidiOutput.reset(); - defaultMidiOutputName = deviceName; - if (deviceName.isNotEmpty()) - defaultMidiOutput.reset (MidiOutput::openDevice (MidiOutput::getDevices().indexOf (deviceName))); + if (identifier.isNotEmpty()) + defaultMidiOutput = MidiOutput::openDevice (identifier); + + if (defaultMidiOutput != nullptr) + defaultMidiOutputDeviceInfo = defaultMidiOutput->getDeviceInfo(); + else + defaultMidiOutputDeviceInfo = {}; if (currentAudioDevice != nullptr) for (auto* c : oldCallbacks) @@ -1020,4 +1101,70 @@ int AudioDeviceManager::getXRunCount() const noexcept return jmax (0, deviceXRuns) + loadMeasurer.getXRunCount(); } +//============================================================================== +// Deprecated +void AudioDeviceManager::setMidiInputEnabled (const String& name, const bool enabled) +{ + for (auto& device : MidiInput::getAvailableDevices()) + { + if (device.name == name) + { + setMidiInputDeviceEnabled (device.identifier, enabled); + return; + } + } +} + +bool AudioDeviceManager::isMidiInputEnabled (const String& name) const +{ + for (auto& device : MidiInput::getAvailableDevices()) + if (device.name == name) + return isMidiInputDeviceEnabled (device.identifier); + + return false; +} + +void AudioDeviceManager::addMidiInputCallback (const String& name, MidiInputCallback* callbackToAdd) +{ + if (name.isEmpty()) + { + addMidiInputDeviceCallback ({}, callbackToAdd); + } + else + { + for (auto& device : MidiInput::getAvailableDevices()) + { + if (device.name == name) + { + addMidiInputDeviceCallback (device.identifier, callbackToAdd); + return; + } + } + } +} + +void AudioDeviceManager::removeMidiInputCallback (const String& name, MidiInputCallback* callbackToRemove) +{ + for (auto& device : MidiInput::getAvailableDevices()) + { + if (device.name == name) + { + removeMidiInputDeviceCallback (device.identifier, callbackToRemove); + return; + } + } +} + +void AudioDeviceManager::setDefaultMidiOutput (const String& name) +{ + for (auto& device : MidiOutput::getAvailableDevices()) + { + if (device.name == name) + { + setDefaultMidiOutputDevice (device.identifier); + return; + } + } +} + } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h index 1a14843..df4e4d8 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h +++ b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.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. @@ -197,7 +197,7 @@ class JUCE_API AudioDeviceManager : public ChangeBroadcaster Note that this can return a null pointer if no settings have been explicitly changed (i.e. if the device manager has just been left in its default state). */ - XmlElement* createStateXml() const; + std::unique_ptr createStateXml() const; //============================================================================== /** Returns the current device properties that are in use. @@ -307,12 +307,12 @@ class JUCE_API AudioDeviceManager : public ChangeBroadcaster //============================================================================== /** Enables or disables a midi input device. - The list of devices can be obtained with the MidiInput::getDevices() method. + The list of devices can be obtained with the MidiInput::getAvailableDevices() method. Any incoming messages from enabled input devices will be forwarded on to all the - listeners that have been registered with the addMidiInputCallback() method. They - can either register for messages from a particular device, or from just the - "default" midi input. + listeners that have been registered with the addMidiInputDeviceCallback() method. They + can either register for messages from a particular device, or from just the "default" + midi input. Routing the midi input via an AudioDeviceManager means that when a listener registers for the default midi input, this default device can be changed by the @@ -322,62 +322,65 @@ class JUCE_API AudioDeviceManager : public ChangeBroadcaster or not present, so that when the input is re-enabled, the listener will start receiving messages again. - @see addMidiInputCallback, isMidiInputEnabled + @see addMidiInputDeviceCallback, isMidiInputDeviceEnabled */ - void setMidiInputEnabled (const String& midiInputDeviceName, bool enabled); + void setMidiInputDeviceEnabled (const String& deviceIdentifier, bool enabled); /** Returns true if a given midi input device is being used. - @see setMidiInputEnabled + + @see setMidiInputDeviceEnabled */ - bool isMidiInputEnabled (const String& midiInputDeviceName) const; + bool isMidiInputDeviceEnabled (const String& deviceIdentifier) const; /** Registers a listener for callbacks when midi events arrive from a midi input. - The device name can be empty to indicate that it wants to receive all incoming - events from all the enabled MIDI inputs. Or it can be the name of one of the + The device identifier can be empty to indicate that it wants to receive all incoming + events from all the enabled MIDI inputs. Or it can be the identifier of one of the MIDI input devices if it just wants the events from that device. (see - MidiInput::getDevices() for the list of device names). + MidiInput::getAvailableDevices() for the list of devices). - Only devices which are enabled (see the setMidiInputEnabled() method) will have their + Only devices which are enabled (see the setMidiInputDeviceEnabled() method) will have their events forwarded on to listeners. */ - void addMidiInputCallback (const String& midiInputDeviceName, - MidiInputCallback* callback); + void addMidiInputDeviceCallback (const String& deviceIdentifier, + MidiInputCallback* callback); - /** Removes a listener that was previously registered with addMidiInputCallback(). */ - void removeMidiInputCallback (const String& midiInputDeviceName, - MidiInputCallback* callback); + /** Removes a listener that was previously registered with addMidiInputDeviceCallback(). */ + void removeMidiInputDeviceCallback (const String& deviceIdentifier, + MidiInputCallback* callback); //============================================================================== /** Sets a midi output device to use as the default. - The list of devices can be obtained with the MidiOutput::getDevices() method. + The list of devices can be obtained with the MidiOutput::getAvailableDevices() method. The specified device will be opened automatically and can be retrieved with the getDefaultMidiOutput() method. Pass in an empty string to deselect all devices. For the default device, you - can use MidiOutput::getDevices() [MidiOutput::getDefaultDeviceIndex()]. + can use MidiOutput::getDefaultDevice(). - @see getDefaultMidiOutput, getDefaultMidiOutputName + @see getDefaultMidiOutput, getDefaultMidiOutputIdentifier */ - void setDefaultMidiOutput (const String& deviceName); + void setDefaultMidiOutputDevice (const String& deviceIdentifier); /** Returns the name of the default midi output. - @see setDefaultMidiOutput, getDefaultMidiOutput + + @see setDefaultMidiOutputDevice, getDefaultMidiOutput */ - const String& getDefaultMidiOutputName() const noexcept { return defaultMidiOutputName; } + const String& getDefaultMidiOutputIdentifier() const noexcept { return defaultMidiOutputDeviceInfo.identifier; } + + /** Returns the current default midi output device. If no device has been selected, or the + device can't be opened, this will return nullptr. - /** Returns the current default midi output device. - If no device has been selected, or the device can't be opened, this will return nullptr. - @see getDefaultMidiOutputName + @see getDefaultMidiOutputIdentifier */ MidiOutput* getDefaultMidiOutput() const noexcept { return defaultMidiOutput.get(); } + //============================================================================== /** Returns a list of the types of device supported. */ const OwnedArray& getAvailableDeviceTypes(); - //============================================================================== /** Creates a list of available types. This will add a set of new AudioIODeviceType objects to the specified list, to @@ -388,10 +391,11 @@ class JUCE_API AudioDeviceManager : public ChangeBroadcaster */ virtual void createAudioDeviceTypes (OwnedArray& types); - /** Adds a new device type to the list of types. - The manager will take ownership of the object that is passed-in. - */ - void addAudioDeviceType (AudioIODeviceType* newDeviceType); + /** Adds a new device type to the list of types. */ + void addAudioDeviceType (std::unique_ptr newDeviceType); + + /** Removes a previously added device type from the manager. */ + void removeAudioDeviceType (AudioIODeviceType* deviceTypeToRemove); //============================================================================== /** Plays a beep through the current audio device. @@ -461,6 +465,20 @@ class JUCE_API AudioDeviceManager : public ChangeBroadcaster */ int getXRunCount() const noexcept; + //============================================================================== + /** Deprecated. */ + void setMidiInputEnabled (const String&, bool); + /** Deprecated. */ + bool isMidiInputEnabled (const String&) const; + /** Deprecated. */ + void addMidiInputCallback (const String&, MidiInputCallback*); + /** Deprecated. */ + void removeMidiInputCallback (const String&, MidiInputCallback*); + /** Deprecated. */ + void setDefaultMidiOutput (const String&); + /** Deprecated. */ + const String& getDefaultMidiOutputName() const noexcept { return defaultMidiOutputDeviceInfo.name; } + private: //============================================================================== OwnedArray availableDeviceTypes; @@ -471,22 +489,21 @@ class JUCE_API AudioDeviceManager : public ChangeBroadcaster Array callbacks; int numInputChansNeeded = 0, numOutputChansNeeded = 2; String preferredDeviceName, currentDeviceType; - BigInteger inputChannels, outputChannels; std::unique_ptr lastExplicitSettings; mutable bool listNeedsScanning = true; AudioBuffer tempBuffer; struct MidiCallbackInfo { - String deviceName; + String deviceIdentifier; MidiInputCallback* callback; }; - StringArray midiInsFromXml; - OwnedArray enabledMidiInputs; + Array midiDeviceInfosFromXml; + std::vector> enabledMidiInputs; Array midiCallbacks; - String defaultMidiOutputName; + MidiDeviceInfo defaultMidiOutputDeviceInfo; std::unique_ptr defaultMidiOutput; CriticalSection audioCallbackLock, midiCallbackLock; diff --git a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODevice.cpp b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODevice.cpp index 7af3fb9..7e108f6 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODevice.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODevice.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_devices/audio_io/juce_AudioIODevice.h b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODevice.h index 910b572..3622c48 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODevice.h +++ b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODevice.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_devices/audio_io/juce_AudioIODeviceType.cpp b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.cpp index fa67206..249620e 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.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_devices/audio_io/juce_AudioIODeviceType.h b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h index 1aa1a67..1ece550 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h +++ b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.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_devices/audio_io/juce_SystemAudioVolume.h b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_SystemAudioVolume.h index 3a0f934..bd0d76c 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_SystemAudioVolume.h +++ b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_SystemAudioVolume.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_devices/juce_audio_devices.cpp b/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.cpp index 0eed4fe..3dcfba3 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.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,15 +84,13 @@ #include #include - #pragma warning (push) - #pragma warning (disable: 4265) + JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4265) #include - #pragma warning (pop) + JUCE_END_IGNORE_WARNINGS_MSVC - #pragma warning (push) - #pragma warning (disable: 4467) + JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4467) #include - #pragma warning (pop) + JUCE_END_IGNORE_WARNINGS_MSVC #endif #if JUCE_ASIO @@ -149,7 +147,6 @@ installed, or you've not got your paths set up correctly to find its header files. */ - #include #include #include #endif @@ -170,7 +167,13 @@ #error "Oboe cannot be enabled at the same time as openSL! Please disable JUCE_USE_ANDROID_OPENSLES" #endif - #include + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunused-parameter", + "-Wzero-as-null-pointer-constant", + "-Winconsistent-missing-destructor-override", + "-Wshadow-field-in-constructor", + "-Wshadow-field") + #include + JUCE_END_IGNORE_WARNINGS_GCC_LIKE #endif #endif @@ -179,7 +182,7 @@ #include "audio_io/juce_AudioIODevice.cpp" #include "audio_io/juce_AudioIODeviceType.cpp" #include "midi_io/juce_MidiMessageCollector.cpp" -#include "midi_io/juce_MidiOutput.cpp" +#include "midi_io/juce_MidiDevices.cpp" #include "sources/juce_AudioSourcePlayer.cpp" #include "sources/juce_AudioTransportSource.cpp" #include "native/juce_MidiDataConcatenator.h" @@ -232,13 +235,18 @@ #include "native/juce_android_Audio.cpp" #include "native/juce_android_Midi.cpp" - #if JUCE_USE_ANDROID_OPENSLES - #include "native/juce_android_OpenSL.cpp" - #endif + #if JUCE_USE_ANDROID_OPENSLES || JUCE_USE_ANDROID_OBOE + #include "native/juce_android_HighPerformanceAudioHelpers.h" - #if JUCE_USE_ANDROID_OBOE - #include "native/juce_android_Oboe.cpp" + #if JUCE_USE_ANDROID_OPENSLES + #include "native/juce_android_OpenSL.cpp" + #endif + + #if JUCE_USE_ANDROID_OBOE + #include "native/juce_android_Oboe.cpp" + #endif #endif + #endif #if ! JUCE_SYSTEMAUDIOVOL_IMPLEMENTED diff --git a/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.h b/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.h index 38ccd0b..d0ee77a 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.h +++ b/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.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,28 +20,29 @@ ============================================================================== */ + /******************************************************************************* 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_devices - vendor: juce - version: 5.4.3 - name: JUCE audio and MIDI I/O device classes - description: Classes to play and record from audio and MIDI I/O devices - website: http://www.juce.com/juce - license: ISC + ID: juce_audio_devices + vendor: juce + version: 6.0.1 + name: JUCE audio and MIDI I/O device classes + description: Classes to play and record from audio and MIDI I/O devices + website: http://www.juce.com/juce + license: ISC - dependencies: juce_audio_basics, juce_events - OSXFrameworks: CoreAudio CoreMIDI AudioToolbox - iOSFrameworks: CoreAudio CoreMIDI AudioToolbox AVFoundation - linuxPackages: alsa - mingwLibs: winmm + dependencies: juce_audio_basics, juce_events + OSXFrameworks: CoreAudio CoreMIDI AudioToolbox + iOSFrameworks: CoreAudio CoreMIDI AudioToolbox AVFoundation + linuxPackages: alsa + mingwLibs: winmm END_JUCE_MODULE_DECLARATION @@ -62,9 +63,8 @@ /** Config: JUCE_USE_WINRT_MIDI Enables the use of the Windows Runtime API for MIDI, allowing connections to Bluetooth Low Energy devices on Windows 10 version 1809 (October 2018 - Update) and later. If you enable this flag then older, unsupported, - versions of Windows will automatically fall back to using the regualar - Win32 MIDI API. + Update) and later. If you enable this flag then older versions of Windows + will automatically fall back to using the regular Win32 MIDI API. You will need version 10.0.14393.0 of the Windows Standalone SDK to compile and you may need to add the path to the WinRT headers. The path to the @@ -132,18 +132,10 @@ #endif /** Config: JUCE_USE_ANDROID_OBOE - *** - DEVELOPER PREVIEW - Oboe is currently in developer preview and - is in active development. This preview allows for early access - and evaluation for developers targeting Android platform. - *** - - Enables Oboe devices (Android only, API 16 or above). Requires - Oboe repository path to be specified in Android exporter. + Enables Oboe devices (Android only, API 16 or above). */ - #ifndef JUCE_USE_ANDROID_OBOE - #define JUCE_USE_ANDROID_OBOE 0 + #define JUCE_USE_ANDROID_OBOE 1 #endif #if JUCE_USE_ANDROID_OBOE && JUCE_ANDROID_API_VERSION < 16 @@ -151,6 +143,15 @@ #define JUCE_USE_ANDROID_OBOE 0 #endif +/** Config: JUCE_USE_OBOE_STABILIZED_CALLBACK + If JUCE_USE_ANDROID_OBOE is enabled, enabling this will wrap output audio + streams in the oboe::StabilizedCallback class. This class attempts to keep + the CPU spinning to avoid it being scaled down on certain devices. +*/ +#ifndef JUCE_USE_ANDROID_OBOE_STABILIZED_CALLBACK + #define JUCE_USE_ANDROID_OBOE_STABILIZED_CALLBACK 0 +#endif + /** Config: JUCE_USE_ANDROID_OPENSLES Enables OpenSLES devices (Android only). */ @@ -171,9 +172,8 @@ #endif //============================================================================== -#include "midi_io/juce_MidiInput.h" +#include "midi_io/juce_MidiDevices.h" #include "midi_io/juce_MidiMessageCollector.h" -#include "midi_io/juce_MidiOutput.h" #include "audio_io/juce_AudioIODevice.h" #include "audio_io/juce_AudioIODeviceType.h" #include "audio_io/juce_SystemAudioVolume.h" diff --git a/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.mm b/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.mm index 6ff08e9..868040a 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.mm +++ b/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.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_devices/midi_io/juce_MidiOutput.cpp b/JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiDevices.cpp similarity index 81% rename from JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiOutput.cpp rename to JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiDevices.cpp index 26b6614..4464777 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiOutput.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiDevices.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,29 +23,15 @@ namespace juce { -struct MidiOutput::PendingMessage -{ - PendingMessage (const void* data, int len, double timeStamp) - : message (data, len, timeStamp) - {} - - MidiMessage message; - PendingMessage* next; -}; - -MidiOutput::MidiOutput (const String& deviceName) - : Thread ("midi out"), name (deviceName) +MidiOutput::MidiOutput (const String& deviceName, const String& deviceIdentifier) + : Thread ("midi out"), deviceInfo (deviceName, deviceIdentifier) { } void MidiOutput::sendBlockOfMessagesNow (const MidiBuffer& buffer) { - MidiBuffer::Iterator i (buffer); - MidiMessage message; - int samplePosition; // Note: Not actually used, so no need to initialise. - - while (i.getNextEvent (message, samplePosition)) - sendMessageNow (message); + for (const auto metadata : buffer) + sendMessageNow (metadata.getMessage()); } void MidiOutput::sendBlockOfMessages (const MidiBuffer& buffer, @@ -60,13 +46,10 @@ void MidiOutput::sendBlockOfMessages (const MidiBuffer& buffer, auto timeScaleFactor = 1000.0 / samplesPerSecondForBuffer; - const uint8* data; - int len, time; - - for (MidiBuffer::Iterator i (buffer); i.getNextEvent (data, len, time);) + for (const auto metadata : buffer) { - auto eventTime = millisecondCounterToStartAt + timeScaleFactor * time; - auto* m = new PendingMessage (data, len, eventTime); + auto eventTime = millisecondCounterToStartAt + timeScaleFactor * metadata.samplePosition; + auto* m = new PendingMessage (metadata.data, metadata.numBytes, eventTime); const ScopedLock sl (lock); @@ -116,7 +99,7 @@ void MidiOutput::run() { while (! threadShouldExit()) { - uint32 now = Time::getMillisecondCounter(); + auto now = Time::getMillisecondCounter(); uint32 eventTime = 0; uint32 timeToWait = 500; diff --git a/JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiDevices.h b/JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiDevices.h new file mode 100644 index 0000000..4da13af --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiDevices.h @@ -0,0 +1,378 @@ +/* + ============================================================================== + + 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 +{ +//============================================================================== +/** + This struct contains information about a MIDI input or output device. + + You can get one of these structs by calling the static getAvailableDevices() or + getDefaultDevice() methods of MidiInput and MidiOutput or by calling getDeviceInfo() + on an instance of these classes. Devices can be opened by passing the identifier to + the openDevice() method. + + @tags{Audio} +*/ +struct MidiDeviceInfo +{ + MidiDeviceInfo() = default; + + MidiDeviceInfo (const String& deviceName, const String& deviceIdentifier) + : name (deviceName), identifier (deviceIdentifier) + { + } + + /** The name of this device. + + This will be provided by the OS unless the device has been created with the + createNewDevice() method. + + Note that the name is not guaranteed to be unique and two devices with the + same name will be indistinguishable. If you want to address a specific device + it is better to use the identifier. + */ + String name; + + /** The identifier for this device. + + This will be provided by the OS and it's format will differ on different systems + e.g. on macOS it will be a number whereas on Windows it will be a long alphanumeric string. + */ + String identifier; + + //============================================================================== + bool operator== (const MidiDeviceInfo& other) const noexcept { return name == other.name && identifier == other.identifier; } + bool operator!= (const MidiDeviceInfo& other) const noexcept { return ! operator== (other); } +}; + +class MidiInputCallback; + +//============================================================================== +/** + Represents a midi input device. + + To create one of these, use the static getAvailableDevices() method to find out what + inputs are available, and then use the openDevice() method to try to open one. + + @see MidiOutput + + @tags{Audio} +*/ +class JUCE_API MidiInput final +{ +public: + //============================================================================== + /** Returns a list of the available midi input devices. + + You can open one of the devices by passing its identifier into the openDevice() method. + + @see MidiDeviceInfo, getDevices, getDefaultDeviceIndex, openDevice + */ + static Array getAvailableDevices(); + + /** Returns the MidiDeviceInfo of the default midi input device to use. */ + static MidiDeviceInfo getDefaultDevice(); + + /** Tries to open one of the midi input devices. + + This will return a MidiInput object if it manages to open it, you can then + call start() and stop() on this device. + + If the device can't be opened, this will return an empty object. + + @param deviceIdentifier the ID of the device to open - use the getAvailableDevices() method to + find the available devices that can be opened + @param callback the object that will receive the midi messages from this device + + @see MidiInputCallback, getDevices + */ + static std::unique_ptr openDevice (const String& deviceIdentifier, MidiInputCallback* callback); + + #if JUCE_LINUX || JUCE_MAC || JUCE_IOS || DOXYGEN + /** This will try to create a new midi input device (only available on Linux, macOS and iOS). + + This will attempt to create a new midi input device with the specified name for other + apps to connect to. + + NB - if you are calling this method on iOS you must have enabled the "Audio Background Capability" + setting in the iOS exporter otherwise this method will fail. + + Returns an empty object if a device can't be created. + + @param deviceName the name of the device to create + @param callback the object that will receive the midi messages from this device + */ + static std::unique_ptr createNewDevice (const String& deviceName, MidiInputCallback* callback); + #endif + + //============================================================================== + /** Destructor. */ + ~MidiInput(); + + /** Starts the device running. + + After calling this, the device will start sending midi messages to the MidiInputCallback + object that was specified when the openDevice() method was called. + + @see stop + */ + void start(); + + /** Stops the device running. + + @see start + */ + void stop(); + + /** Returns the MidiDeviceInfo struct containing some information about this device. */ + MidiDeviceInfo getDeviceInfo() const noexcept { return deviceInfo; } + + /** Returns the identifier of this device. */ + String getIdentifier() const noexcept { return deviceInfo.identifier; } + + /** Returns the name of this device. */ + String getName() const noexcept { return deviceInfo.name; } + + /** Sets a custom name for the device. */ + void setName (const String& newName) noexcept { deviceInfo.name = newName; } + + //============================================================================== + /** Deprecated. */ + static StringArray getDevices(); + /** Deprecated. */ + static int getDefaultDeviceIndex(); + /** Deprecated. */ + static std::unique_ptr openDevice (int, MidiInputCallback*); + +private: + //============================================================================== + explicit MidiInput (const String&, const String&); + + MidiDeviceInfo deviceInfo; + void* internal = nullptr; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiInput) +}; + +//============================================================================== +/** + Receives incoming messages from a physical MIDI input device. + + This class is overridden to handle incoming midi messages. See the MidiInput + class for more details. + + @see MidiInput + + @tags{Audio} +*/ +class JUCE_API MidiInputCallback +{ +public: + /** Destructor. */ + virtual ~MidiInputCallback() = default; + + /** Receives an incoming message. + + A MidiInput object will call this method when a midi event arrives. It'll be + called on a high-priority system thread, so avoid doing anything time-consuming + in here, and avoid making any UI calls. You might find the MidiBuffer class helpful + for queueing incoming messages for use later. + + @param source the MidiInput object that generated the message + @param message the incoming message. The message's timestamp is set to a value + equivalent to (Time::getMillisecondCounter() / 1000.0) to specify the + time when the message arrived + */ + virtual void handleIncomingMidiMessage (MidiInput* source, + const MidiMessage& message) = 0; + + /** Notification sent each time a packet of a multi-packet sysex message arrives. + + If a long sysex message is broken up into multiple packets, this callback is made + for each packet that arrives until the message is finished, at which point + the normal handleIncomingMidiMessage() callback will be made with the entire + message. + + The message passed in will contain the start of a sysex, but won't be finished + with the terminating 0xf7 byte. + */ + virtual void handlePartialSysexMessage (MidiInput* source, + const uint8* messageData, + int numBytesSoFar, + double timestamp) + { + ignoreUnused (source, messageData, numBytesSoFar, timestamp); + } +}; + +//============================================================================== +/** + Represents a midi output device. + + To create one of these, use the static getAvailableDevices() method to find out what + outputs are available, and then use the openDevice() method to try to open one. + + @see MidiInput + + @tags{Audio} +*/ +class JUCE_API MidiOutput final : private Thread +{ +public: + //============================================================================== + /** Returns a list of the available midi output devices. + + You can open one of the devices by passing its identifier into the openDevice() method. + + @see MidiDeviceInfo, getDevices, getDefaultDeviceIndex, openDevice + */ + static Array getAvailableDevices(); + + /** Returns the MidiDeviceInfo of the default midi output device to use. */ + static MidiDeviceInfo getDefaultDevice(); + + /** Tries to open one of the midi output devices. + + This will return a MidiOutput object if it manages to open it, you can then + send messages to this device. + + If the device can't be opened, this will return an empty object. + + @param deviceIdentifier the ID of the device to open - use the getAvailableDevices() method to + find the available devices that can be opened + @see getDevices + */ + static std::unique_ptr openDevice (const String& deviceIdentifier); + + #if JUCE_LINUX || JUCE_MAC || JUCE_IOS || DOXYGEN + /** This will try to create a new midi output device (only available on Linux, macOS and iOS). + + This will attempt to create a new midi output device with the specified name that other + apps can connect to and use as their midi input. + + NB - if you are calling this method on iOS you must have enabled the "Audio Background Capability" + setting in the iOS exporter otherwise this method will fail. + + Returns an empty object if a device can't be created. + + @param deviceName the name of the device to create + */ + static std::unique_ptr createNewDevice (const String& deviceName); + #endif + + //============================================================================== + /** Destructor. */ + ~MidiOutput() override; + + /** Returns the MidiDeviceInfo struct containing some information about this device. */ + MidiDeviceInfo getDeviceInfo() const noexcept { return deviceInfo; } + + /** Returns the identifier of this device. */ + String getIdentifier() const noexcept { return deviceInfo.identifier; } + + /** Returns the name of this device. */ + String getName() const noexcept { return deviceInfo.name; } + + /** Sets a custom name for the device. */ + void setName (const String& newName) noexcept { deviceInfo.name = newName; } + + //============================================================================== + /** Sends out a MIDI message immediately. */ + void sendMessageNow (const MidiMessage& message); + + /** Sends out a sequence of MIDI messages immediately. */ + void sendBlockOfMessagesNow (const MidiBuffer& buffer); + + /** This lets you supply a block of messages that will be sent out at some point + in the future. + + The MidiOutput class has an internal thread that can send out timestamped + messages - this appends a set of messages to its internal buffer, ready for + sending. + + This will only work if you've already started the thread with startBackgroundThread(). + + A time is specified, at which the block of messages should be sent. This time uses + the same time base as Time::getMillisecondCounter(), and must be in the future. + + The samplesPerSecondForBuffer parameter indicates the number of samples per second + used by the MidiBuffer. Each event in a MidiBuffer has a sample position, and the + samplesPerSecondForBuffer value is needed to convert this sample position to a + real time. + */ + void sendBlockOfMessages (const MidiBuffer& buffer, + double millisecondCounterToStartAt, + double samplesPerSecondForBuffer); + + /** Gets rid of any midi messages that had been added by sendBlockOfMessages(). */ + void clearAllPendingMessages(); + + /** Starts up a background thread so that the device can send blocks of data. + Call this to get the device ready, before using sendBlockOfMessages(). + */ + void startBackgroundThread(); + + /** Stops the background thread, and clears any pending midi events. + @see startBackgroundThread + */ + void stopBackgroundThread(); + + /** Returns true if the background thread used to send blocks of data is running. + @see startBackgroundThread, stopBackgroundThread + */ + bool isBackgroundThreadRunning() const noexcept { return isThreadRunning(); } + + //============================================================================== + /** Deprecated. */ + static StringArray getDevices(); + /** Deprecated. */ + static int getDefaultDeviceIndex(); + /** Deprecated. */ + static std::unique_ptr openDevice (int); + +private: + //============================================================================== + struct PendingMessage + { + PendingMessage (const void* data, int len, double timeStamp) + : message (data, len, timeStamp) + { + } + + MidiMessage message; + PendingMessage* next; + }; + + //============================================================================== + explicit MidiOutput (const String&, const String&); + void run() override; + + MidiDeviceInfo deviceInfo; + void* internal = nullptr; + CriticalSection lock; + PendingMessage* firstMessage = nullptr; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiOutput) +}; + +} // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiInput.h b/JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiInput.h deleted file mode 100644 index 4d9e483..0000000 --- a/JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiInput.h +++ /dev/null @@ -1,180 +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 -{ - -class MidiInput; - - -//============================================================================== -/** - Receives incoming messages from a physical MIDI input device. - - This class is overridden to handle incoming midi messages. See the MidiInput - class for more details. - - @see MidiInput - - @tags{Audio} -*/ -class JUCE_API MidiInputCallback -{ -public: - /** Destructor. */ - virtual ~MidiInputCallback() = default; - - - /** Receives an incoming message. - - A MidiInput object will call this method when a midi event arrives. It'll be - called on a high-priority system thread, so avoid doing anything time-consuming - in here, and avoid making any UI calls. You might find the MidiBuffer class helpful - for queueing incoming messages for use later. - - @param source the MidiInput object that generated the message - @param message the incoming message. The message's timestamp is set to a value - equivalent to (Time::getMillisecondCounter() / 1000.0) to specify the - time when the message arrived. - */ - virtual void handleIncomingMidiMessage (MidiInput* source, - const MidiMessage& message) = 0; - - /** Notification sent each time a packet of a multi-packet sysex message arrives. - - If a long sysex message is broken up into multiple packets, this callback is made - for each packet that arrives until the message is finished, at which point - the normal handleIncomingMidiMessage() callback will be made with the entire - message. - - The message passed in will contain the start of a sysex, but won't be finished - with the terminating 0xf7 byte. - */ - virtual void handlePartialSysexMessage (MidiInput* source, - const uint8* messageData, - int numBytesSoFar, - double timestamp) - { - ignoreUnused (source, messageData, numBytesSoFar, timestamp); - } -}; - -//============================================================================== -/** - Represents a midi input device. - - To create one of these, use the static getDevices() method to find out what inputs are - available, and then use the openDevice() method to try to open one. - - @see MidiOutput - - @tags{Audio} -*/ -class JUCE_API MidiInput final -{ -public: - //============================================================================== - /** Returns a list of the available midi input devices. - - You can open one of the devices by passing its index into the - openDevice() method. - - @see getDefaultDeviceIndex, openDevice - */ - static StringArray getDevices(); - - /** Returns the index of the default midi input device to use. - - This refers to the index in the list returned by getDevices(). - */ - static int getDefaultDeviceIndex(); - - /** Tries to open one of the midi input devices. - - This will return a MidiInput object if it manages to open it. You can then - call start() and stop() on this device, and delete it when no longer needed. - - If the device can't be opened, this will return a null pointer. - - @param deviceIndex the index of a device from the list returned by getDevices() - @param callback the object that will receive the midi messages from this device. - - @see MidiInputCallback, getDevices - */ - static MidiInput* openDevice (int deviceIndex, - MidiInputCallback* callback); - - #if JUCE_LINUX || JUCE_MAC || JUCE_IOS || DOXYGEN - /** This will try to create a new midi input device (Not available on Windows). - - This will attempt to create a new midi input device with the specified name, - for other apps to connect to. - - Returns nullptr if a device can't be created. - - @param deviceName the name to use for the new device - @param callback the object that will receive the midi messages from this device. - */ - static MidiInput* createNewDevice (const String& deviceName, - MidiInputCallback* callback); - #endif - - //============================================================================== - /** Destructor. */ - ~MidiInput(); - - /** Returns the name of this device. */ - const String& getName() const noexcept { return name; } - - /** Allows you to set a custom name for the device, in case you don't like the name - it was given when created. - */ - void setName (const String& newName) noexcept { name = newName; } - - //============================================================================== - /** Starts the device running. - - After calling this, the device will start sending midi messages to the - MidiInputCallback object that was specified when the openDevice() method - was called. - - @see stop - */ - void start(); - - /** Stops the device running. - @see start - */ - void stop(); - -private: - //============================================================================== - String name; - void* internal = nullptr; - - // The input objects are created with the openDevice() method. - explicit MidiInput (const String&); - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiInput) -}; - -} // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.cpp b/JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.cpp index 8aa5d01..d11647f 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.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. @@ -34,9 +34,10 @@ MidiMessageCollector::~MidiMessageCollector() //============================================================================== void MidiMessageCollector::reset (const double newSampleRate) { + const ScopedLock sl (midiCallbackLock); + jassert (newSampleRate > 0); - const ScopedLock sl (midiCallbackLock); #if JUCE_DEBUG hasCalledReset = true; #endif @@ -47,6 +48,8 @@ void MidiMessageCollector::reset (const double newSampleRate) void MidiMessageCollector::addMessageToQueue (const MidiMessage& message) { + const ScopedLock sl (midiCallbackLock); + #if JUCE_DEBUG jassert (hasCalledReset); // you need to call reset() to set the correct sample rate before using this object #endif @@ -55,8 +58,6 @@ void MidiMessageCollector::addMessageToQueue (const MidiMessage& message) // for details of what the number should be. jassert (message.getTimeStamp() != 0); - const ScopedLock sl (midiCallbackLock); - auto sampleNumber = (int) ((message.getTimeStamp() - 0.001 * lastCallbackTime) * sampleRate); incomingMessages.addEvent (message, sampleNumber); @@ -70,6 +71,8 @@ void MidiMessageCollector::addMessageToQueue (const MidiMessage& message) void MidiMessageCollector::removeNextBlockOfMessages (MidiBuffer& destBuffer, const int numSamples) { + const ScopedLock sl (midiCallbackLock); + #if JUCE_DEBUG jassert (hasCalledReset); // you need to call reset() to set the correct sample rate before using this object #endif @@ -79,7 +82,6 @@ void MidiMessageCollector::removeNextBlockOfMessages (MidiBuffer& destBuffer, auto timeNow = Time::getMillisecondCounterHiRes(); auto msElapsed = timeNow - lastCallbackTime; - const ScopedLock sl (midiCallbackLock); lastCallbackTime = timeNow; if (! incomingMessages.isEmpty()) @@ -88,33 +90,28 @@ void MidiMessageCollector::removeNextBlockOfMessages (MidiBuffer& destBuffer, int startSample = 0; int scale = 1 << 16; - const uint8* midiData; - int numBytes, samplePosition; - - MidiBuffer::Iterator iter (incomingMessages); - if (numSourceSamples > numSamples) { // if our list of events is longer than the buffer we're being // asked for, scale them down to squeeze them all in.. const int maxBlockLengthToUse = numSamples << 5; + auto iter = incomingMessages.cbegin(); + if (numSourceSamples > maxBlockLengthToUse) { startSample = numSourceSamples - maxBlockLengthToUse; numSourceSamples = maxBlockLengthToUse; - iter.setNextSamplePosition (startSample); + iter = incomingMessages.findNextSamplePosition (startSample); } scale = (numSamples << 10) / numSourceSamples; - while (iter.getNextEvent (midiData, numBytes, samplePosition)) + std::for_each (iter, incomingMessages.cend(), [&] (const MidiMessageMetadata& meta) { - samplePosition = ((samplePosition - startSample) * scale) >> 10; - - destBuffer.addEvent (midiData, numBytes, - jlimit (0, numSamples - 1, samplePosition)); - } + const auto pos = ((meta.samplePosition - startSample) * scale) >> 10; + destBuffer.addEvent (meta.data, meta.numBytes, jlimit (0, numSamples - 1, pos)); + }); } else { @@ -122,17 +119,20 @@ void MidiMessageCollector::removeNextBlockOfMessages (MidiBuffer& destBuffer, // towards the end of the buffer startSample = numSamples - numSourceSamples; - while (iter.getNextEvent (midiData, numBytes, samplePosition)) - { - destBuffer.addEvent (midiData, numBytes, - jlimit (0, numSamples - 1, samplePosition + startSample)); - } + for (const auto metadata : incomingMessages) + destBuffer.addEvent (metadata.data, metadata.numBytes, + jlimit (0, numSamples - 1, metadata.samplePosition + startSample)); } incomingMessages.clear(); } } +void MidiMessageCollector::ensureStorageAllocated (size_t bytes) +{ + incomingMessages.ensureSize (bytes); +} + //============================================================================== void MidiMessageCollector::handleNoteOn (MidiKeyboardState*, int midiChannel, int midiNoteNumber, float velocity) { diff --git a/JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.h b/JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.h index 17aa76f..d76323f 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.h +++ b/JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.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. @@ -28,14 +28,14 @@ namespace juce Collects incoming realtime MIDI messages and turns them into blocks suitable for processing by a block-based audio callback. - The class can also be used as either a MidiKeyboardStateListener or a MidiInputCallback + The class can also be used as either a MidiKeyboardState::Listener or a MidiInputCallback so it can easily use a midi input or keyboard component as its source. @see MidiMessage, MidiInput @tags{Audio} */ -class JUCE_API MidiMessageCollector : public MidiKeyboardStateListener, +class JUCE_API MidiMessageCollector : public MidiKeyboardState::Listener, public MidiInputCallback { public: @@ -80,6 +80,14 @@ class JUCE_API MidiMessageCollector : public MidiKeyboardStateListener, */ void removeNextBlockOfMessages (MidiBuffer& destBuffer, int numSamples); + /** Preallocates storage for collected messages. + + This can be called before audio processing begins to ensure that there + is sufficient space for the expected MIDI messages, in order to avoid + allocations within the audio callback. + */ + void ensureStorageAllocated (size_t bytes); + //============================================================================== /** @internal */ diff --git a/JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiOutput.h b/JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiOutput.h deleted file mode 100644 index fe1e38c..0000000 --- a/JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiOutput.h +++ /dev/null @@ -1,145 +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 -{ - -//============================================================================== -/** - Controls a physical MIDI output device. - - To create one of these, use the static getDevices() method to get a list of the - available output devices, then use the openDevice() method to try to open one. - - @see MidiInput - - @tags{Audio} -*/ -class JUCE_API MidiOutput final : private Thread -{ -public: - //============================================================================== - /** Returns a list of the available midi output devices. - - You can open one of the devices by passing its index into the - openDevice() method. - - @see getDefaultDeviceIndex, openDevice - */ - static StringArray getDevices(); - - /** Returns the index of the default midi output device to use. - - This refers to the index in the list returned by getDevices(). - */ - static int getDefaultDeviceIndex(); - - /** Tries to open one of the midi output devices. - - This will return a MidiOutput object if it manages to open it. You can then - send messages to this device, and delete it when no longer needed. - - If the device can't be opened, this will return a null pointer. - - @param deviceIndex the index of a device from the list returned by getDevices() - @see getDevices - */ - static MidiOutput* openDevice (int deviceIndex); - - - #if JUCE_LINUX || JUCE_MAC || JUCE_IOS || DOXYGEN - /** This will try to create a new midi output device (Not available on Windows). - - This will attempt to create a new midi output device that other apps can connect - to and use as their midi input. - - Returns nullptr if a device can't be created. - - @param deviceName the name to use for the new device - */ - static MidiOutput* createNewDevice (const String& deviceName); - #endif - - //============================================================================== - /** Destructor. */ - ~MidiOutput() override; - - /** Returns the name of this device. */ - const String& getName() const noexcept { return name; } - - /** Sends out a MIDI message immediately. */ - void sendMessageNow (const MidiMessage& message); - - /** Sends out a sequence of MIDI messages immediately. */ - void sendBlockOfMessagesNow (const MidiBuffer& buffer); - - //============================================================================== - /** This lets you supply a block of messages that will be sent out at some point - in the future. - - The MidiOutput class has an internal thread that can send out timestamped - messages - this appends a set of messages to its internal buffer, ready for - sending. - - This will only work if you've already started the thread with startBackgroundThread(). - - A time is specified, at which the block of messages should be sent. This time uses - the same time base as Time::getMillisecondCounter(), and must be in the future. - - The samplesPerSecondForBuffer parameter indicates the number of samples per second - used by the MidiBuffer. Each event in a MidiBuffer has a sample position, and the - samplesPerSecondForBuffer value is needed to convert this sample position to a - real time. - */ - void sendBlockOfMessages (const MidiBuffer& buffer, - double millisecondCounterToStartAt, - double samplesPerSecondForBuffer); - - /** Gets rid of any midi messages that had been added by sendBlockOfMessages(). */ - void clearAllPendingMessages(); - - /** Starts up a background thread so that the device can send blocks of data. - Call this to get the device ready, before using sendBlockOfMessages(). - */ - void startBackgroundThread(); - - /** Stops the background thread, and clears any pending midi events. - @see startBackgroundThread - */ - void stopBackgroundThread(); - - -private: - //============================================================================== - void* internal = nullptr; - CriticalSection lock; - struct PendingMessage; - PendingMessage* firstMessage = nullptr; - String name; - - MidiOutput (const String& midiName); // These objects are created with the openDevice() method. - void run() override; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiOutput) -}; - -} // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/java/app/com/roli/juce/JuceMidiSupport.java b/JuceLibraryCode/modules/juce_audio_devices/native/java/app/com/rmsl/juce/JuceMidiSupport.java similarity index 91% rename from JuceLibraryCode/modules/juce_audio_devices/native/java/app/com/roli/juce/JuceMidiSupport.java rename to JuceLibraryCode/modules/juce_audio_devices/native/java/app/com/rmsl/juce/JuceMidiSupport.java index 57e5f25..1ff979a 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/java/app/com/roli/juce/JuceMidiSupport.java +++ b/JuceLibraryCode/modules/juce_audio_devices/native/java/app/com/rmsl/juce/JuceMidiSupport.java @@ -1,4 +1,26 @@ -package com.roli.juce; +/* + ============================================================================== + + 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. + + ============================================================================== +*/ + +package com.rmsl.juce; import android.bluetooth.BluetoothAdapter; @@ -51,6 +73,8 @@ public interface JuceMidiPort // send will do nothing on an input port void sendMidi (byte[] msg, int offset, int count); + + String getName (); } //============================================================================== @@ -256,6 +280,12 @@ public void sendMidi (byte[] msg, int offset, int count) { } + @Override + public String getName () + { + return owner.getPortName (portPath); + } + MidiDeviceManager owner; MidiOutputPort androidPort; MidiPortPath portPath; @@ -331,6 +361,12 @@ public void close () androidPort = null; } + @Override + public String getName () + { + return owner.getPortName (portPath); + } + MidiDeviceManager owner; MidiInputPort androidPort; MidiPortPath portPath; @@ -343,7 +379,6 @@ public MidiPortPath (int deviceIdToUse, boolean direction, int androidIndex) deviceId = deviceIdToUse; isInput = direction; portIndex = androidIndex; - } public int deviceId; @@ -555,17 +590,17 @@ protected void finalize () throws Throwable super.finalize (); } - public String[] getJuceAndroidMidiInputDevices () + public String[] getJuceAndroidMidiOutputDeviceNameAndIDs () { - return getJuceAndroidMidiDevices (MidiDeviceInfo.PortInfo.TYPE_OUTPUT); + return getJuceAndroidMidiDeviceNameAndIDs (MidiDeviceInfo.PortInfo.TYPE_OUTPUT); } - public String[] getJuceAndroidMidiOutputDevices () + public String[] getJuceAndroidMidiInputDeviceNameAndIDs () { - return getJuceAndroidMidiDevices (MidiDeviceInfo.PortInfo.TYPE_INPUT); + return getJuceAndroidMidiDeviceNameAndIDs (MidiDeviceInfo.PortInfo.TYPE_INPUT); } - private String[] getJuceAndroidMidiDevices (int portType) + private String[] getJuceAndroidMidiDeviceNameAndIDs (int portType) { // only update the list when JUCE asks for a new list synchronized (MidiDeviceManager.class) @@ -573,22 +608,24 @@ private String[] getJuceAndroidMidiDevices (int portType) deviceInfos = getDeviceInfos (); } - ArrayList portNames = new ArrayList (); + ArrayList portNameAndIDs = new ArrayList (); - int index = 0; - for (MidiPortPath portInfo = getPortPathForJuceIndex (portType, index); portInfo != null; portInfo = getPortPathForJuceIndex (portType, ++index)) - portNames.add (getPortName (portInfo)); + for (MidiPortPath portInfo : getAllPorts (portType)) + { + portNameAndIDs.add (getPortName (portInfo)); + portNameAndIDs.add (Integer.toString (portInfo.hashCode ())); + } - String[] names = new String[portNames.size ()]; - return portNames.toArray (names); + String[] names = new String[portNameAndIDs.size ()]; + return portNameAndIDs.toArray (names); } - private JuceMidiPort openMidiPortWithJuceIndex (int index, long host, boolean isInput) + private JuceMidiPort openMidiPortWithID (int deviceID, long host, boolean isInput) { synchronized (MidiDeviceManager.class) { - int portTypeToFind = (isInput ? MidiDeviceInfo.PortInfo.TYPE_OUTPUT : MidiDeviceInfo.PortInfo.TYPE_INPUT); - MidiPortPath portInfo = getPortPathForJuceIndex (portTypeToFind, index); + int portTypeToFind = (isInput ? MidiDeviceInfo.PortInfo.TYPE_INPUT : MidiDeviceInfo.PortInfo.TYPE_OUTPUT); + MidiPortPath portInfo = getPortPathForID (portTypeToFind, deviceID); if (portInfo != null) { @@ -633,14 +670,14 @@ private JuceMidiPort openMidiPortWithJuceIndex (int index, long host, boolean is return null; } - public JuceMidiPort openMidiInputPortWithJuceIndex (int index, long host) + public JuceMidiPort openMidiInputPortWithID (int deviceID, long host) { - return openMidiPortWithJuceIndex (index, host, true); + return openMidiPortWithID (deviceID, host, true); } - public JuceMidiPort openMidiOutputPortWithJuceIndex (int index) + public JuceMidiPort openMidiOutputPortWithID (int deviceID) { - return openMidiPortWithJuceIndex (index, 0, false); + return openMidiPortWithID (deviceID, 0, false); } /* 0: unpaired, 1: paired, 2: pairing */ @@ -773,24 +810,6 @@ public void removePort (MidiPortPath path) openPorts.remove (path); } - public String getInputPortNameForJuceIndex (int index) - { - MidiPortPath portInfo = getPortPathForJuceIndex (MidiDeviceInfo.PortInfo.TYPE_OUTPUT, index); - if (portInfo != null) - return getPortName (portInfo); - - return ""; - } - - public String getOutputPortNameForJuceIndex (int index) - { - MidiPortPath portInfo = getPortPathForJuceIndex (MidiDeviceInfo.PortInfo.TYPE_INPUT, index); - if (portInfo != null) - return getPortName (portInfo); - - return ""; - } - public void onDeviceAdded (MidiDeviceInfo info) { // only add standard midi devices @@ -980,24 +999,24 @@ public String getPortName (MidiPortPath path) return ""; } - public MidiPortPath getPortPathForJuceIndex (int portType, int juceIndex) + public ArrayList getAllPorts (int portType) { - int portIdx = 0; + ArrayList ports = new ArrayList (); + for (MidiDeviceInfo info : deviceInfos) - { for (MidiDeviceInfo.PortInfo portInfo : info.getPorts ()) - { if (portInfo.getType () == portType) - { - if (portIdx == juceIndex) - return new MidiPortPath (info.getId (), - (portType == MidiDeviceInfo.PortInfo.TYPE_INPUT), - portInfo.getPortNumber ()); + ports.add (new MidiPortPath (info.getId (), (portType == MidiDeviceInfo.PortInfo.TYPE_INPUT), + portInfo.getPortNumber ())); - portIdx++; - } - } - } + return ports; + } + + public MidiPortPath getPortPathForID (int portType, int deviceID) + { + for (MidiPortPath port : getAllPorts (portType)) + if (port.hashCode () == deviceID) + return port; return null; } diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_MidiDataConcatenator.h b/JuceLibraryCode/modules/juce_audio_devices/native/juce_MidiDataConcatenator.h index 834c67c..f71de46 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_MidiDataConcatenator.h +++ b/JuceLibraryCode/modules/juce_audio_devices/native/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. @@ -116,7 +116,7 @@ class MidiDataConcatenator do { - if (pendingSysexSize > 0 && isInitialByte (*d)) + if (pendingSysexSize > 0 && isStatusByte (*d)) { if (*d == 0xf7) { @@ -172,7 +172,8 @@ class MidiDataConcatenator } static bool isRealtimeMessage (uint8 byte) { return byte >= 0xf8 && byte <= 0xfe; } - static bool isInitialByte (uint8 byte) { return byte >= 0x80 && byte != 0xf7; } + static bool isStatusByte (uint8 byte) { return byte >= 0x80; } + static bool isInitialByte (uint8 byte) { return isStatusByte (byte) && byte != 0xf7; } uint8 currentMessage[3]; int currentMessageLen = 0; diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_Audio.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_Audio.cpp index 7fc0062..53267e9 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_Audio.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_Audio.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. @@ -73,7 +73,7 @@ class AndroidAudioIODevice : public AudioIODevice, AndroidAudioIODevice (const String& deviceName) : AudioIODevice (deviceName, javaAudioTypeName), Thread ("audio"), - minBufferSizeOut (0), minBufferSizeIn (0), callback (0), sampleRate (0), + minBufferSizeOut (0), minBufferSizeIn (0), callback (nullptr), sampleRate (0), numClientInputChannels (0), numDeviceInputChannels (0), numDeviceInputChannelsAvailable (2), numClientOutputChannels (0), numDeviceOutputChannels (0), actualBufferSize (0), isRunning (false), @@ -100,7 +100,7 @@ class AndroidAudioIODevice : public AudioIODevice, << sampleRate << " Hz; input chans: " << numDeviceInputChannelsAvailable); } - ~AndroidAudioIODevice() + ~AndroidAudioIODevice() override { close(); } @@ -196,7 +196,7 @@ class AndroidAudioIODevice : public AudioIODevice, (jint) (minBufferSizeOut * numDeviceOutputChannels * static_cast (sizeof (int16))), MODE_STREAM))); const bool supportsUnderrunCount = (getAndroidSDKVersion() >= 24); - getUnderrunCount = supportsUnderrunCount ? env->GetMethodID (AudioTrack, "getUnderrunCount", "()I") : 0; + getUnderrunCount = supportsUnderrunCount ? env->GetMethodID (AudioTrack, "getUnderrunCount", "()I") : nullptr; int outputDeviceState = env->CallIntMethod (outputDevice, AudioTrack.getState); if (outputDeviceState > 0) @@ -282,11 +282,11 @@ class AndroidAudioIODevice : public AudioIODevice, BigInteger getActiveOutputChannels() const override { return activeOutputChans; } BigInteger getActiveInputChannels() const override { return activeInputChans; } String getLastError() override { return lastError; } - bool isPlaying() override { return isRunning && callback != 0; } + bool isPlaying() override { return isRunning && callback != nullptr; } int getXRunCount() const noexcept override { - if (outputDevice != nullptr && getUnderrunCount != 0) + if (outputDevice != nullptr && getUnderrunCount != nullptr) return getEnv()->CallIntMethod (outputDevice, getUnderrunCount); return -1; @@ -337,7 +337,7 @@ class AndroidAudioIODevice : public AudioIODevice, DBG ("Audio read under-run! " << numRead); } - jshort* const src = env->GetShortArrayElements (audioBuffer, 0); + jshort* const src = env->GetShortArrayElements (audioBuffer, nullptr); for (int chan = 0; chan < inputChannelBuffer.getNumChannels(); ++chan) { @@ -380,7 +380,7 @@ class AndroidAudioIODevice : public AudioIODevice, if (threadShouldExit()) break; - jshort* const dest = env->GetShortArrayElements (audioBuffer, 0); + jshort* const dest = env->GetShortArrayElements (audioBuffer, nullptr); for (int chan = 0; chan < numDeviceOutputChannels; ++chan) { @@ -417,7 +417,7 @@ class AndroidAudioIODevice : public AudioIODevice, BigInteger activeOutputChans, activeInputChans; GlobalRef outputDevice, inputDevice; AudioBuffer inputChannelBuffer, outputChannelBuffer; - jmethodID getUnderrunCount = 0; + jmethodID getUnderrunCount = nullptr; void closeDevices() { diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_HighPerformanceAudioHelpers.h b/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_HighPerformanceAudioHelpers.h new file mode 100644 index 0000000..02123a6 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_HighPerformanceAudioHelpers.h @@ -0,0 +1,131 @@ +/* + ============================================================================== + + 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 +{ + +//============================================================================== +/** + Some shared helpers methods for using the high-performance audio paths on + Android devices (OpenSL and Oboe). + + @tags{Audio} +*/ +namespace AndroidHighPerformanceAudioHelpers +{ + //============================================================================== + static double getNativeSampleRate() + { + return audioManagerGetProperty ("android.media.property.OUTPUT_SAMPLE_RATE").getDoubleValue(); + } + + static int getNativeBufferSizeHint() + { + // This property is a hint of a native buffer size but it does not guarantee the size used. + auto deviceBufferSize = audioManagerGetProperty ("android.media.property.OUTPUT_FRAMES_PER_BUFFER").getIntValue(); + + if (deviceBufferSize == 0) + return 192; + + return deviceBufferSize; + } + + static bool isProAudioDevice() + { + static bool isSapaSupported = SystemStats::getDeviceManufacturer().containsIgnoreCase ("SAMSUNG") + && DynamicLibrary().open ("libapa_jni.so"); + + return androidHasSystemFeature ("android.hardware.audio.pro") || isSapaSupported; + } + + static bool hasLowLatencyAudioPath() + { + return androidHasSystemFeature ("android.hardware.audio.low_latency"); + } + + static bool canUseHighPerformanceAudioPath (int nativeBufferSize, int requestedBufferSize, int requestedSampleRate) + { + return ((requestedBufferSize % nativeBufferSize) == 0) + && (requestedSampleRate == getNativeSampleRate()) + && isProAudioDevice(); + } + + //============================================================================== + static int getMinimumBuffersToEnqueue (int nativeBufferSize, double requestedSampleRate) + { + if (canUseHighPerformanceAudioPath (nativeBufferSize, nativeBufferSize, (int) requestedSampleRate)) + { + // see https://developer.android.com/ndk/guides/audio/opensl/opensl-prog-notes.html#sandp + // "For Android 4.2 (API level 17) and earlier, a buffer count of two or more is required + // for lower latency. Beginning with Android 4.3 (API level 18), a buffer count of one + // is sufficient for lower latency." + return (getAndroidSDKVersion() >= 18 ? 1 : 2); + } + + // not using low-latency path so we can use the absolute minimum number of buffers to queue + return 1; + } + + static int buffersToQueueForBufferDuration (int nativeBufferSize, int bufferDurationInMs, double sampleRate) noexcept + { + auto maxBufferFrames = static_cast (std::ceil (bufferDurationInMs * sampleRate / 1000.0)); + auto maxNumBuffers = static_cast (std::ceil (static_cast (maxBufferFrames) + / static_cast (nativeBufferSize))); + + return jmax (getMinimumBuffersToEnqueue (nativeBufferSize, sampleRate), maxNumBuffers); + } + + static int getMaximumBuffersToEnqueue (int nativeBufferSize, double maximumSampleRate) noexcept + { + static constexpr int maxBufferSizeMs = 200; + + return jmax (8, buffersToQueueForBufferDuration (nativeBufferSize, maxBufferSizeMs, maximumSampleRate)); + } + + static Array getAvailableBufferSizes (int nativeBufferSize, Array availableSampleRates) + { + auto minBuffersToQueue = getMinimumBuffersToEnqueue (nativeBufferSize, getNativeSampleRate()); + auto maxBuffersToQueue = getMaximumBuffersToEnqueue (nativeBufferSize, findMaximum (availableSampleRates.getRawDataPointer(), + availableSampleRates.size())); + + Array bufferSizes; + + for (int i = minBuffersToQueue; i <= maxBuffersToQueue; ++i) + bufferSizes.add (i * nativeBufferSize); + + return bufferSizes; + } + + static int getDefaultBufferSize (int nativeBufferSize, double currentSampleRate) + { + static constexpr int defaultBufferSizeForLowLatencyDeviceMs = 40; + static constexpr int defaultBufferSizeForStandardLatencyDeviceMs = 100; + + auto defaultBufferLength = (hasLowLatencyAudioPath() ? defaultBufferSizeForLowLatencyDeviceMs + : defaultBufferSizeForStandardLatencyDeviceMs); + + auto defaultBuffersToEnqueue = buffersToQueueForBufferDuration (nativeBufferSize, defaultBufferLength, currentSampleRate); + return defaultBuffersToEnqueue * nativeBufferSize; + } +} + +} // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_Midi.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_Midi.cpp index e153018..163a1d0 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_Midi.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_Midi.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,359 +24,339 @@ namespace juce { //============================================================================== -// This byte-code is generated from native/java/com/roli/juce/JuceMidiSupport.java with min sdk version 23 +// This byte-code is generated from native/java/com/rmsl/juce/JuceMidiSupport.java with min sdk version 23 // See juce_core/native/java/README.txt on how to generate this byte-code. static const uint8 javaMidiByteCode[] = -{31,139,8,8,173,175,226,91,0,3,106,117,99,101,95,97,117,100,105,111,95,100,101,118,105,99,101,115,46,100,101,120,0,149, -124,11,124,220,69,181,255,153,223,99,119,179,217,164,155,77,218,164,105,178,217,164,73,179,133,60,155,182,164,77,26,154, -164,105,155,118,251,160,217,22,105,144,186,77,182,237,150,100,55,236,110,250,0,175,148,135,180,32,42,42,143,42,92,254,40, -175,130,168,232,5,46,34,42,8,87,20,69,184,92,212,122,125,1,194,223,130,200,67,65,68,196,222,239,153,153,125,164,45,84, -203,231,187,103,126,103,206,156,153,57,115,230,204,153,223,46,25,141,238,113,183,117,44,160,7,183,254,71,91,73,96,244, -225,231,218,251,238,107,108,49,191,55,239,138,244,25,191,14,80,247,85,235,137,38,136,104,207,166,249,62,210,255,30,90,71, -116,150,80,252,1,224,25,155,104,19,232,17,7,81,0,244,117,55,209,93,76,11,137,10,64,215,151,128,223,3,121,104,216,209,76, -180,19,24,7,146,192,36,112,61,112,35,112,8,184,27,184,7,120,0,120,8,120,26,40,110,33,90,7,156,11,196,129,36,176,27,56,8, -124,23,248,30,240,3,224,151,192,107,192,123,64,105,43,209,12,160,18,168,1,234,129,83,128,22,160,3,88,4,108,1,46,5,110,7, -158,6,204,54,162,54,96,24,216,7,124,25,248,9,240,6,224,111,39,234,7,206,1,46,4,190,2,60,13,188,3,84,207,35,90,11,236,7, -238,0,126,2,188,1,56,58,136,170,128,5,192,32,240,97,32,9,252,16,120,23,104,153,79,180,21,184,10,248,13,80,191,128,232,76, -224,227,192,109,192,227,192,203,64,209,66,162,38,96,37,176,5,72,2,251,129,235,129,175,1,223,7,94,0,204,211,136,102,2,109, -192,48,144,0,46,1,14,2,119,1,15,3,63,7,142,0,127,3,90,59,137,150,2,67,192,78,224,223,128,135,128,103,128,231,129,130,69, -68,30,192,11,76,7,102,1,179,129,70,160,9,152,7,44,2,122,128,126,96,16,88,7,108,2,62,12,68,128,81,96,7,48,6,76,0,87,3,143, -0,47,1,255,0,74,23,195,55,128,38,96,1,176,24,232,7,206,0,206,1,118,2,73,224,82,224,38,224,30,224,251,192,175,128,87,129, -119,0,179,11,227,3,170,129,122,96,30,176,24,88,5,156,1,124,8,136,0,113,96,15,240,113,224,83,192,13,192,205,192,109,192, -55,128,7,128,71,129,159,0,191,6,94,6,222,1,236,110,216,0,168,2,234,129,86,96,49,176,19,72,3,215,1,247,3,223,5,158,0,126, -1,252,22,120,25,120,13,120,23,40,95,66,52,31,88,13,124,4,56,31,248,12,112,61,240,85,224,155,192,15,129,159,2,191,1,10, -176,95,188,64,121,143,218,59,61,192,89,192,94,224,11,192,189,192,19,192,207,128,183,0,227,116,162,18,224,20,96,62,208,15, -132,129,109,64,2,248,24,176,31,248,12,112,29,240,37,224,86,224,78,224,235,192,127,2,223,1,126,8,252,12,248,29,240,10,240, -22,96,44,133,31,0,51,128,90,160,21,152,15,116,3,43,129,51,128,51,129,17,96,23,112,25,240,57,224,58,224,6,224,139,192,237, -192,87,129,251,129,239,0,143,0,63,2,126,11,252,21,40,238,37,106,0,122,128,245,192,8,144,4,46,6,62,15,220,9,60,12,60,14, -28,6,94,6,172,62,34,31,16,0,130,64,15,48,4,108,1,226,192,167,128,175,1,143,3,255,11,188,8,188,6,252,13,16,253,216,87,64, -25,48,23,24,0,206,1,70,129,113,96,15,112,49,112,37,112,29,240,69,224,110,224,1,224,113,224,73,224,247,192,107,192,187, -128,107,25,246,6,112,42,48,31,232,6,250,128,21,192,102,32,1,236,1,46,6,174,0,174,2,238,2,238,3,30,3,158,1,94,0,222,0,222, -6,254,1,20,32,184,86,0,1,96,14,208,6,116,1,189,192,32,16,6,62,12,164,129,79,3,119,0,119,3,211,16,115,203,128,58,96,54,80, -15,52,0,115,128,70,32,8,204,5,78,1,78,5,154,0,132,89,66,216,36,132,65,66,184,35,132,53,66,8,35,132,41,66,104,34,132,33, -66,136,33,132,13,66,104,32,108,93,194,214,35,108,15,130,123,19,92,150,224,42,132,101,33,152,151,96,18,90,166,207,135,229, -192,10,96,37,48,8,172,2,86,3,33,96,13,176,22,88,199,231,4,112,6,176,1,24,2,194,164,206,149,15,1,155,129,179,129,115,128, -45,64,4,24,1,70,129,40,112,46,112,1,240,49,224,66,96,31,112,17,112,49,112,9,41,155,100,254,121,53,125,22,147,47,209,229, -35,40,87,130,26,250,153,203,166,46,215,232,242,179,90,198,210,252,90,93,126,93,243,93,121,242,56,2,233,239,154,95,168, -249,179,128,34,110,211,164,248,197,121,125,77,203,43,251,242,228,203,180,60,151,43,242,218,86,230,245,85,165,199,198,50, -126,45,83,163,203,204,175,209,114,30,173,167,78,203,84,235,114,89,147,146,229,114,149,110,91,159,215,182,65,183,229,126, -216,135,130,122,12,45,121,227,108,205,27,91,91,222,216,184,220,214,164,242,2,46,119,54,229,248,25,123,182,231,233,105, -207,27,63,151,151,230,149,51,242,157,121,250,217,15,87,234,126,23,107,62,251,194,18,93,30,211,101,214,57,174,203,235,81, -142,235,242,135,80,78,232,242,104,147,202,105,184,156,70,121,183,46,127,20,229,243,116,249,0,202,73,93,190,10,229,73,93, -190,1,229,93,186,124,75,94,249,238,60,157,15,230,149,61,121,229,71,243,202,63,206,235,247,153,60,254,179,121,229,35,121, -253,190,158,199,255,107,94,91,222,208,123,50,125,53,231,228,43,80,222,171,203,129,230,92,219,165,121,122,218,242,244,119, -230,143,225,212,92,185,169,57,215,215,124,148,211,25,61,40,159,175,203,43,155,115,182,90,143,114,74,151,207,110,86,123, -181,71,175,209,71,117,153,215,232,223,116,57,157,87,110,203,43,103,124,160,87,183,229,114,95,158,63,244,231,249,195,50, -205,159,165,203,150,244,243,54,186,143,20,93,42,184,205,52,250,132,108,219,78,159,146,244,52,250,140,164,46,234,17,236, -183,21,116,5,219,10,189,191,36,169,160,87,37,109,160,217,178,126,14,53,11,142,5,101,82,174,86,243,107,53,127,182,126,102, -122,134,224,125,101,209,181,196,212,75,127,145,84,213,215,235,250,6,61,158,6,68,219,107,36,237,163,59,37,45,167,55,37, -157,79,239,232,122,191,80,52,32,212,190,60,68,76,123,232,15,164,158,231,10,142,247,53,116,21,49,109,160,183,137,227,155, -139,190,39,169,73,143,74,106,211,255,18,199,55,39,221,40,105,29,61,168,233,255,176,205,112,82,220,160,233,87,37,181,232, -191,36,93,67,11,161,223,6,223,73,28,251,86,208,42,193,116,1,173,21,156,247,43,190,59,75,221,116,157,164,5,180,28,245,30, -173,167,72,215,23,129,115,157,164,133,180,76,40,58,32,56,46,22,209,119,137,105,45,253,146,56,118,171,241,120,17,61,127, -44,233,52,154,41,152,122,169,90,112,60,87,227,230,184,254,51,77,127,69,42,166,254,72,210,51,232,176,164,37,244,11,205, -231,250,50,173,183,12,167,83,47,244,76,215,227,42,199,105,244,152,164,173,84,46,152,46,162,10,73,187,105,158,164,93,180, -73,112,108,86,237,43,224,225,255,174,41,219,107,166,214,83,137,241,127,139,56,134,250,232,126,226,216,107,208,45,210,15, -151,201,250,26,172,163,162,130,30,150,180,129,126,40,105,152,254,91,210,229,100,74,127,61,133,74,37,61,149,202,36,93,79, -115,36,29,164,213,146,14,208,70,233,151,167,75,125,1,61,46,166,255,33,105,51,253,90,210,16,189,162,249,211,164,252,106, -154,46,233,42,234,23,138,63,168,233,26,233,207,61,82,95,173,214,87,171,245,213,106,61,181,186,93,173,110,87,171,219,213, -105,249,58,45,87,167,229,234,180,92,157,150,155,77,75,165,254,217,200,58,44,249,220,65,182,166,14,73,219,201,41,233,124, -114,105,90,160,249,94,77,75,36,109,35,159,166,51,228,190,234,149,122,235,209,255,231,37,173,163,135,36,117,208,15,72,157, -115,143,75,58,151,186,244,126,114,202,253,165,230,215,0,143,184,71,210,153,116,175,164,106,125,26,224,23,223,151,116,54, -61,33,233,70,250,137,164,97,122,82,211,167,36,45,165,167,181,220,51,146,214,211,79,37,157,69,63,151,180,147,220,178,223, -211,168,80,83,143,80,252,34,73,23,83,177,80,251,191,82,210,25,52,75,210,10,170,146,116,45,213,75,218,66,13,66,197,139, -249,146,14,80,88,198,133,38,57,159,57,200,176,190,166,227,194,111,101,60,152,11,11,40,234,148,116,58,125,91,210,74,250, -14,241,121,126,138,228,183,106,249,86,120,236,135,4,159,219,74,190,77,219,167,13,30,253,8,241,249,172,244,183,195,206,47, -19,231,141,253,82,174,3,30,206,126,63,95,183,155,15,185,253,250,249,122,253,252,255,36,157,67,127,212,207,29,66,229,156, -43,37,29,162,33,193,249,103,35,93,73,156,131,42,61,11,117,251,133,144,191,73,210,26,217,207,66,100,183,127,146,52,64,237, -66,241,89,223,105,186,221,105,186,255,211,116,63,167,233,126,78,211,253,116,98,252,191,33,166,200,136,4,231,23,106,92, -139,53,237,210,122,186,144,205,158,46,56,247,85,207,221,218,191,248,12,2,91,190,247,32,185,255,113,94,115,162,141,36,247, -189,53,42,199,18,142,92,142,196,245,46,156,105,11,215,170,231,128,110,207,252,167,78,85,180,2,116,173,174,175,213,245, -109,121,245,109,160,151,233,250,217,90,175,157,167,127,37,234,191,170,235,235,53,191,59,175,254,67,168,127,81,215,55,104, -253,211,129,195,90,255,14,80,207,58,85,63,71,183,203,31,255,221,168,63,160,235,27,243,198,151,169,127,8,245,55,233,122, -206,175,127,129,196,255,217,144,146,251,131,166,127,11,229,234,10,215,228,202,229,107,84,125,93,30,239,84,93,94,8,186,36, -175,188,114,141,202,211,89,102,8,229,115,116,219,152,166,231,107,250,9,77,111,210,244,94,77,127,156,215,199,111,53,239, -101,169,211,144,229,111,14,168,187,195,132,183,8,207,117,240,153,9,47,251,238,176,215,66,84,31,246,26,52,236,51,112,46, -177,60,235,121,124,64,229,254,97,212,156,231,189,148,248,212,139,7,118,96,141,221,50,223,183,180,220,127,15,168,123,193, -121,178,23,143,136,7,12,236,35,200,122,109,249,204,113,205,68,29,203,254,102,64,157,105,225,128,69,225,90,11,50,95,66, -141,91,204,46,89,6,221,55,99,124,30,248,224,50,41,99,203,83,30,119,121,180,153,1,154,244,222,134,62,61,34,233,189,133, -219,24,157,70,17,120,183,162,204,109,60,228,243,197,219,22,193,131,130,175,23,235,145,17,189,51,160,236,192,119,21,135, -156,25,158,151,171,187,160,175,100,94,153,77,190,218,142,178,18,140,163,4,253,121,176,111,10,41,220,206,227,226,155,145, -199,136,7,110,130,207,250,122,59,202,106,16,191,166,83,165,177,147,206,11,180,131,151,107,225,59,166,197,23,101,173,165, -109,209,141,8,90,44,231,194,125,7,150,171,187,74,190,173,122,161,101,17,250,85,250,191,161,245,251,196,52,17,110,87,150, -23,82,242,124,105,169,224,91,110,104,98,237,109,208,117,38,207,163,220,231,208,250,160,199,77,149,22,244,216,69,82,79,24, -125,199,229,133,209,35,22,137,76,157,71,215,5,255,212,89,176,128,234,12,55,60,129,109,86,105,89,232,175,141,173,108,197, -3,94,196,226,58,179,8,117,62,88,46,30,40,67,6,204,252,233,184,181,122,44,95,3,151,194,52,59,189,20,61,76,67,107,143,189, -198,182,28,231,121,175,83,237,189,165,104,229,177,227,75,11,169,247,227,193,111,199,3,30,220,104,131,223,164,172,127,141, -46,87,247,204,169,254,245,111,240,175,98,228,97,14,57,163,241,229,234,110,57,225,109,65,155,225,217,5,52,92,239,160,225, -6,55,109,158,227,130,229,207,14,56,229,218,218,210,191,4,93,180,92,197,16,159,25,238,117,80,167,112,18,211,184,247,84, -212,133,123,11,192,41,144,52,220,231,70,95,31,133,157,135,251,161,179,223,1,45,69,122,5,124,122,5,130,71,84,28,98,221,66, -52,227,248,18,114,76,215,162,15,142,153,113,126,193,69,9,239,229,218,191,212,46,35,186,113,185,218,135,62,88,69,104,222, -45,203,115,126,88,140,185,241,93,251,206,229,106,223,44,41,244,208,208,69,46,114,238,115,126,78,220,34,238,181,190,191, -203,181,84,203,90,250,182,254,64,94,123,67,239,165,239,47,87,113,46,236,45,80,94,232,197,140,33,177,209,235,148,126,192, -207,241,64,19,246,148,207,123,182,215,57,165,237,147,31,208,182,51,219,182,153,219,82,166,45,143,133,199,112,88,175,219, -132,247,0,71,15,225,161,97,163,144,134,225,41,197,217,117,56,146,183,14,133,122,29,10,97,177,217,114,29,60,122,29,60,88, -135,162,236,58,64,79,127,225,191,176,14,239,101,215,97,229,9,215,193,94,161,215,1,30,228,212,163,47,4,175,148,231,221, -174,71,5,26,95,138,44,43,154,235,183,79,232,126,223,86,239,71,116,191,238,204,90,214,173,200,173,69,134,23,204,227,153, -50,218,17,181,172,80,239,84,134,197,52,216,138,45,54,108,20,203,248,170,222,204,44,206,107,147,89,231,101,39,224,173,95, -145,31,195,44,57,167,179,87,168,56,234,11,116,216,211,176,190,241,64,1,180,134,3,188,219,93,188,239,16,47,46,144,183,140, -156,158,115,79,160,123,247,9,120,151,156,128,247,233,99,230,199,255,174,63,1,239,214,60,158,45,45,71,244,181,21,188,179, -217,14,165,176,195,157,210,14,56,111,204,18,26,182,120,132,150,180,162,73,15,173,80,239,100,170,140,122,170,54,124,98, -184,221,135,85,253,50,106,224,143,237,94,172,215,52,73,227,240,71,161,75,28,37,88,210,139,231,18,72,184,37,141,123,43,52, -191,132,252,6,238,96,194,111,52,138,34,17,124,155,103,51,19,117,53,114,124,166,204,23,28,210,103,231,94,216,220,52,87, -151,13,250,245,10,149,59,86,153,24,139,25,222,0,221,198,108,98,26,247,206,228,88,39,226,222,58,121,10,249,230,119,244, -205,0,183,150,163,180,81,105,125,22,254,220,138,200,201,103,146,137,189,228,202,158,12,126,179,4,168,196,242,5,255,94, -132,82,163,161,206,251,57,104,217,172,125,73,32,223,205,248,239,187,43,84,125,216,235,149,107,109,104,111,19,43,51,231, -178,26,141,140,155,94,245,214,78,157,203,106,15,58,87,242,253,14,115,16,152,131,8,183,249,56,39,167,112,27,230,130,252, -142,159,195,243,160,33,144,70,196,245,11,246,127,191,104,36,213,103,169,236,171,12,251,70,157,193,190,149,234,125,166, -207,154,240,54,192,114,195,225,50,26,222,84,6,139,148,81,165,249,22,180,148,227,230,227,49,106,140,114,26,222,80,14,62, -110,154,56,87,42,13,236,40,115,187,220,201,243,176,214,117,198,66,248,192,65,142,229,27,102,226,105,62,158,62,45,159,42, -166,212,85,78,121,154,46,245,197,189,115,216,242,84,107,250,140,5,243,220,124,15,199,105,155,68,28,59,108,24,88,91,41, -211,54,151,54,88,193,31,187,244,25,115,250,74,149,43,134,71,42,208,254,115,188,51,44,206,31,44,114,155,157,102,155,204, -31,44,57,110,63,133,17,176,106,76,175,180,169,153,91,97,211,183,160,99,232,247,71,245,10,155,149,182,90,225,161,236,10, -255,226,168,94,97,51,30,248,4,206,72,214,252,228,209,18,195,103,4,255,225,200,156,117,43,213,187,234,112,95,37,244,223, -192,243,48,146,222,219,53,189,5,148,91,205,146,227,49,164,230,86,10,247,67,54,112,189,28,75,13,214,48,238,253,136,28,1, -247,50,36,229,95,56,90,34,124,34,248,15,142,51,202,123,46,92,169,222,123,87,217,13,84,109,135,211,60,235,107,120,182,214, -236,190,62,142,243,105,101,7,204,217,33,100,38,229,64,93,167,53,67,246,236,128,246,26,211,79,135,17,239,194,184,194,212, -88,202,26,124,158,175,177,12,33,68,240,247,126,187,196,40,178,252,118,163,197,126,209,34,123,109,37,151,244,19,131,238, -91,169,238,62,170,255,9,111,140,117,90,195,163,51,200,111,215,153,106,181,77,140,35,222,118,30,237,194,220,59,141,82,204, -113,2,123,128,51,139,171,112,235,58,12,7,207,212,6,223,80,61,241,28,76,158,67,47,103,137,215,194,59,61,86,141,133,44,81, -142,129,163,65,67,118,255,240,205,88,237,148,63,106,155,87,25,24,139,17,238,85,51,103,11,242,188,161,79,116,138,10,57, -111,83,90,220,47,111,156,53,66,205,89,230,92,222,26,153,115,117,156,113,228,168,223,224,88,226,163,224,123,42,154,168, -125,210,40,123,10,18,231,130,220,175,99,16,209,141,251,116,163,79,119,167,183,140,124,115,121,54,55,20,121,176,94,107,41, -252,240,76,204,224,11,200,143,185,119,39,44,225,119,151,144,111,102,240,213,13,237,179,104,34,16,199,125,212,227,236,116, -46,162,240,46,140,197,129,168,231,232,128,84,39,124,113,67,123,53,218,206,66,46,204,118,43,64,6,31,32,231,195,214,11,187, -28,242,77,39,191,107,129,246,58,171,3,122,62,137,53,139,183,253,59,181,91,126,119,240,41,140,216,221,40,84,251,74,110, -239,234,116,189,116,180,14,103,220,196,210,21,244,80,103,240,121,191,27,51,123,144,228,157,186,31,51,226,239,56,84,246, -178,66,250,22,123,241,126,204,141,223,253,249,28,225,20,118,90,224,20,248,122,149,133,121,90,225,212,116,216,236,243,124, -2,165,148,127,155,210,202,183,203,12,144,173,109,75,127,45,151,214,182,165,63,183,42,89,248,119,169,244,58,246,239,45, -144,15,190,84,100,250,173,70,211,103,14,163,222,15,221,51,143,213,152,183,131,43,243,118,240,28,146,178,208,56,91,106, -236,64,187,79,201,118,53,102,29,228,214,178,246,223,13,239,154,9,185,19,69,131,186,140,46,229,11,166,160,78,68,3,166,53, -166,37,79,29,51,239,201,33,159,50,17,163,130,117,255,82,233,253,12,202,156,141,112,214,196,247,232,185,176,223,124,82, -119,32,129,155,165,186,11,24,244,237,65,229,159,190,64,149,128,21,225,109,87,242,72,140,69,70,0,43,184,13,235,192,235, -140,27,138,215,207,39,223,188,233,210,115,250,228,205,199,137,88,29,252,139,138,216,19,129,237,90,214,98,238,31,252,194, -39,115,38,142,73,179,208,99,128,248,62,207,125,87,203,236,129,253,246,233,65,149,87,251,106,217,59,125,38,223,99,156,114, -39,26,242,198,198,239,106,130,239,229,242,197,231,7,149,111,248,2,19,129,115,229,141,171,36,91,119,36,83,231,205,213,101, -250,121,53,211,79,201,7,247,227,211,54,249,7,228,183,18,199,179,18,218,232,170,162,78,215,90,220,111,212,110,114,33,159, -9,23,206,160,218,7,125,46,113,249,130,31,174,194,9,80,88,224,51,244,46,117,113,155,13,69,179,168,227,240,34,172,2,191, -233,246,20,213,254,198,231,90,112,164,157,150,91,69,174,184,215,207,246,117,116,236,154,131,250,106,185,234,178,205,180, -106,234,248,115,21,120,85,188,250,54,175,3,252,21,123,164,56,115,174,187,42,11,222,147,81,255,32,234,107,236,118,222,181, -182,175,49,120,207,97,151,75,4,159,58,236,42,16,226,242,224,127,250,221,149,72,84,131,127,46,114,97,191,185,56,227,219, -128,214,31,201,198,166,45,176,133,41,215,37,182,74,125,247,232,43,245,89,62,17,126,12,179,218,35,150,47,184,108,30,45,39, -167,131,71,143,243,164,160,246,11,98,96,193,173,245,180,220,40,176,121,244,56,37,10,59,126,57,147,58,158,155,78,117,246, -156,204,169,239,232,88,82,40,103,132,122,107,98,233,199,40,218,239,28,42,49,69,127,240,47,135,17,179,15,219,182,8,254, -250,176,141,128,191,41,248,164,207,12,254,89,221,221,121,28,95,90,165,214,135,207,58,206,179,124,237,29,94,19,126,27,198, -121,238,19,241,165,65,106,243,5,223,225,247,202,134,204,151,238,130,252,77,28,223,138,176,34,69,105,49,147,119,175,139, -199,225,194,56,124,78,95,1,223,202,194,158,74,220,232,246,115,236,47,102,159,125,133,220,158,69,158,115,100,47,144,243, -248,122,58,94,105,67,212,99,235,186,200,227,169,44,86,103,234,43,210,186,56,83,109,117,131,70,164,176,148,62,229,251,33, -180,237,244,116,83,142,119,61,120,30,103,141,211,202,227,221,8,94,93,97,189,228,184,176,23,92,56,99,38,206,60,135,10,107, -143,27,27,34,228,43,133,117,197,93,56,151,14,97,214,157,5,109,84,234,121,202,121,209,67,182,151,243,67,236,236,165,119, -208,119,188,254,162,226,204,120,60,172,131,119,231,67,228,113,119,186,225,145,119,33,211,122,168,6,214,116,34,110,187, -100,156,112,202,248,224,164,52,206,151,82,242,23,5,159,43,242,248,139,26,61,165,158,81,10,62,93,228,9,190,205,123,99,18, -30,193,223,101,85,235,239,84,84,222,118,80,92,216,124,163,56,40,56,199,51,100,94,221,182,90,125,231,85,229,132,205,157, -124,54,185,113,122,179,205,113,118,27,225,107,213,124,12,94,7,216,232,50,172,67,167,3,209,245,90,196,162,192,103,233,54, -60,47,114,52,208,84,185,235,33,231,113,212,56,56,234,70,228,185,63,181,254,70,212,179,134,58,151,159,38,218,230,209,33, -147,79,231,203,200,239,44,38,61,2,139,87,143,243,136,74,151,90,189,203,100,92,199,234,137,42,105,45,33,243,82,73,29,108, -177,24,86,183,211,134,111,13,169,24,218,105,186,116,84,85,209,148,163,168,155,130,79,22,57,130,79,20,57,252,206,70,135, -58,99,199,97,247,9,29,63,119,203,189,132,8,122,97,115,122,23,114,132,66,25,53,4,237,131,141,62,204,54,194,76,171,165,109, -220,228,182,249,60,61,75,190,163,89,147,141,213,97,129,222,133,69,190,50,223,244,14,36,57,62,43,124,141,58,97,108,121,86, -221,174,169,60,179,176,162,175,30,213,103,150,60,97,54,52,206,34,173,221,213,177,255,213,163,178,45,172,217,32,61,87,157, -56,182,44,171,19,7,209,187,44,248,227,78,225,210,183,22,117,99,9,95,195,107,115,53,106,253,14,228,221,182,223,209,104, -171,185,158,37,227,196,230,236,251,171,71,86,79,189,251,241,61,248,71,171,179,241,118,253,94,154,23,246,200,236,195,144, -117,63,93,173,238,156,252,190,204,103,76,108,216,75,253,94,174,47,144,251,29,247,154,213,234,183,12,136,59,6,175,141,75, -174,17,191,153,230,44,208,164,105,134,58,209,249,61,159,19,22,236,180,113,210,88,193,183,112,95,177,26,141,112,114,58, -233,86,182,207,193,187,103,131,35,156,44,3,111,134,204,100,125,211,235,28,179,225,47,67,180,203,25,95,138,19,49,234,65, -150,131,21,207,107,39,91,9,191,37,230,5,31,231,59,234,126,10,254,77,189,151,116,99,166,252,93,231,169,210,6,21,217,24, -229,8,169,123,126,38,38,53,34,38,169,59,167,178,210,180,144,178,71,216,59,83,238,126,126,127,164,252,194,162,138,144,250, -189,5,207,209,45,119,6,71,55,181,147,194,215,170,168,114,155,228,227,206,114,173,138,40,183,201,181,134,127,26,106,213, -12,185,106,134,174,191,17,245,124,226,222,33,189,25,153,172,119,43,123,138,204,94,236,236,46,163,236,46,98,207,135,44, -172,11,223,235,159,114,195,112,196,3,147,216,21,42,123,240,59,131,247,40,175,47,18,149,14,220,154,92,165,242,214,116,25, -113,188,230,179,100,25,172,178,86,223,181,207,208,241,226,76,157,255,26,52,116,97,243,166,161,236,59,154,177,80,254,59, -154,179,196,44,58,219,168,162,179,204,106,249,246,73,221,48,63,26,82,239,203,125,98,17,98,238,52,228,31,87,200,76,138,41, -124,216,236,152,247,246,81,231,250,26,228,230,27,250,170,105,3,218,118,204,123,245,232,198,190,42,218,104,86,161,124,228, -232,134,190,89,224,227,196,157,247,252,81,95,73,240,183,153,247,112,68,159,12,169,239,10,234,112,55,216,208,59,139,158, -246,237,3,173,166,82,115,31,45,104,47,149,229,187,107,39,2,31,231,24,235,189,140,87,223,216,216,139,243,30,59,197,247, -198,55,106,167,137,82,113,33,5,95,131,214,191,169,219,48,209,23,245,58,251,96,179,26,192,143,185,100,222,5,29,10,169,124, -71,205,183,88,199,82,131,190,18,210,239,161,68,238,13,169,73,37,66,191,19,69,206,244,238,209,42,163,17,247,131,173,194, -79,139,4,178,106,81,131,53,235,64,134,30,3,199,47,249,193,35,153,156,191,68,234,16,250,123,12,33,179,43,83,247,245,88,72, -125,127,82,73,234,62,108,200,222,44,249,93,109,21,242,180,106,177,21,245,139,136,51,247,6,244,49,138,182,60,19,191,228,7, -95,205,220,191,139,116,31,213,217,62,170,228,111,79,229,221,95,219,130,231,250,81,159,250,254,231,82,208,43,179,191,110, -85,255,14,234,231,140,60,255,182,233,22,240,238,58,134,63,168,249,247,31,211,254,209,99,158,159,242,169,62,51,191,41,226, -119,135,207,250,212,111,122,94,247,169,239,73,254,234,83,191,91,56,226,83,191,105,98,189,219,88,184,84,253,94,5,14,77, -222,210,169,122,171,142,121,150,223,149,104,58,67,83,254,237,140,33,105,187,236,127,26,245,200,88,199,117,85,121,115,17, -164,114,25,67,63,153,154,246,80,238,119,81,153,239,118,12,73,219,228,243,28,205,239,207,202,121,116,91,245,11,15,213,215, -233,217,246,66,219,65,97,134,140,89,220,46,99,159,204,239,171,20,207,161,121,14,201,83,101,103,86,87,129,166,94,77,125, -90,198,167,245,10,101,62,202,124,167,101,72,58,139,50,223,177,177,44,127,199,59,71,247,203,223,171,206,209,123,176,1,255, -89,154,122,117,92,88,164,219,44,210,119,19,150,235,214,123,168,71,215,157,174,199,111,101,203,114,214,65,50,131,131,184, -203,204,165,250,182,142,190,206,182,129,5,189,205,3,203,6,58,155,231,247,117,116,52,247,158,182,160,189,121,97,255,64, -199,252,129,254,249,253,167,181,193,180,200,211,186,71,198,98,241,88,186,135,28,221,138,26,61,93,100,245,116,205,221,196, -159,40,123,251,198,38,163,233,68,34,189,99,77,36,30,217,30,77,210,226,99,57,129,104,50,153,72,46,14,140,36,38,199,70,3, -241,68,58,176,61,154,14,100,165,2,161,129,64,106,36,18,143,163,237,233,255,92,219,209,232,182,200,228,88,190,142,200,104, -100,34,13,5,149,203,38,199,199,247,102,249,43,34,233,116,127,100,108,108,107,100,4,23,155,65,50,6,67,100,14,134,66,84,51, -184,46,48,176,103,36,58,145,142,37,226,129,221,59,98,99,209,192,200,88,34,21,139,111,15,76,36,146,105,106,24,92,247,126, -245,227,177,209,24,134,176,43,54,18,37,177,138,172,85,27,251,7,168,100,213,228,72,116,13,106,6,227,19,147,233,245,172, -194,151,97,173,155,76,103,120,158,12,79,62,149,101,158,134,38,39,184,215,150,157,145,93,17,18,33,50,66,131,100,134,6,229, -7,122,192,7,50,10,12,219,12,225,195,10,133,54,135,168,62,20,137,143,38,19,177,209,214,173,153,217,182,102,231,221,171, -204,209,69,179,63,72,106,153,156,67,23,213,126,144,16,155,176,139,230,158,76,36,99,229,46,106,61,169,232,142,72,50,50, -130,225,197,82,233,216,72,23,157,122,178,6,203,162,169,145,100,108,34,157,72,158,120,32,99,209,156,124,40,58,164,124,233, -196,115,135,40,215,231,70,251,62,250,88,104,121,108,12,131,172,239,155,140,141,141,178,190,19,153,105,138,232,7,138,108, -136,166,224,178,39,158,173,22,25,138,166,211,112,176,84,174,203,15,152,66,70,184,139,102,102,133,70,18,241,116,52,158, -110,237,103,186,7,157,213,100,171,198,163,163,177,72,43,187,110,43,59,92,102,233,155,62,88,96,48,190,45,81,207,174,202, -133,252,225,188,175,116,23,53,124,176,208,80,58,146,158,196,168,235,222,79,44,187,129,242,93,233,24,25,29,29,234,149,202, -220,106,158,118,178,6,235,226,170,201,186,137,104,60,58,26,130,7,70,165,175,4,78,210,240,3,230,158,219,221,249,235,127, -140,208,134,232,72,52,182,139,245,148,102,69,18,169,214,190,201,248,232,24,150,161,44,159,185,50,194,76,136,150,231,115, -215,71,146,35,209,177,141,147,177,209,46,242,101,43,38,211,177,177,214,80,98,251,113,188,245,145,88,50,175,175,44,175, -139,54,30,207,236,62,137,155,156,52,62,224,32,104,11,141,36,198,91,147,137,177,88,235,78,68,181,214,99,66,91,253,177,145, -189,139,218,79,210,226,184,136,218,69,243,254,201,38,249,107,210,244,79,182,81,210,161,147,72,231,172,146,245,193,247,61, -113,186,104,217,191,172,45,199,97,23,13,71,82,231,158,220,80,199,105,57,249,164,51,19,94,31,73,239,224,48,241,129,210, -188,89,71,35,99,187,98,231,182,34,180,38,176,129,113,40,182,14,196,245,129,216,63,22,73,97,67,251,79,32,51,200,145,88, -215,215,158,160,126,77,116,124,171,22,136,66,164,250,4,34,67,177,237,113,68,140,36,118,73,229,9,170,195,59,146,137,221, -104,58,61,196,103,103,107,44,209,154,119,112,119,81,137,98,143,69,226,219,91,245,56,74,243,88,131,136,147,210,94,190,60, -230,186,173,59,163,35,233,169,188,161,116,18,51,205,118,35,121,178,235,200,86,222,191,85,121,236,100,116,91,235,153,209, -200,185,27,162,219,162,201,104,28,73,66,245,7,213,242,230,151,213,114,55,246,38,147,145,189,28,150,50,61,77,229,242,121, -117,2,118,247,241,35,237,201,142,63,39,154,154,202,91,25,73,97,51,78,100,12,146,207,59,94,16,199,205,113,130,224,77,29, -253,32,14,193,136,60,166,167,229,113,229,116,188,199,48,186,168,227,24,78,247,73,207,206,158,169,122,101,247,37,121,140, -112,108,156,215,114,250,177,44,181,139,74,142,219,38,212,123,28,235,196,249,102,222,65,16,72,237,197,153,49,30,72,69,147, -50,1,244,29,191,97,201,147,191,187,168,33,255,180,110,233,239,13,133,250,122,251,87,111,9,159,181,126,96,203,154,222,112, -255,202,45,161,117,67,97,18,155,200,216,132,132,111,19,82,84,107,211,224,230,65,114,108,90,133,20,112,21,216,72,252,54, -33,35,180,54,113,74,104,111,146,92,112,228,7,75,135,84,37,202,54,127,174,82,4,105,228,166,205,36,144,57,66,153,129,148, -209,24,238,163,186,225,147,103,49,205,195,255,82,86,80,255,79,136,99,219,13,159,96,139,77,97,102,246,88,97,100,100,36, -154,74,45,31,139,108,79,145,27,153,226,100,100,76,166,203,206,76,150,111,70,70,71,249,105,52,9,57,242,232,222,7,227,163, -209,61,104,173,158,100,11,119,100,98,66,39,67,228,136,164,148,39,110,61,38,75,166,202,44,39,52,32,195,158,90,219,141,27, -7,151,145,111,235,113,153,101,158,134,140,35,149,229,56,217,105,167,242,228,182,232,235,66,193,214,116,175,30,181,107, -107,90,201,65,76,151,82,124,22,195,4,228,216,154,230,115,132,236,173,156,8,146,103,68,31,40,225,189,19,81,114,96,20,200, -4,168,120,100,74,30,77,246,200,88,52,146,100,146,72,69,201,137,92,48,14,27,83,161,46,72,133,46,206,16,35,177,120,74,178, -101,105,117,116,175,20,150,54,242,232,66,56,177,17,58,108,236,130,120,154,196,40,185,71,179,41,56,57,244,92,92,138,194, -70,153,210,40,21,101,74,74,65,225,104,214,1,82,153,186,140,201,220,234,81,230,41,5,163,177,36,134,136,136,13,118,44,149, -25,186,35,122,30,150,62,69,5,114,83,246,39,70,97,192,104,38,182,83,203,182,8,110,101,163,129,116,34,48,146,140,70,210, -209,192,214,201,49,125,29,84,186,3,219,146,137,241,64,198,77,92,219,98,241,200,88,236,252,40,213,162,52,154,91,168,229, -137,100,222,197,73,9,215,176,72,102,67,159,72,192,222,22,75,194,153,60,219,96,162,209,204,130,187,185,67,229,198,100,109, -103,131,23,240,167,50,134,137,72,66,110,124,100,84,84,114,89,57,235,113,151,232,89,185,186,227,195,214,116,174,156,152, -24,139,141,200,51,48,227,224,165,96,31,55,206,138,124,102,126,6,46,181,28,127,109,34,23,216,242,164,164,18,148,150,169, -155,118,102,167,20,72,150,92,254,226,108,81,45,175,59,251,156,34,39,202,210,223,230,162,176,114,114,156,35,56,246,46,142, -74,101,156,19,26,20,162,240,37,73,70,165,6,214,75,85,178,160,147,185,181,145,113,94,45,78,79,212,102,159,137,90,126,58, -206,84,41,242,31,95,37,245,100,234,107,142,175,87,89,99,70,128,117,51,247,216,145,162,106,134,174,90,150,117,97,140,74, -143,154,199,72,213,40,228,114,208,227,134,93,136,234,76,5,21,101,30,38,57,23,162,114,253,200,103,199,148,70,46,93,145,82, -45,146,137,137,104,50,29,195,104,166,225,113,67,116,60,145,142,102,2,10,24,67,242,152,210,145,76,14,76,6,143,162,29,242, -114,161,175,35,228,220,17,73,173,101,223,113,161,176,67,238,48,107,71,2,126,93,192,159,202,111,69,140,204,216,232,30,178, -99,114,24,86,140,151,197,142,201,69,47,136,101,223,118,20,198,82,89,75,241,67,191,218,196,81,88,37,150,26,24,159,72,239, -229,130,92,2,174,206,189,38,113,197,116,214,64,46,78,62,87,202,238,119,102,167,237,217,153,255,198,196,60,23,225,202,129, -15,206,71,220,99,9,68,70,37,230,28,215,155,195,226,211,135,220,227,217,229,161,146,241,227,118,80,241,248,148,213,163, -194,241,60,207,49,198,199,201,28,79,109,199,71,122,146,172,56,47,146,205,159,136,33,241,232,110,222,62,48,83,156,205,102, -38,182,238,36,71,98,219,182,20,134,227,75,196,251,34,233,145,29,185,140,37,69,229,216,158,83,194,52,158,226,219,97,148, -178,99,43,120,135,208,244,99,185,103,38,97,29,169,69,153,19,219,93,246,175,212,144,55,17,207,189,28,145,26,74,242,57,170, -117,81,66,95,122,225,192,232,185,56,49,229,14,204,125,230,63,47,139,142,69,246,130,61,45,195,102,215,218,149,47,167,226, -71,102,34,206,68,124,249,216,100,106,7,121,18,241,53,233,201,12,27,35,227,241,40,191,220,144,74,197,168,130,57,99,49,142, -2,114,92,253,137,241,9,196,107,200,162,165,76,63,100,60,207,60,41,11,194,184,200,157,226,210,94,218,153,83,203,248,132, -192,93,26,178,165,216,4,241,99,194,27,185,153,169,203,69,92,206,249,154,159,31,167,220,41,207,140,165,119,228,246,88,77, -166,62,183,121,167,10,204,204,8,28,95,85,204,85,121,175,250,10,248,89,109,88,87,34,147,26,22,100,74,8,120,24,49,159,131, -137,92,19,59,177,155,67,112,233,4,124,242,216,89,85,158,128,57,148,142,78,132,119,39,168,124,74,93,46,50,145,53,193,25, -168,147,47,113,131,216,194,5,178,160,162,201,132,206,223,84,73,70,162,130,76,41,165,152,50,125,45,202,148,84,52,144,21, -50,148,20,103,74,225,196,114,132,6,50,121,103,207,72,70,183,243,75,149,228,212,55,51,228,72,74,47,34,183,162,42,98,168, -178,202,212,102,38,113,216,71,83,233,156,159,175,79,198,18,240,147,189,220,86,186,130,51,169,55,21,24,233,93,145,49,178, -146,236,87,102,114,50,78,37,169,108,254,170,95,158,81,105,42,47,239,206,48,157,153,55,205,174,212,200,142,232,40,18,6, -114,164,162,72,56,70,201,74,177,159,85,242,167,122,197,187,35,50,26,24,92,23,200,101,28,46,174,99,235,210,52,236,247,254, -252,164,172,16,12,246,218,53,28,66,139,249,65,231,144,147,177,81,84,238,224,235,4,246,13,38,106,165,56,5,177,83,242,161, -64,18,110,72,69,170,152,78,76,200,71,71,74,157,210,86,10,28,244,156,225,23,192,105,50,139,155,222,17,131,49,248,179,190, -13,21,184,234,160,209,248,4,57,211,9,121,223,163,233,147,241,19,185,210,204,99,216,121,14,83,49,25,127,159,21,180,97,241, -73,156,24,146,172,219,70,93,226,102,225,44,54,222,160,174,61,198,167,47,236,106,166,144,184,28,12,90,46,201,126,147,174, -17,22,255,191,111,197,116,171,16,100,89,223,52,22,143,56,139,143,154,116,191,81,180,217,38,186,92,136,175,179,252,39,133, -241,121,113,191,225,44,62,55,100,210,237,194,106,62,104,211,146,61,33,7,181,92,123,62,196,118,75,117,7,164,186,150,61,1, -58,67,252,192,112,54,65,244,83,194,108,49,252,187,141,109,213,33,83,92,37,10,90,174,104,217,108,26,223,54,10,175,219,108, -154,223,49,138,87,111,94,242,200,224,122,219,176,77,186,84,72,37,215,210,189,194,122,87,92,38,190,102,60,143,199,238,102, -252,235,166,223,10,114,86,135,182,172,222,219,220,108,236,170,246,155,244,13,209,66,15,129,89,220,221,77,143,49,165,183, -229,231,27,194,250,187,184,196,184,69,252,15,6,219,124,43,253,93,152,234,25,117,79,176,196,35,155,151,208,207,50,133,3, -134,169,186,82,29,209,125,198,9,186,249,140,161,186,57,200,148,14,25,89,133,107,182,24,23,84,215,40,161,27,101,229,205, -242,243,77,195,160,119,81,223,220,221,76,151,154,198,3,226,122,238,253,98,211,228,210,19,232,139,46,201,43,191,107,160, -252,132,177,15,229,37,171,175,163,143,115,213,109,170,234,178,188,242,229,92,126,79,149,15,112,249,91,134,44,239,231,14, -100,233,162,108,233,179,166,69,119,137,219,197,183,208,239,102,158,215,245,38,198,181,164,27,11,242,128,113,122,104,243, -112,207,218,115,122,154,109,50,246,118,57,136,30,144,149,161,152,41,254,191,40,221,251,136,92,196,230,115,108,178,197, -172,154,69,244,35,174,165,39,229,231,79,165,228,254,61,254,42,250,157,201,158,85,109,220,96,117,25,47,94,208,212,252,104, -200,40,222,13,155,237,217,179,103,111,12,238,35,250,149,190,197,61,182,160,95,216,114,105,133,207,107,25,111,139,154,222, -253,249,93,61,198,61,217,6,189,164,133,102,120,77,58,36,218,32,115,147,209,112,136,43,233,57,39,247,123,192,52,126,47, -250,177,40,47,8,33,156,54,153,2,133,71,44,147,53,10,195,22,14,18,133,54,57,68,141,109,54,75,141,119,88,226,110,182,106, -172,102,216,50,191,98,44,216,140,182,47,162,173,101,26,95,54,26,155,119,25,23,236,134,122,248,94,191,131,28,134,195,196, -136,143,138,1,122,205,41,238,192,64,150,8,223,52,139,88,249,115,1,155,102,213,156,66,15,88,230,139,226,57,241,10,87,118, -155,5,95,55,68,200,52,161,169,117,191,209,208,100,132,171,109,211,46,88,224,48,29,5,59,45,231,87,208,174,101,181,233,184, -93,148,180,192,69,222,16,179,91,118,154,198,205,198,204,102,12,149,70,108,3,91,231,182,118,116,111,218,14,219,105,156, -135,133,64,75,135,195,185,211,116,29,17,211,165,148,48,29,100,120,170,33,4,17,219,85,67,239,194,254,213,195,75,134,197, -140,105,166,128,141,254,203,22,139,187,107,248,201,248,147,104,132,121,109,163,133,141,140,29,90,211,27,218,115,254,229, -54,13,119,211,95,45,54,108,245,146,157,177,133,198,158,234,253,237,157,177,150,26,250,155,45,94,100,239,48,137,77,17,162, -27,45,233,191,242,243,18,199,212,186,59,156,226,16,236,184,215,116,98,202,75,238,149,139,231,55,141,55,133,184,237,54, -211,250,178,225,195,60,239,54,4,166,107,222,105,136,157,171,77,251,46,99,94,76,184,109,187,197,97,55,240,82,96,150,150, -109,219,14,99,164,218,118,46,112,8,88,219,226,201,26,23,116,161,194,97,148,175,98,41,246,54,167,113,183,241,186,112,54, -249,77,113,135,33,16,81,208,215,109,188,94,190,157,205,7,62,201,203,37,4,175,150,177,187,186,214,216,221,180,200,54,12, -239,42,68,160,79,58,48,42,103,241,5,85,244,176,67,60,37,247,146,233,66,91,12,237,144,16,126,211,249,128,176,107,204,130, -151,196,233,207,239,245,63,98,218,28,168,86,155,214,213,98,222,109,194,101,59,155,49,150,234,221,60,200,123,204,66,248, -221,189,162,196,107,23,250,141,209,106,12,212,190,213,114,191,195,235,185,179,165,251,244,165,182,123,161,154,12,175,137, -93,176,136,231,225,112,57,10,28,133,198,100,151,93,200,242,244,174,30,3,92,22,189,63,122,224,40,111,88,251,90,163,230,22, -219,244,35,24,162,103,140,237,17,83,168,97,16,134,177,223,178,101,31,33,135,217,210,221,39,29,195,14,181,74,227,89,116, -141,154,221,146,3,22,105,199,130,215,151,172,49,133,156,149,117,159,113,250,18,63,111,28,118,131,3,162,100,154,191,14, -158,208,221,51,140,230,176,188,191,10,6,122,208,161,98,195,31,45,131,157,24,165,63,89,114,153,233,74,27,195,112,54,169, -97,24,51,118,24,227,213,75,98,70,113,19,166,115,171,240,122,101,39,45,215,183,204,164,67,82,176,56,70,111,217,210,33,54, -211,87,212,158,53,130,59,140,225,234,37,7,100,44,178,209,241,217,182,1,47,128,29,121,114,176,64,55,142,139,213,150,245, -78,110,236,231,247,217,38,124,28,134,132,15,192,243,97,181,26,83,112,36,125,194,48,239,20,95,21,87,168,224,223,66,207,27, -226,98,195,89,221,49,243,190,102,147,190,100,52,210,47,57,200,98,115,154,244,59,209,246,13,155,186,17,195,110,118,97,103, -52,211,28,118,223,207,186,196,151,224,239,8,118,251,133,105,120,154,224,42,231,46,89,189,7,222,117,169,172,41,222,223,96, -156,95,173,56,70,80,252,220,168,104,52,230,26,151,10,171,224,61,81,94,104,156,10,78,149,85,254,225,114,187,124,168,220, -165,30,237,114,81,254,17,48,154,202,11,164,104,125,129,3,178,21,185,102,51,140,38,150,19,21,243,114,188,114,165,188,65, -113,12,112,138,115,197,29,57,185,109,198,41,220,214,168,168,175,152,157,233,110,88,246,94,159,235,159,25,103,148,47,207, -48,156,229,103,130,209,3,180,65,202,157,97,178,212,202,242,141,248,92,150,97,186,48,244,161,114,51,43,171,21,56,202,141, -60,150,28,139,27,99,137,169,177,56,42,26,42,230,84,212,86,4,42,106,42,234,68,185,37,76,81,96,86,26,248,39,140,142,125, -251,172,91,230,204,23,207,204,17,226,239,192,161,70,33,126,5,28,12,10,113,23,112,104,174,16,111,2,247,240,143,174,237, -181,23,185,72,28,3,108,98,151,67,255,230,70,208,146,139,246,89,135,79,53,47,54,168,71,28,104,18,214,43,77,134,184,178,89, -136,155,128,123,128,103,129,55,129,187,91,16,241,29,133,234,215,242,104,243,74,203,74,113,85,171,176,222,108,21,226,234, -54,244,11,188,2,236,107,39,67,184,139,13,113,85,96,8,98,87,183,135,197,61,237,66,252,0,248,21,240,58,112,203,60,33,238,7, -126,12,60,11,188,9,28,232,32,75,216,94,76,80,112,211,115,208,244,134,142,45,226,209,14,33,158,154,47,196,51,11,160,29, -184,122,33,57,157,165,101,74,76,255,55,10,217,103,23,26,198,193,78,97,220,180,200,48,14,44,6,186,76,227,234,238,66,227, -192,146,168,245,66,143,41,238,233,53,196,221,125,134,120,182,15,86,3,61,216,143,33,1,119,15,96,40,203,133,56,2,252,106, -16,163,15,9,113,120,13,250,2,14,172,53,196,161,181,224,175,67,27,224,224,122,88,192,152,37,248,223,199,208,231,85,27,46, -20,247,108,16,226,170,33,254,13,158,223,45,220,23,137,3,251,172,23,134,4,42,247,133,69,193,65,224,210,141,148,251,251,69, -249,191,225,201,252,109,62,254,109,74,230,239,243,241,239,82,50,127,163,143,127,151,18,32,245,119,250,248,183,57,153,191, -213,231,160,220,223,235,51,189,234,183,52,242,119,83,1,245,183,154,234,75,33,19,80,50,252,255,180,11,175,250,253,61,255, -127,232,70,64,245,203,127,223,207,212,242,252,255,75,91,1,245,187,27,254,127,170,237,128,26,31,255,127,240,164,245,200, -31,228,121,21,159,255,174,224,255,1,51,160,178,16,144,80,0,0}; +{31,139,8,8,43,113,161,94,0,3,106,97,118,97,77,105,100,105,66,121,116,101,67,111,100,101,46,100,101,120,0,149,124,11,124,220, +69,181,255,153,223,99,119,179,217,36,155,77,218,164,105,178,217,164,73,179,165,205,171,233,35,109,146,182,121,180,77,218,164,45, +201,182,72,195,5,183,201,182,217,146,236,134,236,166,180,114,189,20,244,210,162,168,40,80,65,177,162,2,242,18,81,65,80,17,81, +80,81,81,122,149,63,214,39,138,112,69,69,64,20,17,229,218,255,247,204,204,110,126,109,3,213,246,243,221,51,191,51,103,206,204, +156,57,115,230,204,111,183,29,141,237,247,54,181,44,167,234,195,55,252,236,231,159,31,184,160,244,71,71,143,188,248,212,248, +199,142,188,62,189,243,225,179,11,151,53,157,77,52,73,68,251,119,44,11,144,254,243,246,109,68,231,10,197,95,15,60,105,19,157,3, +250,188,139,40,4,250,134,151,232,179,76,115,137,114,64,211,133,68,55,174,33,186,22,26,254,86,79,244,119,224,255,0,163,129,200, +6,22,3,13,64,43,176,14,232,1,54,1,219,128,93,192,81,224,105,224,31,192,63,1,163,145,200,13,132,129,173,192,32,240,54,224,66, +224,82,224,125,192,167,128,91,129,59,128,207,2,247,2,95,6,30,2,30,1,190,3,188,4,20,55,17,173,4,118,1,215,0,15,3,127,0,252,205, +68,109,192,249,192,101,192,221,192,143,128,23,129,130,165,68,29,192,46,224,74,224,51,192,47,129,146,22,162,85,192,249,192,101, +192,17,224,46,224,155,192,79,128,63,2,198,50,216,14,120,47,240,16,240,10,16,90,78,148,0,238,5,126,11,204,89,65,180,2,216,9,188, +3,248,24,240,32,112,28,120,9,48,86,162,47,96,49,176,22,216,1,164,129,107,128,219,129,135,1,187,149,168,9,232,1,222,6,76,0,151, +1,71,128,187,128,175,2,79,0,214,42,244,7,132,129,181,192,32,112,29,112,59,112,63,240,75,224,215,192,115,192,239,129,151,129,191, +1,111,0,98,53,214,1,200,7,138,128,82,32,8,212,0,139,129,165,192,10,96,21,208,1,116,2,235,129,56,112,61,240,16,240,35,224,121, +224,85,64,180,17,121,129,2,160,20,88,8,180,0,107,129,141,192,185,192,52,112,37,240,81,224,115,192,35,192,15,128,227,192,239, +129,87,128,215,1,119,59,244,0,149,192,66,160,30,88,1,116,3,3,192,78,96,4,184,8,216,15,92,2,28,2,62,0,220,0,124,10,248,60,240,53, +224,7,192,79,129,231,128,63,1,175,3,86,7,244,3,107,129,62,96,28,120,31,112,45,240,73,224,110,224,94,224,107,192,163,192,49,224, +23,192,235,192,92,236,133,122,160,11,56,15,72,1,239,4,174,6,62,10,220,9,220,15,60,12,252,1,120,5,120,29,48,214,98,46,192,86, +224,0,112,45,112,23,112,31,240,13,224,127,128,223,0,127,4,222,0,242,214,97,254,64,24,88,9,172,3,54,1,219,128,97,224,124,96,4, +136,3,147,192,37,192,97,224,58,224,40,240,105,224,94,224,33,224,49,224,41,224,103,192,111,128,151,128,191,1,255,4,188,157,68, +21,64,61,176,26,88,3,116,3,189,192,22,96,59,112,1,16,3,246,2,83,192,21,192,199,129,251,128,199,129,231,128,215,0,111,23,209,60, +96,17,176,14,56,27,24,3,46,2,46,5,62,8,220,9,124,9,248,54,240,4,240,28,240,119,192,213,13,95,6,26,128,94,224,60,96,28,184,24, +184,12,184,10,184,6,248,56,112,43,240,21,224,199,192,203,192,95,129,55,0,119,15,81,33,48,31,88,12,44,7,122,128,45,192,249,64, +12,216,11,92,14,188,7,56,2,124,10,120,8,248,22,240,4,240,99,224,23,192,51,192,171,128,23,65,178,8,168,0,106,129,197,192,70,224, +108,96,23,144,4,46,5,174,2,62,4,220,0,220,12,124,1,248,10,240,117,224,123,192,83,192,207,129,103,129,151,128,191,1,198,6,216, +11,88,6,108,1,182,3,5,136,185,197,64,53,176,0,168,1,106,129,133,64,29,16,6,22,1,103,1,139,129,37,0,194,49,33,180,18,66,34,33, +252,17,194,28,33,164,17,66,22,33,68,17,194,18,33,244,16,66,11,33,108,16,182,63,97,203,18,182,26,97,59,16,220,154,224,114,132, +37,36,44,5,193,148,212,163,207,7,12,137,54,2,189,64,31,176,9,216,12,244,3,3,192,22,96,43,128,99,133,112,220,208,32,48,4,68,128, +29,192,219,128,97,224,63,128,11,248,252,1,118,1,163,64,12,216,13,140,3,255,9,92,10,28,4,46,3,46,7,222,5,188,155,148,77,50,127, +252,154,78,98,226,133,186,188,31,229,50,80,67,63,115,217,212,229,74,93,158,212,50,150,230,87,233,242,65,205,247,56,228,113,4, +210,85,154,159,171,249,243,129,60,224,90,205,207,119,244,85,224,40,7,28,242,197,90,158,203,165,142,182,101,142,190,202,245,216, +88,38,168,101,42,117,121,82,151,25,55,106,153,106,45,83,161,203,55,47,81,178,92,190,75,203,215,56,218,214,234,182,220,15,251, +208,3,122,12,13,142,113,54,58,198,214,228,24,27,151,31,94,162,242,2,46,63,182,100,134,159,177,103,179,67,79,179,99,252,92,62, +230,40,103,230,184,204,209,87,171,163,47,246,201,227,154,191,90,243,217,47,58,116,121,66,151,185,109,66,151,127,133,114,82,151, +159,95,162,114,26,46,255,5,229,139,116,217,194,230,216,175,203,62,148,167,116,185,20,229,148,46,135,80,222,167,203,75,80,190, +88,151,151,57,202,235,234,103,116,246,59,202,55,58,250,138,56,248,231,57,250,29,117,240,39,29,229,253,142,126,15,58,248,135,29, +109,175,70,249,64,166,47,135,252,109,40,191,67,151,239,113,180,61,230,24,15,175,93,70,254,49,7,127,210,81,126,208,209,215,163, +40,79,103,244,160,124,137,46,31,119,216,234,87,40,167,117,249,133,122,181,111,215,232,53,122,167,46,243,26,253,151,46,179,253, +51,229,135,29,252,140,255,116,234,182,92,238,114,248,67,183,195,31,122,52,127,190,46,95,43,125,190,137,238,39,69,215,10,110, +83,64,87,201,182,205,244,1,73,87,210,135,36,245,80,135,96,31,46,165,247,242,90,163,247,231,37,21,244,71,73,107,169,74,214,47,164, +197,130,227,66,177,148,171,210,252,42,205,95,160,159,153,110,19,188,199,44,250,48,49,245,211,95,36,85,245,53,186,190,86,143,167, +22,145,247,136,164,93,116,167,164,37,244,138,164,203,232,53,93,95,46,20,13,10,181,71,111,39,166,107,232,247,164,227,190,224, +216,95,73,31,228,50,36,95,37,142,117,30,122,84,82,147,190,37,169,77,63,37,142,117,110,250,184,164,213,244,85,77,159,228,117, +192,137,241,49,77,63,43,169,69,223,150,116,11,45,135,126,27,124,55,113,28,236,165,62,193,116,5,13,8,190,3,40,190,55,75,189,116, +189,164,57,180,30,245,62,173,39,79,215,231,129,115,189,164,185,212,45,20,237,17,28,35,243,232,235,196,180,138,126,70,28,199, +213,120,252,136,164,63,144,180,128,74,4,83,63,205,23,28,219,213,184,57,198,63,165,233,207,73,197,215,239,75,58,72,199,37,45,164, +159,104,62,215,23,107,189,197,56,165,214,65,207,28,61,174,18,156,74,223,145,180,137,230,8,166,171,105,174,164,29,212,44,105, +59,237,16,28,167,85,251,82,216,255,168,166,108,175,121,90,79,25,198,255,32,113,60,13,208,151,136,227,176,65,183,72,63,92,47,235, +217,239,20,21,244,136,164,181,244,61,73,183,211,15,37,221,72,66,250,235,98,42,148,116,9,5,36,61,155,106,36,221,68,155,36,221, +64,219,165,95,174,147,250,66,122,92,76,239,149,84,217,39,132,72,254,11,73,7,232,15,186,62,79,182,235,167,34,73,55,83,151,80,252, +94,77,251,165,95,175,149,122,171,180,222,42,173,183,74,235,173,210,250,170,116,251,42,221,190,74,183,175,214,237,170,181,124, +181,150,175,214,242,213,90,190,90,203,47,192,78,231,254,22,32,43,49,228,243,50,50,53,181,36,93,74,182,164,203,201,165,169,91, +243,243,53,45,144,180,153,252,154,22,203,253,214,37,245,214,160,255,143,72,90,77,223,144,212,69,223,37,117,22,62,46,233,89, +180,90,238,51,181,62,181,122,190,181,240,148,251,36,157,71,95,148,116,33,61,36,169,90,191,90,248,205,99,146,238,160,39,36,221,78, +199,52,253,31,73,139,232,71,146,214,208,255,147,116,62,253,88,210,85,228,145,253,181,82,142,166,94,161,248,185,146,182,145,79, +168,120,80,42,233,92,154,39,105,41,149,73,186,149,170,37,109,164,5,146,118,83,139,164,27,40,34,227,68,189,156,199,66,100,94, +247,232,56,241,180,140,15,103,97,230,138,186,37,157,67,95,147,180,140,30,38,62,235,23,75,126,163,150,135,118,26,18,76,43,232, +109,130,207,118,213,174,73,219,167,9,158,254,77,226,51,92,245,211,12,59,255,142,56,183,236,145,114,45,240,124,222,15,203,116, +187,101,144,59,172,159,111,212,207,55,73,90,71,47,232,231,165,66,229,1,27,37,141,208,160,224,28,53,76,239,35,206,83,149,158, +21,186,253,10,200,127,66,210,74,217,207,10,100,191,47,75,26,162,38,161,248,172,111,165,110,183,82,247,191,82,247,179,82,247,179, +82,247,211,138,241,255,146,152,6,233,159,196,121,135,26,215,106,77,219,180,158,54,100,187,107,4,231,199,234,185,93,251,23,159, +77,96,203,119,35,36,227,2,206,50,36,226,55,32,17,62,178,69,229,97,194,53,147,71,113,253,213,168,127,98,139,122,14,233,246,204, +127,251,18,69,111,66,253,31,116,125,149,174,111,114,212,63,128,250,186,173,170,126,129,214,107,59,244,31,67,253,144,174,175,209, +252,118,71,253,175,80,255,30,93,95,171,245,207,1,198,180,254,151,81,255,57,93,191,80,183,115,142,127,29,228,22,109,83,207, +117,142,241,101,234,183,161,190,91,215,115,14,30,197,197,96,108,64,201,165,52,189,124,96,166,238,26,71,249,227,186,254,14,7, +239,11,186,252,16,232,55,29,229,99,3,42,151,103,153,159,1,255,171,219,254,73,83,99,139,162,69,154,134,53,237,208,52,162,105,108, +203,76,95,251,53,239,93,91,88,183,33,203,231,111,80,247,140,73,127,30,158,171,225,59,147,254,79,226,121,216,111,33,234,15,251, +13,26,14,24,56,183,88,158,245,36,55,168,123,66,4,53,23,249,175,32,62,21,19,161,113,172,181,87,222,13,44,45,183,111,131,186,67, +92,36,123,241,137,68,200,192,126,130,172,223,150,207,124,30,152,168,99,217,119,109,80,103,94,36,100,81,164,202,130,204,45,168, +241,138,5,184,224,38,66,183,98,124,62,248,98,143,148,177,101,22,128,188,17,109,230,130,78,249,111,71,159,62,49,229,255,52,183, +49,90,141,60,240,110,67,153,219,248,40,16,72,52,173,130,39,133,95,206,215,35,35,58,186,65,217,129,239,53,46,57,51,220,179,55, +168,123,99,160,112,105,177,77,129,170,150,226,66,140,163,16,253,249,176,127,114,41,210,204,227,226,91,148,207,72,132,62,5,223, +13,116,182,20,87,34,126,205,161,50,227,66,186,40,212,12,222,76,139,192,41,45,110,150,181,150,182,69,59,34,105,190,156,11,247, +253,205,13,234,94,227,180,85,39,180,32,122,106,253,95,208,250,3,162,64,68,154,149,229,133,148,252,79,105,169,240,171,94,104,98, +237,79,109,80,239,56,3,37,1,151,214,7,61,94,42,179,160,199,206,147,122,34,232,59,33,47,151,62,177,74,100,234,124,186,46,252, +74,107,206,114,170,54,188,240,4,182,89,153,101,161,191,38,182,178,149,8,249,113,6,85,155,121,168,11,192,114,137,80,49,178,101, +230,207,193,45,215,103,5,106,185,20,161,5,233,117,232,161,0,173,125,246,128,109,185,46,242,127,68,181,247,23,161,149,207,78, +172,203,165,206,255,14,127,53,17,242,225,6,28,254,18,101,253,203,187,81,221,73,79,246,175,75,225,95,249,200,211,92,202,231,55, +170,123,232,164,191,1,109,134,23,228,208,112,141,139,134,107,189,180,115,161,7,150,63,47,228,150,107,107,75,255,18,84,183,81, +197,146,128,25,233,116,81,171,112,19,211,132,127,49,234,34,157,57,224,228,72,26,233,242,162,175,255,130,157,135,187,161,179,219, +5,45,121,122,5,2,122,5,194,207,171,120,196,186,133,168,199,241,37,228,152,218,209,7,199,206,132,159,51,254,164,255,42,237,95, +25,31,239,217,168,226,104,36,132,126,170,184,159,41,233,215,133,50,142,8,233,151,155,54,170,189,26,128,229,132,230,109,219,56, +227,171,249,152,63,223,221,119,108,84,123,171,35,215,71,67,151,121,200,125,208,125,141,184,89,220,103,125,107,159,167,83,203, +90,250,246,191,219,209,222,208,99,153,218,168,98,98,196,159,163,60,213,15,171,64,98,187,223,45,125,133,159,19,161,37,24,95,192, +127,158,223,125,82,219,75,222,162,109,107,182,109,61,183,165,76,91,30,11,143,225,221,122,109,39,253,124,235,24,22,62,26,54,114, +105,24,222,148,159,93,171,107,29,107,149,171,215,42,23,86,93,32,215,202,167,215,202,135,181,202,203,174,21,244,116,231,254, +27,107,117,123,118,173,250,102,93,171,207,101,215,10,253,84,229,205,186,86,247,103,214,10,158,232,214,51,252,42,120,69,220, +174,89,143,28,52,177,174,134,58,99,51,99,235,20,122,108,175,169,119,50,122,108,222,204,122,63,233,88,175,12,239,167,14,158,41,71, +137,115,110,163,122,143,51,44,10,96,79,182,234,176,145,47,227,180,122,27,244,130,163,77,198,23,254,58,11,207,232,117,198,66, +75,206,41,191,87,197,227,64,168,197,46,128,15,36,224,179,38,172,193,81,195,195,251,23,113,231,157,242,54,51,163,167,162,247,116, +221,139,102,225,45,159,133,215,217,123,242,252,248,207,192,44,188,115,28,60,91,90,14,231,90,47,71,8,182,67,17,236,240,25,105, +7,156,91,102,33,13,91,60,66,75,90,209,164,169,94,245,30,168,220,168,161,10,35,32,134,155,3,88,249,187,81,3,159,109,246,99,189, +10,36,77,192,103,133,46,113,180,97,73,63,158,11,33,225,149,52,225,47,213,252,66,10,26,184,235,137,160,81,39,242,68,248,53,158, +205,60,212,85,202,241,153,50,255,112,73,159,90,116,105,253,146,69,186,108,208,7,122,85,78,90,110,98,44,102,100,16,186,141,5, +196,52,225,159,199,49,83,36,252,213,242,52,11,44,107,233,154,11,110,21,71,123,163,204,186,6,190,216,136,8,204,103,155,137,253, +230,201,158,48,65,179,16,40,195,242,133,223,200,67,169,206,80,249,195,66,180,172,215,190,36,112,255,202,248,239,103,122,85,125, +196,239,207,250,53,215,124,161,55,115,190,171,209,200,248,235,87,111,10,213,249,174,246,233,151,122,249,30,137,57,8,204,65,68, +154,2,24,77,30,69,154,10,249,14,64,252,28,89,10,13,161,125,136,220,65,193,254,31,20,117,164,250,44,146,125,21,99,223,168,179, +252,209,94,245,14,53,96,77,250,107,97,185,225,72,49,13,239,40,134,69,138,169,204,252,51,180,148,224,70,228,51,42,141,18,26,30, +44,1,191,132,86,225,124,42,51,176,163,204,49,185,219,113,115,194,153,181,2,62,240,81,62,19,6,231,225,105,25,158,62,36,159,74, +79,170,43,59,233,105,142,212,151,240,47,100,203,83,149,25,48,150,47,245,210,6,76,51,17,74,35,214,29,55,12,172,173,148,105,90, +68,131,86,248,113,143,62,171,254,212,171,114,207,200,72,41,218,31,225,157,97,113,30,98,145,215,108,53,155,100,30,98,201,113,7, +41,130,160,86,105,250,165,77,205,153,21,54,3,203,91,134,126,123,66,175,176,89,102,171,21,30,202,174,240,79,78,232,21,54,19,161, +247,227,172,101,205,79,156,40,52,2,70,248,159,46,61,142,185,125,234,253,120,164,171,12,250,63,206,243,48,166,252,119,104,250, +105,80,110,53,95,142,199,144,154,27,41,210,13,217,208,81,57,150,74,172,97,194,63,34,71,192,189,12,73,249,103,79,20,138,128,8, +255,147,227,140,242,158,230,62,245,174,189,220,174,165,10,59,146,230,89,95,207,179,181,22,116,117,241,89,144,86,118,192,156,93, +66,102,100,46,212,181,90,115,101,207,46,104,175,52,131,116,28,241,46,130,43,81,165,165,172,193,121,193,128,101,8,33,194,191,13, +218,133,70,158,21,180,235,44,246,139,6,217,107,163,244,19,254,59,214,167,222,209,151,91,232,31,190,50,193,185,150,57,60,52, +151,130,214,204,106,39,66,23,82,140,103,162,86,196,228,113,152,114,28,65,57,14,53,227,133,50,170,207,145,185,203,53,216,81,9, +255,229,188,30,214,69,254,43,117,166,195,220,240,51,121,102,208,170,51,121,158,108,197,5,77,156,145,222,192,86,196,92,144,145, +154,60,78,142,24,43,179,123,108,5,185,244,110,186,70,175,75,185,129,241,26,145,78,101,29,49,51,38,209,42,74,51,99,194,170,4, +229,109,183,82,40,187,200,252,206,95,41,243,187,150,179,159,63,17,52,56,222,4,40,252,127,42,226,168,189,84,39,123,10,19,231,157, +220,239,93,125,234,59,136,114,47,250,244,182,250,139,41,48,47,209,148,162,27,243,124,88,211,45,20,249,250,60,204,224,99,200, +197,185,119,55,86,45,232,45,164,192,162,240,139,131,205,243,105,50,116,17,238,192,62,119,171,123,21,69,246,97,44,46,68,70,87,11, +164,90,225,175,131,205,21,104,59,31,121,183,15,121,118,14,110,11,33,114,127,221,122,118,159,139,223,144,182,98,6,172,189,218, +106,129,158,171,97,197,68,211,77,212,108,5,189,225,99,24,177,183,78,168,246,101,220,222,211,234,249,221,137,106,156,131,147,235, +122,233,225,214,240,51,65,47,102,246,32,201,251,124,55,102,196,223,189,168,44,104,163,244,63,94,255,122,48,249,253,98,192,21, +73,97,55,134,206,194,126,80,190,16,73,205,129,205,110,228,83,42,165,246,128,90,249,59,100,182,201,214,182,165,79,151,72,107,219, +210,3,26,149,44,246,64,145,92,77,222,3,187,32,31,254,157,90,243,128,57,140,250,32,116,207,59,85,163,99,151,151,57,118,249,66, +146,178,208,184,64,106,108,65,187,15,202,118,149,102,53,228,182,177,246,223,12,239,155,7,185,217,34,70,117,70,151,242,5,83,80, +43,34,6,211,74,211,146,39,147,233,120,114,201,167,76,84,41,101,221,63,83,122,175,69,153,179,26,206,190,56,143,89,4,251,45,211, +249,141,192,109,182,64,223,21,70,54,169,247,211,51,123,39,242,212,92,170,218,19,48,197,242,229,211,45,216,107,46,59,225,15,113, +244,241,84,93,9,238,178,229,215,214,32,50,122,144,199,7,101,244,106,249,205,92,170,246,46,204,156,16,185,129,162,150,53,240, +166,162,132,191,130,235,125,147,235,14,210,151,31,225,189,244,73,58,110,90,66,44,11,63,29,48,195,127,58,110,218,66,44,15,255,160, +208,176,245,222,190,114,147,218,43,129,80,185,192,138,194,243,63,192,86,49,86,25,33,120,83,28,62,193,62,135,155,153,63,200,39, +245,210,57,210,139,187,228,141,207,141,179,37,252,87,117,194,76,134,246,106,89,139,185,127,8,138,128,204,3,121,190,243,49,38, +158,77,142,180,67,69,54,167,61,186,73,249,93,192,63,25,74,200,155,99,97,182,238,230,76,93,104,166,46,160,199,124,199,38,245,253, +158,7,188,237,158,114,106,245,108,193,189,75,237,60,15,242,163,72,46,172,249,96,192,35,174,92,254,157,77,176,91,110,78,192, +208,59,218,195,109,6,243,230,83,203,241,85,196,54,134,230,188,170,95,6,60,203,159,111,166,13,86,158,135,45,140,249,187,90,246, +177,117,43,164,135,200,54,5,21,212,242,231,114,240,202,217,83,108,182,19,124,27,251,41,63,147,39,120,202,114,254,33,79,145,235, +81,95,105,55,243,14,183,3,117,225,123,143,123,60,34,124,236,184,39,71,136,43,195,247,7,189,101,72,142,195,127,206,243,96,111, +122,56,131,28,68,235,183,103,227,216,5,217,187,241,156,205,234,59,56,142,172,221,50,42,201,40,230,184,115,23,56,238,220,11,101, +44,133,55,24,45,131,47,159,96,107,241,25,98,105,159,59,107,179,186,187,241,249,199,185,87,160,185,197,111,194,79,35,56,227,3, +34,177,46,76,77,129,240,235,252,78,219,144,57,212,50,200,223,196,241,44,15,86,205,75,139,121,188,91,61,108,69,15,172,19,112,7, +114,248,198,23,241,149,225,182,248,30,62,99,242,217,47,94,128,239,173,242,157,47,123,129,156,47,176,166,229,133,38,142,132,176, +144,135,124,190,178,124,117,206,190,32,45,132,115,214,86,183,115,68,6,75,233,83,254,213,143,182,173,190,118,154,225,29,5,207, +231,174,116,91,14,222,39,192,171,206,173,145,28,15,252,205,99,32,23,61,39,74,185,85,167,141,13,17,241,133,220,234,252,54,236, +183,59,49,235,214,156,38,42,242,29,115,95,246,176,237,231,156,17,59,121,221,93,244,144,63,152,151,159,25,143,143,117,240,14,120, +152,124,222,86,47,188,234,46,65,238,135,43,97,77,55,226,180,71,198,5,183,140,7,110,74,227,60,41,162,96,94,248,215,121,190,96, +94,157,175,200,55,74,225,31,230,249,194,175,241,89,49,141,21,226,239,215,216,155,142,100,115,185,235,197,165,245,71,197,245,130, +243,62,67,230,218,15,108,86,223,195,149,187,97,115,55,159,69,94,156,232,108,115,156,231,70,228,136,154,143,193,235,0,27,93,129, +117,104,117,33,154,30,65,236,9,93,71,183,226,121,149,171,150,78,150,59,10,57,159,171,210,197,81,118,84,230,2,39,215,127,2,245, +172,161,218,19,164,201,166,165,116,155,201,81,227,10,10,186,243,73,143,192,226,213,227,220,162,204,163,86,239,10,25,199,177,122, +162,92,90,75,200,92,85,82,23,91,44,142,213,109,181,225,91,67,42,102,182,154,30,29,69,85,244,228,168,233,165,240,19,121,174, +240,247,243,92,65,119,157,75,157,169,156,87,76,234,120,121,177,220,15,136,82,151,214,167,247,209,62,105,35,142,13,158,126,245, +61,127,57,102,90,33,109,227,37,175,205,231,231,185,242,253,207,64,54,54,71,4,122,23,22,5,138,3,115,90,144,248,4,172,200,117, +234,68,177,229,217,116,135,166,242,140,194,138,190,120,66,159,81,242,68,25,172,155,79,90,187,167,229,208,139,39,100,91,88,179, +86,122,174,58,97,108,89,86,39,12,34,100,113,248,241,86,225,209,55,25,117,139,137,92,199,107,243,97,212,6,93,200,197,237,160, +171,206,86,115,61,87,238,245,157,217,119,99,155,251,79,190,15,242,253,121,168,63,27,31,183,93,66,75,35,62,153,109,24,178,238, +63,250,213,61,148,223,197,5,140,201,193,75,168,219,207,245,57,114,191,27,20,235,87,191,169,8,20,113,236,227,93,195,107,196,223, +90,114,70,102,82,129,161,78,112,126,135,232,134,5,91,109,68,115,43,252,42,238,48,86,157,17,153,154,67,186,149,29,112,241,238, +25,116,69,166,138,193,155,43,179,219,192,156,106,215,2,248,203,14,218,231,78,172,195,9,24,243,33,171,193,138,59,218,201,86,34, +104,137,165,225,239,242,189,245,16,133,255,174,222,121,122,49,83,254,158,117,177,180,65,105,54,70,189,191,95,189,31,200,196, +164,58,196,36,117,15,85,86,250,176,182,71,196,63,79,238,126,126,55,165,252,194,162,155,250,213,111,63,120,142,94,185,51,56,186, +169,157,20,57,162,162,202,173,146,143,123,204,17,21,81,110,149,107,13,255,52,212,170,25,114,213,12,93,255,9,212,243,169,118, +187,244,230,0,234,98,236,41,50,91,177,179,187,140,178,187,136,61,31,178,176,46,124,175,251,164,91,135,43,17,186,24,187,66,101, +11,65,119,248,94,229,245,121,162,204,133,155,148,167,72,222,164,174,192,153,160,222,211,244,192,42,91,244,253,251,108,29,47, +206,209,249,174,65,67,151,214,239,24,202,190,219,249,75,191,243,221,206,185,98,62,157,103,148,211,185,102,133,124,107,165,110, +157,214,128,122,39,31,16,171,16,115,11,112,142,188,79,102,78,76,57,147,111,89,250,218,9,247,54,62,65,6,187,42,104,16,109,91, +150,190,120,98,123,87,57,109,55,203,81,126,254,196,96,215,124,240,113,106,46,125,230,68,160,48,252,116,230,29,31,206,168,1,245, +125,68,53,238,11,131,157,243,233,135,129,131,160,21,84,100,30,164,229,205,69,178,124,79,213,100,232,16,199,88,255,97,121,62, +109,239,196,153,141,157,18,248,211,231,171,10,68,145,184,148,194,47,65,235,223,213,13,25,121,211,128,246,123,216,172,18,8,98,46, +153,119,72,77,3,42,167,80,243,205,215,177,212,160,229,3,250,253,149,152,121,251,106,82,161,208,239,91,113,86,254,227,68,185, +81,135,251,192,46,17,164,85,2,89,180,168,196,154,181,32,35,143,131,19,148,252,240,243,153,28,191,80,234,16,250,187,18,33,51,24, +83,247,181,117,64,125,71,83,70,234,142,108,200,222,44,249,61,113,57,114,161,10,177,11,245,171,136,51,245,90,244,177,7,109,121, +38,65,201,15,191,152,185,147,231,233,62,42,178,125,148,203,223,192,10,34,202,216,130,231,122,83,64,125,199,116,27,232,61,217, +95,217,170,63,15,234,231,140,60,255,198,234,49,240,142,157,194,223,164,249,63,63,165,253,243,167,60,255,37,160,250,204,252,134, +137,223,57,90,69,234,183,69,197,69,234,187,152,242,34,245,155,9,31,232,152,214,27,7,173,193,243,133,160,75,138,212,111,63,150, +129,182,23,157,172,191,247,148,103,65,250,251,44,82,177,140,41,255,150,199,144,180,89,198,202,2,100,203,182,174,43,119,204,73, +144,202,105,12,253,100,106,186,134,102,126,167,149,249,30,201,144,180,73,62,47,212,252,238,172,156,79,183,85,191,50,81,125,173, +205,182,103,152,89,204,149,177,203,208,54,50,29,182,82,60,151,230,185,36,79,149,221,89,93,57,154,250,53,13,104,153,128,214,43, +223,179,211,204,247,103,114,143,201,12,90,217,158,101,249,251,228,133,186,95,254,46,119,161,222,139,181,248,107,105,234,215, +241,97,149,110,179,74,223,73,88,174,93,239,165,53,186,110,173,30,191,149,45,203,89,135,201,12,247,225,14,179,136,106,154,90,186, +90,155,214,47,239,172,95,223,179,190,181,126,89,87,75,75,125,231,202,229,205,245,43,186,215,183,44,91,223,189,172,123,101, +19,76,139,124,173,125,100,60,158,136,167,215,144,171,93,81,99,77,27,89,107,218,22,237,224,79,148,253,93,227,211,177,116,50,153, +30,27,136,38,162,123,98,83,180,250,84,78,40,54,53,149,156,90,29,26,73,78,143,143,134,18,201,116,104,79,44,29,202,74,133,250, +215,135,82,35,209,68,2,109,215,254,107,109,71,99,187,163,211,227,78,29,209,209,232,100,26,10,202,122,166,39,38,14,100,249,27, +163,233,116,119,116,124,124,87,116,228,66,18,125,100,244,245,147,217,215,223,79,149,125,91,67,235,247,143,196,38,211,241,36,130, +249,88,124,60,22,26,25,79,166,226,137,61,161,201,228,84,154,106,251,182,190,89,253,68,124,52,142,33,236,139,143,196,72,108,34, +107,211,246,238,245,84,184,105,122,36,54,128,154,190,196,228,116,122,27,171,8,100,88,91,167,211,25,158,47,195,147,79,197,153, +167,161,233,73,238,181,97,111,116,95,148,68,63,25,253,125,100,246,247,201,15,244,128,15,100,22,24,182,217,143,15,171,191,127, +103,63,213,244,71,19,163,83,201,248,104,227,174,204,108,27,179,243,238,84,230,104,163,5,111,37,213,35,231,208,70,85,111,37,196, +38,108,163,69,103,18,201,88,185,141,26,207,40,58,22,157,138,142,96,120,241,84,58,62,210,70,139,207,212,160,39,150,26,153,138, +79,166,147,83,179,15,100,60,54,35,223,31,27,82,190,52,251,220,33,202,245,51,163,125,19,125,44,180,33,62,142,65,214,116,77,199, +199,71,89,223,108,102,58,73,244,45,69,6,99,41,184,236,236,179,213,34,67,177,116,26,14,150,154,233,242,45,166,144,17,110,163, +121,89,161,145,100,34,29,75,164,27,187,153,238,71,103,149,217,170,137,216,104,60,218,200,174,219,200,14,151,89,250,37,111,45,208, +151,216,157,172,97,87,229,130,115,56,111,42,221,70,181,111,45,52,148,142,166,167,49,234,234,55,19,203,110,32,167,43,157,34,163, +163,67,141,82,57,179,154,43,207,212,96,107,66,53,217,58,25,75,196,70,251,225,129,49,233,43,161,51,52,124,139,185,207,236,110, +231,250,159,34,52,24,27,137,197,247,177,158,162,172,72,50,213,216,53,157,24,29,199,50,20,59,153,189,81,102,66,180,196,201,221, +22,157,26,137,141,111,159,142,143,182,81,32,91,49,157,142,143,55,246,39,247,156,198,219,22,141,79,57,250,202,242,218,104,251, +233,204,246,51,184,201,25,227,3,14,130,166,254,145,228,68,227,212,68,106,188,113,47,162,90,227,41,161,173,230,212,200,222,70, +205,103,104,113,90,68,109,163,165,255,98,19,231,154,44,249,23,219,40,233,254,51,72,207,88,37,235,131,111,122,226,180,81,207,191, +173,109,134,195,46,26,137,166,46,60,179,161,78,211,114,230,73,103,38,188,45,154,30,227,48,241,150,210,188,89,71,163,227,251, +226,23,54,34,180,38,177,129,113,40,54,174,79,232,3,177,123,60,154,194,134,14,206,34,211,199,145,88,215,87,205,82,63,16,155,216, +165,5,98,16,169,152,69,100,40,190,39,129,136,49,133,93,82,54,75,117,100,108,42,121,49,154,206,233,231,179,179,49,158,108,116, +28,220,109,84,168,216,227,209,196,158,70,61,142,34,7,171,15,113,82,218,43,224,96,110,221,181,55,54,146,62,153,55,148,158,194, +76,179,221,72,158,236,58,186,139,247,111,185,131,61,21,219,221,120,78,44,122,225,96,108,119,108,42,150,64,146,80,241,86,181, +188,249,101,181,220,141,157,83,83,209,3,28,150,50,61,157,204,109,163,238,217,216,237,255,206,106,175,225,67,111,86,37,167,77,119, +77,214,8,51,162,169,147,121,189,209,20,118,244,100,198,170,78,222,233,130,56,179,78,19,4,239,100,19,244,225,36,141,202,179,190, +192,193,149,54,241,159,194,104,163,150,83,56,237,103,60,128,215,156,172,87,118,95,232,96,68,226,19,236,16,115,78,101,169,173, +88,120,218,94,163,206,211,88,179,39,173,142,211,36,148,58,128,131,103,34,148,138,77,201,44,50,112,250,174,39,159,115,209,168, +214,121,228,55,116,119,246,247,119,117,118,111,190,32,114,238,182,245,23,12,116,70,186,123,47,232,223,58,20,33,177,131,140,29, +200,26,119,32,207,181,118,244,237,236,35,215,142,77,200,35,55,129,141,236,113,7,210,74,107,7,231,149,246,14,201,5,71,126,176, +116,191,170,68,217,230,207,77,138,32,23,221,177,147,4,210,79,40,51,144,119,26,195,93,84,61,124,230,84,168,126,248,223,74,45,106, +254,5,113,236,221,225,89,246,233,73,204,204,70,205,141,142,140,196,82,169,13,227,209,61,41,242,34,221,156,142,142,203,156,219, +157,185,42,152,209,209,81,126,26,157,130,28,249,116,239,125,137,209,216,126,180,86,79,178,133,55,58,57,169,51,42,114,69,83,202, +19,119,157,146,106,83,89,150,211,191,94,238,61,181,182,219,183,247,245,80,96,215,105,233,169,67,67,198,145,138,103,56,217,105, +167,28,114,23,232,59,71,206,174,116,167,30,181,103,87,90,201,65,76,151,82,124,160,195,4,228,218,149,230,195,136,236,93,156,77, +146,111,68,159,74,145,3,147,49,114,97,20,72,39,40,127,228,164,100,156,236,145,241,88,116,138,73,50,21,35,55,18,202,4,108,76, +185,186,32,21,122,56,205,140,198,19,41,201,150,165,205,177,3,82,88,218,200,167,11,145,228,118,232,176,177,11,18,105,18,163,228, +29,205,230,241,228,210,115,241,40,10,27,101,74,163,148,151,41,41,5,185,163,89,7,72,101,234,50,38,243,170,71,153,236,228,140,198, +167,48,68,132,125,176,227,169,204,208,93,177,139,176,244,41,202,145,155,178,59,57,10,3,198,50,7,4,53,236,142,226,106,55,26, +74,39,67,35,83,177,104,58,22,218,53,61,174,239,148,74,119,104,247,84,114,34,148,113,19,207,238,120,34,58,30,127,71,140,170,80, +26,157,89,168,13,201,41,199,237,75,9,87,178,72,102,67,207,38,96,239,142,79,193,153,124,187,97,162,209,204,130,123,185,67,229, +198,100,237,97,131,231,240,167,50,134,137,72,66,94,124,100,84,228,114,121,92,186,118,138,202,248,65,121,238,105,215,242,249, +51,117,167,199,176,57,92,57,57,57,30,31,145,167,106,198,219,139,192,62,109,208,165,78,166,51,167,151,90,78,191,136,145,7,108,121, +246,82,33,74,61,234,238,158,217,54,57,146,37,125,33,63,91,84,107,237,205,62,167,200,141,178,116,190,69,40,244,78,79,112,56,199, +70,198,225,171,44,53,171,117,33,10,199,146,100,84,106,96,189,84,141,2,31,144,167,25,99,75,116,130,153,125,61,41,170,59,93,70, +102,161,167,9,134,79,23,84,185,231,105,146,243,32,201,213,167,14,19,147,155,171,171,122,178,206,140,233,232,33,179,6,185,200, +188,194,242,33,47,243,48,205,185,19,249,245,35,31,19,220,172,71,218,91,249,131,20,157,74,78,198,166,210,113,244,83,128,199,193, +216,68,50,29,203,4,13,48,134,228,81,164,163,149,236,82,6,136,188,49,121,11,209,247,22,114,143,69,83,91,216,37,60,40,140,201, +93,100,141,37,225,187,57,252,169,124,83,196,201,140,143,238,39,43,206,102,182,227,114,17,115,226,217,247,33,185,241,84,118,242, +252,208,173,118,104,12,19,141,167,214,79,76,166,15,112,65,218,153,171,103,94,164,120,226,58,37,32,15,167,55,189,220,175,111,175, +243,69,138,121,33,2,144,11,31,156,97,120,199,147,136,117,42,144,187,39,180,135,91,124,158,144,119,34,107,102,42,156,56,109, +27,228,79,156,180,10,148,59,225,8,196,198,196,4,153,19,169,61,248,72,79,147,149,224,181,176,249,19,81,33,17,187,152,247,0,140, +146,96,35,153,201,93,123,201,149,220,189,59,133,225,4,146,137,174,104,122,100,108,38,7,73,81,9,246,216,73,129,23,79,137,61,176, +68,241,169,21,236,230,52,231,84,238,57,83,48,137,212,162,108,136,61,43,251,87,106,200,159,76,204,188,51,145,26,10,157,28,213, +58,47,169,239,194,112,68,244,156,159,60,233,106,204,125,58,159,123,98,227,209,3,96,23,100,216,236,72,251,156,114,42,8,100,38, +226,78,38,54,140,79,167,198,200,151,76,12,164,167,51,108,140,140,199,163,188,112,48,149,138,83,41,115,198,227,188,149,229,184, +186,147,19,147,136,192,144,69,75,153,80,200,8,157,121,82,22,132,113,145,13,37,164,189,180,235,166,122,56,230,227,138,13,217, +34,184,124,226,148,24,69,94,102,234,114,30,151,103,28,172,132,31,79,186,106,158,19,79,143,97,43,149,102,42,102,46,148,186,38, +144,169,113,240,242,153,231,120,217,151,195,207,106,39,122,146,153,188,46,39,83,66,128,194,224,248,16,75,206,52,177,147,23,115, +200,44,154,132,251,157,58,129,178,89,152,67,233,216,100,228,226,36,149,156,84,55,19,76,200,154,228,244,209,146,239,52,115,38, +101,186,197,251,194,51,169,51,47,85,146,129,37,63,83,210,17,75,214,200,236,51,47,83,82,27,93,86,200,40,145,159,41,69,146,27,112, +214,145,61,41,103,107,242,22,158,59,21,219,195,239,87,166,78,126,73,67,174,41,233,57,228,85,84,133,6,85,86,249,214,188,41,28, +217,177,84,122,198,183,183,77,197,147,240,141,3,220,86,46,191,123,74,111,36,48,210,251,162,227,100,77,177,47,153,83,211,9,42, +76,101,179,80,253,30,141,138,82,142,236,57,195,116,103,94,58,123,82,35,99,177,81,28,251,228,74,197,144,54,140,146,149,98,223, +42,227,79,245,182,119,44,58,26,234,219,26,154,201,27,60,92,199,102,166,2,236,241,110,103,106,149,11,6,123,234,0,7,201,124,126, +208,153,224,116,124,20,149,99,124,41,192,94,193,68,173,20,39,18,118,74,62,228,72,194,13,41,79,21,211,201,73,249,232,74,169,227, +213,74,129,131,158,51,252,28,120,79,102,149,211,99,113,24,131,63,107,154,80,129,11,11,26,77,76,146,59,157,148,183,54,242,164, +147,58,167,152,51,157,152,205,187,230,157,194,118,248,80,233,116,226,77,214,210,134,237,167,113,58,72,178,117,55,69,196,205, +194,157,111,188,76,109,251,141,171,47,109,171,167,152,120,15,24,116,129,36,135,76,58,34,44,218,73,224,124,85,8,178,172,7,140,213, +163,238,252,19,38,221,111,228,237,180,137,62,33,196,231,89,254,22,97,124,68,220,111,184,243,47,236,55,233,54,97,213,95,111,83, +199,254,126,23,53,28,121,7,196,62,32,164,190,195,82,95,195,254,16,237,21,223,54,220,75,32,251,1,97,54,24,21,23,27,123,42,250, +77,241,65,145,211,240,158,134,157,166,241,160,145,251,225,157,166,249,85,35,127,243,206,142,71,250,182,218,134,109,210,141,74, +201,17,250,190,176,94,23,135,196,103,140,103,240,216,94,143,63,237,244,186,32,119,197,150,183,111,62,80,95,111,76,87,84,154, +244,5,209,64,199,193,204,111,111,167,163,6,207,224,105,126,162,107,101,249,253,134,245,119,113,153,113,139,248,33,198,92,127, +11,221,96,152,234,25,117,207,177,220,163,59,59,232,165,76,225,78,195,84,29,170,238,232,167,198,44,157,221,107,168,206,94,146, +29,124,69,126,126,111,70,237,150,11,140,75,50,162,95,151,149,223,146,159,55,153,6,6,143,65,180,215,211,189,166,241,21,113,35, +143,225,30,211,228,210,227,232,145,62,239,40,127,154,203,143,27,255,132,76,199,230,15,211,23,249,241,211,170,234,1,71,249,33, +46,255,67,149,31,228,242,151,13,89,254,50,119,32,75,119,103,75,223,54,45,250,140,184,77,60,8,157,59,121,118,199,76,140,171,163, +29,139,243,37,99,109,255,206,225,53,91,206,95,83,111,147,177,191,205,69,244,146,172,236,143,155,226,57,81,116,224,17,185,160, +245,231,219,100,139,249,149,171,232,160,197,83,122,183,252,124,15,127,118,28,218,31,44,167,235,45,118,179,10,227,176,213,102, +188,126,201,146,250,71,251,141,252,139,141,125,21,251,247,239,63,16,71,55,162,91,233,91,189,198,22,244,126,151,92,102,17,240, +91,198,171,162,178,243,144,179,171,111,115,79,182,65,71,181,208,92,191,73,183,139,38,200,28,53,106,111,227,74,186,220,195,253, +30,54,141,255,21,221,65,147,158,21,66,184,109,50,5,10,143,88,38,107,20,134,45,92,36,114,109,114,137,74,219,172,151,26,127,105, +137,187,97,142,142,120,229,176,101,220,105,44,31,22,197,126,83,220,110,212,237,55,14,124,131,37,214,187,12,140,245,255,196,122, +186,218,35,238,224,5,16,129,2,139,88,225,175,67,54,205,175,60,139,254,100,153,183,139,95,139,63,112,101,187,153,243,89,67,244, +155,38,84,52,30,50,106,150,24,219,43,108,211,206,89,238,50,93,57,123,45,247,221,104,215,176,217,116,221,38,10,27,224,22,47,137, +5,13,123,77,227,19,198,188,122,12,143,118,217,6,246,206,173,205,152,145,105,187,108,183,113,17,140,143,150,46,151,123,175,233, +249,173,152,35,165,132,233,34,195,87,1,33,136,216,158,74,186,7,54,175,24,238,24,22,115,11,48,118,209,244,77,91,172,110,175,228, +39,227,101,81,7,147,218,70,3,27,22,91,180,178,179,127,255,59,174,180,105,184,157,94,112,203,169,99,222,247,24,203,119,30,49, +177,3,138,238,229,185,7,226,183,236,91,213,191,200,22,219,176,135,239,182,217,228,21,29,123,227,43,140,253,21,135,154,91,227, +13,149,116,92,46,245,143,228,231,119,221,226,86,168,57,96,186,49,241,142,251,228,178,5,77,227,21,33,110,189,213,180,160,13,179, +189,219,16,152,180,121,155,33,246,110,54,237,59,140,165,113,225,181,237,6,151,93,203,38,198,92,45,219,182,93,198,72,133,237,94, +238,18,46,195,101,241,148,141,75,218,80,225,50,74,54,177,20,252,236,117,183,113,183,113,59,59,64,113,129,73,159,54,234,46,196, +0,239,113,161,71,119,254,37,229,244,172,75,60,193,107,185,217,244,96,12,232,246,118,33,130,166,251,43,194,174,52,115,158,23, +107,159,57,16,124,196,180,57,20,109,54,173,235,196,210,91,133,199,118,215,163,159,242,139,121,0,247,154,185,240,166,251,68,161, +223,206,13,26,163,21,24,132,125,139,229,125,141,87,108,111,67,251,218,117,182,119,133,26,40,91,221,206,89,197,99,116,121,92,57, +174,92,35,221,102,231,178,60,125,204,173,198,0,71,68,239,143,30,62,193,219,208,62,98,4,111,182,205,160,177,187,2,61,99,108, +143,152,66,13,131,48,140,67,150,45,251,232,119,153,13,237,93,114,233,237,205,77,210,48,22,61,160,102,215,113,216,34,237,58,240, +229,194,1,83,200,89,89,247,25,107,59,130,188,29,120,161,15,139,194,130,96,53,214,186,125,205,48,154,195,170,193,114,24,232, +105,151,218,241,159,178,13,118,83,148,110,179,5,91,145,224,224,71,132,123,137,26,134,49,103,204,72,84,116,196,141,188,37,198, +190,182,91,132,223,47,59,105,248,72,195,60,250,133,20,204,143,211,29,46,185,216,59,233,25,233,22,249,70,120,204,24,174,232,56, +124,136,227,138,141,142,207,179,13,172,48,236,200,147,131,5,218,113,34,108,182,172,215,102,198,126,73,167,109,194,139,97,72, +172,47,124,27,86,171,52,5,199,199,191,27,230,157,226,179,226,189,58,188,211,251,77,113,208,112,87,180,204,251,98,189,73,55,25, +117,116,136,163,16,182,159,73,191,17,77,159,183,169,29,145,233,81,236,251,138,122,106,103,87,252,130,71,124,10,190,138,16,118, +88,152,134,111,137,113,113,197,133,29,155,247,195,115,110,145,53,249,135,106,141,119,84,40,142,17,22,63,54,74,235,140,69,198, +127,11,43,231,31,162,36,215,88,12,78,185,85,114,126,137,93,50,84,226,81,143,118,137,40,137,130,177,164,36,71,138,214,228,184, +32,91,58,211,108,174,177,132,229,68,233,210,25,94,137,82,94,171,56,6,56,249,51,197,248,140,220,30,227,44,110,107,148,214,148, +46,200,116,119,158,236,189,102,166,127,102,156,93,178,33,195,112,151,156,3,198,26,160,9,82,222,12,147,165,122,75,182,227,179, +39,195,244,96,232,67,37,102,86,54,171,209,144,42,122,51,12,23,24,51,50,114,112,94,12,110,175,26,156,171,180,182,116,97,105,85, +105,168,180,178,180,90,148,88,194,20,57,102,153,129,63,194,104,57,120,208,58,182,112,153,56,88,39,196,109,192,147,192,225,48, +220,30,56,14,60,185,72,136,155,206,18,130,255,145,50,185,182,93,230,33,49,11,200,54,114,92,250,135,56,130,58,46,59,104,189,123, +137,117,185,65,107,196,189,75,132,117,125,189,16,15,212,27,226,231,160,47,3,239,110,16,226,30,224,81,224,96,35,2,188,59,87,182, +235,69,187,7,27,251,196,175,26,133,245,104,147,16,207,2,135,155,133,184,17,248,21,240,151,102,50,132,55,223,16,87,135,118,64, +244,240,210,115,196,109,75,133,120,16,56,6,60,11,92,223,34,196,93,192,195,192,147,192,243,192,27,45,100,9,219,143,201,10,110, +26,69,211,171,151,237,18,15,44,195,8,150,11,241,216,10,104,7,14,175,36,183,59,80,172,196,244,223,61,144,125,114,165,97,92,181, +74,24,215,174,54,141,55,86,11,227,141,54,211,184,171,195,107,220,180,102,204,122,99,173,41,30,239,130,165,186,77,241,100,15, +102,215,99,136,171,214,99,164,27,48,132,141,120,6,158,221,4,221,3,232,99,11,248,192,213,91,13,113,207,86,240,183,193,18,103,195, +186,103,195,2,198,124,193,127,14,10,116,120,253,208,101,152,212,16,38,19,225,159,231,5,189,194,251,46,113,248,160,245,66,132, +107,15,111,23,57,55,1,87,237,200,252,255,74,206,223,244,100,254,239,64,254,173,74,230,255,15,228,223,169,100,254,15,65,254,157, +74,136,212,255,35,200,191,213,201,252,95,130,46,154,249,255,4,77,191,250,29,141,252,61,85,72,253,63,82,219,192,112,133,148,12, +255,123,122,225,87,191,125,231,127,3,111,132,84,191,252,255,15,154,90,158,255,141,182,21,82,191,75,226,127,199,109,135,212,248, +248,223,224,147,214,195,255,38,159,127,204,195,124,254,127,15,255,63,171,27,97,244,48,81,0,0,0,0}; #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ - STATICMETHOD (getAndroidMidiDeviceManager, "getAndroidMidiDeviceManager", "(Landroid/content/Context;)Lcom/roli/juce/JuceMidiSupport$MidiDeviceManager;") \ - STATICMETHOD (getAndroidBluetoothManager, "getAndroidBluetoothManager", "(Landroid/content/Context;)Lcom/roli/juce/JuceMidiSupport$BluetoothManager;") + STATICMETHOD (getAndroidMidiDeviceManager, "getAndroidMidiDeviceManager", "(Landroid/content/Context;)Lcom/rmsl/juce/JuceMidiSupport$MidiDeviceManager;") \ + STATICMETHOD (getAndroidBluetoothManager, "getAndroidBluetoothManager", "(Landroid/content/Context;)Lcom/rmsl/juce/JuceMidiSupport$BluetoothManager;") -DECLARE_JNI_CLASS_WITH_BYTECODE (JuceMidiSupport, "com/roli/juce/JuceMidiSupport", 23, javaMidiByteCode, sizeof (javaMidiByteCode)) +DECLARE_JNI_CLASS_WITH_BYTECODE (JuceMidiSupport, "com/rmsl/juce/JuceMidiSupport", 23, javaMidiByteCode, sizeof (javaMidiByteCode)) #undef JNI_CLASS_MEMBERS #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ - METHOD (getJuceAndroidMidiInputDevices, "getJuceAndroidMidiInputDevices", "()[Ljava/lang/String;") \ - METHOD (getJuceAndroidMidiOutputDevices, "getJuceAndroidMidiOutputDevices", "()[Ljava/lang/String;") \ - METHOD (openMidiInputPortWithJuceIndex, "openMidiInputPortWithJuceIndex", "(IJ)Lcom/roli/juce/JuceMidiSupport$JuceMidiPort;") \ - METHOD (openMidiOutputPortWithJuceIndex, "openMidiOutputPortWithJuceIndex", "(I)Lcom/roli/juce/JuceMidiSupport$JuceMidiPort;") \ - METHOD (getInputPortNameForJuceIndex, "getInputPortNameForJuceIndex", "(I)Ljava/lang/String;") \ - METHOD (getOutputPortNameForJuceIndex, "getOutputPortNameForJuceIndex", "(I)Ljava/lang/String;") - -DECLARE_JNI_CLASS_WITH_MIN_SDK (MidiDeviceManager, "com/roli/juce/JuceMidiSupport$MidiDeviceManager", 23) + METHOD (getJuceAndroidMidiInputDeviceNameAndIDs, "getJuceAndroidMidiInputDeviceNameAndIDs", "()[Ljava/lang/String;") \ + METHOD (getJuceAndroidMidiOutputDeviceNameAndIDs, "getJuceAndroidMidiOutputDeviceNameAndIDs", "()[Ljava/lang/String;") \ + METHOD (openMidiInputPortWithID, "openMidiInputPortWithID", "(IJ)Lcom/rmsl/juce/JuceMidiSupport$JuceMidiPort;") \ + METHOD (openMidiOutputPortWithID, "openMidiOutputPortWithID", "(I)Lcom/rmsl/juce/JuceMidiSupport$JuceMidiPort;") + +DECLARE_JNI_CLASS_WITH_MIN_SDK (MidiDeviceManager, "com/rmsl/juce/JuceMidiSupport$MidiDeviceManager", 23) #undef JNI_CLASS_MEMBERS #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ - METHOD (start, "start", "()V" )\ - METHOD (stop, "stop", "()V") \ - METHOD (close, "close", "()V") \ - METHOD (sendMidi, "sendMidi", "([BII)V") + METHOD (start, "start", "()V") \ + METHOD (stop, "stop", "()V") \ + METHOD (close, "close", "()V") \ + METHOD (sendMidi, "sendMidi", "([BII)V") \ + METHOD (getName, "getName", "()Ljava/lang/String;") -DECLARE_JNI_CLASS_WITH_MIN_SDK (JuceMidiPort, "com/roli/juce/JuceMidiSupport$JuceMidiPort", 23) +DECLARE_JNI_CLASS_WITH_MIN_SDK (JuceMidiPort, "com/rmsl/juce/JuceMidiSupport$JuceMidiPort", 23) #undef JNI_CLASS_MEMBERS //============================================================================== class AndroidMidiInput { public: - AndroidMidiInput (MidiInput* midiInput, int portIdx, - juce::MidiInputCallback* midiInputCallback, jobject deviceManager) - : juceMidiInput (midiInput), - callback (midiInputCallback), - midiConcatenator (2048), - javaMidiDevice (LocalRef(getEnv()->CallObjectMethod (deviceManager, - MidiDeviceManager.openMidiInputPortWithJuceIndex, - (jint) portIdx, - (jlong) this))) + AndroidMidiInput (MidiInput* midiInput, int deviceID, juce::MidiInputCallback* midiInputCallback, jobject deviceManager) + : juceMidiInput (midiInput), callback (midiInputCallback), midiConcatenator (2048), + javaMidiDevice (LocalRef(getEnv()->CallObjectMethod (deviceManager, MidiDeviceManager.openMidiInputPortWithID, + (jint) deviceID, (jlong) this))) { } @@ -408,12 +388,20 @@ class AndroidMidiInput callback = nullptr; } + String getName() const noexcept + { + if (jobject d = javaMidiDevice.get()) + return juceString (LocalRef ((jstring) getEnv()->CallObjectMethod (d, JuceMidiPort.getName))); + + return {}; + } + void handleMidi (jbyteArray byteArray, jlong offset, jint len, jlong timestamp) { auto* env = getEnv(); jassert (byteArray != nullptr); - jbyte* data = env->GetByteArrayElements (byteArray, nullptr); + auto* data = env->GetByteArrayElements (byteArray, nullptr); HeapBlock buffer (static_cast (len)); std::memcpy (buffer.get(), data + offset, static_cast (len)); @@ -466,6 +454,14 @@ class AndroidMidiOutput byteArray, offset, len); } + String getName() const noexcept + { + if (jobject d = javaMidiDevice.get()) + return juceString (LocalRef ((jstring) getEnv()->CallObjectMethod (d, JuceMidiPort.getName))); + + return {}; + } + private: GlobalRef javaMidiDevice; }; @@ -474,7 +470,7 @@ class AndroidMidiOutput #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ CALLBACK (AndroidMidiInput::handleReceive, "handleReceive", "(J[BIIJ)V" ) -DECLARE_JNI_CLASS_WITH_MIN_SDK (JuceMidiInputPort, "com/roli/juce/JuceMidiSupport$JuceMidiInputPort", 23) +DECLARE_JNI_CLASS_WITH_MIN_SDK (JuceMidiInputPort, "com/rmsl/juce/JuceMidiSupport$JuceMidiInputPort", 23) #undef JNI_CLASS_MEMBERS //============================================================================== @@ -482,54 +478,42 @@ class AndroidMidiDeviceManager { public: AndroidMidiDeviceManager() - : deviceManager (LocalRef(getEnv()->CallStaticObjectMethod (JuceMidiSupport, JuceMidiSupport.getAndroidMidiDeviceManager, getAppContext().get()))) + : deviceManager (LocalRef(getEnv()->CallStaticObjectMethod (JuceMidiSupport, + JuceMidiSupport.getAndroidMidiDeviceManager, + getAppContext().get()))) { } - String getInputPortNameForJuceIndex (int idx) + Array getDevices (bool input) { if (jobject dm = deviceManager.get()) { - LocalRef string ((jstring) getEnv()->CallObjectMethod (dm, MidiDeviceManager.getInputPortNameForJuceIndex, idx)); - return juceString (string); - } + jobjectArray jDeviceNameAndIDs + = (jobjectArray) getEnv()->CallObjectMethod (dm, input ? MidiDeviceManager.getJuceAndroidMidiInputDeviceNameAndIDs + : MidiDeviceManager.getJuceAndroidMidiOutputDeviceNameAndIDs); - return {}; - } + // Create a local reference as converting this to a JUCE string will call into JNI + LocalRef localDeviceNameAndIDs (jDeviceNameAndIDs); - String getOutputPortNameForJuceIndex (int idx) - { - if (jobject dm = deviceManager.get()) - { - LocalRef string ((jstring) getEnv()->CallObjectMethod (dm, MidiDeviceManager.getOutputPortNameForJuceIndex, idx)); - return juceString (string); - } + auto deviceNameAndIDs = javaStringArrayToJuce (localDeviceNameAndIDs); + deviceNameAndIDs.appendNumbersToDuplicates (false, false, CharPointer_UTF8 ("-"), CharPointer_UTF8 ("")); - return {}; - } + Array devices; - StringArray getDevices (bool input) - { - if (jobject dm = deviceManager.get()) - { - jobjectArray jDevices - = (jobjectArray) getEnv()->CallObjectMethod (dm, input ? MidiDeviceManager.getJuceAndroidMidiInputDevices - : MidiDeviceManager.getJuceAndroidMidiOutputDevices); - - // Create a local reference as converting this - // to a JUCE string will call into JNI - LocalRef devices (jDevices); - return javaStringArrayToJuce (devices); + for (int i = 0; i < deviceNameAndIDs.size(); i += 2) + devices.add ({ deviceNameAndIDs[i], deviceNameAndIDs[i + 1] }); + + return devices; } return {}; } - AndroidMidiInput* openMidiInputPortWithIndex (int idx, MidiInput* juceMidiInput, juce::MidiInputCallback* callback) + AndroidMidiInput* openMidiInputPortWithID (int deviceID, MidiInput* juceMidiInput, juce::MidiInputCallback* callback) { - if (jobject dm = deviceManager.get()) + if (auto dm = deviceManager.get()) { - std::unique_ptr androidMidiInput (new AndroidMidiInput (juceMidiInput, idx, callback, dm)); + std::unique_ptr androidMidiInput (new AndroidMidiInput (juceMidiInput, deviceID, callback, dm)); if (androidMidiInput->isOpen()) return androidMidiInput.release(); @@ -538,10 +522,10 @@ class AndroidMidiDeviceManager return nullptr; } - AndroidMidiOutput* openMidiOutputPortWithIndex (int idx) + AndroidMidiOutput* openMidiOutputPortWithID (int deviceID) { - if (jobject dm = deviceManager.get()) - if (jobject javaMidiPort = getEnv()->CallObjectMethod (dm, MidiDeviceManager.openMidiOutputPortWithJuceIndex, (jint) idx)) + if (auto dm = deviceManager.get()) + if (auto javaMidiPort = getEnv()->CallObjectMethod (dm, MidiDeviceManager.openMidiOutputPortWithID, (jint) deviceID)) return new AndroidMidiOutput (LocalRef(javaMidiPort)); return nullptr; @@ -552,134 +536,171 @@ class AndroidMidiDeviceManager }; //============================================================================== -StringArray MidiOutput::getDevices() +Array MidiInput::getAvailableDevices() { - if (getAndroidSDKVersion() >= 23) - { - AndroidMidiDeviceManager manager; - return manager.getDevices (false); - } + if (getAndroidSDKVersion() < 23) + return {}; - return {}; + AndroidMidiDeviceManager manager; + return manager.getDevices (true); } -int MidiOutput::getDefaultDeviceIndex() +MidiDeviceInfo MidiInput::getDefaultDevice() { - return (getAndroidSDKVersion() >= 23 ? 0 : -1); + if (getAndroidSDKVersion() < 23) + return {}; + + return getAvailableDevices().getFirst(); } -MidiOutput* MidiOutput::openDevice (int index) +std::unique_ptr MidiInput::openDevice (const String& deviceIdentifier, MidiInputCallback* callback) { - if (index < 0 || getAndroidSDKVersion() < 23) - return nullptr; + if (getAndroidSDKVersion() < 23 || deviceIdentifier.isEmpty()) + return {}; AndroidMidiDeviceManager manager; - String midiOutputName = manager.getOutputPortNameForJuceIndex (index); + std::unique_ptr midiInput (new MidiInput ({}, deviceIdentifier)); - if (midiOutputName.isEmpty()) + if (auto* port = manager.openMidiInputPortWithID (deviceIdentifier.getIntValue(), midiInput.get(), callback)) { - // you supplied an invalid device index! - jassertfalse; - return nullptr; - } + midiInput->internal = port; + midiInput->setName (port->getName()); - if (AndroidMidiOutput* midiOutput = manager.openMidiOutputPortWithIndex (index)) - { - MidiOutput* retval = new MidiOutput (midiOutputName); - retval->internal = midiOutput; - - return retval; + return midiInput; } - return nullptr; + return {}; } -MidiOutput::~MidiOutput() +StringArray MidiInput::getDevices() { - stopBackgroundThread(); + if (getAndroidSDKVersion() < 23) + return {}; - delete reinterpret_cast (internal); + StringArray deviceNames; + + for (auto& d : getAvailableDevices()) + deviceNames.add (d.name); + + return deviceNames; } -void MidiOutput::sendMessageNow (const MidiMessage& message) +int MidiInput::getDefaultDeviceIndex() { - if (AndroidMidiOutput* androidMidi = reinterpret_cast(internal)) - { - JNIEnv* env = getEnv(); - const int messageSize = message.getRawDataSize(); + return (getAndroidSDKVersion() < 23 ? -1 : 0); +} - LocalRef messageContent = LocalRef (env->NewByteArray (messageSize)); - jbyteArray content = messageContent.get(); +std::unique_ptr MidiInput::openDevice (int index, MidiInputCallback* callback) +{ + return openDevice (getAvailableDevices()[index].identifier, callback); +} - jbyte* rawBytes = env->GetByteArrayElements (content, nullptr); - std::memcpy (rawBytes, message.getRawData(), static_cast (messageSize)); - env->ReleaseByteArrayElements (content, rawBytes, 0); +MidiInput::MidiInput (const String& deviceName, const String& deviceIdentifier) + : deviceInfo (deviceName, deviceIdentifier) +{ +} - androidMidi->send (content, (jint) 0, (jint) messageSize); - } +MidiInput::~MidiInput() +{ + delete reinterpret_cast (internal); } -//============================================================================== -MidiInput::MidiInput (const String& nm) : name (nm) +void MidiInput::start() { + if (auto* mi = reinterpret_cast (internal)) + mi->start(); } -StringArray MidiInput::getDevices() +void MidiInput::stop() { - if (getAndroidSDKVersion() >= 23) - { - AndroidMidiDeviceManager manager; - return manager.getDevices (true); - } + if (auto* mi = reinterpret_cast (internal)) + mi->stop(); +} - return {}; +//============================================================================== +Array MidiOutput::getAvailableDevices() +{ + if (getAndroidSDKVersion() < 23) + return {}; + + AndroidMidiDeviceManager manager; + return manager.getDevices (false); } -int MidiInput::getDefaultDeviceIndex() +MidiDeviceInfo MidiOutput::getDefaultDevice() { - return (getAndroidSDKVersion() >= 23 ? 0 : -1); + if (getAndroidSDKVersion() < 23) + return {}; + + return getAvailableDevices().getFirst(); } -MidiInput* MidiInput::openDevice (int index, juce::MidiInputCallback* callback) +std::unique_ptr MidiOutput::openDevice (const String& deviceIdentifier) { - if (getAndroidSDKVersion() < 23 || index < 0) - return nullptr; + if (getAndroidSDKVersion() < 23 || deviceIdentifier.isEmpty()) + return {}; AndroidMidiDeviceManager manager; - String midiInputName (manager.getInputPortNameForJuceIndex (index)); - - if (midiInputName.isEmpty()) + if (auto* port = manager.openMidiOutputPortWithID (deviceIdentifier.getIntValue())) { - // you supplied an invalid device index! - jassertfalse; - return nullptr; + std::unique_ptr midiOutput (new MidiOutput ({}, deviceIdentifier)); + midiOutput->internal = port; + midiOutput->setName (port->getName()); + + return midiOutput; } - std::unique_ptr midiInput (new MidiInput (midiInputName)); + return {}; +} + +StringArray MidiOutput::getDevices() +{ + if (getAndroidSDKVersion() < 23) + return {}; + + StringArray deviceNames; - midiInput->internal = manager.openMidiInputPortWithIndex (index, midiInput.get(), callback); + for (auto& d : getAvailableDevices()) + deviceNames.add (d.name); - return midiInput->internal != nullptr ? midiInput.release() - : nullptr; + return deviceNames; } -void MidiInput::start() +int MidiOutput::getDefaultDeviceIndex() { - if (AndroidMidiInput* mi = reinterpret_cast (internal)) - mi->start(); + return (getAndroidSDKVersion() < 23 ? -1 : 0); } -void MidiInput::stop() +std::unique_ptr MidiOutput::openDevice (int index) { - if (AndroidMidiInput* mi = reinterpret_cast (internal)) - mi->stop(); + return openDevice (getAvailableDevices()[index].identifier); } -MidiInput::~MidiInput() +MidiOutput::~MidiOutput() { - delete reinterpret_cast (internal); + stopBackgroundThread(); + + delete reinterpret_cast (internal); +} + +void MidiOutput::sendMessageNow (const MidiMessage& message) +{ + if (auto* androidMidi = reinterpret_cast(internal)) + { + auto* env = getEnv(); + auto messageSize = message.getRawDataSize(); + + LocalRef messageContent (env->NewByteArray (messageSize)); + auto content = messageContent.get(); + + auto* rawBytes = env->GetByteArrayElements (content, nullptr); + std::memcpy (rawBytes, message.getRawData(), static_cast (messageSize)); + env->ReleaseByteArrayElements (content, rawBytes, 0); + + androidMidi->send (content, (jint) 0, (jint) messageSize); + } } } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_Oboe.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_Oboe.cpp index 2de37b6..8789419 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_Oboe.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_Oboe.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2018 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -42,7 +42,7 @@ struct OboeAudioIODeviceBufferHelpers static constexpr int bitDepth() { return 16; } - static void referAudioBufferDirectlyToOboeIfPossible (int16*, AudioBuffer&, int) {} + static bool referAudioBufferDirectlyToOboeIfPossible (int16*, AudioBuffer&, int) { return false; } static void convertFromOboe (const int16* srcInterleaved, AudioBuffer& audioBuffer, int numSamples) { @@ -78,49 +78,56 @@ struct OboeAudioIODeviceBufferHelpers static constexpr int bitDepth() { return 32; } - static void referAudioBufferDirectlyToOboeIfPossible (float* nativeBuffer, AudioBuffer& audioBuffer, int numSamples) + static bool referAudioBufferDirectlyToOboeIfPossible (float* nativeBuffer, AudioBuffer& audioBuffer, int numSamples) { if (audioBuffer.getNumChannels() == 1) + { audioBuffer.setDataToReferTo (&nativeBuffer, 1, numSamples); + return true; + } + + return false; } static void convertFromOboe (const float* srcInterleaved, AudioBuffer& audioBuffer, int numSamples) { - // No need to convert, we instructed the buffer to point to the src data directly already - if (audioBuffer.getNumChannels() == 1) - { - jassert (audioBuffer.getWritePointer (0) == srcInterleaved); - return; - } + auto numChannels = audioBuffer.getNumChannels(); - for (int i = 0; i < audioBuffer.getNumChannels(); ++i) + if (numChannels > 0) { - using DstSampleType = AudioData::Pointer; - using SrcSampleType = AudioData::Pointer; + // No need to convert, we instructed the buffer to point to the src data directly already + jassert (audioBuffer.getWritePointer (0) != srcInterleaved); - DstSampleType dstData (audioBuffer.getWritePointer (i)); - SrcSampleType srcData (srcInterleaved + i, audioBuffer.getNumChannels()); - dstData.convertSamples (srcData, numSamples); + for (int i = 0; i < numChannels; ++i) + { + using DstSampleType = AudioData::Pointer; + using SrcSampleType = AudioData::Pointer; + + DstSampleType dstData (audioBuffer.getWritePointer (i)); + SrcSampleType srcData (srcInterleaved + i, audioBuffer.getNumChannels()); + dstData.convertSamples (srcData, numSamples); + } } } static void convertToOboe (const AudioBuffer& audioBuffer, float* dstInterleaved, int numSamples) { - // No need to convert, we instructed the buffer to point to the src data directly already - if (audioBuffer.getNumChannels() == 1) - { - jassert (audioBuffer.getReadPointer (0) == dstInterleaved); - return; - } + auto numChannels = audioBuffer.getNumChannels(); - for (int i = 0; i < audioBuffer.getNumChannels(); ++i) + if (numChannels > 0) { - using DstSampleType = AudioData::Pointer; - using SrcSampleType = AudioData::Pointer; + // No need to convert, we instructed the buffer to point to the src data directly already + jassert (audioBuffer.getReadPointer (0) != dstInterleaved); - DstSampleType dstData (dstInterleaved + i, audioBuffer.getNumChannels()); - SrcSampleType srcData (audioBuffer.getReadPointer (i)); - dstData.convertSamples (srcData, numSamples); + for (int i = 0; i < numChannels; ++i) + { + using DstSampleType = AudioData::Pointer; + using SrcSampleType = AudioData::Pointer; + + DstSampleType dstData (dstInterleaved + i, audioBuffer.getNumChannels()); + SrcSampleType srcData (audioBuffer.getReadPointer (i)); + dstData.convertSamples (srcData, numSamples); + } } } }; @@ -151,11 +158,9 @@ class OboeAudioIODevice : public AudioIODevice supportedOutputSampleRates (supportedOutputSampleRatesToUse), maxNumOutputChannels (maxNumOutputChannelsToUse) { - // At least an input or an output has to be supported by the device! - jassert (inputDeviceId != -1 || outputDeviceId != -1); } - ~OboeAudioIODevice() + ~OboeAudioIODevice() override { close(); } @@ -197,16 +202,7 @@ class OboeAudioIODevice : public AudioIODevice Array getAvailableBufferSizes() override { - // we need to offer the lowest possible buffer size which - // is the native buffer size - const int defaultNumMultiples = 8; - const int nativeBufferSize = getNativeBufferSize(); - Array bufferSizes; - - for (int i = 1; i < defaultNumMultiples; ++i) - bufferSizes.add (i * nativeBufferSize); - - return bufferSizes; + return AndroidHighPerformanceAudioHelpers::getAvailableBufferSizes (getNativeBufferSize(), getAvailableSampleRates()); } String open (const BigInteger& inputChannels, const BigInteger& outputChannels, @@ -215,8 +211,8 @@ class OboeAudioIODevice : public AudioIODevice close(); lastError.clear(); - sampleRate = (int) requestedSampleRate; + sampleRate = (int) (requestedSampleRate > 0 ? requestedSampleRate : AndroidHighPerformanceAudioHelpers::getNativeSampleRate()); actualBufferSize = (bufferSize <= 0) ? getDefaultBufferSize() : bufferSize; // The device may report no max, claiming "no limits". Pick sensible defaults. @@ -274,16 +270,12 @@ class OboeAudioIODevice : public AudioIODevice int getDefaultBufferSize() override { - // Only on a Pro-Audio device will we set the lowest possible buffer size - // by default. We need to be more conservative on other devices - // as they may be low-latency, but still have a crappy CPU. - return (isProAudioDevice() ? 1 : 6) - * getNativeBufferSize(); + return AndroidHighPerformanceAudioHelpers::getDefaultBufferSize (getNativeBufferSize(), getCurrentSampleRate()); } double getCurrentSampleRate() override { - return (sampleRate == 0.0 ? getNativeSampleRate() : sampleRate); + return (sampleRate == 0.0 ? AndroidHighPerformanceAudioHelpers::getNativeSampleRate() : sampleRate); } void start (AudioIODeviceCallback* newCallback) override @@ -375,10 +367,11 @@ class OboeAudioIODevice : public AudioIODevice { static const int standardRates[] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }; + Array rates (standardRates, numElementsInArray (standardRates)); // make sure the native sample rate is part of the list - int native = (int) getNativeSampleRate(); + int native = (int) AndroidHighPerformanceAudioHelpers::getNativeSampleRate(); if (native != 0 && ! rates.contains (native)) rates.add (native); @@ -386,6 +379,30 @@ class OboeAudioIODevice : public AudioIODevice return rates; } + static int getNativeBufferSize() + { + auto bufferSizeHint = AndroidHighPerformanceAudioHelpers::getNativeBufferSizeHint(); + + // NB: Exclusive mode could be rejected if a device is already opened in that mode, so to get + // reliable results, only use this function when a device is closed. + // We initially try to open a stream with a buffer size returned from + // android.media.property.OUTPUT_FRAMES_PER_BUFFER property, but then we verify the actual + // size after the stream is open. + OboeAudioIODevice::OboeStream tempStream (oboe::kUnspecified, + oboe::Direction::Output, + oboe::SharingMode::Exclusive, + 2, + getAndroidSDKVersion() >= 21 ? oboe::AudioFormat::Float : oboe::AudioFormat::I16, + (int) AndroidHighPerformanceAudioHelpers::getNativeSampleRate(), + bufferSizeHint, + nullptr); + + if (auto* nativeStream = tempStream.getNativeStream()) + return nativeStream->getFramesPerBurst(); + + return bufferSizeHint; + } + void setCallback (AudioIODeviceCallback* callbackToUse) { if (! running) @@ -424,7 +441,7 @@ class OboeAudioIODevice : public AudioIODevice else { for (int i = 0; i < numOutputChannels; ++i) - zeromem (outputChannelData[i], sizeof (float) * static_cast (numFrames)); + zeromem (outputChannelData[i], (size_t) (numFrames) * sizeof (float)); } } @@ -435,11 +452,11 @@ class OboeAudioIODevice : public AudioIODevice OboeStream (int deviceId, oboe::Direction direction, oboe::SharingMode sharingMode, int channelCount, oboe::AudioFormat format, - int32 sampleRate, int32 bufferSize, - oboe::AudioStreamCallback* callback = nullptr) + int32 sampleRateIn, int32 bufferSize, + oboe::AudioStreamCallback* callbackIn = nullptr) { open (deviceId, direction, sharingMode, channelCount, - format, sampleRate, bufferSize, callback); + format, sampleRateIn, bufferSize, callbackIn); } ~OboeStream() @@ -511,10 +528,10 @@ class OboeAudioIODevice : public AudioIODevice void open (int deviceId, oboe::Direction direction, oboe::SharingMode sharingMode, int channelCount, oboe::AudioFormat format, - int32 sampleRate, int32 bufferSize, - oboe::AudioStreamCallback* callback = nullptr) + int32 newSampleRate, int32 newBufferSize, + oboe::AudioStreamCallback* newCallback = nullptr) { - oboe::DefaultStreamValues::FramesPerBurst = getDefaultFramesPerBurst(); + oboe::DefaultStreamValues::FramesPerBurst = AndroidHighPerformanceAudioHelpers::getNativeBufferSizeHint(); oboe::AudioStreamBuilder builder; @@ -526,9 +543,18 @@ class OboeAudioIODevice : public AudioIODevice builder.setSharingMode (sharingMode); builder.setChannelCount (channelCount); builder.setFormat (format); - builder.setSampleRate (sampleRate); + builder.setSampleRate (newSampleRate); builder.setPerformanceMode (oboe::PerformanceMode::LowLatency); - builder.setCallback (callback); + + #if JUCE_USE_ANDROID_OBOE_STABILIZED_CALLBACK + if (newCallback != nullptr) + { + stabilizedCallback = std::make_unique (newCallback); + builder.setCallback (stabilizedCallback.get()); + } + #else + builder.setCallback (newCallback); + #endif JUCE_OBOE_LOG (String ("Preparing Oboe stream with params:") + "\nAAudio supported = " + String (int (builder.isAAudioSupported())) @@ -538,17 +564,17 @@ class OboeAudioIODevice : public AudioIODevice + "\nSharingMode = " + getOboeString (sharingMode) + "\nChannelCount = " + String (channelCount) + "\nFormat = " + getOboeString (format) - + "\nSampleRate = " + String (sampleRate) + + "\nSampleRate = " + String (newSampleRate) + "\nPerformanceMode = " + getOboeString (oboe::PerformanceMode::LowLatency)); openResult = builder.openStream (&stream); JUCE_OBOE_LOG ("Building Oboe stream with result: " + getOboeString (openResult) + "\nStream state = " + (stream != nullptr ? getOboeString (stream->getState()) : String ("?"))); - if (stream != nullptr && bufferSize != 0) + if (stream != nullptr && newBufferSize != 0) { - JUCE_OBOE_LOG ("Setting the bufferSizeInFrames to " + String (bufferSize)); - stream->setBufferSizeInFrames (bufferSize); + JUCE_OBOE_LOG ("Setting the bufferSizeInFrames to " + String (newBufferSize)); + stream->setBufferSizeInFrames (newBufferSize); } JUCE_OBOE_LOG (String ("Stream details:") @@ -573,11 +599,15 @@ class OboeAudioIODevice : public AudioIODevice if (stream != nullptr) { oboe::Result result = stream->close(); + ignoreUnused (result); JUCE_OBOE_LOG ("Requested Oboe stream close with result: " + getOboeString (result)); } } oboe::AudioStream* stream = nullptr; + #if JUCE_USE_ANDROID_OBOE_STABILIZED_CALLBACK + std::unique_ptr stabilizedCallback; + #endif oboe::Result openResult; }; @@ -665,16 +695,16 @@ class OboeAudioIODevice : public AudioIODevice } // Not strictly required as these should not change, but recommended by Google anyway - void checkStreamSetup (OboeStream* stream, int deviceId, int numChannels, int sampleRate, - int bufferSize, oboe::AudioFormat format) + void checkStreamSetup (OboeStream* stream, int deviceId, int numChannels, int expectedSampleRate, + int expectedBufferSize, oboe::AudioFormat format) { if (auto* nativeStream = stream != nullptr ? stream->getNativeStream() : nullptr) { - ignoreUnused (deviceId, numChannels, sampleRate, bufferSize); + ignoreUnused (deviceId, numChannels, sampleRate, expectedBufferSize); ignoreUnused (streamFormat, bitDepth); - jassert (numChannels == nativeStream->getChannelCount()); - jassert (sampleRate == 0 || sampleRate == nativeStream->getSampleRate()); + jassert (numChannels == 0 || numChannels == nativeStream->getChannelCount()); + jassert (expectedSampleRate == 0 || expectedSampleRate == nativeStream->getSampleRate()); jassert (format == nativeStream->getFormat()); } } @@ -706,11 +736,11 @@ class OboeAudioIODevice : public AudioIODevice { public: OboeSessionImpl (OboeAudioIODevice& ownerToUse, - int inputDeviceId, int outputDeviceId, + int inputDeviceIdIn, int outputDeviceIdIn, int numInputChannelsToUse, int numOutputChannelsToUse, int sampleRateToUse, int bufferSizeToUse) : OboeSessionBase (ownerToUse, - inputDeviceId, outputDeviceId, + inputDeviceIdIn, outputDeviceIdIn, numInputChannelsToUse, numOutputChannelsToUse, sampleRateToUse, bufferSizeToUse, OboeAudioIODeviceBufferHelpers::oboeAudioFormat(), @@ -754,7 +784,7 @@ class OboeAudioIODevice : public AudioIODevice if (stream == nullptr || ! openedOk()) return false; - auto result = stream->getNativeStream()->getTimestamp (CLOCK_MONOTONIC, 0, 0); + auto result = stream->getNativeStream()->getTimestamp (CLOCK_MONOTONIC, nullptr, nullptr); return result != oboe::Result::ErrorUnimplemented; } @@ -768,7 +798,6 @@ class OboeAudioIODevice : public AudioIODevice // only output stream should be the master stream receiving callbacks jassert (stream->getDirection() == oboe::Direction::Output && stream == outputStream->getNativeStream()); - //----------------- // Read input from Oboe inputStreamSampleBuffer.clear(); inputStreamNativeBuffer.calloc (static_cast (numInputChannels * bufferSize)); @@ -788,11 +817,13 @@ class OboeAudioIODevice : public AudioIODevice if (result) { - OboeAudioIODeviceBufferHelpers::referAudioBufferDirectlyToOboeIfPossible (inputStreamNativeBuffer.get(), - inputStreamSampleBuffer, - result.value()); + auto referringDirectlyToOboeData = OboeAudioIODeviceBufferHelpers + ::referAudioBufferDirectlyToOboeIfPossible (inputStreamNativeBuffer.get(), + inputStreamSampleBuffer, + result.value()); - OboeAudioIODeviceBufferHelpers::convertFromOboe (inputStreamNativeBuffer.get(), inputStreamSampleBuffer, result.value()); + if (! referringDirectlyToOboeData) + OboeAudioIODeviceBufferHelpers::convertFromOboe (inputStreamNativeBuffer.get(), inputStreamSampleBuffer, result.value()); } else { @@ -803,24 +834,24 @@ class OboeAudioIODevice : public AudioIODevice inputLatency = getLatencyFor (*inputStream); } - //----------------- // Setup output buffer - outputStreamSampleBuffer.clear(); + auto referringDirectlyToOboeData = OboeAudioIODeviceBufferHelpers + ::referAudioBufferDirectlyToOboeIfPossible (static_cast (audioData), + outputStreamSampleBuffer, + numFrames); - OboeAudioIODeviceBufferHelpers::referAudioBufferDirectlyToOboeIfPossible (static_cast (audioData), - outputStreamSampleBuffer, - numFrames); + if (! referringDirectlyToOboeData) + outputStreamSampleBuffer.clear(); - //----------------- // Process // NB: the number of samples read from the input can potentially differ from numFrames. owner.process (inputStreamSampleBuffer.getArrayOfReadPointers(), numInputChannels, outputStreamSampleBuffer.getArrayOfWritePointers(), numOutputChannels, numFrames); - //----------------- // Write output to Oboe - OboeAudioIODeviceBufferHelpers::convertToOboe (outputStreamSampleBuffer, static_cast (audioData), numFrames); + if (! referringDirectlyToOboeData) + OboeAudioIODeviceBufferHelpers::convertToOboe (outputStreamSampleBuffer, static_cast (audioData), numFrames); if (isOutputLatencyDetectionSupported) outputLatency = getLatencyFor (*outputStream); @@ -874,9 +905,7 @@ class OboeAudioIODevice : public AudioIODevice const int64_t appFrameIndex = isOutput ? nativeStream.getFramesWritten() : nativeStream.getFramesRead(); // Assume that the next frame will be processed at the current time - using namespace std::chrono; - int64_t appFrameAppTime = getCurrentTimeNanos();//duration_cast (steady_clock::now().time_since_epoch()).count(); - int64_t appFrameAppTime2 = duration_cast (steady_clock::now().time_since_epoch()).count(); + int64_t appFrameAppTime = getCurrentTimeNanos(); // Calculate the number of frames between app and hardware int64_t frameIndexDelta = appFrameIndex - hardwareFrameIndex; @@ -903,6 +932,8 @@ class OboeAudioIODevice : public AudioIODevice void onErrorBeforeClose (oboe::AudioStream* stream, oboe::Result error) override { + ignoreUnused (error); + // only output stream should be the master stream receiving callbacks jassert (stream->getDirection() == oboe::Direction::Output); @@ -928,7 +959,7 @@ class OboeAudioIODevice : public AudioIODevice Thread::sleep (1); outputStream = nullptr; - outputStream.reset (new OboeStream (-1, + outputStream.reset (new OboeStream (oboe::kUnspecified, oboe::Direction::Output, oboe::SharingMode::Exclusive, numOutputChannels, @@ -980,31 +1011,6 @@ class OboeAudioIODevice : public AudioIODevice bool running = false; - //============================================================================== - static double getNativeSampleRate() - { - return audioManagerGetProperty ("android.media.property.OUTPUT_SAMPLE_RATE").getDoubleValue(); - } - - static int getNativeBufferSize() - { - auto val = audioManagerGetProperty ("android.media.property.OUTPUT_FRAMES_PER_BUFFER").getIntValue(); - return val > 0 ? val : 512; - } - - static bool isProAudioDevice() - { - return androidHasSystemFeature ("android.hardware.audio.pro"); - } - - static int getDefaultFramesPerBurst() - { - // NB: this function only works for inbuilt speakers and headphones - auto framesPerBurstString = javaString (audioManagerGetProperty ("android.media.property.OUTPUT_FRAMES_PER_BUFFER")); - - return framesPerBurstString != 0 ? getEnv()->CallStaticIntMethod (JavaInteger, JavaInteger.parseInt, framesPerBurstString.get(), 10) : 192; - } - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OboeAudioIODevice) }; @@ -1060,9 +1066,6 @@ class OboeAudioIODeviceType : public AudioIODeviceType StringArray getDeviceNames (bool wantInputNames) const override { - if (inputDevices.isEmpty() && outputDevices.isEmpty()) - return StringArray (OboeAudioIODevice::oboeTypeName); - StringArray names; for (auto& device : wantInputNames ? inputDevices : outputDevices) @@ -1071,36 +1074,8 @@ class OboeAudioIODeviceType : public AudioIODeviceType return names; } - int getDefaultDeviceIndex (bool forInput) const override + int getDefaultDeviceIndex (bool) const override { - // No need to create a stream when only one default device is created. - if (! supportsDevicesInfo()) - return 0; - - if (forInput && (! RuntimePermissions::isGranted (RuntimePermissions::recordAudio))) - return 0; - - // Create stream with a default device ID and query the stream for its device ID - using OboeStream = OboeAudioIODevice::OboeStream; - - OboeStream tempStream (-1, - forInput ? oboe::Direction::Input : oboe::Direction::Output, - oboe::SharingMode::Shared, - forInput ? 1 : 2, - getAndroidSDKVersion() >= 21 ? oboe::AudioFormat::Float : oboe::AudioFormat::I16, - (int) OboeAudioIODevice::getNativeSampleRate(), - OboeAudioIODevice::getNativeBufferSize(), - nullptr); - - if (auto* nativeStream = tempStream.getNativeStream()) - { - auto& devices = forInput ? inputDevices : outputDevices; - - for (int i = 0; i < devices.size(); ++i) - if (devices.getReference (i).id == nativeStream->getDeviceId()) - return i; - } - return 0; } @@ -1129,12 +1104,8 @@ class OboeAudioIODeviceType : public AudioIODeviceType auto outputDeviceInfo = getDeviceInfoForName (outputDeviceName, false); auto inputDeviceInfo = getDeviceInfoForName (inputDeviceName, true); - if (outputDeviceInfo.name.isEmpty() && inputDeviceInfo.name.isEmpty()) - { - // Invalid device name passed. It must be one of the names returned by getDeviceNames(). - jassertfalse; + if (outputDeviceInfo.id < 0 && inputDeviceInfo.id < 0) return nullptr; - } auto& name = outputDeviceInfo.name.isNotEmpty() ? outputDeviceInfo.name : inputDeviceInfo.name; @@ -1158,24 +1129,22 @@ class OboeAudioIODeviceType : public AudioIODeviceType private: void checkAvailableDevices() { - if (! supportsDevicesInfo()) - { - auto sampleRates = OboeAudioIODevice::getDefaultSampleRates(); + auto sampleRates = OboeAudioIODevice::getDefaultSampleRates(); - inputDevices .add ({ OboeAudioIODevice::oboeTypeName, -1, sampleRates, 1 }); - outputDevices.add ({ OboeAudioIODevice::oboeTypeName, -1, sampleRates, 2 }); + inputDevices .add ({ "System Default (Input)", oboe::kUnspecified, sampleRates, 1 }); + outputDevices.add ({ "System Default (Output)", oboe::kUnspecified, sampleRates, 2 }); + if (! supportsDevicesInfo()) return; - } auto* env = getEnv(); jclass audioManagerClass = env->FindClass ("android/media/AudioManager"); // We should be really entering here only if API supports it. - jassert (audioManagerClass != 0); + jassert (audioManagerClass != nullptr); - if (audioManagerClass == 0) + if (audioManagerClass == nullptr) return; auto audioManager = LocalRef (env->CallObjectMethod (getAppContext().get(), @@ -1202,6 +1171,8 @@ class OboeAudioIODeviceType : public AudioIODeviceType for (auto& device : inputDevices) { + ignoreUnused (device); + JUCE_OBOE_LOG ("name = " << device.name); JUCE_OBOE_LOG ("id = " << String (device.id)); JUCE_OBOE_LOG ("sample rates size = " << String (device.sampleRates.size())); @@ -1212,6 +1183,8 @@ class OboeAudioIODeviceType : public AudioIODeviceType for (auto& device : outputDevices) { + ignoreUnused (device); + JUCE_OBOE_LOG ("name = " << device.name); JUCE_OBOE_LOG ("id = " << String (device.id)); JUCE_OBOE_LOG ("sample rates size = " << String (device.sampleRates.size())); @@ -1238,9 +1211,13 @@ class OboeAudioIODeviceType : public AudioIODeviceType jmethodID getChannelCountsMethod = env->GetMethodID (deviceClass, "getChannelCounts", "()[I"); jmethodID isSourceMethod = env->GetMethodID (deviceClass, "isSource", "()Z"); - auto name = juceString ((jstring) env->CallObjectMethod (device, getProductNameMethod)); - name << deviceTypeToString (env->CallIntMethod (device, getTypeMethod)); - int id = env->CallIntMethod (device, getIdMethod); + auto deviceTypeString = deviceTypeToString (env->CallIntMethod (device, getTypeMethod)); + + if (deviceTypeString.isEmpty()) // unknown device + return; + + auto name = juceString ((jstring) env->CallObjectMethod (device, getProductNameMethod)) + " " + deviceTypeString; + auto id = env->CallIntMethod (device, getIdMethod); auto jSampleRates = LocalRef ((jintArray) env->CallObjectMethod (device, getSampleRatesMethod)); auto sampleRates = jintArrayToJuceArray (jSampleRates); @@ -1249,40 +1226,42 @@ class OboeAudioIODeviceType : public AudioIODeviceType auto channelCounts = jintArrayToJuceArray (jChannelCounts); int numChannels = channelCounts.isEmpty() ? -1 : channelCounts.getLast(); - bool isInput = env->CallBooleanMethod (device, isSourceMethod); + auto isInput = env->CallBooleanMethod (device, isSourceMethod); auto& devices = isInput ? inputDevices : outputDevices; devices.add ({ name, id, sampleRates, numChannels }); } - static const char* deviceTypeToString (int type) + static String deviceTypeToString (int type) { switch (type) { - case 0: return ""; - case 1: return " built-in earphone speaker"; - case 2: return " built-in speaker"; - case 3: return " wired headset"; - case 4: return " wired headphones"; - case 5: return " line analog"; - case 6: return " line digital"; - case 7: return " Bluetooth device typically used for telephony"; - case 8: return " Bluetooth device supporting the A2DP profile"; - case 9: return " HDMI"; - case 10: return " HDMI audio return channel"; - case 11: return " USB device"; - case 12: return " USB accessory"; - case 13: return " DOCK"; - case 14: return " FM"; - case 15: return " built-in microphone"; - case 16: return " FM tuner"; - case 17: return " TV tuner"; - case 18: return " telephony"; - case 19: return " auxiliary line-level connectors"; - case 20: return " IP"; - case 21: return " BUS"; - case 22: return " USB headset"; - default: jassertfalse; return ""; // type not supported yet, needs to be added! + case 0: return {}; + case 1: return "built-in earphone speaker"; + case 2: return "built-in speaker"; + case 3: return "wired headset"; + case 4: return "wired headphones"; + case 5: return "line analog"; + case 6: return "line digital"; + case 7: return "Bluetooth device typically used for telephony"; + case 8: return "Bluetooth device supporting the A2DP profile"; + case 9: return "HDMI"; + case 10: return "HDMI audio return channel"; + case 11: return "USB device"; + case 12: return "USB accessory"; + case 13: return "DOCK"; + case 14: return "FM"; + case 15: return "built-in microphone"; + case 16: return "FM tuner"; + case 17: return "TV tuner"; + case 18: return "telephony"; + case 19: return "auxiliary line-level connectors"; + case 20: return "IP"; + case 21: return "BUS"; + case 22: return "USB headset"; + case 23: return "hearing aid"; + case 24: return "built-in speaker safe"; + default: jassertfalse; return {}; // type not supported yet, needs to be added! } } @@ -1290,7 +1269,7 @@ class OboeAudioIODeviceType : public AudioIODeviceType { auto* env = getEnv(); - jint* jArrayElems = env->GetIntArrayElements (jArray, 0); + jint* jArrayElems = env->GetIntArrayElements (jArray, nullptr); int numElems = env->GetArrayLength (jArray); Array juceArray; @@ -1305,19 +1284,21 @@ class OboeAudioIODeviceType : public AudioIODeviceType struct DeviceInfo { String name; - int id; + int id = -1; Array sampleRates; int numChannels; }; DeviceInfo getDeviceInfoForName (const String& name, bool isInput) { - if (name.isEmpty()) - return {}; - - for (auto& device : isInput ? inputDevices : outputDevices) - if (device.name == name) - return device; + if (name.isNotEmpty()) + { + for (auto& device : isInput ? inputDevices : outputDevices) + { + if (device.name == name) + return device; + } + } return {}; } @@ -1345,12 +1326,12 @@ class OboeRealtimeThread : private oboe::AudioStreamCallback public: OboeRealtimeThread() - : testStream (new OboeStream (-1, + : testStream (new OboeStream (oboe::kUnspecified, oboe::Direction::Output, oboe::SharingMode::Exclusive, 1, oboe::AudioFormat::Float, - (int) OboeAudioIODevice::getNativeSampleRate(), + (int) AndroidHighPerformanceAudioHelpers::getNativeSampleRate(), OboeAudioIODevice::getNativeBufferSize(), this)), formatUsed (oboe::AudioFormat::Float) @@ -1358,12 +1339,12 @@ class OboeRealtimeThread : private oboe::AudioStreamCallback // Fallback to I16 stream format if Float has not worked if (! testStream->openedOk()) { - testStream.reset (new OboeStream (-1, + testStream.reset (new OboeStream (oboe::kUnspecified, oboe::Direction::Output, oboe::SharingMode::Exclusive, 1, oboe::AudioFormat::I16, - (int) OboeAudioIODevice::getNativeSampleRate(), + (int) AndroidHighPerformanceAudioHelpers::getNativeSampleRate(), OboeAudioIODevice::getNativeBufferSize(), this)); @@ -1411,7 +1392,7 @@ class OboeRealtimeThread : private oboe::AudioStreamCallback threadEntryProc (threadUserPtr); threadEntryProc = nullptr; - MessageManager::callAsync ([this] () { delete this; }); + MessageManager::callAsync ([this]() { delete this; }); return oboe::DataCallbackResult::Stop; } @@ -1434,7 +1415,7 @@ class OboeRealtimeThread : private oboe::AudioStreamCallback } private: - //============================================================================= + //============================================================================== void* (*threadEntryProc) (void*) = nullptr; void* threadUserPtr = nullptr; @@ -1446,15 +1427,19 @@ class OboeRealtimeThread : private oboe::AudioStreamCallback oboe::AudioFormat formatUsed; }; +//============================================================================== pthread_t juce_createRealtimeAudioThread (void* (*entry) (void*), void* userPtr) { - std::unique_ptr thread (new OboeRealtimeThread()); + auto thread = std::make_unique(); if (! thread->isOk()) return {}; auto threadID = thread->startThread (entry, userPtr); - thread.release(); // the thread will de-allocate itself + + // the thread will de-allocate itself + thread.release(); + return threadID; } diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_OpenSL.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_OpenSL.cpp index aabf59b..04f7c79 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_OpenSL.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_android_OpenSL.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. @@ -71,12 +71,11 @@ static void destroyObject (SLObjectType object) (*object)->Destroy (object); } -template <> -struct ContainerDeletePolicy +struct SLObjectItfFree { - static void destroy (SLObjectItf object) + void operator() (SLObjectItf obj) const noexcept { - destroyObject (object); + destroyObject (obj); } }; @@ -112,7 +111,7 @@ class SlObjectRef ControlBlock() = default; ControlBlock (SLObjectItf o) : ptr (o) {} - std::unique_ptr ptr; + std::unique_ptr ptr; }; ReferenceCountedObjectPtr cb; @@ -288,6 +287,40 @@ struct BufferHelpers } }; +//============================================================================== +using CreateEngineFunc = SLresult (*) (SLObjectItf*, SLuint32, const SLEngineOption*, + SLuint32, const SLInterfaceID*, const SLboolean*); + +struct OpenSLEngineHolder +{ + OpenSLEngineHolder() + { + if (auto createEngine = (CreateEngineFunc) slLibrary.getFunction ("slCreateEngine")) + { + SLObjectItf obj = nullptr; + auto err = createEngine (&obj, 0, nullptr, 0, nullptr, nullptr); + + if (err != SL_RESULT_SUCCESS || obj == nullptr || *obj == nullptr + || (*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS) + { + destroyObject (obj); + } + + engine = SlRef::cast (SlObjectRef (obj)); + } + } + + DynamicLibrary slLibrary { "libOpenSLES.so" }; + SlRef engine; +}; + +OpenSLEngineHolder& getEngineHolder() +{ + static OpenSLEngineHolder holder; + return holder; +} + +//============================================================================== class SLRealtimeThread; //============================================================================== @@ -340,7 +373,7 @@ class OpenSLAudioIODevice : public AudioIODevice auto status = (*config)->AcquireJavaProxy (config, /*SL_ANDROID_JAVA_PROXY_ROUTING*/1, &audioRoutingJni); - if (status == SL_RESULT_SUCCESS && audioRoutingJni != 0) + if (status == SL_RESULT_SUCCESS && audioRoutingJni != nullptr) javaProxy = GlobalRef (LocalRef(getEnv()->NewLocalRef (audioRoutingJni))); } } @@ -430,9 +463,11 @@ class OpenSLAudioIODevice : public AudioIODevice SLObjectItf obj = nullptr; - if (auto e = *Base::owner.engine) + auto& holder = getEngineHolder(); + + if (auto e = *holder.engine) { - auto status = e->CreateAudioPlayer (Base::owner.engine, &obj, &source, &sink, 2, + auto status = e->CreateAudioPlayer (holder.engine, &obj, &source, &sink, 2, queueInterfaces, interfaceRequired); if (status != SL_RESULT_SUCCESS || obj == nullptr || (*obj)->Realize(obj, 0) != SL_RESULT_SUCCESS) @@ -473,9 +508,11 @@ class OpenSLAudioIODevice : public AudioIODevice SLObjectItf obj = nullptr; - if (auto e = *Base::owner.engine) + auto& holder = getEngineHolder(); + + if (auto e = *holder.engine) { - auto status = e->CreateAudioRecorder (Base::owner.engine, &obj, &source, &sink, 2, queueInterfaces, interfaceRequired); + auto status = e->CreateAudioRecorder (holder.engine, &obj, &source, &sink, 2, queueInterfaces, interfaceRequired); if (status != SL_RESULT_SUCCESS || obj == nullptr || (*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS) { @@ -514,8 +551,7 @@ class OpenSLAudioIODevice : public AudioIODevice class OpenSLSession { public: - OpenSLSession (DynamicLibrary& slLibraryToUse, - int numInputChannels, int numOutputChannels, + OpenSLSession (int numInputChannels, int numOutputChannels, double samleRateToUse, int bufferSizeToUse, int numBuffersToUse) : inputChannels (numInputChannels), outputChannels (numOutputChannels), @@ -523,25 +559,12 @@ class OpenSLAudioIODevice : public AudioIODevice { jassert (numInputChannels > 0 || numOutputChannels > 0); - if (auto createEngine = (CreateEngineFunc) slLibraryToUse.getFunction ("slCreateEngine")) - { - SLObjectItf obj = nullptr; - auto err = createEngine (&obj, 0, nullptr, 0, nullptr, nullptr); - - if (err != SL_RESULT_SUCCESS || obj == nullptr || *obj == nullptr - || (*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS) - { - destroyObject (obj); - return; - } - - engine = SlRef::cast (SlObjectRef (obj)); - } - if (outputChannels > 0) { + auto& holder = getEngineHolder(); SLObjectItf obj = nullptr; - auto err = (*engine)->CreateOutputMix (engine, &obj, 0, nullptr, nullptr); + + auto err = (*holder.engine)->CreateOutputMix (holder.engine, &obj, 0, nullptr, nullptr); if (err != SL_RESULT_SUCCESS || obj == nullptr || *obj == nullptr || (*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS) @@ -556,7 +579,7 @@ class OpenSLAudioIODevice : public AudioIODevice virtual ~OpenSLSession() {} - virtual bool openedOK() const { return (engine != nullptr && (outputChannels == 0 || (outputMix != nullptr))); } + virtual bool openedOK() const { return (outputChannels == 0 || outputMix != nullptr); } virtual void start() { stop(); jassert (callback.get() != nullptr); running = true; } virtual void stop() { running = false; } @@ -604,22 +627,16 @@ class OpenSLAudioIODevice : public AudioIODevice } } - static OpenSLSession* create (DynamicLibrary& slLibrary, - int numInputChannels, int numOutputChannels, + static OpenSLSession* create (int numInputChannels, int numOutputChannels, double samleRateToUse, int bufferSizeToUse, int numBuffersToUse); - //============================================================================== - using CreateEngineFunc = SLresult (*) (SLObjectItf*, SLuint32, const SLEngineOption*, - SLuint32, const SLInterfaceID*, const SLboolean*); - //============================================================================== int inputChannels, outputChannels; double sampleRate; int bufferSize, numBuffers; bool running = false, audioProcessingEnabled = true; - SlRef engine; SlRef outputMix; Atomic callback { nullptr }; @@ -629,11 +646,10 @@ class OpenSLAudioIODevice : public AudioIODevice class OpenSLSessionT : public OpenSLSession { public: - OpenSLSessionT (DynamicLibrary& slLibraryToUse, - int numInputChannels, int numOutputChannels, + OpenSLSessionT (int numInputChannels, int numOutputChannels, double samleRateToUse, int bufferSizeToUse, int numBuffersToUse) - : OpenSLSession (slLibraryToUse, numInputChannels, numOutputChannels, + : OpenSLSession (numInputChannels, numOutputChannels, samleRateToUse, bufferSizeToUse, numBuffersToUse) { jassert (numInputChannels > 0 || numOutputChannels > 0); @@ -662,7 +678,7 @@ class OpenSLAudioIODevice : public AudioIODevice } const bool supportsUnderrunCount = (getAndroidSDKVersion() >= 24); - getUnderrunCount = supportsUnderrunCount ? getEnv()->GetMethodID (AudioTrack, "getUnderrunCount", "()I") : 0; + getUnderrunCount = supportsUnderrunCount ? getEnv()->GetMethodID (AudioTrack, "getUnderrunCount", "()I") : nullptr; } } } @@ -727,7 +743,7 @@ class OpenSLAudioIODevice : public AudioIODevice int getXRunCount() const noexcept override { - if (player != nullptr && player->javaProxy != nullptr && getUnderrunCount != 0) + if (player != nullptr && player->javaProxy != nullptr && getUnderrunCount != nullptr) return getEnv()->CallIntMethod (player->javaProxy, getUnderrunCount); return -1; @@ -740,7 +756,7 @@ class OpenSLAudioIODevice : public AudioIODevice // only the player or the recorder should enter this section at any time if (guard.compareAndSetBool (1, 0)) { - // are there enough buffers avaialable to process some audio + // are there enough buffers available to process some audio if ((inputChannels == 0 || recorder->isBufferAvailable()) && (outputChannels == 0 || player->isBufferAvailable())) { T* recorderBuffer = (inputChannels > 0 ? recorder->getNextBuffer() : nullptr); @@ -783,7 +799,7 @@ class OpenSLAudioIODevice : public AudioIODevice std::unique_ptr> player; std::unique_ptr> recorder; Atomic guard; - jmethodID getUnderrunCount = 0; + jmethodID getUnderrunCount = nullptr; }; //============================================================================== @@ -803,14 +819,11 @@ class OpenSLAudioIODevice : public AudioIODevice inputLatency = (int) ((longestLatency * inputLatency) / totalLatency) & ~15; outputLatency = (int) ((longestLatency * outputLatency) / totalLatency) & ~15; - bool success = slLibrary.open ("libOpenSLES.so"); - // You can only create this class if you are sure that your hardware supports OpenSL - jassert (success); - ignoreUnused (success); + jassert (getEngineHolder().slLibrary.getNativeHandle() != nullptr); } - ~OpenSLAudioIODevice() + ~OpenSLAudioIODevice() override { close(); } @@ -838,10 +851,11 @@ class OpenSLAudioIODevice : public AudioIODevice static const double rates[] = { 8000.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0, 44100.0, 48000.0 }; + Array retval (rates, numElementsInArray (rates)); - // make sure the native sample rate is pafrt of the list - double native = getNativeSampleRate(); + // make sure the native sample rate is part of the list + double native = AndroidHighPerformanceAudioHelpers::getNativeSampleRate(); if (native != 0.0 && ! retval.contains (native)) retval.add (native); @@ -851,17 +865,8 @@ class OpenSLAudioIODevice : public AudioIODevice Array getAvailableBufferSizes() override { - // we need to offer the lowest possible buffer size which - // is the native buffer size - auto nativeBufferSize = getNativeBufferSize(); - auto minBuffersToQueue = getMinimumBuffersToEnqueue(); - auto maxBuffersToQueue = getMaximumBuffersToEnqueue(); - - Array retval; - for (int i = minBuffersToQueue; i <= maxBuffersToQueue; ++i) - retval.add (i * nativeBufferSize); - - return retval; + return AndroidHighPerformanceAudioHelpers::getAvailableBufferSizes (AndroidHighPerformanceAudioHelpers::getNativeBufferSizeHint(), + getAvailableSampleRates()); } String open (const BigInteger& inputChannels, @@ -873,15 +878,25 @@ class OpenSLAudioIODevice : public AudioIODevice lastError.clear(); - sampleRate = (int) (requestedSampleRate > 0 ? requestedSampleRate : getNativeSampleRate()); + sampleRate = (int) (requestedSampleRate > 0 ? requestedSampleRate : AndroidHighPerformanceAudioHelpers::getNativeSampleRate()); + auto preferredBufferSize = (bufferSize > 0) ? bufferSize : getDefaultBufferSize(); + + audioBuffersToEnqueue = [this, preferredBufferSize] + { + using namespace AndroidHighPerformanceAudioHelpers; + + auto nativeBufferSize = getNativeBufferSizeHint(); + + if (canUseHighPerformanceAudioPath (nativeBufferSize, preferredBufferSize, sampleRate)) + return preferredBufferSize / nativeBufferSize; + - auto totalPreferredBufferSize = (bufferSize <= 0) ? getDefaultBufferSize() : bufferSize; - auto nativeBufferSize = getNativeBufferSize(); - bool useHighPerformanceAudioPath = canUseHighPerformanceAudioPath (totalPreferredBufferSize, sampleRate); + return 1; + }(); - audioBuffersToEnqueue = useHighPerformanceAudioPath ? (totalPreferredBufferSize / nativeBufferSize) : 1; - actualBufferSize = totalPreferredBufferSize / audioBuffersToEnqueue; - jassert ((actualBufferSize * audioBuffersToEnqueue) == totalPreferredBufferSize); + actualBufferSize = preferredBufferSize / audioBuffersToEnqueue; + + jassert ((actualBufferSize * audioBuffersToEnqueue) == preferredBufferSize); activeOutputChans = outputChannels; activeOutputChans.setRange (2, activeOutputChans.getHighestBit(), false); @@ -899,7 +914,7 @@ class OpenSLAudioIODevice : public AudioIODevice lastError = "Error opening OpenSL input device: the app was not granted android.permission.RECORD_AUDIO"; } - session.reset (OpenSLSession::create (slLibrary, numInputChannels, numOutputChannels, + session.reset (OpenSLSession::create (numInputChannels, numOutputChannels, sampleRate, actualBufferSize, audioBuffersToEnqueue)); if (session != nullptr) { @@ -913,15 +928,15 @@ class OpenSLAudioIODevice : public AudioIODevice activeInputChans = BigInteger(0); numInputChannels = 0; - session.reset (OpenSLSession::create (slLibrary, numInputChannels, numOutputChannels, + session.reset (OpenSLSession::create (numInputChannels, numOutputChannels, sampleRate, actualBufferSize, audioBuffersToEnqueue)); } } DBG ("OpenSL: numInputChannels = " << numInputChannels << ", numOutputChannels = " << numOutputChannels - << ", nativeBufferSize = " << getNativeBufferSize() - << ", nativeSampleRate = " << getNativeSampleRate() + << ", nativeBufferSize = " << AndroidHighPerformanceAudioHelpers::getNativeBufferSizeHint() + << ", nativeSampleRate = " << AndroidHighPerformanceAudioHelpers::getNativeSampleRate() << ", actualBufferSize = " << actualBufferSize << ", audioBuffersToEnqueue = " << audioBuffersToEnqueue << ", sampleRate = " << sampleRate @@ -954,16 +969,13 @@ class OpenSLAudioIODevice : public AudioIODevice int getDefaultBufferSize() override { - auto defaultBufferLength = (hasLowLatencyAudioPath() ? defaultBufferSizeForLowLatencyDeviceMs - : defaultBufferSizeForStandardLatencyDeviceMs); - - auto defaultBuffersToEnqueue = buffersToQueueForBufferDuration (defaultBufferLength, getCurrentSampleRate()); - return defaultBuffersToEnqueue * getNativeBufferSize(); + return AndroidHighPerformanceAudioHelpers::getDefaultBufferSize (AndroidHighPerformanceAudioHelpers::getNativeBufferSizeHint(), + getCurrentSampleRate()); } double getCurrentSampleRate() override { - return (sampleRate == 0.0 ? getNativeSampleRate() : sampleRate); + return (sampleRate == 0.0 ? AndroidHighPerformanceAudioHelpers::getNativeSampleRate() : sampleRate); } void start (AudioIODeviceCallback* newCallback) override @@ -1025,7 +1037,6 @@ class OpenSLAudioIODevice : public AudioIODevice friend class SLRealtimeThread; //============================================================================== - DynamicLibrary slLibrary; int actualBufferSize = 0, sampleRate = 0, audioBuffersToEnqueue = 0; int inputLatency, outputLatency; bool deviceOpen = false, audioProcessingEnabled = true; @@ -1035,96 +1046,10 @@ class OpenSLAudioIODevice : public AudioIODevice std::unique_ptr session; - enum - { - defaultBufferSizeForLowLatencyDeviceMs = 40, - defaultBufferSizeForStandardLatencyDeviceMs = 100 - }; - - static int getMinimumBuffersToEnqueue (double sampleRateToCheck = getNativeSampleRate()) - { - if (canUseHighPerformanceAudioPath (getNativeBufferSize(), (int) sampleRateToCheck)) - { - // see https://developer.android.com/ndk/guides/audio/opensl/opensl-prog-notes.html#sandp - // "For Android 4.2 (API level 17) and earlier, a buffer count of two or more is required - // for lower latency. Beginning with Android 4.3 (API level 18), a buffer count of one - // is sufficient for lower latency." - return (getAndroidSDKVersion() >= 18 ? 1 : 2); - } - - // we will not use the low-latency path so we can use the absolute minimum number of buffers - // to queue - return 1; - } - - int getMaximumBuffersToEnqueue() noexcept - { - constexpr auto maxBufferSizeMs = 200; - - auto availableSampleRates = getAvailableSampleRates(); - auto maximumSampleRate = findMaximum(availableSampleRates.getRawDataPointer(), availableSampleRates.size()); - - // ensure we don't return something crazy small - return jmax (8, buffersToQueueForBufferDuration (maxBufferSizeMs, maximumSampleRate)); - } - - static int buffersToQueueForBufferDuration (int bufferDurationInMs, double sampleRate) noexcept - { - auto maxBufferFrames = static_cast (std::ceil (bufferDurationInMs * sampleRate / 1000.0)); - auto maxNumBuffers = static_cast (std::ceil (static_cast (maxBufferFrames) - / static_cast (getNativeBufferSize()))); - - return jmax (getMinimumBuffersToEnqueue (sampleRate), maxNumBuffers); - } - - //============================================================================== - static double getNativeSampleRate() - { - return audioManagerGetProperty ("android.media.property.OUTPUT_SAMPLE_RATE").getDoubleValue(); - } - - static int getNativeBufferSize() - { - const int val = audioManagerGetProperty ("android.media.property.OUTPUT_FRAMES_PER_BUFFER").getIntValue(); - return val > 0 ? val : 512; - } - - static bool isProAudioDevice() - { - return androidHasSystemFeature ("android.hardware.audio.pro") || isSapaSupported(); - } - - static bool hasLowLatencyAudioPath() - { - return androidHasSystemFeature ("android.hardware.audio.low_latency"); - } - - static bool canUseHighPerformanceAudioPath (int requestedBufferSize, int requestedSampleRate) - { - return ((requestedBufferSize % getNativeBufferSize()) == 0) - && (requestedSampleRate == getNativeSampleRate()) - && isProAudioDevice(); - } - - //============================================================================== - // Some minimum Sapa support to check if this device supports pro audio - static bool isSamsungDevice() - { - return SystemStats::getDeviceManufacturer().containsIgnoreCase ("SAMSUNG"); - } - - static bool isSapaSupported() - { - static bool supported = isSamsungDevice() && DynamicLibrary().open ("libapa_jni.so"); - - return supported; - } - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenSLAudioIODevice) }; -OpenSLAudioIODevice::OpenSLSession* OpenSLAudioIODevice::OpenSLSession::create (DynamicLibrary& slLibrary, - int numInputChannels, int numOutputChannels, +OpenSLAudioIODevice::OpenSLSession* OpenSLAudioIODevice::OpenSLSession::create (int numInputChannels, int numOutputChannels, double samleRateToUse, int bufferSizeToUse, int numBuffersToUse) { @@ -1134,7 +1059,7 @@ OpenSLAudioIODevice::OpenSLSession* OpenSLAudioIODevice::OpenSLSession::create ( // SDK versions 21 and higher should natively support floating point... if (sdkVersion >= 21) { - retval.reset (new OpenSLSessionT (slLibrary, numInputChannels, numOutputChannels, samleRateToUse, + retval.reset (new OpenSLSessionT (numInputChannels, numOutputChannels, samleRateToUse, bufferSizeToUse, numBuffersToUse)); // ...however, some devices lie so re-try without floating point @@ -1144,7 +1069,7 @@ OpenSLAudioIODevice::OpenSLSession* OpenSLAudioIODevice::OpenSLSession::create ( if (retval == nullptr) { - retval.reset (new OpenSLSessionT (slLibrary, numInputChannels, numOutputChannels, samleRateToUse, + retval.reset (new OpenSLSessionT (numInputChannels, numOutputChannels, samleRateToUse, bufferSizeToUse, numBuffersToUse)); if (retval != nullptr && (! retval->openedOK())) @@ -1186,9 +1111,6 @@ class OpenSLAudioDeviceType : public AudioIODeviceType return library.open ("libOpenSLES.so"); } -private: - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenSLAudioDeviceType) }; @@ -1211,7 +1133,7 @@ class SLRealtimeThread SLRealtimeThread() { - if (auto createEngine = (OpenSLAudioIODevice::OpenSLSession::CreateEngineFunc) slLibrary.getFunction ("slCreateEngine")) + if (auto createEngine = (CreateEngineFunc) slLibrary.getFunction ("slCreateEngine")) { SLObjectItf obj = nullptr; auto err = createEngine (&obj, 0, nullptr, 0, nullptr, nullptr); @@ -1254,7 +1176,7 @@ class SLRealtimeThread SLDataLocator_OutputMix outputMixLocator = {SL_DATALOCATOR_OUTPUTMIX, outputMix}; PCMDataFormatEx dataFormat; - BufferHelpers::initPCMDataFormat (dataFormat, 1, OpenSLAudioIODevice::getNativeSampleRate()); + BufferHelpers::initPCMDataFormat (dataFormat, 1, AndroidHighPerformanceAudioHelpers::getNativeSampleRate()); SLDataSource source = { &queueLocator, &dataFormat }; SLDataSink sink = { &outputMixLocator, nullptr }; @@ -1297,7 +1219,7 @@ class SLRealtimeThread } } - bool isOK() const { return queue != nullptr; } + bool isOk() const { return queue != nullptr; } pthread_t startThread (void* (*entry) (void*), void* userPtr) { @@ -1337,18 +1259,18 @@ class SLRealtimeThread threadEntryProc = nullptr; (*player)->SetPlayState (player, SL_PLAYSTATE_STOPPED); - MessageManager::callAsync ([this] () { delete this; }); + MessageManager::callAsync ([this]() { delete this; }); } } private: - //============================================================================= + //============================================================================== static void staticFinished (SLAndroidSimpleBufferQueueItf, void* context) { static_cast (context)->finished(); } - //============================================================================= + //============================================================================== DynamicLibrary slLibrary { "libOpenSLES.so" }; SlRef engine; @@ -1356,7 +1278,7 @@ class SLRealtimeThread SlRef player; SlRef queue; - int bufferSize = OpenSLAudioIODevice::getNativeBufferSize(); + int bufferSize = AndroidHighPerformanceAudioHelpers::getNativeBufferSizeHint(); HeapBlock buffer { HeapBlock (static_cast (1 * bufferSize * numBuffers)) }; void* (*threadEntryProc) (void*) = nullptr; @@ -1367,14 +1289,15 @@ class SLRealtimeThread pthread_t threadID; }; +//============================================================================== pthread_t juce_createRealtimeAudioThread (void* (*entry) (void*), void* userPtr) { - std::unique_ptr thread (new SLRealtimeThread); + auto thread = std::make_unique(); - if (! thread->isOK()) - return 0; + if (! thread->isOk()) + return {}; - pthread_t threadID = thread->startThread (entry, userPtr); + auto threadID = thread->startThread (entry, userPtr); // the thread will de-allocate itself thread.release(); diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_ios_Audio.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_ios_Audio.cpp index 9ff7a08..674bc44 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_ios_Audio.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_ios_Audio.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. @@ -216,7 +216,7 @@ class iOSAudioIODeviceType : public AudioIODeviceType, { public: iOSAudioIODeviceType(); - ~iOSAudioIODeviceType(); + ~iOSAudioIODeviceType() override; void scanForDevices() override; StringArray getDeviceNames (bool) const override; @@ -262,7 +262,7 @@ struct iOSAudioIODevice::Pimpl : public AudioPlayHead, sessionHolder->activeDevices.add (this); } - ~Pimpl() + ~Pimpl() override { sessionHolder->activeDevices.removeFirstMatchingValue (this); @@ -671,6 +671,7 @@ struct iOSAudioIODevice::Pimpl : public AudioPlayHead, //============================================================================== #if JUCE_MODULE_AVAILABLE_juce_graphics + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") Image getIcon (int size) { if (interAppAudioConnected) @@ -681,6 +682,7 @@ struct iOSAudioIODevice::Pimpl : public AudioPlayHead, } return Image(); } + JUCE_END_IGNORE_WARNINGS_GCC_LIKE #endif void switchApplication() @@ -698,7 +700,7 @@ struct iOSAudioIODevice::Pimpl : public AudioPlayHead, &dataSize); if (err == noErr) { - #if (! defined __IPHONE_OS_VERSION_MIN_REQUIRED) || (! defined __IPHONE_10_0) || (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_10_0) + #if (! defined __IPHONE_10_0) || (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_10_0) [[UIApplication sharedApplication] openURL: (NSURL*)hostUrl]; #else [[UIApplication sharedApplication] openURL: (NSURL*)hostUrl options: @{} completionHandler: nil]; diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_ios_Audio.h b/JuceLibraryCode/modules/juce_audio_devices/native/juce_ios_Audio.h index d5e2a4f..45d3ef2 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_ios_Audio.h +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_ios_Audio.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_devices/native/juce_linux_ALSA.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_ALSA.cpp index d51687a..18a1238 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_ALSA.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_ALSA.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. @@ -261,7 +261,7 @@ class ALSADevice unsigned int periods = 4; snd_pcm_uframes_t samplesPerPeriod = (snd_pcm_uframes_t) bufferSize; - if (JUCE_ALSA_FAILED (snd_pcm_hw_params_set_rate_near (handle, hwParams, &sampleRate, 0)) + if (JUCE_ALSA_FAILED (snd_pcm_hw_params_set_rate_near (handle, hwParams, &sampleRate, nullptr)) || JUCE_ALSA_FAILED (snd_pcm_hw_params_set_channels (handle, hwParams, (unsigned int ) numChannels)) || JUCE_ALSA_FAILED (snd_pcm_hw_params_set_periods_near (handle, hwParams, &periods, &dir)) || JUCE_ALSA_FAILED (snd_pcm_hw_params_set_period_size_near (handle, hwParams, &samplesPerPeriod, &dir)) @@ -494,7 +494,7 @@ class ALSAThread : public Thread initialiseRatesAndChannels(); } - ~ALSAThread() + ~ALSAThread() override { close(); } @@ -722,7 +722,7 @@ class ALSAThread : public Thread else { for (int i = 0; i < outputChannelDataForCallback.size(); ++i) - zeromem (outputChannelDataForCallback[i], sizeof (float) * (size_t) bufferSize); + zeromem (outputChannelDataForCallback[i], (size_t) bufferSize * sizeof (float)); } } @@ -791,7 +791,7 @@ class ALSAThread : public Thread //============================================================================== const String inputId, outputId; std::unique_ptr outputDevice, inputDevice; - int numCallbacks = 0; + std::atomic numCallbacks { 0 }; bool audioIoInProgress = false; CriticalSection callbackLock; @@ -853,7 +853,7 @@ class ALSAAudioIODevice : public AudioIODevice { } - ~ALSAAudioIODevice() + ~ALSAAudioIODevice() override { close(); } @@ -1249,7 +1249,7 @@ class ALSAAudioIODeviceType : public AudioIODeviceType snd_device_name_free_hint (hints); } - // sometimes the "default" device is not listed, but it is nice to see it explicitely in the list + // sometimes the "default" device is not listed, but it is nice to see it explicitly in the list if (! outputIds.contains ("default")) testDevice ("default", "Default ALSA Output", "Default ALSA Input"); diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_Bela.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_Bela.cpp index 2d7702d..49112d4 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_Bela.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_Bela.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. @@ -34,6 +34,8 @@ class BelaMidiInput { jassert (midiCallback != nullptr); midiInputs.add (this); + + buffer.resize (32); } ~BelaMidiInput() @@ -54,6 +56,8 @@ class BelaMidiInput void poll() { + size_t receivedBytes = 0; + for (;;) { auto data = midi.getInput(); @@ -61,14 +65,23 @@ class BelaMidiInput if (data < 0) break; - auto byte = (uint8) data; - concatenator.pushMidiData (&byte, 1, 0.0, midiInput, *midiCallback); + buffer[receivedBytes] = (uint8) data; + receivedBytes++; + + if (receivedBytes == buffer.size()) + { + pushMidiData (static_cast (receivedBytes)); + receivedBytes = 0; + } } + + if (receivedBytes > 0) + pushMidiData (receivedBytes); } - static StringArray getDevices (bool input) + static Array getDevices (bool input) { - StringArray devices; + Array devices; for (auto& card : findAllALSACardIDs()) findMidiDevices (devices, input, card); @@ -76,7 +89,19 @@ class BelaMidiInput return devices; } + void pushMidiMessage (juce::MidiMessage& message) + { + concatenator.pushMidiData (message.getRawData(), message.getRawDataSize(), Time::getMillisecondCounter() * 0.001, midiInput, *midiCallback); + } + private: + void pushMidiData (int length) + { + concatenator.pushMidiData (buffer.data(), length, Time::getMillisecondCounter() * 0.001, midiInput, *midiCallback); + } + + std::vector buffer; + static Array findAllALSACardIDs() { Array cards; @@ -96,7 +121,7 @@ class BelaMidiInput } // Adds all midi devices to the devices array of the given input/output type on the given card - static void findMidiDevices (StringArray& devices, bool input, int cardNum) + static void findMidiDevices (Array& devices, bool input, int cardNum) { snd_ctl_t* ctl = nullptr; auto status = snd_ctl_open (&ctl, ("hw:" + String (cardNum)).toRawUTF8(), 0); @@ -124,24 +149,25 @@ class BelaMidiInput auto subCount = snd_rawmidi_info_get_subdevices_count (info); - for (int sub = 0; sub < subCount; ++sub) + for (size_t sub = 0; sub < subCount; ++sub) { snd_rawmidi_info_set_subdevice (info, sub); status = snd_ctl_rawmidi_info (ctl, info); if (status == 0) - devices.add ("hw:" + String (cardNum) + "," - + String (device) + "," - + String (sub)); + { + String deviceName ("hw:" + String (cardNum) + "," + String (device) + "," + String (sub)); + devices.add (MidiDeviceInfo (deviceName, deviceName)); + } } } snd_ctl_close (ctl); } - String midiPort; MidiInput* const midiInput; + String midiPort; MidiInputCallback* const midiCallback; Midi midi; @@ -169,8 +195,26 @@ class BelaAudioIODevice : public AudioIODevice } //============================================================================== - StringArray getOutputChannelNames() override { return { "Out #1", "Out #2" }; } - StringArray getInputChannelNames() override { return { "In #1", "In #2" }; } + StringArray getOutputChannelNames() override + { + StringArray result; + + for (int i = 1; i <= actualNumberOfOutputs; i++) + result.add ("Out #" + std::to_string (i)); + + return result; + } + + StringArray getInputChannelNames() override + { + StringArray result; + + for (int i = 1; i <= actualNumberOfInputs; i++) + result.add ("In #" + std::to_string (i)); + + return result; + } + Array getAvailableSampleRates() override { return { 44100.0 }; } Array getAvailableBufferSizes() override { /* TODO: */ return { getDefaultBufferSize() }; } int getDefaultBufferSize() override { return defaultSettings.periodSize; } @@ -192,15 +236,27 @@ class BelaAudioIODevice : public AudioIODevice auto numIns = getNumContiguousSetBits (inputChannels); auto numOuts = getNumContiguousSetBits (outputChannels); - settings.useAnalog = 0; - settings.useDigital = 0; - settings.numAudioInChannels = numIns; - settings.numAudioOutChannels = numOuts; + // Input and Output channels are numbered as follows + // + // 0 .. 1 - audio + // 2 .. 9 - analog + + if (numIns > 2 || numOuts > 2) + { + settings.useAnalog = true; + settings.numAnalogInChannels = std::max (numIns - 2, 8); + settings.numAnalogOutChannels = std::max (numOuts - 2, 8); + settings.uniformSampleRate = true; + } + + settings.numAudioInChannels = std::max (numIns, 2); + settings.numAudioOutChannels = std::max (numOuts, 2); + settings.detectUnderruns = 1; settings.setup = setupCallback; settings.render = renderCallback; settings.cleanup = cleanupCallback; - settings.interleave = 1; + settings.interleave = 0; if (bufferSizeSamples > 0) settings.periodSize = bufferSizeSamples; @@ -219,10 +275,7 @@ class BelaAudioIODevice : public AudioIODevice actualNumberOfInputs = jmin (numIns, actualNumberOfInputs); actualNumberOfOutputs = jmin (numOuts, actualNumberOfOutputs); - audioInBuffer.setSize (actualNumberOfInputs, actualBufferSize); channelInBuffer.calloc (actualNumberOfInputs); - - audioOutBuffer.setSize (actualNumberOfOutputs, actualBufferSize); channelOutBuffer.calloc (actualNumberOfOutputs); return {}; @@ -244,10 +297,7 @@ class BelaAudioIODevice : public AudioIODevice actualNumberOfInputs = 0; actualNumberOfOutputs = 0; - audioInBuffer.setSize (0, 0); channelInBuffer.free(); - - audioOutBuffer.setSize (0, 0); channelOutBuffer.free(); } } @@ -277,9 +327,6 @@ class BelaAudioIODevice : public AudioIODevice } else { - audioInBuffer.clear(); - audioOutBuffer.clear(); - callback = newCallback; isRunning = (Bela_startAudio() == 0); @@ -321,23 +368,24 @@ class BelaAudioIODevice : public AudioIODevice //============================================================================== int getCurrentBufferSizeSamples() override { return actualBufferSize; } double getCurrentSampleRate() override { return 44100.0; } - int getCurrentBitDepth() override { return 24; } + int getCurrentBitDepth() override { return 16; } BigInteger getActiveOutputChannels() const override { BigInteger b; b.setRange (0, actualNumberOfOutputs, true); return b; } BigInteger getActiveInputChannels() const override { BigInteger b; b.setRange (0, actualNumberOfInputs, true); return b; } int getOutputLatencyInSamples() override { /* TODO */ return 0; } int getInputLatencyInSamples() override { /* TODO */ return 0; } - int getXRunCount() const noexcept { return underruns; } + int getXRunCount() const noexcept override { return underruns; } //============================================================================== static const char* const belaTypeName; private: + //============================================================================== bool setup (BelaContext& context) { actualBufferSize = context.audioFrames; - actualNumberOfInputs = context.audioInChannels; - actualNumberOfOutputs = context.audioOutChannels; + actualNumberOfInputs = context.audioInChannels + context.analogInChannels; + actualNumberOfOutputs = context.audioOutChannels + context.analogOutChannels; isBelaOpen = true; firstCallback = true; @@ -363,59 +411,29 @@ class BelaAudioIODevice : public AudioIODevice if (callback != nullptr) { jassert (context.audioFrames <= actualBufferSize); - auto numSamples = jmin (context.audioFrames, actualBufferSize); - auto interleaved = ((context.flags & BELA_FLAG_INTERLEAVED) != 0); - auto numIns = jmin (actualNumberOfInputs, (int) context.audioInChannels); - auto numOuts = jmin (actualNumberOfOutputs, (int) context.audioOutChannels); - - int ch; + jassert ((context.flags & BELA_FLAG_INTERLEAVED) == 0); - if (interleaved && context.audioInChannels > 1) - { - for (ch = 0; ch < numIns; ++ch) - { - using DstSampleType = AudioData::Pointer; - using SrcSampleType = AudioData::Pointer; - - channelInBuffer[ch] = audioInBuffer.getWritePointer (ch); - DstSampleType dstData (audioInBuffer.getWritePointer (ch)); - SrcSampleType srcData (context.audioIn + ch, context.audioInChannels); - dstData.convertSamples (srcData, numSamples); - } - } - else + // Setup channelInBuffers + for (int ch = 0; ch < actualNumberOfInputs; ++ch) { - for (ch = 0; ch < numIns; ++ch) - channelInBuffer[ch] = context.audioIn + (ch * numSamples); + if (ch < analogChannelStart) + channelInBuffer[ch] = &context.audioIn[ch * context.audioFrames]; + else + channelInBuffer[ch] = &context.analogIn[(ch - analogChannelStart) * context.analogFrames]; } - for (; ch < actualNumberOfInputs; ++ch) + // Setup channelOutBuffers + for (int ch = 0; ch < actualNumberOfOutputs; ++ch) { - channelInBuffer[ch] = audioInBuffer.getWritePointer(ch); - zeromem (audioInBuffer.getWritePointer (ch), sizeof (float) * numSamples); + if (ch < analogChannelStart) + channelOutBuffer[ch] = &context.audioOut[ch * context.audioFrames]; + else + channelOutBuffer[ch] = &context.analogOut[(ch - analogChannelStart) * context.audioFrames]; } - for (int i = 0; i < actualNumberOfOutputs; ++i) - channelOutBuffer[i] = ((interleaved && context.audioOutChannels > 1) || i >= context.audioOutChannels ? audioOutBuffer.getWritePointer (i) - : context.audioOut + (i * numSamples)); - callback->audioDeviceIOCallback (channelInBuffer.getData(), actualNumberOfInputs, channelOutBuffer.getData(), actualNumberOfOutputs, - numSamples); - - if (interleaved && context.audioOutChannels > 1) - { - for (int i = 0; i < numOuts; ++i) - { - using DstSampleType = AudioData::Pointer; - using SrcSampleType = AudioData::Pointer; - - SrcSampleType srcData (channelOutBuffer[i]); - DstSampleType dstData (context.audioOut + i, context.audioOutChannels); - - dstData.convertSamples (srcData, numSamples); - } - } + context.audioFrames); } } @@ -427,6 +445,7 @@ class BelaAudioIODevice : public AudioIODevice callback->audioDeviceStopped(); } + const int analogChannelStart = 2; //============================================================================== uint64_t expectedElapsedAudioSamples = 0; @@ -469,10 +488,11 @@ class BelaAudioIODevice : public AudioIODevice uint32_t actualBufferSize = 0; int actualNumberOfInputs = 0, actualNumberOfOutputs = 0; - AudioBuffer audioInBuffer, audioOutBuffer; HeapBlock channelInBuffer; HeapBlock channelOutBuffer; + bool includeAnalogSupport; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BelaAudioIODevice) }; @@ -483,7 +503,6 @@ struct BelaAudioIODeviceType : public AudioIODeviceType { BelaAudioIODeviceType() : AudioIODeviceType ("Bela") {} - // TODO: support analog outputs StringArray getDeviceNames (bool) const override { return StringArray (BelaAudioIODevice::belaTypeName); } void scanForDevices() override {} int getDefaultDeviceIndex (bool) const override { return 0; } @@ -492,6 +511,7 @@ struct BelaAudioIODeviceType : public AudioIODeviceType AudioIODevice* createDevice (const String& outputName, const String& inputName) override { + // TODO: switching whether to support analog/digital with possible multiple Bela device types? if (outputName == BelaAudioIODevice::belaTypeName || inputName == BelaAudioIODevice::belaTypeName) return new BelaAudioIODevice(); @@ -507,58 +527,74 @@ AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_Bela() return new BelaAudioIODeviceType(); } - //============================================================================== -// TODO: Add Bela MidiOutput support - -StringArray MidiOutput::getDevices() { return {}; } -int MidiOutput::getDefaultDeviceIndex() { return 0; } -MidiOutput* MidiOutput::openDevice (int) { return {}; } -MidiOutput* MidiOutput::createNewDevice (const String&) { return {}; } -MidiOutput::~MidiOutput() {} -void MidiOutput::sendMessageNow (const MidiMessage&) {} +MidiInput::MidiInput (const String& deviceName, const String& deviceID) + : deviceInfo (deviceName, deviceID) +{ +} +MidiInput::~MidiInput() { delete static_cast (internal); } +void MidiInput::start() { static_cast (internal)->start(); } +void MidiInput::stop() { static_cast (internal)->stop(); } -//============================================================================== -MidiInput::MidiInput (const String& nm) : name (nm) {} - -MidiInput::~MidiInput() +Array MidiInput::getAvailableDevices() { - delete static_cast (internal); + return BelaMidiInput::getDevices (true); } -void MidiInput::start() { static_cast (internal)->start(); } -void MidiInput::stop() { static_cast (internal)->stop(); } +MidiDeviceInfo MidiInput::getDefaultDevice() +{ + return getAvailableDevices().getFirst(); +} -int MidiInput::getDefaultDeviceIndex() +std::unique_ptr MidiInput::openDevice (const String& deviceIdentifier, MidiInputCallback* callback) { - return 0; + if (deviceIdentifier.isEmpty()) + return {}; + + std::unique_ptr midiInput (new MidiInput (deviceIdentifier, deviceIdentifier)); + midiInput->internal = new BelaMidiInput (deviceIdentifier, midiInput.get(), callback); + + return midiInput; } -StringArray MidiInput::getDevices() +std::unique_ptr MidiInput::createNewDevice (const String&, MidiInputCallback*) { - return BelaMidiInput::getDevices (true); + // N/A on Bela + jassertfalse; + return {}; } -MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) +StringArray MidiInput::getDevices() { - auto devices = getDevices(); + StringArray deviceNames; - if (index >= 0 && index < devices.size()) - { - auto deviceName = devices[index]; - auto result = new MidiInput (deviceName); - result->internal = new BelaMidiInput (deviceName, result, callback); - return result; - } + for (auto& d : getAvailableDevices()) + deviceNames.add (d.name); - return {}; + return deviceNames; } -MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallback* callback) +int MidiInput::getDefaultDeviceIndex() { - jassertfalse; // N/A on Bela - return {}; + return 0; +} + +std::unique_ptr MidiInput::openDevice (int index, MidiInputCallback* callback) +{ + return openDevice (getAvailableDevices()[index].identifier, callback); } +//============================================================================== +// TODO: Add Bela MidiOutput support +MidiOutput::~MidiOutput() {} +void MidiOutput::sendMessageNow (const MidiMessage&) {} +Array MidiOutput::getAvailableDevices() { return {}; } +MidiDeviceInfo MidiOutput::getDefaultDevice() { return {}; } +std::unique_ptr MidiOutput::openDevice (const String&) { return {}; } +std::unique_ptr MidiOutput::createNewDevice (const String&) { return {}; } +StringArray MidiOutput::getDevices() { return {}; } +int MidiOutput::getDefaultDeviceIndex() { return 0;} +std::unique_ptr MidiOutput::openDevice (int) { return {}; } + } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_JackAudio.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_JackAudio.cpp index 8759d28..3ab41a4 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_JackAudio.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_JackAudio.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. @@ -105,7 +105,11 @@ namespace //============================================================================== #ifndef JUCE_JACK_CLIENT_NAME - #define JUCE_JACK_CLIENT_NAME "JUCEJack" + #ifdef JucePlugin_Name + #define JUCE_JACK_CLIENT_NAME JucePlugin_Name + #else + #define JUCE_JACK_CLIENT_NAME "JUCEJack" + #endif #endif struct JackPortIterator diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_Midi.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_Midi.cpp index 2d0711e..d648a8e 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_Midi.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_Midi.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. @@ -67,12 +67,12 @@ class AlsaClient : public ReferenceCountedObject static String getAlsaMidiName() { #ifdef JUCE_ALSA_MIDI_NAME - return JUCE_ALSA_MIDI_NAME; + return JUCE_ALSA_MIDI_NAME; #else - if (auto* app = JUCEApplicationBase::getInstance()) - return app->getApplicationName(); + if (auto* app = JUCEApplicationBase::getInstance()) + return app->getApplicationName(); - return "JUCE"; + return "JUCE"; #endif } @@ -198,7 +198,8 @@ class AlsaClient : public ReferenceCountedObject isInput ? (SND_SEQ_PORT_CAP_WRITE | (enableSubscription ? SND_SEQ_PORT_CAP_SUBS_WRITE : 0)) : (SND_SEQ_PORT_CAP_READ | (enableSubscription ? SND_SEQ_PORT_CAP_SUBS_READ : 0)); - portId = snd_seq_create_simple_port (seqHandle, name.toUTF8(), caps, + portName = name; + portId = snd_seq_create_simple_port (seqHandle, portName.toUTF8(), caps, SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION); } @@ -215,13 +216,15 @@ class AlsaClient : public ReferenceCountedObject } AlsaClient& client; + MidiInputCallback* callback = nullptr; snd_midi_event_t* midiParser = nullptr; MidiInput* midiInput = nullptr; - int maxEventSize = 4096; - int portId = -1; - bool callbackEnabled = false; - bool isInput = false; + + String portName; + + int maxEventSize = 4096, portId = -1; + bool callbackEnabled = false, isInput = false; }; static Ptr getInstance() @@ -276,7 +279,7 @@ class AlsaClient : public ReferenceCountedObject void deletePort (Port* port) { - ports.remove (port->portId); + ports.set (port->portId, nullptr); decReferenceCount(); } @@ -359,11 +362,16 @@ class AlsaClient : public ReferenceCountedObject AlsaClient* AlsaClient::instance = nullptr; //============================================================================== +static String getFormattedPortIdentifier (int clientId, int portId) +{ + return String (clientId) + "-" + String (portId); +} + static AlsaClient::Port* iterateMidiClient (const AlsaClient::Ptr& client, snd_seq_client_info_t* clientInfo, bool forInput, - StringArray& deviceNamesFound, - int deviceIndexToOpen) + Array& devices, + const String& deviceIdentifierToOpen) { AlsaClient::Port* port = nullptr; @@ -371,7 +379,7 @@ static AlsaClient::Port* iterateMidiClient (const AlsaClient::Ptr& client, snd_seq_port_info_t* portInfo = nullptr; snd_seq_port_info_alloca (&portInfo); - jassert (portInfo); + jassert (portInfo != nullptr); auto numPorts = snd_seq_client_info_get_num_ports (clientInfo); auto sourceClient = snd_seq_client_info_get_client (clientInfo); @@ -384,19 +392,19 @@ static AlsaClient::Port* iterateMidiClient (const AlsaClient::Ptr& client, && (snd_seq_port_info_get_capability (portInfo) & (forInput ? SND_SEQ_PORT_CAP_SUBS_READ : SND_SEQ_PORT_CAP_SUBS_WRITE)) != 0) { - String portName = snd_seq_port_info_get_name(portInfo); + String portName (snd_seq_port_info_get_name (portInfo)); + auto portID = snd_seq_port_info_get_port (portInfo); - deviceNamesFound.add (portName); + MidiDeviceInfo device (portName, getFormattedPortIdentifier (sourceClient, portID)); + devices.add (device); - if (deviceNamesFound.size() == deviceIndexToOpen + 1) + if (deviceIdentifierToOpen.isNotEmpty() && deviceIdentifierToOpen == device.identifier) { - auto sourcePort = snd_seq_port_info_get_port (portInfo); - - if (sourcePort != -1) + if (portID != -1) { port = client->createPort (portName, forInput, false); jassert (port->isValid()); - port->connectWith (sourceClient, sourcePort); + port->connectWith (sourceClient, portID); break; } } @@ -407,8 +415,8 @@ static AlsaClient::Port* iterateMidiClient (const AlsaClient::Ptr& client, } static AlsaClient::Port* iterateMidiDevices (bool forInput, - StringArray& deviceNamesFound, - int deviceIndexToOpen) + Array& devices, + const String& deviceIdentifierToOpen) { AlsaClient::Port* port = nullptr; auto client = AlsaClient::getInstance(); @@ -432,85 +440,96 @@ static AlsaClient::Port* iterateMidiDevices (bool forInput, { if (snd_seq_query_next_client (seqHandle, clientInfo) == 0) { - auto sourceClient = snd_seq_client_info_get_client (clientInfo); + port = iterateMidiClient (client, clientInfo, forInput, + devices, deviceIdentifierToOpen); - if (sourceClient != client->getId() && sourceClient != SND_SEQ_CLIENT_SYSTEM) - { - port = iterateMidiClient (client, clientInfo, forInput, - deviceNamesFound, deviceIndexToOpen); - if (port != nullptr) - break; - } + if (port != nullptr) + break; } } } } - deviceNamesFound.appendNumbersToDuplicates (true, true); - return port; } } // namespace -StringArray MidiOutput::getDevices() +//============================================================================== +Array MidiInput::getAvailableDevices() { - StringArray devices; - iterateMidiDevices (false, devices, -1); + Array devices; + iterateMidiDevices (true, devices, {}); + return devices; } -int MidiOutput::getDefaultDeviceIndex() +MidiDeviceInfo MidiInput::getDefaultDevice() { - return 0; + return getAvailableDevices().getFirst(); } -MidiOutput* MidiOutput::openDevice (int deviceIndex) +std::unique_ptr MidiInput::openDevice (const String& deviceIdentifier, MidiInputCallback* callback) { - MidiOutput* newDevice = nullptr; + if (deviceIdentifier.isEmpty()) + return {}; - StringArray devices; - auto* port = iterateMidiDevices (false, devices, deviceIndex); + Array devices; + auto* port = iterateMidiDevices (true, devices, deviceIdentifier); - if (port == nullptr) - return nullptr; + if (port == nullptr || ! port->isValid()) + return {}; jassert (port->isValid()); - newDevice = new MidiOutput (devices [deviceIndex]); - port->setupOutput(); - newDevice->internal = port; + std::unique_ptr midiInput (new MidiInput (port->portName, deviceIdentifier)); + + port->setupInput (midiInput.get(), callback); + midiInput->internal = port; - return newDevice; + return midiInput; } -MidiOutput* MidiOutput::createNewDevice (const String& deviceName) +std::unique_ptr MidiInput::createNewDevice (const String& deviceName, MidiInputCallback* callback) { - MidiOutput* newDevice = nullptr; auto client = AlsaClient::getInstance(); - auto* port = client->createPort (deviceName, false, true); - jassert (port != nullptr && port->isValid()); + auto* port = client->createPort (deviceName, true, true); - newDevice = new MidiOutput (deviceName); - port->setupOutput(); - newDevice->internal = port; + if (port == nullptr || ! port->isValid()) + return {}; - return newDevice; + std::unique_ptr midiInput (new MidiInput (deviceName, getFormattedPortIdentifier (client->getId(), port->portId))); + + port->setupInput (midiInput.get(), callback); + midiInput->internal = port; + + return midiInput; } -MidiOutput::~MidiOutput() +StringArray MidiInput::getDevices() { - stopBackgroundThread(); - AlsaClient::getInstance()->deletePort (static_cast (internal)); + StringArray deviceNames; + + for (auto& d : getAvailableDevices()) + deviceNames.add (d.name); + + deviceNames.appendNumbersToDuplicates (true, true); + + return deviceNames; } -void MidiOutput::sendMessageNow (const MidiMessage& message) +int MidiInput::getDefaultDeviceIndex() { - static_cast (internal)->sendMessageNow (message); + return 0; } -//============================================================================== -MidiInput::MidiInput (const String& nm) : name (nm) +std::unique_ptr MidiInput::openDevice (int index, MidiInputCallback* callback) +{ + return openDevice (getAvailableDevices()[index].identifier, callback); +} + +MidiInput::MidiInput (const String& deviceName, const String& deviceIdentifier) + : deviceInfo (deviceName, deviceIdentifier) { } @@ -530,68 +549,117 @@ void MidiInput::stop() static_cast (internal)->enableCallback (false); } -int MidiInput::getDefaultDeviceIndex() +//============================================================================== +Array MidiOutput::getAvailableDevices() { - return 0; + Array devices; + iterateMidiDevices (false, devices, {}); + + return devices; } -StringArray MidiInput::getDevices() +MidiDeviceInfo MidiOutput::getDefaultDevice() { - StringArray devices; - iterateMidiDevices (true, devices, -1); - return devices; + return getAvailableDevices().getFirst(); } -MidiInput* MidiInput::openDevice (int deviceIndex, MidiInputCallback* callback) +std::unique_ptr MidiOutput::openDevice (const String& deviceIdentifier) { - StringArray devices; - auto* port = iterateMidiDevices (true, devices, deviceIndex); + if (deviceIdentifier.isEmpty()) + return {}; - if (port == nullptr) - return nullptr; + Array devices; + auto* port = iterateMidiDevices (false, devices, deviceIdentifier); - jassert (port->isValid()); + if (port == nullptr || ! port->isValid()) + return {}; + + std::unique_ptr midiOutput (new MidiOutput (port->portName, deviceIdentifier)); - auto newDevice = new MidiInput (devices [deviceIndex]); - port->setupInput (newDevice, callback); - newDevice->internal = port; - return newDevice; + port->setupOutput(); + midiOutput->internal = port; + + return midiOutput; } -MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallback* callback) +std::unique_ptr MidiOutput::createNewDevice (const String& deviceName) { auto client = AlsaClient::getInstance(); - auto* port = client->createPort (deviceName, true, true); + auto* port = client->createPort (deviceName, false, true); - jassert (port->isValid()); + if (port == nullptr || ! port->isValid()) + return {}; - auto newDevice = new MidiInput (deviceName); - port->setupInput (newDevice, callback); - newDevice->internal = port; - return newDevice; + std::unique_ptr midiOutput (new MidiOutput (deviceName, getFormattedPortIdentifier (client->getId(), port->portId))); + + port->setupOutput(); + midiOutput->internal = port; + + return midiOutput; } +StringArray MidiOutput::getDevices() +{ + StringArray deviceNames; + + for (auto& d : getAvailableDevices()) + deviceNames.add (d.name); + + deviceNames.appendNumbersToDuplicates (true, true); + + return deviceNames; +} + +int MidiOutput::getDefaultDeviceIndex() +{ + return 0; +} + +std::unique_ptr MidiOutput::openDevice (int index) +{ + return openDevice (getAvailableDevices()[index].identifier); +} + +MidiOutput::~MidiOutput() +{ + stopBackgroundThread(); + AlsaClient::getInstance()->deletePort (static_cast (internal)); +} + +void MidiOutput::sendMessageNow (const MidiMessage& message) +{ + static_cast (internal)->sendMessageNow (message); +} //============================================================================== #else // (These are just stub functions if ALSA is unavailable...) +MidiInput::MidiInput (const String& deviceName, const String& deviceID) + : deviceInfo (deviceName, deviceID) +{ +} -StringArray MidiOutput::getDevices() { return {}; } -int MidiOutput::getDefaultDeviceIndex() { return 0; } -MidiOutput* MidiOutput::openDevice (int) { return nullptr; } -MidiOutput* MidiOutput::createNewDevice (const String&) { return nullptr; } -MidiOutput::~MidiOutput() {} -void MidiOutput::sendMessageNow (const MidiMessage&) {} - -MidiInput::MidiInput (const String& nm) : name (nm) {} -MidiInput::~MidiInput() {} -void MidiInput::start() {} -void MidiInput::stop() {} -int MidiInput::getDefaultDeviceIndex() { return 0; } -StringArray MidiInput::getDevices() { return {}; } -MidiInput* MidiInput::openDevice (int, MidiInputCallback*) { return nullptr; } -MidiInput* MidiInput::createNewDevice (const String&, MidiInputCallback*) { return nullptr; } +MidiInput::~MidiInput() {} +void MidiInput::start() {} +void MidiInput::stop() {} +Array MidiInput::getAvailableDevices() { return {}; } +MidiDeviceInfo MidiInput::getDefaultDevice() { return {}; } +std::unique_ptr MidiInput::openDevice (const String&, MidiInputCallback*) { return {}; } +std::unique_ptr MidiInput::createNewDevice (const String&, MidiInputCallback*) { return {}; } +StringArray MidiInput::getDevices() { return {}; } +int MidiInput::getDefaultDeviceIndex() { return 0;} +std::unique_ptr MidiInput::openDevice (int, MidiInputCallback*) { return {}; } + +MidiOutput::~MidiOutput() {} +void MidiOutput::sendMessageNow (const MidiMessage&) {} +Array MidiOutput::getAvailableDevices() { return {}; } +MidiDeviceInfo MidiOutput::getDefaultDevice() { return {}; } +std::unique_ptr MidiOutput::openDevice (const String&) { return {}; } +std::unique_ptr MidiOutput::createNewDevice (const String&) { return {}; } +StringArray MidiOutput::getDevices() { return {}; } +int MidiOutput::getDefaultDeviceIndex() { return 0;} +std::unique_ptr MidiOutput::openDevice (int) { return {}; } #endif diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp index 6f7998a..058dc51 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_mac_CoreAudio.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,18 +29,7 @@ namespace juce #define JUCE_COREAUDIOLOG(a) #endif -#ifdef __clang__ - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wnonnull" // aovid some spurious 10.11 SDK warnings - - // The AudioHardwareService stuff was deprecated in 10.11 but there's no replacement yet, - // so we'll have to silence the warnings here and revisit it in a future OS version.. - #if ((defined (MAC_OS_X_VERSION_10_13) && MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_13) \ - || (defined (MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_12) \ - || (defined (MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_11)) - #pragma clang diagnostic ignored "-Wdeprecated-declarations" - #endif -#endif +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wnonnull") //============================================================================== struct SystemVol @@ -52,11 +41,10 @@ struct SystemVol addr.mElement = kAudioObjectPropertyElementMaster; addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice; - if (AudioHardwareServiceHasProperty (kAudioObjectSystemObject, &addr)) + if (AudioObjectHasProperty (kAudioObjectSystemObject, &addr)) { UInt32 deviceIDSize = sizeof (outputDeviceID); - OSStatus status = AudioHardwareServiceGetPropertyData (kAudioObjectSystemObject, &addr, 0, - nullptr, &deviceIDSize, &outputDeviceID); + OSStatus status = AudioObjectGetPropertyData (kAudioObjectSystemObject, &addr, 0, nullptr, &deviceIDSize, &outputDeviceID); if (status == noErr) { @@ -64,7 +52,7 @@ struct SystemVol addr.mSelector = selector; addr.mScope = kAudioDevicePropertyScopeOutput; - if (! AudioHardwareServiceHasProperty (outputDeviceID, &addr)) + if (! AudioObjectHasProperty (outputDeviceID, &addr)) outputDeviceID = kAudioObjectUnknown; } } @@ -77,8 +65,7 @@ struct SystemVol if (outputDeviceID != kAudioObjectUnknown) { UInt32 size = sizeof (gain); - AudioHardwareServiceGetPropertyData (outputDeviceID, &addr, - 0, nullptr, &size, &gain); + AudioObjectGetPropertyData (outputDeviceID, &addr, 0, nullptr, &size, &gain); } return (float) gain; @@ -91,8 +78,7 @@ struct SystemVol Float32 newVolume = gain; UInt32 size = sizeof (newVolume); - return AudioHardwareServiceSetPropertyData (outputDeviceID, &addr, 0, nullptr, - size, &newVolume) == noErr; + return AudioObjectSetPropertyData (outputDeviceID, &addr, 0, nullptr, size, &newVolume) == noErr; } return false; @@ -105,8 +91,7 @@ struct SystemVol if (outputDeviceID != kAudioObjectUnknown) { UInt32 size = sizeof (muted); - AudioHardwareServiceGetPropertyData (outputDeviceID, &addr, - 0, nullptr, &size, &muted); + AudioObjectGetPropertyData (outputDeviceID, &addr, 0, nullptr, &size, &muted); } return muted != 0; @@ -119,8 +104,7 @@ struct SystemVol UInt32 newMute = mute ? 1 : 0; UInt32 size = sizeof (newMute); - return AudioHardwareServiceSetPropertyData (outputDeviceID, &addr, 0, nullptr, - size, &newMute) == noErr; + return AudioObjectSetPropertyData (outputDeviceID, &addr, 0, nullptr, size, &newMute) == noErr; } return false; @@ -133,14 +117,11 @@ struct SystemVol bool canSetVolume() const noexcept { Boolean isSettable = NO; - return AudioHardwareServiceIsPropertySettable (outputDeviceID, &addr, &isSettable) == noErr - && isSettable; + return AudioObjectIsPropertySettable (outputDeviceID, &addr, &isSettable) == noErr && isSettable; } }; -#ifdef __clang__ - #pragma clang diagnostic pop -#endif +JUCE_END_IGNORE_WARNINGS_GCC_LIKE #define JUCE_SYSTEMAUDIOVOL_IMPLEMENTED 1 float JUCE_CALLTYPE SystemAudioVolume::getGain() { return SystemVol (kAudioHardwareServiceDeviceProperty_VirtualMasterVolume).getGain(); } @@ -547,7 +528,7 @@ class CoreAudioInternal : private Timer if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, ¤tSourceID))) { HeapBlock types; - const int num = getAllDataSourcesForDevice (deviceID, types); + auto num = getAllDataSourcesForDevice (deviceID, types); for (int i = 0; i < num; ++i) { @@ -568,7 +549,7 @@ class CoreAudioInternal : private Timer if (deviceID != 0) { HeapBlock types; - const int num = getAllDataSourcesForDevice (deviceID, types); + auto num = getAllDataSourcesForDevice (deviceID, types); if (isPositiveAndBelow (index, num)) { @@ -816,8 +797,8 @@ class CoreAudioInternal : private Timer JUCE_COREAUDIOLOG ("Device changed"); stopTimer(); - const double oldSampleRate = sampleRate; - const int oldBufferSize = bufferSize; + auto oldSampleRate = sampleRate; + auto oldBufferSize = bufferSize; if (! updateDetailsFromDevice()) owner.stopInternal(); @@ -866,15 +847,17 @@ class CoreAudioInternal : private Timer return noErr; } - static OSStatus deviceListenerProc (AudioDeviceID /*inDevice*/, UInt32 /*inLine*/, const AudioObjectPropertyAddress* pa, void* inClientData) + static OSStatus deviceListenerProc (AudioDeviceID /*inDevice*/, UInt32 /*inLine*/, + const AudioObjectPropertyAddress* pa, void* inClientData) { - CoreAudioInternal* const intern = static_cast (inClientData); + auto intern = static_cast (inClientData); switch (pa->mSelector) { case kAudioDeviceProcessorOverload: intern->xruns++; break; + case kAudioDevicePropertyBufferSize: case kAudioDevicePropertyBufferFrameSize: case kAudioDevicePropertyNominalSampleRate: @@ -950,8 +933,8 @@ class CoreAudioIODevice : public AudioIODevice, public: CoreAudioIODevice (CoreAudioIODeviceType* dt, const String& deviceName, - AudioDeviceID inputDeviceId, const int inputIndex_, - AudioDeviceID outputDeviceId, const int outputIndex_) + AudioDeviceID inputDeviceId, int inputIndex_, + AudioDeviceID outputDeviceId, int outputIndex_) : AudioIODevice (deviceName, "CoreAudio"), deviceType (dt), inputIndex (inputIndex_), @@ -1027,12 +1010,13 @@ class CoreAudioIODevice : public AudioIODevice, inputChannelsRequested = inputChannels; outputChannelsRequested = outputChannels; - sampleRateRequested = sampleRate; - bufferSizeSamplesRequested = bufferSizeSamples; if (bufferSizeSamples <= 0) bufferSizeSamples = getDefaultBufferSize(); + if (sampleRate <= 0) + sampleRate = internal->getNominalSampleRate(); + lastError = internal->reopen (inputChannels, outputChannels, sampleRate, bufferSizeSamples); JUCE_COREAUDIOLOG ("Opened: " << getName()); @@ -1086,7 +1070,7 @@ class CoreAudioIODevice : public AudioIODevice, if (isStarted) { - AudioIODeviceCallback* const lastCallback = internal->callback; + auto lastCallback = internal->callback; isStarted = false; internal->stop (true); @@ -1167,8 +1151,6 @@ class CoreAudioIODevice : public AudioIODevice, AudioIODeviceCallback* previousCallback = nullptr; std::function deviceWrapperRestartCallback = nullptr; BigInteger inputChannelsRequested, outputChannelsRequested; - double sampleRateRequested; - int bufferSizeSamplesRequested; CriticalSection closeLock; void timerCallback() override diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_mac_CoreMidi.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_mac_CoreMidi.cpp index 1130610..a39d9c3 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_mac_CoreMidi.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_mac_CoreMidi.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,6 +29,7 @@ namespace juce namespace CoreMidiHelpers { + //============================================================================== static bool checkError (OSStatus err, int lineNum) { if (err == noErr) @@ -45,79 +46,71 @@ namespace CoreMidiHelpers #undef CHECK_ERROR #define CHECK_ERROR(a) CoreMidiHelpers::checkError (a, __LINE__) - //============================================================================== - struct ScopedCFString - { - ScopedCFString() noexcept {} - ~ScopedCFString() noexcept { if (cfString != nullptr) CFRelease (cfString); } - - CFStringRef cfString = {}; - }; - - static String getMidiObjectName (MIDIObjectRef entity) + static MidiDeviceInfo getMidiObjectInfo (MIDIObjectRef entity) { - String result; - CFStringRef str = nullptr; - MIDIObjectGetStringProperty (entity, kMIDIPropertyName, &str); + MidiDeviceInfo info; - if (str != nullptr) { - result = String::fromCFString (str); - CFRelease (str); - } + ScopedCFString str; - return result; - } + if (CHECK_ERROR (MIDIObjectGetStringProperty (entity, kMIDIPropertyName, &str.cfString))) + info.name = String::fromCFString (str.cfString); + } - static void enableSimulatorMidiSession() - { - #if TARGET_OS_SIMULATOR - static bool hasEnabledNetworkSession = false; + SInt32 objectID = 0; - if (! hasEnabledNetworkSession) + if (CHECK_ERROR (MIDIObjectGetIntegerProperty (entity, kMIDIPropertyUniqueID, &objectID))) { - MIDINetworkSession* session = [MIDINetworkSession defaultSession]; - session.enabled = YES; - session.connectionPolicy = MIDINetworkConnectionPolicy_Anyone; + info.identifier = String (objectID); + } + else + { + ScopedCFString str; - hasEnabledNetworkSession = true; + if (CHECK_ERROR (MIDIObjectGetStringProperty (entity, kMIDIPropertyUniqueID, &str.cfString))) + info.identifier = String::fromCFString (str.cfString); } - #endif + + return info; } - static String getEndpointName (MIDIEndpointRef endpoint, bool isExternal) + static MidiDeviceInfo getEndpointInfo (MIDIEndpointRef endpoint, bool isExternal) { - auto result = getMidiObjectName (endpoint); - - MIDIEntityRef entity = 0; // NB: don't attempt to use nullptr for refs - it fails in some types of build. + // NB: don't attempt to use nullptr for refs - it fails in some types of build. + MIDIEntityRef entity = 0; MIDIEndpointGetEntity (endpoint, &entity); + // probably virtual if (entity == 0) - return result; // probably virtual + return getMidiObjectInfo (endpoint); - if (result.isEmpty()) - result = getMidiObjectName (entity); // endpoint name is empty - try the entity + auto result = getMidiObjectInfo (endpoint); - // now consider the device's name + // endpoint is empty - try the entity + if (result == MidiDeviceInfo()) + result = getMidiObjectInfo (entity); + + // now consider the device MIDIDeviceRef device = 0; MIDIEntityGetDevice (entity, &device); if (device != 0) { - auto deviceName = getMidiObjectName (device); + auto info = getMidiObjectInfo (device); - if (deviceName.isNotEmpty()) + if (info != MidiDeviceInfo()) { // if an external device has only one entity, throw away // the endpoint name and just use the device name if (isExternal && MIDIDeviceGetNumberOfEntities (device) < 2) { - result = deviceName; + result = info; } - else if (! result.startsWithIgnoreCase (deviceName)) + else if (! result.name.startsWithIgnoreCase (info.name)) { - // prepend the device name to the entity name - result = (deviceName + " " + result).trimEnd(); + // prepend the device name and identifier to the entity's + result.name = (info.name + " " + result.name).trimEnd(); + result.identifier = info.identifier + " " + result.identifier; } } } @@ -125,9 +118,9 @@ namespace CoreMidiHelpers return result; } - static String getConnectedEndpointName (MIDIEndpointRef endpoint) + static MidiDeviceInfo getConnectedEndpointInfo (MIDIEndpointRef endpoint) { - String result; + MidiDeviceInfo result; // Does the endpoint have connections? CFDataRef connections = nullptr; @@ -141,37 +134,38 @@ namespace CoreMidiHelpers if (numConnections > 0) { - auto pid = reinterpret_cast (CFDataGetBytePtr (connections)); + auto* pid = reinterpret_cast (CFDataGetBytePtr (connections)); for (int i = 0; i < numConnections; ++i, ++pid) { - auto uid = (MIDIUniqueID) ByteOrder::swapIfLittleEndian ((uint32) *pid); + auto id = (MIDIUniqueID) ByteOrder::swapIfLittleEndian ((uint32) *pid); MIDIObjectRef connObject; MIDIObjectType connObjectType; - auto err = MIDIObjectFindByUniqueID (uid, &connObject, &connObjectType); + auto err = MIDIObjectFindByUniqueID (id, &connObject, &connObjectType); if (err == noErr) { - String s; + MidiDeviceInfo deviceInfo; if (connObjectType == kMIDIObjectType_ExternalSource || connObjectType == kMIDIObjectType_ExternalDestination) { // Connected to an external device's endpoint (10.3 and later). - s = getEndpointName (static_cast (connObject), true); + deviceInfo = getEndpointInfo (static_cast (connObject), true); } else { // Connected to an external device (10.2) (or something else, catch-all) - s = getMidiObjectName (connObject); + deviceInfo = getMidiObjectInfo (connObject); } - if (s.isNotEmpty()) + if (deviceInfo != MidiDeviceInfo()) { - if (result.isNotEmpty()) - result += ", "; + if (result.name.isNotEmpty()) result.name += ", "; + if (result.identifier.isNotEmpty()) result.identifier += ", "; - result += s; + result.name += deviceInfo.name; + result.identifier += deviceInfo.identifier; } } } @@ -180,22 +174,24 @@ namespace CoreMidiHelpers CFRelease (connections); } - if (result.isEmpty()) // Here, either the endpoint had no connections, or we failed to obtain names for them. - result = getEndpointName (endpoint, false); + // Here, either the endpoint had no connections, or we failed to obtain names for them. + if (result == MidiDeviceInfo()) + return getEndpointInfo (endpoint, false); return result; } - static void setUniqueIdForMidiPort (MIDIObjectRef device, const String& portName, bool isInput) + static int createUniqueIDForMidiPort (String deviceName, bool isInput) { - String portUniqueId; - #if defined (JucePlugin_CFBundleIdentifier) - portUniqueId = JUCE_STRINGIFY (JucePlugin_CFBundleIdentifier); + String uniqueID; + + #ifdef JucePlugin_CFBundleIdentifier + uniqueID = JUCE_STRINGIFY (JucePlugin_CFBundleIdentifier); #else auto appBundle = File::getSpecialLocation (File::currentApplicationFile); + ScopedCFString appBundlePath (appBundle.getFullPathName()); - if (auto bundleURL = CFURLCreateWithFileSystemPath (kCFAllocatorDefault, appBundle.getFullPathName().toCFString(), - kCFURLPOSIXPathStyle, true)) + if (auto bundleURL = CFURLCreateWithFileSystemPath (kCFAllocatorDefault, appBundlePath.cfString, kCFURLPOSIXPathStyle, true)) { auto bundleRef = CFBundleCreate (kCFAllocatorDefault, bundleURL); CFRelease (bundleURL); @@ -203,19 +199,34 @@ namespace CoreMidiHelpers if (bundleRef != nullptr) { if (auto bundleId = CFBundleGetIdentifier (bundleRef)) - portUniqueId = String::fromCFString (bundleId); + uniqueID = String::fromCFString (bundleId); CFRelease (bundleRef); } } #endif - if (portUniqueId.isNotEmpty()) + if (uniqueID.isEmpty()) + uniqueID = String (Random::getSystemRandom().nextInt (1024)); + + uniqueID += "." + deviceName + (isInput ? ".input" : ".output"); + return uniqueID.hashCode(); + } + + static void enableSimulatorMidiSession() + { + #if TARGET_OS_SIMULATOR + static bool hasEnabledNetworkSession = false; + + if (! hasEnabledNetworkSession) { - portUniqueId += "." + portName + (isInput ? ".input" : ".output"); + MIDINetworkSession* session = [MIDINetworkSession defaultSession]; + session.enabled = YES; + session.connectionPolicy = MIDINetworkConnectionPolicy_Anyone; - CHECK_ERROR (MIDIObjectSetStringProperty (device, kMIDIPropertyUniqueID, portUniqueId.toCFString())); + hasEnabledNetworkSession = true; } + #endif } static void globalSystemChangeCallback (const MIDINotification*, void*) @@ -243,15 +254,14 @@ namespace CoreMidiHelpers enableSimulatorMidiSession(); - CoreMidiHelpers::ScopedCFString name; - name.cfString = getGlobalMidiClientName().toCFString(); + ScopedCFString name (getGlobalMidiClientName()); CHECK_ERROR (MIDIClientCreate (name.cfString, &globalSystemChangeCallback, nullptr, &globalMidiClient)); } return globalMidiClient; } - static StringArray findDevices (bool forInput) + static Array findDevices (bool forInput) { // It seems that OSX can be a bit picky about the thread that's first used to // search for devices. It's safest to use the message thread for calling this. @@ -263,26 +273,25 @@ namespace CoreMidiHelpers return {}; } - StringArray s; enableSimulatorMidiSession(); - auto num = forInput ? MIDIGetNumberOfSources() - : MIDIGetNumberOfDestinations(); + Array devices; + auto numDevices = (forInput ? MIDIGetNumberOfSources() : MIDIGetNumberOfDestinations()); - for (ItemCount i = 0; i < num; ++i) + for (ItemCount i = 0; i < numDevices; ++i) { - String name; + MidiDeviceInfo deviceInfo; if (auto dest = forInput ? MIDIGetSource (i) : MIDIGetDestination (i)) - name = getConnectedEndpointName (dest); + deviceInfo = getConnectedEndpointInfo (dest); - if (name.isEmpty()) - name = ""; + if (deviceInfo == MidiDeviceInfo()) + deviceInfo.name = deviceInfo.identifier = ""; - s.add (name); + devices.add (deviceInfo); } - return s; + return devices; } //============================================================================== @@ -290,7 +299,7 @@ namespace CoreMidiHelpers { public: MidiPortAndEndpoint (MIDIPortRef p, MIDIEndpointRef ep) noexcept - : port (p), endPoint (ep) + : port (p), endpoint (ep) { } @@ -299,20 +308,21 @@ namespace CoreMidiHelpers if (port != 0) MIDIPortDispose (port); - if (port == 0 && endPoint != 0) // if port == nullptr, it means we created the endpoint, so it's safe to delete it - MIDIEndpointDispose (endPoint); + // if port == nullptr, it means we created the endpoint, so it's safe to delete it + if (port == 0 && endpoint != 0) + MIDIEndpointDispose (endpoint); } void send (const MIDIPacketList* packets) noexcept { if (port != 0) - MIDISend (port, endPoint, packets); + MIDISend (port, endpoint, packets); else - MIDIReceived (endPoint, packets); + MIDIReceived (endpoint, packets); } MIDIPortRef port; - MIDIEndpointRef endPoint; + MIDIEndpointRef endpoint; }; //============================================================================== @@ -334,7 +344,7 @@ namespace CoreMidiHelpers } if (portAndEndpoint != nullptr && portAndEndpoint->port != 0) - CHECK_ERROR (MIDIPortDisconnectSource (portAndEndpoint->port, portAndEndpoint->endPoint)); + CHECK_ERROR (MIDIPortDisconnectSource (portAndEndpoint->port, portAndEndpoint->endpoint)); } void handlePackets (const MIDIPacketList* pktlist) @@ -370,61 +380,276 @@ namespace CoreMidiHelpers { static_cast (readProcRefCon)->handlePackets (pktlist); } + + static Array getEndpoints (bool isInput) + { + Array endpoints; + auto numDevices = (isInput ? MIDIGetNumberOfSources() : MIDIGetNumberOfDestinations()); + + for (ItemCount i = 0; i < numDevices; ++i) + endpoints.add (isInput ? MIDIGetSource (i) : MIDIGetDestination (i)); + + return endpoints; + } } //============================================================================== -StringArray MidiOutput::getDevices() { return CoreMidiHelpers::findDevices (false); } -int MidiOutput::getDefaultDeviceIndex() { return 0; } +Array MidiInput::getAvailableDevices() +{ + return CoreMidiHelpers::findDevices (true); +} + +MidiDeviceInfo MidiInput::getDefaultDevice() +{ + return getAvailableDevices().getFirst(); +} + +std::unique_ptr MidiInput::openDevice (const String& deviceIdentifier, MidiInputCallback* callback) +{ + if (deviceIdentifier.isEmpty()) + return nullptr; + + using namespace CoreMidiHelpers; + + if (auto client = getGlobalMidiClient()) + { + for (auto& endpoint : getEndpoints (true)) + { + auto endpointInfo = getConnectedEndpointInfo (endpoint); + + if (deviceIdentifier == endpointInfo.identifier) + { + ScopedCFString cfName; + + if (CHECK_ERROR (MIDIObjectGetStringProperty (endpoint, kMIDIPropertyName, &cfName.cfString))) + { + MIDIPortRef port; + auto mpc = std::make_unique (*callback); + + if (CHECK_ERROR (MIDIInputPortCreate (client, cfName.cfString, midiInputProc, mpc.get(), &port))) + { + if (CHECK_ERROR (MIDIPortConnectSource (port, endpoint, nullptr))) + { + mpc->portAndEndpoint = std::make_unique (port, endpoint); + + std::unique_ptr midiInput (new MidiInput (endpointInfo.name, endpointInfo.identifier)); + + mpc->input = midiInput.get(); + midiInput->internal = mpc.get(); + + const ScopedLock sl (callbackLock); + activeCallbacks.add (mpc.release()); + + return midiInput; + } + else + { + CHECK_ERROR (MIDIPortDispose (port)); + } + } + } + } + } + } + + return {}; +} -MidiOutput* MidiOutput::openDevice (int index) +std::unique_ptr MidiInput::createNewDevice (const String& deviceName, MidiInputCallback* callback) { - MidiOutput* mo = nullptr; + using namespace CoreMidiHelpers; + jassert (callback != nullptr); - if (auto client = CoreMidiHelpers::getGlobalMidiClient()) + if (auto client = getGlobalMidiClient()) { - if (isPositiveAndBelow (index, MIDIGetNumberOfDestinations())) + auto mpc = std::make_unique (*callback); + mpc->active = false; + + MIDIEndpointRef endpoint; + ScopedCFString name (deviceName); + + auto err = MIDIDestinationCreate (client, name.cfString, midiInputProc, mpc.get(), &endpoint); + + #if JUCE_IOS + if (err == kMIDINotPermitted) { - auto endPoint = MIDIGetDestination ((ItemCount) index); + // If you've hit this assertion then you probably haven't enabled the "Audio Background Capability" + // setting in the iOS exporter for your app - this is required if you want to create a MIDI device! + jassertfalse; + return nullptr; + } + #endif - CoreMidiHelpers::ScopedCFString pname; + if (CHECK_ERROR (err)) + { + auto deviceIdentifier = createUniqueIDForMidiPort (deviceName, true); - if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname.cfString))) + if (CHECK_ERROR (MIDIObjectSetIntegerProperty (endpoint, kMIDIPropertyUniqueID, (SInt32) deviceIdentifier))) { - MIDIPortRef port; - auto deviceName = CoreMidiHelpers::getConnectedEndpointName (endPoint); + mpc->portAndEndpoint = std::make_unique ((UInt32) 0, endpoint); + + std::unique_ptr midiInput (new MidiInput (deviceName, String (deviceIdentifier))); - if (CHECK_ERROR (MIDIOutputPortCreate (client, pname.cfString, &port))) + mpc->input = midiInput.get(); + midiInput->internal = mpc.get(); + + const ScopedLock sl (callbackLock); + activeCallbacks.add (mpc.release()); + + return midiInput; + } + } + } + + return {}; +} + +StringArray MidiInput::getDevices() +{ + StringArray deviceNames; + + for (auto& d : getAvailableDevices()) + deviceNames.add (d.name); + + return deviceNames; +} + +int MidiInput::getDefaultDeviceIndex() +{ + return 0; +} + +std::unique_ptr MidiInput::openDevice (int index, MidiInputCallback* callback) +{ + return openDevice (getAvailableDevices()[index].identifier, callback); +} + +MidiInput::MidiInput (const String& deviceName, const String& deviceIdentifier) + : deviceInfo (deviceName, deviceIdentifier) +{ +} + +MidiInput::~MidiInput() +{ + delete static_cast (internal); +} + +void MidiInput::start() +{ + const ScopedLock sl (CoreMidiHelpers::callbackLock); + static_cast (internal)->active = true; +} + +void MidiInput::stop() +{ + const ScopedLock sl (CoreMidiHelpers::callbackLock); + static_cast (internal)->active = false; +} + +//============================================================================== +Array MidiOutput::getAvailableDevices() +{ + return CoreMidiHelpers::findDevices (false); +} + +MidiDeviceInfo MidiOutput::getDefaultDevice() +{ + return getAvailableDevices().getFirst(); +} + +std::unique_ptr MidiOutput::openDevice (const String& deviceIdentifier) +{ + if (deviceIdentifier.isEmpty()) + return nullptr; + + using namespace CoreMidiHelpers; + + if (auto client = getGlobalMidiClient()) + { + for (auto& endpoint : getEndpoints (false)) + { + auto endpointInfo = getConnectedEndpointInfo (endpoint); + + if (deviceIdentifier == endpointInfo.identifier) + { + ScopedCFString cfName; + + if (CHECK_ERROR (MIDIObjectGetStringProperty (endpoint, kMIDIPropertyName, &cfName.cfString))) { - mo = new MidiOutput (deviceName); - mo->internal = new CoreMidiHelpers::MidiPortAndEndpoint (port, endPoint); + MIDIPortRef port; + + if (CHECK_ERROR (MIDIOutputPortCreate (client, cfName.cfString, &port))) + { + std::unique_ptr midiOutput (new MidiOutput (endpointInfo.name, endpointInfo.identifier)); + midiOutput->internal = new MidiPortAndEndpoint (port, endpoint); + + return midiOutput; + } } } } } - return mo; + return {}; } -MidiOutput* MidiOutput::createNewDevice (const String& deviceName) +std::unique_ptr MidiOutput::createNewDevice (const String& deviceName) { - if (auto client = CoreMidiHelpers::getGlobalMidiClient()) + using namespace CoreMidiHelpers; + + if (auto client = getGlobalMidiClient()) { - MIDIEndpointRef endPoint; + MIDIEndpointRef endpoint; + + ScopedCFString name (deviceName); - CoreMidiHelpers::ScopedCFString name; - name.cfString = deviceName.toCFString(); + auto err = MIDISourceCreate (client, name.cfString, &endpoint); + + #if JUCE_IOS + if (err == kMIDINotPermitted) + { + // If you've hit this assertion then you probably haven't enabled the "Audio Background Capability" + // setting in the iOS exporter for your app - this is required if you want to create a MIDI device! + jassertfalse; + return nullptr; + } + #endif - if (CHECK_ERROR (MIDISourceCreate (client, name.cfString, &endPoint))) + if (CHECK_ERROR (err)) { - CoreMidiHelpers::setUniqueIdForMidiPort (endPoint, deviceName, false); + auto deviceIdentifier = createUniqueIDForMidiPort (deviceName, false); + + if (CHECK_ERROR (MIDIObjectSetIntegerProperty (endpoint, kMIDIPropertyUniqueID, (SInt32) deviceIdentifier))) + { + std::unique_ptr midiOutput (new MidiOutput (deviceName, String (deviceIdentifier))); + midiOutput->internal = new MidiPortAndEndpoint (0, endpoint); - auto mo = new MidiOutput (deviceName); - mo->internal = new CoreMidiHelpers::MidiPortAndEndpoint (0, endPoint); - return mo; + return midiOutput; + } } } - return nullptr; + return {}; +} + +StringArray MidiOutput::getDevices() +{ + StringArray deviceNames; + + for (auto& d : getAvailableDevices()) + deviceNames.add (d.name); + + return deviceNames; +} + +int MidiOutput::getDefaultDeviceIndex() +{ + return 0; +} + +std::unique_ptr MidiOutput::openDevice (int index) +{ + return openDevice (getAvailableDevices()[index].identifier); } MidiOutput::~MidiOutput() @@ -493,111 +718,6 @@ void MidiOutput::sendMessageNow (const MidiMessage& message) static_cast (internal)->send (packetToSend); } -//============================================================================== -StringArray MidiInput::getDevices() { return CoreMidiHelpers::findDevices (true); } -int MidiInput::getDefaultDeviceIndex() { return 0; } - -MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) -{ - jassert (callback != nullptr); - - using namespace CoreMidiHelpers; - MidiInput* newInput = nullptr; - - if (auto client = getGlobalMidiClient()) - { - if (isPositiveAndBelow (index, MIDIGetNumberOfSources())) - { - if (auto endPoint = MIDIGetSource ((ItemCount) index)) - { - ScopedCFString name; - - if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &name.cfString))) - { - MIDIPortRef port; - std::unique_ptr mpc (new MidiPortAndCallback (*callback)); - - if (CHECK_ERROR (MIDIInputPortCreate (client, name.cfString, midiInputProc, mpc.get(), &port))) - { - if (CHECK_ERROR (MIDIPortConnectSource (port, endPoint, nullptr))) - { - mpc->portAndEndpoint.reset (new MidiPortAndEndpoint (port, endPoint)); - - newInput = new MidiInput (getDevices() [index]); - mpc->input = newInput; - newInput->internal = mpc.get(); - - const ScopedLock sl (callbackLock); - activeCallbacks.add (mpc.release()); - } - else - { - CHECK_ERROR (MIDIPortDispose (port)); - } - } - } - } - } - } - - return newInput; -} - -MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallback* callback) -{ - jassert (callback != nullptr); - using namespace CoreMidiHelpers; - - if (auto client = getGlobalMidiClient()) - { - std::unique_ptr mpc (new MidiPortAndCallback (*callback)); - mpc->active = false; - - MIDIEndpointRef endPoint; - ScopedCFString name; - name.cfString = deviceName.toCFString(); - - if (CHECK_ERROR (MIDIDestinationCreate (client, name.cfString, midiInputProc, mpc.get(), &endPoint))) - { - setUniqueIdForMidiPort (endPoint, deviceName, true); - - mpc->portAndEndpoint.reset (new MidiPortAndEndpoint (0, endPoint)); - - auto mi = new MidiInput (deviceName); - mpc->input = mi; - mi->internal = mpc.get(); - - const ScopedLock sl (callbackLock); - activeCallbacks.add (mpc.release()); - - return mi; - } - } - - return nullptr; -} - -MidiInput::MidiInput (const String& nm) : name (nm) -{ -} - -MidiInput::~MidiInput() -{ - delete static_cast (internal); -} - -void MidiInput::start() -{ - const ScopedLock sl (CoreMidiHelpers::callbackLock); - static_cast (internal)->active = true; -} - -void MidiInput::stop() -{ - const ScopedLock sl (CoreMidiHelpers::callbackLock); - static_cast (internal)->active = false; -} - #undef CHECK_ERROR } // namespace juce diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_ASIO.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_ASIO.cpp index 31aa298..466bf1f 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_ASIO.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_ASIO.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,7 +43,9 @@ namespace ASIODebugging { message = "ASIO: " + message; DBG (message); - Logger::writeToLog (message); + + if (Logger::getCurrentLogger() != nullptr) + Logger::writeToLog (message); } static void logError (const String& context, long error) @@ -336,7 +338,9 @@ class ASIOAudioIODevice : public AudioIODevice, close(); JUCE_ASIO_LOG ("closed"); - removeCurrentDriver(); + + if (! removeCurrentDriver()) + JUCE_ASIO_LOG ("** Driver crashed while being closed"); } void updateSampleRates() @@ -451,7 +455,9 @@ class ASIOAudioIODevice : public AudioIODevice, if (needToReset) { JUCE_ASIO_LOG (" Resetting"); - removeCurrentDriver(); + + if (! removeCurrentDriver()) + JUCE_ASIO_LOG ("** Driver crashed while being closed"); loadDriver(); String initError = initDriver(); @@ -459,6 +465,8 @@ class ASIOAudioIODevice : public AudioIODevice, if (initError.isNotEmpty()) JUCE_ASIO_LOG ("ASIOInit: " + initError); + setSampleRate (getSampleRate()); + needToReset = false; } @@ -638,8 +646,8 @@ class ASIOAudioIODevice : public AudioIODevice, BigInteger getActiveOutputChannels() const override { return currentChansOut; } BigInteger getActiveInputChannels() const override { return currentChansIn; } - int getOutputLatencyInSamples() override { return outputLatency + currentBlockSizeSamples / 4; } - int getInputLatencyInSamples() override { return inputLatency + currentBlockSizeSamples / 4; } + int getOutputLatencyInSamples() override { return outputLatency; } + int getInputLatencyInSamples() override { return inputLatency; } void start (AudioIODeviceCallback* callback) override { @@ -1073,18 +1081,32 @@ class ASIOAudioIODevice : public AudioIODevice, } } - void removeCurrentDriver() + bool removeCurrentDriver() { + bool releasedOK = true; + if (asioObject != nullptr) { - asioObject->Release(); + #if ! JUCE_MINGW + __try + #endif + { + asioObject->Release(); + } + #if ! JUCE_MINGW + __except (EXCEPTION_EXECUTE_HANDLER) { releasedOK = false; } + #endif + asioObject = nullptr; } + + return releasedOK; } bool loadDriver() { - removeCurrentDriver(); + if (! removeCurrentDriver()) + JUCE_ASIO_LOG ("** Driver crashed while being closed"); bool crashed = false; bool ok = tryCreatingDriver (crashed); @@ -1125,7 +1147,7 @@ class ASIOAudioIODevice : public AudioIODevice, if (asioObject == nullptr) return "No Driver"; - const bool initOk = !! asioObject->init (juce_messageWindowHandle); + auto initOk = (asioObject->init (juce_messageWindowHandle) > 0); String driverError; // Get error message if init() failed, or if it's a buggy Denon driver, @@ -1244,7 +1266,9 @@ class ASIOAudioIODevice : public AudioIODevice, { JUCE_ASIO_LOG_ERROR (error, err); disposeBuffers(); - removeCurrentDriver(); + + if (! removeCurrentDriver()) + JUCE_ASIO_LOG ("** Driver crashed while being closed"); } else { @@ -1566,7 +1590,7 @@ class ASIOAudioIODeviceType : public AudioIODeviceType //============================================================================== static bool isBlacklistedDriver (const String& driverName) { - return driverName == "ASIO DirectX Full Duplex Driver" || driverName == "ASIO Multimedia Driver"; + return driverName.startsWith ("ASIO DirectX Full Duplex") || driverName == "ASIO Multimedia Driver"; } void addDriverInfo (const String& keyName, HKEY hk) diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_DirectSound.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_DirectSound.cpp index 79882dd..9498067 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_DirectSound.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_DirectSound.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. @@ -291,7 +291,7 @@ class DSoundInternalOutChannel { IDirectSoundBuffer* pPrimaryBuffer; - DSBUFFERDESC primaryDesc = { 0 }; + DSBUFFERDESC primaryDesc = {}; primaryDesc.dwSize = sizeof (DSBUFFERDESC); primaryDesc.dwFlags = 1 /* DSBCAPS_PRIMARYBUFFER */; primaryDesc.dwBufferBytes = 0; @@ -317,7 +317,7 @@ class DSoundInternalOutChannel if (SUCCEEDED (hr)) { - DSBUFFERDESC secondaryDesc = { 0 }; + DSBUFFERDESC secondaryDesc = {}; secondaryDesc.dwSize = sizeof (DSBUFFERDESC); secondaryDesc.dwFlags = 0x8000 /* DSBCAPS_GLOBALFOCUS */ | 0x10000 /* DSBCAPS_GETCURRENTPOSITION2 */; @@ -514,12 +514,11 @@ class DSoundInternalOutChannel IDirectSoundBuffer* pOutputBuffer; DWORD writeOffset; int totalBytesPerBuffer, bytesPerBuffer; - unsigned int lastPlayCursor; bool firstPlayTime; int64 lastPlayTime, ticksPerBuffer; - static inline int convertInputValues (const float l, const float r) noexcept + static int convertInputValues (const float l, const float r) noexcept { return jlimit (-32768, 32767, roundToInt (32767.0f * r)) << 16 | (0xffff & jlimit (-32768, 32767, roundToInt (32767.0f * l))); @@ -599,7 +598,7 @@ struct DSoundInternalInChannel wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign; wfFormat.cbSize = 0; - DSCBUFFERDESC captureDesc = { 0 }; + DSCBUFFERDESC captureDesc = {}; captureDesc.dwSize = sizeof (DSCBUFFERDESC); captureDesc.dwFlags = 0; captureDesc.dwBufferBytes = (DWORD) totalBytesPerBuffer; @@ -1094,7 +1093,7 @@ String DSoundAudioIODevice::openDevice (const BigInteger& inputChannels, { closeDevice(); - sampleRate = sampleRate_; + sampleRate = sampleRate_ > 0.0 ? sampleRate_ : 44100.0; if (bufferSizeSamples_ <= 0) bufferSizeSamples_ = 960; // use as a default size if none is set. @@ -1215,13 +1214,13 @@ class DSoundAudioIODeviceType : public AudioIODeviceType, initialiseDSoundFunctions(); } - void scanForDevices() + void scanForDevices() override { hasScanned = true; deviceList.scan(); } - StringArray getDeviceNames (bool wantInputNames) const + StringArray getDeviceNames (bool wantInputNames) const override { jassert (hasScanned); // need to call scanForDevices() before doing this @@ -1229,13 +1228,13 @@ class DSoundAudioIODeviceType : public AudioIODeviceType, : deviceList.outputDeviceNames; } - int getDefaultDeviceIndex (bool /*forInput*/) const + int getDefaultDeviceIndex (bool /*forInput*/) const override { jassert (hasScanned); // need to call scanForDevices() before doing this return 0; } - int getIndexOfDevice (AudioIODevice* device, bool asInput) const + int getIndexOfDevice (AudioIODevice* device, bool asInput) const override { jassert (hasScanned); // need to call scanForDevices() before doing this @@ -1246,10 +1245,10 @@ class DSoundAudioIODeviceType : public AudioIODeviceType, return -1; } - bool hasSeparateInputsAndOutputs() const { return true; } + bool hasSeparateInputsAndOutputs() const override { return true; } AudioIODevice* createDevice (const String& outputDeviceName, - const String& inputDeviceName) + const String& inputDeviceName) override { jassert (hasScanned); // need to call scanForDevices() before doing this diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_Midi.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_Midi.cpp index ca795b4..21cc58d 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_Midi.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_Midi.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. @@ -20,6 +20,12 @@ ============================================================================== */ +#ifndef DRV_QUERYDEVICEINTERFACE + #define DRV_RESERVED 0x0800 + #define DRV_QUERYDEVICEINTERFACE (DRV_RESERVED + 12) + #define DRV_QUERYDEVICEINTERFACESIZE (DRV_RESERVED + 13) +#endif + namespace juce { @@ -29,7 +35,9 @@ struct MidiServiceType { virtual ~InputWrapper() {} + virtual String getDeviceIdentifier() = 0; virtual String getDeviceName() = 0; + virtual void start() = 0; virtual void stop() = 0; }; @@ -38,18 +46,20 @@ struct MidiServiceType { virtual ~OutputWrapper() {} + virtual String getDeviceIdentifier() = 0; virtual String getDeviceName() = 0; + virtual void sendMessageNow (const MidiMessage&) = 0; }; MidiServiceType() {} virtual ~MidiServiceType() {} - virtual StringArray getDevices (bool) = 0; - virtual int getDefaultDeviceIndex (bool) = 0; + virtual Array getAvailableDevices (bool) = 0; + virtual MidiDeviceInfo getDefaultDevice (bool) = 0; - virtual InputWrapper* createInputWrapper (MidiInput&, int, MidiInputCallback&) = 0; - virtual OutputWrapper* createOutputWrapper (int) = 0; + virtual InputWrapper* createInputWrapper (MidiInput&, const String&, MidiInputCallback&) = 0; + virtual OutputWrapper* createOutputWrapper (const String&) = 0; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiServiceType) }; @@ -60,26 +70,26 @@ struct Win32MidiService : public MidiServiceType, { Win32MidiService() {} - StringArray getDevices (bool isInput) override + Array getAvailableDevices (bool isInput) override { - return isInput ? Win32InputWrapper::getDevices() - : Win32OutputWrapper::getDevices(); + return isInput ? Win32InputWrapper::getAvailableDevices() + : Win32OutputWrapper::getAvailableDevices(); } - int getDefaultDeviceIndex (bool isInput) override + MidiDeviceInfo getDefaultDevice (bool isInput) override { - return isInput ? Win32InputWrapper::getDefaultDeviceIndex() - : Win32OutputWrapper::getDefaultDeviceIndex(); + return isInput ? Win32InputWrapper::getDefaultDevice() + : Win32OutputWrapper::getDefaultDevice(); } - InputWrapper* createInputWrapper (MidiInput& input, int index, MidiInputCallback& callback) override + InputWrapper* createInputWrapper (MidiInput& input, const String& deviceIdentifier, MidiInputCallback& callback) override { - return new Win32InputWrapper (*this, input, index, callback); + return new Win32InputWrapper (*this, input, deviceIdentifier, callback); } - OutputWrapper* createOutputWrapper (int index) override + OutputWrapper* createOutputWrapper (const String& deviceIdentifier) override { - return new Win32OutputWrapper (*this, index); + return new Win32OutputWrapper (*this, deviceIdentifier); } private: @@ -88,7 +98,10 @@ struct Win32MidiService : public MidiServiceType, //============================================================================== struct MidiInCollector : public ReferenceCountedObject { - MidiInCollector (Win32MidiService& s, const String& name) : deviceName (name), midiService (s) {} + MidiInCollector (Win32MidiService& s, MidiDeviceInfo d) + : deviceInfo (d), midiService (s) + { + } ~MidiInCollector() { @@ -216,7 +229,7 @@ struct Win32MidiService : public MidiServiceType, } } - String deviceName; + MidiDeviceInfo deviceInfo; HMIDIIN deviceHandle = 0; private: @@ -319,13 +332,65 @@ struct Win32MidiService : public MidiServiceType, }; //============================================================================== - struct Win32InputWrapper : public InputWrapper + template + struct Win32MidiDeviceQuery { - Win32InputWrapper (Win32MidiService& parentService, - MidiInput& midiInput, int index, MidiInputCallback& c) + static Array getAvailableDevices() + { + StringArray deviceNames, deviceIDs; + auto deviceCaps = WrapperType::getDeviceCaps(); + + for (int i = 0; i < deviceCaps.size(); ++i) + { + deviceNames.add (deviceCaps[i].szPname); + + auto identifier = getInterfaceIDForDevice ((UINT) i); + + if (identifier.isNotEmpty()) + deviceIDs.add (identifier); + else + deviceIDs.add (deviceNames[i]); + } + + deviceNames.appendNumbersToDuplicates (false, false, CharPointer_UTF8 ("-"), CharPointer_UTF8 ("")); + deviceIDs .appendNumbersToDuplicates (false, false, CharPointer_UTF8 ("-"), CharPointer_UTF8 ("")); + + Array devices; + + for (int i = 0; i < deviceNames.size(); ++i) + devices.add ({ deviceNames[i], deviceIDs[i] }); + + return devices; + } + + private: + static String getInterfaceIDForDevice (UINT id) + { + ULONG size = 0; + + if (WrapperType::sendMidiMessage ((UINT_PTR) id, DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR) &size, 0) == MMSYSERR_NOERROR) + { + WCHAR interfaceName[512] = {}; + + if (isPositiveAndBelow (size, sizeof (interfaceName)) + && WrapperType::sendMidiMessage ((UINT_PTR) id, DRV_QUERYDEVICEINTERFACE, + (DWORD_PTR) interfaceName, sizeof (interfaceName)) == MMSYSERR_NOERROR) + { + return interfaceName; + } + } + + return {}; + } + }; + + struct Win32InputWrapper : public InputWrapper, + public Win32MidiDeviceQuery + { + Win32InputWrapper (Win32MidiService& parentService, MidiInput& midiInput, const String& deviceIdentifier, MidiInputCallback& c) : input (midiInput), callback (c) { - collector = getOrCreateCollector (parentService, index); + collector = getOrCreateCollector (parentService, deviceIdentifier); collector->addClient (this); } @@ -334,25 +399,31 @@ struct Win32MidiService : public MidiServiceType, collector->removeClient (this); } - static MidiInCollector::Ptr getOrCreateCollector (Win32MidiService& parentService, int index) + static MidiInCollector::Ptr getOrCreateCollector (Win32MidiService& parentService, const String& deviceIdentifier) { - auto names = getDevices(); UINT deviceID = MIDI_MAPPER; String deviceName; + auto devices = getAvailableDevices(); - if (isPositiveAndBelow (index, names.size())) + for (int i = 0; i < devices.size(); ++i) { - deviceName = names[index]; - deviceID = index; + auto d = devices.getUnchecked (i); + + if (d.identifier == deviceIdentifier) + { + deviceID = i; + deviceName = d.name; + break; + } } const ScopedLock sl (parentService.activeCollectorLock); for (auto& c : parentService.activeCollectors) - if (c->deviceName == deviceName) + if (c->deviceInfo.identifier == deviceIdentifier) return c; - MidiInCollector::Ptr c (new MidiInCollector (parentService, deviceName)); + MidiInCollector::Ptr c (new MidiInCollector (parentService, { deviceName, deviceIdentifier })); HMIDIIN h; auto err = midiInOpen (&h, deviceID, @@ -368,29 +439,33 @@ struct Win32MidiService : public MidiServiceType, return c; } - static StringArray getDevices() + static DWORD sendMidiMessage (UINT_PTR deviceID, UINT msg, DWORD_PTR arg1, DWORD_PTR arg2) { - StringArray s; - auto num = midiInGetNumDevs(); + return midiInMessage ((HMIDIIN) deviceID, msg, arg1, arg2); + } - for (UINT i = 0; i < num; ++i) + static Array getDeviceCaps() + { + Array devices; + + for (UINT i = 0; i < midiInGetNumDevs(); ++i) { - MIDIINCAPS mc = { 0 }; + MIDIINCAPS mc = {}; if (midiInGetDevCaps (i, &mc, sizeof (mc)) == MMSYSERR_NOERROR) - s.add (String (mc.szPname, (size_t) numElementsInArray (mc.szPname))); + devices.add (mc); } - s.appendNumbersToDuplicates (false, false, CharPointer_UTF8 ("-"), CharPointer_UTF8 ("")); - return s; + return devices; } - static int getDefaultDeviceIndex() { return 0; } + static MidiDeviceInfo getDefaultDevice() { return getAvailableDevices().getFirst(); } void start() override { started = true; concatenator.reset(); collector->startOrStop(); } void stop() override { started = false; collector->startOrStop(); concatenator.reset(); } - String getDeviceName() override { return collector->deviceName; } + String getDeviceIdentifier() override { return collector->deviceInfo.identifier; } + String getDeviceName() override { return collector->deviceInfo.name; } void pushMidiData (const void* inputData, int numBytes, double time) { @@ -411,8 +486,8 @@ struct Win32MidiService : public MidiServiceType, { using Ptr = ReferenceCountedObjectPtr; - MidiOutHandle (Win32MidiService& parent, const String& name, HMIDIOUT h) - : owner (parent), deviceName (name), handle (h) + MidiOutHandle (Win32MidiService& parent, MidiDeviceInfo d, HMIDIOUT h) + : owner (parent), deviceInfo (d), handle (h) { owner.activeOutputHandles.add (this); } @@ -426,32 +501,41 @@ struct Win32MidiService : public MidiServiceType, } Win32MidiService& owner; - String deviceName; + MidiDeviceInfo deviceInfo; HMIDIOUT handle; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiOutHandle) }; //============================================================================== - struct Win32OutputWrapper : public OutputWrapper + struct Win32OutputWrapper : public OutputWrapper, + public Win32MidiDeviceQuery { - Win32OutputWrapper (Win32MidiService& p, int index) : parent (p) + Win32OutputWrapper (Win32MidiService& p, const String& deviceIdentifier) + : parent (p) { - auto names = getDevices(); + auto devices = getAvailableDevices(); UINT deviceID = MIDI_MAPPER; + String deviceName; - if (isPositiveAndBelow (index, names.size())) + for (int i = 0; i < devices.size(); ++i) { - deviceName = names[index]; - deviceID = index; + auto d = devices.getUnchecked (i); + + if (d.identifier == deviceIdentifier) + { + deviceID = i; + deviceName = d.name; + break; + } } if (deviceID == MIDI_MAPPER) { // use the microsoft sw synth as a default - best not to allow deviceID // to be MIDI_MAPPER, or else device sharing breaks - for (int i = 0; i < names.size(); ++i) - if (names[i].containsIgnoreCase ("microsoft")) + for (int i = 0; i < devices.size(); ++i) + if (devices[i].name.containsIgnoreCase ("microsoft")) deviceID = (UINT) i; } @@ -459,7 +543,7 @@ struct Win32MidiService : public MidiServiceType, { auto* activeHandle = parent.activeOutputHandles.getUnchecked (i); - if (activeHandle->deviceName == deviceName) + if (activeHandle->deviceInfo.identifier == deviceIdentifier) { han = activeHandle; return; @@ -473,7 +557,7 @@ struct Win32MidiService : public MidiServiceType, if (res == MMSYSERR_NOERROR) { - han = new MidiOutHandle (parent, deviceName, h); + han = new MidiOutHandle (parent, { deviceName, deviceIdentifier }, h); return; } @@ -490,7 +574,7 @@ struct Win32MidiService : public MidiServiceType, { if (message.getRawDataSize() > 3 || message.isSysEx()) { - MIDIHDR h = { 0 }; + MIDIHDR h = {}; h.lpData = (char*) message.getRawData(); h.dwBytesRecorded = h.dwBufferLength = (DWORD) message.getRawDataSize(); @@ -530,14 +614,18 @@ struct Win32MidiService : public MidiServiceType, } } + static DWORD sendMidiMessage (UINT_PTR deviceID, UINT msg, DWORD_PTR arg1, DWORD_PTR arg2) + { + return midiOutMessage ((HMIDIOUT) deviceID, msg, arg1, arg2); + } + static Array getDeviceCaps() { Array devices; - auto num = midiOutGetNumDevs(); - for (UINT i = 0; i < num; ++i) + for (UINT i = 0; i < midiOutGetNumDevs(); ++i) { - MIDIOUTCAPS mc = { 0 }; + MIDIOUTCAPS mc = {}; if (midiOutGetDevCaps (i, &mc, sizeof (mc)) == MMSYSERR_NOERROR) devices.add (mc); @@ -546,36 +634,26 @@ struct Win32MidiService : public MidiServiceType, return devices; } - static StringArray getDevices() + static MidiDeviceInfo getDefaultDevice() { - StringArray s; - - for (auto& mc : getDeviceCaps()) - s.add (String (mc.szPname, (size_t) numElementsInArray (mc.szPname))); - - s.appendNumbersToDuplicates (false, false, CharPointer_UTF8 ("-"), CharPointer_UTF8 ("")); - return s; - } - - static int getDefaultDeviceIndex() - { - int n = 0; - - for (auto& mc : getDeviceCaps()) + auto defaultIndex = []() { - if ((mc.wTechnology & MOD_MAPPER) != 0) - return n; + auto deviceCaps = getDeviceCaps(); - ++n; - } + for (int i = 0; i < deviceCaps.size(); ++i) + if ((deviceCaps[i].wTechnology & MOD_MAPPER) != 0) + return i; - return 0; + return 0; + }(); + + return getAvailableDevices()[defaultIndex]; } - String getDeviceName() override { return deviceName; } + String getDeviceIdentifier() override { return han->deviceInfo.identifier; } + String getDeviceName() override { return han->deviceInfo.name; } Win32MidiService& parent; - String deviceName; MidiOutHandle::Ptr han; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Win32OutputWrapper) @@ -638,15 +716,17 @@ struct WinRTMidiService : public MidiServiceType //============================================================================== WinRTMidiService() { - if (! WinRTWrapper::getInstance()->isInitialised()) + auto* wrtWrapper = WinRTWrapper::getInstance(); + + if (! wrtWrapper->isInitialised()) throw std::runtime_error ("Failed to initialise the WinRT wrapper"); - midiInFactory = WinRTWrapper::getInstance()->getWRLFactory (&RuntimeClass_Windows_Devices_Midi_MidiInPort[0]); + midiInFactory = wrtWrapper->getWRLFactory (&RuntimeClass_Windows_Devices_Midi_MidiInPort[0]); if (midiInFactory == nullptr) throw std::runtime_error ("Failed to create midi in factory"); - midiOutFactory = WinRTWrapper::getInstance()->getWRLFactory (&RuntimeClass_Windows_Devices_Midi_MidiOutPort[0]); + midiOutFactory = wrtWrapper->getWRLFactory (&RuntimeClass_Windows_Devices_Midi_MidiOutPort[0]); if (midiOutFactory == nullptr) throw std::runtime_error ("Failed to create midi out factory"); @@ -671,26 +751,26 @@ struct WinRTMidiService : public MidiServiceType throw std::runtime_error ("Failed to start the midi output device watcher"); } - StringArray getDevices (bool isInput) override + Array getAvailableDevices (bool isInput) override { - return isInput ? inputDeviceWatcher ->getDevices() - : outputDeviceWatcher->getDevices(); + return isInput ? inputDeviceWatcher ->getAvailableDevices() + : outputDeviceWatcher->getAvailableDevices(); } - int getDefaultDeviceIndex (bool isInput) override + MidiDeviceInfo getDefaultDevice (bool isInput) override { - return isInput ? inputDeviceWatcher ->getDefaultDeviceIndex() - : outputDeviceWatcher->getDefaultDeviceIndex(); + return isInput ? inputDeviceWatcher ->getDefaultDevice() + : outputDeviceWatcher->getDefaultDevice(); } - InputWrapper* createInputWrapper (MidiInput& input, int index, MidiInputCallback& callback) override + InputWrapper* createInputWrapper (MidiInput& input, const String& deviceIdentifier, MidiInputCallback& callback) override { - return new WinRTInputWrapper (*this, input, index, callback); + return new WinRTInputWrapper (*this, input, deviceIdentifier, callback); } - OutputWrapper* createOutputWrapper (int index) override + OutputWrapper* createOutputWrapper (const String& deviceIdentifier) override { - return new WinRTOutputWrapper (*this, index); + return new WinRTOutputWrapper (*this, deviceIdentifier); } private: @@ -706,16 +786,24 @@ struct WinRTMidiService : public MidiServiceType bool attach (HSTRING deviceSelector, DeviceInformationKind infoKind) { - auto deviceInfoFactory = WinRTWrapper::getInstance()->getWRLFactory (&RuntimeClass_Windows_Devices_Enumeration_DeviceInformation[0]); + auto* wrtWrapper = WinRTWrapper::getInstanceWithoutCreating(); + + if (wrtWrapper == nullptr) + { + JUCE_WINRT_MIDI_LOG ("Failed to get the WinRTWrapper singleton!"); + return false; + } + + auto deviceInfoFactory = wrtWrapper->getWRLFactory (&RuntimeClass_Windows_Devices_Enumeration_DeviceInformation[0]); if (deviceInfoFactory == nullptr) return false; // A quick way of getting an IVector... - auto requestedProperties = [] + auto requestedProperties = [wrtWrapper] { - auto devicePicker = WinRTWrapper::getInstance()->activateInstance (&RuntimeClass_Windows_Devices_Enumeration_DevicePicker[0], - __uuidof (IDevicePicker)); + auto devicePicker = wrtWrapper->activateInstance (&RuntimeClass_Windows_Devices_Enumeration_DevicePicker[0], + __uuidof (IDevicePicker)); jassert (devicePicker != nullptr); IVector* result; @@ -728,9 +816,9 @@ struct WinRTMidiService : public MidiServiceType return result; }(); - StringArray propertyKeys = { "System.Devices.ContainerId", - "System.Devices.Aep.ContainerId", - "System.Devices.Aep.IsConnected" }; + StringArray propertyKeys ("System.Devices.ContainerId", + "System.Devices.Aep.ContainerId", + "System.Devices.Aep.IsConnected"); for (auto& key : propertyKeys) { @@ -902,21 +990,21 @@ struct WinRTMidiService : public MidiServiceType watcher->add_Added ( Callback> ( - [handlerPtr](IDeviceWatcher*, IDeviceInformation* info) { return handlerPtr->addDevice (info); } + [handlerPtr] (IDeviceWatcher*, IDeviceInformation* info) { return handlerPtr->addDevice (info); } ).Get(), &deviceAddedToken); watcher->add_Removed ( Callback> ( - [handlerPtr](IDeviceWatcher*, IDeviceInformationUpdate* infoUpdate) { return handlerPtr->removeDevice (infoUpdate); } + [handlerPtr] (IDeviceWatcher*, IDeviceInformationUpdate* infoUpdate) { return handlerPtr->removeDevice (infoUpdate); } ).Get(), &deviceRemovedToken); watcher->add_Updated ( Callback> ( - [handlerPtr](IDeviceWatcher*, IDeviceInformationUpdate* infoUpdate) { return handlerPtr->updateDevice (infoUpdate); } + [handlerPtr] (IDeviceWatcher*, IDeviceInformationUpdate* infoUpdate) { return handlerPtr->updateDevice (infoUpdate); } ).Get(), - &deviceRemovedToken); + &deviceUpdatedToken); watcher->Start(); } @@ -967,7 +1055,15 @@ struct WinRTMidiService : public MidiServiceType return S_OK; } - auto deviceID = WinRTWrapper::getInstance()->hStringToString (deviceIDHst); + auto* wrtWrapper = WinRTWrapper::getInstanceWithoutCreating(); + + if (wrtWrapper == nullptr) + { + JUCE_WINRT_MIDI_LOG ("Failed to get the WinRTWrapper singleton!"); + return false; + } + + auto deviceID = wrtWrapper->hStringToString (deviceIDHst); JUCE_WINRT_MIDI_LOG ("Detected paired BLE device: " << deviceID); if (auto* containerIDValue = getValueFromDeviceInfo ("System.Devices.Aep.ContainerId", addedDeviceInfo)) @@ -1004,7 +1100,15 @@ struct WinRTMidiService : public MidiServiceType return S_OK; } - auto removedDeviceId = WinRTWrapper::getInstance()->hStringToString (removedDeviceIdHstr); + auto* wrtWrapper = WinRTWrapper::getInstanceWithoutCreating(); + + if (wrtWrapper == nullptr) + { + JUCE_WINRT_MIDI_LOG ("Failed to get the WinRTWrapper singleton!"); + return false; + } + + auto removedDeviceId = wrtWrapper->hStringToString (removedDeviceIdHstr); JUCE_WINRT_MIDI_LOG ("Removing BLE device: " << removedDeviceId); @@ -1014,7 +1118,7 @@ struct WinRTMidiService : public MidiServiceType if (devices.contains (removedDeviceId)) { auto& info = devices.getReference (removedDeviceId); - listeners.call ([&info](Listener& l) { l.bleDeviceDisconnected (info.containerID); }); + listeners.call ([&info] (Listener& l) { l.bleDeviceDisconnected (info.containerID); }); devices.remove (removedDeviceId); JUCE_WINRT_MIDI_LOG ("Removed BLE device: " << removedDeviceId); } @@ -1034,7 +1138,15 @@ struct WinRTMidiService : public MidiServiceType return S_OK; } - auto updatedDeviceId = WinRTWrapper::getInstance()->hStringToString (updatedDeviceIdHstr); + auto* wrtWrapper = WinRTWrapper::getInstanceWithoutCreating(); + + if (wrtWrapper == nullptr) + { + JUCE_WINRT_MIDI_LOG ("Failed to get the WinRTWrapper singleton!"); + return false; + } + + auto updatedDeviceId = wrtWrapper->hStringToString (updatedDeviceIdHstr); JUCE_WINRT_MIDI_LOG ("Updating BLE device: " << updatedDeviceId); @@ -1053,7 +1165,7 @@ struct WinRTMidiService : public MidiServiceType if (info.isConnected && ! isConnected) { JUCE_WINRT_MIDI_LOG ("BLE device connection status change: " << updatedDeviceId << " " << info.containerID << " " << (isConnected ? "connected" : "disconnected")); - listeners.call ([&info](Listener& l) { l.bleDeviceDisconnected (info.containerID); }); + listeners.call ([&info] (Listener& l) { l.bleDeviceDisconnected (info.containerID); }); } info.isConnected = isConnected; @@ -1098,7 +1210,7 @@ struct WinRTMidiService : public MidiServiceType }; //============================================================================== - struct MIDIDeviceInfo + struct WinRTMIDIDeviceInfo { String deviceID, containerID, name; bool isDefault = false; @@ -1120,7 +1232,7 @@ struct WinRTMidiService : public MidiServiceType HRESULT addDevice (IDeviceInformation* addedDeviceInfo) override { - MIDIDeviceInfo info; + WinRTMIDIDeviceInfo info; HSTRING deviceID; auto hr = addedDeviceInfo->get_Id (&deviceID); @@ -1131,7 +1243,15 @@ struct WinRTMidiService : public MidiServiceType return S_OK; } - info.deviceID = WinRTWrapper::getInstance()->hStringToString (deviceID); + auto* wrtWrapper = WinRTWrapper::getInstanceWithoutCreating(); + + if (wrtWrapper == nullptr) + { + JUCE_WINRT_MIDI_LOG ("Failed to get the WinRTWrapper singleton!"); + return false; + } + + info.deviceID = wrtWrapper->hStringToString (deviceID); JUCE_WINRT_MIDI_LOG ("Detected MIDI device: " << info.deviceID); @@ -1157,7 +1277,7 @@ struct WinRTMidiService : public MidiServiceType return S_OK; } - info.name = WinRTWrapper::getInstance()->hStringToString (name); + info.name = wrtWrapper->hStringToString (name); boolean isDefault = false; hr = addedDeviceInfo->get_IsDefault (&isDefault); @@ -1191,7 +1311,15 @@ struct WinRTMidiService : public MidiServiceType return S_OK; } - auto removedDeviceId = WinRTWrapper::getInstance()->hStringToString (removedDeviceIdHstr); + auto* wrtWrapper = WinRTWrapper::getInstanceWithoutCreating(); + + if (wrtWrapper == nullptr) + { + JUCE_WINRT_MIDI_LOG ("Failed to get the WinRTWrapper singleton!"); + return false; + } + + auto removedDeviceId = wrtWrapper->hStringToString (removedDeviceIdHstr); JUCE_WINRT_MIDI_LOG ("Removing MIDI device: " << removedDeviceId); @@ -1229,56 +1357,59 @@ struct WinRTMidiService : public MidiServiceType return attach (deviceSelector, DeviceInformationKind::DeviceInformationKind_DeviceInterface); } - StringArray getDevices() + Array getAvailableDevices() { { const ScopedLock lock (deviceChanges); lastQueriedConnectedDevices = connectedDevices; } - StringArray result; + StringArray deviceNames, deviceIDs; for (auto info : lastQueriedConnectedDevices.get()) - result.add (info.name); + { + deviceNames.add (info.name); + deviceIDs .add (info.containerID); + } - return result; - } + deviceNames.appendNumbersToDuplicates (false, false, CharPointer_UTF8 ("-"), CharPointer_UTF8 ("")); + deviceIDs .appendNumbersToDuplicates (false, false, CharPointer_UTF8 ("-"), CharPointer_UTF8 ("")); - int getDefaultDeviceIndex() - { - auto& lastDevices = lastQueriedConnectedDevices.get(); + Array devices; - for (int i = 0; i < lastDevices.size(); ++i) - if (lastDevices[i].isDefault) - return i; + for (int i = 0; i < deviceNames.size(); ++i) + devices.add ({ deviceNames[i], deviceIDs[i] }); - return 0; + return devices; } - MIDIDeviceInfo getDeviceInfoFromIndex (int index) + MidiDeviceInfo getDefaultDevice() { - if (isPositiveAndBelow (index, lastQueriedConnectedDevices.get().size())) - return lastQueriedConnectedDevices.get()[index]; + auto& lastDevices = lastQueriedConnectedDevices.get(); + + for (auto& d : lastDevices) + if (d.isDefault) + return { d.name, d.containerID }; return {}; } - String getDeviceID (const String& name) + WinRTMIDIDeviceInfo getWinRTDeviceInfoForDevice (const String& deviceIdentifier) { - const ScopedLock lock (deviceChanges); + auto devices = getAvailableDevices(); - for (auto info : connectedDevices) - if (info.name == name) - return info.deviceID; + for (int i = 0; i < devices.size(); ++i) + if (devices.getUnchecked (i).identifier == deviceIdentifier) + return lastQueriedConnectedDevices.get()[i]; return {}; } WinRTWrapper::ComPtr& factory; - Array connectedDevices; + Array connectedDevices; CriticalSection deviceChanges; - ThreadLocalValue> lastQueriedConnectedDevices; + ThreadLocalValue> lastQueriedConnectedDevices; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiIODeviceWatcher); }; @@ -1327,8 +1458,8 @@ struct WinRTMidiService : public MidiServiceType } ).Get()); - // We need to use a timout here, rather than waiting indefinitely, as the - // WinRT API can occaisonally hang! + // We need to use a timeout here, rather than waiting indefinitely, as the + // WinRT API can occasionally hang! portOpened.wait (2000); } @@ -1345,12 +1476,12 @@ struct WinRTMidiService : public MidiServiceType public: WinRTIOWrapper (BLEDeviceWatcher& bleWatcher, MidiIODeviceWatcher& midiDeviceWatcher, - int index) + const String& deviceIdentifier) : bleDeviceWatcher (bleWatcher) { { const ScopedLock lock (midiDeviceWatcher.deviceChanges); - deviceInfo = midiDeviceWatcher.getDeviceInfoFromIndex (index); + deviceInfo = midiDeviceWatcher.getWinRTDeviceInfoForDevice (deviceIdentifier); } if (deviceInfo.deviceID.isEmpty()) @@ -1417,7 +1548,7 @@ struct WinRTMidiService : public MidiServiceType protected: //============================================================================== BLEDeviceWatcher& bleDeviceWatcher; - MIDIDeviceInfo deviceInfo; + WinRTMIDIDeviceInfo deviceInfo; bool isBLEDevice = false; WinRTWrapper::ComPtr midiPort; }; @@ -1427,8 +1558,8 @@ struct WinRTMidiService : public MidiServiceType private WinRTIOWrapper { - WinRTInputWrapper (WinRTMidiService& service, MidiInput& input, int index, MidiInputCallback& cb) - : WinRTIOWrapper (*service.bleDeviceWatcher, *service.inputDeviceWatcher, index), + WinRTInputWrapper (WinRTMidiService& service, MidiInput& input, const String& deviceIdentifier, MidiInputCallback& cb) + : WinRTIOWrapper (*service.bleDeviceWatcher, *service.inputDeviceWatcher, deviceIdentifier), inputDevice (input), callback (cb) { @@ -1449,7 +1580,7 @@ struct WinRTMidiService : public MidiServiceType auto hr = midiPort->add_MessageReceived ( Callback> ( - [this](IMidiInPort*, IMidiMessageReceivedEventArgs* args) { return midiInMessageReceived (args); } + [this] (IMidiInPort*, IMidiMessageReceivedEventArgs* args) { return midiInMessageReceived (args); } ).Get(), &midiInMessageToken); @@ -1484,7 +1615,8 @@ struct WinRTMidiService : public MidiServiceType } } - String getDeviceName() override { return deviceInfo.name; } + String getDeviceIdentifier() override { return deviceInfo.containerID; } + String getDeviceName() override { return deviceInfo.name; } //============================================================================== void disconnect() override @@ -1579,8 +1711,8 @@ struct WinRTMidiService : public MidiServiceType struct WinRTOutputWrapper final : public OutputWrapper, private WinRTIOWrapper { - WinRTOutputWrapper (WinRTMidiService& service, int index) - : WinRTIOWrapper (*service.bleDeviceWatcher, *service.outputDeviceWatcher, index) + WinRTOutputWrapper (WinRTMidiService& service, const String& deviceIdentifier) + : WinRTIOWrapper (*service.bleDeviceWatcher, *service.outputDeviceWatcher, deviceIdentifier) { OpenMidiPortThread portThread ("Open WinRT MIDI output port", deviceInfo.deviceID, @@ -1592,7 +1724,12 @@ struct WinRTMidiService : public MidiServiceType if (midiPort == nullptr) throw std::runtime_error ("Timed out waiting for midi output port creation"); - auto bufferFactory = WinRTWrapper::getInstance()->getWRLFactory (&RuntimeClass_Windows_Storage_Streams_Buffer[0]); + auto* wrtWrapper = WinRTWrapper::getInstanceWithoutCreating(); + + if (wrtWrapper == nullptr) + throw std::runtime_error ("Failed to get the WinRTWrapper singleton!"); + + auto bufferFactory = wrtWrapper->getWRLFactory (&RuntimeClass_Windows_Storage_Streams_Buffer[0]); if (bufferFactory == nullptr) throw std::runtime_error ("Failed to create output buffer factory"); @@ -1632,7 +1769,8 @@ struct WinRTMidiService : public MidiServiceType midiPort->SendBuffer (buffer); } - String getDeviceName() override { return deviceInfo.name; } + String getDeviceIdentifier() override { return deviceInfo.containerID; } + String getDeviceName() override { return deviceInfo.name; } //============================================================================== WinRTWrapper::ComPtr buffer; @@ -1656,33 +1794,17 @@ struct WinRTMidiService : public MidiServiceType //============================================================================== //============================================================================== +#if ! JUCE_MINGW + extern RTL_OSVERSIONINFOW getWindowsVersionInfo(); +#endif + struct MidiService : public DeletedAtShutdown { MidiService() { - #if JUCE_USE_WINRT_MIDI + #if JUCE_USE_WINRT_MIDI && ! JUCE_MINGW #if ! JUCE_FORCE_WINRT_MIDI - auto windowsVersionInfo = [] - { - RTL_OSVERSIONINFOW versionInfo = { 0 }; - - if (auto* mod = ::GetModuleHandleW (L"ntdll.dll")) - { - using RtlGetVersion = LONG (WINAPI*)(PRTL_OSVERSIONINFOW); - - if (auto* rtlGetVersion = (RtlGetVersion) ::GetProcAddress (mod, "RtlGetVersion")) - { - versionInfo.dwOSVersionInfoSize = sizeof (versionInfo); - LONG STATUS_SUCCESS = 0; - - if (rtlGetVersion (&versionInfo) != STATUS_SUCCESS) - versionInfo = { 0 }; - } - } - - return versionInfo; - }(); - + auto windowsVersionInfo = getWindowsVersionInfo(); if (windowsVersionInfo.dwMajorVersion >= 10 && windowsVersionInfo.dwBuildNumber >= 17763) #endif { @@ -1718,40 +1840,71 @@ struct MidiService : public DeletedAtShutdown JUCE_IMPLEMENT_SINGLETON (MidiService) //============================================================================== -StringArray MidiInput::getDevices() +static int findDefaultDeviceIndex (const Array& available, const MidiDeviceInfo& defaultDevice) { - return MidiService::getService().getDevices (true); + for (int i = 0; i < available.size(); ++i) + if (available.getUnchecked (i) == defaultDevice) + return i; + + return 0; } -int MidiInput::getDefaultDeviceIndex() +Array MidiInput::getAvailableDevices() { - return MidiService::getService().getDefaultDeviceIndex (true); + return MidiService::getService().getAvailableDevices (true); } -MidiInput::MidiInput (const String& deviceName) : name (deviceName) +MidiDeviceInfo MidiInput::getDefaultDevice() { + return MidiService::getService().getDefaultDevice (true); } -MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) +std::unique_ptr MidiInput::openDevice (const String& deviceIdentifier, MidiInputCallback* callback) { - if (callback == nullptr) - return nullptr; + if (deviceIdentifier.isEmpty() || callback == nullptr) + return {}; - std::unique_ptr in (new MidiInput (String())); + std::unique_ptr in (new MidiInput ({}, deviceIdentifier)); std::unique_ptr wrapper; try { - wrapper.reset (MidiService::getService().createInputWrapper (*in, index, *callback)); + wrapper.reset (MidiService::getService().createInputWrapper (*in, deviceIdentifier, *callback)); } catch (std::runtime_error&) { - return nullptr; + return {}; } in->setName (wrapper->getDeviceName()); in->internal = wrapper.release(); - return in.release(); + + return in; +} + +StringArray MidiInput::getDevices() +{ + StringArray deviceNames; + + for (auto& d : getAvailableDevices()) + deviceNames.add (d.name); + + return deviceNames; +} + +int MidiInput::getDefaultDeviceIndex() +{ + return findDefaultDeviceIndex (getAvailableDevices(), getDefaultDevice()); +} + +std::unique_ptr MidiInput::openDevice (int index, MidiInputCallback* callback) +{ + return openDevice (getAvailableDevices()[index].identifier, callback); +} + +MidiInput::MidiInput (const String& deviceName, const String& deviceIdentifier) + : deviceInfo (deviceName, deviceIdentifier) +{ } MidiInput::~MidiInput() @@ -1763,32 +1916,58 @@ void MidiInput::start() { static_cast (interna void MidiInput::stop() { static_cast (internal)->stop(); } //============================================================================== -StringArray MidiOutput::getDevices() +Array MidiOutput::getAvailableDevices() { - return MidiService::getService().getDevices (false); + return MidiService::getService().getAvailableDevices (false); } -int MidiOutput::getDefaultDeviceIndex() +MidiDeviceInfo MidiOutput::getDefaultDevice() { - return MidiService::getService().getDefaultDeviceIndex (false); + return MidiService::getService().getDefaultDevice (false); } -MidiOutput* MidiOutput::openDevice (int index) +std::unique_ptr MidiOutput::openDevice (const String& deviceIdentifier) { + if (deviceIdentifier.isEmpty()) + return {}; + std::unique_ptr wrapper; try { - wrapper.reset (MidiService::getService().createOutputWrapper (index)); + wrapper.reset (MidiService::getService().createOutputWrapper (deviceIdentifier)); } catch (std::runtime_error&) { - return nullptr; + return {}; } - std::unique_ptr out (new MidiOutput (wrapper->getDeviceName())); + std::unique_ptr out; + out.reset (new MidiOutput (wrapper->getDeviceName(), deviceIdentifier)); + out->internal = wrapper.release(); - return out.release(); + + return out; +} + +StringArray MidiOutput::getDevices() +{ + StringArray deviceNames; + + for (auto& d : getAvailableDevices()) + deviceNames.add (d.name); + + return deviceNames; +} + +int MidiOutput::getDefaultDeviceIndex() +{ + return findDefaultDeviceIndex (getAvailableDevices(), getDefaultDevice()); +} + +std::unique_ptr MidiOutput::openDevice (int index) +{ + return openDevice (getAvailableDevices()[index].identifier); } MidiOutput::~MidiOutput() diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_WASAPI.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_WASAPI.cpp index 1264848..64d2004 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_WASAPI.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_WASAPI.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. @@ -352,8 +352,8 @@ void copyWavFormat (WAVEFORMATEXTENSIBLE& dest, const WAVEFORMATEX* src) noexcep class WASAPIDeviceBase { public: - WASAPIDeviceBase (const ComSmartPtr& d, bool exclusiveMode, std::function&& cb) - : device (d), useExclusiveMode (exclusiveMode), reopenCallback (cb) + WASAPIDeviceBase (const ComSmartPtr& d, bool exclusiveMode) + : device (d), useExclusiveMode (exclusiveMode) { clientEvent = CreateEvent (nullptr, false, false, nullptr); @@ -429,7 +429,8 @@ class WASAPIDeviceBase && tryInitialisingWithBufferSize (bufferSizeSamples)) { sampleRateHasChanged = false; - shouldClose = false; + shouldShutdown = false; + channelMaps.clear(); for (int i = 0; i <= channels.getHighestBit(); ++i) @@ -454,6 +455,10 @@ class WASAPIDeviceBase if (client != nullptr) client->Stop(); + // N.B. this is needed to prevent a double-deletion of the IAudioSessionEvents object + // on older versions of Windows + Thread::sleep (5); + deleteSessionEventCallback(); client = nullptr; ResetEvent (clientEvent); @@ -464,9 +469,19 @@ class WASAPIDeviceBase sampleRateHasChanged = true; } - void deviceBecameInactive() + void deviceSessionBecameInactive() + { + isActive = false; + } + + void deviceSessionExpired() { - shouldClose = true; + shouldShutdown = true; + } + + void deviceSessionBecameActive() + { + isActive = true; } //============================================================================== @@ -483,8 +498,7 @@ class WASAPIDeviceBase Array channelMaps; UINT32 actualBufferSize = 0; int bytesPerSample = 0, bytesPerFrame = 0; - bool sampleRateHasChanged = false, shouldClose = false; - std::function reopenCallback; + std::atomic sampleRateHasChanged { false }, shouldShutdown { false }, isActive { true }; virtual void updateFormat (bool isFloat) = 0; @@ -500,13 +514,20 @@ class WASAPIDeviceBase JUCE_COMRESULT OnChannelVolumeChanged (DWORD, float*, DWORD, LPCGUID) { return S_OK; } JUCE_COMRESULT OnGroupingParamChanged (LPCGUID, LPCGUID) { return S_OK; } - JUCE_COMRESULT OnStateChanged(AudioSessionState state) + JUCE_COMRESULT OnStateChanged (AudioSessionState state) { - if (state == AudioSessionStateActive) - owner.reopenCallback(); - - if (state == AudioSessionStateInactive || state == AudioSessionStateExpired) - owner.deviceBecameInactive(); + switch (state) + { + case AudioSessionStateInactive: + owner.deviceSessionBecameInactive(); + break; + case AudioSessionStateExpired: + owner.deviceSessionExpired(); + break; + case AudioSessionStateActive: + owner.deviceSessionBecameActive(); + break; + } return S_OK; } @@ -688,8 +709,8 @@ class WASAPIDeviceBase class WASAPIInputDevice : public WASAPIDeviceBase { public: - WASAPIInputDevice (const ComSmartPtr& d, bool exclusiveMode, std::function&& reopenCallback) - : WASAPIDeviceBase (d, exclusiveMode, std::move (reopenCallback)) + WASAPIInputDevice (const ComSmartPtr& d, bool exclusiveMode) + : WASAPIDeviceBase (d, exclusiveMode) { } @@ -742,6 +763,8 @@ class WASAPIInputDevice : public WASAPIDeviceBase return false; purgeInputBuffers(); + isActive = true; + return true; } @@ -849,8 +872,8 @@ class WASAPIInputDevice : public WASAPIDeviceBase class WASAPIOutputDevice : public WASAPIDeviceBase { public: - WASAPIOutputDevice (const ComSmartPtr& d, bool exclusiveMode, std::function&& reopenCallback) - : WASAPIDeviceBase (d, exclusiveMode, std::move (reopenCallback)) + WASAPIOutputDevice (const ComSmartPtr& d, bool exclusiveMode) + : WASAPIDeviceBase (d, exclusiveMode) { } @@ -895,7 +918,12 @@ class WASAPIOutputDevice : public WASAPIDeviceBase if (check (renderClient->GetBuffer (samplesToDo, &outputData))) renderClient->ReleaseBuffer (samplesToDo, AUDCLNT_BUFFERFLAGS_SILENT); - return check (client->Start()); + if (! check (client->Start())) + return false; + + isActive = true; + + return true; } int getNumSamplesAvailableToCopy() const @@ -1016,7 +1044,9 @@ class WASAPIAudioIODevice : public AudioIODevice, sampleRates = d->rates; } + bufferSizes.clear(); bufferSizes.addUsingDefaultSort (defaultBufferSize); + if (minBufferSize != defaultBufferSize) bufferSizes.addUsingDefaultSort (minBufferSize); @@ -1118,7 +1148,8 @@ class WASAPIAudioIODevice : public AudioIODevice, if (inputDevice != nullptr) ResetEvent (inputDevice->clientEvent); if (outputDevice != nullptr) ResetEvent (outputDevice->clientEvent); - deviceBecameInactive = false; + shouldShutdown = false; + deviceSampleRateChanged = false; startThread (8); Thread::sleep (5); @@ -1227,7 +1258,6 @@ class WASAPIAudioIODevice : public AudioIODevice, auto bufferSize = currentBufferSizeSamples; auto numInputBuffers = getActiveInputChannels().countNumberOfSetBits(); auto numOutputBuffers = getActiveOutputChannels().countNumberOfSetBits(); - bool sampleRateHasChanged = false; AudioBuffer ins (jmax (1, numInputBuffers), bufferSize + 32); AudioBuffer outs (jmax (1, numOutputBuffers), bufferSize + 32); @@ -1238,14 +1268,23 @@ class WASAPIAudioIODevice : public AudioIODevice, while (! threadShouldExit()) { - if (outputDevice != nullptr && outputDevice->shouldClose) - deviceBecameInactive = true; - - if (inputDevice != nullptr && ! deviceBecameInactive) + if ((outputDevice != nullptr && outputDevice->shouldShutdown) + || (inputDevice != nullptr && inputDevice->shouldShutdown)) { - if (inputDevice->shouldClose) - deviceBecameInactive = true; + shouldShutdown = true; + triggerAsyncUpdate(); + + break; + } + + auto inputDeviceActive = (inputDevice != nullptr && inputDevice->isActive); + auto outputDeviceActive = (outputDevice != nullptr && outputDevice->isActive); + + if (! inputDeviceActive && ! outputDeviceActive) + continue; + if (inputDeviceActive) + { if (outputDevice == nullptr) { if (WaitForSingleObject (inputDevice->clientEvent, 1000) == WAIT_TIMEOUT) @@ -1266,12 +1305,13 @@ class WASAPIAudioIODevice : public AudioIODevice, if (inputDevice->sampleRateHasChanged) { - sampleRateHasChanged = true; - sampleRateChangedByOutput = false; + deviceSampleRateChanged = true; + triggerAsyncUpdate(); + + break; } } - if (! deviceBecameInactive) { const ScopedTryLock sl (startStopLock); @@ -1282,7 +1322,7 @@ class WASAPIAudioIODevice : public AudioIODevice, outs.clear(); } - if (outputDevice != nullptr && ! deviceBecameInactive) + if (outputDeviceActive) { // Note that this function is handed the input device so it can check for the event and make sure // the input reservoir is filled up correctly even when bufferSize > device actualBufferSize @@ -1290,15 +1330,11 @@ class WASAPIAudioIODevice : public AudioIODevice, if (outputDevice->sampleRateHasChanged) { - sampleRateHasChanged = true; - sampleRateChangedByOutput = true; - } - } + deviceSampleRateChanged = true; + triggerAsyncUpdate(); - if (sampleRateHasChanged || deviceBecameInactive) - { - triggerAsyncUpdate(); - break; // Quit the thread... will restart it later! + break; + } } } } @@ -1326,7 +1362,7 @@ class WASAPIAudioIODevice : public AudioIODevice, AudioIODeviceCallback* callback = {}; CriticalSection startStopLock; - bool sampleRateChangedByOutput = false, deviceBecameInactive = false; + std::atomic shouldShutdown { false }, deviceSampleRateChanged { false }; BigInteger lastKnownInputChannels, lastKnownOutputChannels; @@ -1362,57 +1398,54 @@ class WASAPIAudioIODevice : public AudioIODevice, auto flow = getDataFlow (device); - auto deviceReopenCallback = [this] - { - if (deviceBecameInactive) - { - deviceBecameInactive = false; - MessageManager::callAsync ([this] { reopenDevices(); }); - } - }; - if (deviceId == inputDeviceId && flow == eCapture) - inputDevice.reset (new WASAPIInputDevice (device, useExclusiveMode, deviceReopenCallback)); + inputDevice.reset (new WASAPIInputDevice (device, useExclusiveMode)); else if (deviceId == outputDeviceId && flow == eRender) - outputDevice.reset (new WASAPIOutputDevice (device, useExclusiveMode, deviceReopenCallback)); + outputDevice.reset (new WASAPIOutputDevice (device, useExclusiveMode)); } return (outputDeviceId.isEmpty() || (outputDevice != nullptr && outputDevice->isOk())) && (inputDeviceId.isEmpty() || (inputDevice != nullptr && inputDevice->isOk())); } - void reopenDevices() + //============================================================================== + void handleAsyncUpdate() override { - outputDevice = nullptr; - inputDevice = nullptr; + auto closeDevices = [this] + { + close(); - initialise(); + outputDevice = nullptr; + inputDevice = nullptr; + }; - open (lastKnownInputChannels, lastKnownOutputChannels, - getChangedSampleRate(), currentBufferSizeSamples); + if (shouldShutdown) + { + closeDevices(); + } + else if (deviceSampleRateChanged) + { + auto sampleRateChangedByInput = (inputDevice != nullptr && inputDevice->sampleRateHasChanged); - start (callback); - } + closeDevices(); + initialise(); - //============================================================================== - void handleAsyncUpdate() override - { - stop(); + auto changedSampleRate = [this, sampleRateChangedByInput]() + { + if (inputDevice != nullptr && sampleRateChangedByInput) + return inputDevice->defaultSampleRate; - // sample rate change - if (! deviceBecameInactive) - reopenDevices(); - } + if (outputDevice != nullptr && ! sampleRateChangedByInput) + return outputDevice->defaultSampleRate; - double getChangedSampleRate() const - { - if (outputDevice != nullptr && sampleRateChangedByOutput) - return outputDevice->defaultSampleRate; + return 0.0; + }(); - if (inputDevice != nullptr && ! sampleRateChangedByOutput) - return inputDevice->defaultSampleRate; + open (lastKnownInputChannels, lastKnownOutputChannels, + changedSampleRate, currentBufferSizeSamples); - return 0.0; + start (callback); + } } //============================================================================== @@ -1439,7 +1472,7 @@ class WASAPIAudioIODeviceType : public AudioIODeviceType, } //============================================================================== - void scanForDevices() + void scanForDevices() override { hasScanned = true; @@ -1452,7 +1485,7 @@ class WASAPIAudioIODeviceType : public AudioIODeviceType, outputDeviceIds, inputDeviceIds); } - StringArray getDeviceNames (bool wantInputNames) const + StringArray getDeviceNames (bool wantInputNames) const override { jassert (hasScanned); // need to call scanForDevices() before doing this @@ -1460,13 +1493,13 @@ class WASAPIAudioIODeviceType : public AudioIODeviceType, : outputDeviceNames; } - int getDefaultDeviceIndex (bool /*forInput*/) const + int getDefaultDeviceIndex (bool /*forInput*/) const override { jassert (hasScanned); // need to call scanForDevices() before doing this return 0; } - int getIndexOfDevice (AudioIODevice* device, bool asInput) const + int getIndexOfDevice (AudioIODevice* device, bool asInput) const override { jassert (hasScanned); // need to call scanForDevices() before doing this @@ -1477,10 +1510,10 @@ class WASAPIAudioIODeviceType : public AudioIODeviceType, return -1; } - bool hasSeparateInputsAndOutputs() const { return true; } + bool hasSeparateInputsAndOutputs() const override { return true; } AudioIODevice* createDevice (const String& outputDeviceName, - const String& inputDeviceName) + const String& inputDeviceName) override { jassert (hasScanned); // need to call scanForDevices() before doing this @@ -1533,7 +1566,7 @@ class WASAPIAudioIODeviceType : public AudioIODeviceType, HRESULT notify() { if (device != nullptr) - device->triggerAsyncDeviceChangeCallback(); + device->triggerAsyncDeviceChangeCallback(); return S_OK; } diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/CMakeLists.txt b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/CMakeLists.txt new file mode 100644 index 0000000..f05dd46 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/CMakeLists.txt @@ -0,0 +1,91 @@ +cmake_minimum_required(VERSION 3.4.1) + +# Set the name of the project and store it in PROJECT_NAME. Also set the following variables: +# PROJECT_SOURCE_DIR (usually the root directory where Oboe has been cloned e.g.) +# PROJECT_BINARY_DIR (usually the containing project's binary directory, +# e.g. ${OBOE_HOME}/samples/RhythmGame/.externalNativeBuild/cmake/ndkExtractorDebug/x86/oboe-bin) +project(oboe) + +set (oboe_sources + src/aaudio/AAudioLoader.cpp + src/aaudio/AudioStreamAAudio.cpp + src/common/AudioSourceCaller.cpp + src/common/AudioStream.cpp + src/common/AudioStreamBuilder.cpp + src/common/DataConversionFlowGraph.cpp + src/common/FilterAudioStream.cpp + src/common/FixedBlockAdapter.cpp + src/common/FixedBlockReader.cpp + src/common/FixedBlockWriter.cpp + src/common/LatencyTuner.cpp + src/common/SourceFloatCaller.cpp + src/common/SourceI16Caller.cpp + src/common/Utilities.cpp + src/common/QuirksManager.cpp + src/fifo/FifoBuffer.cpp + src/fifo/FifoController.cpp + src/fifo/FifoControllerBase.cpp + src/fifo/FifoControllerIndirect.cpp + src/flowgraph/FlowGraphNode.cpp + src/flowgraph/ClipToRange.cpp + src/flowgraph/ManyToMultiConverter.cpp + src/flowgraph/MonoToMultiConverter.cpp + src/flowgraph/RampLinear.cpp + src/flowgraph/SampleRateConverter.cpp + src/flowgraph/SinkFloat.cpp + src/flowgraph/SinkI16.cpp + src/flowgraph/SinkI24.cpp + src/flowgraph/SourceFloat.cpp + src/flowgraph/SourceI16.cpp + src/flowgraph/SourceI24.cpp + src/flowgraph/resampler/IntegerRatio.cpp + src/flowgraph/resampler/LinearResampler.cpp + src/flowgraph/resampler/MultiChannelResampler.cpp + src/flowgraph/resampler/PolyphaseResampler.cpp + src/flowgraph/resampler/PolyphaseResamplerMono.cpp + src/flowgraph/resampler/PolyphaseResamplerStereo.cpp + src/flowgraph/resampler/SincResampler.cpp + src/flowgraph/resampler/SincResamplerStereo.cpp + src/opensles/AudioInputStreamOpenSLES.cpp + src/opensles/AudioOutputStreamOpenSLES.cpp + src/opensles/AudioStreamBuffered.cpp + src/opensles/AudioStreamOpenSLES.cpp + src/opensles/EngineOpenSLES.cpp + src/opensles/OpenSLESUtilities.cpp + src/opensles/OutputMixerOpenSLES.cpp + src/common/StabilizedCallback.cpp + src/common/Trace.cpp + src/common/Version.cpp + ) + +add_library(oboe ${oboe_sources}) + +# Specify directories which the compiler should look for headers +target_include_directories(oboe + PRIVATE src + PUBLIC include) + +# JUCE CHANGE STARTS HERE + +# This comment provided for Apache License compliance. We've removed the extra warnings flags and +# the `-Werror` option, to avoid cases where compilers produce unexpected errors and fail the build. +# We've also removed the explicit `-std=c++14` compile option, and replaced it with a more +# cmake-friendly way of specifying the language standard. + +target_compile_options(oboe PRIVATE -Ofast) +set_target_properties(oboe PROPERTIES CXX_STANDARD 14 CXX_STANDARD_REQUIRED TRUE CXX_EXTENSIONS FALSE) + +# JUCE CHANGE ENDS HERE + +# Enable logging for debug builds +target_compile_definitions(oboe PUBLIC $<$:OBOE_ENABLE_LOGGING=1>) + +target_link_libraries(oboe PRIVATE log OpenSLES) + +# When installing oboe put the libraries in the lib/ folder e.g. lib/arm64-v8a +install(TARGETS oboe + LIBRARY DESTINATION lib/${ANDROID_ABI} + ARCHIVE DESTINATION lib/${ANDROID_ABI}) + +# Also install the headers +install(DIRECTORY include/oboe DESTINATION include) diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/LICENSE b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/LICENSE new file mode 100755 index 0000000..d645695 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/AudioStream.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/AudioStream.h new file mode 100644 index 0000000..a158aaf --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/AudioStream.h @@ -0,0 +1,543 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_STREAM_H_ +#define OBOE_STREAM_H_ + +#include +#include +#include +#include +#include "oboe/Definitions.h" +#include "oboe/ResultWithValue.h" +#include "oboe/AudioStreamBuilder.h" +#include "oboe/AudioStreamBase.h" + +/** WARNING - UNDER CONSTRUCTION - THIS API WILL CHANGE. */ + +namespace oboe { + +/** + * The default number of nanoseconds to wait for when performing state change operations on the + * stream, such as `start` and `stop`. + * + * @see oboe::AudioStream::start + */ +constexpr int64_t kDefaultTimeoutNanos = (2000 * kNanosPerMillisecond); + +/** + * Base class for Oboe C++ audio stream. + */ +class AudioStream : public AudioStreamBase { + friend class AudioStreamBuilder; // allow access to setWeakThis() and lockWeakThis() +public: + + AudioStream() {} + + /** + * Construct an `AudioStream` using the given `AudioStreamBuilder` + * + * @param builder containing all the stream's attributes + */ + explicit AudioStream(const AudioStreamBuilder &builder); + + virtual ~AudioStream() = default; + + /** + * Open a stream based on the current settings. + * + * Note that we do not recommend re-opening a stream that has been closed. + * TODO Should we prevent re-opening? + * + * @return + */ + virtual Result open() { + return Result::OK; // Called by subclasses. Might do more in the future. + } + + /** + * Close the stream and deallocate any resources from the open() call. + */ + virtual Result close(); + + /** + * Start the stream. This will block until the stream has been started, an error occurs + * or `timeoutNanoseconds` has been reached. + */ + virtual Result start(int64_t timeoutNanoseconds = kDefaultTimeoutNanos); + + /** + * Pause the stream. This will block until the stream has been paused, an error occurs + * or `timeoutNanoseconds` has been reached. + */ + virtual Result pause(int64_t timeoutNanoseconds = kDefaultTimeoutNanos); + + /** + * Flush the stream. This will block until the stream has been flushed, an error occurs + * or `timeoutNanoseconds` has been reached. + */ + virtual Result flush(int64_t timeoutNanoseconds = kDefaultTimeoutNanos); + + /** + * Stop the stream. This will block until the stream has been stopped, an error occurs + * or `timeoutNanoseconds` has been reached. + */ + virtual Result stop(int64_t timeoutNanoseconds = kDefaultTimeoutNanos); + + /* Asynchronous requests. + * Use waitForStateChange() if you need to wait for completion. + */ + + /** + * Start the stream asynchronously. Returns immediately (does not block). Equivalent to calling + * `start(0)`. + */ + virtual Result requestStart() = 0; + + /** + * Pause the stream asynchronously. Returns immediately (does not block). Equivalent to calling + * `pause(0)`. + */ + virtual Result requestPause() = 0; + + /** + * Flush the stream asynchronously. Returns immediately (does not block). Equivalent to calling + * `flush(0)`. + */ + virtual Result requestFlush() = 0; + + /** + * Stop the stream asynchronously. Returns immediately (does not block). Equivalent to calling + * `stop(0)`. + */ + virtual Result requestStop() = 0; + + /** + * Query the current state, eg. StreamState::Pausing + * + * @return state or a negative error. + */ + virtual StreamState getState() const = 0; + + /** + * Wait until the stream's current state no longer matches the input state. + * The input state is passed to avoid race conditions caused by the state + * changing between calls. + * + * Note that generally applications do not need to call this. It is considered + * an advanced technique and is mostly used for testing. + * + *

+     * int64_t timeoutNanos = 500 * kNanosPerMillisecond; // arbitrary 1/2 second
+     * StreamState currentState = stream->getState();
+     * StreamState nextState = StreamState::Unknown;
+     * while (result == Result::OK && currentState != StreamState::Paused) {
+     *     result = stream->waitForStateChange(
+     *                                   currentState, &nextState, timeoutNanos);
+     *     currentState = nextState;
+     * }
+     * 
+ * + * If the state does not change within the timeout period then it will + * return ErrorTimeout. This is true even if timeoutNanoseconds is zero. + * + * @param inputState The state we want to change away from. + * @param nextState Pointer to a variable that will be set to the new state. + * @param timeoutNanoseconds The maximum time to wait in nanoseconds. + * @return Result::OK or a Result::Error. + */ + virtual Result waitForStateChange(StreamState inputState, + StreamState *nextState, + int64_t timeoutNanoseconds) = 0; + + /** + * This can be used to adjust the latency of the buffer by changing + * the threshold where blocking will occur. + * By combining this with getXRunCount(), the latency can be tuned + * at run-time for each device. + * + * This cannot be set higher than getBufferCapacity(). + * + * @param requestedFrames requested number of frames that can be filled without blocking + * @return the resulting buffer size in frames (obtained using value()) or an error (obtained + * using error()) + */ + virtual ResultWithValue setBufferSizeInFrames(int32_t /* requestedFrames */) { + return Result::ErrorUnimplemented; + } + + /** + * An XRun is an Underrun or an Overrun. + * During playing, an underrun will occur if the stream is not written in time + * and the system runs out of valid data. + * During recording, an overrun will occur if the stream is not read in time + * and there is no place to put the incoming data so it is discarded. + * + * An underrun or overrun can cause an audible "pop" or "glitch". + * + * @return a result which is either Result::OK with the xRun count as the value, or a + * Result::Error* code + */ + virtual ResultWithValue getXRunCount() const { + return ResultWithValue(Result::ErrorUnimplemented); + } + + /** + * @return true if XRun counts are supported on the stream + */ + virtual bool isXRunCountSupported() const = 0; + + /** + * Query the number of frames that are read or written by the endpoint at one time. + * + * @return burst size + */ + virtual int32_t getFramesPerBurst() = 0; + + /** + * Get the number of bytes in each audio frame. This is calculated using the channel count + * and the sample format. For example, a 2 channel floating point stream will have + * 2 * 4 = 8 bytes per frame. + * + * @return number of bytes in each audio frame. + */ + int32_t getBytesPerFrame() const { return mChannelCount * getBytesPerSample(); } + + /** + * Get the number of bytes per sample. This is calculated using the sample format. For example, + * a stream using 16-bit integer samples will have 2 bytes per sample. + * + * @return the number of bytes per sample. + */ + int32_t getBytesPerSample() const; + + /** + * The number of audio frames written into the stream. + * This monotonic counter will never get reset. + * + * @return the number of frames written so far + */ + virtual int64_t getFramesWritten(); + + /** + * The number of audio frames read from the stream. + * This monotonic counter will never get reset. + * + * @return the number of frames read so far + */ + virtual int64_t getFramesRead(); + + /** + * Calculate the latency of a stream based on getTimestamp(). + * + * Output latency is the time it takes for a given frame to travel from the + * app to some type of digital-to-analog converter. If the DAC is external, for example + * in a USB interface or a TV connected by HDMI, then there may be additional latency + * that the Android device is unaware of. + * + * Input latency is the time it takes to a given frame to travel from an analog-to-digital + * converter (ADC) to the app. + * + * Note that the latency of an OUTPUT stream will increase abruptly when you write data to it + * and then decrease slowly over time as the data is consumed. + * + * The latency of an INPUT stream will decrease abruptly when you read data from it + * and then increase slowly over time as more data arrives. + * + * The latency of an OUTPUT stream is generally higher than the INPUT latency + * because an app generally tries to keep the OUTPUT buffer full and the INPUT buffer empty. + * + * @return a ResultWithValue which has a result of Result::OK and a value containing the latency + * in milliseconds, or a result of Result::Error*. + */ + virtual ResultWithValue calculateLatencyMillis() { + return ResultWithValue(Result::ErrorUnimplemented); + } + + /** + * Get the estimated time that the frame at `framePosition` entered or left the audio processing + * pipeline. + * + * This can be used to coordinate events and interactions with the external environment, and to + * estimate the latency of an audio stream. An example of usage can be found in the hello-oboe + * sample (search for "calculateCurrentOutputLatencyMillis"). + * + * The time is based on the implementation's best effort, using whatever knowledge is available + * to the system, but cannot account for any delay unknown to the implementation. + * + * @deprecated since 1.0, use AudioStream::getTimestamp(clockid_t clockId) instead, which + * returns ResultWithValue + * @param clockId the type of clock to use e.g. CLOCK_MONOTONIC + * @param framePosition the frame number to query + * @param timeNanoseconds an output parameter which will contain the presentation timestamp + */ + virtual Result getTimestamp(clockid_t /* clockId */, + int64_t* /* framePosition */, + int64_t* /* timeNanoseconds */) { + return Result::ErrorUnimplemented; + } + + /** + * Get the estimated time that the frame at `framePosition` entered or left the audio processing + * pipeline. + * + * This can be used to coordinate events and interactions with the external environment, and to + * estimate the latency of an audio stream. An example of usage can be found in the hello-oboe + * sample (search for "calculateCurrentOutputLatencyMillis"). + * + * The time is based on the implementation's best effort, using whatever knowledge is available + * to the system, but cannot account for any delay unknown to the implementation. + * + * @param clockId the type of clock to use e.g. CLOCK_MONOTONIC + * @return a FrameTimestamp containing the position and time at which a particular audio frame + * entered or left the audio processing pipeline, or an error if the operation failed. + */ + virtual ResultWithValue getTimestamp(clockid_t /* clockId */); + + // ============== I/O =========================== + /** + * Write data from the supplied buffer into the stream. This method will block until the write + * is complete or it runs out of time. + * + * If `timeoutNanoseconds` is zero then this call will not wait. + * + * @param buffer The address of the first sample. + * @param numFrames Number of frames to write. Only complete frames will be written. + * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion. + * @return a ResultWithValue which has a result of Result::OK and a value containing the number + * of frames actually written, or result of Result::Error*. + */ + virtual ResultWithValue write(const void* /* buffer */, + int32_t /* numFrames */, + int64_t /* timeoutNanoseconds */ ) { + return ResultWithValue(Result::ErrorUnimplemented); + } + + /** + * Read data into the supplied buffer from the stream. This method will block until the read + * is complete or it runs out of time. + * + * If `timeoutNanoseconds` is zero then this call will not wait. + * + * @param buffer The address of the first sample. + * @param numFrames Number of frames to read. Only complete frames will be read. + * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion. + * @return a ResultWithValue which has a result of Result::OK and a value containing the number + * of frames actually read, or result of Result::Error*. + */ + virtual ResultWithValue read(void* /* buffer */, + int32_t /* numFrames */, + int64_t /* timeoutNanoseconds */) { + return ResultWithValue(Result::ErrorUnimplemented); + } + + /** + * Get the underlying audio API which the stream uses. + * + * @return the API that this stream uses. + */ + virtual AudioApi getAudioApi() const = 0; + + /** + * Returns true if the underlying audio API is AAudio. + * + * @return true if this stream is implemented using the AAudio API. + */ + bool usesAAudio() const { + return getAudioApi() == AudioApi::AAudio; + } + + /** + * Only for debugging. Do not use in production. + * If you need to call this method something is wrong. + * If you think you need it for production then please let us know + * so we can modify Oboe so that you don't need this. + * + * @return nullptr or a pointer to a stream from the system API + */ + virtual void *getUnderlyingStream() const { + return nullptr; + } + + /** + * Launch a thread that will stop the stream. + */ + void launchStopThread(); + + /** + * Update mFramesWritten. + * For internal use only. + */ + virtual void updateFramesWritten() = 0; + + /** + * Update mFramesRead. + * For internal use only. + */ + virtual void updateFramesRead() = 0; + + /* + * Swap old callback for new callback. + * This not atomic. + * This should only be used internally. + * @param streamCallback + * @return previous streamCallback + */ + AudioStreamCallback *swapCallback(AudioStreamCallback *streamCallback) { + AudioStreamCallback *previousCallback = mStreamCallback; + mStreamCallback = streamCallback; + return previousCallback; + } + + /** + * @return number of frames of data currently in the buffer + */ + ResultWithValue getAvailableFrames(); + + /** + * Wait until the stream has a minimum amount of data available in its buffer. + * This can be used with an EXCLUSIVE MMAP input stream to avoid reading data too close to + * the DSP write position, which may cause glitches. + * + * @param numFrames minimum frames available + * @param timeoutNanoseconds + * @return number of frames available, ErrorTimeout + */ + ResultWithValue waitForAvailableFrames(int32_t numFrames, + int64_t timeoutNanoseconds); + +protected: + + /** + * This is used to detect more than one error callback from a stream. + * These were bugs in some versions of Android that caused multiple error callbacks. + * Internal bug b/63087953 + * + * Calling this sets an atomic true and returns the previous value. + * + * @return false on first call, true on subsequent calls + */ + bool wasErrorCallbackCalled() { + return mErrorCallbackCalled.exchange(true); + } + + /** + * Wait for a transition from one state to another. + * @return OK if the endingState was observed, or ErrorUnexpectedState + * if any state that was not the startingState or endingState was observed + * or ErrorTimeout. + */ + virtual Result waitForStateTransition(StreamState startingState, + StreamState endingState, + int64_t timeoutNanoseconds); + + /** + * Override this to provide a default for when the application did not specify a callback. + * + * @param audioData + * @param numFrames + * @return result + */ + virtual DataCallbackResult onDefaultCallback(void* /* audioData */, int /* numFrames */) { + return DataCallbackResult::Stop; + } + + /** + * Override this to provide your own behaviour for the audio callback + * + * @param audioData container array which audio frames will be written into or read from + * @param numFrames number of frames which were read/written + * @return the result of the callback: stop or continue + * + */ + DataCallbackResult fireDataCallback(void *audioData, int numFrames); + + /** + * @return true if callbacks may be called + */ + bool isDataCallbackEnabled() { + return mDataCallbackEnabled; + } + + /** + * This can be set false internally to prevent callbacks + * after DataCallbackResult::Stop has been returned. + */ + void setDataCallbackEnabled(bool enabled) { + mDataCallbackEnabled = enabled; + } + + /* + * Set a weak_ptr to this stream from the shared_ptr so that we can + * later use a shared_ptr in the error callback. + */ + void setWeakThis(std::shared_ptr &sharedStream) { + mWeakThis = sharedStream; + } + + /* + * Make a shared_ptr that will prevent this stream from being deleted. + */ + std::shared_ptr lockWeakThis() { + return mWeakThis.lock(); + } + + std::weak_ptr mWeakThis; // weak pointer to this object + + /** + * Number of frames which have been written into the stream + * + * This is signed integer to match the counters in AAudio. + * At audio rates, the counter will overflow in about six million years. + */ + std::atomic mFramesWritten{}; + + /** + * Number of frames which have been read from the stream. + * + * This is signed integer to match the counters in AAudio. + * At audio rates, the counter will overflow in about six million years. + */ + std::atomic mFramesRead{}; + + std::mutex mLock; // for synchronizing start/stop/close + + +private: + // Log the scheduler if it changes. + void checkScheduler(); + int mPreviousScheduler = -1; + + std::atomic mDataCallbackEnabled{false}; + std::atomic mErrorCallbackCalled{false}; + +}; + +/** + * This struct is a stateless functor which closes an AudioStream prior to its deletion. + * This means it can be used to safely delete a smart pointer referring to an open stream. + */ + struct StreamDeleterFunctor { + void operator()(AudioStream *audioStream) { + if (audioStream) { + audioStream->close(); + } + delete audioStream; + } + }; +} // namespace oboe + +#endif /* OBOE_STREAM_H_ */ diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/AudioStreamBase.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/AudioStreamBase.h new file mode 100644 index 0000000..4a6237d --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/AudioStreamBase.h @@ -0,0 +1,202 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_STREAM_BASE_H_ +#define OBOE_STREAM_BASE_H_ + +#include +#include "oboe/AudioStreamCallback.h" +#include "oboe/Definitions.h" + +namespace oboe { + +/** + * Base class containing parameters for audio streams and builders. + **/ +class AudioStreamBase { + +public: + + AudioStreamBase() {} + + virtual ~AudioStreamBase() = default; + + // This class only contains primitives so we can use default constructor and copy methods. + + /** + * Default copy constructor + */ + AudioStreamBase(const AudioStreamBase&) = default; + + /** + * Default assignment operator + */ + AudioStreamBase& operator=(const AudioStreamBase&) = default; + + /** + * @return number of channels, for example 2 for stereo, or kUnspecified + */ + int32_t getChannelCount() const { return mChannelCount; } + + /** + * @return Direction::Input or Direction::Output + */ + Direction getDirection() const { return mDirection; } + + /** + * @return sample rate for the stream or kUnspecified + */ + int32_t getSampleRate() const { return mSampleRate; } + + /** + * @return the number of frames in each callback or kUnspecified. + */ + int32_t getFramesPerCallback() const { return mFramesPerCallback; } + + /** + * @return the audio sample format (e.g. Float or I16) + */ + AudioFormat getFormat() const { return mFormat; } + + /** + * Query the maximum number of frames that can be filled without blocking. + * If the stream has been closed the last known value will be returned. + * + * @return buffer size + */ + virtual int32_t getBufferSizeInFrames() { return mBufferSizeInFrames; } + + /** + * @return capacityInFrames or kUnspecified + */ + virtual int32_t getBufferCapacityInFrames() const { return mBufferCapacityInFrames; } + + /** + * @return the sharing mode of the stream. + */ + SharingMode getSharingMode() const { return mSharingMode; } + + /** + * @return the performance mode of the stream. + */ + PerformanceMode getPerformanceMode() const { return mPerformanceMode; } + + /** + * @return the device ID of the stream. + */ + int32_t getDeviceId() const { return mDeviceId; } + + /** + * @return the callback object for this stream, if set. + */ + AudioStreamCallback* getCallback() const { + return mStreamCallback; + } + + /** + * @return the usage for this stream. + */ + Usage getUsage() const { return mUsage; } + + /** + * @return the stream's content type. + */ + ContentType getContentType() const { return mContentType; } + + /** + * @return the stream's input preset. + */ + InputPreset getInputPreset() const { return mInputPreset; } + + /** + * @return the stream's session ID allocation strategy (None or Allocate). + */ + SessionId getSessionId() const { return mSessionId; } + + /** + * @return true if Oboe can convert channel counts to achieve optimal results. + */ + bool isChannelConversionAllowed() const { + return mChannelConversionAllowed; + } + + /** + * @return true if Oboe can convert data formats to achieve optimal results. + */ + bool isFormatConversionAllowed() const { + return mFormatConversionAllowed; + } + + /** + * @return whether and how Oboe can convert sample rates to achieve optimal results. + */ + SampleRateConversionQuality getSampleRateConversionQuality() const { + return mSampleRateConversionQuality; + } + +protected: + + /** The callback which will be fired when new data is ready to be read/written **/ + AudioStreamCallback *mStreamCallback = nullptr; + /** Number of audio frames which will be requested in each callback */ + int32_t mFramesPerCallback = kUnspecified; + /** Stream channel count */ + int32_t mChannelCount = kUnspecified; + /** Stream sample rate */ + int32_t mSampleRate = kUnspecified; + /** Stream audio device ID */ + int32_t mDeviceId = kUnspecified; + /** Stream buffer capacity specified as a number of audio frames */ + int32_t mBufferCapacityInFrames = kUnspecified; + /** Stream buffer size specified as a number of audio frames */ + int32_t mBufferSizeInFrames = kUnspecified; + /** + * Number of frames which will be copied to/from the audio device in a single read/write + * operation + */ + int32_t mFramesPerBurst = kUnspecified; + + /** Stream sharing mode */ + SharingMode mSharingMode = SharingMode::Shared; + /** Format of audio frames */ + AudioFormat mFormat = AudioFormat::Unspecified; + /** Stream direction */ + Direction mDirection = Direction::Output; + /** Stream performance mode */ + PerformanceMode mPerformanceMode = PerformanceMode::None; + + /** Stream usage. Only active on Android 28+ */ + Usage mUsage = Usage::Media; + /** Stream content type. Only active on Android 28+ */ + ContentType mContentType = ContentType::Music; + /** Stream input preset. Only active on Android 28+ + * TODO InputPreset::Unspecified should be considered as a possible default alternative. + */ + InputPreset mInputPreset = InputPreset::VoiceRecognition; + /** Stream session ID allocation strategy. Only active on Android 28+ */ + SessionId mSessionId = SessionId::None; + + // Control whether Oboe can convert channel counts to achieve optimal results. + bool mChannelConversionAllowed = false; + // Control whether Oboe can convert data formats to achieve optimal results. + bool mFormatConversionAllowed = false; + // Control whether and how Oboe can convert sample rates to achieve optimal results. + SampleRateConversionQuality mSampleRateConversionQuality = SampleRateConversionQuality::None; +}; + +} // namespace oboe + +#endif /* OBOE_STREAM_BASE_H_ */ diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/AudioStreamBuilder.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/AudioStreamBuilder.h new file mode 100644 index 0000000..a1ea0a8 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/AudioStreamBuilder.h @@ -0,0 +1,438 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_STREAM_BUILDER_H_ +#define OBOE_STREAM_BUILDER_H_ + +#include "oboe/Definitions.h" +#include "oboe/AudioStreamBase.h" +#include "ResultWithValue.h" + +namespace oboe { + + // This depends on AudioStream, so we use forward declaration, it will close and delete the stream + struct StreamDeleterFunctor; + using ManagedStream = std::unique_ptr; + +/** + * Factory class for an audio Stream. + */ +class AudioStreamBuilder : public AudioStreamBase { +public: + + AudioStreamBuilder() : AudioStreamBase() {} + + AudioStreamBuilder(const AudioStreamBase &audioStreamBase): AudioStreamBase(audioStreamBase) {} + + /** + * Request a specific number of channels. + * + * Default is kUnspecified. If the value is unspecified then + * the application should query for the actual value after the stream is opened. + */ + AudioStreamBuilder *setChannelCount(int channelCount) { + mChannelCount = channelCount; + return this; + } + + /** + * Request the direction for a stream. The default is Direction::Output. + * + * @param direction Direction::Output or Direction::Input + */ + AudioStreamBuilder *setDirection(Direction direction) { + mDirection = direction; + return this; + } + + /** + * Request a specific sample rate in Hz. + * + * Default is kUnspecified. If the value is unspecified then + * the application should query for the actual value after the stream is opened. + * + * Technically, this should be called the "frame rate" or "frames per second", + * because it refers to the number of complete frames transferred per second. + * But it is traditionally called "sample rate". Se we use that term. + * + */ + AudioStreamBuilder *setSampleRate(int32_t sampleRate) { + mSampleRate = sampleRate; + return this; + } + + /** + * Request a specific number of frames for the data callback. + * + * Default is kUnspecified. If the value is unspecified then + * the actual number may vary from callback to callback. + * + * If an application can handle a varying number of frames then we recommend + * leaving this unspecified. This allow the underlying API to optimize + * the callbacks. But if your application is, for example, doing FFTs or other block + * oriented operations, then call this function to get the sizes you need. + * + * @param framesPerCallback + * @return pointer to the builder so calls can be chained + */ + AudioStreamBuilder *setFramesPerCallback(int framesPerCallback) { + mFramesPerCallback = framesPerCallback; + return this; + } + + /** + * Request a sample data format, for example Format::Float. + * + * Default is Format::Unspecified. If the value is unspecified then + * the application should query for the actual value after the stream is opened. + */ + AudioStreamBuilder *setFormat(AudioFormat format) { + mFormat = format; + return this; + } + + /** + * Set the requested buffer capacity in frames. + * BufferCapacityInFrames is the maximum possible BufferSizeInFrames. + * + * The final stream capacity may differ. For AAudio it should be at least this big. + * For OpenSL ES, it could be smaller. + * + * Default is kUnspecified. + * + * @param bufferCapacityInFrames the desired buffer capacity in frames or kUnspecified + * @return pointer to the builder so calls can be chained + */ + AudioStreamBuilder *setBufferCapacityInFrames(int32_t bufferCapacityInFrames) { + mBufferCapacityInFrames = bufferCapacityInFrames; + return this; + } + + /** + * Get the audio API which will be requested when opening the stream. No guarantees that this is + * the API which will actually be used. Query the stream itself to find out the API which is + * being used. + * + * If you do not specify the API, then AAudio will be used if isAAudioRecommended() + * returns true. Otherwise OpenSL ES will be used. + * + * @return the requested audio API + */ + AudioApi getAudioApi() const { return mAudioApi; } + + /** + * If you leave this unspecified then Oboe will choose the best API + * for the device and SDK version at runtime. + * + * This should almost always be left unspecified, except for debugging purposes. + * Specifying AAudio will force Oboe to use AAudio on 8.0, which is extremely risky. + * Specifying OpenSLES should mainly be used to test legacy performance/functionality. + * + * If the caller requests AAudio and it is supported then AAudio will be used. + * + * @param audioApi Must be AudioApi::Unspecified, AudioApi::OpenSLES or AudioApi::AAudio. + * @return pointer to the builder so calls can be chained + */ + AudioStreamBuilder *setAudioApi(AudioApi audioApi) { + mAudioApi = audioApi; + return this; + } + + /** + * Is the AAudio API supported on this device? + * + * AAudio was introduced in the Oreo 8.0 release. + * + * @return true if supported + */ + static bool isAAudioSupported(); + + /** + * Is the AAudio API recommended this device? + * + * AAudio may be supported but not recommended because of version specific issues. + * AAudio is not recommended for Android 8.0 or earlier versions. + * + * @return true if recommended + */ + static bool isAAudioRecommended(); + + /** + * Request a mode for sharing the device. + * The requested sharing mode may not be available. + * So the application should query for the actual mode after the stream is opened. + * + * @param sharingMode SharingMode::Shared or SharingMode::Exclusive + * @return pointer to the builder so calls can be chained + */ + AudioStreamBuilder *setSharingMode(SharingMode sharingMode) { + mSharingMode = sharingMode; + return this; + } + + /** + * Request a performance level for the stream. + * This will determine the latency, the power consumption, and the level of + * protection from glitches. + * + * @param performanceMode for example, PerformanceMode::LowLatency + * @return pointer to the builder so calls can be chained + */ + AudioStreamBuilder *setPerformanceMode(PerformanceMode performanceMode) { + mPerformanceMode = performanceMode; + return this; + } + + + /** + * Set the intended use case for the stream. + * + * The system will use this information to optimize the behavior of the stream. + * This could, for example, affect how volume and focus is handled for the stream. + * + * The default, if you do not call this function, is Usage::Media. + * + * Added in API level 28. + * + * @param usage the desired usage, eg. Usage::Game + */ + AudioStreamBuilder *setUsage(Usage usage) { + mUsage = usage; + return this; + } + + /** + * Set the type of audio data that the stream will carry. + * + * The system will use this information to optimize the behavior of the stream. + * This could, for example, affect whether a stream is paused when a notification occurs. + * + * The default, if you do not call this function, is ContentType::Music. + * + * Added in API level 28. + * + * @param contentType the type of audio data, eg. ContentType::Speech + */ + AudioStreamBuilder *setContentType(ContentType contentType) { + mContentType = contentType; + return this; + } + + /** + * Set the input (capture) preset for the stream. + * + * The system will use this information to optimize the behavior of the stream. + * This could, for example, affect which microphones are used and how the + * recorded data is processed. + * + * The default, if you do not call this function, is InputPreset::VoiceRecognition. + * That is because VoiceRecognition is the preset with the lowest latency + * on many platforms. + * + * Added in API level 28. + * + * @param inputPreset the desired configuration for recording + */ + AudioStreamBuilder *setInputPreset(InputPreset inputPreset) { + mInputPreset = inputPreset; + return this; + } + + /** Set the requested session ID. + * + * The session ID can be used to associate a stream with effects processors. + * The effects are controlled using the Android AudioEffect Java API. + * + * The default, if you do not call this function, is SessionId::None. + * + * If set to SessionId::Allocate then a session ID will be allocated + * when the stream is opened. + * + * The allocated session ID can be obtained by calling AudioStream::getSessionId() + * and then used with this function when opening another stream. + * This allows effects to be shared between streams. + * + * Session IDs from Oboe can be used the Android Java APIs and vice versa. + * So a session ID from an Oboe stream can be passed to Java + * and effects applied using the Java AudioEffect API. + * + * Allocated session IDs will always be positive and nonzero. + * + * Added in API level 28. + * + * @param sessionId an allocated sessionID or SessionId::Allocate + */ + AudioStreamBuilder *setSessionId(SessionId sessionId) { + mSessionId = sessionId; + return this; + } + + /** + * Request a stream to a specific audio input/output device given an audio device ID. + * + * In most cases, the primary device will be the appropriate device to use, and the + * deviceId can be left kUnspecified. + * + * On Android, for example, the ID could be obtained from the Java AudioManager. + * AudioManager.getDevices() returns an array of AudioDeviceInfo[], which contains + * a getId() method (as well as other type information), that should be passed + * to this method. + * + * + * Note that when using OpenSL ES, this will be ignored and the created + * stream will have deviceId kUnspecified. + * + * @param deviceId device identifier or kUnspecified + * @return pointer to the builder so calls can be chained + */ + AudioStreamBuilder *setDeviceId(int32_t deviceId) { + mDeviceId = deviceId; + return this; + } + + /** + * Specifies an object to handle data or error related callbacks from the underlying API. + * + * Important: See AudioStreamCallback for restrictions on what may be called + * from the callback methods. + * + * When an error callback occurs, the associated stream will be stopped and closed in a separate thread. + * + * A note on why the streamCallback parameter is a raw pointer rather than a smart pointer: + * + * The caller should retain ownership of the object streamCallback points to. At first glance weak_ptr may seem like + * a good candidate for streamCallback as this implies temporary ownership. However, a weak_ptr can only be created + * from a shared_ptr. A shared_ptr incurs some performance overhead. The callback object is likely to be accessed + * every few milliseconds when the stream requires new data so this overhead is something we want to avoid. + * + * This leaves a raw pointer as the logical type choice. The only caveat being that the caller must not destroy + * the callback before the stream has been closed. + * + * @param streamCallback + * @return pointer to the builder so calls can be chained + */ + AudioStreamBuilder *setCallback(AudioStreamCallback *streamCallback) { + mStreamCallback = streamCallback; + return this; + } + + /** + * If true then Oboe might convert channel counts to achieve optimal results. + * On some versions of Android for example, stereo streams could not use a FAST track. + * So a mono stream might be used instead and duplicated to two channels. + * On some devices, mono streams might be broken, so a stereo stream might be opened + * and converted to mono. + * + * Default is true. + */ + AudioStreamBuilder *setChannelConversionAllowed(bool allowed) { + mChannelConversionAllowed = allowed; + return this; + } + + /** + * If true then Oboe might convert data formats to achieve optimal results. + * On some versions of Android, for example, a float stream could not get a + * low latency data path. So an I16 stream might be opened and converted to float. + * + * Default is true. + */ + AudioStreamBuilder *setFormatConversionAllowed(bool allowed) { + mFormatConversionAllowed = allowed; + return this; + } + + /** + * Specify the quality of the sample rate converter in Oboe. + * + * If set to None then Oboe will not do sample rate conversion. But the underlying APIs might + * still do sample rate conversion if you specify a sample rate. + * That can prevent you from getting a low latency stream. + * + * If you do the conversion in Oboe then you might still get a low latency stream. + * + * Default is SampleRateConversionQuality::None + */ + AudioStreamBuilder *setSampleRateConversionQuality(SampleRateConversionQuality quality) { + mSampleRateConversionQuality = quality; + return this; + } + + /** + * @return true if AAudio will be used based on the current settings. + */ + bool willUseAAudio() const { + return (mAudioApi == AudioApi::AAudio && isAAudioSupported()) + || (mAudioApi == AudioApi::Unspecified && isAAudioRecommended()); + } + + /** + * Create and open a stream object based on the current settings. + * + * The caller owns the pointer to the AudioStream object. + * + * @deprecated Use openStream(std::shared_ptr &stream) instead. + * @param stream pointer to a variable to receive the stream address + * @return OBOE_OK if successful or a negative error code + */ + Result openStream(AudioStream **stream); + + /** + * Create and open a stream object based on the current settings. + * + * The caller shares the pointer to the AudioStream object. + * The shared_ptr is used internally by Oboe to prevent the stream from being + * deleted while it is being used by callbacks. + * + * @param stream reference to a shared_ptr to receive the stream address + * @return OBOE_OK if successful or a negative error code + */ + Result openStream(std::shared_ptr &stream); + + /** + * Create and open a ManagedStream object based on the current builder state. + * + * The caller must create a unique ptr, and pass by reference so it can be + * modified to point to an opened stream. The caller owns the unique ptr, + * and it will be automatically closed and deleted when going out of scope. + * @param stream Reference to the ManagedStream (uniqueptr) used to keep track of stream + * @return OBOE_OK if successful or a negative error code. + */ + Result openManagedStream(ManagedStream &stream); + +private: + + /** + * @param other + * @return true if channels, format and sample rate match + */ + bool isCompatible(AudioStreamBase &other); + + /** + * Create an AudioStream object. The AudioStream must be opened before use. + * + * The caller owns the pointer. + * + * @return pointer to an AudioStream object or nullptr. + */ + oboe::AudioStream *build(); + + AudioApi mAudioApi = AudioApi::Unspecified; +}; + +} // namespace oboe + +#endif /* OBOE_STREAM_BUILDER_H_ */ diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/AudioStreamCallback.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/AudioStreamCallback.h new file mode 100644 index 0000000..f427693 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/AudioStreamCallback.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_STREAM_CALLBACK_H +#define OBOE_STREAM_CALLBACK_H + +#include "oboe/Definitions.h" + +namespace oboe { + +class AudioStream; + +/** + * AudioStreamCallback defines a callback interface for: + * + * 1) moving data to/from an audio stream using `onAudioReady` + * 2) being alerted when a stream has an error using `onError*` methods + * + */ +class AudioStreamCallback { +public: + virtual ~AudioStreamCallback() = default; + + /** + * A buffer is ready for processing. + * + * For an output stream, this function should render and write numFrames of data + * in the stream's current data format to the audioData buffer. + * + * For an input stream, this function should read and process numFrames of data + * from the audioData buffer. + * + * The audio data is passed through the buffer. So do NOT call read() or + * write() on the stream that is making the callback. + * + * Note that numFrames can vary unless AudioStreamBuilder::setFramesPerCallback() + * is called. + * + * Also note that this callback function should be considered a "real-time" function. + * It must not do anything that could cause an unbounded delay because that can cause the + * audio to glitch or pop. + * + * These are things the function should NOT do: + *
    + *
  • allocate memory using, for example, malloc() or new
  • + *
  • any file operations such as opening, closing, reading or writing
  • + *
  • any network operations such as streaming
  • + *
  • use any mutexes or other synchronization primitives
  • + *
  • sleep
  • + *
  • oboeStream->stop(), pause(), flush() or close()
  • + *
  • oboeStream->read()
  • + *
  • oboeStream->write()
  • + *
+ * + * The following are OK to call from the data callback: + *
    + *
  • oboeStream->get*()
  • + *
  • oboe::convertToText()
  • + *
  • oboeStream->setBufferSizeInFrames()
  • + *
+ * + * If you need to move data, eg. MIDI commands, in or out of the callback function then + * we recommend the use of non-blocking techniques such as an atomic FIFO. + * + * @param oboeStream pointer to the associated stream + * @param audioData buffer containing input data or a place to put output data + * @param numFrames number of frames to be processed + * @return DataCallbackResult::Continue or DataCallbackResult::Stop + */ + virtual DataCallbackResult onAudioReady( + AudioStream *oboeStream, + void *audioData, + int32_t numFrames) = 0; + + /** + * This will be called when an error occurs on a stream or when the stream is disconnected. + * + * Note that this will be called on a different thread than the onAudioReady() thread. + * This thread will be created by Oboe. + * + * The underlying stream will already be stopped by Oboe but not yet closed. + * So the stream can be queried. + * + * Do not close or delete the stream in this method because it will be + * closed after this method returns. + * + * @param oboeStream pointer to the associated stream + * @param error + */ + virtual void onErrorBeforeClose(AudioStream* /* oboeStream */, Result /* error */) {} + + /** + * This will be called when an error occurs on a stream or when the stream is disconnected. + * The underlying AAudio or OpenSL ES stream will already be stopped AND closed by Oboe. + * So the underlying stream cannot be referenced. + * But you can still query most parameters. + * + * This callback could be used to reopen a new stream on another device. + * You can safely delete the old AudioStream in this method. + * + * @param oboeStream pointer to the associated stream + * @param error + */ + virtual void onErrorAfterClose(AudioStream* /* oboeStream */, Result /* error */) {} + +}; + +} // namespace oboe + +#endif //OBOE_STREAM_CALLBACK_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/Definitions.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/Definitions.h new file mode 100644 index 0000000..8063a83 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/Definitions.h @@ -0,0 +1,519 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_DEFINITIONS_H +#define OBOE_DEFINITIONS_H + + +#include +#include + +// Oboe needs to be able to build on old NDKs so we use hard coded constants. +// The correctness of these constants is verified in "aaudio/AAudioLoader.cpp". + +namespace oboe { + + /** + * Represents any attribute, property or value which hasn't been specified. + */ + constexpr int32_t kUnspecified = 0; + + // TODO: Investigate using std::chrono + /** + * The number of nanoseconds in a microsecond. 1,000. + */ + constexpr int64_t kNanosPerMicrosecond = 1000; + + /** + * The number of nanoseconds in a millisecond. 1,000,000. + */ + constexpr int64_t kNanosPerMillisecond = kNanosPerMicrosecond * 1000; + + /** + * The number of milliseconds in a second. 1,000. + */ + constexpr int64_t kMillisPerSecond = 1000; + + /** + * The number of nanoseconds in a second. 1,000,000,000. + */ + constexpr int64_t kNanosPerSecond = kNanosPerMillisecond * kMillisPerSecond; + + /** + * The state of the audio stream. + */ + enum class StreamState : int32_t { // aaudio_stream_state_t + Uninitialized = 0, // AAUDIO_STREAM_STATE_UNINITIALIZED, + Unknown = 1, // AAUDIO_STREAM_STATE_UNKNOWN, + Open = 2, // AAUDIO_STREAM_STATE_OPEN, + Starting = 3, // AAUDIO_STREAM_STATE_STARTING, + Started = 4, // AAUDIO_STREAM_STATE_STARTED, + Pausing = 5, // AAUDIO_STREAM_STATE_PAUSING, + Paused = 6, // AAUDIO_STREAM_STATE_PAUSED, + Flushing = 7, // AAUDIO_STREAM_STATE_FLUSHING, + Flushed = 8, // AAUDIO_STREAM_STATE_FLUSHED, + Stopping = 9, // AAUDIO_STREAM_STATE_STOPPING, + Stopped = 10, // AAUDIO_STREAM_STATE_STOPPED, + Closing = 11, // AAUDIO_STREAM_STATE_CLOSING, + Closed = 12, // AAUDIO_STREAM_STATE_CLOSED, + Disconnected = 13, // AAUDIO_STREAM_STATE_DISCONNECTED, + }; + + /** + * The direction of the stream. + */ + enum class Direction : int32_t { // aaudio_direction_t + + /** + * Used for playback. + */ + Output = 0, // AAUDIO_DIRECTION_OUTPUT, + + /** + * Used for recording. + */ + Input = 1, // AAUDIO_DIRECTION_INPUT, + }; + + /** + * The format of audio samples. + */ + enum class AudioFormat : int32_t { // aaudio_format_t + /** + * Invalid format. + */ + Invalid = -1, // AAUDIO_FORMAT_INVALID, + + /** + * Unspecified format. Format will be decided by Oboe. + */ + Unspecified = 0, // AAUDIO_FORMAT_UNSPECIFIED, + + /** + * Signed 16-bit integers. + */ + I16 = 1, // AAUDIO_FORMAT_PCM_I16, + + /** + * Single precision floating points. + */ + Float = 2, // AAUDIO_FORMAT_PCM_FLOAT, + }; + + /** + * The result of an audio callback. + */ + enum class DataCallbackResult : int32_t { // aaudio_data_callback_result_t + // Indicates to the caller that the callbacks should continue. + Continue = 0, // AAUDIO_CALLBACK_RESULT_CONTINUE, + + // Indicates to the caller that the callbacks should stop immediately. + Stop = 1, // AAUDIO_CALLBACK_RESULT_STOP, + }; + + /** + * The result of an operation. All except the `OK` result indicates that an error occurred. + * The `Result` can be converted into a human readable string using `convertToText`. + */ + enum class Result : int32_t { // aaudio_result_t + OK = 0, // AAUDIO_OK + ErrorBase = -900, // AAUDIO_ERROR_BASE, + ErrorDisconnected = -899, // AAUDIO_ERROR_DISCONNECTED, + ErrorIllegalArgument = -898, // AAUDIO_ERROR_ILLEGAL_ARGUMENT, + ErrorInternal = -896, // AAUDIO_ERROR_INTERNAL, + ErrorInvalidState = -895, // AAUDIO_ERROR_INVALID_STATE, + ErrorInvalidHandle = -892, // AAUDIO_ERROR_INVALID_HANDLE, + ErrorUnimplemented = -890, // AAUDIO_ERROR_UNIMPLEMENTED, + ErrorUnavailable = -889, // AAUDIO_ERROR_UNAVAILABLE, + ErrorNoFreeHandles = -888, // AAUDIO_ERROR_NO_FREE_HANDLES, + ErrorNoMemory = -887, // AAUDIO_ERROR_NO_MEMORY, + ErrorNull = -886, // AAUDIO_ERROR_NULL, + ErrorTimeout = -885, // AAUDIO_ERROR_TIMEOUT, + ErrorWouldBlock = -884, // AAUDIO_ERROR_WOULD_BLOCK, + ErrorInvalidFormat = -883, // AAUDIO_ERROR_INVALID_FORMAT, + ErrorOutOfRange = -882, // AAUDIO_ERROR_OUT_OF_RANGE, + ErrorNoService = -881, // AAUDIO_ERROR_NO_SERVICE, + ErrorInvalidRate = -880, // AAUDIO_ERROR_INVALID_RATE, + // Reserved for future AAudio result types + Reserved1, + Reserved2, + Reserved3, + Reserved4, + Reserved5, + Reserved6, + Reserved7, + Reserved8, + Reserved9, + Reserved10, + ErrorClosed, + }; + + /** + * The sharing mode of the audio stream. + */ + enum class SharingMode : int32_t { // aaudio_sharing_mode_t + + /** + * This will be the only stream using a particular source or sink. + * This mode will provide the lowest possible latency. + * You should close EXCLUSIVE streams immediately when you are not using them. + * + * If you do not need the lowest possible latency then we recommend using Shared, + * which is the default. + */ + Exclusive = 0, // AAUDIO_SHARING_MODE_EXCLUSIVE, + + /** + * Multiple applications can share the same device. + * The data from output streams will be mixed by the audio service. + * The data for input streams will be distributed by the audio service. + * + * This will have higher latency than the EXCLUSIVE mode. + */ + Shared = 1, // AAUDIO_SHARING_MODE_SHARED, + }; + + /** + * The performance mode of the audio stream. + */ + enum class PerformanceMode : int32_t { // aaudio_performance_mode_t + + /** + * No particular performance needs. Default. + */ + None = 10, // AAUDIO_PERFORMANCE_MODE_NONE, + + /** + * Extending battery life is most important. + */ + PowerSaving = 11, // AAUDIO_PERFORMANCE_MODE_POWER_SAVING, + + /** + * Reducing latency is most important. + */ + LowLatency = 12, // AAUDIO_PERFORMANCE_MODE_LOW_LATENCY + }; + + /** + * The underlying audio API used by the audio stream. + */ + enum class AudioApi : int32_t { + /** + * Try to use AAudio. If not available then use OpenSL ES. + */ + Unspecified = kUnspecified, + + /** + * Use OpenSL ES. + */ + OpenSLES, + + /** + * Try to use AAudio. Fail if unavailable. + */ + AAudio + }; + + /** + * Specifies the quality of the sample rate conversion performed by Oboe. + * Higher quality will require more CPU load. + * Higher quality conversion will probably be implemented using a sinc based resampler. + */ + enum class SampleRateConversionQuality : int32_t { + /** + * No conversion by Oboe. Underlying APIs may still do conversion. + */ + None, + /** + * Fastest conversion but may not sound great. + * This may be implemented using bilinear interpolation. + */ + Fastest, + Low, + Medium, + High, + /** + * Highest quality conversion, which may be expensive in terms of CPU. + */ + Best, + }; + + /** + * The Usage attribute expresses *why* you are playing a sound, what is this sound used for. + * This information is used by certain platforms or routing policies + * to make more refined volume or routing decisions. + * + * Note that these match the equivalent values in AudioAttributes in the Android Java API. + * + * This attribute only has an effect on Android API 28+. + */ + enum class Usage : int32_t { // aaudio_usage_t + /** + * Use this for streaming media, music performance, video, podcasts, etcetera. + */ + Media = 1, // AAUDIO_USAGE_MEDIA + + /** + * Use this for voice over IP, telephony, etcetera. + */ + VoiceCommunication = 2, // AAUDIO_USAGE_VOICE_COMMUNICATION + + /** + * Use this for sounds associated with telephony such as busy tones, DTMF, etcetera. + */ + VoiceCommunicationSignalling = 3, // AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING + + /** + * Use this to demand the users attention. + */ + Alarm = 4, // AAUDIO_USAGE_ALARM + + /** + * Use this for notifying the user when a message has arrived or some + * other background event has occured. + */ + Notification = 5, // AAUDIO_USAGE_NOTIFICATION + + /** + * Use this when the phone rings. + */ + NotificationRingtone = 6, // AAUDIO_USAGE_NOTIFICATION_RINGTONE + + /** + * Use this to attract the users attention when, for example, the battery is low. + */ + NotificationEvent = 10, // AAUDIO_USAGE_NOTIFICATION_EVENT + + /** + * Use this for screen readers, etcetera. + */ + AssistanceAccessibility = 11, // AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY + + /** + * Use this for driving or navigation directions. + */ + AssistanceNavigationGuidance = 12, // AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE + + /** + * Use this for user interface sounds, beeps, etcetera. + */ + AssistanceSonification = 13, // AAUDIO_USAGE_ASSISTANCE_SONIFICATION + + /** + * Use this for game audio and sound effects. + */ + Game = 14, // AAUDIO_USAGE_GAME + + /** + * Use this for audio responses to user queries, audio instructions or help utterances. + */ + Assistant = 16, // AAUDIO_USAGE_ASSISTANT + }; + + + /** + * The ContentType attribute describes *what* you are playing. + * It expresses the general category of the content. This information is optional. + * But in case it is known (for instance {@link Movie} for a + * movie streaming service or {@link Speech} for + * an audio book application) this information might be used by the audio framework to + * enforce audio focus. + * + * Note that these match the equivalent values in AudioAttributes in the Android Java API. + * + * This attribute only has an effect on Android API 28+. + */ + enum ContentType : int32_t { // aaudio_content_type_t + + /** + * Use this for spoken voice, audio books, etcetera. + */ + Speech = 1, // AAUDIO_CONTENT_TYPE_SPEECH + + /** + * Use this for pre-recorded or live music. + */ + Music = 2, // AAUDIO_CONTENT_TYPE_MUSIC + + /** + * Use this for a movie or video soundtrack. + */ + Movie = 3, // AAUDIO_CONTENT_TYPE_MOVIE + + /** + * Use this for sound is designed to accompany a user action, + * such as a click or beep sound made when the user presses a button. + */ + Sonification = 4, // AAUDIO_CONTENT_TYPE_SONIFICATION + }; + + /** + * Defines the audio source. + * An audio source defines both a default physical source of audio signal, and a recording + * configuration. + * + * Note that these match the equivalent values in MediaRecorder.AudioSource in the Android Java API. + * + * This attribute only has an effect on Android API 28+. + */ + enum InputPreset : int32_t { // aaudio_input_preset_t + /** + * Use this preset when other presets do not apply. + */ + Generic = 1, // AAUDIO_INPUT_PRESET_GENERIC + + /** + * Use this preset when recording video. + */ + Camcorder = 5, // AAUDIO_INPUT_PRESET_CAMCORDER + + /** + * Use this preset when doing speech recognition. + */ + VoiceRecognition = 6, // AAUDIO_INPUT_PRESET_VOICE_RECOGNITION + + /** + * Use this preset when doing telephony or voice messaging. + */ + VoiceCommunication = 7, // AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION + + /** + * Use this preset to obtain an input with no effects. + * Note that this input will not have automatic gain control + * so the recorded volume may be very low. + */ + Unprocessed = 9, // AAUDIO_INPUT_PRESET_UNPROCESSED + + /** + * Use this preset for capturing audio meant to be processed in real time + * and played back for live performance (e.g karaoke). + * The capture path will minimize latency and coupling with playback path. + */ + VoicePerformance = 10, // AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE + + }; + + /** + * This attribute can be used to allocate a session ID to the audio stream. + * + * This attribute only has an effect on Android API 28+. + */ + enum SessionId { + /** + * Do not allocate a session ID. + * Effects cannot be used with this stream. + * Default. + */ + None = -1, // AAUDIO_SESSION_ID_NONE + + /** + * Allocate a session ID that can be used to attach and control + * effects using the Java AudioEffects API. + * Note that the use of this flag may result in higher latency. + * + * Note that this matches the value of AudioManager.AUDIO_SESSION_ID_GENERATE. + */ + Allocate = 0, // AAUDIO_SESSION_ID_ALLOCATE + }; + + /** + * The channel count of the audio stream. The underlying type is `int32_t`. + * Use of this enum is convenient to avoid "magic" + * numbers when specifying the channel count. + * + * For example, you can write + * `builder.setChannelCount(ChannelCount::Stereo)` + * rather than `builder.setChannelCount(2)` + * + */ + enum ChannelCount : int32_t { + /** + * Audio channel count definition, use Mono or Stereo + */ + Unspecified = kUnspecified, + + /** + * Use this for mono audio + */ + Mono = 1, + + /** + * Use this for stereo audio. + */ + Stereo = 2, + }; + + /** + * On API 16 to 26 OpenSL ES will be used. When using OpenSL ES the optimal values for sampleRate and + * framesPerBurst are not known by the native code. + * On API 17+ these values should be obtained from the AudioManager using this code: + * + *

+     * // Note that this technique only works for built-in speakers and headphones.
+     * AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+     * String sampleRateStr = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
+     * int defaultSampleRate = Integer.parseInt(sampleRateStr);
+     * String framesPerBurstStr = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
+     * int defaultFramesPerBurst = Integer.parseInt(framesPerBurstStr);
+     * 
+ * + * It can then be passed down to Oboe through JNI. + * + * AAudio will get the optimal framesPerBurst from the HAL and will ignore this value. + */ + class DefaultStreamValues { + + public: + + /** The default sample rate to use when opening new audio streams */ + static int32_t SampleRate; + /** The default frames per burst to use when opening new audio streams */ + static int32_t FramesPerBurst; + /** The default channel count to use when opening new audio streams */ + static int32_t ChannelCount; + + }; + + /** + * The time at which the frame at `position` was presented + */ + struct FrameTimestamp { + int64_t position; // in frames + int64_t timestamp; // in nanoseconds + }; + + class OboeGlobals { + public: + + static bool areWorkaroundsEnabled() { + return mWorkaroundsEnabled; + } + + /** + * Disable this when writing tests to reproduce bugs in AAudio or OpenSL ES + * that have workarounds in Oboe. + * @param enabled + */ + static void setWorkaroundsEnabled(bool enabled) { + mWorkaroundsEnabled = enabled; + } + + private: + static bool mWorkaroundsEnabled; + }; +} // namespace oboe + +#endif // OBOE_DEFINITIONS_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/LatencyTuner.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/LatencyTuner.h new file mode 100644 index 0000000..df472f5 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/LatencyTuner.h @@ -0,0 +1,118 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_LATENCY_TUNER_ +#define OBOE_LATENCY_TUNER_ + +#include +#include +#include "oboe/Definitions.h" +#include "oboe/AudioStream.h" + +namespace oboe { + +/** + * LatencyTuner can be used to dynamically tune the latency of an output stream. + * It adjusts the stream's bufferSize by monitoring the number of underruns. + * + * This only affects the latency associated with the first level of buffering that is closest + * to the application. It does not affect low latency in the HAL, or touch latency in the UI. + * + * Call tune() right before returning from your data callback function if using callbacks. + * Call tune() right before calling write() if using blocking writes. + * + * If you want to see the ongoing results of this tuning process then call + * stream->getBufferSize() periodically. + * + */ +class LatencyTuner { +public: + + /** + * Construct a new LatencyTuner object which will act on the given audio stream + * + * @param stream the stream who's latency will be tuned + */ + explicit LatencyTuner(AudioStream &stream); + + /** + * Construct a new LatencyTuner object which will act on the given audio stream. + * + * @param stream the stream who's latency will be tuned + * @param the maximum buffer size which the tune() operation will set the buffer size to + */ + explicit LatencyTuner(AudioStream &stream, int32_t maximumBufferSize); + + /** + * Adjust the bufferSizeInFrames to optimize latency. + * It will start with a low latency and then raise it if an underrun occurs. + * + * Latency tuning is only supported for AAudio. + * + * @return OK or negative error, ErrorUnimplemented for OpenSL ES + */ + Result tune(); + + /** + * This may be called from another thread. Then tune() will call reset(), + * which will lower the latency to the minimum and then allow it to rise back up + * if there are glitches. + * + * This is typically called in response to a user decision to minimize latency. In other words, + * call this from a button handler. + */ + void requestReset(); + + /** + * @return true if the audio stream's buffer size is at the maximum value. If no maximum value + * was specified when constructing the LatencyTuner then the value of + * stream->getBufferCapacityInFrames is used + */ + bool isAtMaximumBufferSize(); + + +private: + + /** + * Drop the latency down to the minimum and then let it rise back up. + * This is useful if a glitch caused the latency to increase and it hasn't gone back down. + * + * This should only be called in the same thread as tune(). + */ + void reset(); + + enum class State { + Idle, + Active, + AtMax, + Unsupported + } ; + + // arbitrary number of calls to wait before bumping up the latency + static constexpr int32_t kIdleCount = 8; + + AudioStream &mStream; + State mState = State::Idle; + int32_t mMaxBufferSize = 0; + int32_t mPreviousXRuns = 0; + int32_t mIdleCountDown = 0; + std::atomic mLatencyTriggerRequests{0}; // TODO user atomic requester from AAudio + std::atomic mLatencyTriggerResponses{0}; +}; + +} // namespace oboe + +#endif // OBOE_LATENCY_TUNER_ diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/Oboe.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/Oboe.h new file mode 100644 index 0000000..c3a0bca --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/Oboe.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_OBOE_H +#define OBOE_OBOE_H + +/** + * \mainpage API reference + * + * All documentation is found in the oboe namespace section + * + */ + +#include "oboe/Definitions.h" +#include "oboe/ResultWithValue.h" +#include "oboe/LatencyTuner.h" +#include "oboe/AudioStream.h" +#include "oboe/AudioStreamBase.h" +#include "oboe/AudioStreamBuilder.h" +#include "oboe/Utilities.h" +#include "oboe/Version.h" +#include "oboe/StabilizedCallback.h" + +#endif //OBOE_OBOE_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/ResultWithValue.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/ResultWithValue.h new file mode 100644 index 0000000..fcb1fac --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/ResultWithValue.h @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_RESULT_WITH_VALUE_H +#define OBOE_RESULT_WITH_VALUE_H + +#include "oboe/Definitions.h" +#include +#include + +namespace oboe { + +/** + * A ResultWithValue can store both the result of an operation (either OK or an error) and a value. + * + * It has been designed for cases where the caller needs to know whether an operation succeeded and, + * if it did, a value which was obtained during the operation. + * + * For example, when reading from a stream the caller needs to know the result of the read operation + * and, if it was successful, how many frames were read. Note that ResultWithValue can be evaluated + * as a boolean so it's simple to check whether the result is OK. + * + * + * ResultWithValue resultOfRead = myStream.read(&buffer, numFrames, timeoutNanoseconds); + * + * if (resultOfRead) { + * LOGD("Frames read: %d", resultOfRead.value()); + * } else { + * LOGD("Error reading from stream: %s", resultOfRead.error()); + * } + * + */ +template +class ResultWithValue { +public: + + /** + * Construct a ResultWithValue containing an error result. + * + * @param error The error + */ + ResultWithValue(oboe::Result error) + : mValue{} + , mError(error) {} + + /** + * Construct a ResultWithValue containing an OK result and a value. + * + * @param value the value to store + */ + explicit ResultWithValue(T value) + : mValue(value) + , mError(oboe::Result::OK) {} + + /** + * Get the result. + * + * @return the result + */ + oboe::Result error() const { + return mError; + } + + /** + * Get the value + * @return + */ + T value() const { + return mValue; + } + + /** + * @return true if OK + */ + explicit operator bool() const { return mError == oboe::Result::OK; } + + /** + * Quick way to check for an error. + * + * The caller could write something like this: + * + * if (!result) { printf("Got error %s\n", convertToText(result.error())); } + * + * + * @return true if an error occurred + */ + bool operator !() const { return mError != oboe::Result::OK; } + + /** + * Implicitly convert to a Result. This enables easy comparison with Result values. Example: + * + * + * ResultWithValue result = openStream(); + * if (result == Result::ErrorNoMemory){ // tell user they're out of memory } + * + */ + operator Result() const { + return mError; + } + + /** + * Create a ResultWithValue from a number. If the number is positive the ResultWithValue will + * have a result of Result::OK and the value will contain the number. If the number is negative + * the result will be obtained from the negative number (numeric error codes can be found in + * AAudio.h) and the value will be null. + * + */ + static ResultWithValue createBasedOnSign(T numericResult){ + + // Ensure that the type is either an integer or float + static_assert(std::is_arithmetic::value, + "createBasedOnSign can only be called for numeric types (int or float)"); + + if (numericResult >= 0){ + return ResultWithValue(numericResult); + } else { + return ResultWithValue(static_cast(numericResult)); + } + } + +private: + const T mValue; + const oboe::Result mError; +}; + +/** + * If the result is `OK` then return the value, otherwise return a human-readable error message. + */ +template +std::ostream& operator<<(std::ostream &strm, const ResultWithValue &result) { + if (!result) { + strm << convertToText(result.error()); + } else { + strm << result.value(); + } + return strm; +} + +} // namespace oboe + + +#endif //OBOE_RESULT_WITH_VALUE_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/StabilizedCallback.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/StabilizedCallback.h new file mode 100644 index 0000000..3f1a689 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/StabilizedCallback.h @@ -0,0 +1,75 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_STABILIZEDCALLBACK_H +#define OBOE_STABILIZEDCALLBACK_H + +#include +#include "oboe/AudioStream.h" + +namespace oboe { + +class StabilizedCallback : public AudioStreamCallback { + +public: + explicit StabilizedCallback(AudioStreamCallback *callback); + + DataCallbackResult + onAudioReady(AudioStream *oboeStream, void *audioData, int32_t numFrames) override; + + void onErrorBeforeClose(AudioStream *oboeStream, Result error) override { + return mCallback->onErrorBeforeClose(oboeStream, error); + } + + void onErrorAfterClose(AudioStream *oboeStream, Result error) override { + + // Reset all fields now that the stream has been closed + mFrameCount = 0; + mEpochTimeNanos = 0; + mOpsPerNano = 1; + return mCallback->onErrorAfterClose(oboeStream, error); + } + +private: + + AudioStreamCallback *mCallback = nullptr; + int64_t mFrameCount = 0; + int64_t mEpochTimeNanos = 0; + double mOpsPerNano = 1; + + void generateLoad(int64_t durationNanos); +}; + +/** + * cpu_relax is an architecture specific method of telling the CPU that you don't want it to + * do much work. asm volatile keeps the compiler from optimising these instructions out. + */ +#if defined(__i386__) || defined(__x86_64__) +#define cpu_relax() asm volatile("rep; nop" ::: "memory"); + +#elif defined(__arm__) || defined(__mips__) + #define cpu_relax() asm volatile("":::"memory") + +#elif defined(__aarch64__) +#define cpu_relax() asm volatile("yield" ::: "memory") + +#else +#error "cpu_relax is not defined for this architecture" +#endif + +} + +#endif //OBOE_STABILIZEDCALLBACK_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/Utilities.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/Utilities.h new file mode 100644 index 0000000..2c27088 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/Utilities.h @@ -0,0 +1,87 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_UTILITIES_H +#define OBOE_UTILITIES_H + +#include +#include +#include +#include "oboe/Definitions.h" + +namespace oboe { + +/** + * Convert an array of floats to an array of 16-bit integers. + * + * @param source the input array. + * @param destination the output array. + * @param numSamples the number of values to convert. + */ +void convertFloatToPcm16(const float *source, int16_t *destination, int32_t numSamples); + +/** + * Convert an array of 16-bit integers to an array of floats. + * + * @param source the input array. + * @param destination the output array. + * @param numSamples the number of values to convert. + */ +void convertPcm16ToFloat(const int16_t *source, float *destination, int32_t numSamples); + +/** + * @return the size of a sample of the given format in bytes or 0 if format is invalid + */ +int32_t convertFormatToSizeInBytes(AudioFormat format); + +/** + * The text is the ASCII symbol corresponding to the supplied Oboe enum value, + * or an English message saying the value is unrecognized. + * This is intended for developers to use when debugging. + * It is not for displaying to users. + * + * @param input object to convert from. @see common/Utilities.cpp for concrete implementations + * @return text representation of an Oboe enum value. There is no need to call free on this. + */ +template +const char * convertToText(FromType input); + +/** + * @param name + * @return the value of a named system property in a string or empty string + */ +std::string getPropertyString(const char * name); + +/** + * @param name + * @param defaultValue + * @return integer value associated with a property or the default value + */ +int getPropertyInteger(const char * name, int defaultValue); + +/** + * Return the version of the SDK that is currently running. + * + * For example, on Android, this would return 27 for Oreo 8.1. + * If the version number cannot be determined then this will return -1. + * + * @return version number or -1 + */ +int getSdkVersion(); + +} // namespace oboe + +#endif //OBOE_UTILITIES_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/Version.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/Version.h new file mode 100644 index 0000000..bdc12e4 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/include/oboe/Version.h @@ -0,0 +1,92 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_VERSIONINFO_H +#define OBOE_VERSIONINFO_H + +#include + +/** + * A note on use of preprocessor defines: + * + * This is one of the few times when it's suitable to use preprocessor defines rather than constexpr + * Why? Because C++11 requires a lot of boilerplate code to convert integers into compile-time + * string literals. The preprocessor, despite it's lack of type checking, is more suited to the task + * + * See: https://stackoverflow.com/questions/6713420/c-convert-integer-to-string-at-compile-time/26824971#26824971 + * + */ + +// Type: 8-bit unsigned int. Min value: 0 Max value: 255. See below for description. +#define OBOE_VERSION_MAJOR 1 + +// Type: 8-bit unsigned int. Min value: 0 Max value: 255. See below for description. +#define OBOE_VERSION_MINOR 4 + +// Type: 16-bit unsigned int. Min value: 0 Max value: 65535. See below for description. +#define OBOE_VERSION_PATCH 2 + +#define OBOE_STRINGIFY(x) #x +#define OBOE_TOSTRING(x) OBOE_STRINGIFY(x) + +// Type: String literal. See below for description. +#define OBOE_VERSION_TEXT \ + OBOE_TOSTRING(OBOE_VERSION_MAJOR) "." \ + OBOE_TOSTRING(OBOE_VERSION_MINOR) "." \ + OBOE_TOSTRING(OBOE_VERSION_PATCH) + +// Type: 32-bit unsigned int. See below for description. +#define OBOE_VERSION_NUMBER ((OBOE_VERSION_MAJOR << 24) | (OBOE_VERSION_MINOR << 16) | OBOE_VERSION_PATCH) + +namespace oboe { + +const char * getVersionText(); + +/** + * Oboe versioning object + */ +struct Version { + /** + * This is incremented when we make breaking API changes. Based loosely on https://semver.org/. + */ + static constexpr uint8_t Major = OBOE_VERSION_MAJOR; + + /** + * This is incremented when we add backwards compatible functionality. Or set to zero when MAJOR is + * incremented. + */ + static constexpr uint8_t Minor = OBOE_VERSION_MINOR; + + /** + * This is incremented when we make backwards compatible bug fixes. Or set to zero when MINOR is + * incremented. + */ + static constexpr uint16_t Patch = OBOE_VERSION_PATCH; + + /** + * Version string in the form MAJOR.MINOR.PATCH. + */ + static constexpr const char * Text = OBOE_VERSION_TEXT; + + /** + * Integer representation of the current Oboe library version. This will always increase when the + * version number changes so can be compared using integer comparison. + */ + static constexpr uint32_t Number = OBOE_VERSION_NUMBER; +}; + +} // namespace oboe +#endif //OBOE_VERSIONINFO_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/readme.md b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/readme.md new file mode 100644 index 0000000..5446d4b --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/readme.md @@ -0,0 +1,10 @@ +The files in this directory are reproduced from the official Oboe repository, which can be found at +github.com/google/oboe. + +These files are from tag 1.4.2 (55304d7). + +We've included only those parts of the original repository which are required to build the Oboe +library. Documentation, samples, tests, and other non-library items have been omitted. + +Files in this directory and below are licensed under the terms of the license in the LICENSE file +which you can find in the same directory as this readme. diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/aaudio/AAudioLoader.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/aaudio/AAudioLoader.cpp new file mode 100644 index 0000000..064633c --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/aaudio/AAudioLoader.cpp @@ -0,0 +1,348 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "common/OboeDebug.h" +#include "AAudioLoader.h" + +#define LIB_AAUDIO_NAME "libaaudio.so" + +namespace oboe { + +AAudioLoader::~AAudioLoader() { + if (mLibHandle != nullptr) { + dlclose(mLibHandle); + mLibHandle = nullptr; + } +} + +AAudioLoader* AAudioLoader::getInstance() { + static AAudioLoader instance; + return &instance; +} + +int AAudioLoader::open() { + if (mLibHandle != nullptr) { + return 0; + } + + // Use RTLD_NOW to avoid the unpredictable behavior that RTLD_LAZY can cause. + // Also resolving all the links now will prevent a run-time penalty later. + mLibHandle = dlopen(LIB_AAUDIO_NAME, RTLD_NOW); + if (mLibHandle == nullptr) { + LOGI("AAudioLoader::open() could not find " LIB_AAUDIO_NAME); + return -1; // TODO review return code + } else { + LOGD("AAudioLoader(): dlopen(%s) returned %p", LIB_AAUDIO_NAME, mLibHandle); + } + + // Load all the function pointers. + createStreamBuilder = load_I_PPB("AAudio_createStreamBuilder"); + builder_openStream = load_I_PBPPS("AAudioStreamBuilder_openStream"); + + builder_setChannelCount = load_V_PBI("AAudioStreamBuilder_setChannelCount"); + if (builder_setChannelCount == nullptr) { + // Use old deprecated alias if needed. + builder_setChannelCount = load_V_PBI("AAudioStreamBuilder_setSamplesPerFrame"); + } + + builder_setBufferCapacityInFrames = load_V_PBI("AAudioStreamBuilder_setBufferCapacityInFrames"); + builder_setDeviceId = load_V_PBI("AAudioStreamBuilder_setDeviceId"); + builder_setDirection = load_V_PBI("AAudioStreamBuilder_setDirection"); + builder_setFormat = load_V_PBI("AAudioStreamBuilder_setFormat"); + builder_setFramesPerDataCallback = load_V_PBI("AAudioStreamBuilder_setFramesPerDataCallback"); + builder_setSharingMode = load_V_PBI("AAudioStreamBuilder_setSharingMode"); + builder_setPerformanceMode = load_V_PBI("AAudioStreamBuilder_setPerformanceMode"); + builder_setSampleRate = load_V_PBI("AAudioStreamBuilder_setSampleRate"); + + if (getSdkVersion() >= __ANDROID_API_P__){ + builder_setUsage = load_V_PBI("AAudioStreamBuilder_setUsage"); + builder_setContentType = load_V_PBI("AAudioStreamBuilder_setContentType"); + builder_setInputPreset = load_V_PBI("AAudioStreamBuilder_setInputPreset"); + builder_setSessionId = load_V_PBI("AAudioStreamBuilder_setSessionId"); + } + + builder_delete = load_I_PB("AAudioStreamBuilder_delete"); + + + builder_setDataCallback = load_V_PBPDPV("AAudioStreamBuilder_setDataCallback"); + builder_setErrorCallback = load_V_PBPEPV("AAudioStreamBuilder_setErrorCallback"); + + stream_read = load_I_PSPVIL("AAudioStream_read"); + + stream_write = load_I_PSCPVIL("AAudioStream_write"); + + stream_waitForStateChange = load_I_PSTPTL("AAudioStream_waitForStateChange"); + + stream_getTimestamp = load_I_PSKPLPL("AAudioStream_getTimestamp"); + + stream_isMMapUsed = load_B_PS("AAudioStream_isMMapUsed"); + + stream_getChannelCount = load_I_PS("AAudioStream_getChannelCount"); + if (stream_getChannelCount == nullptr) { + // Use old alias if needed. + stream_getChannelCount = load_I_PS("AAudioStream_getSamplesPerFrame"); + } + + stream_close = load_I_PS("AAudioStream_close"); + + stream_getBufferSize = load_I_PS("AAudioStream_getBufferSizeInFrames"); + stream_getDeviceId = load_I_PS("AAudioStream_getDeviceId"); + stream_getBufferCapacity = load_I_PS("AAudioStream_getBufferCapacityInFrames"); + stream_getFormat = load_F_PS("AAudioStream_getFormat"); + stream_getFramesPerBurst = load_I_PS("AAudioStream_getFramesPerBurst"); + stream_getFramesRead = load_L_PS("AAudioStream_getFramesRead"); + stream_getFramesWritten = load_L_PS("AAudioStream_getFramesWritten"); + stream_getPerformanceMode = load_I_PS("AAudioStream_getPerformanceMode"); + stream_getSampleRate = load_I_PS("AAudioStream_getSampleRate"); + stream_getSharingMode = load_I_PS("AAudioStream_getSharingMode"); + stream_getState = load_I_PS("AAudioStream_getState"); + stream_getXRunCount = load_I_PS("AAudioStream_getXRunCount"); + + stream_requestStart = load_I_PS("AAudioStream_requestStart"); + stream_requestPause = load_I_PS("AAudioStream_requestPause"); + stream_requestFlush = load_I_PS("AAudioStream_requestFlush"); + stream_requestStop = load_I_PS("AAudioStream_requestStop"); + + stream_setBufferSize = load_I_PSI("AAudioStream_setBufferSizeInFrames"); + + convertResultToText = load_CPH_I("AAudio_convertResultToText"); + + if (getSdkVersion() >= __ANDROID_API_P__){ + stream_getUsage = load_I_PS("AAudioStream_getUsage"); + stream_getContentType = load_I_PS("AAudioStream_getContentType"); + stream_getInputPreset = load_I_PS("AAudioStream_getInputPreset"); + stream_getSessionId = load_I_PS("AAudioStream_getSessionId"); + } + return 0; +} + +static void AAudioLoader_check(void *proc, const char *functionName) { + if (proc == nullptr) { + LOGW("AAudioLoader could not find %s", functionName); + } +} + +AAudioLoader::signature_I_PPB AAudioLoader::load_I_PPB(const char *functionName) { + void *proc = dlsym(mLibHandle, functionName); + AAudioLoader_check(proc, functionName); + return reinterpret_cast(proc); +} + +AAudioLoader::signature_CPH_I AAudioLoader::load_CPH_I(const char *functionName) { + void *proc = dlsym(mLibHandle, functionName); + AAudioLoader_check(proc, functionName); + return reinterpret_cast(proc); +} + +AAudioLoader::signature_V_PBI AAudioLoader::load_V_PBI(const char *functionName) { + void *proc = dlsym(mLibHandle, functionName); + AAudioLoader_check(proc, functionName); + return reinterpret_cast(proc); +} + +AAudioLoader::signature_V_PBPDPV AAudioLoader::load_V_PBPDPV(const char *functionName) { + void *proc = dlsym(mLibHandle, functionName); + AAudioLoader_check(proc, functionName); + return reinterpret_cast(proc); +} + +AAudioLoader::signature_V_PBPEPV AAudioLoader::load_V_PBPEPV(const char *functionName) { + void *proc = dlsym(mLibHandle, functionName); + AAudioLoader_check(proc, functionName); + return reinterpret_cast(proc); +} + +AAudioLoader::signature_I_PSI AAudioLoader::load_I_PSI(const char *functionName) { + void *proc = dlsym(mLibHandle, functionName); + AAudioLoader_check(proc, functionName); + return reinterpret_cast(proc); +} + +AAudioLoader::signature_I_PS AAudioLoader::load_I_PS(const char *functionName) { + void *proc = dlsym(mLibHandle, functionName); + AAudioLoader_check(proc, functionName); + return reinterpret_cast(proc); +} + +AAudioLoader::signature_L_PS AAudioLoader::load_L_PS(const char *functionName) { + void *proc = dlsym(mLibHandle, functionName); + AAudioLoader_check(proc, functionName); + return reinterpret_cast(proc); +} + +AAudioLoader::signature_F_PS AAudioLoader::load_F_PS(const char *functionName) { + void *proc = dlsym(mLibHandle, functionName); + AAudioLoader_check(proc, functionName); + return reinterpret_cast(proc); +} + +AAudioLoader::signature_B_PS AAudioLoader::load_B_PS(const char *functionName) { + void *proc = dlsym(mLibHandle, functionName); + AAudioLoader_check(proc, functionName); + return reinterpret_cast(proc); +} + +AAudioLoader::signature_I_PB AAudioLoader::load_I_PB(const char *functionName) { + void *proc = dlsym(mLibHandle, functionName); + AAudioLoader_check(proc, functionName); + return reinterpret_cast(proc); +} + +AAudioLoader::signature_I_PBPPS AAudioLoader::load_I_PBPPS(const char *functionName) { + void *proc = dlsym(mLibHandle, functionName); + AAudioLoader_check(proc, functionName); + return reinterpret_cast(proc); +} + +AAudioLoader::signature_I_PSCPVIL AAudioLoader::load_I_PSCPVIL(const char *functionName) { + void *proc = dlsym(mLibHandle, functionName); + AAudioLoader_check(proc, functionName); + return reinterpret_cast(proc); +} + +AAudioLoader::signature_I_PSPVIL AAudioLoader::load_I_PSPVIL(const char *functionName) { + void *proc = dlsym(mLibHandle, functionName); + AAudioLoader_check(proc, functionName); + return reinterpret_cast(proc); +} + +AAudioLoader::signature_I_PSTPTL AAudioLoader::load_I_PSTPTL(const char *functionName) { + void *proc = dlsym(mLibHandle, functionName); + AAudioLoader_check(proc, functionName); + return reinterpret_cast(proc); +} + +AAudioLoader::signature_I_PSKPLPL AAudioLoader::load_I_PSKPLPL(const char *functionName) { + void *proc = dlsym(mLibHandle, functionName); + AAudioLoader_check(proc, functionName); + return reinterpret_cast(proc); +} + +// Ensure that all AAudio primitive data types are int32_t +#define ASSERT_INT32(type) static_assert(std::is_same::value, \ +#type" must be int32_t") + +#define ERRMSG "Oboe constants must match AAudio constants." + +// These asserts help verify that the Oboe definitions match the equivalent AAudio definitions. +// This code is in this .cpp file so it only gets tested once. +#ifdef AAUDIO_AAUDIO_H + + ASSERT_INT32(aaudio_stream_state_t); + ASSERT_INT32(aaudio_direction_t); + ASSERT_INT32(aaudio_format_t); + ASSERT_INT32(aaudio_data_callback_result_t); + ASSERT_INT32(aaudio_result_t); + ASSERT_INT32(aaudio_sharing_mode_t); + ASSERT_INT32(aaudio_performance_mode_t); + + static_assert((int32_t)StreamState::Uninitialized == AAUDIO_STREAM_STATE_UNINITIALIZED, ERRMSG); + static_assert((int32_t)StreamState::Unknown == AAUDIO_STREAM_STATE_UNKNOWN, ERRMSG); + static_assert((int32_t)StreamState::Open == AAUDIO_STREAM_STATE_OPEN, ERRMSG); + static_assert((int32_t)StreamState::Starting == AAUDIO_STREAM_STATE_STARTING, ERRMSG); + static_assert((int32_t)StreamState::Started == AAUDIO_STREAM_STATE_STARTED, ERRMSG); + static_assert((int32_t)StreamState::Pausing == AAUDIO_STREAM_STATE_PAUSING, ERRMSG); + static_assert((int32_t)StreamState::Paused == AAUDIO_STREAM_STATE_PAUSED, ERRMSG); + static_assert((int32_t)StreamState::Flushing == AAUDIO_STREAM_STATE_FLUSHING, ERRMSG); + static_assert((int32_t)StreamState::Flushed == AAUDIO_STREAM_STATE_FLUSHED, ERRMSG); + static_assert((int32_t)StreamState::Stopping == AAUDIO_STREAM_STATE_STOPPING, ERRMSG); + static_assert((int32_t)StreamState::Stopped == AAUDIO_STREAM_STATE_STOPPED, ERRMSG); + static_assert((int32_t)StreamState::Closing == AAUDIO_STREAM_STATE_CLOSING, ERRMSG); + static_assert((int32_t)StreamState::Closed == AAUDIO_STREAM_STATE_CLOSED, ERRMSG); + static_assert((int32_t)StreamState::Disconnected == AAUDIO_STREAM_STATE_DISCONNECTED, ERRMSG); + + static_assert((int32_t)Direction::Output == AAUDIO_DIRECTION_OUTPUT, ERRMSG); + static_assert((int32_t)Direction::Input == AAUDIO_DIRECTION_INPUT, ERRMSG); + + static_assert((int32_t)AudioFormat::Invalid == AAUDIO_FORMAT_INVALID, ERRMSG); + static_assert((int32_t)AudioFormat::Unspecified == AAUDIO_FORMAT_UNSPECIFIED, ERRMSG); + static_assert((int32_t)AudioFormat::I16 == AAUDIO_FORMAT_PCM_I16, ERRMSG); + static_assert((int32_t)AudioFormat::Float == AAUDIO_FORMAT_PCM_FLOAT, ERRMSG); + + static_assert((int32_t)DataCallbackResult::Continue == AAUDIO_CALLBACK_RESULT_CONTINUE, ERRMSG); + static_assert((int32_t)DataCallbackResult::Stop == AAUDIO_CALLBACK_RESULT_STOP, ERRMSG); + + static_assert((int32_t)Result::OK == AAUDIO_OK, ERRMSG); + static_assert((int32_t)Result::ErrorBase == AAUDIO_ERROR_BASE, ERRMSG); + static_assert((int32_t)Result::ErrorDisconnected == AAUDIO_ERROR_DISCONNECTED, ERRMSG); + static_assert((int32_t)Result::ErrorIllegalArgument == AAUDIO_ERROR_ILLEGAL_ARGUMENT, ERRMSG); + static_assert((int32_t)Result::ErrorInternal == AAUDIO_ERROR_INTERNAL, ERRMSG); + static_assert((int32_t)Result::ErrorInvalidState == AAUDIO_ERROR_INVALID_STATE, ERRMSG); + static_assert((int32_t)Result::ErrorInvalidHandle == AAUDIO_ERROR_INVALID_HANDLE, ERRMSG); + static_assert((int32_t)Result::ErrorUnimplemented == AAUDIO_ERROR_UNIMPLEMENTED, ERRMSG); + static_assert((int32_t)Result::ErrorUnavailable == AAUDIO_ERROR_UNAVAILABLE, ERRMSG); + static_assert((int32_t)Result::ErrorNoFreeHandles == AAUDIO_ERROR_NO_FREE_HANDLES, ERRMSG); + static_assert((int32_t)Result::ErrorNoMemory == AAUDIO_ERROR_NO_MEMORY, ERRMSG); + static_assert((int32_t)Result::ErrorNull == AAUDIO_ERROR_NULL, ERRMSG); + static_assert((int32_t)Result::ErrorTimeout == AAUDIO_ERROR_TIMEOUT, ERRMSG); + static_assert((int32_t)Result::ErrorWouldBlock == AAUDIO_ERROR_WOULD_BLOCK, ERRMSG); + static_assert((int32_t)Result::ErrorInvalidFormat == AAUDIO_ERROR_INVALID_FORMAT, ERRMSG); + static_assert((int32_t)Result::ErrorOutOfRange == AAUDIO_ERROR_OUT_OF_RANGE, ERRMSG); + static_assert((int32_t)Result::ErrorNoService == AAUDIO_ERROR_NO_SERVICE, ERRMSG); + static_assert((int32_t)Result::ErrorInvalidRate == AAUDIO_ERROR_INVALID_RATE, ERRMSG); + + static_assert((int32_t)SharingMode::Exclusive == AAUDIO_SHARING_MODE_EXCLUSIVE, ERRMSG); + static_assert((int32_t)SharingMode::Shared == AAUDIO_SHARING_MODE_SHARED, ERRMSG); + + static_assert((int32_t)PerformanceMode::None == AAUDIO_PERFORMANCE_MODE_NONE, ERRMSG); + static_assert((int32_t)PerformanceMode::PowerSaving + == AAUDIO_PERFORMANCE_MODE_POWER_SAVING, ERRMSG); + static_assert((int32_t)PerformanceMode::LowLatency + == AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, ERRMSG); +#endif + +// The aaudio_ usage, content and input_preset types were added in NDK 17, +// which is the first version to support Android Pie (API 28). +#if __NDK_MAJOR__ >= 17 + + ASSERT_INT32(aaudio_usage_t); + ASSERT_INT32(aaudio_content_type_t); + ASSERT_INT32(aaudio_input_preset_t); + + static_assert((int32_t)Usage::Media == AAUDIO_USAGE_MEDIA, ERRMSG); + static_assert((int32_t)Usage::VoiceCommunication == AAUDIO_USAGE_VOICE_COMMUNICATION, ERRMSG); + static_assert((int32_t)Usage::VoiceCommunicationSignalling + == AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING, ERRMSG); + static_assert((int32_t)Usage::Alarm == AAUDIO_USAGE_ALARM, ERRMSG); + static_assert((int32_t)Usage::Notification == AAUDIO_USAGE_NOTIFICATION, ERRMSG); + static_assert((int32_t)Usage::NotificationRingtone == AAUDIO_USAGE_NOTIFICATION_RINGTONE, ERRMSG); + static_assert((int32_t)Usage::NotificationEvent == AAUDIO_USAGE_NOTIFICATION_EVENT, ERRMSG); + static_assert((int32_t)Usage::AssistanceAccessibility == AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY, ERRMSG); + static_assert((int32_t)Usage::AssistanceNavigationGuidance + == AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, ERRMSG); + static_assert((int32_t)Usage::AssistanceSonification == AAUDIO_USAGE_ASSISTANCE_SONIFICATION, ERRMSG); + static_assert((int32_t)Usage::Game == AAUDIO_USAGE_GAME, ERRMSG); + static_assert((int32_t)Usage::Assistant == AAUDIO_USAGE_ASSISTANT, ERRMSG); + + static_assert((int32_t)ContentType::Speech == AAUDIO_CONTENT_TYPE_SPEECH, ERRMSG); + static_assert((int32_t)ContentType::Music == AAUDIO_CONTENT_TYPE_MUSIC, ERRMSG); + static_assert((int32_t)ContentType::Movie == AAUDIO_CONTENT_TYPE_MOVIE, ERRMSG); + static_assert((int32_t)ContentType::Sonification == AAUDIO_CONTENT_TYPE_SONIFICATION, ERRMSG); + + static_assert((int32_t)InputPreset::Generic == AAUDIO_INPUT_PRESET_GENERIC, ERRMSG); + static_assert((int32_t)InputPreset::Camcorder == AAUDIO_INPUT_PRESET_CAMCORDER, ERRMSG); + static_assert((int32_t)InputPreset::VoiceRecognition == AAUDIO_INPUT_PRESET_VOICE_RECOGNITION, ERRMSG); + static_assert((int32_t)InputPreset::VoiceCommunication + == AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION, ERRMSG); + static_assert((int32_t)InputPreset::Unprocessed == AAUDIO_INPUT_PRESET_UNPROCESSED, ERRMSG); + + static_assert((int32_t)SessionId::None == AAUDIO_SESSION_ID_NONE, ERRMSG); + static_assert((int32_t)SessionId::Allocate == AAUDIO_SESSION_ID_ALLOCATE, ERRMSG); +#endif + +} // namespace oboe diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/aaudio/AAudioLoader.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/aaudio/AAudioLoader.h new file mode 100644 index 0000000..6f5bb95 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/aaudio/AAudioLoader.h @@ -0,0 +1,229 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_AAUDIO_LOADER_H_ +#define OBOE_AAUDIO_LOADER_H_ + +#include +#include "oboe/Definitions.h" + +// If the NDK is before O then define this in your build +// so that AAudio.h will not be included. +#ifdef OBOE_NO_INCLUDE_AAUDIO + +// Define missing types from AAudio.h +typedef int32_t aaudio_stream_state_t; +typedef int32_t aaudio_direction_t; +typedef int32_t aaudio_format_t; +typedef int32_t aaudio_data_callback_result_t; +typedef int32_t aaudio_result_t; +typedef int32_t aaudio_sharing_mode_t; +typedef int32_t aaudio_performance_mode_t; + +typedef struct AAudioStreamStruct AAudioStream; +typedef struct AAudioStreamBuilderStruct AAudioStreamBuilder; + +typedef aaudio_data_callback_result_t (*AAudioStream_dataCallback)( + AAudioStream *stream, + void *userData, + void *audioData, + int32_t numFrames); + +typedef void (*AAudioStream_errorCallback)( + AAudioStream *stream, + void *userData, + aaudio_result_t error); + +// These were defined in P +typedef int32_t aaudio_usage_t; +typedef int32_t aaudio_content_type_t; +typedef int32_t aaudio_input_preset_t; +typedef int32_t aaudio_session_id_t; +#else +#include +#include +#endif + +#ifndef __NDK_MAJOR__ +#define __NDK_MAJOR__ 0 +#endif + +namespace oboe { + + +/** + * The AAudio API was not available in early versions of Android. + * To avoid linker errors, we dynamically link with the functions by name using dlsym(). + * On older versions this linkage will safely fail. + */ +class AAudioLoader { + public: + // Use signatures for common functions. + // Key to letter abbreviations. + // S = Stream + // B = Builder + // I = int32_t + // L = int64_t + // T = sTate + // K = clocKid_t + // P = Pointer to following data type + // C = Const prefix + // H = cHar + typedef int32_t (*signature_I_PPB)(AAudioStreamBuilder **builder); + + typedef const char * (*signature_CPH_I)(int32_t); + + typedef int32_t (*signature_I_PBPPS)(AAudioStreamBuilder *, + AAudioStream **stream); // AAudioStreamBuilder_open() + + typedef int32_t (*signature_I_PB)(AAudioStreamBuilder *); // AAudioStreamBuilder_delete() + // AAudioStreamBuilder_setSampleRate() + typedef void (*signature_V_PBI)(AAudioStreamBuilder *, int32_t); + + typedef int32_t (*signature_I_PS)(AAudioStream *); // AAudioStream_getSampleRate() + typedef int64_t (*signature_L_PS)(AAudioStream *); // AAudioStream_getFramesRead() + // AAudioStream_setBufferSizeInFrames() + typedef int32_t (*signature_I_PSI)(AAudioStream *, int32_t); + + typedef void (*signature_V_PBPDPV)(AAudioStreamBuilder *, + AAudioStream_dataCallback, + void *); + + typedef void (*signature_V_PBPEPV)(AAudioStreamBuilder *, + AAudioStream_errorCallback, + void *); + + typedef aaudio_format_t (*signature_F_PS)(AAudioStream *stream); + + typedef int32_t (*signature_I_PSPVIL)(AAudioStream *, void *, int32_t, int64_t); + typedef int32_t (*signature_I_PSCPVIL)(AAudioStream *, const void *, int32_t, int64_t); + + typedef int32_t (*signature_I_PSTPTL)(AAudioStream *, + aaudio_stream_state_t, + aaudio_stream_state_t *, + int64_t); + + typedef int32_t (*signature_I_PSKPLPL)(AAudioStream *, clockid_t, int64_t *, int64_t *); + + typedef bool (*signature_B_PS)(AAudioStream *); + + static AAudioLoader* getInstance(); // singleton + + /** + * Open the AAudio shared library and load the function pointers. + * This can be called multiple times. + * It should only be called from one thread. + * + * The destructor will clean up after the open. + * + * @return 0 if successful or negative error. + */ + int open(); + + // Function pointers into the AAudio shared library. + signature_I_PPB createStreamBuilder = nullptr; + + signature_I_PBPPS builder_openStream = nullptr; + + signature_V_PBI builder_setBufferCapacityInFrames = nullptr; + signature_V_PBI builder_setChannelCount = nullptr; + signature_V_PBI builder_setDeviceId = nullptr; + signature_V_PBI builder_setDirection = nullptr; + signature_V_PBI builder_setFormat = nullptr; + signature_V_PBI builder_setFramesPerDataCallback = nullptr; + signature_V_PBI builder_setPerformanceMode = nullptr; + signature_V_PBI builder_setSampleRate = nullptr; + signature_V_PBI builder_setSharingMode = nullptr; + + signature_V_PBI builder_setUsage = nullptr; + signature_V_PBI builder_setContentType = nullptr; + signature_V_PBI builder_setInputPreset = nullptr; + signature_V_PBI builder_setSessionId = nullptr; + + signature_V_PBPDPV builder_setDataCallback = nullptr; + signature_V_PBPEPV builder_setErrorCallback = nullptr; + + signature_I_PB builder_delete = nullptr; + + signature_F_PS stream_getFormat = nullptr; + + signature_I_PSPVIL stream_read = nullptr; + signature_I_PSCPVIL stream_write = nullptr; + + signature_I_PSTPTL stream_waitForStateChange = nullptr; + + signature_I_PSKPLPL stream_getTimestamp = nullptr; + + signature_B_PS stream_isMMapUsed = nullptr; + + signature_I_PS stream_close = nullptr; + + signature_I_PS stream_getChannelCount = nullptr; + signature_I_PS stream_getDeviceId = nullptr; + + signature_I_PS stream_getBufferSize = nullptr; + signature_I_PS stream_getBufferCapacity = nullptr; + signature_I_PS stream_getFramesPerBurst = nullptr; + signature_I_PS stream_getState = nullptr; + signature_I_PS stream_getPerformanceMode = nullptr; + signature_I_PS stream_getSampleRate = nullptr; + signature_I_PS stream_getSharingMode = nullptr; + signature_I_PS stream_getXRunCount = nullptr; + + signature_I_PSI stream_setBufferSize = nullptr; + signature_I_PS stream_requestStart = nullptr; + signature_I_PS stream_requestPause = nullptr; + signature_I_PS stream_requestFlush = nullptr; + signature_I_PS stream_requestStop = nullptr; + + signature_L_PS stream_getFramesRead = nullptr; + signature_L_PS stream_getFramesWritten = nullptr; + + signature_CPH_I convertResultToText = nullptr; + + signature_I_PS stream_getUsage = nullptr; + signature_I_PS stream_getContentType = nullptr; + signature_I_PS stream_getInputPreset = nullptr; + signature_I_PS stream_getSessionId = nullptr; + + private: + AAudioLoader() {} + ~AAudioLoader(); + + // Load function pointers for specific signatures. + signature_I_PPB load_I_PPB(const char *name); + signature_CPH_I load_CPH_I(const char *name); + signature_V_PBI load_V_PBI(const char *name); + signature_V_PBPDPV load_V_PBPDPV(const char *name); + signature_V_PBPEPV load_V_PBPEPV(const char *name); + signature_I_PB load_I_PB(const char *name); + signature_I_PBPPS load_I_PBPPS(const char *name); + signature_I_PS load_I_PS(const char *name); + signature_L_PS load_L_PS(const char *name); + signature_F_PS load_F_PS(const char *name); + signature_B_PS load_B_PS(const char *name); + signature_I_PSI load_I_PSI(const char *name); + signature_I_PSPVIL load_I_PSPVIL(const char *name); + signature_I_PSCPVIL load_I_PSCPVIL(const char *name); + signature_I_PSTPTL load_I_PSTPTL(const char *name); + signature_I_PSKPLPL load_I_PSKPLPL(const char *name); + + void *mLibHandle = nullptr; +}; + +} // namespace oboe + +#endif //OBOE_AAUDIO_LOADER_H_ diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/aaudio/AudioStreamAAudio.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/aaudio/AudioStreamAAudio.cpp new file mode 100644 index 0000000..52d85b9 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/aaudio/AudioStreamAAudio.cpp @@ -0,0 +1,643 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "aaudio/AAudioLoader.h" +#include "aaudio/AudioStreamAAudio.h" +#include "common/AudioClock.h" +#include "common/OboeDebug.h" +#include "oboe/Utilities.h" + +#ifdef __ANDROID__ +#include +#include + +#endif + +#ifndef OBOE_FIX_FORCE_STARTING_TO_STARTED +// Workaround state problems in AAudio +// TODO Which versions does this occur in? Verify fixed in Q. +#define OBOE_FIX_FORCE_STARTING_TO_STARTED 1 +#endif // OBOE_FIX_FORCE_STARTING_TO_STARTED + +using namespace oboe; +AAudioLoader *AudioStreamAAudio::mLibLoader = nullptr; + +// 'C' wrapper for the data callback method +static aaudio_data_callback_result_t oboe_aaudio_data_callback_proc( + AAudioStream *stream, + void *userData, + void *audioData, + int32_t numFrames) { + + AudioStreamAAudio *oboeStream = reinterpret_cast(userData); + if (oboeStream != nullptr) { + return static_cast( + oboeStream->callOnAudioReady(stream, audioData, numFrames)); + + } else { + return static_cast(DataCallbackResult::Stop); + } +} + +// This runs in its own thread. +// Only one of these threads will be launched from internalErrorCallback(). +// It calls app error callbacks from a static function in case the stream gets deleted. +static void oboe_aaudio_error_thread_proc(AudioStreamAAudio *oboeStream, + Result error) { + LOGD("%s() - entering >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", __func__); + oboeStream->requestStop(); + if (oboeStream->getCallback() != nullptr) { + oboeStream->getCallback()->onErrorBeforeClose(oboeStream, error); + } + oboeStream->close(); + if (oboeStream->getCallback() != nullptr) { + // Warning, oboeStream may get deleted by this callback. + oboeStream->getCallback()->onErrorAfterClose(oboeStream, error); + } + LOGD("%s() - exiting <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<", __func__); +} + +// This runs in its own thread. +// Only one of these threads will be launched from internalErrorCallback(). +// Prevents deletion of the stream if the app is using AudioStreamBuilder::openSharedStream() +static void oboe_aaudio_error_thread_proc_shared(std::shared_ptr sharedStream, + Result error) { + AudioStreamAAudio *oboeStream = reinterpret_cast(sharedStream.get()); + oboe_aaudio_error_thread_proc(oboeStream, error); +} + +namespace oboe { + +/* + * Create a stream that uses Oboe Audio API. + */ +AudioStreamAAudio::AudioStreamAAudio(const AudioStreamBuilder &builder) + : AudioStream(builder) + , mAAudioStream(nullptr) { + mCallbackThreadEnabled.store(false); + isSupported(); +} + +bool AudioStreamAAudio::isSupported() { + mLibLoader = AAudioLoader::getInstance(); + int openResult = mLibLoader->open(); + return openResult == 0; +} + +// Static 'C' wrapper for the error callback method. +// Launch a thread to handle the error. +// That other thread can safely stop, close and delete the stream. +void AudioStreamAAudio::internalErrorCallback( + AAudioStream *stream, + void *userData, + aaudio_result_t error) { + AudioStreamAAudio *oboeStream = reinterpret_cast(userData); + + // Prevents deletion of the stream if the app is using AudioStreamBuilder::openSharedStream() + std::shared_ptr sharedStream = oboeStream->lockWeakThis(); + + // These checks should be enough because we assume that the stream close() + // will join() any active callback threads and will not allow new callbacks. + if (oboeStream->wasErrorCallbackCalled()) { // block extra error callbacks + LOGE("%s() multiple error callbacks called!", __func__); + } else if (stream != oboeStream->getUnderlyingStream()) { + LOGW("%s() stream already closed", __func__); // can happen if there are bugs + } else if (sharedStream) { + // Handle error on a separate thread using shared pointer. + std::thread t(oboe_aaudio_error_thread_proc_shared, sharedStream, + static_cast(error)); + t.detach(); + } else { + // Handle error on a separate thread. + std::thread t(oboe_aaudio_error_thread_proc, oboeStream, + static_cast(error)); + t.detach(); + } +} + +void AudioStreamAAudio::logUnsupportedAttributes() { + int sdkVersion = getSdkVersion(); + + // These attributes are not supported pre Android "P" + if (sdkVersion < __ANDROID_API_P__) { + if (mUsage != Usage::Media) { + LOGW("Usage [AudioStreamBuilder::setUsage()] " + "is not supported on AAudio streams running on pre-Android P versions."); + } + + if (mContentType != ContentType::Music) { + LOGW("ContentType [AudioStreamBuilder::setContentType()] " + "is not supported on AAudio streams running on pre-Android P versions."); + } + + if (mSessionId != SessionId::None) { + LOGW("SessionId [AudioStreamBuilder::setSessionId()] " + "is not supported on AAudio streams running on pre-Android P versions."); + } + } +} + +Result AudioStreamAAudio::open() { + Result result = Result::OK; + + if (mAAudioStream != nullptr) { + return Result::ErrorInvalidState; + } + + result = AudioStream::open(); + if (result != Result::OK) { + return result; + } + + AAudioStreamBuilder *aaudioBuilder; + result = static_cast(mLibLoader->createStreamBuilder(&aaudioBuilder)); + if (result != Result::OK) { + return result; + } + + // Do not set INPUT capacity below 4096 because that prevents us from getting a FAST track + // when using the Legacy data path. + // If the app requests > 4096 then we allow it but we are less likely to get LowLatency. + // See internal bug b/80308183 for more details. + // Fixed in Q but let's still clip the capacity because high input capacity + // does not increase latency. + int32_t capacity = mBufferCapacityInFrames; + constexpr int kCapacityRequiredForFastLegacyTrack = 4096; // matches value in AudioFinger + if (OboeGlobals::areWorkaroundsEnabled() + && mDirection == oboe::Direction::Input + && capacity != oboe::Unspecified + && capacity < kCapacityRequiredForFastLegacyTrack + && mPerformanceMode == oboe::PerformanceMode::LowLatency) { + capacity = kCapacityRequiredForFastLegacyTrack; + LOGD("AudioStreamAAudio.open() capacity changed from %d to %d for lower latency", + static_cast(mBufferCapacityInFrames), capacity); + } + mLibLoader->builder_setBufferCapacityInFrames(aaudioBuilder, capacity); + + mLibLoader->builder_setChannelCount(aaudioBuilder, mChannelCount); + mLibLoader->builder_setDeviceId(aaudioBuilder, mDeviceId); + mLibLoader->builder_setDirection(aaudioBuilder, static_cast(mDirection)); + mLibLoader->builder_setFormat(aaudioBuilder, static_cast(mFormat)); + mLibLoader->builder_setSampleRate(aaudioBuilder, mSampleRate); + mLibLoader->builder_setSharingMode(aaudioBuilder, + static_cast(mSharingMode)); + mLibLoader->builder_setPerformanceMode(aaudioBuilder, + static_cast(mPerformanceMode)); + + // These were added in P so we have to check for the function pointer. + if (mLibLoader->builder_setUsage != nullptr) { + mLibLoader->builder_setUsage(aaudioBuilder, + static_cast(mUsage)); + } + + if (mLibLoader->builder_setContentType != nullptr) { + mLibLoader->builder_setContentType(aaudioBuilder, + static_cast(mContentType)); + } + + if (mLibLoader->builder_setInputPreset != nullptr) { + mLibLoader->builder_setInputPreset(aaudioBuilder, + static_cast(mInputPreset)); + } + + if (mLibLoader->builder_setSessionId != nullptr) { + mLibLoader->builder_setSessionId(aaudioBuilder, + static_cast(mSessionId)); + } + + // TODO get more parameters from the builder? + + if (mStreamCallback != nullptr) { + mLibLoader->builder_setDataCallback(aaudioBuilder, oboe_aaudio_data_callback_proc, this); + mLibLoader->builder_setFramesPerDataCallback(aaudioBuilder, getFramesPerCallback()); + // If the data callback is not being used then the write method will return an error + // and the app can stop and close the stream. + mLibLoader->builder_setErrorCallback(aaudioBuilder, internalErrorCallback, this); + } + + // ============= OPEN THE STREAM ================ + { + AAudioStream *stream = nullptr; + result = static_cast(mLibLoader->builder_openStream(aaudioBuilder, &stream)); + mAAudioStream.store(stream); + } + if (result != Result::OK) { + goto error2; + } + + // Query and cache the stream properties + mDeviceId = mLibLoader->stream_getDeviceId(mAAudioStream); + mChannelCount = mLibLoader->stream_getChannelCount(mAAudioStream); + mSampleRate = mLibLoader->stream_getSampleRate(mAAudioStream); + mFormat = static_cast(mLibLoader->stream_getFormat(mAAudioStream)); + mSharingMode = static_cast(mLibLoader->stream_getSharingMode(mAAudioStream)); + mPerformanceMode = static_cast( + mLibLoader->stream_getPerformanceMode(mAAudioStream)); + mBufferCapacityInFrames = mLibLoader->stream_getBufferCapacity(mAAudioStream); + mBufferSizeInFrames = mLibLoader->stream_getBufferSize(mAAudioStream); + + + // These were added in P so we have to check for the function pointer. + if (mLibLoader->stream_getUsage != nullptr) { + mUsage = static_cast(mLibLoader->stream_getUsage(mAAudioStream)); + } + if (mLibLoader->stream_getContentType != nullptr) { + mContentType = static_cast(mLibLoader->stream_getContentType(mAAudioStream)); + } + if (mLibLoader->stream_getInputPreset != nullptr) { + mInputPreset = static_cast(mLibLoader->stream_getInputPreset(mAAudioStream)); + } + if (mLibLoader->stream_getSessionId != nullptr) { + mSessionId = static_cast(mLibLoader->stream_getSessionId(mAAudioStream)); + } else { + mSessionId = SessionId::None; + } + + LOGD("AudioStreamAAudio.open() format=%d, sampleRate=%d, capacity = %d", + static_cast(mFormat), static_cast(mSampleRate), + static_cast(mBufferCapacityInFrames)); + +error2: + mLibLoader->builder_delete(aaudioBuilder); + LOGD("AudioStreamAAudio.open: AAudioStream_Open() returned %s", + mLibLoader->convertResultToText(static_cast(result))); + return result; +} + +Result AudioStreamAAudio::close() { + // The main reason we have this mutex if to prevent a collision between a call + // by the application to stop a stream at the same time that an onError callback + // is being executed because of a disconnect. The close will delete the stream, + // which could otherwise cause the requestStop() to crash. + std::lock_guard lock(mLock); + + AudioStream::close(); + + // This will delete the AAudio stream object so we need to null out the pointer. + AAudioStream *stream = mAAudioStream.exchange(nullptr); + if (stream != nullptr) { + return static_cast(mLibLoader->stream_close(stream)); + } else { + return Result::ErrorClosed; + } +} + +DataCallbackResult AudioStreamAAudio::callOnAudioReady(AAudioStream *stream, + void *audioData, + int32_t numFrames) { + DataCallbackResult result = fireDataCallback(audioData, numFrames); + if (result == DataCallbackResult::Continue) { + return result; + } else { + if (result == DataCallbackResult::Stop) { + LOGD("Oboe callback returned DataCallbackResult::Stop"); + } else { + LOGE("Oboe callback returned unexpected value = %d", result); + } + + if (getSdkVersion() <= __ANDROID_API_P__) { + launchStopThread(); + if (isMMapUsed()) { + return DataCallbackResult::Stop; + } else { + // Legacy stream <= API_P cannot be restarted after returning Stop. + return DataCallbackResult::Continue; + } + } else { + return DataCallbackResult::Stop; // OK >= API_Q + } + } +} + +Result AudioStreamAAudio::requestStart() { + std::lock_guard lock(mLock); + AAudioStream *stream = mAAudioStream.load(); + if (stream != nullptr) { + // Avoid state machine errors in O_MR1. + if (getSdkVersion() <= __ANDROID_API_O_MR1__) { + StreamState state = static_cast(mLibLoader->stream_getState(stream)); + if (state == StreamState::Starting || state == StreamState::Started) { + // WARNING: On P, AAudio is returning ErrorInvalidState for Output and OK for Input. + return Result::OK; + } + } + if (mStreamCallback != nullptr) { // Was a callback requested? + setDataCallbackEnabled(true); + } + return static_cast(mLibLoader->stream_requestStart(stream)); + } else { + return Result::ErrorClosed; + } +} + +Result AudioStreamAAudio::requestPause() { + std::lock_guard lock(mLock); + AAudioStream *stream = mAAudioStream.load(); + if (stream != nullptr) { + // Avoid state machine errors in O_MR1. + if (getSdkVersion() <= __ANDROID_API_O_MR1__) { + StreamState state = static_cast(mLibLoader->stream_getState(stream)); + if (state == StreamState::Pausing || state == StreamState::Paused) { + return Result::OK; + } + } + return static_cast(mLibLoader->stream_requestPause(stream)); + } else { + return Result::ErrorClosed; + } +} + +Result AudioStreamAAudio::requestFlush() { + std::lock_guard lock(mLock); + AAudioStream *stream = mAAudioStream.load(); + if (stream != nullptr) { + // Avoid state machine errors in O_MR1. + if (getSdkVersion() <= __ANDROID_API_O_MR1__) { + StreamState state = static_cast(mLibLoader->stream_getState(stream)); + if (state == StreamState::Flushing || state == StreamState::Flushed) { + return Result::OK; + } + } + return static_cast(mLibLoader->stream_requestFlush(stream)); + } else { + return Result::ErrorClosed; + } +} + +Result AudioStreamAAudio::requestStop() { + std::lock_guard lock(mLock); + AAudioStream *stream = mAAudioStream.load(); + if (stream != nullptr) { + // Avoid state machine errors in O_MR1. + if (getSdkVersion() <= __ANDROID_API_O_MR1__) { + StreamState state = static_cast(mLibLoader->stream_getState(stream)); + if (state == StreamState::Stopping || state == StreamState::Stopped) { + return Result::OK; + } + } + return static_cast(mLibLoader->stream_requestStop(stream)); + } else { + return Result::ErrorClosed; + } +} + +ResultWithValue AudioStreamAAudio::write(const void *buffer, + int32_t numFrames, + int64_t timeoutNanoseconds) { + AAudioStream *stream = mAAudioStream.load(); + if (stream != nullptr) { + int32_t result = mLibLoader->stream_write(mAAudioStream, buffer, + numFrames, timeoutNanoseconds); + return ResultWithValue::createBasedOnSign(result); + } else { + return ResultWithValue(Result::ErrorClosed); + } +} + +ResultWithValue AudioStreamAAudio::read(void *buffer, + int32_t numFrames, + int64_t timeoutNanoseconds) { + AAudioStream *stream = mAAudioStream.load(); + if (stream != nullptr) { + int32_t result = mLibLoader->stream_read(mAAudioStream, buffer, + numFrames, timeoutNanoseconds); + return ResultWithValue::createBasedOnSign(result); + } else { + return ResultWithValue(Result::ErrorClosed); + } +} + + +// AAudioStream_waitForStateChange() can crash if it is waiting on a stream and that stream +// is closed from another thread. We do not want to lock the stream for the duration of the call. +// So we call AAudioStream_waitForStateChange() with a timeout of zero so that it will not block. +// Then we can do our own sleep with the lock unlocked. +Result AudioStreamAAudio::waitForStateChange(StreamState currentState, + StreamState *nextState, + int64_t timeoutNanoseconds) { + Result oboeResult = Result::ErrorTimeout; + int64_t sleepTimeNanos = 20 * kNanosPerMillisecond; // arbitrary + aaudio_stream_state_t currentAAudioState = static_cast(currentState); + + aaudio_result_t result = AAUDIO_OK; + int64_t timeLeftNanos = timeoutNanoseconds; + + mLock.lock(); + while (true) { + // Do we still have an AAudio stream? If not then stream must have been closed. + AAudioStream *stream = mAAudioStream.load(); + if (stream == nullptr) { + if (nextState != nullptr) { + *nextState = StreamState::Closed; + } + oboeResult = Result::ErrorClosed; + break; + } + + // Update and query state change with no blocking. + aaudio_stream_state_t aaudioNextState; + result = mLibLoader->stream_waitForStateChange( + mAAudioStream, + currentAAudioState, + &aaudioNextState, + 0); // timeout=0 for non-blocking + // AAudio will return AAUDIO_ERROR_TIMEOUT if timeout=0 and the state does not change. + if (result != AAUDIO_OK && result != AAUDIO_ERROR_TIMEOUT) { + oboeResult = static_cast(result); + break; + } +#if OBOE_FIX_FORCE_STARTING_TO_STARTED + if (OboeGlobals::areWorkaroundsEnabled() + && aaudioNextState == static_cast(StreamState::Starting)) { + aaudioNextState = static_cast(StreamState::Started); + } +#endif // OBOE_FIX_FORCE_STARTING_TO_STARTED + if (nextState != nullptr) { + *nextState = static_cast(aaudioNextState); + } + if (currentAAudioState != aaudioNextState) { // state changed? + oboeResult = Result::OK; + break; + } + + // Did we timeout or did user ask for non-blocking? + if (timeLeftNanos <= 0) { + break; + } + + // No change yet so sleep. + mLock.unlock(); // Don't sleep while locked. + if (sleepTimeNanos > timeLeftNanos) { + sleepTimeNanos = timeLeftNanos; // last little bit + } + AudioClock::sleepForNanos(sleepTimeNanos); + timeLeftNanos -= sleepTimeNanos; + mLock.lock(); + } + + mLock.unlock(); + return oboeResult; +} + +ResultWithValue AudioStreamAAudio::setBufferSizeInFrames(int32_t requestedFrames) { + + AAudioStream *stream = mAAudioStream.load(); + + if (stream != nullptr) { + int32_t adjustedFrames = requestedFrames; + if (adjustedFrames > mBufferCapacityInFrames) { + adjustedFrames = mBufferCapacityInFrames; + } + adjustedFrames = QuirksManager::getInstance().clipBufferSize(*this, adjustedFrames); + + int32_t newBufferSize = mLibLoader->stream_setBufferSize(mAAudioStream, adjustedFrames); + + // Cache the result if it's valid + if (newBufferSize > 0) mBufferSizeInFrames = newBufferSize; + + return ResultWithValue::createBasedOnSign(newBufferSize); + + } else { + return ResultWithValue(Result::ErrorClosed); + } +} + +StreamState AudioStreamAAudio::getState() const { + AAudioStream *stream = mAAudioStream.load(); + if (stream != nullptr) { + aaudio_stream_state_t aaudioState = mLibLoader->stream_getState(stream); +#if OBOE_FIX_FORCE_STARTING_TO_STARTED + if (OboeGlobals::areWorkaroundsEnabled() + && aaudioState == AAUDIO_STREAM_STATE_STARTING) { + aaudioState = AAUDIO_STREAM_STATE_STARTED; + } +#endif // OBOE_FIX_FORCE_STARTING_TO_STARTED + return static_cast(aaudioState); + } else { + return StreamState::Closed; + } +} + +int32_t AudioStreamAAudio::getBufferSizeInFrames() { + AAudioStream *stream = mAAudioStream.load(); + if (stream != nullptr) { + mBufferSizeInFrames = mLibLoader->stream_getBufferSize(stream); + } + return mBufferSizeInFrames; +} + +int32_t AudioStreamAAudio::getFramesPerBurst() { + AAudioStream *stream = mAAudioStream.load(); + if (stream != nullptr) { + mFramesPerBurst = mLibLoader->stream_getFramesPerBurst(stream); + } + return mFramesPerBurst; +} + +void AudioStreamAAudio::updateFramesRead() { + AAudioStream *stream = mAAudioStream.load(); + if (stream != nullptr) { + mFramesRead = mLibLoader->stream_getFramesRead(stream); + } +} + +void AudioStreamAAudio::updateFramesWritten() { + AAudioStream *stream = mAAudioStream.load(); + if (stream != nullptr) { + mFramesWritten = mLibLoader->stream_getFramesWritten(stream); + } +} + +ResultWithValue AudioStreamAAudio::getXRunCount() const { + AAudioStream *stream = mAAudioStream.load(); + if (stream != nullptr) { + return ResultWithValue::createBasedOnSign(mLibLoader->stream_getXRunCount(stream)); + } else { + return ResultWithValue(Result::ErrorNull); + } +} + +Result AudioStreamAAudio::getTimestamp(clockid_t clockId, + int64_t *framePosition, + int64_t *timeNanoseconds) { + AAudioStream *stream = mAAudioStream.load(); + if (stream != nullptr) { + if (getState() != StreamState::Started) { + return Result::ErrorInvalidState; + } + return static_cast(mLibLoader->stream_getTimestamp(stream, clockId, + framePosition, timeNanoseconds)); + } else { + return Result::ErrorNull; + } +} + +ResultWithValue AudioStreamAAudio::calculateLatencyMillis() { + AAudioStream *stream = mAAudioStream.load(); + if (stream == nullptr) { + return ResultWithValue(Result::ErrorClosed); + } + + // Get the time that a known audio frame was presented. + int64_t hardwareFrameIndex; + int64_t hardwareFrameHardwareTime; + auto result = getTimestamp(CLOCK_MONOTONIC, + &hardwareFrameIndex, + &hardwareFrameHardwareTime); + if (result != oboe::Result::OK) { + return ResultWithValue(static_cast(result)); + } + + // Get counter closest to the app. + bool isOutput = (getDirection() == oboe::Direction::Output); + int64_t appFrameIndex = isOutput ? getFramesWritten() : getFramesRead(); + + // Assume that the next frame will be processed at the current time + using namespace std::chrono; + int64_t appFrameAppTime = + duration_cast(steady_clock::now().time_since_epoch()).count(); + + // Calculate the number of frames between app and hardware + int64_t frameIndexDelta = appFrameIndex - hardwareFrameIndex; + + // Calculate the time which the next frame will be or was presented + int64_t frameTimeDelta = (frameIndexDelta * oboe::kNanosPerSecond) / getSampleRate(); + int64_t appFrameHardwareTime = hardwareFrameHardwareTime + frameTimeDelta; + + // The current latency is the difference in time between when the current frame is at + // the app and when it is at the hardware. + double latencyNanos = static_cast(isOutput + ? (appFrameHardwareTime - appFrameAppTime) // hardware is later + : (appFrameAppTime - appFrameHardwareTime)); // hardware is earlier + double latencyMillis = latencyNanos / kNanosPerMillisecond; + + return ResultWithValue(latencyMillis); +} + +bool AudioStreamAAudio::isMMapUsed() { + AAudioStream *stream = mAAudioStream.load(); + if (stream != nullptr) { + return mLibLoader->stream_isMMapUsed(stream); + } else { + return false; + } +} + +} // namespace oboe diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/aaudio/AudioStreamAAudio.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/aaudio/AudioStreamAAudio.h new file mode 100644 index 0000000..6267328 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/aaudio/AudioStreamAAudio.h @@ -0,0 +1,123 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_STREAM_AAUDIO_H_ +#define OBOE_STREAM_AAUDIO_H_ + +#include +#include +#include + +#include "oboe/AudioStreamBuilder.h" +#include "oboe/AudioStream.h" +#include "oboe/Definitions.h" +#include "AAudioLoader.h" + +namespace oboe { + +/** + * Implementation of OboeStream that uses AAudio. + * + * Do not create this class directly. + * Use an OboeStreamBuilder to create one. + */ +class AudioStreamAAudio : public AudioStream { +public: + AudioStreamAAudio(); + explicit AudioStreamAAudio(const AudioStreamBuilder &builder); + + virtual ~AudioStreamAAudio() = default; + + /** + * + * @return true if AAudio is supported on this device. + */ + static bool isSupported(); + + // These functions override methods in AudioStream. + // See AudioStream for documentation. + Result open() override; + Result close() override; + + Result requestStart() override; + Result requestPause() override; + Result requestFlush() override; + Result requestStop() override; + + ResultWithValue write(const void *buffer, + int32_t numFrames, + int64_t timeoutNanoseconds) override; + + ResultWithValue read(void *buffer, + int32_t numFrames, + int64_t timeoutNanoseconds) override; + + ResultWithValue setBufferSizeInFrames(int32_t requestedFrames) override; + int32_t getBufferSizeInFrames() override; + int32_t getFramesPerBurst() override; + ResultWithValue getXRunCount() const override; + bool isXRunCountSupported() const override { return true; } + + ResultWithValue calculateLatencyMillis() override; + + Result waitForStateChange(StreamState currentState, + StreamState *nextState, + int64_t timeoutNanoseconds) override; + + Result getTimestamp(clockid_t clockId, + int64_t *framePosition, + int64_t *timeNanoseconds) override; + + StreamState getState() const override; + + AudioApi getAudioApi() const override { + return AudioApi::AAudio; + } + + DataCallbackResult callOnAudioReady(AAudioStream *stream, + void *audioData, + int32_t numFrames); + + bool isMMapUsed(); + +protected: + static void internalErrorCallback( + AAudioStream *stream, + void *userData, + aaudio_result_t error); + + void *getUnderlyingStream() const override { + return mAAudioStream.load(); + } + + void updateFramesRead() override; + void updateFramesWritten() override; + + void logUnsupportedAttributes(); + +private: + + std::atomic mCallbackThreadEnabled; + + // pointer to the underlying AAudio stream, valid if open, null if closed + std::atomic mAAudioStream{nullptr}; + + static AAudioLoader *mLibLoader; +}; + +} // namespace oboe + +#endif // OBOE_STREAM_AAUDIO_H_ diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/AudioClock.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/AudioClock.h new file mode 100644 index 0000000..3fe20cb --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/AudioClock.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_AUDIO_CLOCK_H +#define OBOE_AUDIO_CLOCK_H + +#include +#include +#include "oboe/Definitions.h" + +namespace oboe { + +// TODO: Move this class into the public headers because it is useful when calculating stream latency +class AudioClock { +public: + static int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) { + struct timespec time; + int result = clock_gettime(clockId, &time); + if (result < 0) { + return result; + } + return (time.tv_sec * kNanosPerSecond) + time.tv_nsec; + } + + /** + * Sleep until the specified time. + * + * @param nanoTime time to wake up + * @param clockId CLOCK_MONOTONIC is default + * @return 0 or a negative error, eg. -EINTR + */ + + static int sleepUntilNanoTime(int64_t nanoTime, clockid_t clockId = CLOCK_MONOTONIC) { + struct timespec time; + time.tv_sec = nanoTime / kNanosPerSecond; + time.tv_nsec = nanoTime - (time.tv_sec * kNanosPerSecond); + return 0 - clock_nanosleep(clockId, TIMER_ABSTIME, &time, NULL); + } + + /** + * Sleep for the specified number of nanoseconds in real-time. + * Return immediately with 0 if a negative nanoseconds is specified. + * + * @param nanoseconds time to sleep + * @param clockId CLOCK_REALTIME is default + * @return 0 or a negative error, eg. -EINTR + */ + + static int sleepForNanos(int64_t nanoseconds, clockid_t clockId = CLOCK_REALTIME) { + if (nanoseconds > 0) { + struct timespec time; + time.tv_sec = nanoseconds / kNanosPerSecond; + time.tv_nsec = nanoseconds - (time.tv_sec * kNanosPerSecond); + return 0 - clock_nanosleep(clockId, 0, &time, NULL); + } + return 0; + } +}; + +} // namespace oboe + +#endif //OBOE_AUDIO_CLOCK_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/AudioSourceCaller.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/AudioSourceCaller.cpp new file mode 100644 index 0000000..0180c22 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/AudioSourceCaller.cpp @@ -0,0 +1,38 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AudioSourceCaller.h" + +using namespace oboe; +using namespace flowgraph; + +int32_t AudioSourceCaller::onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) { + oboe::AudioStreamCallback *callback = mStream->getCallback(); + int32_t result = 0; + int32_t numFrames = numBytes / mStream->getBytesPerFrame(); + if (callback != nullptr) { + DataCallbackResult callbackResult = callback->onAudioReady(mStream, buffer, numFrames); + // onAudioReady() does not return the number of bytes processed so we have to assume all. + result = (callbackResult == DataCallbackResult::Continue) + ? numBytes + : -1; + } else { + auto readResult = mStream->read(buffer, numFrames, mTimeoutNanos); + if (!readResult) return (int32_t) readResult.error(); + result = readResult.value() * mStream->getBytesPerFrame(); + } + return result; +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/AudioSourceCaller.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/AudioSourceCaller.h new file mode 100644 index 0000000..d196d41 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/AudioSourceCaller.h @@ -0,0 +1,83 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_AUDIO_SOURCE_CALLER_H +#define OBOE_AUDIO_SOURCE_CALLER_H + +#include "OboeDebug.h" +#include "oboe/Oboe.h" + +#include "flowgraph/FlowGraphNode.h" +#include "FixedBlockReader.h" + +namespace oboe { + +class AudioStreamCallback; +class AudioStream; + +/** + * For output streams that use a callback, call the application for more data. + * For input streams that do not use a callback, read from the stream. + */ +class AudioSourceCaller : public flowgraph::FlowGraphSource, public FixedBlockProcessor { +public: + AudioSourceCaller(int32_t channelCount, int32_t framesPerCallback, int32_t bytesPerSample) + : FlowGraphSource(channelCount) + , mBlockReader(*this) { + mBlockReader.open(channelCount * framesPerCallback * bytesPerSample); + } + + /** + * Set the stream to use as a source of data. + * @param stream + */ + void setStream(oboe::AudioStream *stream) { + mStream = stream; + } + + oboe::AudioStream *getStream() { + return mStream; + } + + /** + * Timeout value to use when calling audioStream->read(). + * @param timeoutNanos Zero for no timeout or time in nanoseconds. + */ + void setTimeoutNanos(int64_t timeoutNanos) { + mTimeoutNanos = timeoutNanos; + } + + int64_t getTimeoutNanos() const { + return mTimeoutNanos; + } + + /** + * Called internally for block size adaptation. + * @param buffer + * @param numBytes + * @return + */ + int32_t onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) override; + +protected: + oboe::AudioStream *mStream = nullptr; + int64_t mTimeoutNanos = 0; + + FixedBlockReader mBlockReader; +}; + +} +#endif //OBOE_AUDIO_SOURCE_CALLER_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/AudioStream.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/AudioStream.cpp new file mode 100644 index 0000000..7bcd087 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/AudioStream.cpp @@ -0,0 +1,211 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include "OboeDebug.h" +#include "AudioClock.h" +#include + +namespace oboe { + +/* + * AudioStream + */ +AudioStream::AudioStream(const AudioStreamBuilder &builder) + : AudioStreamBase(builder) { +} + +Result AudioStream::close() { + // Update local counters so they can be read after the close. + updateFramesWritten(); + updateFramesRead(); + return Result::OK; +} + +// Call this from fireDataCallback() if you want to monitor CPU scheduler. +void AudioStream::checkScheduler() { + int scheduler = sched_getscheduler(0) & ~SCHED_RESET_ON_FORK; // for current thread + if (scheduler != mPreviousScheduler) { + LOGD("AudioStream::%s() scheduler = %s", __func__, + ((scheduler == SCHED_FIFO) ? "SCHED_FIFO" : + ((scheduler == SCHED_OTHER) ? "SCHED_OTHER" : + ((scheduler == SCHED_RR) ? "SCHED_RR" : "UNKNOWN"))) + ); + mPreviousScheduler = scheduler; + } +} + +DataCallbackResult AudioStream::fireDataCallback(void *audioData, int32_t numFrames) { + if (!isDataCallbackEnabled()) { + LOGW("AudioStream::%s() called with data callback disabled!", __func__); + return DataCallbackResult::Stop; // We should not be getting called any more. + } + + DataCallbackResult result; + if (mStreamCallback == nullptr) { + result = onDefaultCallback(audioData, numFrames); + } else { + result = mStreamCallback->onAudioReady(this, audioData, numFrames); + } + // On Oreo, we might get called after returning stop. + // So block that here. + setDataCallbackEnabled(result == DataCallbackResult::Continue); + + return result; +} + +Result AudioStream::waitForStateTransition(StreamState startingState, + StreamState endingState, + int64_t timeoutNanoseconds) +{ + StreamState state; + { + std::lock_guard lock(mLock); + state = getState(); + if (state == StreamState::Closed) { + return Result::ErrorClosed; + } else if (state == StreamState::Disconnected) { + return Result::ErrorDisconnected; + } + } + + StreamState nextState = state; + // TODO Should this be a while()?! + if (state == startingState && state != endingState) { + Result result = waitForStateChange(state, &nextState, timeoutNanoseconds); + if (result != Result::OK) { + return result; + } + } + + if (nextState != endingState) { + return Result::ErrorInvalidState; + } else { + return Result::OK; + } +} + +Result AudioStream::start(int64_t timeoutNanoseconds) +{ + Result result = requestStart(); + if (result != Result::OK) return result; + if (timeoutNanoseconds <= 0) return result; + return waitForStateTransition(StreamState::Starting, + StreamState::Started, timeoutNanoseconds); +} + +Result AudioStream::pause(int64_t timeoutNanoseconds) +{ + Result result = requestPause(); + if (result != Result::OK) return result; + if (timeoutNanoseconds <= 0) return result; + return waitForStateTransition(StreamState::Pausing, + StreamState::Paused, timeoutNanoseconds); +} + +Result AudioStream::flush(int64_t timeoutNanoseconds) +{ + Result result = requestFlush(); + if (result != Result::OK) return result; + if (timeoutNanoseconds <= 0) return result; + return waitForStateTransition(StreamState::Flushing, + StreamState::Flushed, timeoutNanoseconds); +} + +Result AudioStream::stop(int64_t timeoutNanoseconds) +{ + Result result = requestStop(); + if (result != Result::OK) return result; + if (timeoutNanoseconds <= 0) return result; + return waitForStateTransition(StreamState::Stopping, + StreamState::Stopped, timeoutNanoseconds); +} + +int32_t AudioStream::getBytesPerSample() const { + return convertFormatToSizeInBytes(mFormat); +} + +int64_t AudioStream::getFramesRead() { + updateFramesRead(); + return mFramesRead; +} + +int64_t AudioStream::getFramesWritten() { + updateFramesWritten(); + return mFramesWritten; +} + +ResultWithValue AudioStream::getAvailableFrames() { + int64_t readCounter = getFramesRead(); + if (readCounter < 0) return ResultWithValue::createBasedOnSign(readCounter); + int64_t writeCounter = getFramesWritten(); + if (writeCounter < 0) return ResultWithValue::createBasedOnSign(writeCounter); + int32_t framesAvailable = writeCounter - readCounter; + return ResultWithValue(framesAvailable); +} + +ResultWithValue AudioStream::waitForAvailableFrames(int32_t numFrames, + int64_t timeoutNanoseconds) { + if (numFrames == 0) return Result::OK; + if (numFrames < 0) return Result::ErrorOutOfRange; + + int64_t framesAvailable = 0; + int64_t burstInNanos = getFramesPerBurst() * kNanosPerSecond / getSampleRate(); + bool ready = false; + int64_t deadline = AudioClock::getNanoseconds() + timeoutNanoseconds; + do { + ResultWithValue result = getAvailableFrames(); + if (!result) return result; + framesAvailable = result.value(); + ready = (framesAvailable >= numFrames); + if (!ready) { + int64_t now = AudioClock::getNanoseconds(); + if (now > deadline) break; + AudioClock::sleepForNanos(burstInNanos); + } + } while (!ready); + return (!ready) + ? ResultWithValue(Result::ErrorTimeout) + : ResultWithValue(framesAvailable); +} + +ResultWithValue AudioStream::getTimestamp(clockid_t clockId) { + FrameTimestamp frame; + Result result = getTimestamp(clockId, &frame.position, &frame.timestamp); + if (result == Result::OK){ + return ResultWithValue(frame); + } else { + return ResultWithValue(static_cast(result)); + } +} + +static void oboe_stop_thread_proc(AudioStream *oboeStream) { + if (oboeStream != nullptr) { + oboeStream->requestStop(); + } +} + +void AudioStream::launchStopThread() { + // Stop this stream on a separate thread + std::thread t(oboe_stop_thread_proc, this); + t.detach(); +} + +} // namespace oboe diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/AudioStreamBuilder.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/AudioStreamBuilder.cpp new file mode 100644 index 0000000..9f1e31b --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/AudioStreamBuilder.cpp @@ -0,0 +1,201 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "aaudio/AudioStreamAAudio.h" +#include "FilterAudioStream.h" +#include "OboeDebug.h" +#include "oboe/Oboe.h" +#include "oboe/AudioStreamBuilder.h" +#include "opensles/AudioInputStreamOpenSLES.h" +#include "opensles/AudioOutputStreamOpenSLES.h" +#include "opensles/AudioStreamOpenSLES.h" +#include "QuirksManager.h" + +bool oboe::OboeGlobals::mWorkaroundsEnabled = true; + +namespace oboe { + +/** + * The following default values are used when oboe does not have any better way of determining the optimal values + * for an audio stream. This can happen when: + * + * - Client is creating a stream on API < 26 (OpenSLES) but has not supplied the optimal sample + * rate and/or frames per burst + * - Client is creating a stream on API 16 (OpenSLES) where AudioManager.PROPERTY_OUTPUT_* values + * are not available + */ +int32_t DefaultStreamValues::SampleRate = 48000; // Common rate for mobile audio and video +int32_t DefaultStreamValues::FramesPerBurst = 192; // 4 msec at 48000 Hz +int32_t DefaultStreamValues::ChannelCount = 2; // Stereo + +constexpr int kBufferSizeInBurstsForLowLatencyStreams = 2; + +#ifndef OBOE_ENABLE_AAUDIO +// Set OBOE_ENABLE_AAUDIO to 0 if you want to disable the AAudio API. +// This might be useful if you want to force all the unit tests to use OpenSL ES. +#define OBOE_ENABLE_AAUDIO 1 +#endif + +bool AudioStreamBuilder::isAAudioSupported() { + return AudioStreamAAudio::isSupported() && OBOE_ENABLE_AAUDIO; +} + +bool AudioStreamBuilder::isAAudioRecommended() { + // See https://github.com/google/oboe/issues/40, + // AAudio may not be stable on Android O, depending on how it is used. + // To be safe, use AAudio only on O_MR1 and above. + return (getSdkVersion() >= __ANDROID_API_O_MR1__) && isAAudioSupported(); +} + +AudioStream *AudioStreamBuilder::build() { + AudioStream *stream = nullptr; + if (isAAudioRecommended() && mAudioApi != AudioApi::OpenSLES) { + stream = new AudioStreamAAudio(*this); + } else if (isAAudioSupported() && mAudioApi == AudioApi::AAudio) { + stream = new AudioStreamAAudio(*this); + LOGE("Creating AAudio stream on 8.0 because it was specified. This is error prone."); + } else { + if (getDirection() == oboe::Direction::Output) { + stream = new AudioOutputStreamOpenSLES(*this); + } else if (getDirection() == oboe::Direction::Input) { + stream = new AudioInputStreamOpenSLES(*this); + } + } + return stream; +} + +bool AudioStreamBuilder::isCompatible(AudioStreamBase &other) { + return getSampleRate() == other.getSampleRate() + && getFormat() == other.getFormat() + && getChannelCount() == other.getChannelCount(); +} + +Result AudioStreamBuilder::openStream(AudioStream **streamPP) { + Result result = Result::OK; + LOGI("%s() %s -------- %s --------", + __func__, getDirection() == Direction::Input ? "INPUT" : "OUTPUT", getVersionText()); + + if (streamPP == nullptr) { + return Result::ErrorNull; + } + *streamPP = nullptr; + + AudioStream *streamP = nullptr; + + // Maybe make a FilterInputStream. + AudioStreamBuilder childBuilder(*this); + // Check need for conversion and modify childBuilder for optimal stream. + bool conversionNeeded = QuirksManager::getInstance().isConversionNeeded(*this, childBuilder); + // Do we need to make a child stream and convert. + if (conversionNeeded) { + AudioStream *tempStream; + + result = childBuilder.openStream(&tempStream); + if (result != Result::OK) { + return result; + } + + if (isCompatible(*tempStream)) { + // Everything matches so we can just use the child stream directly. + *streamPP = tempStream; + return result; + } else { + AudioStreamBuilder parentBuilder = *this; + // Build a stream that is as close as possible to the childStream. + if (getFormat() == oboe::AudioFormat::Unspecified) { + parentBuilder.setFormat(tempStream->getFormat()); + } + if (getChannelCount() == oboe::Unspecified) { + parentBuilder.setChannelCount(tempStream->getChannelCount()); + } + if (getSampleRate() == oboe::Unspecified) { + parentBuilder.setSampleRate(tempStream->getSampleRate()); + } + + // Use childStream in a FilterAudioStream. + LOGI("%s() create a FilterAudioStream for data conversion.", __func__); + FilterAudioStream *filterStream = new FilterAudioStream(parentBuilder, tempStream); + result = filterStream->configureFlowGraph(); + if (result != Result::OK) { + filterStream->close(); + delete filterStream; + // Just open streamP the old way. + } else { + streamP = static_cast(filterStream); + } + } + } + + if (streamP == nullptr) { + streamP = build(); + if (streamP == nullptr) { + return Result::ErrorNull; + } + } + + result = streamP->open(); // TODO review API + if (result == Result::OK) { + + int32_t optimalBufferSize = -1; + // Use a reasonable default buffer size. + if (streamP->getDirection() == Direction::Input) { + // For input, small size does not improve latency because the stream is usually + // run close to empty. And a low size can result in XRuns so always use the maximum. + optimalBufferSize = streamP->getBufferCapacityInFrames(); + } else if (streamP->getPerformanceMode() == PerformanceMode::LowLatency + && streamP->getDirection() == Direction::Output) { // Output check is redundant. + optimalBufferSize = streamP->getFramesPerBurst() * + kBufferSizeInBurstsForLowLatencyStreams; + } + if (optimalBufferSize >= 0) { + auto setBufferResult = streamP->setBufferSizeInFrames(optimalBufferSize); + if (!setBufferResult) { + LOGW("Failed to setBufferSizeInFrames(%d). Error was %s", + optimalBufferSize, + convertToText(setBufferResult.error())); + } + } + + *streamPP = streamP; + } else { + delete streamP; + } + return result; +} + +Result AudioStreamBuilder::openManagedStream(oboe::ManagedStream &stream) { + stream.reset(); + AudioStream *streamptr; + auto result = openStream(&streamptr); + stream.reset(streamptr); + return result; +} + +Result AudioStreamBuilder::openStream(std::shared_ptr &sharedStream) { + sharedStream.reset(); + AudioStream *streamptr; + auto result = openStream(&streamptr); + if (result == Result::OK) { + sharedStream.reset(streamptr); + // Save a weak_ptr in the stream for use with callbacks. + streamptr->setWeakThis(sharedStream); + } + return result; +} + +} // namespace oboe diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/DataConversionFlowGraph.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/DataConversionFlowGraph.cpp new file mode 100644 index 0000000..c15e92d --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/DataConversionFlowGraph.cpp @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "OboeDebug.h" +#include "DataConversionFlowGraph.h" +#include "SourceFloatCaller.h" +#include "SourceI16Caller.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace oboe; +using namespace flowgraph; +using namespace resampler; + +void DataConversionFlowGraph::setSource(const void *buffer, int32_t numFrames) { + mSource->setData(buffer, numFrames); +} + +static MultiChannelResampler::Quality convertOboeSRQualityToMCR(SampleRateConversionQuality quality) { + switch (quality) { + case SampleRateConversionQuality::Fastest: + return MultiChannelResampler::Quality::Fastest; + case SampleRateConversionQuality::Low: + return MultiChannelResampler::Quality::Low; + default: + case SampleRateConversionQuality::Medium: + return MultiChannelResampler::Quality::Medium; + case SampleRateConversionQuality::High: + return MultiChannelResampler::Quality::High; + case SampleRateConversionQuality::Best: + return MultiChannelResampler::Quality::Best; + } +} + +// Chain together multiple processors. +// Callback Output +// Use SourceCaller that calls original app callback from the flowgraph. +// The child callback from FilteredAudioStream read()s from the flowgraph. +// Callback Input +// Child callback from FilteredAudioStream writes()s to the flowgraph. +// The output of the flowgraph goes through a BlockWriter to the app callback. +// Blocking Write +// Write buffer is set on an AudioSource. +// Data is pulled through the graph and written to the child stream. +// Blocking Read +// Reads in a loop from the flowgraph Sink to fill the read buffer. +// A SourceCaller then does a blocking read from the child Stream. +// +Result DataConversionFlowGraph::configure(AudioStream *sourceStream, AudioStream *sinkStream) { + + FlowGraphPortFloatOutput *lastOutput = nullptr; + + bool isOutput = sourceStream->getDirection() == Direction::Output; + bool isInput = !isOutput; + mFilterStream = isOutput ? sourceStream : sinkStream; + + AudioFormat sourceFormat = sourceStream->getFormat(); + int32_t sourceChannelCount = sourceStream->getChannelCount(); + int32_t sourceSampleRate = sourceStream->getSampleRate(); + + AudioFormat sinkFormat = sinkStream->getFormat(); + int32_t sinkChannelCount = sinkStream->getChannelCount(); + int32_t sinkSampleRate = sinkStream->getSampleRate(); + + LOGI("%s() flowgraph converts channels: %d to %d, format: %d to %d, rate: %d to %d, qual = %d", + __func__, + sourceChannelCount, sinkChannelCount, + sourceFormat, sinkFormat, + sourceSampleRate, sinkSampleRate, + sourceStream->getSampleRateConversionQuality()); + + int32_t framesPerCallback = (sourceStream->getFramesPerCallback() == kUnspecified) + ? sourceStream->getFramesPerBurst() + : sourceStream->getFramesPerCallback(); + // Source + // If OUTPUT and using a callback then call back to the app using a SourceCaller. + // If INPUT and NOT using a callback then read from the child stream using a SourceCaller. + if ((sourceStream->getCallback() != nullptr && isOutput) + || (sourceStream->getCallback() == nullptr && isInput)) { + switch (sourceFormat) { + case AudioFormat::Float: + mSourceCaller = std::make_unique(sourceChannelCount, + framesPerCallback); + break; + case AudioFormat::I16: + mSourceCaller = std::make_unique(sourceChannelCount, + framesPerCallback); + break; + default: + LOGE("%s() Unsupported source caller format = %d", __func__, sourceFormat); + return Result::ErrorIllegalArgument; + } + mSourceCaller->setStream(sourceStream); + lastOutput = &mSourceCaller->output; + } else { + // If OUTPUT and NOT using a callback then write to the child stream using a BlockWriter. + // If INPUT and using a callback then write to the app using a BlockWriter. + switch (sourceFormat) { + case AudioFormat::Float: + mSource = std::make_unique(sourceChannelCount); + break; + case AudioFormat::I16: + mSource = std::make_unique(sourceChannelCount); + break; + default: + LOGE("%s() Unsupported source format = %d", __func__, sourceFormat); + return Result::ErrorIllegalArgument; + } + if (isInput) { + // The BlockWriter is after the Sink so use the SinkStream size. + mBlockWriter.open(framesPerCallback * sinkStream->getBytesPerFrame()); + mAppBuffer = std::make_unique( + kDefaultBufferSize * sinkStream->getBytesPerFrame()); + } + lastOutput = &mSource->output; + } + + // Sample Rate conversion + if (sourceSampleRate != sinkSampleRate) { + mResampler.reset(MultiChannelResampler::make(sourceChannelCount, + sourceSampleRate, + sinkSampleRate, + convertOboeSRQualityToMCR( + sourceStream->getSampleRateConversionQuality()))); + mRateConverter = std::make_unique(sourceChannelCount, + *mResampler.get()); + lastOutput->connect(&mRateConverter->input); + lastOutput = &mRateConverter->output; + } + + // Expand the number of channels if required. + if (sourceChannelCount == 1 && sinkChannelCount > 1) { + mChannelConverter = std::make_unique(sinkChannelCount); + lastOutput->connect(&mChannelConverter->input); + lastOutput = &mChannelConverter->output; + } else if (sourceChannelCount != sinkChannelCount) { + LOGW("%s() Channel reduction not supported.", __func__); + return Result::ErrorUnimplemented; // TODO + } + + // Sink + switch (sinkFormat) { + case AudioFormat::Float: + mSink = std::make_unique(sinkChannelCount); + break; + case AudioFormat::I16: + mSink = std::make_unique(sinkChannelCount); + break; + default: + LOGE("%s() Unsupported sink format = %d", __func__, sinkFormat); + return Result::ErrorIllegalArgument;; + } + lastOutput->connect(&mSink->input); + + mFramePosition = 0; + + return Result::OK; +} + +int32_t DataConversionFlowGraph::read(void *buffer, int32_t numFrames, int64_t timeoutNanos) { + if (mSourceCaller) { + mSourceCaller->setTimeoutNanos(timeoutNanos); + } + int32_t numRead = mSink->read(mFramePosition, buffer, numFrames); + mFramePosition += numRead; + return numRead; +} + +// This is similar to pushing data through the flowgraph. +int32_t DataConversionFlowGraph::write(void *inputBuffer, int32_t numFrames) { + // Put the data from the input at the head of the flowgraph. + mSource->setData(inputBuffer, numFrames); + while (true) { + // Pull and read some data in app format into a small buffer. + int32_t framesRead = mSink->read(mFramePosition, mAppBuffer.get(), flowgraph::kDefaultBufferSize); + mFramePosition += framesRead; + if (framesRead <= 0) break; + // Write to a block adapter, which will call the destination whenever it has enough data. + int32_t bytesRead = mBlockWriter.write(mAppBuffer.get(), + framesRead * mFilterStream->getBytesPerFrame()); + if (bytesRead < 0) return bytesRead; // TODO review + } + return numFrames; +} + +int32_t DataConversionFlowGraph::onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) { + int32_t numFrames = numBytes / mFilterStream->getBytesPerFrame(); + mCallbackResult = mFilterStream->getCallback()->onAudioReady(mFilterStream, buffer, numFrames); + // TODO handle STOP from callback, process data remaining in the block adapter + return numBytes; +} \ No newline at end of file diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/DataConversionFlowGraph.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/DataConversionFlowGraph.h new file mode 100644 index 0000000..b1d5ebe --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/DataConversionFlowGraph.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_OBOE_FLOW_GRAPH_H +#define OBOE_OBOE_FLOW_GRAPH_H + +#include +#include +#include + +#include +#include +#include +#include "AudioSourceCaller.h" +#include "FixedBlockWriter.h" + +namespace oboe { + +class AudioStream; +class AudioSourceCaller; + +/** + * Convert PCM channels, format and sample rate for optimal latency. + */ +class DataConversionFlowGraph : public FixedBlockProcessor { +public: + + DataConversionFlowGraph() + : mBlockWriter(*this) {} + + void setSource(const void *buffer, int32_t numFrames); + + /** Connect several modules together to convert from source to sink. + * This should only be called once for each instance. + * + * @param sourceFormat + * @param sourceChannelCount + * @param sinkFormat + * @param sinkChannelCount + * @return + */ + oboe::Result configure(oboe::AudioStream *sourceStream, oboe::AudioStream *sinkStream); + + int32_t read(void *buffer, int32_t numFrames, int64_t timeoutNanos); + + int32_t write(void *buffer, int32_t numFrames); + + int32_t onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) override; + + DataCallbackResult getDataCallbackResult() { + return mCallbackResult; + } + +private: + std::unique_ptr mSource; + std::unique_ptr mSourceCaller; + std::unique_ptr mChannelConverter; + std::unique_ptr mResampler; + std::unique_ptr mRateConverter; + std::unique_ptr mSink; + + FixedBlockWriter mBlockWriter; + DataCallbackResult mCallbackResult = DataCallbackResult::Continue; + AudioStream *mFilterStream = nullptr; + std::unique_ptr mAppBuffer; + + int64_t mFramePosition = 0; +}; + +} +#endif //OBOE_OBOE_FLOW_GRAPH_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FilterAudioStream.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FilterAudioStream.cpp new file mode 100644 index 0000000..a471583 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FilterAudioStream.cpp @@ -0,0 +1,92 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "FilterAudioStream.h" + +using namespace oboe; +using namespace flowgraph; + +// Output callback uses FixedBlockReader::read() +// <= SourceFloatCaller::onProcess() +// <=== DataConversionFlowGraph::read() +// <== FilterAudioStream::onAudioReady() +// +// Output blocking uses no block adapter because AAudio can accept +// writes of any size. It uses DataConversionFlowGraph::read() <== FilterAudioStream::write() <= app +// +// Input callback uses FixedBlockWriter::write() +// <= DataConversionFlowGraph::write() +// <= FilterAudioStream::onAudioReady() +// +// Input blocking uses FixedBlockReader::read() // TODO may not need block adapter +// <= SourceFloatCaller::onProcess() +// <=== SinkFloat::read() +// <= DataConversionFlowGraph::read() +// <== FilterAudioStream::read() +// <= app + +Result FilterAudioStream::configureFlowGraph() { + mFlowGraph = std::make_unique(); + bool isOutput = getDirection() == Direction::Output; + + AudioStream *sourceStream = isOutput ? this : mChildStream.get(); + AudioStream *sinkStream = isOutput ? mChildStream.get() : this; + + mRateScaler = ((double) sourceStream->getSampleRate()) / sinkStream->getSampleRate(); + + return mFlowGraph->configure(sourceStream, sinkStream); +} + +// Put the data to be written at the source end of the flowgraph. +// Then read (pull) the data from the flowgraph and write it to the +// child stream. +ResultWithValue FilterAudioStream::write(const void *buffer, + int32_t numFrames, + int64_t timeoutNanoseconds) { + int32_t framesWritten = 0; + mFlowGraph->setSource(buffer, numFrames); + while (true) { + int32_t numRead = mFlowGraph->read(mBlockingBuffer.get(), + getFramesPerBurst(), + timeoutNanoseconds); + if (numRead < 0) { + return ResultWithValue::createBasedOnSign(numRead); + } + if (numRead == 0) { + break; // finished processing the source buffer + } + auto writeResult = mChildStream->write(mBlockingBuffer.get(), + numRead, + timeoutNanoseconds); + if (!writeResult) { + return writeResult; + } + framesWritten += writeResult.value(); + } + return ResultWithValue::createBasedOnSign(framesWritten); +} + +// Read (pull) the data we want from the sink end of the flowgraph. +// The necessary data will be read from the child stream using a flowgraph callback. +ResultWithValue FilterAudioStream::read(void *buffer, + int32_t numFrames, + int64_t timeoutNanoseconds) { + int32_t framesRead = mFlowGraph->read(buffer, numFrames, timeoutNanoseconds); + return ResultWithValue::createBasedOnSign(framesRead); +} + diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FilterAudioStream.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FilterAudioStream.h new file mode 100644 index 0000000..3949de7 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FilterAudioStream.h @@ -0,0 +1,214 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_FILTER_AUDIO_STREAM_H +#define OBOE_FILTER_AUDIO_STREAM_H + +#include +#include +#include "DataConversionFlowGraph.h" + +namespace oboe { + +/** + * An AudioStream that wraps another AudioStream and provides audio data conversion. + * Operations may include channel conversion, data format conversion and/or sample rate conversion. + */ +class FilterAudioStream : public AudioStream, AudioStreamCallback { +public: + + /** + * Construct an `AudioStream` using the given `AudioStreamBuilder` and a child AudioStream. + * + * This should only be called internally by AudioStreamBuilder. + * Ownership of childStream will be passed to this object. + * + * @param builder containing all the stream's attributes + */ + FilterAudioStream(const AudioStreamBuilder &builder, AudioStream *childStream) + : AudioStream(builder) + , mChildStream(childStream) { + // Intercept the callback if used. + if (builder.getCallback() != nullptr) { + mStreamCallback = mChildStream->swapCallback(this); + } else { + const int size = childStream->getFramesPerBurst() * childStream->getBytesPerFrame(); + mBlockingBuffer = std::make_unique(size); + } + + // Copy parameters that may not match builder. + mBufferCapacityInFrames = mChildStream->getBufferCapacityInFrames(); + mPerformanceMode = mChildStream->getPerformanceMode(); + } + + virtual ~FilterAudioStream() = default; + + AudioStream *getChildStream() const { + return mChildStream.get(); + } + + Result configureFlowGraph(); + + // Close child and parent. + Result close() override { + const Result result1 = mChildStream->close(); + const Result result2 = AudioStream::close(); + return (result1 != Result::OK ? result1 : result2); + } + + /** + * Start the stream asynchronously. Returns immediately (does not block). Equivalent to calling + * `start(0)`. + */ + Result requestStart() override { + return mChildStream->requestStart(); + } + + /** + * Pause the stream asynchronously. Returns immediately (does not block). Equivalent to calling + * `pause(0)`. + */ + Result requestPause() override { + return mChildStream->requestPause(); + } + + /** + * Flush the stream asynchronously. Returns immediately (does not block). Equivalent to calling + * `flush(0)`. + */ + Result requestFlush() override { + return mChildStream->requestFlush(); + } + + /** + * Stop the stream asynchronously. Returns immediately (does not block). Equivalent to calling + * `stop(0)`. + */ + Result requestStop() override { + return mChildStream->requestStop(); + } + + ResultWithValue read(void *buffer, + int32_t numFrames, + int64_t timeoutNanoseconds) override; + + ResultWithValue write(const void *buffer, + int32_t numFrames, + int64_t timeoutNanoseconds) override; + + StreamState getState() const override { + return mChildStream->getState(); + } + + Result waitForStateChange( + StreamState inputState, + StreamState *nextState, + int64_t timeoutNanoseconds) override { + return mChildStream->waitForStateChange(inputState, nextState, timeoutNanoseconds); + } + + bool isXRunCountSupported() const override { + return mChildStream->isXRunCountSupported(); + } + + int32_t getFramesPerBurst() override { + return mChildStream->getFramesPerBurst(); + } + + AudioApi getAudioApi() const override { + return mChildStream->getAudioApi(); + } + + void updateFramesWritten() override { + // TODO for output, just count local writes? + mFramesWritten = static_cast(mChildStream->getFramesWritten() * mRateScaler); + } + + void updateFramesRead() override { + // TODO for input, just count local reads? + mFramesRead = static_cast(mChildStream->getFramesRead() * mRateScaler); + } + + void *getUnderlyingStream() const override { + return mChildStream->getUnderlyingStream(); + } + + ResultWithValue setBufferSizeInFrames(int32_t requestedFrames) override { + return mChildStream->setBufferSizeInFrames(requestedFrames); + } + + int32_t getBufferSizeInFrames() override { + mBufferSizeInFrames = mChildStream->getBufferSizeInFrames(); + return mBufferSizeInFrames; + } + + ResultWithValue getXRunCount() const override { + return mChildStream->getXRunCount(); + } + + ResultWithValue calculateLatencyMillis() override { + // This will automatically include the latency of the flowgraph? + return mChildStream->calculateLatencyMillis(); + } + + Result getTimestamp(clockid_t clockId, + int64_t *framePosition, + int64_t *timeNanoseconds) override { + int64_t childPosition = 0; + Result result = mChildStream->getTimestamp(clockId, &childPosition, timeNanoseconds); + *framePosition = childPosition * mRateScaler; + return result; + } + + DataCallbackResult onAudioReady(AudioStream *oboeStream, + void *audioData, + int32_t numFrames) override { + int32_t framesProcessed; + if (oboeStream->getDirection() == Direction::Output) { + framesProcessed = mFlowGraph->read(audioData, numFrames, 0 /* timeout */); + } else { + framesProcessed = mFlowGraph->write(audioData, numFrames); + } + return (framesProcessed < numFrames) + ? DataCallbackResult::Stop + : mFlowGraph->getDataCallbackResult(); + } + + void onErrorBeforeClose(AudioStream *oboeStream, Result error) override { + if (mStreamCallback != nullptr) { + mStreamCallback->onErrorBeforeClose(this, error); + } + } + + void onErrorAfterClose(AudioStream *oboeStream, Result error) override { + // Close this parent stream because the callback will only close the child. + AudioStream::close(); + if (mStreamCallback != nullptr) { + mStreamCallback->onErrorAfterClose(this, error); + } + } + +private: + + std::unique_ptr mChildStream; // this stream wraps the child stream + std::unique_ptr mFlowGraph; // for converting data + std::unique_ptr mBlockingBuffer; // temp buffer for write() + double mRateScaler = 1.0; // ratio parent/child sample rates +}; + +} // oboe + +#endif //OBOE_FILTER_AUDIO_STREAM_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockAdapter.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockAdapter.cpp new file mode 100644 index 0000000..e14c2ca --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockAdapter.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "FixedBlockAdapter.h" + +FixedBlockAdapter::~FixedBlockAdapter() { +} + +int32_t FixedBlockAdapter::open(int32_t bytesPerFixedBlock) +{ + mSize = bytesPerFixedBlock; + mStorage = std::make_unique(bytesPerFixedBlock); + mPosition = 0; + return 0; +} + +int32_t FixedBlockAdapter::close() +{ + mStorage.reset(nullptr); + mSize = 0; + mPosition = 0; + return 0; +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockAdapter.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockAdapter.h new file mode 100644 index 0000000..76e961c --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockAdapter.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AAUDIO_FIXED_BLOCK_ADAPTER_H +#define AAUDIO_FIXED_BLOCK_ADAPTER_H + +#include +#include +#include + +/** + * Interface for a class that needs fixed-size blocks. + */ +class FixedBlockProcessor { +public: + virtual ~FixedBlockProcessor() = default; + /** + * + * @param buffer Pointer to first byte of data. + * @param numBytes This will be a fixed size specified in FixedBlockAdapter::open(). + * @return Number of bytes processed or a negative error code. + */ + virtual int32_t onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) = 0; +}; + +/** + * Base class for a variable-to-fixed-size block adapter. + */ +class FixedBlockAdapter +{ +public: + FixedBlockAdapter(FixedBlockProcessor &fixedBlockProcessor) + : mFixedBlockProcessor(fixedBlockProcessor) {} + + virtual ~FixedBlockAdapter(); + + /** + * Allocate internal resources needed for buffering data. + */ + virtual int32_t open(int32_t bytesPerFixedBlock); + + /** + * Free internal resources. + */ + int32_t close(); + +protected: + FixedBlockProcessor &mFixedBlockProcessor; + std::unique_ptr mStorage; // Store data here while assembling buffers. + int32_t mSize = 0; // Size in bytes of the fixed size buffer. + int32_t mPosition = 0; // Offset of the last byte read or written. +}; + +#endif /* AAUDIO_FIXED_BLOCK_ADAPTER_H */ diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockReader.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockReader.cpp new file mode 100644 index 0000000..62e9664 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockReader.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "FixedBlockAdapter.h" + +#include "FixedBlockReader.h" + + +FixedBlockReader::FixedBlockReader(FixedBlockProcessor &fixedBlockProcessor) + : FixedBlockAdapter(fixedBlockProcessor) { + mPosition = mSize; +} + +int32_t FixedBlockReader::open(int32_t bytesPerFixedBlock) { + int32_t result = FixedBlockAdapter::open(bytesPerFixedBlock); + mPosition = 0; + mValid = 0; + return result; +} + +int32_t FixedBlockReader::readFromStorage(uint8_t *buffer, int32_t numBytes) { + int32_t bytesToRead = numBytes; + int32_t dataAvailable = mValid - mPosition; + if (bytesToRead > dataAvailable) { + bytesToRead = dataAvailable; + } + memcpy(buffer, mStorage.get() + mPosition, bytesToRead); + mPosition += bytesToRead; + return bytesToRead; +} + +int32_t FixedBlockReader::read(uint8_t *buffer, int32_t numBytes) { + int32_t bytesRead; + int32_t bytesLeft = numBytes; + while(bytesLeft > 0) { + if (mPosition < mValid) { + // Use up bytes currently in storage. + bytesRead = readFromStorage(buffer, bytesLeft); + buffer += bytesRead; + bytesLeft -= bytesRead; + } else if (bytesLeft >= mSize) { + // Nothing in storage. Read through if enough for a complete block. + bytesRead = mFixedBlockProcessor.onProcessFixedBlock(buffer, mSize); + if (bytesRead < 0) return bytesRead; + buffer += bytesRead; + bytesLeft -= bytesRead; + } else { + // Just need a partial block so we have to reload storage. + bytesRead = mFixedBlockProcessor.onProcessFixedBlock(mStorage.get(), mSize); + if (bytesRead < 0) return bytesRead; + mPosition = 0; + mValid = bytesRead; + if (bytesRead == 0) break; + } + } + return numBytes - bytesLeft; +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockReader.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockReader.h new file mode 100644 index 0000000..4cea9c8 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockReader.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AAUDIO_FIXED_BLOCK_READER_H +#define AAUDIO_FIXED_BLOCK_READER_H + +#include + +#include "FixedBlockAdapter.h" + +/** + * Read from a fixed-size block to a variable sized block. + * + * This can be used to convert a pull data flow from fixed sized buffers to variable sized buffers. + * An example would be an audio output callback that reads from the app. + */ +class FixedBlockReader : public FixedBlockAdapter +{ +public: + FixedBlockReader(FixedBlockProcessor &fixedBlockProcessor); + + virtual ~FixedBlockReader() = default; + + int32_t open(int32_t bytesPerFixedBlock) override; + + /** + * Read into a variable sized block. + * + * Note that if the fixed-sized blocks must be aligned, then the variable-sized blocks + * must have the same alignment. + * For example, if the fixed-size blocks must be a multiple of 8, then the variable-sized + * blocks must also be a multiple of 8. + * + * @param buffer + * @param numBytes + * @return Number of bytes read or a negative error code. + */ + int32_t read(uint8_t *buffer, int32_t numBytes); + +private: + int32_t readFromStorage(uint8_t *buffer, int32_t numBytes); + + int32_t mValid = 0; // Number of valid bytes in mStorage. +}; + + +#endif /* AAUDIO_FIXED_BLOCK_READER_H */ diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockWriter.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockWriter.cpp new file mode 100644 index 0000000..b315609 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockWriter.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "FixedBlockAdapter.h" +#include "FixedBlockWriter.h" + +FixedBlockWriter::FixedBlockWriter(FixedBlockProcessor &fixedBlockProcessor) + : FixedBlockAdapter(fixedBlockProcessor) {} + + +int32_t FixedBlockWriter::writeToStorage(uint8_t *buffer, int32_t numBytes) { + int32_t bytesToStore = numBytes; + int32_t roomAvailable = mSize - mPosition; + if (bytesToStore > roomAvailable) { + bytesToStore = roomAvailable; + } + memcpy(mStorage.get() + mPosition, buffer, bytesToStore); + mPosition += bytesToStore; + return bytesToStore; +} + +int32_t FixedBlockWriter::write(uint8_t *buffer, int32_t numBytes) { + int32_t bytesLeft = numBytes; + + // If we already have data in storage then add to it. + if (mPosition > 0) { + int32_t bytesWritten = writeToStorage(buffer, bytesLeft); + buffer += bytesWritten; + bytesLeft -= bytesWritten; + // If storage full then flush it out + if (mPosition == mSize) { + bytesWritten = mFixedBlockProcessor.onProcessFixedBlock(mStorage.get(), mSize); + if (bytesWritten < 0) return bytesWritten; + mPosition = 0; + if (bytesWritten < mSize) { + // Only some of the data was written! This should not happen. + return -1; + } + } + } + + // Write through if enough for a complete block. + while(bytesLeft > mSize) { + int32_t bytesWritten = mFixedBlockProcessor.onProcessFixedBlock(buffer, mSize); + if (bytesWritten < 0) return bytesWritten; + buffer += bytesWritten; + bytesLeft -= bytesWritten; + } + + // Save any remaining partial blocks for next time. + if (bytesLeft > 0) { + int32_t bytesWritten = writeToStorage(buffer, bytesLeft); + bytesLeft -= bytesWritten; + } + + return numBytes - bytesLeft; +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockWriter.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockWriter.h new file mode 100644 index 0000000..6dea6ca --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/FixedBlockWriter.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AAUDIO_FIXED_BLOCK_WRITER_H +#define AAUDIO_FIXED_BLOCK_WRITER_H + +#include + +#include "FixedBlockAdapter.h" + +/** + * This can be used to convert a push data flow from variable sized buffers to fixed sized buffers. + * An example would be an audio input callback. + */ +class FixedBlockWriter : public FixedBlockAdapter +{ +public: + FixedBlockWriter(FixedBlockProcessor &fixedBlockProcessor); + + virtual ~FixedBlockWriter() = default; + + /** + * Write from a variable sized block. + * + * Note that if the fixed-sized blocks must be aligned, then the variable-sized blocks + * must have the same alignment. + * For example, if the fixed-size blocks must be a multiple of 8, then the variable-sized + * blocks must also be a multiple of 8. + * + * @param buffer + * @param numBytes + * @return Number of bytes written or a negative error code. + */ + int32_t write(uint8_t *buffer, int32_t numBytes); + +private: + + int32_t writeToStorage(uint8_t *buffer, int32_t numBytes); +}; + +#endif /* AAUDIO_FIXED_BLOCK_WRITER_H */ diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/LatencyTuner.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/LatencyTuner.cpp new file mode 100644 index 0000000..cce8e18 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/LatencyTuner.cpp @@ -0,0 +1,102 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "oboe/LatencyTuner.h" + +using namespace oboe; + +LatencyTuner::LatencyTuner(AudioStream &stream) + : LatencyTuner(stream, stream.getBufferCapacityInFrames()){ + } + +LatencyTuner::LatencyTuner(oboe::AudioStream &stream, int32_t maximumBufferSize) + : mStream(stream) + , mMaxBufferSize(maximumBufferSize) { + reset(); +} + +Result LatencyTuner::tune() { + if (mState == State::Unsupported) { + return Result::ErrorUnimplemented; + } + + Result result = Result::OK; + + // Process reset requests. + int32_t numRequests = mLatencyTriggerRequests.load(); + if (numRequests != mLatencyTriggerResponses.load()) { + mLatencyTriggerResponses.store(numRequests); + reset(); + } + + // Set state to Active if the idle countdown has reached zero. + if (mState == State::Idle && --mIdleCountDown <= 0) { + mState = State::Active; + } + + // When state is Active attempt to change the buffer size if the number of xRuns has increased. + if (mState == State::Active) { + + auto xRunCountResult = mStream.getXRunCount(); + if (xRunCountResult == Result::OK) { + if ((xRunCountResult.value() - mPreviousXRuns) > 0) { + mPreviousXRuns = xRunCountResult.value(); + int32_t oldBufferSize = mStream.getBufferSizeInFrames(); + int32_t requestedBufferSize = oldBufferSize + mStream.getFramesPerBurst(); + + // Do not request more than the maximum buffer size (which was either user-specified + // or was from stream->getBufferCapacityInFrames()) + if (requestedBufferSize > mMaxBufferSize) requestedBufferSize = mMaxBufferSize; + + auto setBufferResult = mStream.setBufferSizeInFrames(requestedBufferSize); + if (setBufferResult != Result::OK) { + result = setBufferResult; + mState = State::Unsupported; + } else if (setBufferResult.value() == oldBufferSize) { + mState = State::AtMax; + } + } + } else { + mState = State::Unsupported; + } + } + + if (mState == State::Unsupported) { + result = Result::ErrorUnimplemented; + } + + if (mState == State::AtMax) { + result = Result::OK; + } + return result; +} + +void LatencyTuner::requestReset() { + if (mState != State::Unsupported) { + mLatencyTriggerRequests++; + } +} + +void LatencyTuner::reset() { + mState = State::Idle; + mIdleCountDown = kIdleCount; + // Set to minimal latency + mStream.setBufferSizeInFrames(2 * mStream.getFramesPerBurst()); +} + +bool LatencyTuner::isAtMaximumBufferSize() { + return mState == State::AtMax; +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/MonotonicCounter.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/MonotonicCounter.h new file mode 100644 index 0000000..00c979c --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/MonotonicCounter.h @@ -0,0 +1,112 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef COMMON_MONOTONIC_COUNTER_H +#define COMMON_MONOTONIC_COUNTER_H + +#include + +/** + * Maintain a 64-bit monotonic counter. + * Can be used to track a 32-bit counter that wraps or gets reset. + * + * Note that this is not atomic and has no interior locks. + * A caller will need to provide their own exterior locking + * if they need to use it from multiple threads. + */ +class MonotonicCounter { + +public: + MonotonicCounter() {} + virtual ~MonotonicCounter() {} + + /** + * @return current value of the counter + */ + int64_t get() const { + return mCounter64; + } + + /** + * set the current value of the counter + */ + void set(int64_t counter) { + mCounter64 = counter; + } + + /** + * Advance the counter if delta is positive. + * @return current value of the counter + */ + int64_t increment(int64_t delta) { + if (delta > 0) { + mCounter64 += delta; + } + return mCounter64; + } + + /** + * Advance the 64-bit counter if (current32 - previousCurrent32) > 0. + * This can be used to convert a 32-bit counter that may be wrapping into + * a monotonic 64-bit counter. + * + * This counter32 should NOT be allowed to advance by more than 0x7FFFFFFF between calls. + * Think of the wrapping counter like a sine wave. If the frequency of the signal + * is more than half the sampling rate (Nyquist rate) then you cannot measure it properly. + * If the counter wraps around every 24 hours then we should measure it with a period + * of less than 12 hours. + * + * @return current value of the 64-bit counter + */ + int64_t update32(int32_t counter32) { + int32_t delta = counter32 - mCounter32; + // protect against the mCounter64 going backwards + if (delta > 0) { + mCounter64 += delta; + mCounter32 = counter32; + } + return mCounter64; + } + + /** + * Reset the stored value of the 32-bit counter. + * This is used if your counter32 has been reset to zero. + */ + void reset32() { + mCounter32 = 0; + } + + /** + * Round 64-bit counter up to a multiple of the period. + * + * The period must be positive. + * + * @param period might be, for example, a buffer capacity + */ + void roundUp64(int32_t period) { + if (period > 0) { + int64_t numPeriods = (mCounter64 + period - 1) / period; + mCounter64 = numPeriods * period; + } + } + +private: + int64_t mCounter64 = 0; + int32_t mCounter32 = 0; +}; + + +#endif //COMMON_MONOTONIC_COUNTER_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/OboeDebug.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/OboeDebug.h new file mode 100644 index 0000000..dc7434c --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/OboeDebug.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef OBOE_DEBUG_H +#define OBOE_DEBUG_H + +#include + +#ifndef MODULE_NAME +#define MODULE_NAME "OboeAudio" +#endif + +// Always log INFO and errors. +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, MODULE_NAME, __VA_ARGS__) +#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, MODULE_NAME, __VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, MODULE_NAME, __VA_ARGS__) +#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL, MODULE_NAME, __VA_ARGS__) + +#if OBOE_ENABLE_LOGGING +#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, MODULE_NAME, __VA_ARGS__) +#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, MODULE_NAME, __VA_ARGS__) +#else +#define LOGV(...) +#define LOGD(...) +#endif + +#endif //OBOE_DEBUG_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/QuirksManager.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/QuirksManager.cpp new file mode 100644 index 0000000..3df1bc4 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/QuirksManager.cpp @@ -0,0 +1,138 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "QuirksManager.h" + +using namespace oboe; + +int32_t QuirksManager::DeviceQuirks::clipBufferSize(AudioStream &stream, + int32_t requestedSize) { + if (!OboeGlobals::areWorkaroundsEnabled()) { + return requestedSize; + } + int bottomMargin = kDefaultBottomMarginInBursts; + int topMargin = kDefaultTopMarginInBursts; + if (isMMapUsed(stream)) { + if (stream.getSharingMode() == SharingMode::Exclusive) { + bottomMargin = getExclusiveBottomMarginInBursts(); + topMargin = getExclusiveTopMarginInBursts(); + } + } else { + bottomMargin = kLegacyBottomMarginInBursts; + } + + int32_t burst = stream.getFramesPerBurst(); + int32_t minSize = bottomMargin * burst; + int32_t adjustedSize = requestedSize; + if (adjustedSize < minSize ) { + adjustedSize = minSize; + } else { + int32_t maxSize = stream.getBufferCapacityInFrames() - (topMargin * burst); + if (adjustedSize > maxSize ) { + adjustedSize = maxSize; + } + } + return adjustedSize; +} + +class SamsungDeviceQuirks : public QuirksManager::DeviceQuirks { +public: + SamsungDeviceQuirks() { + std::string arch = getPropertyString("ro.arch"); + isExynos = (arch.rfind("exynos", 0) == 0); // starts with? + } + + virtual ~SamsungDeviceQuirks() = default; + + int32_t getExclusiveBottomMarginInBursts() const override { + // TODO Make this conditional on build version when MMAP timing improves. + return isExynos ? kBottomMarginExynos : kBottomMarginOther; + } + + int32_t getExclusiveTopMarginInBursts() const override { + return kTopMargin; + } + +private: + // Stay farther away from DSP position on Exynos devices. + static constexpr int32_t kBottomMarginExynos = 2; + static constexpr int32_t kBottomMarginOther = 1; + static constexpr int32_t kTopMargin = 1; + bool isExynos = false; +}; + +QuirksManager::QuirksManager() { + std::string manufacturer = getPropertyString("ro.product.manufacturer"); + if (manufacturer == "samsung") { + mDeviceQuirks = std::make_unique(); + } else { + mDeviceQuirks = std::make_unique(); + } +} + +bool QuirksManager::isConversionNeeded( + const AudioStreamBuilder &builder, + AudioStreamBuilder &childBuilder) { + bool conversionNeeded = false; + const bool isLowLatency = builder.getPerformanceMode() == PerformanceMode::LowLatency; + const bool isInput = builder.getDirection() == Direction::Input; + const bool isFloat = builder.getFormat() == AudioFormat::Float; + + // If a SAMPLE RATE is specified for low latency then let the native code choose an optimal rate. + // TODO There may be a problem if the devices supports low latency + // at a higher rate than the default. + if (builder.getSampleRate() != oboe::Unspecified + && builder.getSampleRateConversionQuality() != SampleRateConversionQuality::None + && isLowLatency + ) { + childBuilder.setSampleRate(oboe::Unspecified); // native API decides the best sample rate + conversionNeeded = true; + } + + // Data Format + // OpenSL ES and AAudio before P do not support FAST path for FLOAT capture. + if (isFloat + && isInput + && builder.isFormatConversionAllowed() + && isLowLatency + && (!builder.willUseAAudio() || (getSdkVersion() < __ANDROID_API_P__)) + ) { + childBuilder.setFormat(AudioFormat::I16); // needed for FAST track + conversionNeeded = true; + } + + // Channel Count + if (builder.getChannelCount() != oboe::Unspecified + && builder.isChannelConversionAllowed()) { + if (OboeGlobals::areWorkaroundsEnabled() + && builder.getChannelCount() == 2 // stereo? + && isInput + && isLowLatency + && (!builder.willUseAAudio() && (getSdkVersion() == __ANDROID_API_O__))) { + // Workaround for heap size regression in O. + // b/66967812 AudioRecord does not allow FAST track for stereo capture in O + childBuilder.setChannelCount(1); + conversionNeeded = true; + } + // Note that MMAP does not support mono in 8.1. But that would only matter on Pixel 1 + // phones and they have almost all been updated to 9.0. + } + + return conversionNeeded; +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/QuirksManager.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/QuirksManager.h new file mode 100644 index 0000000..a177764 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/QuirksManager.h @@ -0,0 +1,110 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_QUIRKS_MANAGER_H +#define OBOE_QUIRKS_MANAGER_H + +#include +#include +#include + +namespace oboe { + +/** + * INTERNAL USE ONLY. + * + * Based on manufacturer, model and Android version number + * decide whether data conversion needs to occur. + * + * This also manages device and version specific workarounds. + */ + +class QuirksManager { +public: + + static QuirksManager &getInstance() { + static QuirksManager instance; // singleton + return instance; + } + + QuirksManager(); + virtual ~QuirksManager() = default; + + /** + * Do we need to do channel, format or rate conversion to provide a low latency + * stream for this builder? If so then provide a builder for the native child stream + * that will be used to get low latency. + * + * @param builder builder provided by application + * @param childBuilder modified builder appropriate for the underlying device + * @return true if conversion is needed + */ + bool isConversionNeeded(const AudioStreamBuilder &builder, AudioStreamBuilder &childBuilder); + + static bool isMMapUsed(AudioStream &stream) { + bool answer = false; + if (stream.getAudioApi() == AudioApi::AAudio) { + AudioStreamAAudio *streamAAudio = + reinterpret_cast(&stream); + answer = streamAAudio->isMMapUsed(); + } + return answer; + } + + virtual int32_t clipBufferSize(AudioStream &stream, int32_t bufferSize) { + return mDeviceQuirks->clipBufferSize(stream, bufferSize); + } + + class DeviceQuirks { + public: + virtual ~DeviceQuirks() = default; + + /** + * Restrict buffer size. This is mainly to avoid glitches caused by MMAP + * timestamp inaccuracies. + * @param stream + * @param requestedSize + * @return + */ + int32_t clipBufferSize(AudioStream &stream, int32_t requestedSize); + + // Exclusive MMAP streams can have glitches because they are using a timing + // model of the DSP to control IO instead of direct synchronization. + virtual int32_t getExclusiveBottomMarginInBursts() const { + return kDefaultBottomMarginInBursts; + } + + virtual int32_t getExclusiveTopMarginInBursts() const { + return kDefaultTopMarginInBursts; + } + + static constexpr int32_t kDefaultBottomMarginInBursts = 0; + static constexpr int32_t kDefaultTopMarginInBursts = 0; + + // For Legacy streams, do not let the buffer go below one burst. + // b/129545119 | AAudio Legacy allows setBufferSizeInFrames too low + // Fixed in Q + static constexpr int32_t kLegacyBottomMarginInBursts = 1; + }; + +private: + + std::unique_ptr mDeviceQuirks{}; + +}; + +} +#endif //OBOE_QUIRKS_MANAGER_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/SourceFloatCaller.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/SourceFloatCaller.cpp new file mode 100644 index 0000000..631af85 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/SourceFloatCaller.cpp @@ -0,0 +1,30 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "flowgraph/FlowGraphNode.h" +#include "SourceFloatCaller.h" + +using namespace oboe; +using namespace flowgraph; + +int32_t SourceFloatCaller::onProcess(int32_t numFrames) { + int32_t numBytes = mStream->getBytesPerFrame() * numFrames; + int32_t bytesRead = mBlockReader.read((uint8_t *) output.getBuffer(), numBytes); + int32_t framesRead = bytesRead / mStream->getBytesPerFrame(); + return framesRead; +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/SourceFloatCaller.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/SourceFloatCaller.h new file mode 100644 index 0000000..85a1585 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/SourceFloatCaller.h @@ -0,0 +1,44 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_SOURCE_FLOAT_CALLER_H +#define OBOE_SOURCE_FLOAT_CALLER_H + +#include +#include + +#include "flowgraph/FlowGraphNode.h" +#include "AudioSourceCaller.h" +#include "FixedBlockReader.h" + +namespace oboe { +/** + * AudioSource that uses callback to get more float data. + */ +class SourceFloatCaller : public AudioSourceCaller { +public: + SourceFloatCaller(int32_t channelCount, int32_t framesPerCallback) + : AudioSourceCaller(channelCount, framesPerCallback, (int32_t)sizeof(float)) {} + + int32_t onProcess(int32_t numFrames) override; + + const char *getName() override { + return "SourceFloatCaller"; + } +}; + +} +#endif //OBOE_SOURCE_FLOAT_CALLER_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/SourceI16Caller.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/SourceI16Caller.cpp new file mode 100644 index 0000000..2ab372b --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/SourceI16Caller.cpp @@ -0,0 +1,47 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "flowgraph/FlowGraphNode.h" +#include "SourceI16Caller.h" + +#if FLOWGRAPH_ANDROID_INTERNAL +#include +#endif + +using namespace oboe; +using namespace flowgraph; + +int32_t SourceI16Caller::onProcess(int32_t numFrames) { + int32_t numBytes = mStream->getBytesPerFrame() * numFrames; + int32_t bytesRead = mBlockReader.read((uint8_t *) mConversionBuffer.get(), numBytes); + int32_t framesRead = bytesRead / mStream->getBytesPerFrame(); + + float *floatData = output.getBuffer(); + const int16_t *shortData = mConversionBuffer.get(); + int32_t numSamples = framesRead * output.getSamplesPerFrame(); + +#if FLOWGRAPH_ANDROID_INTERNAL + memcpy_to_float_from_i16(floatData, shortData, numSamples); +#else + for (int i = 0; i < numSamples; i++) { + *floatData++ = *shortData++ * (1.0f / 32768); + } +#endif + + return framesRead; +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/SourceI16Caller.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/SourceI16Caller.h new file mode 100644 index 0000000..22c1b9a --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/SourceI16Caller.h @@ -0,0 +1,48 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_SOURCE_I16_CALLER_H +#define OBOE_SOURCE_I16_CALLER_H + +#include +#include + +#include "flowgraph/FlowGraphNode.h" +#include "AudioSourceCaller.h" +#include "FixedBlockReader.h" + +namespace oboe { +/** + * AudioSource that uses callback to get more data. + */ +class SourceI16Caller : public AudioSourceCaller { +public: + SourceI16Caller(int32_t channelCount, int32_t framesPerCallback) + : AudioSourceCaller(channelCount, framesPerCallback, sizeof(int16_t)) { + mConversionBuffer = std::make_unique(channelCount * output.getFramesPerBuffer()); + } + + int32_t onProcess(int32_t numFrames) override; + + const char *getName() override { + return "SourceI16Caller"; + } +private: + std::unique_ptr mConversionBuffer; +}; + +} +#endif //OBOE_SOURCE_I16_CALLER_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/StabilizedCallback.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/StabilizedCallback.cpp new file mode 100644 index 0000000..692db89 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/StabilizedCallback.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "oboe/StabilizedCallback.h" +#include "common/AudioClock.h" +#include "common/Trace.h" + +constexpr int32_t kLoadGenerationStepSizeNanos = 20000; +constexpr float kPercentageOfCallbackToUse = 0.8; + +using namespace oboe; + +StabilizedCallback::StabilizedCallback(AudioStreamCallback *callback) : mCallback(callback){ + Trace::initialize(); +} + +/** + * An audio callback which attempts to do work for a fixed amount of time. + * + * @param oboeStream + * @param audioData + * @param numFrames + * @return + */ +DataCallbackResult +StabilizedCallback::onAudioReady(AudioStream *oboeStream, void *audioData, int32_t numFrames) { + + int64_t startTimeNanos = AudioClock::getNanoseconds(); + + if (mFrameCount == 0){ + mEpochTimeNanos = startTimeNanos; + } + + int64_t durationSinceEpochNanos = startTimeNanos - mEpochTimeNanos; + + // In an ideal world the callback start time will be exactly the same as the duration of the + // frames already read/written into the stream. In reality the callback can start early + // or late. By finding the delta we can calculate the target duration for our stabilized + // callback. + int64_t idealStartTimeNanos = (mFrameCount * kNanosPerSecond) / oboeStream->getSampleRate(); + int64_t lateStartNanos = durationSinceEpochNanos - idealStartTimeNanos; + + if (lateStartNanos < 0){ + // This was an early start which indicates that our previous epoch was a late callback. + // Update our epoch to this more accurate time. + mEpochTimeNanos = startTimeNanos; + mFrameCount = 0; + } + + int64_t numFramesAsNanos = (numFrames * kNanosPerSecond) / oboeStream->getSampleRate(); + int64_t targetDurationNanos = static_cast( + (numFramesAsNanos * kPercentageOfCallbackToUse) - lateStartNanos); + + Trace::beginSection("Actual load"); + DataCallbackResult result = mCallback->onAudioReady(oboeStream, audioData, numFrames); + Trace::endSection(); + + int64_t executionDurationNanos = AudioClock::getNanoseconds() - startTimeNanos; + int64_t stabilizingLoadDurationNanos = targetDurationNanos - executionDurationNanos; + + Trace::beginSection("Stabilized load for %lldns", stabilizingLoadDurationNanos); + generateLoad(stabilizingLoadDurationNanos); + Trace::endSection(); + + // Wraparound: At 48000 frames per second mFrameCount wraparound will occur after 6m years, + // significantly longer than the average lifetime of an Android phone. + mFrameCount += numFrames; + return result; +} + +void StabilizedCallback::generateLoad(int64_t durationNanos) { + + int64_t currentTimeNanos = AudioClock::getNanoseconds(); + int64_t deadlineTimeNanos = currentTimeNanos + durationNanos; + + // opsPerStep gives us an estimated number of operations which need to be run to fully utilize + // the CPU for a fixed amount of time (specified by kLoadGenerationStepSizeNanos). + // After each step the opsPerStep value is re-calculated based on the actual time taken to + // execute those operations. + auto opsPerStep = (int)(mOpsPerNano * kLoadGenerationStepSizeNanos); + int64_t stepDurationNanos = 0; + int64_t previousTimeNanos = 0; + + while (currentTimeNanos <= deadlineTimeNanos){ + + for (int i = 0; i < opsPerStep; i++) cpu_relax(); + + previousTimeNanos = currentTimeNanos; + currentTimeNanos = AudioClock::getNanoseconds(); + stepDurationNanos = currentTimeNanos - previousTimeNanos; + + // Calculate exponential moving average to smooth out values, this acts as a low pass filter. + // @see https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average + static const float kFilterCoefficient = 0.1; + auto measuredOpsPerNano = (double) opsPerStep / stepDurationNanos; + mOpsPerNano = kFilterCoefficient * measuredOpsPerNano + (1.0 - kFilterCoefficient) * mOpsPerNano; + opsPerStep = (int) (mOpsPerNano * kLoadGenerationStepSizeNanos); + } +} \ No newline at end of file diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/Trace.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/Trace.cpp new file mode 100644 index 0000000..5ed445b --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/Trace.cpp @@ -0,0 +1,75 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "Trace.h" +#include "OboeDebug.h" + +static char buffer[256]; + +// Tracing functions +static void *(*ATrace_beginSection)(const char *sectionName); + +static void *(*ATrace_endSection)(); + +typedef void *(*fp_ATrace_beginSection)(const char *sectionName); + +typedef void *(*fp_ATrace_endSection)(); + +bool Trace::mIsTracingSupported = false; + +void Trace::beginSection(const char *format, ...){ + + if (mIsTracingSupported) { + va_list va; + va_start(va, format); + vsprintf(buffer, format, va); + ATrace_beginSection(buffer); + va_end(va); + } else { + LOGE("Tracing is either not initialized (call Trace::initialize()) " + "or not supported on this device"); + } +} + +void Trace::endSection() { + + if (mIsTracingSupported) { + ATrace_endSection(); + } +} + +void Trace::initialize() { + + // Using dlsym allows us to use tracing on API 21+ without needing android/trace.h which wasn't + // published until API 23 + void *lib = dlopen("libandroid.so", RTLD_NOW | RTLD_LOCAL); + if (lib == nullptr) { + LOGE("Could not open libandroid.so to dynamically load tracing symbols"); + } else { + ATrace_beginSection = + reinterpret_cast( + dlsym(lib, "ATrace_beginSection")); + ATrace_endSection = + reinterpret_cast( + dlsym(lib, "ATrace_endSection")); + + if (ATrace_beginSection != nullptr && ATrace_endSection != nullptr){ + mIsTracingSupported = true; + } + } +} \ No newline at end of file diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/Trace.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/Trace.h new file mode 100644 index 0000000..c7965f9 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/Trace.h @@ -0,0 +1,31 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_TRACE_H +#define OBOE_TRACE_H + +class Trace { + +public: + static void beginSection(const char *format, ...); + static void endSection(); + static void initialize(); + +private: + static bool mIsTracingSupported; +}; + +#endif //OBOE_TRACE_H \ No newline at end of file diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/Utilities.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/Utilities.cpp new file mode 100644 index 0000000..c3acf47 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/Utilities.cpp @@ -0,0 +1,305 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include + +#ifdef __ANDROID__ +#include +#endif + +#include +#include "oboe/Definitions.h" +#include "oboe/Utilities.h" + +namespace oboe { + +constexpr float kScaleI16ToFloat = (1.0f / 32768.0f); + +void convertFloatToPcm16(const float *source, int16_t *destination, int32_t numSamples) { + for (int i = 0; i < numSamples; i++) { + float fval = source[i]; + fval += 1.0; // to avoid discontinuity at 0.0 caused by truncation + fval *= 32768.0f; + auto sample = static_cast(fval); + // clip to 16-bit range + if (sample < 0) sample = 0; + else if (sample > 0x0FFFF) sample = 0x0FFFF; + sample -= 32768; // center at zero + destination[i] = static_cast(sample); + } +} + +void convertPcm16ToFloat(const int16_t *source, float *destination, int32_t numSamples) { + for (int i = 0; i < numSamples; i++) { + destination[i] = source[i] * kScaleI16ToFloat; + } +} + +int32_t convertFormatToSizeInBytes(AudioFormat format) { + int32_t size = 0; + switch (format) { + case AudioFormat::I16: + size = sizeof(int16_t); + break; + case AudioFormat::Float: + size = sizeof(float); + break; + default: + break; + } + return size; +} + +template<> +const char *convertToText(Result returnCode) { + switch (returnCode) { + case Result::OK: return "OK"; + case Result::ErrorDisconnected: return "ErrorDisconnected"; + case Result::ErrorIllegalArgument: return "ErrorIllegalArgument"; + case Result::ErrorInternal: return "ErrorInternal"; + case Result::ErrorInvalidState: return "ErrorInvalidState"; + case Result::ErrorInvalidHandle: return "ErrorInvalidHandle"; + case Result::ErrorUnimplemented: return "ErrorUnimplemented"; + case Result::ErrorUnavailable: return "ErrorUnavailable"; + case Result::ErrorNoFreeHandles: return "ErrorNoFreeHandles"; + case Result::ErrorNoMemory: return "ErrorNoMemory"; + case Result::ErrorNull: return "ErrorNull"; + case Result::ErrorTimeout: return "ErrorTimeout"; + case Result::ErrorWouldBlock: return "ErrorWouldBlock"; + case Result::ErrorInvalidFormat: return "ErrorInvalidFormat"; + case Result::ErrorOutOfRange: return "ErrorOutOfRange"; + case Result::ErrorNoService: return "ErrorNoService"; + case Result::ErrorInvalidRate: return "ErrorInvalidRate"; + case Result::ErrorClosed: return "ErrorClosed"; + default: return "Unrecognized result"; + } +} + +template<> +const char *convertToText(AudioFormat format) { + switch (format) { + case AudioFormat::Invalid: return "Invalid"; + case AudioFormat::Unspecified: return "Unspecified"; + case AudioFormat::I16: return "I16"; + case AudioFormat::Float: return "Float"; + default: return "Unrecognized format"; + } +} + +template<> +const char *convertToText(PerformanceMode mode) { + switch (mode) { + case PerformanceMode::LowLatency: return "LowLatency"; + case PerformanceMode::None: return "None"; + case PerformanceMode::PowerSaving: return "PowerSaving"; + default: return "Unrecognized performance mode"; + } +} + +template<> +const char *convertToText(SharingMode mode) { + switch (mode) { + case SharingMode::Exclusive: return "Exclusive"; + case SharingMode::Shared: return "Shared"; + default: return "Unrecognized sharing mode"; + } +} + +template<> +const char *convertToText(DataCallbackResult result) { + switch (result) { + case DataCallbackResult::Continue: return "Continue"; + case DataCallbackResult::Stop: return "Stop"; + default: return "Unrecognized data callback result"; + } +} + +template<> +const char *convertToText(Direction direction) { + switch (direction) { + case Direction::Input: return "Input"; + case Direction::Output: return "Output"; + default: return "Unrecognized direction"; + } +} + +template<> +const char *convertToText(StreamState state) { + switch (state) { + case StreamState::Closed: return "Closed"; + case StreamState::Closing: return "Closing"; + case StreamState::Disconnected: return "Disconnected"; + case StreamState::Flushed: return "Flushed"; + case StreamState::Flushing: return "Flushing"; + case StreamState::Open: return "Open"; + case StreamState::Paused: return "Paused"; + case StreamState::Pausing: return "Pausing"; + case StreamState::Started: return "Started"; + case StreamState::Starting: return "Starting"; + case StreamState::Stopped: return "Stopped"; + case StreamState::Stopping: return "Stopping"; + case StreamState::Uninitialized: return "Uninitialized"; + case StreamState::Unknown: return "Unknown"; + default: return "Unrecognized stream state"; + } +} + +template<> +const char *convertToText(AudioApi audioApi) { + + switch (audioApi) { + case AudioApi::Unspecified: return "Unspecified"; + case AudioApi::OpenSLES: return "OpenSLES"; + case AudioApi::AAudio: return "AAudio"; + default: return "Unrecognized audio API"; + } +} + +template<> +const char *convertToText(AudioStream* stream) { + static std::string streamText; + std::stringstream s; + + s<<"StreamID: "<< static_cast(stream)<getDeviceId()<getDirection())<getAudioApi())<getBufferCapacityInFrames()<getBufferSizeInFrames()<getFramesPerBurst()<getFramesPerCallback()<getSampleRate()<getChannelCount()<getFormat())<getSharingMode())<getPerformanceMode()) + <getState())<getXRunCount()<getFramesRead()<getFramesWritten()< +const char *convertToText(Usage usage) { + + switch (usage) { + case Usage::Media: return "Media"; + case Usage::VoiceCommunication: return "VoiceCommunication"; + case Usage::VoiceCommunicationSignalling: return "VoiceCommunicationSignalling"; + case Usage::Alarm: return "Alarm"; + case Usage::Notification: return "Notification"; + case Usage::NotificationRingtone: return "NotificationRingtone"; + case Usage::NotificationEvent: return "NotificationEvent"; + case Usage::AssistanceAccessibility: return "AssistanceAccessibility"; + case Usage::AssistanceNavigationGuidance: return "AssistanceNavigationGuidance"; + case Usage::AssistanceSonification: return "AssistanceSonification"; + case Usage::Game: return "Game"; + case Usage::Assistant: return "Assistant"; + default: return "Unrecognized usage"; + } +} + +template<> +const char *convertToText(ContentType contentType) { + + switch (contentType) { + case ContentType::Speech: return "Speech"; + case ContentType::Music: return "Music"; + case ContentType::Movie: return "Movie"; + case ContentType::Sonification: return "Sonification"; + default: return "Unrecognized content type"; + } +} + +template<> +const char *convertToText(InputPreset inputPreset) { + + switch (inputPreset) { + case InputPreset::Generic: return "Generic"; + case InputPreset::Camcorder: return "Camcorder"; + case InputPreset::VoiceRecognition: return "VoiceRecognition"; + case InputPreset::VoiceCommunication: return "VoiceCommunication"; + case InputPreset::Unprocessed: return "Unprocessed"; + case InputPreset::VoicePerformance: return "VoicePerformance"; + default: return "Unrecognized input preset"; + } +} + +template<> +const char *convertToText(SessionId sessionId) { + + switch (sessionId) { + case SessionId::None: return "None"; + case SessionId::Allocate: return "Allocate"; + default: return "Unrecognized session id"; + } +} + +template<> +const char *convertToText(ChannelCount channelCount) { + + switch (channelCount) { + case ChannelCount::Unspecified: return "Unspecified"; + case ChannelCount::Mono: return "Mono"; + case ChannelCount::Stereo: return "Stereo"; + default: return "Unrecognized channel count"; + } +} + +std::string getPropertyString(const char * name) { + std::string result; +#ifdef __ANDROID__ + char valueText[PROP_VALUE_MAX] = {0}; + if (__system_property_get(name, valueText) != 0) { + result = valueText; + } +#else + (void) name; +#endif + return result; +} + +int getPropertyInteger(const char * name, int defaultValue) { + int result = defaultValue; +#ifdef __ANDROID__ + char valueText[PROP_VALUE_MAX] = {0}; + if (__system_property_get(name, valueText) != 0) { + result = atoi(valueText); + } +#else + (void) name; +#endif + return result; +} + +int getSdkVersion() { + static int sCachedSdkVersion = -1; +#ifdef __ANDROID__ + if (sCachedSdkVersion == -1) { + sCachedSdkVersion = getPropertyInteger("ro.build.version.sdk", -1); + } +#endif + return sCachedSdkVersion; +} + +}// namespace oboe diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/Version.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/Version.cpp new file mode 100644 index 0000000..481bee7 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/common/Version.cpp @@ -0,0 +1,28 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "oboe/Version.h" + +namespace oboe { + + // This variable enables the version information to be read from the resulting binary e.g. + // by running `objdump -s --section=.data ` + // Please do not optimize or change in any way. + char kVersionText[] = "OboeVersion" OBOE_VERSION_TEXT; + + const char * getVersionText(){ + return kVersionText; + } +} // namespace oboe diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoBuffer.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoBuffer.cpp new file mode 100644 index 0000000..8d6b03b --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoBuffer.cpp @@ -0,0 +1,182 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include "common/OboeDebug.h" +#include "fifo/FifoControllerBase.h" +#include "fifo/FifoController.h" +#include "fifo/FifoControllerIndirect.h" +#include "fifo/FifoBuffer.h" +#include "common/AudioClock.h" + +namespace oboe { + +FifoBuffer::FifoBuffer(uint32_t bytesPerFrame, uint32_t capacityInFrames) + : mBytesPerFrame(bytesPerFrame) + , mStorage(nullptr) + , mFramesReadCount(0) + , mFramesUnderrunCount(0) +{ + mFifo = std::make_unique(capacityInFrames); + // allocate buffer + int32_t bytesPerBuffer = bytesPerFrame * capacityInFrames; + mStorage = new uint8_t[bytesPerBuffer]; + mStorageOwned = true; +} + +FifoBuffer::FifoBuffer( uint32_t bytesPerFrame, + uint32_t capacityInFrames, + std::atomic *readCounterAddress, + std::atomic *writeCounterAddress, + uint8_t *dataStorageAddress + ) + : mBytesPerFrame(bytesPerFrame) + , mStorage(dataStorageAddress) + , mFramesReadCount(0) + , mFramesUnderrunCount(0) +{ + mFifo = std::make_unique(capacityInFrames, + readCounterAddress, + writeCounterAddress); + mStorage = dataStorageAddress; + mStorageOwned = false; +} + +FifoBuffer::~FifoBuffer() { + if (mStorageOwned) { + delete[] mStorage; + } +} + +int32_t FifoBuffer::convertFramesToBytes(int32_t frames) { + return frames * mBytesPerFrame; +} + +int32_t FifoBuffer::read(void *buffer, int32_t numFrames) { + if (numFrames <= 0) { + return 0; + } + // safe because numFrames is guaranteed positive + uint32_t framesToRead = static_cast(numFrames); + uint32_t framesAvailable = mFifo->getFullFramesAvailable(); + framesToRead = std::min(framesToRead, framesAvailable); + + uint32_t readIndex = mFifo->getReadIndex(); // ranges 0 to capacity + uint8_t *destination = reinterpret_cast(buffer); + uint8_t *source = &mStorage[convertFramesToBytes(readIndex)]; + if ((readIndex + framesToRead) > mFifo->getFrameCapacity()) { + // read in two parts, first part here is at the end of the mStorage buffer + int32_t frames1 = static_cast(mFifo->getFrameCapacity() - readIndex); + int32_t numBytes = convertFramesToBytes(frames1); + if (numBytes < 0) { + return static_cast(Result::ErrorOutOfRange); + } + memcpy(destination, source, static_cast(numBytes)); + destination += numBytes; + // read second part, which is at the beginning of mStorage + source = &mStorage[0]; + int32_t frames2 = static_cast(framesToRead - frames1); + numBytes = convertFramesToBytes(frames2); + if (numBytes < 0) { + return static_cast(Result::ErrorOutOfRange); + } + memcpy(destination, source, static_cast(numBytes)); + } else { + // just read in one shot + int32_t numBytes = convertFramesToBytes(framesToRead); + if (numBytes < 0) { + return static_cast(Result::ErrorOutOfRange); + } + memcpy(destination, source, static_cast(numBytes)); + } + mFifo->advanceReadIndex(framesToRead); + + return framesToRead; +} + +int32_t FifoBuffer::write(const void *buffer, int32_t numFrames) { + if (numFrames <= 0) { + return 0; + } + // Guaranteed positive. + uint32_t framesToWrite = static_cast(numFrames); + uint32_t framesAvailable = mFifo->getEmptyFramesAvailable(); + framesToWrite = std::min(framesToWrite, framesAvailable); + + uint32_t writeIndex = mFifo->getWriteIndex(); + int byteIndex = convertFramesToBytes(writeIndex); + const uint8_t *source = reinterpret_cast(buffer); + uint8_t *destination = &mStorage[byteIndex]; + if ((writeIndex + framesToWrite) > mFifo->getFrameCapacity()) { + // write in two parts, first part here + int32_t frames1 = static_cast(mFifo->getFrameCapacity() - writeIndex); + int32_t numBytes = convertFramesToBytes(frames1); + if (numBytes < 0) { + return static_cast(Result::ErrorOutOfRange); + } + memcpy(destination, source, static_cast(numBytes)); + // read second part + source += convertFramesToBytes(frames1); + destination = &mStorage[0]; + int frames2 = static_cast(framesToWrite - frames1); + numBytes = convertFramesToBytes(frames2); + if (numBytes < 0) { + return static_cast(Result::ErrorOutOfRange); + } + memcpy(destination, source, static_cast(numBytes)); + } else { + // just write in one shot + int32_t numBytes = convertFramesToBytes(framesToWrite); + if (numBytes < 0) { + return static_cast(Result::ErrorOutOfRange); + } + memcpy(destination, source, static_cast(numBytes)); + } + mFifo->advanceWriteIndex(framesToWrite); + + return framesToWrite; +} + +int32_t FifoBuffer::readNow(void *buffer, int32_t numFrames) { + int32_t framesRead = read(buffer, numFrames); + if (framesRead < 0) { + return framesRead; + } + int32_t framesLeft = numFrames - framesRead; + mFramesReadCount += framesRead; + mFramesUnderrunCount += framesLeft; + // Zero out any samples we could not set. + if (framesLeft > 0) { + uint8_t *destination = reinterpret_cast(buffer); + destination += convertFramesToBytes(framesRead); // point to first byte not set + int32_t bytesToZero = convertFramesToBytes(framesLeft); + memset(destination, 0, static_cast(bytesToZero)); + } + + return framesRead; +} + + +uint32_t FifoBuffer::getBufferCapacityInFrames() const { + return mFifo->getFrameCapacity(); +} + +} // namespace oboe diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoBuffer.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoBuffer.h new file mode 100644 index 0000000..8018620 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoBuffer.h @@ -0,0 +1,99 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_FIFOPROCESSOR_H +#define OBOE_FIFOPROCESSOR_H + +#include +#include + +#include "common/OboeDebug.h" +#include "FifoControllerBase.h" +#include "oboe/Definitions.h" + +namespace oboe { + +class FifoBuffer { +public: + FifoBuffer(uint32_t bytesPerFrame, uint32_t capacityInFrames); + + FifoBuffer(uint32_t bytesPerFrame, + uint32_t capacityInFrames, + std::atomic *readCounterAddress, + std::atomic *writeCounterAddress, + uint8_t *dataStorageAddress); + + ~FifoBuffer(); + + int32_t convertFramesToBytes(int32_t frames); + + /** + * Read framesToRead or, if not enough, then read as many as are available. + * @param destination + * @param framesToRead number of frames requested + * @return number of frames actually read + */ + int32_t read(void *destination, int32_t framesToRead); + + int32_t write(const void *source, int32_t framesToWrite); + + uint32_t getBufferCapacityInFrames() const; + + /** + * Calls read(). If all of the frames cannot be read then the remainder of the buffer + * is set to zero. + * + * @param destination + * @param framesToRead number of frames requested + * @return number of frames actually read + */ + int32_t readNow(void *destination, int32_t numFrames); + + uint32_t getFullFramesAvailable() { + return mFifo->getFullFramesAvailable(); + } + + uint32_t getBytesPerFrame() const { + return mBytesPerFrame; + } + + uint64_t getReadCounter() const { + return mFifo->getReadCounter(); + } + + void setReadCounter(uint64_t n) { + mFifo->setReadCounter(n); + } + + uint64_t getWriteCounter() { + return mFifo->getWriteCounter(); + } + void setWriteCounter(uint64_t n) { + mFifo->setWriteCounter(n); + } + +private: + uint32_t mBytesPerFrame; + uint8_t* mStorage; + bool mStorageOwned; // did this object allocate the storage? + std::unique_ptr mFifo; + uint64_t mFramesReadCount; + uint64_t mFramesUnderrunCount; +}; + +} // namespace oboe + +#endif //OBOE_FIFOPROCESSOR_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoController.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoController.cpp new file mode 100644 index 0000000..5590683 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoController.cpp @@ -0,0 +1,31 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "FifoControllerBase.h" +#include "FifoController.h" + +namespace oboe { + +FifoController::FifoController(uint32_t numFrames) + : FifoControllerBase(numFrames) +{ + setReadCounter(0); + setWriteCounter(0); +} + +} // namespace oboe diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoController.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoController.h new file mode 100644 index 0000000..6562e6d --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoController.h @@ -0,0 +1,61 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NATIVEOBOE_FIFOCONTROLLER_H +#define NATIVEOBOE_FIFOCONTROLLER_H + +#include +#include "FifoControllerBase.h" +#include + +namespace oboe { + +/** + * A FifoControllerBase with counters contained in the class. + */ +class FifoController : public FifoControllerBase +{ +public: + FifoController(uint32_t bufferSize); + virtual ~FifoController() = default; + + virtual uint64_t getReadCounter() const override { + return mReadCounter.load(std::memory_order_acquire); + } + virtual void setReadCounter(uint64_t n) override { + mReadCounter.store(n, std::memory_order_release); + } + virtual void incrementReadCounter(uint64_t n) override { + mReadCounter.fetch_add(n, std::memory_order_acq_rel); + } + virtual uint64_t getWriteCounter() const override { + return mWriteCounter.load(std::memory_order_acquire); + } + virtual void setWriteCounter(uint64_t n) override { + mWriteCounter.store(n, std::memory_order_release); + } + virtual void incrementWriteCounter(uint64_t n) override { + mWriteCounter.fetch_add(n, std::memory_order_acq_rel); + } + +private: + std::atomic mReadCounter{}; + std::atomic mWriteCounter{}; +}; + +} // namespace oboe + +#endif //NATIVEOBOE_FIFOCONTROLLER_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoControllerBase.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoControllerBase.cpp new file mode 100644 index 0000000..6aceea0 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoControllerBase.cpp @@ -0,0 +1,71 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "FifoControllerBase.h" + +#include +#include +#include +#include "FifoControllerBase.h" + +#include "common/OboeDebug.h" + +namespace oboe { + +FifoControllerBase::FifoControllerBase(uint32_t capacityInFrames) + : mTotalFrames(capacityInFrames) +{ + // Avoid ridiculously large buffers and the arithmetic wraparound issues that can follow. + assert(capacityInFrames <= (UINT32_MAX / 4)); +} + +uint32_t FifoControllerBase::getFullFramesAvailable() const { + uint64_t writeCounter = getWriteCounter(); + uint64_t readCounter = getReadCounter(); + if (readCounter > writeCounter) { + return 0; + } + uint64_t delta = writeCounter - readCounter; + if (delta >= mTotalFrames) { + return mTotalFrames; + } + // delta is now guaranteed to fit within the range of a uint32_t + return static_cast(delta); +} + +uint32_t FifoControllerBase::getReadIndex() const { + // % works with non-power of two sizes + return static_cast(getReadCounter() % mTotalFrames); +} + +void FifoControllerBase::advanceReadIndex(uint32_t numFrames) { + incrementReadCounter(numFrames); +} + +uint32_t FifoControllerBase::getEmptyFramesAvailable() const { + return static_cast(mTotalFrames - getFullFramesAvailable()); +} + +uint32_t FifoControllerBase::getWriteIndex() const { + // % works with non-power of two sizes + return static_cast(getWriteCounter() % mTotalFrames); +} + +void FifoControllerBase::advanceWriteIndex(uint32_t numFrames) { + incrementWriteCounter(numFrames); +} + +} // namespace oboe diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoControllerBase.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoControllerBase.h new file mode 100644 index 0000000..c8041e0 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoControllerBase.h @@ -0,0 +1,93 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NATIVEOBOE_FIFOCONTROLLERBASE_H +#define NATIVEOBOE_FIFOCONTROLLERBASE_H + +#include +#include + +namespace oboe { + +/** + * Manage the read/write indices of a circular buffer. + * + * The caller is responsible for reading and writing the actual data. + * Note that the span of available frames may not be contiguous. They + * may wrap around from the end to the beginning of the buffer. In that + * case the data must be read or written in at least two blocks of frames. + * + */ + +class FifoControllerBase { + +public: + /** + * @param totalFrames capacity of the circular buffer in frames. + */ + FifoControllerBase(uint32_t totalFrames); + + virtual ~FifoControllerBase() = default; + + /** + * The frames available to read will be calculated from the read and write counters. + * The result will be clipped to the capacity of the buffer. + * If the buffer has underflowed then this will return zero. + * @return number of valid frames available to read. + */ + uint32_t getFullFramesAvailable() const; + + /** + * The index in a circular buffer of the next frame to read. + */ + uint32_t getReadIndex() const; + + /** + * @param numFrames number of frames to advance the read index + */ + void advanceReadIndex(uint32_t numFrames); + + /** + * @return maximum number of frames that can be written without exceeding the threshold. + */ + uint32_t getEmptyFramesAvailable() const; + + /** + * The index in a circular buffer of the next frame to write. + */ + uint32_t getWriteIndex() const; + + /** + * @param numFrames number of frames to advance the write index + */ + void advanceWriteIndex(uint32_t numFrames); + + uint32_t getFrameCapacity() const { return mTotalFrames; } + + virtual uint64_t getReadCounter() const = 0; + virtual void setReadCounter(uint64_t n) = 0; + virtual void incrementReadCounter(uint64_t n) = 0; + virtual uint64_t getWriteCounter() const = 0; + virtual void setWriteCounter(uint64_t n) = 0; + virtual void incrementWriteCounter(uint64_t n) = 0; + +private: + uint32_t mTotalFrames; +}; + +} // namespace oboe + +#endif //NATIVEOBOE_FIFOCONTROLLERBASE_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoControllerIndirect.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoControllerIndirect.cpp new file mode 100644 index 0000000..f596461 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoControllerIndirect.cpp @@ -0,0 +1,31 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "FifoControllerIndirect.h" + +namespace oboe { + +FifoControllerIndirect::FifoControllerIndirect(uint32_t numFrames, + std::atomic *readCounterAddress, + std::atomic *writeCounterAddress) + : FifoControllerBase(numFrames) + , mReadCounterAddress(readCounterAddress) + , mWriteCounterAddress(writeCounterAddress) +{ +} + +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoControllerIndirect.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoControllerIndirect.h new file mode 100644 index 0000000..216a28b --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/fifo/FifoControllerIndirect.h @@ -0,0 +1,64 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NATIVEOBOE_FIFOCONTROLLERINDIRECT_H +#define NATIVEOBOE_FIFOCONTROLLERINDIRECT_H + +#include "FifoControllerBase.h" +#include + +namespace oboe { + +/** + * A FifoControllerBase with counters external to the class. + */ +class FifoControllerIndirect : public FifoControllerBase { + +public: + FifoControllerIndirect(uint32_t bufferSize, + std::atomic *readCounterAddress, + std::atomic *writeCounterAddress); + virtual ~FifoControllerIndirect() = default; + + virtual uint64_t getReadCounter() const override { + return mReadCounterAddress->load(std::memory_order_acquire); + } + virtual void setReadCounter(uint64_t n) override { + mReadCounterAddress->store(n, std::memory_order_release); + } + virtual void incrementReadCounter(uint64_t n) override { + mReadCounterAddress->fetch_add(n, std::memory_order_acq_rel); + } + virtual uint64_t getWriteCounter() const override { + return mWriteCounterAddress->load(std::memory_order_acquire); + } + virtual void setWriteCounter(uint64_t n) override { + mWriteCounterAddress->store(n, std::memory_order_release); + } + virtual void incrementWriteCounter(uint64_t n) override { + mWriteCounterAddress->fetch_add(n, std::memory_order_acq_rel); + } + +private: + + std::atomic *mReadCounterAddress; + std::atomic *mWriteCounterAddress; + +}; + +} // namespace oboe + +#endif //NATIVEOBOE_FIFOCONTROLLERINDIRECT_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/ClipToRange.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/ClipToRange.cpp new file mode 100644 index 0000000..d2f8a02 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/ClipToRange.cpp @@ -0,0 +1,38 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "FlowGraphNode.h" +#include "ClipToRange.h" + +using namespace flowgraph; + +ClipToRange::ClipToRange(int32_t channelCount) + : FlowGraphFilter(channelCount) { +} + +int32_t ClipToRange::onProcess(int32_t numFrames) { + const float *inputBuffer = input.getBuffer(); + float *outputBuffer = output.getBuffer(); + + int32_t numSamples = numFrames * output.getSamplesPerFrame(); + for (int32_t i = 0; i < numSamples; i++) { + *outputBuffer++ = std::min(mMaximum, std::max(mMinimum, *inputBuffer++)); + } + + return numFrames; +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/ClipToRange.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/ClipToRange.h new file mode 100644 index 0000000..22b7804 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/ClipToRange.h @@ -0,0 +1,68 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLOWGRAPH_CLIP_TO_RANGE_H +#define FLOWGRAPH_CLIP_TO_RANGE_H + +#include +#include +#include + +#include "FlowGraphNode.h" + +namespace flowgraph { + +// This is 3 dB, (10^(3/20)), to match the maximum headroom in AudioTrack for float data. +// It is designed to allow occasional transient peaks. +constexpr float kDefaultMaxHeadroom = 1.41253754f; +constexpr float kDefaultMinHeadroom = -kDefaultMaxHeadroom; + +class ClipToRange : public FlowGraphFilter { +public: + explicit ClipToRange(int32_t channelCount); + + virtual ~ClipToRange() = default; + + int32_t onProcess(int32_t numFrames) override; + + void setMinimum(float min) { + mMinimum = min; + } + + float getMinimum() const { + return mMinimum; + } + + void setMaximum(float min) { + mMaximum = min; + } + + float getMaximum() const { + return mMaximum; + } + + const char *getName() override { + return "ClipToRange"; + } + +private: + float mMinimum = kDefaultMinHeadroom; + float mMaximum = kDefaultMaxHeadroom; +}; + +} /* namespace flowgraph */ + +#endif //FLOWGRAPH_CLIP_TO_RANGE_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/FlowGraphNode.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/FlowGraphNode.cpp new file mode 100644 index 0000000..bb6ecc9 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/FlowGraphNode.cpp @@ -0,0 +1,111 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stdio.h" +#include +#include +#include "FlowGraphNode.h" + +using namespace flowgraph; + +/***************************************************************************/ +int32_t FlowGraphNode::pullData(int64_t framePosition, int32_t numFrames) { + int32_t frameCount = numFrames; + // Prevent recursion and multiple execution of nodes. + if (framePosition <= mLastFramePosition && !mBlockRecursion) { + mBlockRecursion = true; // for cyclic graphs + if (mDataPulledAutomatically) { + // Pull from all the upstream nodes. + for (auto &port : mInputPorts) { + // TODO fix bug of leaving unused data in some ports if using multiple AudioSource + frameCount = port.get().pullData(framePosition, frameCount); + } + } + if (frameCount > 0) { + frameCount = onProcess(frameCount); + } + mLastFramePosition += frameCount; + mBlockRecursion = false; + mLastFrameCount = frameCount; + } else { + frameCount = mLastFrameCount; + } + return frameCount; +} + +void FlowGraphNode::pullReset() { + if (!mBlockRecursion) { + mBlockRecursion = true; // for cyclic graphs + // Pull reset from all the upstream nodes. + for (auto &port : mInputPorts) { + port.get().pullReset(); + } + mBlockRecursion = false; + reset(); + } +} + +void FlowGraphNode::reset() { + mLastFrameCount = 0; +} + +/***************************************************************************/ +FlowGraphPortFloat::FlowGraphPortFloat(FlowGraphNode &parent, + int32_t samplesPerFrame, + int32_t framesPerBuffer) + : FlowGraphPort(parent, samplesPerFrame) + , mFramesPerBuffer(framesPerBuffer) + , mBuffer(nullptr) { + size_t numFloats = static_cast(framesPerBuffer * getSamplesPerFrame()); + mBuffer = std::make_unique(numFloats); +} + +/***************************************************************************/ +int32_t FlowGraphPortFloatOutput::pullData(int64_t framePosition, int32_t numFrames) { + numFrames = std::min(getFramesPerBuffer(), numFrames); + return mContainingNode.pullData(framePosition, numFrames); +} + +void FlowGraphPortFloatOutput::pullReset() { + mContainingNode.pullReset(); +} + +// These need to be in the .cpp file because of forward cross references. +void FlowGraphPortFloatOutput::connect(FlowGraphPortFloatInput *port) { + port->connect(this); +} + +void FlowGraphPortFloatOutput::disconnect(FlowGraphPortFloatInput *port) { + port->disconnect(this); +} + +/***************************************************************************/ +int32_t FlowGraphPortFloatInput::pullData(int64_t framePosition, int32_t numFrames) { + return (mConnected == nullptr) + ? std::min(getFramesPerBuffer(), numFrames) + : mConnected->pullData(framePosition, numFrames); +} +void FlowGraphPortFloatInput::pullReset() { + if (mConnected != nullptr) mConnected->pullReset(); +} + +float *FlowGraphPortFloatInput::getBuffer() { + if (mConnected == nullptr) { + return FlowGraphPortFloat::getBuffer(); // loaded using setValue() + } else { + return mConnected->getBuffer(); + } +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/FlowGraphNode.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/FlowGraphNode.h new file mode 100644 index 0000000..007131e --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/FlowGraphNode.h @@ -0,0 +1,422 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * FlowGraph.h + * + * Processing node and ports that can be used in a simple data flow graph. + * This was designed to work with audio but could be used for other + * types of data. + */ + +#ifndef FLOWGRAPH_FLOW_GRAPH_NODE_H +#define FLOWGRAPH_FLOW_GRAPH_NODE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +// TODO Move these classes into separate files. +// TODO Review use of raw pointers for connect(). Maybe use smart pointers but need to avoid +// run-time deallocation in audio thread. + +// Set this to 1 if using it inside the Android framework. +// This code is kept here so that it can be moved easily between Oboe and AAudio. +#define FLOWGRAPH_ANDROID_INTERNAL 0 + +namespace flowgraph { + +// Default block size that can be overridden when the FlowGraphPortFloat is created. +// If it is too small then we will have too much overhead from switching between nodes. +// If it is too high then we will thrash the caches. +constexpr int kDefaultBufferSize = 8; // arbitrary + +class FlowGraphPort; +class FlowGraphPortFloatInput; + +/***************************************************************************/ +/** + * Base class for all nodes in the flowgraph. + */ +class FlowGraphNode { +public: + FlowGraphNode() {} + virtual ~FlowGraphNode() = default; + + /** + * Read from the input ports, + * generate multiple frames of data then write the results to the output ports. + * + * @param numFrames maximum number of frames requested for processing + * @return number of frames actually processed + */ + virtual int32_t onProcess(int32_t numFrames) = 0; + + /** + * If the framePosition is at or after the last frame position then call onProcess(). + * This prevents infinite recursion in case of cyclic graphs. + * It also prevents nodes upstream from a branch from being executed twice. + * + * @param framePosition + * @param numFrames + * @return number of frames valid + */ + int32_t pullData(int64_t framePosition, int32_t numFrames); + + /** + * Recursively reset all the nodes in the graph, starting from a Sink. + * + * This must not be called at the same time as pullData! + */ + void pullReset(); + + /** + * Reset framePosition counters. + */ + virtual void reset(); + + void addInputPort(FlowGraphPort &port) { + mInputPorts.push_back(port); + } + + bool isDataPulledAutomatically() const { + return mDataPulledAutomatically; + } + + /** + * Set true if you want the data pulled through the graph automatically. + * This is the default. + * + * Set false if you want to pull the data from the input ports in the onProcess() method. + * You might do this, for example, in a sample rate converting node. + * + * @param automatic + */ + void setDataPulledAutomatically(bool automatic) { + mDataPulledAutomatically = automatic; + } + + virtual const char *getName() { + return "FlowGraph"; + } + + int64_t getLastFramePosition() { + return mLastFramePosition; + } + +protected: + int64_t mLastFramePosition = 0; + + std::vector> mInputPorts; + +private: + bool mDataPulledAutomatically = true; + bool mBlockRecursion = false; + int32_t mLastFrameCount = 0; + +}; + +/***************************************************************************/ +/** + * This is a connector that allows data to flow between modules. + * + * The ports are the primary means of interacting with a module. + * So they are generally declared as public. + * + */ +class FlowGraphPort { +public: + FlowGraphPort(FlowGraphNode &parent, int32_t samplesPerFrame) + : mContainingNode(parent) + , mSamplesPerFrame(samplesPerFrame) { + } + + // Ports are often declared public. So let's make them non-copyable. + FlowGraphPort(const FlowGraphPort&) = delete; + FlowGraphPort& operator=(const FlowGraphPort&) = delete; + + int32_t getSamplesPerFrame() const { + return mSamplesPerFrame; + } + + virtual int32_t pullData(int64_t framePosition, int32_t numFrames) = 0; + + virtual void pullReset() {} + +protected: + FlowGraphNode &mContainingNode; + +private: + const int32_t mSamplesPerFrame = 1; +}; + +/***************************************************************************/ +/** + * This port contains a 32-bit float buffer that can contain several frames of data. + * Processing the data in a block improves performance. + * + * The size is framesPerBuffer * samplesPerFrame). + */ +class FlowGraphPortFloat : public FlowGraphPort { +public: + FlowGraphPortFloat(FlowGraphNode &parent, + int32_t samplesPerFrame, + int32_t framesPerBuffer = kDefaultBufferSize + ); + + virtual ~FlowGraphPortFloat() = default; + + int32_t getFramesPerBuffer() const { + return mFramesPerBuffer; + } + +protected: + + /** + * @return buffer internal to the port or from a connected port + */ + virtual float *getBuffer() { + return mBuffer.get(); + } + +private: + const int32_t mFramesPerBuffer = 1; + std::unique_ptr mBuffer; // allocated in constructor +}; + +/***************************************************************************/ +/** + * The results of a node's processing are stored in the buffers of the output ports. + */ +class FlowGraphPortFloatOutput : public FlowGraphPortFloat { +public: + FlowGraphPortFloatOutput(FlowGraphNode &parent, int32_t samplesPerFrame) + : FlowGraphPortFloat(parent, samplesPerFrame) { + } + + virtual ~FlowGraphPortFloatOutput() = default; + + using FlowGraphPortFloat::getBuffer; + + /** + * Connect to the input of another module. + * An input port can only have one connection. + * An output port can have multiple connections. + * If you connect a second output port to an input port + * then it overwrites the previous connection. + * + * This not thread safe. Do not modify the graph topology from another thread while running. + * Also do not delete a module while it is connected to another port if the graph is running. + */ + void connect(FlowGraphPortFloatInput *port); + + /** + * Disconnect from the input of another module. + * This not thread safe. + */ + void disconnect(FlowGraphPortFloatInput *port); + + /** + * Call the parent module's onProcess() method. + * That may pull data from its inputs and recursively + * process the entire graph. + * @return number of frames actually pulled + */ + int32_t pullData(int64_t framePosition, int32_t numFrames) override; + + + void pullReset() override; + +}; + +/***************************************************************************/ + +/** + * An input port for streaming audio data. + * You can set a value that will be used for processing. + * If you connect an output port to this port then its value will be used instead. + */ +class FlowGraphPortFloatInput : public FlowGraphPortFloat { +public: + FlowGraphPortFloatInput(FlowGraphNode &parent, int32_t samplesPerFrame) + : FlowGraphPortFloat(parent, samplesPerFrame) { + // Add to parent so it can pull data from each input. + parent.addInputPort(*this); + } + + virtual ~FlowGraphPortFloatInput() = default; + + /** + * If connected to an output port then this will return + * that output ports buffers. + * If not connected then it returns the input ports own buffer + * which can be loaded using setValue(). + */ + float *getBuffer() override; + + /** + * Write every value of the float buffer. + * This value will be ignored if an output port is connected + * to this port. + */ + void setValue(float value) { + int numFloats = kDefaultBufferSize * getSamplesPerFrame(); + float *buffer = getBuffer(); + for (int i = 0; i < numFloats; i++) { + *buffer++ = value; + } + } + + /** + * Connect to the output of another module. + * An input port can only have one connection. + * An output port can have multiple connections. + * This not thread safe. + */ + void connect(FlowGraphPortFloatOutput *port) { + assert(getSamplesPerFrame() == port->getSamplesPerFrame()); + mConnected = port; + } + + void disconnect(FlowGraphPortFloatOutput *port) { + assert(mConnected == port); + (void) port; + mConnected = nullptr; + } + + void disconnect() { + mConnected = nullptr; + } + + /** + * Pull data from any output port that is connected. + */ + int32_t pullData(int64_t framePosition, int32_t numFrames) override; + + void pullReset() override; + +private: + FlowGraphPortFloatOutput *mConnected = nullptr; +}; + +/***************************************************************************/ + +/** + * Base class for an edge node in a graph that has no upstream nodes. + * It outputs data but does not consume data. + * By default, it will read its data from an external buffer. + */ +class FlowGraphSource : public FlowGraphNode { +public: + explicit FlowGraphSource(int32_t channelCount) + : output(*this, channelCount) { + } + + virtual ~FlowGraphSource() = default; + + FlowGraphPortFloatOutput output; +}; + +/***************************************************************************/ + +/** + * Base class for an edge node in a graph that has no upstream nodes. + * It outputs data but does not consume data. + * By default, it will read its data from an external buffer. + */ +class FlowGraphSourceBuffered : public FlowGraphSource { +public: + explicit FlowGraphSourceBuffered(int32_t channelCount) + : FlowGraphSource(channelCount) {} + + virtual ~FlowGraphSourceBuffered() = default; + + /** + * Specify buffer that the node will read from. + * + * @param data TODO Consider using std::shared_ptr. + * @param numFrames + */ + void setData(const void *data, int32_t numFrames) { + mData = data; + mSizeInFrames = numFrames; + mFrameIndex = 0; + } + +protected: + const void *mData = nullptr; + int32_t mSizeInFrames = 0; // number of frames in mData + int32_t mFrameIndex = 0; // index of next frame to be processed +}; + +/***************************************************************************/ +/** + * Base class for an edge node in a graph that has no downstream nodes. + * It consumes data but does not output data. + * This graph will be executed when data is read() from this node + * by pulling data from upstream nodes. + */ +class FlowGraphSink : public FlowGraphNode { +public: + explicit FlowGraphSink(int32_t channelCount) + : input(*this, channelCount) { + } + + virtual ~FlowGraphSink() = default; + + FlowGraphPortFloatInput input; + + /** + * Dummy processor. The work happens in the read() method. + * + * @param numFrames + * @return number of frames actually processed + */ + int32_t onProcess(int32_t numFrames) override { + return numFrames; + } + + virtual int32_t read(int64_t framePosition, void *data, int32_t numFrames) = 0; + +}; + +/***************************************************************************/ +/** + * Base class for a node that has an input and an output with the same number of channels. + * This may include traditional filters, eg. FIR, but also include + * any processing node that converts input to output. + */ +class FlowGraphFilter : public FlowGraphNode { +public: + explicit FlowGraphFilter(int32_t channelCount) + : input(*this, channelCount) + , output(*this, channelCount) { + } + + virtual ~FlowGraphFilter() = default; + + FlowGraphPortFloatInput input; + FlowGraphPortFloatOutput output; +}; + +} /* namespace flowgraph */ + +#endif /* FLOWGRAPH_FLOW_GRAPH_NODE_H */ diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/ManyToMultiConverter.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/ManyToMultiConverter.cpp new file mode 100644 index 0000000..879685e --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/ManyToMultiConverter.cpp @@ -0,0 +1,47 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "ManyToMultiConverter.h" + +using namespace flowgraph; + +ManyToMultiConverter::ManyToMultiConverter(int32_t channelCount) + : inputs(channelCount) + , output(*this, channelCount) { + for (int i = 0; i < channelCount; i++) { + inputs[i] = std::make_unique(*this, 1); + } +} + +int32_t ManyToMultiConverter::onProcess(int32_t numFrames) { + int32_t channelCount = output.getSamplesPerFrame(); + + for (int ch = 0; ch < channelCount; ch++) { + const float *inputBuffer = inputs[ch]->getBuffer(); + float *outputBuffer = output.getBuffer() + ch; + + for (int i = 0; i < numFrames; i++) { + // read one, write into the proper interleaved output channel + float sample = *inputBuffer++; + *outputBuffer = sample; + outputBuffer += channelCount; // advance to next multichannel frame + } + } + return numFrames; +} + diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/ManyToMultiConverter.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/ManyToMultiConverter.h new file mode 100644 index 0000000..eca4a8e --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/ManyToMultiConverter.h @@ -0,0 +1,49 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLOWGRAPH_MANY_TO_MULTI_CONVERTER_H +#define FLOWGRAPH_MANY_TO_MULTI_CONVERTER_H + +#include +#include +#include + +#include "FlowGraphNode.h" + +/** + * Combine multiple mono inputs into one interleaved multi-channel output. + */ +class ManyToMultiConverter : public flowgraph::FlowGraphNode { +public: + explicit ManyToMultiConverter(int32_t channelCount); + + virtual ~ManyToMultiConverter() = default; + + int32_t onProcess(int numFrames) override; + + void setEnabled(bool enabled) {} + + std::vector> inputs; + flowgraph::FlowGraphPortFloatOutput output; + + const char *getName() override { + return "ManyToMultiConverter"; + } + +private: +}; + +#endif //FLOWGRAPH_MANY_TO_MULTI_CONVERTER_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/MonoToMultiConverter.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/MonoToMultiConverter.cpp new file mode 100644 index 0000000..11cea78 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/MonoToMultiConverter.cpp @@ -0,0 +1,43 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "FlowGraphNode.h" +#include "MonoToMultiConverter.h" + +using namespace flowgraph; + +MonoToMultiConverter::MonoToMultiConverter(int32_t channelCount) + : input(*this, 1) + , output(*this, channelCount) { +} + +MonoToMultiConverter::~MonoToMultiConverter() { } + +int32_t MonoToMultiConverter::onProcess(int32_t numFrames) { + const float *inputBuffer = input.getBuffer(); + float *outputBuffer = output.getBuffer(); + int32_t channelCount = output.getSamplesPerFrame(); + for (int i = 0; i < numFrames; i++) { + // read one, write many + float sample = *inputBuffer++; + for (int channel = 0; channel < channelCount; channel++) { + *outputBuffer++ = sample; + } + } + return numFrames; +} + diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/MonoToMultiConverter.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/MonoToMultiConverter.h new file mode 100644 index 0000000..376f7a3 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/MonoToMultiConverter.h @@ -0,0 +1,49 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLOWGRAPH_MONO_TO_MULTI_CONVERTER_H +#define FLOWGRAPH_MONO_TO_MULTI_CONVERTER_H + +#include +#include + +#include "FlowGraphNode.h" + +namespace flowgraph { + +/** + * Convert a monophonic stream to a multi-channel stream + * with the same signal on each channel. + */ +class MonoToMultiConverter : public FlowGraphNode { +public: + explicit MonoToMultiConverter(int32_t channelCount); + + virtual ~MonoToMultiConverter(); + + int32_t onProcess(int32_t numFrames) override; + + const char *getName() override { + return "MonoToMultiConverter"; + } + + FlowGraphPortFloatInput input; + FlowGraphPortFloatOutput output; +}; + +} /* namespace flowgraph */ + +#endif //FLOWGRAPH_MONO_TO_MULTI_CONVERTER_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/RampLinear.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/RampLinear.cpp new file mode 100644 index 0000000..afef018 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/RampLinear.cpp @@ -0,0 +1,77 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "FlowGraphNode.h" +#include "RampLinear.h" + +using namespace flowgraph; + +RampLinear::RampLinear(int32_t channelCount) + : FlowGraphFilter(channelCount) { + mTarget.store(1.0f); +} + +void RampLinear::setLengthInFrames(int32_t frames) { + mLengthInFrames = frames; +} + +void RampLinear::setTarget(float target) { + mTarget.store(target); +} + +float RampLinear::interpolateCurrent() { + return mLevelTo - (mRemaining * mScaler); +} + +int32_t RampLinear::onProcess(int32_t numFrames) { + const float *inputBuffer = input.getBuffer(); + float *outputBuffer = output.getBuffer(); + int32_t channelCount = output.getSamplesPerFrame(); + + float target = getTarget(); + if (target != mLevelTo) { + // Start new ramp. Continue from previous level. + mLevelFrom = interpolateCurrent(); + mLevelTo = target; + mRemaining = mLengthInFrames; + mScaler = (mLevelTo - mLevelFrom) / mLengthInFrames; // for interpolation + } + + int32_t framesLeft = numFrames; + + if (mRemaining > 0) { // Ramping? This doesn't happen very often. + int32_t framesToRamp = std::min(framesLeft, mRemaining); + framesLeft -= framesToRamp; + while (framesToRamp > 0) { + float currentLevel = interpolateCurrent(); + for (int ch = 0; ch < channelCount; ch++) { + *outputBuffer++ = *inputBuffer++ * currentLevel; + } + mRemaining--; + framesToRamp--; + } + } + + // Process any frames after the ramp. + int32_t samplesLeft = framesLeft * channelCount; + for (int i = 0; i < samplesLeft; i++) { + *outputBuffer++ = *inputBuffer++ * mLevelTo; + } + + return numFrames; +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/RampLinear.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/RampLinear.h new file mode 100644 index 0000000..f285704 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/RampLinear.h @@ -0,0 +1,96 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLOWGRAPH_RAMP_LINEAR_H +#define FLOWGRAPH_RAMP_LINEAR_H + +#include +#include +#include + +#include "FlowGraphNode.h" + +namespace flowgraph { + +/** + * When the target is modified then the output will ramp smoothly + * between the original and the new target value. + * This can be used to smooth out control values and reduce pops. + * + * The target may be updated while a ramp is in progress, which will trigger + * a new ramp from the current value. + */ +class RampLinear : public FlowGraphFilter { +public: + explicit RampLinear(int32_t channelCount); + + virtual ~RampLinear() = default; + + int32_t onProcess(int32_t numFrames) override; + + /** + * This is used for the next ramp. + * Calling this does not affect a ramp that is in progress. + */ + void setLengthInFrames(int32_t frames); + + int32_t getLengthInFrames() const { + return mLengthInFrames; + } + + /** + * This may be safely called by another thread. + * @param target + */ + void setTarget(float target); + + float getTarget() const { + return mTarget.load(); + } + + /** + * Force the nextSegment to start from this level. + * + * WARNING: this can cause a discontinuity if called while the ramp is being used. + * Only call this when setting the initial ramp. + * + * @param level + */ + void forceCurrent(float level) { + mLevelFrom = level; + mLevelTo = level; + } + + const char *getName() override { + return "RampLinear"; + } + +private: + + float interpolateCurrent(); + + std::atomic mTarget; + + int32_t mLengthInFrames = 48000.0f / 100.0f ; // 10 msec at 48000 Hz; + int32_t mRemaining = 0; + float mScaler = 0.0f; + float mLevelFrom = 0.0f; + float mLevelTo = 0.0f; +}; + +} /* namespace flowgraph */ + +#endif //FLOWGRAPH_RAMP_LINEAR_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SampleRateConverter.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SampleRateConverter.cpp new file mode 100644 index 0000000..708c684 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SampleRateConverter.cpp @@ -0,0 +1,64 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SampleRateConverter.h" + +using namespace flowgraph; +using namespace resampler; + +SampleRateConverter::SampleRateConverter(int32_t channelCount, MultiChannelResampler &resampler) + : FlowGraphFilter(channelCount) + , mResampler(resampler) { + setDataPulledAutomatically(false); +} + +// Return true if there is a sample available. +bool SampleRateConverter::isInputAvailable() { + if (mInputCursor >= mNumValidInputFrames) { + mNumValidInputFrames = input.pullData(mInputFramePosition, input.getFramesPerBuffer()); + mInputFramePosition += mNumValidInputFrames; + mInputCursor = 0; + } + return (mInputCursor < mNumValidInputFrames); +} + +const float *SampleRateConverter::getNextInputFrame() { + const float *inputBuffer = input.getBuffer(); + return &inputBuffer[mInputCursor++ * input.getSamplesPerFrame()]; +} + +int32_t SampleRateConverter::onProcess(int32_t numFrames) { + float *outputBuffer = output.getBuffer(); + int32_t channelCount = output.getSamplesPerFrame(); + int framesLeft = numFrames; + while (framesLeft > 0) { + // Gather input samples as needed. + if(mResampler.isWriteNeeded()) { + if (isInputAvailable()) { + const float *frame = getNextInputFrame(); + mResampler.writeNextFrame(frame); + } else { + break; + } + } else { + // Output frame is interpolated from input samples. + mResampler.readNextFrame(outputBuffer); + outputBuffer += channelCount; + framesLeft--; + } + } + return numFrames - framesLeft; +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SampleRateConverter.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SampleRateConverter.h new file mode 100644 index 0000000..d940b22 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SampleRateConverter.h @@ -0,0 +1,56 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_SAMPLE_RATE_CONVERTER_H +#define OBOE_SAMPLE_RATE_CONVERTER_H + +#include +#include + +#include "FlowGraphNode.h" +#include "resampler/MultiChannelResampler.h" + +namespace flowgraph { + +class SampleRateConverter : public FlowGraphFilter { +public: + explicit SampleRateConverter(int32_t channelCount, resampler::MultiChannelResampler &mResampler); + + virtual ~SampleRateConverter() = default; + + int32_t onProcess(int32_t numFrames) override; + + const char *getName() override { + return "SampleRateConverter"; + } + +private: + + // Return true if there is a sample available. + bool isInputAvailable(); + + // This assumes data is available. Only call after calling isInputAvailable(). + const float *getNextInputFrame(); + + resampler::MultiChannelResampler &mResampler; + + int32_t mInputCursor = 0; + int32_t mNumValidInputFrames = 0; + int64_t mInputFramePosition = 0; // monotonic counter of input frames used for pullData + +}; +} /* namespace flowgraph */ +#endif //OBOE_SAMPLE_RATE_CONVERTER_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkFloat.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkFloat.cpp new file mode 100644 index 0000000..f830daf --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkFloat.cpp @@ -0,0 +1,50 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "FlowGraphNode.h" +#include "SinkFloat.h" + +using namespace flowgraph; + +SinkFloat::SinkFloat(int32_t channelCount) + : FlowGraphSink(channelCount) { +} + +int32_t SinkFloat::read(int64_t framePosition, void *data, int32_t numFrames) { + // printf("SinkFloat::read(,,%d)\n", numFrames); + float *floatData = (float *) data; + int32_t channelCount = input.getSamplesPerFrame(); + + int32_t framesLeft = numFrames; + while (framesLeft > 0) { + // Run the graph and pull data through the input port. + int32_t framesPulled = pullData(framePosition, framesLeft); + // printf("SinkFloat::read: framesLeft = %d, framesPulled = %d\n", framesLeft, framesPulled); + if (framesPulled <= 0) { + break; + } + const float *signal = input.getBuffer(); + int32_t numSamples = framesPulled * channelCount; + memcpy(floatData, signal, numSamples * sizeof(float)); + floatData += numSamples; + framesLeft -= framesPulled; + framePosition += framesPulled; + } + // printf("SinkFloat returning %d\n", numFrames - framesLeft); + return numFrames - framesLeft; +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkFloat.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkFloat.h new file mode 100644 index 0000000..b6474d1 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkFloat.h @@ -0,0 +1,44 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef FLOWGRAPH_SINK_FLOAT_H +#define FLOWGRAPH_SINK_FLOAT_H + +#include +#include + +#include "FlowGraphNode.h" + +namespace flowgraph { + +/** + * AudioSink that lets you read data as 32-bit floats. + */ +class SinkFloat : public FlowGraphSink { +public: + explicit SinkFloat(int32_t channelCount); + + int32_t read(int64_t framePosition, void *data, int32_t numFrames) override; + + const char *getName() override { + return "SinkFloat"; + } +}; + +} /* namespace flowgraph */ + +#endif //FLOWGRAPH_SINK_FLOAT_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkI16.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkI16.cpp new file mode 100644 index 0000000..a5904e8 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkI16.cpp @@ -0,0 +1,58 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "SinkI16.h" + +#if FLOWGRAPH_ANDROID_INTERNAL +#include +#endif + +using namespace flowgraph; + +SinkI16::SinkI16(int32_t channelCount) + : FlowGraphSink(channelCount) {} + +int32_t SinkI16::read(int64_t framePosition, void *data, int32_t numFrames) { + int16_t *shortData = (int16_t *) data; + const int32_t channelCount = input.getSamplesPerFrame(); + + int32_t framesLeft = numFrames; + while (framesLeft > 0) { + // Run the graph and pull data through the input port. + int32_t framesRead = pullData(framePosition, framesLeft); + if (framesRead <= 0) { + break; + } + const float *signal = input.getBuffer(); + int32_t numSamples = framesRead * channelCount; +#if FLOWGRAPH_ANDROID_INTERNAL + memcpy_to_i16_from_float(shortData, signal, numSamples); + shortData += numSamples; + signal += numSamples; +#else + for (int i = 0; i < numSamples; i++) { + int32_t n = (int32_t) (*signal++ * 32768.0f); + *shortData++ = std::min(INT16_MAX, std::max(INT16_MIN, n)); // clip + } +#endif + framesLeft -= framesRead; + framePosition += framesRead; + } + return numFrames - framesLeft; +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkI16.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkI16.h new file mode 100644 index 0000000..2cfdfb0 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkI16.h @@ -0,0 +1,43 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLOWGRAPH_SINK_I16_H +#define FLOWGRAPH_SINK_I16_H + +#include +#include + +#include "FlowGraphNode.h" + +namespace flowgraph { + +/** + * AudioSink that lets you read data as 16-bit signed integers. + */ +class SinkI16 : public FlowGraphSink { +public: + explicit SinkI16(int32_t channelCount); + + int32_t read(int64_t framePosition, void *data, int32_t numFrames) override; + + const char *getName() override { + return "SinkI16"; + } +}; + +} /* namespace flowgraph */ + +#endif //FLOWGRAPH_SINK_I16_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkI24.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkI24.cpp new file mode 100644 index 0000000..b944b77 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkI24.cpp @@ -0,0 +1,67 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + + +#include "FlowGraphNode.h" +#include "SinkI24.h" + +#if FLOWGRAPH_ANDROID_INTERNAL +#include +#endif + +using namespace flowgraph; + +SinkI24::SinkI24(int32_t channelCount) + : FlowGraphSink(channelCount) {} + +int32_t SinkI24::read(int64_t framePosition, void *data, int32_t numFrames) { + uint8_t *byteData = (uint8_t *) data; + const int32_t channelCount = input.getSamplesPerFrame(); + + int32_t framesLeft = numFrames; + while (framesLeft > 0) { + // Run the graph and pull data through the input port. + int32_t framesRead = pullData(framePosition, framesLeft); + if (framesRead <= 0) { + break; + } + const float *floatData = input.getBuffer(); + int32_t numSamples = framesRead * channelCount; +#if FLOWGRAPH_ANDROID_INTERNAL + memcpy_to_p24_from_float(byteData, floatData, numSamples); + static const int kBytesPerI24Packed = 3; + byteData += numSamples * kBytesPerI24Packed; + floatData += numSamples; +#else + const int32_t kI24PackedMax = 0x007FFFFF; + const int32_t kI24PackedMin = 0xFF800000; + for (int i = 0; i < numSamples; i++) { + int32_t n = (int32_t) (*floatData++ * 0x00800000); + n = std::min(kI24PackedMax, std::max(kI24PackedMin, n)); // clip + // Write as a packed 24-bit integer in Little Endian format. + *byteData++ = (uint8_t) n; + *byteData++ = (uint8_t) (n >> 8); + *byteData++ = (uint8_t) (n >> 16); + } +#endif + framesLeft -= framesRead; + framePosition += framesRead; + } + return numFrames - framesLeft; +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkI24.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkI24.h new file mode 100644 index 0000000..7477c8d --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SinkI24.h @@ -0,0 +1,44 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLOWGRAPH_SINK_I24_H +#define FLOWGRAPH_SINK_I24_H + +#include +#include + +#include "FlowGraphNode.h" + +namespace flowgraph { + +/** + * AudioSink that lets you read data as packed 24-bit signed integers. + * The sample size is 3 bytes. + */ +class SinkI24 : public FlowGraphSink { +public: + explicit SinkI24(int32_t channelCount); + + int32_t read(int64_t framePosition, void *data, int32_t numFrames) override; + + const char *getName() override { + return "SinkI24"; + } +}; + +} /* namespace flowgraph */ + +#endif //FLOWGRAPH_SINK_I24_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceFloat.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceFloat.cpp new file mode 100644 index 0000000..f574d84 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceFloat.cpp @@ -0,0 +1,43 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common/OboeDebug.h" +#include +#include +#include "FlowGraphNode.h" +#include "SourceFloat.h" + +using namespace flowgraph; + +SourceFloat::SourceFloat(int32_t channelCount) + : FlowGraphSourceBuffered(channelCount) { +} + +int32_t SourceFloat::onProcess(int32_t numFrames) { + float *outputBuffer = output.getBuffer(); + int32_t channelCount = output.getSamplesPerFrame(); + + int32_t framesLeft = mSizeInFrames - mFrameIndex; + int32_t framesToProcess = std::min(numFrames, framesLeft); + int32_t numSamples = framesToProcess * channelCount; + + const float *floatBase = (float *) mData; + const float *floatData = &floatBase[mFrameIndex * channelCount]; + memcpy(outputBuffer, floatData, numSamples * sizeof(float)); + mFrameIndex += framesToProcess; + return framesToProcess; +} + diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceFloat.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceFloat.h new file mode 100644 index 0000000..4de1b41 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceFloat.h @@ -0,0 +1,43 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLOWGRAPH_SOURCE_FLOAT_H +#define FLOWGRAPH_SOURCE_FLOAT_H + +#include +#include + +#include "FlowGraphNode.h" + +namespace flowgraph { + +/** + * AudioSource that reads a block of pre-defined float data. + */ +class SourceFloat : public FlowGraphSourceBuffered { +public: + explicit SourceFloat(int32_t channelCount); + + int32_t onProcess(int32_t numFrames) override; + + const char *getName() override { + return "SourceFloat"; + } +}; + +} /* namespace flowgraph */ + +#endif //FLOWGRAPH_SOURCE_FLOAT_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceI16.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceI16.cpp new file mode 100644 index 0000000..8813023 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceI16.cpp @@ -0,0 +1,54 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "FlowGraphNode.h" +#include "SourceI16.h" + +#if FLOWGRAPH_ANDROID_INTERNAL +#include +#endif + +using namespace flowgraph; + +SourceI16::SourceI16(int32_t channelCount) + : FlowGraphSourceBuffered(channelCount) { +} + +int32_t SourceI16::onProcess(int32_t numFrames) { + float *floatData = output.getBuffer(); + int32_t channelCount = output.getSamplesPerFrame(); + + int32_t framesLeft = mSizeInFrames - mFrameIndex; + int32_t framesToProcess = std::min(numFrames, framesLeft); + int32_t numSamples = framesToProcess * channelCount; + + const int16_t *shortBase = static_cast(mData); + const int16_t *shortData = &shortBase[mFrameIndex * channelCount]; + +#if FLOWGRAPH_ANDROID_INTERNAL + memcpy_to_float_from_i16(floatData, shortData, numSamples); +#else + for (int i = 0; i < numSamples; i++) { + *floatData++ = *shortData++ * (1.0f / 32768); + } +#endif + + mFrameIndex += framesToProcess; + return framesToProcess; +} \ No newline at end of file diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceI16.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceI16.h new file mode 100644 index 0000000..fe440b2 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceI16.h @@ -0,0 +1,42 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLOWGRAPH_SOURCE_I16_H +#define FLOWGRAPH_SOURCE_I16_H + +#include +#include + +#include "FlowGraphNode.h" + +namespace flowgraph { +/** + * AudioSource that reads a block of pre-defined 16-bit integer data. + */ +class SourceI16 : public FlowGraphSourceBuffered { +public: + explicit SourceI16(int32_t channelCount); + + int32_t onProcess(int32_t numFrames) override; + + const char *getName() override { + return "SourceI16"; + } +}; + +} /* namespace flowgraph */ + +#endif //FLOWGRAPH_SOURCE_I16_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceI24.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceI24.cpp new file mode 100644 index 0000000..1975878 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceI24.cpp @@ -0,0 +1,65 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#if FLOWGRAPH_ANDROID_INTERNAL +#include +#endif + +#include "FlowGraphNode.h" +#include "SourceI24.h" + +using namespace flowgraph; + +constexpr int kBytesPerI24Packed = 3; + +SourceI24::SourceI24(int32_t channelCount) + : FlowGraphSourceBuffered(channelCount) { +} + +int32_t SourceI24::onProcess(int32_t numFrames) { + float *floatData = output.getBuffer(); + int32_t channelCount = output.getSamplesPerFrame(); + + int32_t framesLeft = mSizeInFrames - mFrameIndex; + int32_t framesToProcess = std::min(numFrames, framesLeft); + int32_t numSamples = framesToProcess * channelCount; + + const uint8_t *byteBase = (uint8_t *) mData; + const uint8_t *byteData = &byteBase[mFrameIndex * channelCount * kBytesPerI24Packed]; + +#if FLOWGRAPH_ANDROID_INTERNAL + memcpy_to_float_from_p24(floatData, byteData, numSamples); +#else + static const float scale = 1. / (float)(1UL << 31); + for (int i = 0; i < numSamples; i++) { + // Assemble the data assuming Little Endian format. + int32_t pad = byteData[2]; + pad <<= 8; + pad |= byteData[1]; + pad <<= 8; + pad |= byteData[0]; + pad <<= 8; // Shift to 32 bit data so the sign is correct. + byteData += kBytesPerI24Packed; + *floatData++ = pad * scale; // scale to range -1.0 to 1.0 + } +#endif + + mFrameIndex += framesToProcess; + return framesToProcess; +} \ No newline at end of file diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceI24.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceI24.h new file mode 100644 index 0000000..3779534 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/SourceI24.h @@ -0,0 +1,43 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLOWGRAPH_SOURCE_I24_H +#define FLOWGRAPH_SOURCE_I24_H + +#include +#include + +#include "FlowGraphNode.h" + +namespace flowgraph { + +/** + * AudioSource that reads a block of pre-defined 24-bit packed integer data. + */ +class SourceI24 : public FlowGraphSourceBuffered { +public: + explicit SourceI24(int32_t channelCount); + + int32_t onProcess(int32_t numFrames) override; + + const char *getName() override { + return "SourceI24"; + } +}; + +} /* namespace flowgraph */ + +#endif //FLOWGRAPH_SOURCE_I24_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/HyperbolicCosineWindow.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/HyperbolicCosineWindow.h new file mode 100644 index 0000000..f6479ae --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/HyperbolicCosineWindow.h @@ -0,0 +1,68 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RESAMPLER_HYPERBOLIC_COSINE_WINDOW_H +#define RESAMPLER_HYPERBOLIC_COSINE_WINDOW_H + +#include + +namespace resampler { + +/** + * Calculate a HyperbolicCosineWindow window centered at 0. + * This can be used in place of a Kaiser window. + * + * The code is based on an anonymous contribution by "a concerned citizen": + * https://dsp.stackexchange.com/questions/37714/kaiser-window-approximation + */ +class HyperbolicCosineWindow { +public: + HyperbolicCosineWindow() { + setStopBandAttenuation(60); + } + + /** + * @param attenuation typical values range from 30 to 90 dB + * @return beta + */ + double setStopBandAttenuation(double attenuation) { + double alpha = ((-325.1e-6 * attenuation + 0.1677) * attenuation) - 3.149; + setAlpha(alpha); + return alpha; + } + + void setAlpha(double alpha) { + mAlpha = alpha; + mInverseCoshAlpha = 1.0 / cosh(alpha); + } + + /** + * @param x ranges from -1.0 to +1.0 + */ + double operator()(double x) { + double x2 = x * x; + if (x2 >= 1.0) return 0.0; + double w = mAlpha * sqrt(1.0 - x2); + return cosh(w) * mInverseCoshAlpha; + } + +private: + double mAlpha = 0.0; + double mInverseCoshAlpha = 1.0; +}; + +} // namespace resampler +#endif //RESAMPLER_HYPERBOLIC_COSINE_WINDOW_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/IntegerRatio.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/IntegerRatio.cpp new file mode 100644 index 0000000..4bd75b3 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/IntegerRatio.cpp @@ -0,0 +1,50 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "IntegerRatio.h" + +using namespace resampler; + +// Enough primes to cover the common sample rates. +static const int kPrimes[] = { + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, + 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, + 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199}; + +void IntegerRatio::reduce() { + for (int prime : kPrimes) { + if (mNumerator < prime || mDenominator < prime) { + break; + } + + // Find biggest prime factor for numerator. + while (true) { + int top = mNumerator / prime; + int bottom = mDenominator / prime; + if ((top >= 1) + && (bottom >= 1) + && (top * prime == mNumerator) // divided evenly? + && (bottom * prime == mDenominator)) { + mNumerator = top; + mDenominator = bottom; + } else { + break; + } + } + + } +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/IntegerRatio.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/IntegerRatio.h new file mode 100644 index 0000000..fb390f1 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/IntegerRatio.h @@ -0,0 +1,52 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_INTEGER_RATIO_H +#define OBOE_INTEGER_RATIO_H + +#include + +namespace resampler { + +/** + * Represent the ratio of two integers. + */ +class IntegerRatio { +public: + IntegerRatio(int32_t numerator, int32_t denominator) + : mNumerator(numerator), mDenominator(denominator) {} + + /** + * Reduce by removing common prime factors. + */ + void reduce(); + + int32_t getNumerator() { + return mNumerator; + } + + int32_t getDenominator() { + return mDenominator; + } + +private: + int32_t mNumerator; + int32_t mDenominator; +}; + +} + +#endif //OBOE_INTEGER_RATIO_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/KaiserWindow.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/KaiserWindow.h new file mode 100644 index 0000000..73dbc41 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/KaiserWindow.h @@ -0,0 +1,87 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RESAMPLER_KAISER_WINDOW_H +#define RESAMPLER_KAISER_WINDOW_H + +#include + +namespace resampler { + +/** + * Calculate a Kaiser window centered at 0. + */ +class KaiserWindow { +public: + KaiserWindow() { + setStopBandAttenuation(60); + } + + /** + * @param attenuation typical values range from 30 to 90 dB + * @return beta + */ + double setStopBandAttenuation(double attenuation) { + double beta = 0.0; + if (attenuation > 50) { + beta = 0.1102 * (attenuation - 8.7); + } else if (attenuation >= 21) { + double a21 = attenuation - 21; + beta = 0.5842 * pow(a21, 0.4) + (0.07886 * a21); + } + setBeta(beta); + return beta; + } + + void setBeta(double beta) { + mBeta = beta; + mInverseBesselBeta = 1.0 / bessel(beta); + } + + /** + * @param x ranges from -1.0 to +1.0 + */ + double operator()(double x) { + double x2 = x * x; + if (x2 >= 1.0) return 0.0; + double w = mBeta * sqrt(1.0 - x2); + return bessel(w) * mInverseBesselBeta; + } + + // Approximation of a + // modified zero order Bessel function of the first kind. + // Based on a discussion at: + // https://dsp.stackexchange.com/questions/37714/kaiser-window-approximation + static double bessel(double x) { + double y = cosh(0.970941817426052 * x); + y += cosh(0.8854560256532099 * x); + y += cosh(0.7485107481711011 * x); + y += cosh(0.5680647467311558 * x); + y += cosh(0.3546048870425356 * x); + y += cosh(0.120536680255323 * x); + y *= 2; + y += cosh(x); + y /= 13; + return y; + } + +private: + double mBeta = 0.0; + double mInverseBesselBeta = 1.0; +}; + +} // namespace resampler +#endif //RESAMPLER_KAISER_WINDOW_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/LinearResampler.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/LinearResampler.cpp new file mode 100644 index 0000000..a7748c1 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/LinearResampler.cpp @@ -0,0 +1,42 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LinearResampler.h" + +using namespace resampler; + +LinearResampler::LinearResampler(const MultiChannelResampler::Builder &builder) + : MultiChannelResampler(builder) { + mPreviousFrame = std::make_unique(getChannelCount()); + mCurrentFrame = std::make_unique(getChannelCount()); +} + +void LinearResampler::writeFrame(const float *frame) { + memcpy(mPreviousFrame.get(), mCurrentFrame.get(), sizeof(float) * getChannelCount()); + memcpy(mCurrentFrame.get(), frame, sizeof(float) * getChannelCount()); +} + +void LinearResampler::readFrame(float *frame) { + float *previous = mPreviousFrame.get(); + float *current = mCurrentFrame.get(); + float phase = (float) getIntegerPhase() / mDenominator; + // iterate across samples in the frame + for (int channel = 0; channel < getChannelCount(); channel++) { + float f0 = *previous++; + float f1 = *current++; + *frame++ = f0 + (phase * (f1 - f0)); + } +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/LinearResampler.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/LinearResampler.h new file mode 100644 index 0000000..5dcc881 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/LinearResampler.h @@ -0,0 +1,44 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_LINEAR_RESAMPLER_H +#define OBOE_LINEAR_RESAMPLER_H + +#include +#include +#include +#include "MultiChannelResampler.h" + +namespace resampler { + +/** + * Simple resampler that uses bi-linear interpolation. + */ +class LinearResampler : public MultiChannelResampler { +public: + LinearResampler(const MultiChannelResampler::Builder &builder); + + void writeFrame(const float *frame) override; + + void readFrame(float *frame) override; + +private: + std::unique_ptr mPreviousFrame; + std::unique_ptr mCurrentFrame; +}; + +} // namespace resampler +#endif //OBOE_LINEAR_RESAMPLER_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/MultiChannelResampler.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/MultiChannelResampler.cpp new file mode 100644 index 0000000..d630520 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/MultiChannelResampler.cpp @@ -0,0 +1,171 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "IntegerRatio.h" +#include "LinearResampler.h" +#include "MultiChannelResampler.h" +#include "PolyphaseResampler.h" +#include "PolyphaseResamplerMono.h" +#include "PolyphaseResamplerStereo.h" +#include "SincResampler.h" +#include "SincResamplerStereo.h" + +using namespace resampler; + +MultiChannelResampler::MultiChannelResampler(const MultiChannelResampler::Builder &builder) + : mNumTaps(builder.getNumTaps()) + , mX(builder.getChannelCount() * builder.getNumTaps() * 2) + , mSingleFrame(builder.getChannelCount()) + , mChannelCount(builder.getChannelCount()) + { + // Reduce sample rates to the smallest ratio. + // For example 44100/48000 would become 147/160. + IntegerRatio ratio(builder.getInputRate(), builder.getOutputRate()); + ratio.reduce(); + mNumerator = ratio.getNumerator(); + mDenominator = ratio.getDenominator(); + mIntegerPhase = mDenominator; +} + +// static factory method +MultiChannelResampler *MultiChannelResampler::make(int32_t channelCount, + int32_t inputRate, + int32_t outputRate, + Quality quality) { + Builder builder; + builder.setInputRate(inputRate); + builder.setOutputRate(outputRate); + builder.setChannelCount(channelCount); + + switch (quality) { + case Quality::Fastest: + builder.setNumTaps(2); + break; + case Quality::Low: + builder.setNumTaps(4); + break; + case Quality::Medium: + default: + builder.setNumTaps(8); + break; + case Quality::High: + builder.setNumTaps(16); + break; + case Quality::Best: + builder.setNumTaps(32); + break; + } + + // Set the cutoff frequency so that we do not get aliasing when down-sampling. + if (inputRate > outputRate) { + builder.setNormalizedCutoff(kDefaultNormalizedCutoff); + } + return builder.build(); +} + +MultiChannelResampler *MultiChannelResampler::Builder::build() { + if (getNumTaps() == 2) { + // Note that this does not do low pass filteringh. + return new LinearResampler(*this); + } + IntegerRatio ratio(getInputRate(), getOutputRate()); + ratio.reduce(); + bool usePolyphase = (getNumTaps() * ratio.getDenominator()) <= kMaxCoefficients; + if (usePolyphase) { + if (getChannelCount() == 1) { + return new PolyphaseResamplerMono(*this); + } else if (getChannelCount() == 2) { + return new PolyphaseResamplerStereo(*this); + } else { + return new PolyphaseResampler(*this); + } + } else { + // Use less optimized resampler that uses a float phaseIncrement. + // TODO mono resampler + if (getChannelCount() == 2) { + return new SincResamplerStereo(*this); + } else { + return new SincResampler(*this); + } + } +} + +void MultiChannelResampler::writeFrame(const float *frame) { + // Move cursor before write so that cursor points to last written frame in read. + if (--mCursor < 0) { + mCursor = getNumTaps() - 1; + } + float *dest = &mX[mCursor * getChannelCount()]; + int offset = getNumTaps() * getChannelCount(); + for (int channel = 0; channel < getChannelCount(); channel++) { + // Write twice so we avoid having to wrap when reading. + dest[channel] = dest[channel + offset] = frame[channel]; + } +} + +float MultiChannelResampler::sinc(float radians) { + if (abs(radians) < 1.0e-9) return 1.0f; // avoid divide by zero + return sinf(radians) / radians; // Sinc function +} + +// Generate coefficients in the order they will be used by readFrame(). +// This is more complicated but readFrame() is called repeatedly and should be optimized. +void MultiChannelResampler::generateCoefficients(int32_t inputRate, + int32_t outputRate, + int32_t numRows, + double phaseIncrement, + float normalizedCutoff) { + mCoefficients.resize(getNumTaps() * numRows); + int coefficientIndex = 0; + double phase = 0.0; // ranges from 0.0 to 1.0, fraction between samples + // Stretch the sinc function for low pass filtering. + const float cutoffScaler = normalizedCutoff * + ((outputRate < inputRate) + ? ((float)outputRate / inputRate) + : ((float)inputRate / outputRate)); + const int numTapsHalf = getNumTaps() / 2; // numTaps must be even. + const float numTapsHalfInverse = 1.0f / numTapsHalf; + for (int i = 0; i < numRows; i++) { + float tapPhase = phase - numTapsHalf; + float gain = 0.0; // sum of raw coefficients + int gainCursor = coefficientIndex; + for (int tap = 0; tap < getNumTaps(); tap++) { + float radians = tapPhase * M_PI; + +#if MCR_USE_KAISER + float window = mKaiserWindow(tapPhase * numTapsHalfInverse); +#else + float window = mCoshWindow(tapPhase * numTapsHalfInverse); +#endif + float coefficient = sinc(radians * cutoffScaler) * window; + mCoefficients.at(coefficientIndex++) = coefficient; + gain += coefficient; + tapPhase += 1.0; + } + phase += phaseIncrement; + while (phase >= 1.0) { + phase -= 1.0; + } + + // Correct for gain variations. + float gainCorrection = 1.0 / gain; // normalize the gain + for (int tap = 0; tap < getNumTaps(); tap++) { + mCoefficients.at(gainCursor + tap) *= gainCorrection; + } + } +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/MultiChannelResampler.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/MultiChannelResampler.h new file mode 100644 index 0000000..8b23d81 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/MultiChannelResampler.h @@ -0,0 +1,271 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_MULTICHANNEL_RESAMPLER_H +#define OBOE_MULTICHANNEL_RESAMPLER_H + +#include +#include +#include +#include + +#ifndef MCR_USE_KAISER +// It appears from the spectrogram that the HyperbolicCosine window leads to fewer artifacts. +// And it is faster to calculate. +#define MCR_USE_KAISER 0 +#endif + +#if MCR_USE_KAISER +#include "KaiserWindow.h" +#else +#include "HyperbolicCosineWindow.h" +#endif + +namespace resampler { + +class MultiChannelResampler { + +public: + + enum class Quality : int32_t { + Fastest, + Low, + Medium, + High, + Best, + }; + + class Builder { + public: + /** + * Construct an optimal resampler based on the specified parameters. + * @return address of a resampler + */ + MultiChannelResampler *build(); + + /** + * The number of taps in the resampling filter. + * More taps gives better quality but uses more CPU time. + * This typically ranges from 4 to 64. Default is 16. + * + * For polyphase filters, numTaps must be a multiple of four for loop unrolling. + * @param numTaps number of taps for the filter + * @return address of this builder for chaining calls + */ + Builder *setNumTaps(int32_t numTaps) { + mNumTaps = numTaps; + return this; + } + + /** + * Use 1 for mono, 2 for stereo, etc. Default is 1. + * + * @param channelCount number of channels + * @return address of this builder for chaining calls + */ + Builder *setChannelCount(int32_t channelCount) { + mChannelCount = channelCount; + return this; + } + + /** + * Default is 48000. + * + * @param inputRate sample rate of the input stream + * @return address of this builder for chaining calls + */ + Builder *setInputRate(int32_t inputRate) { + mInputRate = inputRate; + return this; + } + + /** + * Default is 48000. + * + * @param outputRate sample rate of the output stream + * @return address of this builder for chaining calls + */ + Builder *setOutputRate(int32_t outputRate) { + mOutputRate = outputRate; + return this; + } + + /** + * Set cutoff frequency relative to the Nyquist rate of the output sample rate. + * Set to 1.0 to match the Nyquist frequency. + * Set lower to reduce aliasing. + * Default is 0.70. + * + * @param normalizedCutoff anti-aliasing filter cutoff + * @return address of this builder for chaining calls + */ + Builder *setNormalizedCutoff(float normalizedCutoff) { + mNormalizedCutoff = normalizedCutoff; + return this; + } + + int32_t getNumTaps() const { + return mNumTaps; + } + + int32_t getChannelCount() const { + return mChannelCount; + } + + int32_t getInputRate() const { + return mInputRate; + } + + int32_t getOutputRate() const { + return mOutputRate; + } + + float getNormalizedCutoff() const { + return mNormalizedCutoff; + } + + protected: + int32_t mChannelCount = 1; + int32_t mNumTaps = 16; + int32_t mInputRate = 48000; + int32_t mOutputRate = 48000; + float mNormalizedCutoff = kDefaultNormalizedCutoff; + }; + + virtual ~MultiChannelResampler() = default; + + /** + * Factory method for making a resampler that is optimal for the given inputs. + * + * @param channelCount number of channels, 2 for stereo + * @param inputRate sample rate of the input stream + * @param outputRate sample rate of the output stream + * @param quality higher quality sounds better but uses more CPU + * @return an optimal resampler + */ + static MultiChannelResampler *make(int32_t channelCount, + int32_t inputRate, + int32_t outputRate, + Quality quality); + + bool isWriteNeeded() const { + return mIntegerPhase >= mDenominator; + } + + /** + * Write a frame containing N samples. + * + * @param frame pointer to the first sample in a frame + */ + void writeNextFrame(const float *frame) { + writeFrame(frame); + advanceWrite(); + } + + /** + * Read a frame containing N samples. + * + * @param frame pointer to the first sample in a frame + */ + void readNextFrame(float *frame) { + readFrame(frame); + advanceRead(); + } + + int getNumTaps() const { + return mNumTaps; + } + + int getChannelCount() const { + return mChannelCount; + } + + static float hammingWindow(float radians, float spread); + + static float sinc(float radians); + +protected: + + explicit MultiChannelResampler(const MultiChannelResampler::Builder &builder); + + /** + * Write a frame containing N samples. + * Call advanceWrite() after calling this. + * @param frame pointer to the first sample in a frame + */ + virtual void writeFrame(const float *frame); + + /** + * Read a frame containing N samples using interpolation. + * Call advanceRead() after calling this. + * @param frame pointer to the first sample in a frame + */ + virtual void readFrame(float *frame) = 0; + + void advanceWrite() { + mIntegerPhase -= mDenominator; + } + + void advanceRead() { + mIntegerPhase += mNumerator; + } + + /** + * Generate the filter coefficients in optimal order. + * @param inputRate sample rate of the input stream + * @param outputRate sample rate of the output stream + * @param numRows number of rows in the array that contain a set of tap coefficients + * @param phaseIncrement how much to increment the phase between rows + * @param normalizedCutoff filter cutoff frequency normalized to Nyquist rate of output + */ + void generateCoefficients(int32_t inputRate, + int32_t outputRate, + int32_t numRows, + double phaseIncrement, + float normalizedCutoff); + + + int32_t getIntegerPhase() { + return mIntegerPhase; + } + + static constexpr int kMaxCoefficients = 8 * 1024; + std::vector mCoefficients; + + const int mNumTaps; + int mCursor = 0; + std::vector mX; // delayed input values for the FIR + std::vector mSingleFrame; // one frame for temporary use + int32_t mIntegerPhase = 0; + int32_t mNumerator = 0; + int32_t mDenominator = 0; + + +private: + +#if MCR_USE_KAISER + KaiserWindow mKaiserWindow; +#else + HyperbolicCosineWindow mCoshWindow; +#endif + + static constexpr float kDefaultNormalizedCutoff = 0.70f; + + const int mChannelCount; +}; + +} +#endif //OBOE_MULTICHANNEL_RESAMPLER_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResampler.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResampler.cpp new file mode 100644 index 0000000..4862ad8 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResampler.cpp @@ -0,0 +1,61 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "IntegerRatio.h" +#include "PolyphaseResampler.h" + +using namespace resampler; + +PolyphaseResampler::PolyphaseResampler(const MultiChannelResampler::Builder &builder) + : MultiChannelResampler(builder) + { + assert((getNumTaps() % 4) == 0); // Required for loop unrolling. + + int32_t inputRate = builder.getInputRate(); + int32_t outputRate = builder.getOutputRate(); + + int32_t numRows = mDenominator; + double phaseIncrement = (double) inputRate / (double) outputRate; + generateCoefficients(inputRate, outputRate, + numRows, phaseIncrement, + builder.getNormalizedCutoff()); +} + +void PolyphaseResampler::readFrame(float *frame) { + // Clear accumulator for mixing. + std::fill(mSingleFrame.begin(), mSingleFrame.end(), 0.0); + +// printf("PolyphaseResampler: mCoefficientCursor = %4d\n", mCoefficientCursor); + // Multiply input times windowed sinc function. + float *coefficients = &mCoefficients[mCoefficientCursor]; + float *xFrame = &mX[mCursor * getChannelCount()]; + for (int i = 0; i < mNumTaps; i++) { + float coefficient = *coefficients++; +// printf("PolyphaseResampler: coeff = %10.6f, xFrame[0] = %10.6f\n", coefficient, xFrame[0]); + for (int channel = 0; channel < getChannelCount(); channel++) { + mSingleFrame[channel] += *xFrame++ * coefficient; + } + } + + // Advance and wrap through coefficients. + mCoefficientCursor = (mCoefficientCursor + mNumTaps) % mCoefficients.size(); + + // Copy accumulator to output. + for (int channel = 0; channel < getChannelCount(); channel++) { + frame[channel] = mSingleFrame[channel]; + } +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResampler.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResampler.h new file mode 100644 index 0000000..c7de118 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResampler.h @@ -0,0 +1,51 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_POLYPHASE_RESAMPLER_H +#define OBOE_POLYPHASE_RESAMPLER_H + +#include +#include +#include +#include +#include "MultiChannelResampler.h" + +namespace resampler { +/** + * Resample that is optimized for a reduced ratio of sample rates. + * All of the coefficients for eacxh possible phase value are precalculated. + */ +class PolyphaseResampler : public MultiChannelResampler { +public: + /** + * + * @param builder containing lots of parameters + */ + explicit PolyphaseResampler(const MultiChannelResampler::Builder &builder); + + virtual ~PolyphaseResampler() = default; + + void readFrame(float *frame) override; + +protected: + + int32_t mCoefficientCursor = 0; + +}; + +} + +#endif //OBOE_POLYPHASE_RESAMPLER_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResamplerMono.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResamplerMono.cpp new file mode 100644 index 0000000..2dcdc8e --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResamplerMono.cpp @@ -0,0 +1,62 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "PolyphaseResamplerMono.h" + +using namespace resampler; + +#define MONO 1 + +PolyphaseResamplerMono::PolyphaseResamplerMono(const MultiChannelResampler::Builder &builder) + : PolyphaseResampler(builder) { + assert(builder.getChannelCount() == MONO); +} + +void PolyphaseResamplerMono::writeFrame(const float *frame) { + // Move cursor before write so that cursor points to last written frame in read. + if (--mCursor < 0) { + mCursor = getNumTaps() - 1; + } + float *dest = &mX[mCursor * MONO]; + const int offset = mNumTaps * MONO; + // Write each channel twice so we avoid having to wrap when running the FIR. + const float sample = frame[0]; + // Put ordered writes together. + dest[0] = sample; + dest[offset] = sample; +} + +void PolyphaseResamplerMono::readFrame(float *frame) { + // Clear accumulator. + float sum = 0.0; + + // Multiply input times precomputed windowed sinc function. + const float *coefficients = &mCoefficients[mCoefficientCursor]; + float *xFrame = &mX[mCursor * MONO]; + const int numLoops = mNumTaps >> 2; // n/4 + for (int i = 0; i < numLoops; i++) { + // Manual loop unrolling, might get converted to SIMD. + sum += *xFrame++ * *coefficients++; + sum += *xFrame++ * *coefficients++; + sum += *xFrame++ * *coefficients++; + sum += *xFrame++ * *coefficients++; + } + + mCoefficientCursor = (mCoefficientCursor + mNumTaps) % mCoefficients.size(); + + // Copy accumulator to output. + frame[0] = sum; +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResamplerMono.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResamplerMono.h new file mode 100644 index 0000000..d97b513 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResamplerMono.h @@ -0,0 +1,39 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_POLYPHASE_RESAMPLER_MONO_H +#define OBOE_POLYPHASE_RESAMPLER_MONO_H + +#include +#include +#include "PolyphaseResampler.h" + +namespace resampler { + +class PolyphaseResamplerMono : public PolyphaseResampler { +public: + explicit PolyphaseResamplerMono(const MultiChannelResampler::Builder &builder); + + virtual ~PolyphaseResamplerMono() = default; + + void writeFrame(const float *frame) override; + + void readFrame(float *frame) override; +}; + +} + +#endif //OBOE_POLYPHASE_RESAMPLER_MONO_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResamplerStereo.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResamplerStereo.cpp new file mode 100644 index 0000000..5c73a8e --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResamplerStereo.cpp @@ -0,0 +1,78 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "PolyphaseResamplerStereo.h" + +using namespace resampler; + +#define STEREO 2 + +PolyphaseResamplerStereo::PolyphaseResamplerStereo(const MultiChannelResampler::Builder &builder) + : PolyphaseResampler(builder) { + assert(builder.getChannelCount() == STEREO); +} + +void PolyphaseResamplerStereo::writeFrame(const float *frame) { + // Move cursor before write so that cursor points to last written frame in read. + if (--mCursor < 0) { + mCursor = getNumTaps() - 1; + } + float *dest = &mX[mCursor * STEREO]; + const int offset = mNumTaps * STEREO; + // Write each channel twice so we avoid having to wrap when running the FIR. + const float left = frame[0]; + const float right = frame[1]; + // Put ordered writes together. + dest[0] = left; + dest[1] = right; + dest[offset] = left; + dest[1 + offset] = right; +} + +void PolyphaseResamplerStereo::readFrame(float *frame) { + // Clear accumulators. + float left = 0.0; + float right = 0.0; + + // Multiply input times precomputed windowed sinc function. + const float *coefficients = &mCoefficients[mCoefficientCursor]; + float *xFrame = &mX[mCursor * STEREO]; + const int numLoops = mNumTaps >> 2; // n/4 + for (int i = 0; i < numLoops; i++) { + // Manual loop unrolling, might get converted to SIMD. + float coefficient = *coefficients++; + left += *xFrame++ * coefficient; + right += *xFrame++ * coefficient; + + coefficient = *coefficients++; // next tap + left += *xFrame++ * coefficient; + right += *xFrame++ * coefficient; + + coefficient = *coefficients++; // next tap + left += *xFrame++ * coefficient; + right += *xFrame++ * coefficient; + + coefficient = *coefficients++; // next tap + left += *xFrame++ * coefficient; + right += *xFrame++ * coefficient; + } + + mCoefficientCursor = (mCoefficientCursor + mNumTaps) % mCoefficients.size(); + + // Copy accumulators to output. + frame[0] = left; + frame[1] = right; +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResamplerStereo.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResamplerStereo.h new file mode 100644 index 0000000..3dfd4e2 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/PolyphaseResamplerStereo.h @@ -0,0 +1,39 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_POLYPHASE_RESAMPLER_STEREO_H +#define OBOE_POLYPHASE_RESAMPLER_STEREO_H + +#include +#include +#include "PolyphaseResampler.h" + +namespace resampler { + +class PolyphaseResamplerStereo : public PolyphaseResampler { +public: + explicit PolyphaseResamplerStereo(const MultiChannelResampler::Builder &builder); + + virtual ~PolyphaseResamplerStereo() = default; + + void writeFrame(const float *frame) override; + + void readFrame(float *frame) override; +}; + +} + +#endif //OBOE_POLYPHASE_RESAMPLER_STEREO_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/SincResampler.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/SincResampler.cpp new file mode 100644 index 0000000..1084356 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/SincResampler.cpp @@ -0,0 +1,76 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "SincResampler.h" + +using namespace resampler; + +SincResampler::SincResampler(const MultiChannelResampler::Builder &builder) + : MultiChannelResampler(builder) + , mSingleFrame2(builder.getChannelCount()) { + assert((getNumTaps() % 4) == 0); // Required for loop unrolling. + mNumRows = kMaxCoefficients / getNumTaps(); // no guard row needed +// printf("SincResampler: numRows = %d\n", mNumRows); + mPhaseScaler = (double) mNumRows / mDenominator; + double phaseIncrement = 1.0 / mNumRows; + generateCoefficients(builder.getInputRate(), + builder.getOutputRate(), + mNumRows, + phaseIncrement, + builder.getNormalizedCutoff()); +} + +void SincResampler::readFrame(float *frame) { + // Clear accumulator for mixing. + std::fill(mSingleFrame.begin(), mSingleFrame.end(), 0.0); + std::fill(mSingleFrame2.begin(), mSingleFrame2.end(), 0.0); + + // Determine indices into coefficients table. + double tablePhase = getIntegerPhase() * mPhaseScaler; + int index1 = static_cast(floor(tablePhase)); + if (index1 >= mNumRows) { // no guard row needed because we wrap the indices + tablePhase -= mNumRows; + index1 -= mNumRows; + } + + int index2 = index1 + 1; + if (index2 >= mNumRows) { // no guard row needed because we wrap the indices + index2 -= mNumRows; + } + + float *coefficients1 = &mCoefficients[index1 * getNumTaps()]; + float *coefficients2 = &mCoefficients[index2 * getNumTaps()]; + + float *xFrame = &mX[mCursor * getChannelCount()]; + for (int i = 0; i < mNumTaps; i++) { + float coefficient1 = *coefficients1++; + float coefficient2 = *coefficients2++; + for (int channel = 0; channel < getChannelCount(); channel++) { + float sample = *xFrame++; + mSingleFrame[channel] += sample * coefficient1; + mSingleFrame2[channel] += sample * coefficient2; + } + } + + // Interpolate and copy to output. + float fraction = tablePhase - index1; + for (int channel = 0; channel < getChannelCount(); channel++) { + float low = mSingleFrame[channel]; + float high = mSingleFrame2[channel]; + frame[channel] = low + (fraction * (high - low)); + } +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/SincResampler.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/SincResampler.h new file mode 100644 index 0000000..6ab61c9 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/SincResampler.h @@ -0,0 +1,47 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_SINC_RESAMPLER_H +#define OBOE_SINC_RESAMPLER_H + +#include +#include +#include +#include "MultiChannelResampler.h" + +namespace resampler { + +/** + * Resampler that can interpolate between coefficients. + * This can be used to support arbitrary ratios. + */ +class SincResampler : public MultiChannelResampler { +public: + explicit SincResampler(const MultiChannelResampler::Builder &builder); + + virtual ~SincResampler() = default; + + void readFrame(float *frame) override; + +protected: + + std::vector mSingleFrame2; // for interpolation + int32_t mNumRows = 0; + double mPhaseScaler = 1.0; +}; + +} +#endif //OBOE_SINC_RESAMPLER_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/SincResamplerStereo.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/SincResamplerStereo.cpp new file mode 100644 index 0000000..bde658a --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/SincResamplerStereo.cpp @@ -0,0 +1,80 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "SincResamplerStereo.h" + +using namespace resampler; + +#define STEREO 2 + +SincResamplerStereo::SincResamplerStereo(const MultiChannelResampler::Builder &builder) + : SincResampler(builder) { + assert(builder.getChannelCount() == STEREO); +} + +void SincResamplerStereo::writeFrame(const float *frame) { + // Move cursor before write so that cursor points to last written frame in read. + if (--mCursor < 0) { + mCursor = getNumTaps() - 1; + } + float *dest = &mX[mCursor * STEREO]; + const int offset = mNumTaps * STEREO; + // Write each channel twice so we avoid having to wrap when running the FIR. + const float left = frame[0]; + const float right = frame[1]; + // Put ordered writes together. + dest[0] = left; + dest[1] = right; + dest[offset] = left; + dest[1 + offset] = right; +} + +// Multiply input times windowed sinc function. +void SincResamplerStereo::readFrame(float *frame) { + // Clear accumulator for mixing. + std::fill(mSingleFrame.begin(), mSingleFrame.end(), 0.0); + std::fill(mSingleFrame2.begin(), mSingleFrame2.end(), 0.0); + + // Determine indices into coefficients table. + double tablePhase = getIntegerPhase() * mPhaseScaler; + int index1 = static_cast(floor(tablePhase)); + float *coefficients1 = &mCoefficients[index1 * getNumTaps()]; + int index2 = (index1 + 1); + if (index2 >= mNumRows) { // no guard row needed because we wrap the indices + index2 = 0; + } + float *coefficients2 = &mCoefficients[index2 * getNumTaps()]; + float *xFrame = &mX[mCursor * getChannelCount()]; + for (int i = 0; i < mNumTaps; i++) { + float coefficient1 = *coefficients1++; + float coefficient2 = *coefficients2++; + for (int channel = 0; channel < getChannelCount(); channel++) { + float sample = *xFrame++; + mSingleFrame[channel] += sample * coefficient1; + mSingleFrame2[channel] += sample * coefficient2; + } + } + + // Interpolate and copy to output. + float fraction = tablePhase - index1; + for (int channel = 0; channel < getChannelCount(); channel++) { + float low = mSingleFrame[channel]; + float high = mSingleFrame2[channel]; + frame[channel] = low + (fraction * (high - low)); + } +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/SincResamplerStereo.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/SincResamplerStereo.h new file mode 100644 index 0000000..7d66c26 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/flowgraph/resampler/SincResamplerStereo.h @@ -0,0 +1,39 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_SINC_RESAMPLER_STEREO_H +#define OBOE_SINC_RESAMPLER_STEREO_H + +#include +#include +#include "SincResampler.h" + +namespace resampler { + +class SincResamplerStereo : public SincResampler { +public: + explicit SincResamplerStereo(const MultiChannelResampler::Builder &builder); + + virtual ~SincResamplerStereo() = default; + + void writeFrame(const float *frame) override; + + void readFrame(float *frame) override; + +}; + +} +#endif //OBOE_SINC_RESAMPLER_STEREO_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioInputStreamOpenSLES.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioInputStreamOpenSLES.cpp new file mode 100644 index 0000000..fcad183 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioInputStreamOpenSLES.cpp @@ -0,0 +1,352 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include + +#include "oboe/AudioStreamBuilder.h" +#include "AudioInputStreamOpenSLES.h" +#include "AudioStreamOpenSLES.h" +#include "OpenSLESUtilities.h" + +using namespace oboe; + +static SLuint32 OpenSLES_convertInputPreset(InputPreset oboePreset) { + SLuint32 openslPreset = SL_ANDROID_RECORDING_PRESET_NONE; + switch(oboePreset) { + case InputPreset::Generic: + openslPreset = SL_ANDROID_RECORDING_PRESET_GENERIC; + break; + case InputPreset::Camcorder: + openslPreset = SL_ANDROID_RECORDING_PRESET_CAMCORDER; + break; + case InputPreset::VoiceRecognition: + openslPreset = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION; + break; + case InputPreset::VoiceCommunication: + openslPreset = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION; + break; + case InputPreset::Unprocessed: + openslPreset = SL_ANDROID_RECORDING_PRESET_UNPROCESSED; + break; + default: + break; + } + return openslPreset; +} + +AudioInputStreamOpenSLES::AudioInputStreamOpenSLES(const AudioStreamBuilder &builder) + : AudioStreamOpenSLES(builder) { +} + +AudioInputStreamOpenSLES::~AudioInputStreamOpenSLES() { +} + +// Calculate masks specific to INPUT streams. +SLuint32 AudioInputStreamOpenSLES::channelCountToChannelMask(int channelCount) const { + // Derived from internal sles_channel_in_mask_from_count(chanCount); + // in "frameworks/wilhelm/src/android/channels.cpp". + // Yes, it seems strange to use SPEAKER constants to describe inputs. + // But that is how OpenSL ES does it internally. + switch (channelCount) { + case 1: + return SL_SPEAKER_FRONT_LEFT; + case 2: + return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; + default: + return channelCountToChannelMaskDefault(channelCount); + } +} + +Result AudioInputStreamOpenSLES::open() { + logUnsupportedAttributes(); + + SLAndroidConfigurationItf configItf = nullptr; + + if (getSdkVersion() < __ANDROID_API_M__ && mFormat == AudioFormat::Float){ + // TODO: Allow floating point format on API <23 using float->int16 converter + return Result::ErrorInvalidFormat; + } + + // If audio format is unspecified then choose a suitable default. + // API 23+: FLOAT + // API <23: INT16 + if (mFormat == AudioFormat::Unspecified){ + mFormat = (getSdkVersion() < __ANDROID_API_M__) ? + AudioFormat::I16 : AudioFormat::Float; + } + + Result oboeResult = AudioStreamOpenSLES::open(); + if (Result::OK != oboeResult) return oboeResult; + + SLuint32 bitsPerSample = static_cast(getBytesPerSample() * kBitsPerByte); + + // configure audio sink + SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { + SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, // locatorType + static_cast(kBufferQueueLength)}; // numBuffers + + // Define the audio data format. + SLDataFormat_PCM format_pcm = { + SL_DATAFORMAT_PCM, // formatType + static_cast(mChannelCount), // numChannels + static_cast(mSampleRate * kMillisPerSecond), // milliSamplesPerSec + bitsPerSample, // bitsPerSample + bitsPerSample, // containerSize; + channelCountToChannelMask(mChannelCount), // channelMask + getDefaultByteOrder(), + }; + + SLDataSink audioSink = {&loc_bufq, &format_pcm}; + + /** + * API 23 (Marshmallow) introduced support for floating-point data representation and an + * extended data format type: SLAndroidDataFormat_PCM_EX for recording streams (playback streams + * got this in API 21). If running on API 23+ use this newer format type, creating it from our + * original format. + */ + SLAndroidDataFormat_PCM_EX format_pcm_ex; + if (getSdkVersion() >= __ANDROID_API_M__) { + SLuint32 representation = OpenSLES_ConvertFormatToRepresentation(getFormat()); + // Fill in the format structure. + format_pcm_ex = OpenSLES_createExtendedFormat(format_pcm, representation); + // Use in place of the previous format. + audioSink.pFormat = &format_pcm_ex; + } + + + // configure audio source + SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, + SL_IODEVICE_AUDIOINPUT, + SL_DEFAULTDEVICEID_AUDIOINPUT, + NULL}; + SLDataSource audioSrc = {&loc_dev, NULL}; + + SLresult result = EngineOpenSLES::getInstance().createAudioRecorder(&mObjectInterface, + &audioSrc, + &audioSink); + + if (SL_RESULT_SUCCESS != result) { + LOGE("createAudioRecorder() result:%s", getSLErrStr(result)); + goto error; + } + + // Configure the stream. + result = (*mObjectInterface)->GetInterface(mObjectInterface, + SL_IID_ANDROIDCONFIGURATION, + &configItf); + + if (SL_RESULT_SUCCESS != result) { + LOGW("%s() GetInterface(SL_IID_ANDROIDCONFIGURATION) failed with %s", + __func__, getSLErrStr(result)); + } else { + SLuint32 presetValue = OpenSLES_convertInputPreset(getInputPreset()); + result = (*configItf)->SetConfiguration(configItf, + SL_ANDROID_KEY_RECORDING_PRESET, + &presetValue, + sizeof(SLuint32)); + if (SL_RESULT_SUCCESS != result + && presetValue != SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION) { + presetValue = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION; + mInputPreset = InputPreset::VoiceRecognition; + (*configItf)->SetConfiguration(configItf, + SL_ANDROID_KEY_RECORDING_PRESET, + &presetValue, + sizeof(SLuint32)); + } + + result = configurePerformanceMode(configItf); + if (SL_RESULT_SUCCESS != result) { + goto error; + } + } + + result = (*mObjectInterface)->Realize(mObjectInterface, SL_BOOLEAN_FALSE); + if (SL_RESULT_SUCCESS != result) { + LOGE("Realize recorder object result:%s", getSLErrStr(result)); + goto error; + } + + result = (*mObjectInterface)->GetInterface(mObjectInterface, SL_IID_RECORD, &mRecordInterface); + if (SL_RESULT_SUCCESS != result) { + LOGE("GetInterface RECORD result:%s", getSLErrStr(result)); + goto error; + } + + result = AudioStreamOpenSLES::registerBufferQueueCallback(); + if (SL_RESULT_SUCCESS != result) { + goto error; + } + + result = updateStreamParameters(configItf); + if (SL_RESULT_SUCCESS != result) { + goto error; + } + + oboeResult = configureBufferSizes(mSampleRate); + if (Result::OK != oboeResult) { + goto error; + } + + allocateFifo(); + + setState(StreamState::Open); + return Result::OK; + +error: + return Result::ErrorInternal; // TODO convert error from SLES to OBOE +} + +Result AudioInputStreamOpenSLES::close() { + LOGD("AudioInputStreamOpenSLES::%s()", __func__); + mLock.lock(); + Result result = Result::OK; + if (getState() == StreamState::Closed){ + result = Result::ErrorClosed; + } else { + mLock.unlock(); // avoid recursive lock + requestStop(); + mLock.lock(); + // invalidate any interfaces + mRecordInterface = nullptr; + result = AudioStreamOpenSLES::close(); + } + mLock.unlock(); // avoid recursive lock + return result; +} + +Result AudioInputStreamOpenSLES::setRecordState_l(SLuint32 newState) { + LOGD("AudioInputStreamOpenSLES::%s(%u)", __func__, newState); + Result result = Result::OK; + + if (mRecordInterface == nullptr) { + LOGE("AudioInputStreamOpenSLES::%s() mRecordInterface is null", __func__); + return Result::ErrorInvalidState; + } + SLresult slResult = (*mRecordInterface)->SetRecordState(mRecordInterface, newState); + //LOGD("AudioInputStreamOpenSLES::%s(%u) returned %u", __func__, newState, slResult); + if (SL_RESULT_SUCCESS != slResult) { + LOGE("AudioInputStreamOpenSLES::%s(%u) returned error %s", + __func__, newState, getSLErrStr(slResult)); + result = Result::ErrorInternal; // TODO review + } + return result; +} + +Result AudioInputStreamOpenSLES::requestStart() { + LOGD("AudioInputStreamOpenSLES(): %s() called", __func__); + std::lock_guard lock(mLock); + StreamState initialState = getState(); + switch (initialState) { + case StreamState::Starting: + case StreamState::Started: + return Result::OK; + case StreamState::Closed: + return Result::ErrorClosed; + default: + break; + } + + // We use a callback if the user requests one + // OR if we have an internal callback to fill the blocking IO buffer. + setDataCallbackEnabled(true); + + setState(StreamState::Starting); + Result result = setRecordState_l(SL_RECORDSTATE_RECORDING); + if (result == Result::OK) { + setState(StreamState::Started); + // Enqueue the first buffer to start the streaming. + // This does not call the callback function. + enqueueCallbackBuffer(mSimpleBufferQueueInterface); + } else { + setState(initialState); + } + return result; +} + + +Result AudioInputStreamOpenSLES::requestPause() { + LOGW("AudioInputStreamOpenSLES::%s() is intentionally not implemented for input " + "streams", __func__); + return Result::ErrorUnimplemented; // Matches AAudio behavior. +} + +Result AudioInputStreamOpenSLES::requestFlush() { + LOGW("AudioInputStreamOpenSLES::%s() is intentionally not implemented for input " + "streams", __func__); + return Result::ErrorUnimplemented; // Matches AAudio behavior. +} + +Result AudioInputStreamOpenSLES::requestStop() { + LOGD("AudioInputStreamOpenSLES(): %s() called", __func__); + + std::lock_guard lock(mLock); + StreamState initialState = getState(); + switch (initialState) { + case StreamState::Stopping: + case StreamState::Stopped: + return Result::OK; + case StreamState::Closed: + return Result::ErrorClosed; + default: + break; + } + + setState(StreamState::Stopping); + + Result result = setRecordState_l(SL_RECORDSTATE_STOPPED); + if (result == Result::OK) { + mPositionMillis.reset32(); // OpenSL ES resets its millisecond position when stopped. + setState(StreamState::Stopped); + } else { + setState(initialState); + } + return result; +} + +void AudioInputStreamOpenSLES::updateFramesWritten() { + if (usingFIFO()) { + AudioStreamBuffered::updateFramesWritten(); + } else { + mFramesWritten = getFramesProcessedByServer(); + } +} + +Result AudioInputStreamOpenSLES::updateServiceFrameCounter() { + Result result = Result::OK; + // Avoid deadlock if another thread is trying to stop or close this stream + // and this is being called from a callback. + if (mLock.try_lock()) { + + if (mRecordInterface == nullptr) { + mLock.unlock(); + return Result::ErrorNull; + } + SLmillisecond msec = 0; + SLresult slResult = (*mRecordInterface)->GetPosition(mRecordInterface, &msec); + if (SL_RESULT_SUCCESS != slResult) { + LOGW("%s(): GetPosition() returned %s", __func__, getSLErrStr(slResult)); + // set result based on SLresult + result = Result::ErrorInternal; + } else { + mPositionMillis.update32(msec); + } + mLock.unlock(); + } + return result; +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioInputStreamOpenSLES.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioInputStreamOpenSLES.h new file mode 100644 index 0000000..7be1c96 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioInputStreamOpenSLES.h @@ -0,0 +1,65 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AUDIO_INPUT_STREAM_OPENSL_ES_H_ +#define AUDIO_INPUT_STREAM_OPENSL_ES_H_ + + +#include +#include + +#include "oboe/Oboe.h" +#include "AudioStreamOpenSLES.h" + +namespace oboe { + +/** + * INTERNAL USE ONLY + */ + +class AudioInputStreamOpenSLES : public AudioStreamOpenSLES { +public: + AudioInputStreamOpenSLES(); + explicit AudioInputStreamOpenSLES(const AudioStreamBuilder &builder); + + virtual ~AudioInputStreamOpenSLES(); + + Result open() override; + Result close() override; + + Result requestStart() override; + Result requestPause() override; + Result requestFlush() override; + Result requestStop() override; + +protected: + + Result updateServiceFrameCounter() override; + + void updateFramesWritten() override; + +private: + + SLuint32 channelCountToChannelMask(int chanCount) const; + + Result setRecordState_l(SLuint32 newState); + + SLRecordItf mRecordInterface = nullptr; +}; + +} // namespace oboe + +#endif //AUDIO_INPUT_STREAM_OPENSL_ES_H_ diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioOutputStreamOpenSLES.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioOutputStreamOpenSLES.cpp new file mode 100644 index 0000000..cdb8883 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioOutputStreamOpenSLES.cpp @@ -0,0 +1,448 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include + +#include "oboe/AudioStreamBuilder.h" +#include "AudioOutputStreamOpenSLES.h" +#include "AudioStreamOpenSLES.h" +#include "OpenSLESUtilities.h" +#include "OutputMixerOpenSLES.h" + +using namespace oboe; + +static SLuint32 OpenSLES_convertOutputUsage(Usage oboeUsage) { + SLuint32 openslStream = SL_ANDROID_STREAM_MEDIA; + switch(oboeUsage) { + case Usage::Media: + openslStream = SL_ANDROID_STREAM_MEDIA; + break; + case Usage::VoiceCommunication: + case Usage::VoiceCommunicationSignalling: + openslStream = SL_ANDROID_STREAM_VOICE; + break; + case Usage::Alarm: + openslStream = SL_ANDROID_STREAM_ALARM; + break; + case Usage::Notification: + case Usage::NotificationRingtone: + case Usage::NotificationEvent: + openslStream = SL_ANDROID_STREAM_NOTIFICATION; + break; + case Usage::AssistanceAccessibility: + case Usage::AssistanceNavigationGuidance: + case Usage::AssistanceSonification: + openslStream = SL_ANDROID_STREAM_SYSTEM; + break; + case Usage::Game: + openslStream = SL_ANDROID_STREAM_MEDIA; + break; + case Usage::Assistant: + default: + openslStream = SL_ANDROID_STREAM_SYSTEM; + break; + } + return openslStream; +} + +AudioOutputStreamOpenSLES::AudioOutputStreamOpenSLES(const AudioStreamBuilder &builder) + : AudioStreamOpenSLES(builder) { +} + +// These will wind up in +constexpr int SL_ANDROID_SPEAKER_STEREO = (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT); + +constexpr int SL_ANDROID_SPEAKER_QUAD = (SL_ANDROID_SPEAKER_STEREO + | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT); + +constexpr int SL_ANDROID_SPEAKER_5DOT1 = (SL_ANDROID_SPEAKER_QUAD + | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY); + +constexpr int SL_ANDROID_SPEAKER_7DOT1 = (SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_SIDE_LEFT + | SL_SPEAKER_SIDE_RIGHT); + +SLuint32 AudioOutputStreamOpenSLES::channelCountToChannelMask(int channelCount) const { + SLuint32 channelMask = 0; + + switch (channelCount) { + case 1: + channelMask = SL_SPEAKER_FRONT_CENTER; + break; + + case 2: + channelMask = SL_ANDROID_SPEAKER_STEREO; + break; + + case 4: // Quad + channelMask = SL_ANDROID_SPEAKER_QUAD; + break; + + case 6: // 5.1 + channelMask = SL_ANDROID_SPEAKER_5DOT1; + break; + + case 8: // 7.1 + channelMask = SL_ANDROID_SPEAKER_7DOT1; + break; + + default: + channelMask = channelCountToChannelMaskDefault(channelCount); + break; + } + return channelMask; +} + +Result AudioOutputStreamOpenSLES::open() { + logUnsupportedAttributes(); + + SLAndroidConfigurationItf configItf = nullptr; + + + if (getSdkVersion() < __ANDROID_API_L__ && mFormat == AudioFormat::Float){ + // TODO: Allow floating point format on API <21 using float->int16 converter + return Result::ErrorInvalidFormat; + } + + // If audio format is unspecified then choose a suitable default. + // API 21+: FLOAT + // API <21: INT16 + if (mFormat == AudioFormat::Unspecified){ + mFormat = (getSdkVersion() < __ANDROID_API_L__) ? + AudioFormat::I16 : AudioFormat::Float; + } + + Result oboeResult = AudioStreamOpenSLES::open(); + if (Result::OK != oboeResult) return oboeResult; + + SLresult result = OutputMixerOpenSL::getInstance().open(); + if (SL_RESULT_SUCCESS != result) { + AudioStreamOpenSLES::close(); + return Result::ErrorInternal; + } + + SLuint32 bitsPerSample = static_cast(getBytesPerSample() * kBitsPerByte); + + // configure audio source + SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { + SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, // locatorType + static_cast(kBufferQueueLength)}; // numBuffers + + // Define the audio data format. + SLDataFormat_PCM format_pcm = { + SL_DATAFORMAT_PCM, // formatType + static_cast(mChannelCount), // numChannels + static_cast(mSampleRate * kMillisPerSecond), // milliSamplesPerSec + bitsPerSample, // bitsPerSample + bitsPerSample, // containerSize; + channelCountToChannelMask(mChannelCount), // channelMask + getDefaultByteOrder(), + }; + + SLDataSource audioSrc = {&loc_bufq, &format_pcm}; + + /** + * API 21 (Lollipop) introduced support for floating-point data representation and an extended + * data format type: SLAndroidDataFormat_PCM_EX. If running on API 21+ use this newer format + * type, creating it from our original format. + */ + SLAndroidDataFormat_PCM_EX format_pcm_ex; + if (getSdkVersion() >= __ANDROID_API_L__) { + SLuint32 representation = OpenSLES_ConvertFormatToRepresentation(getFormat()); + // Fill in the format structure. + format_pcm_ex = OpenSLES_createExtendedFormat(format_pcm, representation); + // Use in place of the previous format. + audioSrc.pFormat = &format_pcm_ex; + } + + result = OutputMixerOpenSL::getInstance().createAudioPlayer(&mObjectInterface, + &audioSrc); + if (SL_RESULT_SUCCESS != result) { + LOGE("createAudioPlayer() result:%s", getSLErrStr(result)); + goto error; + } + + // Configure the stream. + result = (*mObjectInterface)->GetInterface(mObjectInterface, + SL_IID_ANDROIDCONFIGURATION, + (void *)&configItf); + if (SL_RESULT_SUCCESS != result) { + LOGW("%s() GetInterface(SL_IID_ANDROIDCONFIGURATION) failed with %s", + __func__, getSLErrStr(result)); + } else { + result = configurePerformanceMode(configItf); + if (SL_RESULT_SUCCESS != result) { + goto error; + } + + SLuint32 presetValue = OpenSLES_convertOutputUsage(getUsage()); + result = (*configItf)->SetConfiguration(configItf, + SL_ANDROID_KEY_STREAM_TYPE, + &presetValue, + sizeof(presetValue)); + if (SL_RESULT_SUCCESS != result) { + goto error; + } + } + + result = (*mObjectInterface)->Realize(mObjectInterface, SL_BOOLEAN_FALSE); + if (SL_RESULT_SUCCESS != result) { + LOGE("Realize player object result:%s", getSLErrStr(result)); + goto error; + } + + result = (*mObjectInterface)->GetInterface(mObjectInterface, SL_IID_PLAY, &mPlayInterface); + if (SL_RESULT_SUCCESS != result) { + LOGE("GetInterface PLAY result:%s", getSLErrStr(result)); + goto error; + } + + result = AudioStreamOpenSLES::registerBufferQueueCallback(); + if (SL_RESULT_SUCCESS != result) { + goto error; + } + + result = updateStreamParameters(configItf); + if (SL_RESULT_SUCCESS != result) { + goto error; + } + + oboeResult = configureBufferSizes(mSampleRate); + if (Result::OK != oboeResult) { + goto error; + } + + allocateFifo(); + + setState(StreamState::Open); + return Result::OK; + +error: + return Result::ErrorInternal; // TODO convert error from SLES to OBOE +} + +Result AudioOutputStreamOpenSLES::onAfterDestroy() { + OutputMixerOpenSL::getInstance().close(); + return Result::OK; +} + +Result AudioOutputStreamOpenSLES::close() { + mLock.lock(); + Result result = Result::OK; + if (getState() == StreamState::Closed){ + result = Result::ErrorClosed; + } else { + mLock.unlock(); // avoid recursive lock + requestPause(); + mLock.lock(); + // invalidate any interfaces + mPlayInterface = nullptr; + result = AudioStreamOpenSLES::close(); + } + mLock.unlock(); // avoid recursive lock + return result; +} + +Result AudioOutputStreamOpenSLES::setPlayState_l(SLuint32 newState) { + + LOGD("AudioOutputStreamOpenSLES(): %s() called", __func__); + Result result = Result::OK; + + if (mPlayInterface == nullptr){ + LOGE("AudioOutputStreamOpenSLES::%s() mPlayInterface is null", __func__); + return Result::ErrorInvalidState; + } + + SLresult slResult = (*mPlayInterface)->SetPlayState(mPlayInterface, newState); + if (SL_RESULT_SUCCESS != slResult) { + LOGW("AudioOutputStreamOpenSLES(): %s() returned %s", __func__, getSLErrStr(slResult)); + result = Result::ErrorInternal; // TODO convert slResult to Result::Error + } + return result; +} + +Result AudioOutputStreamOpenSLES::requestStart() { + LOGD("AudioOutputStreamOpenSLES(): %s() called", __func__); + + mLock.lock(); + StreamState initialState = getState(); + switch (initialState) { + case StreamState::Starting: + case StreamState::Started: + mLock.unlock(); + return Result::OK; + case StreamState::Closed: + mLock.unlock(); + return Result::ErrorClosed; + default: + break; + } + + // We use a callback if the user requests one + // OR if we have an internal callback to read the blocking IO buffer. + setDataCallbackEnabled(true); + + setState(StreamState::Starting); + Result result = setPlayState_l(SL_PLAYSTATE_PLAYING); + if (result == Result::OK) { + setState(StreamState::Started); + mLock.unlock(); + if (getBufferDepth(mSimpleBufferQueueInterface) == 0) { + // Enqueue the first buffer if needed to start the streaming. + // This might call requestStop() so try to avoid a recursive lock. + processBufferCallback(mSimpleBufferQueueInterface); + } + } else { + setState(initialState); + mLock.unlock(); + } + return result; +} + +Result AudioOutputStreamOpenSLES::requestPause() { + LOGD("AudioOutputStreamOpenSLES(): %s() called", __func__); + + std::lock_guard lock(mLock); + StreamState initialState = getState(); + switch (initialState) { + case StreamState::Pausing: + case StreamState::Paused: + return Result::OK; + case StreamState::Closed: + return Result::ErrorClosed; + default: + break; + } + + setState(StreamState::Pausing); + Result result = setPlayState_l(SL_PLAYSTATE_PAUSED); + if (result == Result::OK) { + // Note that OpenSL ES does NOT reset its millisecond position when OUTPUT is paused. + int64_t framesWritten = getFramesWritten(); + if (framesWritten >= 0) { + setFramesRead(framesWritten); + } + setState(StreamState::Paused); + } else { + setState(initialState); + } + return result; +} + +/** + * Flush/clear the queue buffers + */ +Result AudioOutputStreamOpenSLES::requestFlush() { + std::lock_guard lock(mLock); + return requestFlush_l(); +} + +Result AudioOutputStreamOpenSLES::requestFlush_l() { + LOGD("AudioOutputStreamOpenSLES(): %s() called", __func__); + if (getState() == StreamState::Closed) { + return Result::ErrorClosed; + } + + Result result = Result::OK; + if (mPlayInterface == nullptr || mSimpleBufferQueueInterface == nullptr) { + result = Result::ErrorInvalidState; + } else { + SLresult slResult = (*mSimpleBufferQueueInterface)->Clear(mSimpleBufferQueueInterface); + if (slResult != SL_RESULT_SUCCESS){ + LOGW("Failed to clear buffer queue. OpenSLES error: %d", result); + result = Result::ErrorInternal; + } + } + return result; +} + +Result AudioOutputStreamOpenSLES::requestStop() { + LOGD("AudioOutputStreamOpenSLES(): %s() called", __func__); + + std::lock_guard lock(mLock); + StreamState initialState = getState(); + switch (initialState) { + case StreamState::Stopping: + case StreamState::Stopped: + return Result::OK; + case StreamState::Closed: + return Result::ErrorClosed; + default: + break; + } + + setState(StreamState::Stopping); + + Result result = setPlayState_l(SL_PLAYSTATE_STOPPED); + if (result == Result::OK) { + + // Also clear the buffer queue so the old data won't be played if the stream is restarted. + // Call the _l function that expects to already be under a lock. + if (requestFlush_l() != Result::OK) { + LOGW("Failed to flush the stream. Error %s", convertToText(flush())); + } + + mPositionMillis.reset32(); // OpenSL ES resets its millisecond position when stopped. + int64_t framesWritten = getFramesWritten(); + if (framesWritten >= 0) { + setFramesRead(framesWritten); + } + setState(StreamState::Stopped); + } else { + setState(initialState); + } + return result; +} + +void AudioOutputStreamOpenSLES::setFramesRead(int64_t framesRead) { + int64_t millisWritten = framesRead * kMillisPerSecond / getSampleRate(); + mPositionMillis.set(millisWritten); +} + +void AudioOutputStreamOpenSLES::updateFramesRead() { + if (usingFIFO()) { + AudioStreamBuffered::updateFramesRead(); + } else { + mFramesRead = getFramesProcessedByServer(); + } +} + +Result AudioOutputStreamOpenSLES::updateServiceFrameCounter() { + Result result = Result::OK; + // Avoid deadlock if another thread is trying to stop or close this stream + // and this is being called from a callback. + if (mLock.try_lock()) { + + if (mPlayInterface == nullptr) { + mLock.unlock(); + return Result::ErrorNull; + } + SLmillisecond msec = 0; + SLresult slResult = (*mPlayInterface)->GetPosition(mPlayInterface, &msec); + if (SL_RESULT_SUCCESS != slResult) { + LOGW("%s(): GetPosition() returned %s", __func__, getSLErrStr(slResult)); + // set result based on SLresult + result = Result::ErrorInternal; + } else { + mPositionMillis.update32(msec); + } + mLock.unlock(); + } + return result; +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioOutputStreamOpenSLES.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioOutputStreamOpenSLES.h new file mode 100644 index 0000000..d74faf6 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioOutputStreamOpenSLES.h @@ -0,0 +1,77 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AUDIO_OUTPUT_STREAM_OPENSL_ES_H_ +#define AUDIO_OUTPUT_STREAM_OPENSL_ES_H_ + + +#include +#include + +#include "oboe/Oboe.h" +#include "AudioStreamOpenSLES.h" + +namespace oboe { + +/** + * INTERNAL USE ONLY + */ +class AudioOutputStreamOpenSLES : public AudioStreamOpenSLES { +public: + AudioOutputStreamOpenSLES(); + explicit AudioOutputStreamOpenSLES(const AudioStreamBuilder &builder); + + virtual ~AudioOutputStreamOpenSLES() = default; + + Result open() override; + Result close() override; + + Result requestStart() override; + Result requestPause() override; + Result requestFlush() override; + Result requestStop() override; + +protected: + + void setFramesRead(int64_t framesRead); + + Result updateServiceFrameCounter() override; + + void updateFramesRead() override; + +private: + + SLuint32 channelCountToChannelMask(int chanCount) const; + + Result onAfterDestroy() override; + + Result requestFlush_l(); + + /** + * Set OpenSL ES PLAYSTATE. + * + * @param newState SL_PLAYSTATE_PAUSED, SL_PLAYSTATE_PLAYING, SL_PLAYSTATE_STOPPED + * @return + */ + Result setPlayState_l(SLuint32 newState); + + SLPlayItf mPlayInterface = nullptr; + +}; + +} // namespace oboe + +#endif //AUDIO_OUTPUT_STREAM_OPENSL_ES_H_ diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioStreamBuffered.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioStreamBuffered.cpp new file mode 100644 index 0000000..85b9f8e --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioStreamBuffered.cpp @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "oboe/Oboe.h" + +#include "opensles/AudioStreamBuffered.h" +#include "common/AudioClock.h" + +namespace oboe { + +constexpr int kDefaultBurstsPerBuffer = 16; // arbitrary, allows dynamic latency tuning +constexpr int kMinBurstsPerBuffer = 4; // arbitrary, allows dynamic latency tuning +constexpr int kMinFramesPerBuffer = 48 * 32; // arbitrary + +/* + * AudioStream with a FifoBuffer + */ +AudioStreamBuffered::AudioStreamBuffered(const AudioStreamBuilder &builder) + : AudioStream(builder) { +} + +void AudioStreamBuffered::allocateFifo() { + // If the caller does not provide a callback use our own internal + // callback that reads data from the FIFO. + if (usingFIFO()) { + // FIFO is configured with the same format and channels as the stream. + int32_t capacityFrames = getBufferCapacityInFrames(); + if (capacityFrames == oboe::kUnspecified) { + capacityFrames = getFramesPerBurst() * kDefaultBurstsPerBuffer; + } else { + int32_t minFramesPerBufferByBursts = getFramesPerBurst() * kMinBurstsPerBuffer; + if (capacityFrames <= minFramesPerBufferByBursts) { + capacityFrames = minFramesPerBufferByBursts; + } else { + capacityFrames = std::max(kMinFramesPerBuffer, capacityFrames); + // round up to nearest burst + int32_t numBursts = (capacityFrames + getFramesPerBurst() - 1) + / getFramesPerBurst(); + capacityFrames = numBursts * getFramesPerBurst(); + } + } + // TODO consider using std::make_unique if we require c++14 + mFifoBuffer.reset(new FifoBuffer(getBytesPerFrame(), capacityFrames)); + mBufferCapacityInFrames = capacityFrames; + } +} + +void AudioStreamBuffered::updateFramesWritten() { + if (mFifoBuffer) { + mFramesWritten = static_cast(mFifoBuffer->getWriteCounter()); + } // or else it will get updated by processBufferCallback() +} + +void AudioStreamBuffered::updateFramesRead() { + if (mFifoBuffer) { + mFramesRead = static_cast(mFifoBuffer->getReadCounter()); + } // or else it will get updated by processBufferCallback() +} + +// This is called by the OpenSL ES callback to read or write the back end of the FIFO. +DataCallbackResult AudioStreamBuffered::onDefaultCallback(void *audioData, int numFrames) { + int32_t framesTransferred = 0; + + if (getDirection() == oboe::Direction::Output) { + // Read from the FIFO and write to audioData, clear part of buffer if not enough data. + framesTransferred = mFifoBuffer->readNow(audioData, numFrames); + } else { + // Read from audioData and write to the FIFO + framesTransferred = mFifoBuffer->write(audioData, numFrames); // There is no writeNow() + } + + if (framesTransferred < numFrames) { + LOGD("AudioStreamBuffered::%s(): xrun! framesTransferred = %d, numFrames = %d", + __func__, framesTransferred, numFrames); + // TODO If we do not allow FIFO to wrap then our timestamps will drift when there is an XRun! + incrementXRunCount(); + } + markCallbackTime(static_cast(numFrames)); // so foreground knows how long to wait. + return DataCallbackResult::Continue; +} + +void AudioStreamBuffered::markCallbackTime(int32_t numFrames) { + mLastBackgroundSize = numFrames; + mBackgroundRanAtNanoseconds = AudioClock::getNanoseconds(); +} + +int64_t AudioStreamBuffered::predictNextCallbackTime() { + if (mBackgroundRanAtNanoseconds == 0) { + return 0; + } + int64_t nanosPerBuffer = (kNanosPerSecond * mLastBackgroundSize) / getSampleRate(); + const int64_t margin = 200 * kNanosPerMicrosecond; // arbitrary delay so we wake up just after + return mBackgroundRanAtNanoseconds + nanosPerBuffer + margin; +} + +// Common code for read/write. +// @return Result::OK with frames read/written, or Result::Error* +ResultWithValue AudioStreamBuffered::transfer(void *buffer, + int32_t numFrames, + int64_t timeoutNanoseconds) { + // Validate arguments. + if (buffer == nullptr) { + LOGE("AudioStreamBuffered::%s(): buffer is NULL", __func__); + return ResultWithValue(Result::ErrorNull); + } + if (numFrames < 0) { + LOGE("AudioStreamBuffered::%s(): numFrames is negative", __func__); + return ResultWithValue(Result::ErrorOutOfRange); + } else if (numFrames == 0) { + return ResultWithValue(numFrames); + } + if (timeoutNanoseconds < 0) { + LOGE("AudioStreamBuffered::%s(): timeoutNanoseconds is negative", __func__); + return ResultWithValue(Result::ErrorOutOfRange); + } + + int32_t result = 0; + uint8_t *data = reinterpret_cast(buffer); + int32_t framesLeft = numFrames; + int64_t timeToQuit = 0; + bool repeat = true; + + // Calculate when to timeout. + if (timeoutNanoseconds > 0) { + timeToQuit = AudioClock::getNanoseconds() + timeoutNanoseconds; + } + + // Loop until we get the data, or we have an error, or we timeout. + do { + // read or write + if (getDirection() == Direction::Input) { + result = mFifoBuffer->read(data, framesLeft); + } else { + // between zero and capacity + uint32_t fullFrames = mFifoBuffer->getFullFramesAvailable(); + // Do not write above threshold size. + int32_t emptyFrames = getBufferSizeInFrames() - static_cast(fullFrames); + int32_t framesToWrite = std::max(0, std::min(framesLeft, emptyFrames)); + result = mFifoBuffer->write(data, framesToWrite); + } + if (result > 0) { + data += mFifoBuffer->convertFramesToBytes(result); + framesLeft -= result; + } + + // If we need more data then sleep and try again. + if (framesLeft > 0 && result >= 0 && timeoutNanoseconds > 0) { + int64_t timeNow = AudioClock::getNanoseconds(); + if (timeNow >= timeToQuit) { + LOGE("AudioStreamBuffered::%s(): TIMEOUT", __func__); + repeat = false; // TIMEOUT + } else { + // Figure out how long to sleep. + int64_t sleepForNanos; + int64_t wakeTimeNanos = predictNextCallbackTime(); + if (wakeTimeNanos <= 0) { + // No estimate available. Sleep for one burst. + sleepForNanos = (getFramesPerBurst() * kNanosPerSecond) / getSampleRate(); + } else { + // Don't sleep past timeout. + if (wakeTimeNanos > timeToQuit) { + wakeTimeNanos = timeToQuit; + } + sleepForNanos = wakeTimeNanos - timeNow; + // Avoid rapid loop with no sleep. + const int64_t minSleepTime = kNanosPerMillisecond; // arbitrary + if (sleepForNanos < minSleepTime) { + sleepForNanos = minSleepTime; + } + } + + AudioClock::sleepForNanos(sleepForNanos); + } + + } else { + repeat = false; + } + } while(repeat); + + if (result < 0) { + return ResultWithValue(static_cast(result)); + } else { + int32_t framesWritten = numFrames - framesLeft; + return ResultWithValue(framesWritten); + } +} + +// Write to the FIFO so the callback can read from it. +ResultWithValue AudioStreamBuffered::write(const void *buffer, + int32_t numFrames, + int64_t timeoutNanoseconds) { + if (getState() == StreamState::Closed){ + return ResultWithValue(Result::ErrorClosed); + } + + if (getDirection() == Direction::Input) { + return ResultWithValue(Result::ErrorUnavailable); // TODO review, better error code? + } + updateServiceFrameCounter(); + return transfer(const_cast(buffer), numFrames, timeoutNanoseconds); +} + +// Read data from the FIFO that was written by the callback. +ResultWithValue AudioStreamBuffered::read(void *buffer, + int32_t numFrames, + int64_t timeoutNanoseconds) { + if (getState() == StreamState::Closed){ + return ResultWithValue(Result::ErrorClosed); + } + + if (getDirection() == Direction::Output) { + return ResultWithValue(Result::ErrorUnavailable); // TODO review, better error code? + } + updateServiceFrameCounter(); + return transfer(buffer, numFrames, timeoutNanoseconds); +} + +// Only supported when we are not using a callback. +ResultWithValue AudioStreamBuffered::setBufferSizeInFrames(int32_t requestedFrames) +{ + if (getState() == StreamState::Closed){ + return ResultWithValue(Result::ErrorClosed); + } + + if (!mFifoBuffer) { + return ResultWithValue(Result::ErrorUnimplemented); + } + + if (requestedFrames > mFifoBuffer->getBufferCapacityInFrames()) { + requestedFrames = mFifoBuffer->getBufferCapacityInFrames(); + } else if (requestedFrames < getFramesPerBurst()) { + requestedFrames = getFramesPerBurst(); + } + mBufferSizeInFrames = requestedFrames; + return ResultWithValue(requestedFrames); +} + +int32_t AudioStreamBuffered::getBufferCapacityInFrames() const { + if (mFifoBuffer) { + return mFifoBuffer->getBufferCapacityInFrames(); + } else { + return AudioStream::getBufferCapacityInFrames(); + } +} + +bool AudioStreamBuffered::isXRunCountSupported() const { + // XRun count is only supported if we're using blocking I/O (not callbacks) + return (getCallback() == nullptr); +} + +} // namespace oboe \ No newline at end of file diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioStreamBuffered.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioStreamBuffered.h new file mode 100644 index 0000000..5923e8d --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioStreamBuffered.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_STREAM_BUFFERED_H +#define OBOE_STREAM_BUFFERED_H + +#include +#include +#include "common/OboeDebug.h" +#include "oboe/AudioStream.h" +#include "oboe/AudioStreamCallback.h" +#include "fifo/FifoBuffer.h" + +namespace oboe { + +// A stream that contains a FIFO buffer. +// This is used to implement blocking reads and writes. +class AudioStreamBuffered : public AudioStream { +public: + + AudioStreamBuffered(); + explicit AudioStreamBuffered(const AudioStreamBuilder &builder); + + void allocateFifo(); + + + ResultWithValue write(const void *buffer, + int32_t numFrames, + int64_t timeoutNanoseconds) override; + + ResultWithValue read(void *buffer, + int32_t numFrames, + int64_t timeoutNanoseconds) override; + + ResultWithValue setBufferSizeInFrames(int32_t requestedFrames) override; + + int32_t getBufferCapacityInFrames() const override; + + ResultWithValue getXRunCount() const override { + return ResultWithValue(mXRunCount); + } + + bool isXRunCountSupported() const override; + +protected: + + DataCallbackResult onDefaultCallback(void *audioData, int numFrames) override; + + // If there is no callback then we need a FIFO between the App and OpenSL ES. + bool usingFIFO() const { return getCallback() == nullptr; } + + virtual Result updateServiceFrameCounter() = 0; + + void updateFramesRead() override; + void updateFramesWritten() override; + +private: + + int64_t predictNextCallbackTime(); + + void markCallbackTime(int32_t numFrames); + + // Read or write to the FIFO. + ResultWithValue transfer(void *buffer, int32_t numFrames, int64_t timeoutNanoseconds); + + void incrementXRunCount() { + ++mXRunCount; + } + + std::unique_ptr mFifoBuffer{}; + + int64_t mBackgroundRanAtNanoseconds = 0; + int32_t mLastBackgroundSize = 0; + int32_t mXRunCount = 0; +}; + +} // namespace oboe + +#endif //OBOE_STREAM_BUFFERED_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioStreamOpenSLES.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioStreamOpenSLES.cpp new file mode 100644 index 0000000..3af1a30 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioStreamOpenSLES.cpp @@ -0,0 +1,396 @@ +/* Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include + + +#include +#include +#include +#include + +#include "common/OboeDebug.h" +#include "oboe/AudioStreamBuilder.h" +#include "AudioStreamOpenSLES.h" +#include "OpenSLESUtilities.h" + +using namespace oboe; + +AudioStreamOpenSLES::AudioStreamOpenSLES(const AudioStreamBuilder &builder) + : AudioStreamBuffered(builder) { + // OpenSL ES does not support device IDs. So overwrite value from builder. + mDeviceId = kUnspecified; + // OpenSL ES does not support session IDs. So overwrite value from builder. + mSessionId = SessionId::None; +} + +static constexpr int32_t kHighLatencyBufferSizeMillis = 20; // typical Android period +static constexpr SLuint32 kAudioChannelCountMax = 30; // TODO Why 30? +static constexpr SLuint32 SL_ANDROID_UNKNOWN_CHANNELMASK = 0; // Matches name used internally. + +SLuint32 AudioStreamOpenSLES::channelCountToChannelMaskDefault(int channelCount) const { + if (channelCount > kAudioChannelCountMax) { + return SL_ANDROID_UNKNOWN_CHANNELMASK; + } + + SLuint32 bitfield = (1 << channelCount) - 1; + + // Check for OS at run-time. + if(getSdkVersion() >= __ANDROID_API_N__) { + return SL_ANDROID_MAKE_INDEXED_CHANNEL_MASK(bitfield); + } + + // Indexed channels masks were added in N. + // For before N, the best we can do is use a positional channel mask. + return bitfield; +} + +static bool s_isLittleEndian() { + static uint32_t value = 1; + return (*reinterpret_cast(&value) == 1); // Does address point to LSB? +} + +SLuint32 AudioStreamOpenSLES::getDefaultByteOrder() { + return s_isLittleEndian() ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; +} + +Result AudioStreamOpenSLES::open() { + + LOGI("AudioStreamOpenSLES::open() chans=%d, rate=%d", mChannelCount, mSampleRate); + + SLresult result = EngineOpenSLES::getInstance().open(); + if (SL_RESULT_SUCCESS != result) { + return Result::ErrorInternal; + } + + Result oboeResult = AudioStreamBuffered::open(); + if (oboeResult != Result::OK) { + return oboeResult; + } + // Convert to defaults if UNSPECIFIED + if (mSampleRate == kUnspecified) { + mSampleRate = DefaultStreamValues::SampleRate; + } + if (mChannelCount == kUnspecified) { + mChannelCount = DefaultStreamValues::ChannelCount; + } + + mSharingMode = SharingMode::Shared; + + return Result::OK; +} + +Result AudioStreamOpenSLES::configureBufferSizes(int32_t sampleRate) { + LOGD("AudioStreamOpenSLES:%s(%d) initial mFramesPerBurst = %d, mFramesPerCallback = %d", + __func__, sampleRate, mFramesPerBurst, mFramesPerCallback); + // Decide frames per burst based on hints from caller. + if (mFramesPerCallback != kUnspecified) { + // Requested framesPerCallback must be honored. + mFramesPerBurst = mFramesPerCallback; + } else { + mFramesPerBurst = DefaultStreamValues::FramesPerBurst; + + // Calculate the size of a fixed duration high latency buffer based on sample rate. + int32_t framesPerHighLatencyBuffer = + (kHighLatencyBufferSizeMillis * sampleRate) / kMillisPerSecond; + + // For high latency streams, use a larger buffer size. + // Performance Mode support was added in N_MR1 (7.1) + if (getSdkVersion() >= __ANDROID_API_N_MR1__ + && mPerformanceMode != PerformanceMode::LowLatency + && mFramesPerBurst < framesPerHighLatencyBuffer) { + // Find a multiple of framesPerBurst >= framesPerHighLatencyBuffer. + int32_t numBursts = (framesPerHighLatencyBuffer + mFramesPerBurst - 1) / mFramesPerBurst; + mFramesPerBurst *= numBursts; + LOGD("AudioStreamOpenSLES:%s() NOT low latency, set mFramesPerBurst = %d", + __func__, mFramesPerBurst); + } + mFramesPerCallback = mFramesPerBurst; + } + LOGD("AudioStreamOpenSLES:%s(%d) final mFramesPerBurst = %d, mFramesPerCallback = %d", + __func__, sampleRate, mFramesPerBurst, mFramesPerCallback); + + mBytesPerCallback = mFramesPerCallback * getBytesPerFrame(); + if (mBytesPerCallback <= 0) { + LOGE("AudioStreamOpenSLES::open() bytesPerCallback < 0 = %d, bad format?", + mBytesPerCallback); + return Result::ErrorInvalidFormat; // causing bytesPerFrame == 0 + } + + mCallbackBuffer = std::make_unique(mBytesPerCallback); + + if (!usingFIFO()) { + mBufferCapacityInFrames = mFramesPerBurst * kBufferQueueLength; + mBufferSizeInFrames = mBufferCapacityInFrames; + } + + return Result::OK; +} + +SLuint32 AudioStreamOpenSLES::convertPerformanceMode(PerformanceMode oboeMode) const { + SLuint32 openslMode = SL_ANDROID_PERFORMANCE_NONE; + switch(oboeMode) { + case PerformanceMode::None: + openslMode = SL_ANDROID_PERFORMANCE_NONE; + break; + case PerformanceMode::LowLatency: + openslMode = (getSessionId() == SessionId::None) ? SL_ANDROID_PERFORMANCE_LATENCY : SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS; + break; + case PerformanceMode::PowerSaving: + openslMode = SL_ANDROID_PERFORMANCE_POWER_SAVING; + break; + default: + break; + } + return openslMode; +} + +PerformanceMode AudioStreamOpenSLES::convertPerformanceMode(SLuint32 openslMode) const { + PerformanceMode oboeMode = PerformanceMode::None; + switch(openslMode) { + case SL_ANDROID_PERFORMANCE_NONE: + oboeMode = PerformanceMode::None; + break; + case SL_ANDROID_PERFORMANCE_LATENCY: + case SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS: + oboeMode = PerformanceMode::LowLatency; + break; + case SL_ANDROID_PERFORMANCE_POWER_SAVING: + oboeMode = PerformanceMode::PowerSaving; + break; + default: + break; + } + return oboeMode; +} + +void AudioStreamOpenSLES::logUnsupportedAttributes() { + // Log unsupported attributes + // only report if changed from the default + + // Device ID + if (mDeviceId != kUnspecified) { + LOGW("Device ID [AudioStreamBuilder::setDeviceId()] " + "is not supported on OpenSLES streams."); + } + // Sharing Mode + if (mSharingMode != SharingMode::Shared) { + LOGW("SharingMode [AudioStreamBuilder::setSharingMode()] " + "is not supported on OpenSLES streams."); + } + // Performance Mode + int sdkVersion = getSdkVersion(); + if (mPerformanceMode != PerformanceMode::None && sdkVersion < __ANDROID_API_N_MR1__) { + LOGW("PerformanceMode [AudioStreamBuilder::setPerformanceMode()] " + "is not supported on OpenSLES streams running on pre-Android N-MR1 versions."); + } + // Content Type + if (mContentType != ContentType::Music) { + LOGW("ContentType [AudioStreamBuilder::setContentType()] " + "is not supported on OpenSLES streams."); + } + + // Session Id + if (mSessionId != SessionId::None) { + LOGW("SessionId [AudioStreamBuilder::setSessionId()] " + "is not supported on OpenSLES streams."); + } + + // Input Preset + if (mInputPreset != InputPreset::VoiceRecognition) { + LOGW("InputPreset [AudioStreamBuilder::setInputPreset()] " + "is not supported on OpenSLES streams."); + } +} + +SLresult AudioStreamOpenSLES::configurePerformanceMode(SLAndroidConfigurationItf configItf) { + + if (configItf == nullptr) { + LOGW("%s() called with NULL configuration", __func__); + mPerformanceMode = PerformanceMode::None; + return SL_RESULT_INTERNAL_ERROR; + } + if (getSdkVersion() < __ANDROID_API_N_MR1__) { + LOGW("%s() not supported until N_MR1", __func__); + mPerformanceMode = PerformanceMode::None; + return SL_RESULT_SUCCESS; + } + + SLresult result = SL_RESULT_SUCCESS; + SLuint32 performanceMode = convertPerformanceMode(getPerformanceMode()); + result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_PERFORMANCE_MODE, + &performanceMode, sizeof(performanceMode)); + if (SL_RESULT_SUCCESS != result) { + LOGW("SetConfiguration(PERFORMANCE_MODE, SL %u) returned %s", + performanceMode, getSLErrStr(result)); + mPerformanceMode = PerformanceMode::None; + } + + return result; +} + +SLresult AudioStreamOpenSLES::updateStreamParameters(SLAndroidConfigurationItf configItf) { + SLresult result = SL_RESULT_SUCCESS; + if(getSdkVersion() >= __ANDROID_API_N_MR1__ && configItf != nullptr) { + SLuint32 performanceMode = 0; + SLuint32 performanceModeSize = sizeof(performanceMode); + result = (*configItf)->GetConfiguration(configItf, SL_ANDROID_KEY_PERFORMANCE_MODE, + &performanceModeSize, &performanceMode); + // A bug in GetConfiguration() before P caused a wrong result code to be returned. + if (getSdkVersion() <= __ANDROID_API_O_MR1__) { + result = SL_RESULT_SUCCESS; // Ignore actual result before P. + } + + if (SL_RESULT_SUCCESS != result) { + LOGW("GetConfiguration(SL_ANDROID_KEY_PERFORMANCE_MODE) returned %d", result); + mPerformanceMode = PerformanceMode::None; // If we can't query it then assume None. + } else { + mPerformanceMode = convertPerformanceMode(performanceMode); // convert SL to Oboe mode + } + } else { + mPerformanceMode = PerformanceMode::None; // If we can't query it then assume None. + } + return result; +} + +Result AudioStreamOpenSLES::close() { + if (mState == StreamState::Closed) { + return Result::ErrorClosed; + } + + AudioStreamBuffered::close(); + + onBeforeDestroy(); + + if (mObjectInterface != nullptr) { + (*mObjectInterface)->Destroy(mObjectInterface); + mObjectInterface = nullptr; + } + + onAfterDestroy(); + + mSimpleBufferQueueInterface = nullptr; + EngineOpenSLES::getInstance().close(); + + setState(StreamState::Closed); + return Result::OK; +} + +SLresult AudioStreamOpenSLES::enqueueCallbackBuffer(SLAndroidSimpleBufferQueueItf bq) { + return (*bq)->Enqueue(bq, mCallbackBuffer.get(), mBytesPerCallback); +} + +int32_t AudioStreamOpenSLES::getBufferDepth(SLAndroidSimpleBufferQueueItf bq) { + SLAndroidSimpleBufferQueueState queueState; + SLresult result = (*bq)->GetState(bq, &queueState); + return (result == SL_RESULT_SUCCESS) ? queueState.count : -1; +} + +void AudioStreamOpenSLES::processBufferCallback(SLAndroidSimpleBufferQueueItf bq) { + bool stopStream = false; + // Ask the app callback to process the buffer. + DataCallbackResult result = fireDataCallback(mCallbackBuffer.get(), mFramesPerCallback); + if (result == DataCallbackResult::Continue) { + // Pass the buffer to OpenSLES. + SLresult enqueueResult = enqueueCallbackBuffer(bq); + if (enqueueResult != SL_RESULT_SUCCESS) { + LOGE("%s() returned %d", __func__, enqueueResult); + stopStream = true; + } + // Update Oboe client position with frames handled by the callback. + if (getDirection() == Direction::Input) { + mFramesRead += mFramesPerCallback; + } else { + mFramesWritten += mFramesPerCallback; + } + } else if (result == DataCallbackResult::Stop) { + LOGD("Oboe callback returned Stop"); + stopStream = true; + } else { + LOGW("Oboe callback returned unexpected value = %d", result); + stopStream = true; + } + if (stopStream) { + requestStop(); + } +} + +// This callback handler is called every time a buffer has been processed by OpenSL ES. +static void bqCallbackGlue(SLAndroidSimpleBufferQueueItf bq, void *context) { + (reinterpret_cast(context))->processBufferCallback(bq); +} + +SLresult AudioStreamOpenSLES::registerBufferQueueCallback() { + // The BufferQueue + SLresult result = (*mObjectInterface)->GetInterface(mObjectInterface, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &mSimpleBufferQueueInterface); + if (SL_RESULT_SUCCESS != result) { + LOGE("get buffer queue interface:%p result:%s", + mSimpleBufferQueueInterface, + getSLErrStr(result)); + } else { + // Register the BufferQueue callback + result = (*mSimpleBufferQueueInterface)->RegisterCallback(mSimpleBufferQueueInterface, + bqCallbackGlue, this); + if (SL_RESULT_SUCCESS != result) { + LOGE("RegisterCallback result:%s", getSLErrStr(result)); + } + } + return result; +} + +int32_t AudioStreamOpenSLES::getFramesPerBurst() { + return mFramesPerBurst; +} + +int64_t AudioStreamOpenSLES::getFramesProcessedByServer() { + updateServiceFrameCounter(); + int64_t millis64 = mPositionMillis.get(); + int64_t framesProcessed = millis64 * getSampleRate() / kMillisPerSecond; + return framesProcessed; +} + +Result AudioStreamOpenSLES::waitForStateChange(StreamState currentState, + StreamState *nextState, + int64_t timeoutNanoseconds) { + Result oboeResult = Result::ErrorTimeout; + int64_t sleepTimeNanos = 20 * kNanosPerMillisecond; // arbitrary + int64_t timeLeftNanos = timeoutNanoseconds; + + while (true) { + const StreamState state = getState(); // this does not require a lock + if (nextState != nullptr) { + *nextState = state; + } + if (currentState != state) { // state changed? + oboeResult = Result::OK; + break; + } + + // Did we timeout or did user ask for non-blocking? + if (timeoutNanoseconds <= 0) { + break; + } + + if (sleepTimeNanos > timeLeftNanos){ + sleepTimeNanos = timeLeftNanos; + } + AudioClock::sleepForNanos(sleepTimeNanos); + timeLeftNanos -= sleepTimeNanos; + } + + return oboeResult; +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioStreamOpenSLES.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioStreamOpenSLES.h new file mode 100644 index 0000000..81fdc63 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/AudioStreamOpenSLES.h @@ -0,0 +1,132 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_AUDIO_STREAM_OPENSL_ES_H_ +#define OBOE_AUDIO_STREAM_OPENSL_ES_H_ + +#include + +#include +#include + +#include "oboe/Oboe.h" +#include "common/MonotonicCounter.h" +#include "opensles/AudioStreamBuffered.h" +#include "opensles/EngineOpenSLES.h" + +namespace oboe { + +constexpr int kBitsPerByte = 8; +constexpr int kBufferQueueLength = 2; // double buffered for callbacks + +/** + * INTERNAL USE ONLY + * + * A stream that wraps OpenSL ES. + * + * Do not instantiate this class directly. + * Use an OboeStreamBuilder to create one. + */ + +class AudioStreamOpenSLES : public AudioStreamBuffered { +public: + + AudioStreamOpenSLES(); + explicit AudioStreamOpenSLES(const AudioStreamBuilder &builder); + + virtual ~AudioStreamOpenSLES() = default; + + virtual Result open() override; + virtual Result close() override; + + /** + * Query the current state, eg. OBOE_STREAM_STATE_PAUSING + * + * @return state or a negative error. + */ + StreamState getState() const override { return mState.load(); } + + int32_t getFramesPerBurst() override; + + + AudioApi getAudioApi() const override { + return AudioApi::OpenSLES; + } + + /** + * Process next OpenSL ES buffer. + * Called by by OpenSL ES framework. + * + * This is public, but don't call it directly. + */ + void processBufferCallback(SLAndroidSimpleBufferQueueItf bq); + + Result waitForStateChange(StreamState currentState, + StreamState *nextState, + int64_t timeoutNanoseconds) override; + +protected: + + SLuint32 channelCountToChannelMaskDefault(int channelCount) const; + + virtual Result onBeforeDestroy() { return Result::OK; } + virtual Result onAfterDestroy() { return Result::OK; } + + static SLuint32 getDefaultByteOrder(); + + SLresult registerBufferQueueCallback(); + + int32_t getBufferDepth(SLAndroidSimpleBufferQueueItf bq); + + SLresult enqueueCallbackBuffer(SLAndroidSimpleBufferQueueItf bq); + + SLresult configurePerformanceMode(SLAndroidConfigurationItf configItf); + + SLresult updateStreamParameters(SLAndroidConfigurationItf configItf); + + PerformanceMode convertPerformanceMode(SLuint32 openslMode) const; + SLuint32 convertPerformanceMode(PerformanceMode oboeMode) const; + + Result configureBufferSizes(int32_t sampleRate); + + void logUnsupportedAttributes(); + + /** + * Internal use only. + * Use this instead of directly setting the internal state variable. + */ + void setState(StreamState state) { + mState.store(state); + } + + int64_t getFramesProcessedByServer(); + + // OpenSLES stuff + SLObjectItf mObjectInterface = nullptr; + SLAndroidSimpleBufferQueueItf mSimpleBufferQueueInterface = nullptr; + + int32_t mBytesPerCallback = oboe::kUnspecified; + MonotonicCounter mPositionMillis; // for tracking OpenSL ES service position + +private: + std::unique_ptr mCallbackBuffer; + std::atomic mState{StreamState::Uninitialized}; + +}; + +} // namespace oboe + +#endif // OBOE_AUDIO_STREAM_OPENSL_ES_H_ diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/EngineOpenSLES.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/EngineOpenSLES.cpp new file mode 100644 index 0000000..d82219e --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/EngineOpenSLES.cpp @@ -0,0 +1,101 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common/OboeDebug.h" +#include "EngineOpenSLES.h" +#include "OpenSLESUtilities.h" + +using namespace oboe; + +EngineOpenSLES &EngineOpenSLES::getInstance() { + static EngineOpenSLES sInstance; + return sInstance; +} + +SLresult EngineOpenSLES::open() { + std::lock_guard lock(mLock); + + SLresult result = SL_RESULT_SUCCESS; + if (mOpenCount++ == 0) { + + // create engine + result = slCreateEngine(&mEngineObject, 0, NULL, 0, NULL, NULL); + if (SL_RESULT_SUCCESS != result) { + LOGE("EngineOpenSLES - slCreateEngine() result:%s", getSLErrStr(result)); + goto error; + } + + // realize the engine + result = (*mEngineObject)->Realize(mEngineObject, SL_BOOLEAN_FALSE); + if (SL_RESULT_SUCCESS != result) { + LOGE("EngineOpenSLES - Realize() engine result:%s", getSLErrStr(result)); + goto error; + } + + // get the engine interface, which is needed in order to create other objects + result = (*mEngineObject)->GetInterface(mEngineObject, SL_IID_ENGINE, &mEngineInterface); + if (SL_RESULT_SUCCESS != result) { + LOGE("EngineOpenSLES - GetInterface() engine result:%s", getSLErrStr(result)); + goto error; + } + } + + return result; + +error: + close(); + return result; +} + +void EngineOpenSLES::close() { + std::lock_guard lock(mLock); + if (--mOpenCount == 0) { + if (mEngineObject != nullptr) { + (*mEngineObject)->Destroy(mEngineObject); + mEngineObject = nullptr; + mEngineInterface = nullptr; + } + } +} + +SLresult EngineOpenSLES::createOutputMix(SLObjectItf *objectItf) { + return (*mEngineInterface)->CreateOutputMix(mEngineInterface, objectItf, 0, 0, 0); +} + +SLresult EngineOpenSLES::createAudioPlayer(SLObjectItf *objectItf, + SLDataSource *audioSource, + SLDataSink *audioSink) { + + const SLInterfaceID ids[] = {SL_IID_BUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION}; + const SLboolean reqs[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; + + return (*mEngineInterface)->CreateAudioPlayer(mEngineInterface, objectItf, audioSource, + audioSink, + sizeof(ids) / sizeof(ids[0]), ids, reqs); +} + +SLresult EngineOpenSLES::createAudioRecorder(SLObjectItf *objectItf, + SLDataSource *audioSource, + SLDataSink *audioSink) { + + const SLInterfaceID ids[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }; + const SLboolean reqs[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; + + return (*mEngineInterface)->CreateAudioRecorder(mEngineInterface, objectItf, audioSource, + audioSink, + sizeof(ids) / sizeof(ids[0]), ids, reqs); +} + diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/EngineOpenSLES.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/EngineOpenSLES.h new file mode 100644 index 0000000..3d238a8 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/EngineOpenSLES.h @@ -0,0 +1,65 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_ENGINE_OPENSLES_H +#define OBOE_ENGINE_OPENSLES_H + +#include +#include + +#include +#include + +namespace oboe { + +/** + * INTERNAL USE ONLY + */ +class EngineOpenSLES { +public: + static EngineOpenSLES &getInstance(); + + SLresult open(); + + void close(); + + SLresult createOutputMix(SLObjectItf *objectItf); + + SLresult createAudioPlayer(SLObjectItf *objectItf, + SLDataSource *audioSource, + SLDataSink *audioSink); + SLresult createAudioRecorder(SLObjectItf *objectItf, + SLDataSource *audioSource, + SLDataSink *audioSink); + +private: + // Make this a safe Singleton + EngineOpenSLES()= default; + ~EngineOpenSLES()= default; + EngineOpenSLES(const EngineOpenSLES&)= delete; + EngineOpenSLES& operator=(const EngineOpenSLES&)= delete; + + std::mutex mLock; + int32_t mOpenCount = 0; + + SLObjectItf mEngineObject = nullptr; + SLEngineItf mEngineInterface = nullptr; +}; + +} // namespace oboe + + +#endif //OBOE_ENGINE_OPENSLES_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/OpenSLESUtilities.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/OpenSLESUtilities.cpp new file mode 100644 index 0000000..071c0d0 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/OpenSLESUtilities.cpp @@ -0,0 +1,93 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OpenSLESUtilities.h" + +namespace oboe { + +/* + * OSLES Helpers + */ + +const char *getSLErrStr(SLresult code) { + switch (code) { + case 0: + return "SL_RESULT_SUCCESS"; + case 1: + return "SL_RESULT_PRECONDITIONS_VIOLATE"; + case 2: + return "SL_RESULT_PARAMETER_INVALID"; + case 3: + return "SL_RESULT_MEMORY_FAILURE"; + case 4: + return "SL_RESULT_RESOURCE_ERROR"; + case 5: + return "SL_RESULT_RESOURCE_LOST"; + case 6: + return "SL_RESULT_IO_ERROR"; + case 7: + return "SL_RESULT_BUFFER_INSUFFICIENT"; + case 8: + return "SL_RESULT_CONTENT_CORRUPTED"; + case 9: + return "SL_RESULT_CONTENT_UNSUPPORTED"; + case 10: + return "SL_RESULT_CONTENT_NOT_FOUND"; + case 11: + return "SL_RESULT_PERMISSION_DENIED"; + case 12: + return "SL_RESULT_FEATURE_UNSUPPORTED"; + case 13: + return "SL_RESULT_INTERNAL_ERROR"; + case 14: + return "SL_RESULT_UNKNOWN_ERROR"; + case 15: + return "SL_RESULT_OPERATION_ABORTED"; + case 16: + return "SL_RESULT_CONTROL_LOST"; + default: + return "Unknown error"; + } +} + +SLAndroidDataFormat_PCM_EX OpenSLES_createExtendedFormat( + SLDataFormat_PCM format, SLuint32 representation) { + SLAndroidDataFormat_PCM_EX format_pcm_ex; + format_pcm_ex.formatType = SL_ANDROID_DATAFORMAT_PCM_EX; + format_pcm_ex.numChannels = format.numChannels; + format_pcm_ex.sampleRate = format.samplesPerSec; + format_pcm_ex.bitsPerSample = format.bitsPerSample; + format_pcm_ex.containerSize = format.containerSize; + format_pcm_ex.channelMask = format.channelMask; + format_pcm_ex.endianness = format.endianness; + format_pcm_ex.representation = representation; + return format_pcm_ex; +} + +SLuint32 OpenSLES_ConvertFormatToRepresentation(AudioFormat format) { + switch(format) { + case AudioFormat::I16: + return SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT; + case AudioFormat::Float: + return SL_ANDROID_PCM_REPRESENTATION_FLOAT; + case AudioFormat::Invalid: + case AudioFormat::Unspecified: + default: + return 0; + } +} + +} // namespace oboe diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/OpenSLESUtilities.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/OpenSLESUtilities.h new file mode 100644 index 0000000..50c0e2d --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/OpenSLESUtilities.h @@ -0,0 +1,44 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_OPENSLES_OPENSLESUTILITIES_H +#define OBOE_OPENSLES_OPENSLESUTILITIES_H + +#include +#include "oboe/Oboe.h" + +namespace oboe { + +const char *getSLErrStr(SLresult code); + +/** + * Creates an extended PCM format from the supplied format and data representation. This method + * should only be called on Android devices with API level 21+. API 21 introduced the + * SLAndroidDataFormat_PCM_EX object which allows audio samples to be represented using + * single precision floating-point. + * + * @param format + * @param representation + * @return the extended PCM format + */ +SLAndroidDataFormat_PCM_EX OpenSLES_createExtendedFormat(SLDataFormat_PCM format, + SLuint32 representation); + +SLuint32 OpenSLES_ConvertFormatToRepresentation(AudioFormat format); + +} // namespace oboe + +#endif //OBOE_OPENSLES_OPENSLESUTILITIES_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/OutputMixerOpenSLES.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/OutputMixerOpenSLES.cpp new file mode 100644 index 0000000..e06f306 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/OutputMixerOpenSLES.cpp @@ -0,0 +1,74 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "common/OboeDebug.h" +#include "EngineOpenSLES.h" +#include "OpenSLESUtilities.h" +#include "OutputMixerOpenSLES.h" + +using namespace oboe; + +OutputMixerOpenSL &OutputMixerOpenSL::getInstance() { + static OutputMixerOpenSL sInstance; + return sInstance; +} + +SLresult OutputMixerOpenSL::open() { + std::lock_guard lock(mLock); + + SLresult result = SL_RESULT_SUCCESS; + if (mOpenCount++ == 0) { + // get the output mixer + result = EngineOpenSLES::getInstance().createOutputMix(&mOutputMixObject); + if (SL_RESULT_SUCCESS != result) { + LOGE("OutputMixerOpenSL() - createOutputMix() result:%s", getSLErrStr(result)); + goto error; + } + + // realize the output mix + result = (*mOutputMixObject)->Realize(mOutputMixObject, SL_BOOLEAN_FALSE); + if (SL_RESULT_SUCCESS != result) { + LOGE("OutputMixerOpenSL() - Realize() mOutputMixObject result:%s", getSLErrStr(result)); + goto error; + } + } + + return result; + +error: + close(); + return result; +} + +void OutputMixerOpenSL::close() { + std::lock_guard lock(mLock); + + if (--mOpenCount == 0) { + // destroy output mix object, and invalidate all associated interfaces + if (mOutputMixObject != nullptr) { + (*mOutputMixObject)->Destroy(mOutputMixObject); + mOutputMixObject = nullptr; + } + } +} + +SLresult OutputMixerOpenSL::createAudioPlayer(SLObjectItf *objectItf, + SLDataSource *audioSource) { + SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, mOutputMixObject}; + SLDataSink audioSink = {&loc_outmix, NULL}; + return EngineOpenSLES::getInstance().createAudioPlayer(objectItf, audioSource, &audioSink); +} diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/OutputMixerOpenSLES.h b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/OutputMixerOpenSLES.h new file mode 100644 index 0000000..813fd01 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_devices/native/oboe/src/opensles/OutputMixerOpenSLES.h @@ -0,0 +1,58 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBOE_OUTPUT_MIXER_OPENSLES_H +#define OBOE_OUTPUT_MIXER_OPENSLES_H + +#include +#include + +#include +#include + +namespace oboe { + +/** + * INTERNAL USE ONLY + */ + +class OutputMixerOpenSL { +public: + static OutputMixerOpenSL &getInstance(); + + SLresult open(); + + void close(); + + SLresult createAudioPlayer(SLObjectItf *objectItf, + SLDataSource *audioSource); + +private: + // Make this a safe Singleton + OutputMixerOpenSL()= default; + ~OutputMixerOpenSL()= default; + OutputMixerOpenSL(const OutputMixerOpenSL&)= delete; + OutputMixerOpenSL& operator=(const OutputMixerOpenSL&)= delete; + + std::mutex mLock; + int32_t mOpenCount = 0; + + SLObjectItf mOutputMixObject = nullptr; +}; + +} // namespace oboe + +#endif //OBOE_OUTPUT_MIXER_OPENSLES_H diff --git a/JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioSourcePlayer.cpp b/JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioSourcePlayer.cpp index 0959329..186a303 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioSourcePlayer.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioSourcePlayer.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. @@ -104,14 +104,14 @@ void AudioSourcePlayer::audioDeviceIOCallback (const float** inputChannelData, for (int i = 0; i < numOutputs; ++i) { channels[numActiveChans] = outputChans[i]; - memcpy (channels[numActiveChans], inputChans[i], sizeof (float) * (size_t) numSamples); + memcpy (channels[numActiveChans], inputChans[i], (size_t) numSamples * sizeof (float)); ++numActiveChans; } for (int i = numOutputs; i < numInputs; ++i) { channels[numActiveChans] = tempBuffer.getWritePointer (i - numOutputs); - memcpy (channels[numActiveChans], inputChans[i], sizeof (float) * (size_t) numSamples); + memcpy (channels[numActiveChans], inputChans[i], (size_t) numSamples * sizeof (float)); ++numActiveChans; } } @@ -120,14 +120,14 @@ void AudioSourcePlayer::audioDeviceIOCallback (const float** inputChannelData, for (int i = 0; i < numInputs; ++i) { channels[numActiveChans] = outputChans[i]; - memcpy (channels[numActiveChans], inputChans[i], sizeof (float) * (size_t) numSamples); + memcpy (channels[numActiveChans], inputChans[i], (size_t) numSamples * sizeof (float)); ++numActiveChans; } for (int i = numInputs; i < numOutputs; ++i) { channels[numActiveChans] = outputChans[i]; - zeromem (channels[numActiveChans], sizeof (float) * (size_t) numSamples); + zeromem (channels[numActiveChans], (size_t) numSamples * sizeof (float)); ++numActiveChans; } } @@ -146,7 +146,7 @@ void AudioSourcePlayer::audioDeviceIOCallback (const float** inputChannelData, { for (int i = 0; i < totalNumOutputChannels; ++i) if (outputChannelData[i] != nullptr) - zeromem (outputChannelData[i], sizeof (float) * (size_t) numSamples); + zeromem (outputChannelData[i], (size_t) numSamples * sizeof (float)); } } diff --git a/JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioSourcePlayer.h b/JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioSourcePlayer.h index bb6143a..c5c1f0f 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioSourcePlayer.h +++ b/JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioSourcePlayer.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. @@ -105,7 +105,8 @@ class JUCE_API AudioSourcePlayer : public AudioIODeviceCallback float* outputChans[128]; const float* inputChans[128]; AudioBuffer tempBuffer; - float lastGain = 1.0f, gain = 1.0f; + float lastGain = 1.0f; + std::atomic gain { 1.0f }; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioSourcePlayer) }; diff --git a/JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp b/JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp index 16d5709..5bddda3 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioTransportSource.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. @@ -125,10 +125,7 @@ void AudioTransportSource::stop() { if (playing) { - { - const ScopedLock sl (callbackLock); - playing = false; - } + playing = false; int n = 500; while (--n >= 0 && ! stopped) diff --git a/JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioTransportSource.h b/JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioTransportSource.h index 27adcbe..e91b143 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioTransportSource.h +++ b/JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioTransportSource.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. @@ -167,7 +167,7 @@ class JUCE_API AudioTransportSource : public PositionableAudioSource, CriticalSection callbackLock; float gain = 1.0f, lastGain = 1.0f; - bool playing = false, stopped = true; + std::atomic playing { false }, stopped { true }; double sampleRate = 44100.0, sourceSampleRate = 0; int blockSize = 128, readAheadBufferSize = 0; bool isPrepared = false, inputStreamEOF = false; diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_AbstractFifo.cpp b/JuceLibraryCode/modules/juce_core/containers/juce_AbstractFifo.cpp index 4db6bfa..3aaa978 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_AbstractFifo.cpp +++ b/JuceLibraryCode/modules/juce_core/containers/juce_AbstractFifo.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. @@ -166,13 +166,16 @@ AbstractFifo::ScopedRead AbstractFifo::read (int numToRead) noexcept { ret AbstractFifo::ScopedWrite AbstractFifo::write (int numToWrite) noexcept { return { *this, numToWrite }; } +//============================================================================== //============================================================================== #if JUCE_UNIT_TESTS class AbstractFifoTests : public UnitTest { public: - AbstractFifoTests() : UnitTest ("Abstract Fifo", "Containers") {} + AbstractFifoTests() + : UnitTest ("Abstract Fifo", UnitTestCategories::containers) + {} struct WriteThread : public Thread { diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_AbstractFifo.h b/JuceLibraryCode/modules/juce_core/containers/juce_AbstractFifo.h index 4f00255..dd4cb56 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_AbstractFifo.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_AbstractFifo.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_core/containers/juce_Array.h b/JuceLibraryCode/modules/juce_core/containers/juce_Array.h index fdec1be..13ce43e 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_Array.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_Array.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. @@ -30,7 +30,7 @@ namespace juce Examples of arrays are: Array, Array or Array The Array class can be used to hold simple, non-polymorphic objects as well as primitive types - to - do so, the class must fulfil these requirements: + do so, the class must fulfill these requirements: - it must have a copy constructor and assignment operator - it must be able to be relocated in memory by a memcpy without this causing any problems - so objects whose functionality relies on external pointers or references to themselves can not be used. @@ -264,7 +264,21 @@ class Array @param index the index of the element being requested (0 is the first element in the array) @see operator[], getFirst, getLast */ - inline ElementType& getReference (int index) const noexcept + inline ElementType& getReference (int index) noexcept + { + const ScopedLockType lock (getLock()); + return values[index]; + } + + /** Returns a direct reference to one of the elements in the array, without checking the index passed in. + + This is like getUnchecked, but returns a direct reference to the element. Obviously + this can be dangerous, so only use it when absolutely necessary. + + @param index the index of the element being requested (0 is the first element in the array) + @see operator[], getFirst, getLast + */ + inline const ElementType& getReference (int index) const noexcept { const ScopedLockType lock (getLock()); return values[index]; @@ -298,11 +312,28 @@ class Array return values.begin(); } + /** Returns a pointer to the actual array data. + This pointer will only be valid until the next time a non-const method + is called on the array. + */ + inline const ElementType* getRawDataPointer() const noexcept + { + return values.begin(); + } + //============================================================================== /** Returns a pointer to the first element in the array. This method is provided for compatibility with standard C++ iteration mechanisms. */ - inline ElementType* begin() const noexcept + inline ElementType* begin() noexcept + { + return values.begin(); + } + + /** Returns a pointer to the first element in the array. + This method is provided for compatibility with standard C++ iteration mechanisms. + */ + inline const ElementType* begin() const noexcept { return values.begin(); } @@ -310,7 +341,15 @@ class Array /** Returns a pointer to the element which follows the last element in the array. This method is provided for compatibility with standard C++ iteration mechanisms. */ - inline ElementType* end() const noexcept + inline ElementType* end() noexcept + { + return values.end(); + } + + /** Returns a pointer to the element which follows the last element in the array. + This method is provided for compatibility with standard C++ iteration mechanisms. + */ + inline const ElementType* end() const noexcept { return values.end(); } @@ -318,7 +357,15 @@ class Array /** Returns a pointer to the first element in the array. This method is provided for compatibility with the standard C++ containers. */ - inline ElementType* data() const noexcept + inline ElementType* data() noexcept + { + return begin(); + } + + /** Returns a pointer to the first element in the array. + This method is provided for compatibility with the standard C++ containers. + */ + inline const ElementType* data() const noexcept { return begin(); } diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_ArrayAllocationBase.h b/JuceLibraryCode/modules/juce_core/containers/juce_ArrayAllocationBase.h index 34f98b7..46e6aff 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_ArrayAllocationBase.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_ArrayAllocationBase.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_core/containers/juce_ArrayBase.cpp b/JuceLibraryCode/modules/juce_core/containers/juce_ArrayBase.cpp index 0ac9685..6f19a0b 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_ArrayBase.cpp +++ b/JuceLibraryCode/modules/juce_core/containers/juce_ArrayBase.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2018 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -113,7 +113,7 @@ class ArrayBaseTests : public UnitTest public: ArrayBaseTests() - : UnitTest ("ArrayBase", "Containers") + : UnitTest ("ArrayBase", UnitTestCategories::containers) {} void runTest() override @@ -304,7 +304,7 @@ class ArrayBaseTests : public UnitTest checkEqual (copyableContainer, noncopyableContainer, referenceContainer); } - beginTest ("add array from initilizer list"); + beginTest ("add array from initializer_list"); { std::vector referenceContainer; ArrayBase copyableContainer; diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_ArrayBase.h b/JuceLibraryCode/modules/juce_core/containers/juce_ArrayBase.h index 85a4cfa..fdd7af2 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_ArrayBase.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_ArrayBase.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. @@ -136,7 +136,14 @@ class ArrayBase : public TypeOfCriticalSectionToUse } //============================================================================== - inline ElementType& operator[] (const int index) const noexcept + inline ElementType& operator[] (const int index) noexcept + { + jassert (elements != nullptr); + jassert (isPositiveAndBelow (index, numUsed)); + return elements[index]; + } + + inline const ElementType& operator[] (const int index) const noexcept { jassert (elements != nullptr); jassert (isPositiveAndBelow (index, numUsed)); @@ -159,17 +166,32 @@ class ArrayBase : public TypeOfCriticalSectionToUse } //============================================================================== - inline ElementType* begin() const noexcept + inline ElementType* begin() noexcept + { + return elements; + } + + inline const ElementType* begin() const noexcept { return elements; } - inline ElementType* end() const noexcept + inline ElementType* end() noexcept + { + return elements + numUsed; + } + + inline const ElementType* end() const noexcept { return elements + numUsed; } - inline ElementType* data() const noexcept + inline ElementType* data() noexcept + { + return elements; + } + + inline const ElementType* data() const noexcept { return elements; } @@ -499,13 +521,13 @@ class ArrayBase : public TypeOfCriticalSectionToUse { memmove (elements + currentIndex, elements + currentIndex + 1, - sizeof (ElementType) * (size_t) (newIndex - currentIndex)); + (size_t) (newIndex - currentIndex) * sizeof (ElementType)); } else { memmove (elements + newIndex + 1, elements + newIndex, - sizeof (ElementType) * (size_t) (currentIndex - newIndex)); + (size_t) (currentIndex - newIndex) * sizeof (ElementType)); } memcpy (elements + newIndex, tempCopy, sizeof (ElementType)); diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_DynamicObject.cpp b/JuceLibraryCode/modules/juce_core/containers/juce_DynamicObject.cpp index 5e7ee2e..540820f 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_DynamicObject.cpp +++ b/JuceLibraryCode/modules/juce_core/containers/juce_DynamicObject.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_core/containers/juce_DynamicObject.h b/JuceLibraryCode/modules/juce_core/containers/juce_DynamicObject.h index d144d80..6fbd902 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_DynamicObject.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_DynamicObject.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. @@ -78,7 +78,7 @@ class JUCE_API DynamicObject : public ReferenceCountedObject call, then it invokes it. This method is virtual to allow more dynamic invocation to used for objects - where the methods may not already be set as properies. + where the methods may not already be set as properties. */ virtual var invokeMethod (Identifier methodName, const var::NativeFunctionArgs& args); diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_ElementComparator.h b/JuceLibraryCode/modules/juce_core/containers/juce_ElementComparator.h index 0b4f427..095ec25 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_ElementComparator.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_ElementComparator.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_core/containers/juce_HashMap.h b/JuceLibraryCode/modules/juce_core/containers/juce_HashMap.h index 2767a6d..655991a 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_HashMap.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_HashMap.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. @@ -203,7 +203,7 @@ class HashMap } //============================================================================== - /** Returns true if the map contains an item with the specied key. */ + /** Returns true if the map contains an item with the specified key. */ bool contains (KeyTypeParameter keyToLookFor) const { const ScopedLockType sl (getLock()); @@ -489,7 +489,7 @@ class HashMap return hash; } - static inline HashEntry* getEntry (HashEntry* firstEntry, KeyType keyToLookFor) noexcept + static HashEntry* getEntry (HashEntry* firstEntry, KeyType keyToLookFor) noexcept { for (auto* entry = firstEntry; entry != nullptr; entry = entry->nextEntry) if (entry->key == keyToLookFor) diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_HashMap_test.cpp b/JuceLibraryCode/modules/juce_core/containers/juce_HashMap_test.cpp index b80f7a7..8fa3711 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_HashMap_test.cpp +++ b/JuceLibraryCode/modules/juce_core/containers/juce_HashMap_test.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,7 +25,9 @@ namespace juce struct HashMapTest : public UnitTest { - HashMapTest() : UnitTest ("HashMap", "Containers") {} + HashMapTest() + : UnitTest ("HashMap", UnitTestCategories::containers) + {} void runTest() override { diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_LinkedListPointer.h b/JuceLibraryCode/modules/juce_core/containers/juce_LinkedListPointer.h index 8889326..92aed42 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_LinkedListPointer.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_LinkedListPointer.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_core/containers/juce_ListenerList.h b/JuceLibraryCode/modules/juce_core/containers/juce_ListenerList.h index 09daea8..1ccf504 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_ListenerList.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_ListenerList.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_core/containers/juce_NamedValueSet.cpp b/JuceLibraryCode/modules/juce_core/containers/juce_NamedValueSet.cpp index cea5c4f..b781e00 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_NamedValueSet.cpp +++ b/JuceLibraryCode/modules/juce_core/containers/juce_NamedValueSet.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. @@ -147,7 +147,16 @@ var NamedValueSet::getWithDefault (const Identifier& name, const var& defaultRet return defaultReturnValue; } -var* NamedValueSet::getVarPointer (const Identifier& name) const noexcept +var* NamedValueSet::getVarPointer (const Identifier& name) noexcept +{ + for (auto& i : values) + if (i.name == name) + return &(i.value); + + return {}; +} + +const var* NamedValueSet::getVarPointer (const Identifier& name) const noexcept { for (auto& i : values) if (i.name == name) @@ -236,7 +245,15 @@ const var& NamedValueSet::getValueAt (const int index) const noexcept return getNullVarRef(); } -var* NamedValueSet::getVarPointerAt (int index) const noexcept +var* NamedValueSet::getVarPointerAt (int index) noexcept +{ + if (isPositiveAndBelow (index, values.size())) + return &(values.getReference (index).value); + + return {}; +} + +const var* NamedValueSet::getVarPointerAt (int index) const noexcept { if (isPositiveAndBelow (index, values.size())) return &(values.getReference (index).value); diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_NamedValueSet.h b/JuceLibraryCode/modules/juce_core/containers/juce_NamedValueSet.h index 30bc032..8224a59 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_NamedValueSet.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_NamedValueSet.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. @@ -89,7 +89,6 @@ class JUCE_API NamedValueSet /** Returns the value of a named item. If the name isn't found, this will return a void variant. - @see getProperty */ const var& operator[] (const Identifier& name) const noexcept; @@ -132,7 +131,17 @@ class JUCE_API NamedValueSet Also note that the pointer returned may become invalid as soon as any subsequent methods are called on the NamedValueSet. */ - var* getVarPointer (const Identifier& name) const noexcept; + var* getVarPointer (const Identifier& name) noexcept; + + /** Returns a pointer to the var that holds a named value, or null if there is + no value with this name. + + Do not use this method unless you really need access to the internal var object + for some reason - for normal reading and writing always prefer operator[]() and set(). + Also note that the pointer returned may become invalid as soon as any subsequent + methods are called on the NamedValueSet. + */ + const var* getVarPointer (const Identifier& name) const noexcept; /** Returns the value of the item at a given index. The index must be between 0 and size() - 1. @@ -144,7 +153,14 @@ class JUCE_API NamedValueSet Also note that the pointer returned may become invalid as soon as any subsequent methods are called on the NamedValueSet. */ - var* getVarPointerAt (int index) const noexcept; + var* getVarPointerAt (int index) noexcept; + + /** Returns the value of the item at a given index. + The index must be between 0 and size() - 1, or this will return a nullptr + Also note that the pointer returned may become invalid as soon as any subsequent + methods are called on the NamedValueSet. + */ + const var* getVarPointerAt (int index) const noexcept; /** Returns the index of the given name, or -1 if it's not found. */ int indexOf (const Identifier& name) const noexcept; diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_OwnedArray.cpp b/JuceLibraryCode/modules/juce_core/containers/juce_OwnedArray.cpp index 2f6e3f3..b0312bc 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_OwnedArray.cpp +++ b/JuceLibraryCode/modules/juce_core/containers/juce_OwnedArray.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,17 +27,51 @@ namespace juce static struct OwnedArrayTest : public UnitTest { - OwnedArrayTest() : UnitTest { "OwnedArray" } {} - struct Base { + Base() = default; virtual ~Base() = default; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Base) }; struct Derived : Base { + Derived() = default; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Derived) + }; + + struct DestructorObj + { + DestructorObj (OwnedArrayTest& p, + OwnedArray& arr) + : parent (p), objectArray (arr) + {} + + ~DestructorObj() + { + data = 0; + + for (auto* o : objectArray) + { + parent.expect (o != nullptr); + parent.expect (o != this); + parent.expectEquals (o->data, 956); + } + } + + OwnedArrayTest& parent; + OwnedArray& objectArray; + int data = 956; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DestructorObj) }; + OwnedArrayTest() + : UnitTest ("OwnedArray", UnitTestCategories::containers) + {} + void runTest() override { beginTest ("After converting move construction, ownership is transferred"); @@ -58,6 +92,34 @@ static struct OwnedArrayTest : public UnitTest expectEquals (base.size(), 3); } + + beginTest ("Iterate in destructor"); + { + { + OwnedArray arr; + + for (int i = 0; i < 2; ++i) + arr.add (new DestructorObj (*this, arr)); + } + + OwnedArray arr; + + for (int i = 0; i < 1025; ++i) + arr.add (new DestructorObj (*this, arr)); + + while (! arr.isEmpty()) + arr.remove (0); + + for (int i = 0; i < 1025; ++i) + arr.add (new DestructorObj (*this, arr)); + + arr.removeRange (1, arr.size() - 3); + + for (int i = 0; i < 1025; ++i) + arr.add (new DestructorObj (*this, arr)); + + arr.set (500, new DestructorObj (*this, arr)); + } } } ownedArrayTest; diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_OwnedArray.h b/JuceLibraryCode/modules/juce_core/containers/juce_OwnedArray.h index a0ed55d..9a53464 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_OwnedArray.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_OwnedArray.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. @@ -146,7 +146,7 @@ class OwnedArray @see getUnchecked */ - inline ObjectClass* operator[] (const int index) const noexcept + inline ObjectClass* operator[] (int index) const noexcept { const ScopedLockType lock (getLock()); return values.getValueWithDefault (index); @@ -157,7 +157,7 @@ class OwnedArray This is a faster and less safe version of operator[] which doesn't check the index passed in, so it can be used when you're sure the index is always going to be legal. */ - inline ObjectClass* getUnchecked (const int index) const noexcept + inline ObjectClass* getUnchecked (int index) const noexcept { const ScopedLockType lock (getLock()); return values[index]; @@ -198,15 +198,31 @@ class OwnedArray /** Returns a pointer to the first element in the array. This method is provided for compatibility with standard C++ iteration mechanisms. */ - inline ObjectClass** begin() const noexcept + inline ObjectClass** begin() noexcept { return values.begin(); } + /** Returns a pointer to the first element in the array. + This method is provided for compatibility with standard C++ iteration mechanisms. + */ + inline ObjectClass* const* begin() const noexcept + { + return values.begin(); + } + + /** Returns a pointer to the element which follows the last element in the array. + This method is provided for compatibility with standard C++ iteration mechanisms. + */ + inline ObjectClass** end() noexcept + { + return values.end(); + } + /** Returns a pointer to the element which follows the last element in the array. This method is provided for compatibility with standard C++ iteration mechanisms. */ - inline ObjectClass** end() const noexcept + inline ObjectClass* const* end() const noexcept { return values.end(); } @@ -214,7 +230,15 @@ class OwnedArray /** Returns a pointer to the first element in the array. This method is provided for compatibility with the standard C++ containers. */ - inline ObjectClass** data() const noexcept + inline ObjectClass** data() noexcept + { + return begin(); + } + + /** Returns a pointer to the first element in the array. + This method is provided for compatibility with the standard C++ containers. + */ + inline ObjectClass* const* data() const noexcept { return begin(); } @@ -228,7 +252,7 @@ class OwnedArray int indexOf (const ObjectClass* objectToLookFor) const noexcept { const ScopedLockType lock (getLock()); - auto** e = values.begin(); + auto* e = values.begin(); for (; e != values.end(); ++e) if (objectToLookFor == *e) @@ -245,7 +269,7 @@ class OwnedArray bool contains (const ObjectClass* objectToLookFor) const noexcept { const ScopedLockType lock (getLock()); - auto** e = values.begin(); + auto* e = values.begin(); for (; e != values.end(); ++e) if (objectToLookFor == *e) @@ -257,27 +281,44 @@ class OwnedArray //============================================================================== /** Appends a new object to the end of the array. - Note that the this object will be deleted by the OwnedArray when it - is removed, so be careful not to delete it somewhere else. + Note that this object will be deleted by the OwnedArray when it is removed, + so be careful not to delete it somewhere else. Also be careful not to add the same object to the array more than once, as this will obviously cause deletion of dangling pointers. @param newObject the new object to add to the array @returns the new object that was added - @see set, insert, addIfNotAlreadyThere, addSorted + @see set, insert, addSorted */ - ObjectClass* add (ObjectClass* newObject) noexcept + ObjectClass* add (ObjectClass* newObject) { const ScopedLockType lock (getLock()); values.add (newObject); return newObject; } + /** Appends a new object to the end of the array. + + Note that this object will be deleted by the OwnedArray when it is removed, + so be careful not to delete it somewhere else. + + Also be careful not to add the same object to the array more than once, + as this will obviously cause deletion of dangling pointers. + + @param newObject the new object to add to the array + @returns the new object that was added + @see set, insert, addSorted + */ + ObjectClass* add (std::unique_ptr newObject) + { + return add (newObject.release()); + } + /** Inserts a new object into the array at the given index. - Note that the this object will be deleted by the OwnedArray when it - is removed, so be careful not to delete it somewhere else. + Note that this object will be deleted by the OwnedArray when it is removed, + so be careful not to delete it somewhere else. If the index is less than 0 or greater than the size of the array, the element will be added to the end of the array. @@ -290,15 +331,38 @@ class OwnedArray @param indexToInsertAt the index at which the new element should be inserted @param newObject the new object to add to the array @returns the new object that was added - @see add, addSorted, addIfNotAlreadyThere, set + @see add, addSorted, set */ - ObjectClass* insert (int indexToInsertAt, ObjectClass* newObject) noexcept + ObjectClass* insert (int indexToInsertAt, ObjectClass* newObject) { const ScopedLockType lock (getLock()); values.insert (indexToInsertAt, newObject, 1); return newObject; } + /** Inserts a new object into the array at the given index. + + Note that this object will be deleted by the OwnedArray when it is removed, + so be careful not to delete it somewhere else. + + If the index is less than 0 or greater than the size of the array, the + element will be added to the end of the array. + Otherwise, it will be inserted into the array, moving all the later elements + along to make room. + + Be careful not to add the same object to the array more than once, + as this will obviously cause deletion of dangling pointers. + + @param indexToInsertAt the index at which the new element should be inserted + @param newObject the new object to add to the array + @returns the new object that was added + @see add, addSorted, set + */ + ObjectClass* insert (int indexToInsertAt, std::unique_ptr newObject) + { + return insert (indexToInsertAt, newObject.release()); + } + /** Inserts an array of values into this array at a given position. If the index is less than 0 or greater than the size of the array, the @@ -322,25 +386,6 @@ class OwnedArray } } - /** Appends a new object at the end of the array as long as the array doesn't - already contain it. - - If the array already contains a matching object, nothing will be done. - - @param newObject the new object to add to the array - @returns true if the new object was added, false otherwise - */ - bool addIfNotAlreadyThere (ObjectClass* newObject) noexcept - { - const ScopedLockType lock (getLock()); - - if (contains (newObject)) - return false; - - add (newObject); - return true; - } - /** Replaces an object in the array with a different one. If the index is less than zero, this method does nothing. @@ -390,6 +435,24 @@ class OwnedArray return newObject; } + /** Replaces an object in the array with a different one. + + If the index is less than zero, this method does nothing. + If the index is beyond the end of the array, the new object is added to the end of the array. + + Be careful not to add the same object to the array more than once, + as this will obviously cause deletion of dangling pointers. + + @param indexToChange the index whose value you want to change + @param newObject the new value to set for this index. + @param deleteOldElement whether to delete the object that's being replaced with the new one + @see add, insert, remove + */ + ObjectClass* set (int indexToChange, std::unique_ptr newObject, bool deleteOldElement = true) + { + return set (indexToChange, newObject.release(), deleteOldElement); + } + /** Adds elements from another array to the end of this array. @param arrayToAddFrom the array from which to copy the elements @@ -468,14 +531,14 @@ class OwnedArray @see add, sort, indexOfSorted */ template - int addSorted (ElementComparator& comparator, ObjectClass* const newObject) noexcept + int addSorted (ElementComparator& comparator, ObjectClass* newObject) noexcept { // If you pass in an object with a static compareElements() method, this // avoids getting warning messages about the parameter being unused ignoreUnused (comparator); const ScopedLockType lock (getLock()); - const int index = findInsertIndexInSortedArray (comparator, values.begin(), newObject, 0, values.size()); + auto index = findInsertIndexInSortedArray (comparator, values.begin(), newObject, 0, values.size()); insert (index, newObject); return index; } @@ -493,7 +556,7 @@ class OwnedArray @see addSorted, sort */ template - int indexOfSorted (ElementComparator& comparator, const ObjectClass* const objectToLookFor) const noexcept + int indexOfSorted (ElementComparator& comparator, const ObjectClass* objectToLookFor) const noexcept { // If you pass in an object with a static compareElements() method, this // avoids getting warning messages about the parameter being unused @@ -625,17 +688,16 @@ class OwnedArray if (numberToRemove > 0) { + Array objectsToDelete; + if (deleteObjects) - { - for (int i = startIndex; i < endIndex; ++i) - { - ContainerDeletePolicy::destroy (values[i]); - values[i] = nullptr; // (in case one of the destructors accesses this array and hits a dangling pointer) - } - } + objectsToDelete.addArray (values.begin() + startIndex, numberToRemove); values.removeElements (startIndex, numberToRemove); + for (auto& o : objectsToDelete) + ContainerDeletePolicy::destroy (o); + if ((values.size() << 1) < values.capacity()) minimiseStorageOverheads(); } @@ -723,7 +785,7 @@ class OwnedArray the array won't have to keep dynamically resizing itself as the elements are added, and it'll therefore be more efficient. */ - void ensureStorageAllocated (const int minNumElements) noexcept + void ensureStorageAllocated (int minNumElements) noexcept { const ScopedLockType lock (getLock()); values.ensureAllocatedSize (minNumElements); @@ -757,7 +819,7 @@ class OwnedArray */ template void sort (ElementComparator& comparator, - bool retainOrderOfEquivalentItems = false) const noexcept + bool retainOrderOfEquivalentItems = false) noexcept { // If you pass in an object with a static compareElements() method, this // avoids getting warning messages about the parameter being unused @@ -792,10 +854,14 @@ class OwnedArray void deleteAllObjects() { - for (auto& e : values) - ContainerDeletePolicy::destroy (e); + auto i = values.size(); - values.clear(); + while (--i >= 0) + { + auto* e = values[i]; + values.removeElements (i, 1); + ContainerDeletePolicy::destroy (e); + } } template diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_PropertySet.cpp b/JuceLibraryCode/modules/juce_core/containers/juce_PropertySet.cpp index ac429fa..63964a5 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_PropertySet.cpp +++ b/JuceLibraryCode/modules/juce_core/containers/juce_PropertySet.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,7 @@ namespace juce { -PropertySet::PropertySet (const bool ignoreCaseOfKeyNames) +PropertySet::PropertySet (bool ignoreCaseOfKeyNames) : properties (ignoreCaseOfKeyNames), fallbackProperties (nullptr), ignoreCaseOfKeys (ignoreCaseOfKeyNames) @@ -65,8 +65,7 @@ void PropertySet::clear() String PropertySet::getValue (StringRef keyName, const String& defaultValue) const noexcept { const ScopedLock sl (lock); - - const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys); + auto index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys); if (index >= 0) return properties.getAllValues() [index]; @@ -75,10 +74,10 @@ String PropertySet::getValue (StringRef keyName, const String& defaultValue) con : defaultValue; } -int PropertySet::getIntValue (StringRef keyName, const int defaultValue) const noexcept +int PropertySet::getIntValue (StringRef keyName, int defaultValue) const noexcept { const ScopedLock sl (lock); - const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys); + auto index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys); if (index >= 0) return properties.getAllValues() [index].getIntValue(); @@ -87,10 +86,10 @@ int PropertySet::getIntValue (StringRef keyName, const int defaultValue) const n : defaultValue; } -double PropertySet::getDoubleValue (StringRef keyName, const double defaultValue) const noexcept +double PropertySet::getDoubleValue (StringRef keyName, double defaultValue) const noexcept { const ScopedLock sl (lock); - const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys); + auto index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys); if (index >= 0) return properties.getAllValues()[index].getDoubleValue(); @@ -99,10 +98,10 @@ double PropertySet::getDoubleValue (StringRef keyName, const double defaultValue : defaultValue; } -bool PropertySet::getBoolValue (StringRef keyName, const bool defaultValue) const noexcept +bool PropertySet::getBoolValue (StringRef keyName, bool defaultValue) const noexcept { const ScopedLock sl (lock); - const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys); + auto index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys); if (index >= 0) return properties.getAllValues() [index].getIntValue() != 0; @@ -111,21 +110,20 @@ bool PropertySet::getBoolValue (StringRef keyName, const bool defaultValue) cons : defaultValue; } -XmlElement* PropertySet::getXmlValue (StringRef keyName) const +std::unique_ptr PropertySet::getXmlValue (StringRef keyName) const { - return XmlDocument::parse (getValue (keyName)); + return parseXML (getValue (keyName)); } -void PropertySet::setValue (const String& keyName, const var& v) +void PropertySet::setValue (StringRef keyName, const var& v) { jassert (keyName.isNotEmpty()); // shouldn't use an empty key name! if (keyName.isNotEmpty()) { - const String value (v.toString()); + auto value = v.toString(); const ScopedLock sl (lock); - - const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys); + auto index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys); if (index < 0 || properties.getAllValues() [index] != value) { @@ -140,7 +138,7 @@ void PropertySet::removeValue (StringRef keyName) if (keyName.isNotEmpty()) { const ScopedLock sl (lock); - const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys); + auto index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys); if (index >= 0) { @@ -150,10 +148,10 @@ void PropertySet::removeValue (StringRef keyName) } } -void PropertySet::setValue (const String& keyName, const XmlElement* const xml) +void PropertySet::setValue (StringRef keyName, const XmlElement* xml) { setValue (keyName, xml == nullptr ? var() - : var (xml->createDocument ("", true))); + : var (xml->toString (XmlElement::TextFormat().singleLine().withoutHeader()))); } bool PropertySet::containsKey (StringRef keyName) const noexcept @@ -177,14 +175,15 @@ void PropertySet::setFallbackPropertySet (PropertySet* fallbackProperties_) noex fallbackProperties = fallbackProperties_; } -XmlElement* PropertySet::createXml (const String& nodeName) const +std::unique_ptr PropertySet::createXml (const String& nodeName) const { + auto xml = std::make_unique (nodeName); + const ScopedLock sl (lock); - XmlElement* const xml = new XmlElement (nodeName); for (int i = 0; i < properties.getAllKeys().size(); ++i) { - XmlElement* const e = xml->createNewChildElement ("VALUE"); + auto e = xml->createNewChildElement ("VALUE"); e->setAttribute ("name", properties.getAllKeys()[i]); e->setAttribute ("val", properties.getAllValues()[i]); } diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_PropertySet.h b/JuceLibraryCode/modules/juce_core/containers/juce_PropertySet.h index 3b4ee32..c9da4ed 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_PropertySet.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_PropertySet.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. @@ -104,8 +104,8 @@ class JUCE_API PropertySet /** Returns one of the properties as an XML element. - The result will a new XMLElement object that the caller must delete. If may return nullptr - if the key isn't found, or if the entry contains an string that isn't valid XML. + The result will a new XMLElement object. It may return nullptr if the key isn't found, + or if the entry contains an string that isn't valid XML. If the value isn't found in this set, then this will look for it in a fallback property set (if you've specified one with the setFallbackPropertySet() method), @@ -113,7 +113,7 @@ class JUCE_API PropertySet @param keyName the name of the property to retrieve */ - XmlElement* getXmlValue (StringRef keyName) const; + std::unique_ptr getXmlValue (StringRef keyName) const; //============================================================================== /** Sets a named property. @@ -121,7 +121,7 @@ class JUCE_API PropertySet @param keyName the name of the property to set. (This mustn't be an empty string) @param value the new value to set it to */ - void setValue (const String& keyName, const var& value); + void setValue (StringRef keyName, const var& value); /** Sets a named property to an XML element. @@ -130,7 +130,7 @@ class JUCE_API PropertySet be set to an empty string @see getXmlValue */ - void setValue (const String& keyName, const XmlElement* xml); + void setValue (StringRef keyName, const XmlElement* xml); /** This copies all the values from a source PropertySet to this one. This won't remove any existing settings, it just adds any that it finds in the source set. @@ -143,7 +143,7 @@ class JUCE_API PropertySet */ void removeValue (StringRef keyName); - /** Returns true if the properies include the given key. */ + /** Returns true if the properties include the given key. */ bool containsKey (StringRef keyName) const noexcept; /** Removes all values. */ @@ -161,7 +161,7 @@ class JUCE_API PropertySet The string parameter is the tag name that should be used for the node. @see restoreFromXml */ - XmlElement* createXml (const String& nodeName) const; + std::unique_ptr createXml (const String& nodeName) const; /** Reloads a set of properties that were previously stored as XML. The node passed in must have been created by the createXml() method. @@ -190,7 +190,7 @@ class JUCE_API PropertySet PropertySet* getFallbackPropertySet() const noexcept { return fallbackProperties; } protected: - /** Subclasses can override this to be told when one of the properies has been changed. */ + /** Subclasses can override this to be told when one of the properties has been changed. */ virtual void propertyChanged(); private: diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_ReferenceCountedArray.cpp b/JuceLibraryCode/modules/juce_core/containers/juce_ReferenceCountedArray.cpp index 0769646..dc11d67 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_ReferenceCountedArray.cpp +++ b/JuceLibraryCode/modules/juce_core/containers/juce_ReferenceCountedArray.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2018 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -28,7 +28,9 @@ namespace juce class ReferenceCountedArrayTests : public UnitTest { public: - ReferenceCountedArrayTests() : UnitTest ("ReferenceCountedArray", "Containers") {} + ReferenceCountedArrayTests() + : UnitTest ("ReferenceCountedArray", UnitTestCategories::containers) + {} //============================================================================== void runTest() override @@ -82,12 +84,7 @@ class ReferenceCountedArrayTests : public UnitTest expectEquals (derivedObject->getReferenceCount(), 1); baseArray.add (baseObjectPtr); - - #if JUCE_STRICT_REFCOUNTEDPOINTER - baseArray.add (derivedObjectPtr); - #else baseArray.add (derivedObjectPtr.get()); - #endif for (auto o : baseArray) expectEquals (o->getReferenceCount(), 2); @@ -97,6 +94,34 @@ class ReferenceCountedArrayTests : public UnitTest for (auto o : derivedArray) expectEquals (o->getReferenceCount(), 3); } + + beginTest ("Iterate in destructor"); + { + { + ReferenceCountedArray arr; + + for (int i = 0; i < 2; ++i) + arr.add (new DestructorObj (*this, arr)); + } + + ReferenceCountedArray arr; + + for (int i = 0; i < 1025; ++i) + arr.add (new DestructorObj (*this, arr)); + + while (! arr.isEmpty()) + arr.remove (0); + + for (int i = 0; i < 1025; ++i) + arr.add (new DestructorObj (*this, arr)); + + arr.removeRange (1, arr.size() - 3); + + for (int i = 0; i < 1025; ++i) + arr.add (new DestructorObj (*this, arr)); + + arr.set (500, new DestructorObj (*this, arr)); + } } private: @@ -105,6 +130,8 @@ class ReferenceCountedArrayTests : public UnitTest using Ptr = ReferenceCountedObjectPtr; TestBaseObj() = default; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TestBaseObj) }; struct TestDerivedObj : public TestBaseObj @@ -112,6 +139,34 @@ class ReferenceCountedArrayTests : public UnitTest using Ptr = ReferenceCountedObjectPtr; TestDerivedObj() = default; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TestDerivedObj) + }; + + struct DestructorObj : public ReferenceCountedObject + { + DestructorObj (ReferenceCountedArrayTests& p, + ReferenceCountedArray& arr) + : parent (p), objectArray (arr) + {} + + ~DestructorObj() + { + data = 0; + + for (auto* o : objectArray) + { + parent.expect (o != nullptr); + parent.expect (o != this); + parent.expectEquals (o->data, 374); + } + } + + ReferenceCountedArrayTests& parent; + ReferenceCountedArray& objectArray; + int data = 374; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DestructorObj) }; }; diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_ReferenceCountedArray.h b/JuceLibraryCode/modules/juce_core/containers/juce_ReferenceCountedArray.h index 227258e..157a5a4 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_ReferenceCountedArray.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_ReferenceCountedArray.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. @@ -240,15 +240,31 @@ class ReferenceCountedArray /** Returns a pointer to the first element in the array. This method is provided for compatibility with standard C++ iteration mechanisms. */ - inline ObjectClass** begin() const noexcept + inline ObjectClass** begin() noexcept { return values.begin(); } + /** Returns a pointer to the first element in the array. + This method is provided for compatibility with standard C++ iteration mechanisms. + */ + inline ObjectClass* const* begin() const noexcept + { + return values.begin(); + } + + /** Returns a pointer to the element which follows the last element in the array. + This method is provided for compatibility with standard C++ iteration mechanisms. + */ + inline ObjectClass** end() noexcept + { + return values.end(); + } + /** Returns a pointer to the element which follows the last element in the array. This method is provided for compatibility with standard C++ iteration mechanisms. */ - inline ObjectClass** end() const noexcept + inline ObjectClass* const* end() const noexcept { return values.end(); } @@ -256,7 +272,15 @@ class ReferenceCountedArray /** Returns a pointer to the first element in the array. This method is provided for compatibility with the standard C++ containers. */ - inline ObjectClass** data() const noexcept + inline ObjectClass** data() noexcept + { + return begin(); + } + + /** Returns a pointer to the first element in the array. + This method is provided for compatibility with the standard C++ containers. + */ + inline ObjectClass* const* data() const noexcept { return begin(); } @@ -270,8 +294,8 @@ class ReferenceCountedArray int indexOf (const ObjectClass* objectToLookFor) const noexcept { const ScopedLockType lock (getLock()); - auto** e = values.begin(); - auto** endPointer = values.end(); + auto* e = values.begin(); + auto* endPointer = values.end(); while (e != endPointer) { @@ -299,8 +323,8 @@ class ReferenceCountedArray bool contains (const ObjectClass* objectToLookFor) const noexcept { const ScopedLockType lock (getLock()); - auto** e = values.begin(); - auto** endPointer = values.end(); + auto* e = values.begin(); + auto* endPointer = values.end(); while (e != endPointer) { @@ -437,8 +461,9 @@ class ReferenceCountedArray if (indexToChange < values.size()) { - releaseObject (values[indexToChange]); + auto* e = values[indexToChange]; values[indexToChange] = newObject; + releaseObject (e); } else { @@ -447,6 +472,20 @@ class ReferenceCountedArray } } + /** Replaces an object in the array with a different one. + + If the index is less than zero, this method does nothing. + If the index is beyond the end of the array, the new object is added to the end of the array. + + The object being added has its reference count increased, and if it's replacing + another object, then that one has its reference count decreased, and may be deleted. + + @param indexToChange the index whose value you want to change + @param newObject the new value to set for this index. + @see add, insert, remove + */ + void set (int indexToChange, const ObjectClassPtr& newObject) { set (indexToChange, newObject.get()); } + /** Adds elements from another array to the end of this array. @param arrayToAddFrom the array from which to copy the elements @@ -570,9 +609,9 @@ class ReferenceCountedArray if (isPositiveAndBelow (indexToRemove, values.size())) { - auto** e = values.begin() + indexToRemove; - releaseObject (*e); + auto* e = *(values.begin() + indexToRemove); values.removeElements (indexToRemove, 1); + releaseObject (e); if ((values.size() << 1) < values.capacity()) minimiseStorageOverheads(); @@ -595,10 +634,10 @@ class ReferenceCountedArray if (isPositiveAndBelow (indexToRemove, values.size())) { - auto** e = values.begin() + indexToRemove; - removedItem = *e; - releaseObject (*e); + auto* e = *(values.begin() + indexToRemove); + removedItem = e; values.removeElements (indexToRemove, 1); + releaseObject (e); if ((values.size() << 1) < values.capacity()) minimiseStorageOverheads(); @@ -656,14 +695,14 @@ class ReferenceCountedArray if (numberToRemove > 0) { - for (int i = startIndex; i < endIndex; ++i) - { - releaseObject (values[i]); - values[i] = nullptr; // (in case one of the destructors accesses this array and hits a dangling pointer) - } + Array objectsToRemove; + objectsToRemove.addArray (values.begin() + startIndex, numberToRemove); values.removeElements (startIndex, numberToRemove); + for (auto& o : objectsToRemove) + releaseObject (o); + if ((values.size() << 1) < values.capacity()) minimiseStorageOverheads(); } @@ -790,7 +829,7 @@ class ReferenceCountedArray */ template void sort (ElementComparator& comparator, - bool retainOrderOfEquivalentItems = false) const noexcept + bool retainOrderOfEquivalentItems = false) noexcept { // If you pass in an object with a static compareElements() method, this // avoids getting warning messages about the parameter being unused @@ -848,10 +887,14 @@ class ReferenceCountedArray void releaseAllObjects() { - for (auto& v : values) - releaseObject (v); + auto i = values.size(); - values.clear(); + while (--i >= 0) + { + auto* e = values[i]; + values.removeElements (i, 1); + releaseObject (e); + } } static void releaseObject (ObjectClass* o) diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_ScopedValueSetter.h b/JuceLibraryCode/modules/juce_core/containers/juce_ScopedValueSetter.h index d4ff9f6..456bc58 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_ScopedValueSetter.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_ScopedValueSetter.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_core/containers/juce_SortedSet.h b/JuceLibraryCode/modules/juce_core/containers/juce_SortedSet.h index e791a74..bf0f27b 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_SortedSet.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_SortedSet.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,7 @@ namespace juce { -#if JUCE_MSVC - #pragma warning (push) - #pragma warning (disable: 4512) -#endif +JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4512) //============================================================================== /** @@ -58,22 +55,19 @@ class SortedSet public: //============================================================================== /** Creates an empty set. */ - // VS2013 doesn't allow defaulted noexcept constructors. SortedSet() = default; /** Creates a copy of another set. */ SortedSet (const SortedSet&) = default; /** Creates a copy of another set. */ - // VS2013 doesn't allow defaulted noexcept constructors. - SortedSet (SortedSet&& other) noexcept : data (std::move (other.data)) {} + SortedSet (SortedSet&&) noexcept = default; /** Makes a copy of another set. */ SortedSet& operator= (const SortedSet&) = default; /** Makes a copy of another set. */ - // VS2013 doesn't allow defaulted noexcept constructors. - SortedSet& operator= (SortedSet&& other) noexcept { data = std::move (other.data); return *this; } + SortedSet& operator= (SortedSet&&) noexcept = default; /** Destructor. */ ~SortedSet() = default; @@ -169,7 +163,16 @@ class SortedSet @param index the index of the element being requested (0 is the first element in the array) */ - inline ElementType& getReference (const int index) const noexcept + inline ElementType& getReference (const int index) noexcept + { + return data.getReference (index); + } + + /** Returns a direct reference to one of the elements in the set, without checking the index passed in. + + @param index the index of the element being requested (0 is the first element in the array) + */ + inline const ElementType& getReference (const int index) const noexcept { return data.getReference (index); } @@ -194,7 +197,7 @@ class SortedSet /** Returns a pointer to the first element in the set. This method is provided for compatibility with standard C++ iteration mechanisms. */ - inline ElementType* begin() const noexcept + inline const ElementType* begin() const noexcept { return data.begin(); } @@ -202,7 +205,7 @@ class SortedSet /** Returns a pointer to the element which follows the last element in the set. This method is provided for compatibility with standard C++ iteration mechanisms. */ - inline ElementType* end() const noexcept + inline const ElementType* end() const noexcept { return data.end(); } @@ -374,7 +377,7 @@ class SortedSet @param valueToRemove the object to try to remove @see remove, removeRange */ - void removeValue (const ElementType valueToRemove) noexcept + void removeValue (const ElementType& valueToRemove) noexcept { const ScopedLockType lock (getLock()); data.remove (indexOf (valueToRemove)); @@ -481,8 +484,6 @@ class SortedSet Array data; }; -#if JUCE_MSVC - #pragma warning (pop) -#endif +JUCE_END_IGNORE_WARNINGS_MSVC } // namespace juce diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_SparseSet.cpp b/JuceLibraryCode/modules/juce_core/containers/juce_SparseSet.cpp index 194910b..0c61ed9 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_SparseSet.cpp +++ b/JuceLibraryCode/modules/juce_core/containers/juce_SparseSet.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the JUCE library. - Copyright (c) 2018 - ROLI Ltd. + Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. @@ -28,7 +28,9 @@ namespace juce class SparseSetTests : public UnitTest { public: - SparseSetTests() : UnitTest ("SparseSet class", "Containers") {} + SparseSetTests() + : UnitTest ("SparseSet class", UnitTestCategories::containers) + {} void runTest() override { diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_SparseSet.h b/JuceLibraryCode/modules/juce_core/containers/juce_SparseSet.h index 0c2ae72..fb51d8e 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_SparseSet.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_SparseSet.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_core/containers/juce_Variant.cpp b/JuceLibraryCode/modules/juce_core/containers/juce_Variant.cpp index a3b08c0..129540f 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_Variant.cpp +++ b/JuceLibraryCode/modules/juce_core/containers/juce_Variant.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. @@ -175,7 +175,7 @@ class var::VariantType_Double : public var::VariantType int toInt (const ValueUnion& data) const noexcept override { return (int) data.doubleValue; } int64 toInt64 (const ValueUnion& data) const noexcept override { return (int64) data.doubleValue; } double toDouble (const ValueUnion& data) const noexcept override { return data.doubleValue; } - String toString (const ValueUnion& data) const override { return minimiseLengthOfFloatString (String (data.doubleValue, 15, true)); } + String toString (const ValueUnion& data) const override { return serialiseDouble (data.doubleValue); } bool toBool (const ValueUnion& data) const noexcept override { return data.doubleValue != 0.0; } bool isDouble() const noexcept override { return true; } bool isComparable() const noexcept override { return true; } @@ -257,8 +257,8 @@ class var::VariantType_String : public var::VariantType } private: - static inline const String* getString (const ValueUnion& data) noexcept { return reinterpret_cast (data.stringValue); } - static inline String* getString (ValueUnion& data) noexcept { return reinterpret_cast (data.stringValue); } + static const String* getString (const ValueUnion& data) noexcept { return reinterpret_cast (data.stringValue); } + static String* getString (ValueUnion& data) noexcept { return reinterpret_cast (data.stringValue); } }; //============================================================================== diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_Variant.h b/JuceLibraryCode/modules/juce_core/containers/juce_Variant.h index da50fc4..00b2ff0 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_Variant.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_Variant.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,9 +49,6 @@ class JUCE_API var { NativeFunctionArgs (const var& thisObject, const var* args, int numArgs) noexcept; - // Suppress a VS2013 compiler warning - NativeFunctionArgs& operator= (const NativeFunctionArgs&) = delete; - const var& thisObject; const var* arguments; int numArguments; @@ -305,7 +302,7 @@ class JUCE_API var int64 int64Value; bool boolValue; double doubleValue; - char stringValue [sizeof (String)]; + char stringValue[sizeof (String)]; ReferenceCountedObject* objectValue; MemoryBlock* binaryValue; NativeFunction* methodValue; @@ -322,6 +319,8 @@ class JUCE_API var // This is needed to prevent the wrong constructor/operator being called var (const ReferenceCountedObject*) = delete; var& operator= (const ReferenceCountedObject*) = delete; + var (const void*) = delete; + var& operator= (const void*) = delete; }; /** Compares the values of two var objects, using the var::equals() comparison. */ diff --git a/JuceLibraryCode/modules/juce_core/files/juce_DirectoryIterator.cpp b/JuceLibraryCode/modules/juce_core/files/juce_DirectoryIterator.cpp index 0c0b152..2c17654 100644 --- a/JuceLibraryCode/modules/juce_core/files/juce_DirectoryIterator.cpp +++ b/JuceLibraryCode/modules/juce_core/files/juce_DirectoryIterator.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. @@ -64,6 +64,9 @@ bool DirectoryIterator::next() return next (nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); } +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") +JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996) + bool DirectoryIterator::next (bool* isDirResult, bool* isHiddenResult, int64* fileSize, Time* modTime, Time* creationTime, bool* isReadOnly) { @@ -134,6 +137,9 @@ bool DirectoryIterator::next (bool* isDirResult, bool* isHiddenResult, int64* fi } } +JUCE_END_IGNORE_WARNINGS_GCC_LIKE +JUCE_END_IGNORE_WARNINGS_MSVC + const File& DirectoryIterator::getFile() const { if (subIterator != nullptr && subIterator->hasBeenAdvanced) @@ -153,10 +159,10 @@ float DirectoryIterator::getEstimatedProgress() const if (totalNumFiles <= 0) return 0.0f; - auto detailedIndex = (subIterator != nullptr) ? index + subIterator->getEstimatedProgress() + auto detailedIndex = (subIterator != nullptr) ? (float) index + subIterator->getEstimatedProgress() : (float) index; - return jlimit (0.0f, 1.0f, detailedIndex / totalNumFiles); + return jlimit (0.0f, 1.0f, detailedIndex / (float) totalNumFiles); } } // namespace juce diff --git a/JuceLibraryCode/modules/juce_core/files/juce_DirectoryIterator.h b/JuceLibraryCode/modules/juce_core/files/juce_DirectoryIterator.h index 23711e4..cbf19cc 100644 --- a/JuceLibraryCode/modules/juce_core/files/juce_DirectoryIterator.h +++ b/JuceLibraryCode/modules/juce_core/files/juce_DirectoryIterator.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. @@ -25,6 +25,8 @@ namespace juce //============================================================================== /** + This class is now deprecated in favour of RangedDirectoryIterator. + Searches through the files in a directory, returning each file that is found. A DirectoryIterator will search through a directory and its subdirectories using @@ -42,12 +44,15 @@ namespace juce It also provides an estimate of its progress, using a (highly inaccurate!) algorithm. @tags{Core} + @see RangedDirectoryIterator */ class JUCE_API DirectoryIterator final { public: //============================================================================== - /** Creates a DirectoryIterator for a given directory. + /** This class is now deprecated in favour of RangedDirectoryIterator. + + Creates a DirectoryIterator for a given directory. After creating one of these, call its next() method to get the first file - e.g. @code @@ -62,17 +67,12 @@ class JUCE_API DirectoryIterator final } @endcode - @param directory the directory to search in - @param isRecursive whether all the subdirectories should also be searched - @param wildCard the file pattern to match. This may contain multiple patterns - separated by a semi-colon or comma, e.g. "*.jpg;*.png" - @param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying - whether to look for files, directories, or both. + @see RangedDirectoryIterator */ - DirectoryIterator (const File& directory, - bool isRecursive, - const String& wildCard = "*", - int whatToLookFor = File::findFiles); + JUCE_DEPRECATED (DirectoryIterator (const File& directory, + bool isRecursive, + const String& wildCard = "*", + int whatToLookFor = File::findFiles)); /** Destructor. */ ~DirectoryIterator(); diff --git a/JuceLibraryCode/modules/juce_core/files/juce_File.cpp b/JuceLibraryCode/modules/juce_core/files/juce_File.cpp index 3df73d2..0fbb9f3 100644 --- a/JuceLibraryCode/modules/juce_core/files/juce_File.cpp +++ b/JuceLibraryCode/modules/juce_core/files/juce_File.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. @@ -104,6 +104,26 @@ static String removeEllipsis (const String& path) return path; } +static String normaliseSeparators (const String& path) +{ + auto normalisedPath = path; + + String separator (File::getSeparatorString()); + String doubleSeparator (separator + separator); + + auto uncPath = normalisedPath.startsWith (doubleSeparator) + && ! normalisedPath.fromFirstOccurrenceOf (doubleSeparator, false, false).startsWith (separator); + + if (uncPath) + normalisedPath = normalisedPath.fromFirstOccurrenceOf (doubleSeparator, false, false); + + while (normalisedPath.contains (doubleSeparator)) + normalisedPath = normalisedPath.replace (doubleSeparator, separator); + + return uncPath ? doubleSeparator + normalisedPath + : normalisedPath; +} + bool File::isRoot() const { return fullPath.isNotEmpty() && *this == getParentDirectory(); @@ -114,9 +134,9 @@ String File::parseAbsolutePath (const String& p) if (p.isEmpty()) return {}; -#if JUCE_WINDOWS + #if JUCE_WINDOWS // Windows.. - auto path = removeEllipsis (p.replaceCharacter ('/', '\\')); + auto path = normaliseSeparators (removeEllipsis (p.replaceCharacter ('/', '\\'))); if (path.startsWithChar (getSeparatorChar())) { @@ -147,7 +167,7 @@ String File::parseAbsolutePath (const String& p) return File::getCurrentWorkingDirectory().getChildFile (path).getFullPathName(); } -#else + #else // Mac or Linux.. // Yes, I know it's legal for a unix pathname to contain a backslash, but this assertion is here @@ -155,7 +175,7 @@ String File::parseAbsolutePath (const String& p) // If that's why you've ended up here, use File::getChildFile() to build your paths instead. jassert ((! p.containsChar ('\\')) || (p.indexOfChar ('/') >= 0 && p.indexOfChar ('/') < p.indexOfChar ('\\'))); - auto path = removeEllipsis (p); + auto path = normaliseSeparators (removeEllipsis (p)); if (path.startsWithChar ('~')) { @@ -196,7 +216,7 @@ String File::parseAbsolutePath (const String& p) return File::getCurrentWorkingDirectory().getChildFile (path).getFullPathName(); } -#endif + #endif while (path.endsWithChar (getSeparatorChar()) && path != getSeparatorString()) // careful not to turn a single "/" into an empty string. path = path.dropLastCharacters (1); @@ -465,7 +485,7 @@ String File::descriptionOfSizeInBytes (const int64 bytes) else if (bytes < 1024 * 1024 * 1024) { suffix = " MB"; divisor = 1024.0 * 1024.0; } else { suffix = " GB"; divisor = 1024.0 * 1024.0 * 1024.0; } - return (divisor > 0 ? String (bytes / divisor, 1) : String (bytes)) + suffix; + return (divisor > 0 ? String ((double) bytes / divisor, 1) : String (bytes)) + suffix; } //============================================================================== @@ -554,7 +574,7 @@ int File::findChildFiles (Array& results, int whatToLookFor, bool searchRe { int total = 0; - for (DirectoryIterator di (*this, searchRecursively, wildcard, whatToLookFor); di.next();) + for (const auto& di : RangedDirectoryIterator (*this, searchRecursively, wildcard, whatToLookFor)) { results.add (di.getFile()); ++total; @@ -565,12 +585,10 @@ int File::findChildFiles (Array& results, int whatToLookFor, bool searchRe int File::getNumberOfChildFiles (const int whatToLookFor, const String& wildCardPattern) const { - int total = 0; - - for (DirectoryIterator di (*this, false, wildCardPattern, whatToLookFor); di.next();) - ++total; - - return total; + return std::accumulate (RangedDirectoryIterator (*this, false, wildCardPattern, whatToLookFor), + RangedDirectoryIterator(), + 0, + [] (int acc, const DirectoryEntry&) { return acc + 1; }); } bool File::containsSubDirectories() const @@ -578,8 +596,7 @@ bool File::containsSubDirectories() const if (! isDirectory()) return false; - DirectoryIterator di (*this, false, "*", findDirectories); - return di.next(); + return RangedDirectoryIterator (*this, false, "*", findDirectories) != RangedDirectoryIterator(); } //============================================================================== @@ -706,22 +723,24 @@ bool File::startAsProcess (const String& parameters) const } //============================================================================== -FileInputStream* File::createInputStream() const +std::unique_ptr File::createInputStream() const { - std::unique_ptr fin (new FileInputStream (*this)); + auto fin = std::make_unique (*this); if (fin->openedOk()) - return fin.release(); + return fin; return nullptr; } -FileOutputStream* File::createOutputStream (size_t bufferSize) const +std::unique_ptr File::createOutputStream (size_t bufferSize) const { - std::unique_ptr out (new FileOutputStream (*this, bufferSize)); + auto fout = std::make_unique (*this, bufferSize); - return out->failedToOpen() ? nullptr - : out.release(); + if (fout->openedOk()) + return fout; + + return nullptr; } //============================================================================== @@ -733,8 +752,8 @@ bool File::appendData (const void* const dataToAppend, if (numberOfBytes == 0) return true; - FileOutputStream out (*this, 8192); - return out.openedOk() && out.write (dataToAppend, numberOfBytes); + FileOutputStream fout (*this, 8192); + return fout.openedOk() && fout.write (dataToAppend, numberOfBytes); } bool File::replaceWithData (const void* const dataToWrite, @@ -750,12 +769,12 @@ bool File::replaceWithData (const void* const dataToWrite, bool File::appendText (const String& text, bool asUnicode, bool writeHeaderBytes, const char* lineFeed) const { - FileOutputStream out (*this); + FileOutputStream fout (*this); - if (out.failedToOpen()) + if (fout.failedToOpen()) return false; - return out.writeText (text, asUnicode, writeHeaderBytes, lineFeed); + return fout.writeText (text, asUnicode, writeHeaderBytes, lineFeed); } bool File::replaceWithText (const String& textToWrite, bool asUnicode, bool writeHeaderBytes, const char* lineFeed) const @@ -1004,13 +1023,16 @@ MemoryMappedFile::MemoryMappedFile (const File& file, const Range& fileRa } +//============================================================================== //============================================================================== #if JUCE_UNIT_TESTS class FileTests : public UnitTest { public: - FileTests() : UnitTest ("Files", "Files") {} + FileTests() + : UnitTest ("Files", UnitTestCategories::files) + {} void runTest() override { @@ -1028,7 +1050,6 @@ class FileTests : public UnitTest expect (home.isDirectory()); expect (home.exists()); expect (! home.existsAsFile()); - expect (File::getSpecialLocation (File::userDocumentsDirectory).isDirectory()); expect (File::getSpecialLocation (File::userApplicationDataDirectory).isDirectory()); expect (File::getSpecialLocation (File::currentExecutableFile).exists()); expect (File::getSpecialLocation (File::currentApplicationFile).exists()); @@ -1195,6 +1216,28 @@ class FileTests : public UnitTest expect (demoFolder.deleteRecursively()); expect (! demoFolder.exists()); + + { + URL url ("https://audio.dev/foo/bar/"); + expectEquals (url.toString (false), String ("https://audio.dev/foo/bar/")); + expectEquals (url.getChildURL ("x").toString (false), String ("https://audio.dev/foo/bar/x")); + expectEquals (url.getParentURL().toString (false), String ("https://audio.dev/foo")); + expectEquals (url.getParentURL().getParentURL().toString (false), String ("https://audio.dev/")); + expectEquals (url.getParentURL().getParentURL().getParentURL().toString (false), String ("https://audio.dev/")); + expectEquals (url.getParentURL().getChildURL ("x").toString (false), String ("https://audio.dev/foo/x")); + expectEquals (url.getParentURL().getParentURL().getParentURL().getChildURL ("x").toString (false), String ("https://audio.dev/x")); + } + + { + URL url ("https://audio.dev/foo/bar"); + expectEquals (url.toString (false), String ("https://audio.dev/foo/bar")); + expectEquals (url.getChildURL ("x").toString (false), String ("https://audio.dev/foo/bar/x")); + expectEquals (url.getParentURL().toString (false), String ("https://audio.dev/foo")); + expectEquals (url.getParentURL().getParentURL().toString (false), String ("https://audio.dev/")); + expectEquals (url.getParentURL().getParentURL().getParentURL().toString (false), String ("https://audio.dev/")); + expectEquals (url.getParentURL().getChildURL ("x").toString (false), String ("https://audio.dev/foo/x")); + expectEquals (url.getParentURL().getParentURL().getParentURL().getChildURL ("x").toString (false), String ("https://audio.dev/x")); + } } }; diff --git a/JuceLibraryCode/modules/juce_core/files/juce_File.h b/JuceLibraryCode/modules/juce_core/files/juce_File.h index 644ad9d..d060d06 100644 --- a/JuceLibraryCode/modules/juce_core/files/juce_File.h +++ b/JuceLibraryCode/modules/juce_core/files/juce_File.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,6 +20,14 @@ ============================================================================== */ +#if ! DOXYGEN && (JUCE_MAC || JUCE_IOS) + #if __LP64__ + using OSType = unsigned int; + #else + using OSType = unsigned long; + #endif +#endif + namespace juce { @@ -566,7 +574,7 @@ class JUCE_API File final @param wildCardPattern the filename pattern to search for, e.g. "*.txt" @returns the set of files that were found - @see getNumberOfChildFiles, DirectoryIterator + @see getNumberOfChildFiles, RangedDirectoryIterator */ Array findChildFiles (int whatToLookFor, bool searchRecursively, @@ -594,7 +602,8 @@ class JUCE_API File final is also added to this value, hidden files won't be counted @param wildCardPattern the filename pattern to search for, e.g. "*.txt" @returns the number of matches found - @see findChildFiles, DirectoryIterator + + @see findChildFiles, RangedDirectoryIterator */ int getNumberOfChildFiles (int whatToLookFor, const String& wildCardPattern = "*") const; @@ -622,7 +631,7 @@ class JUCE_API File final start of the file), or nullptr if the file can't be opened for some reason @see createOutputStream, loadFileAsData */ - FileInputStream* createInputStream() const; + std::unique_ptr createInputStream() const; /** Creates a stream to write to this file. @@ -655,7 +664,7 @@ class JUCE_API File final end of the file), or nullptr if the file can't be opened for some reason @see createInputStream, appendData, appendText */ - FileOutputStream* createOutputStream (size_t bufferSize = 0x8000) const; + std::unique_ptr createOutputStream (size_t bufferSize = 0x8000) const; //============================================================================== /** Loads a file's contents into memory as a block of binary data. diff --git a/JuceLibraryCode/modules/juce_core/files/juce_FileFilter.cpp b/JuceLibraryCode/modules/juce_core/files/juce_FileFilter.cpp index 467f8d7..c0b0e55 100644 --- a/JuceLibraryCode/modules/juce_core/files/juce_FileFilter.cpp +++ b/JuceLibraryCode/modules/juce_core/files/juce_FileFilter.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_core/files/juce_FileFilter.h b/JuceLibraryCode/modules/juce_core/files/juce_FileFilter.h index 52dbbd0..9421fdc 100644 --- a/JuceLibraryCode/modules/juce_core/files/juce_FileFilter.h +++ b/JuceLibraryCode/modules/juce_core/files/juce_FileFilter.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_core/files/juce_FileInputStream.cpp b/JuceLibraryCode/modules/juce_core/files/juce_FileInputStream.cpp index 4af76cc..8bb5d33 100644 --- a/JuceLibraryCode/modules/juce_core/files/juce_FileInputStream.cpp +++ b/JuceLibraryCode/modules/juce_core/files/juce_FileInputStream.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. @@ -76,74 +76,97 @@ bool FileInputStream::setPosition (int64 pos) return currentPosition == pos; } + +//============================================================================== //============================================================================== #if JUCE_UNIT_TESTS struct FileInputStreamTests : public UnitTest { FileInputStreamTests() - : UnitTest ("FileInputStream", "Streams") + : UnitTest ("FileInputStream", UnitTestCategories::streams) {} void runTest() override { + beginTest ("Open stream non-existent file"); + { + auto tempFile = File::createTempFile (".txt"); + expect (! tempFile.exists()); + + FileInputStream stream (tempFile); + expect (stream.failedToOpen()); + } + + beginTest ("Open stream existing file"); + { + auto tempFile = File::createTempFile (".txt"); + tempFile.create(); + expect (tempFile.exists()); + + FileInputStream stream (tempFile); + expect (stream.openedOk()); + } + const MemoryBlock data ("abcdefghijklmnopqrstuvwxyz", 26); File f (File::createTempFile (".txt")); f.appendData (data.getData(), data.getSize()); FileInputStream stream (f); beginTest ("Read"); - - expectEquals (stream.getPosition(), (int64) 0); - expectEquals (stream.getTotalLength(), (int64) data.getSize()); - expectEquals (stream.getNumBytesRemaining(), stream.getTotalLength()); - expect (! stream.isExhausted()); - - size_t numBytesRead = 0; - MemoryBlock readBuffer (data.getSize()); - - while (numBytesRead < data.getSize()) { - numBytesRead += (size_t) stream.read (&readBuffer[numBytesRead], 3); + expectEquals (stream.getPosition(), (int64) 0); + expectEquals (stream.getTotalLength(), (int64) data.getSize()); + expectEquals (stream.getNumBytesRemaining(), stream.getTotalLength()); + expect (! stream.isExhausted()); - expectEquals (stream.getPosition(), (int64) numBytesRead); - expectEquals (stream.getNumBytesRemaining(), (int64) (data.getSize() - numBytesRead)); - expect (stream.isExhausted() == (numBytesRead == data.getSize())); - } + size_t numBytesRead = 0; + MemoryBlock readBuffer (data.getSize()); - expectEquals (stream.getPosition(), (int64) data.getSize()); - expectEquals (stream.getNumBytesRemaining(), (int64) 0); - expect (stream.isExhausted()); + while (numBytesRead < data.getSize()) + { + numBytesRead += (size_t) stream.read (&readBuffer[numBytesRead], 3); - expect (readBuffer == data); - - beginTest ("Skip"); + expectEquals (stream.getPosition(), (int64) numBytesRead); + expectEquals (stream.getNumBytesRemaining(), (int64) (data.getSize() - numBytesRead)); + expect (stream.isExhausted() == (numBytesRead == data.getSize())); + } - stream.setPosition (0); - expectEquals (stream.getPosition(), (int64) 0); - expectEquals (stream.getTotalLength(), (int64) data.getSize()); - expectEquals (stream.getNumBytesRemaining(), stream.getTotalLength()); - expect (! stream.isExhausted()); + expectEquals (stream.getPosition(), (int64) data.getSize()); + expectEquals (stream.getNumBytesRemaining(), (int64) 0); + expect (stream.isExhausted()); - numBytesRead = 0; - const int numBytesToSkip = 5; + expect (readBuffer == data); + } - while (numBytesRead < data.getSize()) + beginTest ("Skip"); { - stream.skipNextBytes (numBytesToSkip); - numBytesRead += numBytesToSkip; - numBytesRead = std::min (numBytesRead, data.getSize()); - - expectEquals (stream.getPosition(), (int64) numBytesRead); - expectEquals (stream.getNumBytesRemaining(), (int64) (data.getSize() - numBytesRead)); - expect (stream.isExhausted() == (numBytesRead == data.getSize())); + stream.setPosition (0); + expectEquals (stream.getPosition(), (int64) 0); + expectEquals (stream.getTotalLength(), (int64) data.getSize()); + expectEquals (stream.getNumBytesRemaining(), stream.getTotalLength()); + expect (! stream.isExhausted()); + + size_t numBytesRead = 0; + const int numBytesToSkip = 5; + + while (numBytesRead < data.getSize()) + { + stream.skipNextBytes (numBytesToSkip); + numBytesRead += numBytesToSkip; + numBytesRead = std::min (numBytesRead, data.getSize()); + + expectEquals (stream.getPosition(), (int64) numBytesRead); + expectEquals (stream.getNumBytesRemaining(), (int64) (data.getSize() - numBytesRead)); + expect (stream.isExhausted() == (numBytesRead == data.getSize())); + } + + expectEquals (stream.getPosition(), (int64) data.getSize()); + expectEquals (stream.getNumBytesRemaining(), (int64) 0); + expect (stream.isExhausted()); + + f.deleteFile(); } - - expectEquals (stream.getPosition(), (int64) data.getSize()); - expectEquals (stream.getNumBytesRemaining(), (int64) 0); - expect (stream.isExhausted()); - - f.deleteFile(); } }; diff --git a/JuceLibraryCode/modules/juce_core/files/juce_FileInputStream.h b/JuceLibraryCode/modules/juce_core/files/juce_FileInputStream.h index fdff83c..fccbaac 100644 --- a/JuceLibraryCode/modules/juce_core/files/juce_FileInputStream.h +++ b/JuceLibraryCode/modules/juce_core/files/juce_FileInputStream.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_core/files/juce_FileOutputStream.cpp b/JuceLibraryCode/modules/juce_core/files/juce_FileOutputStream.cpp index 59e592c..b84d877 100644 --- a/JuceLibraryCode/modules/juce_core/files/juce_FileOutputStream.cpp +++ b/JuceLibraryCode/modules/juce_core/files/juce_FileOutputStream.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,8 +23,6 @@ namespace juce { -int64 juce_fileSetPosition (void* handle, int64 pos); - //============================================================================== FileOutputStream::FileOutputStream (const File& f, const size_t bufferSizeToUse) : file (f), @@ -79,6 +77,9 @@ bool FileOutputStream::write (const void* const src, const size_t numBytes) { jassert (src != nullptr && ((ssize_t) numBytes) >= 0); + if (! openedOk()) + return false; + if (bytesInBuffer + numBytes < bufferSize) { memcpy (buffer + bytesInBuffer, src, numBytes); diff --git a/JuceLibraryCode/modules/juce_core/files/juce_FileOutputStream.h b/JuceLibraryCode/modules/juce_core/files/juce_FileOutputStream.h index 68307e2..004640e 100644 --- a/JuceLibraryCode/modules/juce_core/files/juce_FileOutputStream.h +++ b/JuceLibraryCode/modules/juce_core/files/juce_FileOutputStream.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_core/files/juce_FileSearchPath.cpp b/JuceLibraryCode/modules/juce_core/files/juce_FileSearchPath.cpp index e2bcff2..2c72da2 100644 --- a/JuceLibraryCode/modules/juce_core/files/juce_FileSearchPath.cpp +++ b/JuceLibraryCode/modules/juce_core/files/juce_FileSearchPath.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_core/files/juce_FileSearchPath.h b/JuceLibraryCode/modules/juce_core/files/juce_FileSearchPath.h index 4d900b8..b595300 100644 --- a/JuceLibraryCode/modules/juce_core/files/juce_FileSearchPath.h +++ b/JuceLibraryCode/modules/juce_core/files/juce_FileSearchPath.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_core/files/juce_MemoryMappedFile.h b/JuceLibraryCode/modules/juce_core/files/juce_MemoryMappedFile.h index 3be541f..4f13e6b 100644 --- a/JuceLibraryCode/modules/juce_core/files/juce_MemoryMappedFile.h +++ b/JuceLibraryCode/modules/juce_core/files/juce_MemoryMappedFile.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_core/files/juce_RangedDirectoryIterator.cpp b/JuceLibraryCode/modules/juce_core/files/juce_RangedDirectoryIterator.cpp new file mode 100644 index 0000000..10c6b78 --- /dev/null +++ b/JuceLibraryCode/modules/juce_core/files/juce_RangedDirectoryIterator.cpp @@ -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. + + ============================================================================== +*/ + +namespace juce +{ + +float DirectoryEntry::getEstimatedProgress() const +{ + if (auto it = iterator.lock()) + return it->getEstimatedProgress(); + + return 0.0f; +} + +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") +JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996) + +// We implement this in terms of the deprecated DirectoryIterator, +// but the old DirectoryIterator might go away in the future! +RangedDirectoryIterator::RangedDirectoryIterator (const File& directory, + bool isRecursive, + const String& wildCard, + int whatToLookFor) + : iterator (new DirectoryIterator (directory, + isRecursive, + wildCard, + whatToLookFor)) +{ + entry.iterator = iterator; + increment(); +} + +JUCE_END_IGNORE_WARNINGS_GCC_LIKE +JUCE_END_IGNORE_WARNINGS_MSVC + +bool RangedDirectoryIterator::next() +{ + const auto result = iterator->next (&entry.directory, + &entry.hidden, + &entry.fileSize, + &entry.modTime, + &entry.creationTime, + &entry.readOnly); + if (result) + entry.file = iterator->getFile(); + else + entry = {}; + + return result; +} + +void RangedDirectoryIterator::increment() +{ + if (iterator != nullptr && ! next()) + iterator = nullptr; +} + +} // namespace juce diff --git a/JuceLibraryCode/modules/juce_core/files/juce_RangedDirectoryIterator.h b/JuceLibraryCode/modules/juce_core/files/juce_RangedDirectoryIterator.h new file mode 100644 index 0000000..3322f78 --- /dev/null +++ b/JuceLibraryCode/modules/juce_core/files/juce_RangedDirectoryIterator.h @@ -0,0 +1,181 @@ +/* + ============================================================================== + + 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 +{ + +//============================================================================== +/** + Describes the attributes of a file or folder. + + @tags{Core} +*/ +class DirectoryEntry final +{ +public: + /** The path to a file or folder. */ + File getFile() const { return file; } + + /** The time at which the item was last modified. */ + Time getModificationTime() const { return modTime; } + + /** The time at which the item was created. */ + Time getCreationTime() const { return creationTime; } + + /** The size of the item. */ + int64 getFileSize() const { return fileSize; } + + /** True if the item is a directory, false otherwise. */ + bool isDirectory() const { return directory; } + + /** True if the item is hidden, false otherwise. */ + bool isHidden() const { return hidden; } + + /** True if the item is read-only, false otherwise. */ + bool isReadOnly() const { return readOnly; } + + /** The estimated proportion of the range that has been visited + by the iterator, from 0.0 to 1.0. + */ + float getEstimatedProgress() const; + +private: + std::weak_ptr iterator; + File file; + Time modTime; + Time creationTime; + int64 fileSize = 0; + bool directory = false; + bool hidden = false; + bool readOnly = false; + + friend class RangedDirectoryIterator; +}; + +/** A convenience operator so that the expression `*it++` works correctly when + `it` is an instance of RangedDirectoryIterator. +*/ +inline const DirectoryEntry& operator* (const DirectoryEntry& e) noexcept { return e; } + +//============================================================================== +/** + Allows iterating over files and folders using C++11 range-for syntax. + + In the following example, we recursively find all hidden files in a + specific directory. + + @code + std::vector hiddenFiles; + + for (DirectoryEntry entry : RangedDirectoryIterator (File ("/path/to/folder"), isRecursive)) + if (entry.isHidden()) + hiddenFiles.push_back (entry.getFile()); + @endcode + + @tags{Core} +*/ +class RangedDirectoryIterator final +{ +public: + using difference_type = std::ptrdiff_t; + using value_type = DirectoryEntry; + using reference = DirectoryEntry; + using pointer = void; + using iterator_category = std::input_iterator_tag; + + /** The default-constructed iterator acts as the 'end' sentinel. */ + RangedDirectoryIterator() = default; + + /** Creates a RangedDirectoryIterator for a given directory. + + The resulting iterator can be used directly in a 'range-for' expression. + + @param directory the directory to search in + @param isRecursive whether all the subdirectories should also be searched + @param wildCard the file pattern to match. This may contain multiple patterns + separated by a semi-colon or comma, e.g. "*.jpg;*.png" + @param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying + whether to look for files, directories, or both. + */ + RangedDirectoryIterator (const File& directory, + bool isRecursive, + const String& wildCard = "*", + int whatToLookFor = File::findFiles); + + /** Returns true if both iterators are in their end/sentinel state, + otherwise returns false. + */ + bool operator== (const RangedDirectoryIterator& other) const noexcept + { + return iterator == nullptr && other.iterator == nullptr; + } + + /** Returns the inverse of operator== */ + bool operator!= (const RangedDirectoryIterator& other) const noexcept + { + return ! operator== (other); + } + + /** Return an object containing metadata about the file or folder to + which the iterator is currently pointing. + */ + const DirectoryEntry& operator* () const noexcept { return entry; } + const DirectoryEntry* operator->() const noexcept { return &entry; } + + /** Moves the iterator along to the next file. */ + RangedDirectoryIterator& operator++() + { + increment(); + return *this; + } + + /** Moves the iterator along to the next file. + + @returns an object containing metadata about the file or folder to + to which the iterator was previously pointing. + */ + DirectoryEntry operator++ (int) + { + auto result = *(*this); + ++(*this); + return result; + } + +private: + bool next(); + void increment(); + + std::shared_ptr iterator; + DirectoryEntry entry; +}; + +/** Returns the iterator that was passed in. + Provided for range-for compatibility. +*/ +inline RangedDirectoryIterator begin (const RangedDirectoryIterator& it) { return it; } + +/** Returns a default-constructed sentinel value. + Provided for range-for compatibility. +*/ +inline RangedDirectoryIterator end (const RangedDirectoryIterator&) { return {}; } + +} // namespace juce diff --git a/JuceLibraryCode/modules/juce_core/files/juce_TemporaryFile.cpp b/JuceLibraryCode/modules/juce_core/files/juce_TemporaryFile.cpp index 92cb1be..2641f93 100644 --- a/JuceLibraryCode/modules/juce_core/files/juce_TemporaryFile.cpp +++ b/JuceLibraryCode/modules/juce_core/files/juce_TemporaryFile.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_core/files/juce_TemporaryFile.h b/JuceLibraryCode/modules/juce_core/files/juce_TemporaryFile.h index 1050baa..d2b2f38 100644 --- a/JuceLibraryCode/modules/juce_core/files/juce_TemporaryFile.h +++ b/JuceLibraryCode/modules/juce_core/files/juce_TemporaryFile.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_core/files/juce_WildcardFileFilter.cpp b/JuceLibraryCode/modules/juce_core/files/juce_WildcardFileFilter.cpp index d881ea1..78848e0 100644 --- a/JuceLibraryCode/modules/juce_core/files/juce_WildcardFileFilter.cpp +++ b/JuceLibraryCode/modules/juce_core/files/juce_WildcardFileFilter.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_core/files/juce_WildcardFileFilter.h b/JuceLibraryCode/modules/juce_core/files/juce_WildcardFileFilter.h index 6fead61..946d2bc 100644 --- a/JuceLibraryCode/modules/juce_core/files/juce_WildcardFileFilter.h +++ b/JuceLibraryCode/modules/juce_core/files/juce_WildcardFileFilter.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. @@ -54,7 +54,7 @@ class JUCE_API WildcardFileFilter : public FileFilter */ WildcardFileFilter (const String& fileWildcardPatterns, const String& directoryWildcardPatterns, - const String& description); + const String& filterDescription); /** Destructor. */ ~WildcardFileFilter() override; diff --git a/JuceLibraryCode/modules/juce_core/javascript/juce_JSON.cpp b/JuceLibraryCode/modules/juce_core/javascript/juce_JSON.cpp index dc0af55..e989a70 100644 --- a/JuceLibraryCode/modules/juce_core/javascript/juce_JSON.cpp +++ b/JuceLibraryCode/modules/juce_core/javascript/juce_JSON.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,34 +25,76 @@ namespace juce struct JSONParser { - static Result parseObjectOrArray (String::CharPointerType t, var& result) + JSONParser (String::CharPointerType text) : startLocation (text), currentLocation (text) {} + + String::CharPointerType startLocation, currentLocation; + + struct ErrorException + { + String message; + int line = 1, column = 1; + + String getDescription() const { return String (line) + ":" + String (column) + ": error: " + message; } + Result getResult() const { return Result::fail (getDescription()); } + }; + + [[noreturn]] void throwError (juce::String message, String::CharPointerType location) { - t = t.findEndOfWhitespace(); + ErrorException e; + e.message = std::move (message); - switch (t.getAndAdvance()) + for (auto i = startLocation; i < location && ! i.isEmpty(); ++i) { - case 0: result = var(); return Result::ok(); - case '{': return parseObject (t, result); - case '[': return parseArray (t, result); + ++e.column; + if (*i == '\n') { e.column = 1; e.line++; } } - return createFail ("Expected '{' or '['", &t); + throw e; + } + + void skipWhitespace() { currentLocation = currentLocation.findEndOfWhitespace(); } + juce_wchar readChar() { return currentLocation.getAndAdvance(); } + juce_wchar peekChar() const { return *currentLocation; } + bool matchIf (char c) { if (peekChar() == (juce_wchar) c) { ++currentLocation; return true; } return false; } + bool isEOF() const { return peekChar() == 0; } + + bool matchString (const char* t) + { + while (*t != 0) + if (! matchIf (*t++)) + return false; + + return true; } - static Result parseString (const juce_wchar quoteChar, String::CharPointerType& t, var& result) + var parseObjectOrArray() + { + skipWhitespace(); + + if (matchIf ('{')) return parseObject(); + if (matchIf ('[')) return parseArray(); + + if (! isEOF()) + throwError ("Expected '{' or '['", currentLocation); + + return {}; + } + + String parseString (const juce_wchar quoteChar) { MemoryOutputStream buffer (256); for (;;) { - auto c = t.getAndAdvance(); + auto c = readChar(); if (c == quoteChar) break; if (c == '\\') { - c = t.getAndAdvance(); + auto errorLocation = currentLocation; + c = readChar(); switch (c) { @@ -74,109 +116,87 @@ struct JSONParser for (int i = 4; --i >= 0;) { - auto digitValue = CharacterFunctions::getHexDigitValue (t.getAndAdvance()); + auto digitValue = CharacterFunctions::getHexDigitValue (readChar()); if (digitValue < 0) - return createFail ("Syntax error in unicode escape sequence"); + throwError ("Syntax error in unicode escape sequence", errorLocation); c = (juce_wchar) ((c << 4) + static_cast (digitValue)); } break; } + + default: break; } } if (c == 0) - return createFail ("Unexpected end-of-input in string constant"); + throwError ("Unexpected EOF in string constant", currentLocation); buffer.appendUTF8Char (c); } - result = buffer.toUTF8(); - return Result::ok(); + return buffer.toUTF8(); } - static Result parseAny (String::CharPointerType& t, var& result) + var parseAny() { - t = t.findEndOfWhitespace(); - auto t2 = t; + skipWhitespace(); + auto originalLocation = currentLocation; - switch (t2.getAndAdvance()) + switch (readChar()) { - case '{': t = t2; return parseObject (t, result); - case '[': t = t2; return parseArray (t, result); - case '"': t = t2; return parseString ('"', t, result); - case '\'': t = t2; return parseString ('\'', t, result); + case '{': return parseObject(); + case '[': return parseArray(); + case '"': return parseString ('"'); + case '\'': return parseString ('\''); case '-': - t2 = t2.findEndOfWhitespace(); - if (! CharacterFunctions::isDigit (*t2)) - break; - - t = t2; - return parseNumber (t, result, true); + skipWhitespace(); + return parseNumber (true); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - return parseNumber (t, result, false); + currentLocation = originalLocation; + return parseNumber (false); case 't': // "true" - if (t2.getAndAdvance() == 'r' && t2.getAndAdvance() == 'u' && t2.getAndAdvance() == 'e') - { - t = t2; - result = var (true); - return Result::ok(); - } + if (matchString ("rue")) + return var (true); + break; case 'f': // "false" - if (t2.getAndAdvance() == 'a' && t2.getAndAdvance() == 'l' - && t2.getAndAdvance() == 's' && t2.getAndAdvance() == 'e') - { - t = t2; - result = var (false); - return Result::ok(); - } + if (matchString ("alse")) + return var (false); + break; case 'n': // "null" - if (t2.getAndAdvance() == 'u' && t2.getAndAdvance() == 'l' && t2.getAndAdvance() == 'l') - { - t = t2; - result = var(); - return Result::ok(); - } + if (matchString ("ull")) + return {}; + break; default: break; } - return createFail ("Syntax error", &t); - } - -private: - static Result createFail (const char* const message, const String::CharPointerType* location = nullptr) - { - String m (message); - if (location != nullptr) - m << ": \"" << String (*location, 20) << '"'; - - return Result::fail (m); + throwError ("Syntax error", originalLocation); } - static Result parseNumber (String::CharPointerType& t, var& result, const bool isNegative) + var parseNumber (bool isNegative) { - auto oldT = t; + auto originalPos = currentLocation; - int64 intValue = t.getAndAdvance() - '0'; + int64 intValue = readChar() - '0'; jassert (intValue >= 0 && intValue < 10); for (;;) { - auto previousChar = t; - auto c = t.getAndAdvance(); + auto lastPos = currentLocation; + auto c = readChar(); auto digit = ((int) c) - '0'; if (isPositiveAndBelow (digit, 10)) @@ -187,138 +207,99 @@ struct JSONParser if (c == 'e' || c == 'E' || c == '.') { - t = oldT; - auto asDouble = CharacterFunctions::readDoubleValue (t); - result = isNegative ? -asDouble : asDouble; - return Result::ok(); + currentLocation = originalPos; + auto asDouble = CharacterFunctions::readDoubleValue (currentLocation); + return var (isNegative ? -asDouble : asDouble); } if (CharacterFunctions::isWhitespace (c) || c == ',' || c == '}' || c == ']' || c == 0) { - t = previousChar; + currentLocation = lastPos; break; } - return createFail ("Syntax error in number", &oldT); + throwError ("Syntax error in number", lastPos); } auto correctedValue = isNegative ? -intValue : intValue; - if ((intValue >> 31) != 0) - result = correctedValue; - else - result = (int) correctedValue; - - return Result::ok(); + return (intValue >> 31) != 0 ? var (correctedValue) + : var ((int) correctedValue); } - static Result parseObject (String::CharPointerType& t, var& result) + var parseObject() { auto resultObject = new DynamicObject(); - result = resultObject; + var result (resultObject); auto& resultProperties = resultObject->getProperties(); + auto startOfObjectDecl = currentLocation; for (;;) { - t = t.findEndOfWhitespace(); - - auto oldT = t; - auto c = t.getAndAdvance(); + skipWhitespace(); + auto errorLocation = currentLocation; + auto c = readChar(); if (c == '}') break; if (c == 0) - return createFail ("Unexpected end-of-input in object declaration"); - - if (c == '"') - { - var propertyNameVar; - auto r = parseString ('"', t, propertyNameVar); - - if (r.failed()) - return r; - - const Identifier propertyName (propertyNameVar.toString()); - - if (propertyName.isValid()) - { - t = t.findEndOfWhitespace(); - oldT = t; - - auto c2 = t.getAndAdvance(); - - if (c2 != ':') - return createFail ("Expected ':', but found", &oldT); + throwError ("Unexpected EOF in object declaration", startOfObjectDecl); - resultProperties.set (propertyName, var()); - var* propertyValue = resultProperties.getVarPointer (propertyName); + if (c != '"') + throwError ("Expected a property name in double-quotes", errorLocation); - auto r2 = parseAny (t, *propertyValue); + errorLocation = currentLocation; + Identifier propertyName (parseString ('"')); - if (r2.failed()) - return r2; + if (! propertyName.isValid()) + throwError ("Invalid property name", errorLocation); - t = t.findEndOfWhitespace(); - oldT = t; + skipWhitespace(); + errorLocation = currentLocation; - auto nextChar = t.getAndAdvance(); + if (readChar() != ':') + throwError ("Expected ':'", errorLocation); - if (nextChar == ',') - continue; + resultProperties.set (propertyName, parseAny()); - if (nextChar == '}') - break; - } - } + skipWhitespace(); + if (matchIf (',')) continue; + if (matchIf ('}')) break; - return createFail ("Expected object member declaration, but found", &oldT); + throwError ("Expected ',' or '}'", currentLocation); } - return Result::ok(); + return result; } - static Result parseArray (String::CharPointerType& t, var& result) + var parseArray() { - result = var (Array()); - auto* destArray = result.getArray(); + auto result = var (Array()); + auto destArray = result.getArray(); + auto startOfArrayDecl = currentLocation; for (;;) { - t = t.findEndOfWhitespace(); - - auto oldT = t; - auto c = t.getAndAdvance(); + skipWhitespace(); - if (c == ']') + if (matchIf (']')) break; - if (c == 0) - return createFail ("Unexpected end-of-input in array declaration"); - - t = oldT; - destArray->add (var()); - auto r = parseAny (t, destArray->getReference (destArray->size() - 1)); - - if (r.failed()) - return r; - - t = t.findEndOfWhitespace(); - oldT = t; + if (isEOF()) + throwError ("Unexpected EOF in array declaration", startOfArrayDecl); - auto nextChar = t.getAndAdvance(); + destArray->add (parseAny()); + skipWhitespace(); - if (nextChar == ',') - continue; - - if (nextChar == ']') - break; + if (matchIf (',')) continue; + if (matchIf (']')) break; - return createFail ("Expected object array item, but found", &oldT); + throwError ("Expected ',' or ']'", currentLocation); } - return Result::ok(); + return result; } }; @@ -352,8 +333,7 @@ struct JSONFormatter if (juce_isfinite (d)) { - String doubleString (d, maximumDecimalPlaces, true); - out << minimiseLengthOfFloatString (doubleString); + out << serialiseDouble (d); } else { @@ -479,20 +459,21 @@ var JSON::parse (const String& text) { var result; - if (! parse (text, result)) - result = var(); + if (parse (text, result)) + return result; - return result; + return {}; } var JSON::fromString (StringRef text) { - var result; - - if (! JSONParser::parseAny (text.text, result)) - result = var(); + try + { + return JSONParser (text.text).parseAny(); + } + catch (const JSONParser::ErrorException&) {} - return result; + return {}; } var JSON::parse (InputStream& input) @@ -507,7 +488,16 @@ var JSON::parse (const File& file) Result JSON::parse (const String& text, var& result) { - return JSONParser::parseObjectOrArray (text.getCharPointer(), result); + try + { + result = JSONParser (text.getCharPointer()).parseObjectOrArray(); + } + catch (const JSONParser::ErrorException& error) + { + return error.getResult(); + } + + return Result::ok(); } String JSON::toString (const var& data, const bool allOnOneLine, int maximumDecimalPlaces) @@ -531,14 +521,26 @@ String JSON::escapeString (StringRef s) Result JSON::parseQuotedString (String::CharPointerType& t, var& result) { - auto quote = t.getAndAdvance(); + try + { + JSONParser parser (t); + auto quote = parser.readChar(); - if (quote == '"' || quote == '\'') - return JSONParser::parseString (quote, t, result); + if (quote != '"' && quote != '\'') + return Result::fail ("Not a quoted string!"); - return Result::fail ("Not a quoted string!"); + result = parser.parseString (quote); + t = parser.currentLocation; + } + catch (const JSONParser::ErrorException& error) + { + return error.getResult(); + } + + return Result::ok(); } + //============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -546,7 +548,9 @@ Result JSON::parseQuotedString (String::CharPointerType& t, var& result) class JSONTests : public UnitTest { public: - JSONTests() : UnitTest ("JSON", "JSON") {} + JSONTests() + : UnitTest ("JSON", UnitTestCategories::json) + {} static String createRandomWideCharString (Random& r) { @@ -612,7 +616,7 @@ class JSONTests : public UnitTest case 7: { - DynamicObject* o = new DynamicObject(); + auto o = new DynamicObject(); for (int i = r.nextInt (30); --i >= 0;) o->setProperty (createRandomIdentifier (r), createRandomVar (r, depth + 1)); @@ -630,7 +634,7 @@ class JSONTests : public UnitTest { beginTest ("JSON"); - Random r = getRandom(); + auto r = getRandom(); expect (JSON::parse (String()) == var()); expect (JSON::parse ("{}").isObject()); @@ -661,15 +665,20 @@ class JSONTests : public UnitTest beginTest ("Float formatting"); std::map tests; - tests[1] = "1"; + tests[1] = "1.0"; tests[1.1] = "1.1"; tests[1.01] = "1.01"; - tests[0.76378] = "7.6378e-1"; - tests[-10] = "-1e1"; - tests[10.01] = "1.001e1"; - tests[0.0123] = "1.23e-2"; + tests[0.76378] = "0.76378"; + tests[-10] = "-10.0"; + tests[10.01] = "10.01"; + tests[0.0123] = "0.0123"; tests[-3.7e-27] = "-3.7e-27"; - tests[1e+40] = "1e40"; + tests[1e+40] = "1.0e40"; + tests[-12345678901234567.0] = "-1.234567890123457e16"; + tests[192000] = "192000.0"; + tests[1234567] = "1.234567e6"; + tests[0.00006] = "0.00006"; + tests[0.000006] = "6.0e-6"; for (auto& test : tests) expectEquals (JSON::toString (test.first), test.second); diff --git a/JuceLibraryCode/modules/juce_core/javascript/juce_JSON.h b/JuceLibraryCode/modules/juce_core/javascript/juce_JSON.h index 576be32..eb39d51 100644 --- a/JuceLibraryCode/modules/juce_core/javascript/juce_JSON.h +++ b/JuceLibraryCode/modules/juce_core/javascript/juce_JSON.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_core/javascript/juce_Javascript.cpp b/JuceLibraryCode/modules/juce_core/javascript/juce_Javascript.cpp index 8ae2231..a46ad4a 100644 --- a/JuceLibraryCode/modules/juce_core/javascript/juce_Javascript.cpp +++ b/JuceLibraryCode/modules/juce_core/javascript/juce_Javascript.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. @@ -54,10 +54,7 @@ namespace TokenTypes JUCE_DECLARE_JS_TOKEN (identifier, "$identifier") } -#if JUCE_MSVC - #pragma warning (push) - #pragma warning (disable: 4702) -#endif +JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4702) //============================================================================== struct JavascriptEngine::RootObject : public DynamicObject @@ -597,7 +594,7 @@ struct JavascriptEngine::RootObject : public DynamicObject { DivideOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::divide) {} var getWithDoubles (double a, double b) const override { return b != 0 ? a / b : std::numeric_limits::infinity(); } - var getWithInts (int64 a, int64 b) const override { return b != 0 ? var (a / (double) b) : var (std::numeric_limits::infinity()); } + var getWithInts (int64 a, int64 b) const override { return b != 0 ? var ((double) a / (double) b) : var (std::numeric_limits::infinity()); } }; struct ModuloOp : public BinaryOperator @@ -816,7 +813,10 @@ struct JavascriptEngine::RootObject : public DynamicObject for (int i = 0; i < values.size(); ++i) a.add (values.getUnchecked(i)->getResult (s)); - return a; + // std::move() needed here for older compilers + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wredundant-move") + return std::move (a); + JUCE_END_IGNORE_WARNINGS_GCC_LIKE } OwnedArray values; @@ -1183,7 +1183,7 @@ struct JavascriptEngine::RootObject : public DynamicObject if (matchIf (TokenTypes::comma)) { std::unique_ptr block (new BlockStatement (location)); - block->statements.add (s.release()); + block->statements.add (std::move (s)); block->statements.add (parseVar()); return block.release(); } @@ -1625,7 +1625,10 @@ struct JavascriptEngine::RootObject : public DynamicObject for (int i = 2; i < a.numArguments; ++i) array->insert (start++, get (a, i)); - return itemsRemoved; + // std::move() needed here for older compilers + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wredundant-move") + return std::move (itemsRemoved); + JUCE_END_IGNORE_WARNINGS_GCC_LIKE } return var::undefined(); @@ -1911,8 +1914,6 @@ const NamedValueSet& JavascriptEngine::getRootObjectProperties() const noexcept return root->getProperties(); } -#if JUCE_MSVC - #pragma warning (pop) -#endif +JUCE_END_IGNORE_WARNINGS_MSVC } // namespace juce diff --git a/JuceLibraryCode/modules/juce_core/javascript/juce_Javascript.h b/JuceLibraryCode/modules/juce_core/javascript/juce_Javascript.h index 55e6f9f..9c367e4 100644 --- a/JuceLibraryCode/modules/juce_core/javascript/juce_Javascript.h +++ b/JuceLibraryCode/modules/juce_core/javascript/juce_Javascript.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_core/juce_core.cpp b/JuceLibraryCode/modules/juce_core/juce_core.cpp index e374982..4015cc8 100644 --- a/JuceLibraryCode/modules/juce_core/juce_core.cpp +++ b/JuceLibraryCode/modules/juce_core/juce_core.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. @@ -48,23 +48,20 @@ #if JUCE_WINDOWS #include - #if ! JUCE_MINGW - #pragma warning (push) - #pragma warning (disable: 4091) + #if JUCE_MINGW + #include + #include + #include + #else + JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4091) #include - #pragma warning (pop) + JUCE_END_IGNORE_WARNINGS_MSVC #if ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES #pragma comment (lib, "DbgHelp.lib") #endif #endif - #if JUCE_MINGW - #include - #include - #include - #endif - #else #if JUCE_LINUX || JUCE_ANDROID #include @@ -102,6 +99,7 @@ #if JUCE_MAC || JUCE_IOS #include #include + #include #endif #if JUCE_ANDROID @@ -126,6 +124,7 @@ #include "containers/juce_ReferenceCountedArray.cpp" #include "containers/juce_SparseSet.cpp" #include "files/juce_DirectoryIterator.cpp" +#include "files/juce_RangedDirectoryIterator.cpp" #include "files/juce_File.cpp" #include "files/juce_FileInputStream.cpp" #include "files/juce_FileOutputStream.cpp" @@ -137,10 +136,10 @@ #include "maths/juce_Expression.cpp" #include "maths/juce_Random.cpp" #include "memory/juce_MemoryBlock.cpp" +#include "memory/juce_AllocationHooks.cpp" #include "misc/juce_RuntimePermissions.cpp" #include "misc/juce_Result.cpp" #include "misc/juce_Uuid.cpp" -#include "misc/juce_StdFunctionCompat.cpp" #include "misc/juce_ConsoleApplication.cpp" #include "network/juce_MACAddress.cpp" #include "network/juce_NamedPipe.cpp" @@ -185,63 +184,63 @@ //============================================================================== #if ! JUCE_WINDOWS -#include "native/juce_posix_SharedCode.h" -#include "native/juce_posix_NamedPipe.cpp" -#if ! JUCE_ANDROID || __ANDROID_API__ >= 24 - #include "native/juce_posix_IPAddress.h" -#endif + #include "native/juce_posix_SharedCode.h" + #include "native/juce_posix_NamedPipe.cpp" + #if ! JUCE_ANDROID || __ANDROID_API__ >= 24 + #include "native/juce_posix_IPAddress.h" + #endif #endif //============================================================================== #if JUCE_MAC || JUCE_IOS -#include "native/juce_mac_Files.mm" -#include "native/juce_mac_Network.mm" -#include "native/juce_mac_Strings.mm" -#include "native/juce_mac_SystemStats.mm" -#include "native/juce_mac_Threads.mm" + #include "native/juce_mac_Files.mm" + #include "native/juce_mac_Network.mm" + #include "native/juce_mac_Strings.mm" + #include "native/juce_mac_SystemStats.mm" + #include "native/juce_mac_Threads.mm" //============================================================================== #elif JUCE_WINDOWS -#include "native/juce_win32_Files.cpp" -#include "native/juce_win32_Network.cpp" -#include "native/juce_win32_Registry.cpp" -#include "native/juce_win32_SystemStats.cpp" -#include "native/juce_win32_Threads.cpp" + #include "native/juce_win32_Files.cpp" + #include "native/juce_win32_Network.cpp" + #include "native/juce_win32_Registry.cpp" + #include "native/juce_win32_SystemStats.cpp" + #include "native/juce_win32_Threads.cpp" //============================================================================== #elif JUCE_LINUX -#include "native/juce_linux_CommonFile.cpp" -#include "native/juce_linux_Files.cpp" -#include "native/juce_linux_Network.cpp" -#if JUCE_USE_CURL - #include "native/juce_curl_Network.cpp" -#endif -#include "native/juce_linux_SystemStats.cpp" -#include "native/juce_linux_Threads.cpp" + #include "native/juce_linux_CommonFile.cpp" + #include "native/juce_linux_Files.cpp" + #include "native/juce_linux_Network.cpp" + #if JUCE_USE_CURL + #include "native/juce_curl_Network.cpp" + #endif + #include "native/juce_linux_SystemStats.cpp" + #include "native/juce_linux_Threads.cpp" //============================================================================== #elif JUCE_ANDROID - -#include "native/juce_linux_CommonFile.cpp" -#include "native/juce_android_JNIHelpers.cpp" -#include "native/juce_android_Files.cpp" -#include "native/juce_android_Misc.cpp" -#include "native/juce_android_Network.cpp" -#include "native/juce_android_SystemStats.cpp" -#include "native/juce_android_Threads.cpp" -#include "native/juce_android_RuntimePermissions.cpp" + #include "native/juce_linux_CommonFile.cpp" + #include "native/juce_android_JNIHelpers.cpp" + #include "native/juce_android_Files.cpp" + #include "native/juce_android_Misc.cpp" + #include "native/juce_android_Network.cpp" + #include "native/juce_android_SystemStats.cpp" + #include "native/juce_android_Threads.cpp" + #include "native/juce_android_RuntimePermissions.cpp" #endif #include "threads/juce_ChildProcess.cpp" #include "threads/juce_HighResolutionTimer.cpp" +#include "threads/juce_WaitableEvent.cpp" #include "network/juce_URL.cpp" #include "network/juce_WebInputStream.cpp" #include "streams/juce_URLInputSource.cpp" //============================================================================== #if JUCE_UNIT_TESTS -#include "containers/juce_HashMap_test.cpp" + #include "containers/juce_HashMap_test.cpp" #endif //============================================================================== diff --git a/JuceLibraryCode/modules/juce_core/juce_core.h b/JuceLibraryCode/modules/juce_core/juce_core.h index ddc5fb0..ed6ca99 100644 --- a/JuceLibraryCode/modules/juce_core/juce_core.h +++ b/JuceLibraryCode/modules/juce_core/juce_core.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. @@ -25,24 +25,24 @@ 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_core - vendor: juce - version: 5.4.3 - name: JUCE core classes - description: The essential set of basic JUCE classes, as required by all the other JUCE modules. Includes text, container, memory, threading and i/o functionality. - website: http://www.juce.com/juce - license: ISC + ID: juce_core + vendor: juce + version: 6.0.1 + name: JUCE core classes + description: The essential set of basic JUCE classes, as required by all the other JUCE modules. Includes text, container, memory, threading and i/o functionality. + website: http://www.juce.com/juce + license: ISC dependencies: - OSXFrameworks: Cocoa IOKit - iOSFrameworks: Foundation - linuxLibs: rt dl pthread - mingwLibs: uuid wsock32 wininet version ole32 ws2_32 oleaut32 imm32 comdlg32 shlwapi rpcrt4 winmm + OSXFrameworks: Cocoa IOKit + iOSFrameworks: Foundation + linuxLibs: rt dl pthread + mingwLibs: uuid wsock32 wininet version ole32 ws2_32 oleaut32 imm32 comdlg32 shlwapi rpcrt4 winmm END_JUCE_MODULE_DECLARATION @@ -107,7 +107,7 @@ //============================================================================== /** Config: JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES - In a Visual C++ build, this can be used to stop the required system libs being + In a Windows build, this can be used to stop the required system libs being automatically added to the link stage. */ #ifndef JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES @@ -134,19 +134,15 @@ Enables http/https support via libcurl (Linux only). Enabling this will add an additional run-time dynamic dependency to libcurl. - If you disable this then https/ssl support will not be available on linux. + If you disable this then https/ssl support will not be available on Linux. */ #ifndef JUCE_USE_CURL - #if JUCE_LINUX - #define JUCE_USE_CURL 1 - #else - #define JUCE_USE_CURL 0 - #endif + #define JUCE_USE_CURL 1 #endif /** Config: JUCE_LOAD_CURL_SYMBOLS_LAZILY If enabled, JUCE will load libcurl lazily when required (for example, when WebInputStream - is used). Enabling this flag may also help with library dependency erros as linking + is used). Enabling this flag may also help with library dependency errors as linking libcurl at compile-time may instruct the linker to hard depend on a specific version of libcurl. It's also useful if you want to limit the amount of JUCE dependencies and you are not using WebInputStream or the URL classes. @@ -155,13 +151,12 @@ #define JUCE_LOAD_CURL_SYMBOLS_LAZILY 0 #endif - /** Config: JUCE_CATCH_UNHANDLED_EXCEPTIONS If enabled, this will add some exception-catching code to forward unhandled exceptions to your JUCEApplicationBase::unhandledException() callback. */ #ifndef JUCE_CATCH_UNHANDLED_EXCEPTIONS - //#define JUCE_CATCH_UNHANDLED_EXCEPTIONS 1 + #define JUCE_CATCH_UNHANDLED_EXCEPTIONS 0 #endif /** Config: JUCE_ALLOW_STATIC_NULL_VARIABLES @@ -170,7 +165,7 @@ constructor code. */ #ifndef JUCE_ALLOW_STATIC_NULL_VARIABLES - #define JUCE_ALLOW_STATIC_NULL_VARIABLES 1 + #define JUCE_ALLOW_STATIC_NULL_VARIABLES 0 #endif /** Config: JUCE_STRICT_REFCOUNTEDPOINTER @@ -182,6 +177,13 @@ #define JUCE_STRICT_REFCOUNTEDPOINTER 0 #endif +/** Config: JUCE_ENABLE_ALLOCATION_HOOKS + If enabled, this will add global allocation functions with built-in assertions, which may + help when debugging allocations in unit tests. +*/ +#ifndef JUCE_ENABLE_ALLOCATION_HOOKS + #define JUCE_ENABLE_ALLOCATION_HOOKS 0 +#endif #ifndef JUCE_STRING_UTF_TYPE #define JUCE_STRING_UTF_TYPE 8 @@ -222,19 +224,14 @@ namespace juce #include "memory/juce_Atomic.h" #include "text/juce_CharacterFunctions.h" -#if JUCE_MSVC - #pragma warning (push) - #pragma warning (disable: 4514 4996) -#endif +JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4514 4996) #include "text/juce_CharPointer_UTF8.h" #include "text/juce_CharPointer_UTF16.h" #include "text/juce_CharPointer_UTF32.h" #include "text/juce_CharPointer_ASCII.h" -#if JUCE_MSVC - #pragma warning (pop) -#endif +JUCE_END_IGNORE_WARNINGS_MSVC #include "text/juce_String.h" #include "text/juce_StringRef.h" @@ -269,6 +266,8 @@ namespace juce #include "text/juce_StringPool.h" #include "text/juce_Identifier.h" #include "text/juce_StringArray.h" +#include "system/juce_SystemStats.h" +#include "memory/juce_HeavyweightLeakedObjectDetector.h" #include "text/juce_StringPairArray.h" #include "text/juce_TextDiff.h" #include "text/juce_LocalisedStrings.h" @@ -280,8 +279,6 @@ namespace juce #include "containers/juce_NamedValueSet.h" #include "containers/juce_DynamicObject.h" #include "containers/juce_HashMap.h" -#include "system/juce_SystemStats.h" -#include "memory/juce_HeavyweightLeakedObjectDetector.h" #include "time/juce_RelativeTime.h" #include "time/juce_Time.h" #include "streams/juce_InputStream.h" @@ -293,6 +290,7 @@ namespace juce #include "streams/juce_InputSource.h" #include "files/juce_File.h" #include "files/juce_DirectoryIterator.h" +#include "files/juce_RangedDirectoryIterator.h" #include "files/juce_FileInputStream.h" #include "files/juce_FileOutputStream.h" #include "files/juce_FileSearchPath.h" @@ -339,6 +337,7 @@ namespace juce #include "zip/juce_ZipFile.h" #include "containers/juce_PropertySet.h" #include "memory/juce_SharedResourcePointer.h" +#include "memory/juce_AllocationHooks.h" #if JUCE_CORE_INCLUDE_OBJC_HELPERS && (JUCE_MAC || JUCE_IOS) #include "native/juce_osx_ObjCHelpers.h" @@ -353,6 +352,10 @@ namespace juce #include "native/juce_android_JNIHelpers.h" #endif +#if JUCE_UNIT_TESTS + #include "unit_tests/juce_UnitTestCategories.h" +#endif + #ifndef DOXYGEN namespace juce { @@ -376,11 +379,9 @@ namespace juce } #endif -#if JUCE_MSVC - #pragma warning (pop) +JUCE_END_IGNORE_WARNINGS_MSVC - // In DLL builds, need to disable this warnings for other modules - #if defined (JUCE_DLL_BUILD) || defined (JUCE_DLL) - #pragma warning (disable: 4251) - #endif +// In DLL builds, need to disable this warnings for other modules +#if defined (JUCE_DLL_BUILD) || defined (JUCE_DLL) + JUCE_IGNORE_MSVC (4251) #endif diff --git a/JuceLibraryCode/modules/juce_core/juce_core.mm b/JuceLibraryCode/modules/juce_core/juce_core.mm index d41cc84..c317b33 100644 --- a/JuceLibraryCode/modules/juce_core/juce_core.mm +++ b/JuceLibraryCode/modules/juce_core/juce_core.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_core/logging/juce_FileLogger.cpp b/JuceLibraryCode/modules/juce_core/logging/juce_FileLogger.cpp index 93dcdb5..3ccc838 100644 --- a/JuceLibraryCode/modules/juce_core/logging/juce_FileLogger.cpp +++ b/JuceLibraryCode/modules/juce_core/logging/juce_FileLogger.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_core/logging/juce_FileLogger.h b/JuceLibraryCode/modules/juce_core/logging/juce_FileLogger.h index dfdf8ec..3449b67 100644 --- a/JuceLibraryCode/modules/juce_core/logging/juce_FileLogger.h +++ b/JuceLibraryCode/modules/juce_core/logging/juce_FileLogger.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,7 +83,7 @@ class JUCE_API FileLogger : public Logger The filename used is based on the root and suffix strings provided, along with a time and date string, meaning that a new, empty log file will be always be created - rather than appending to an exising one. + rather than appending to an existing one. The method might return nullptr if the file can't be created for some reason. diff --git a/JuceLibraryCode/modules/juce_core/logging/juce_Logger.cpp b/JuceLibraryCode/modules/juce_core/logging/juce_Logger.cpp index f422fcc..06b75e0 100644 --- a/JuceLibraryCode/modules/juce_core/logging/juce_Logger.cpp +++ b/JuceLibraryCode/modules/juce_core/logging/juce_Logger.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_core/logging/juce_Logger.h b/JuceLibraryCode/modules/juce_core/logging/juce_Logger.h index 31cce7f..15ba8fd 100644 --- a/JuceLibraryCode/modules/juce_core/logging/juce_Logger.h +++ b/JuceLibraryCode/modules/juce_core/logging/juce_Logger.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_core/maths/juce_BigInteger.cpp b/JuceLibraryCode/modules/juce_core/maths/juce_BigInteger.cpp index 9f6b951..6c86681 100644 --- a/JuceLibraryCode/modules/juce_core/maths/juce_BigInteger.cpp +++ b/JuceLibraryCode/modules/juce_core/maths/juce_BigInteger.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. @@ -551,7 +551,7 @@ BigInteger& BigInteger::operator*= (const BigInteger& other) { auto uv = (uint64) totalValues[i + j] + (uint64) values[j] * (uint64) mValues[i] + (uint64) c; totalValues[i + j] = (uint32) uv; - c = uv >> 32; + c = static_cast (uv >> 32); } totalValues[i + n + 1] = c; @@ -1196,7 +1196,7 @@ void BigInteger::loadFromMemoryBlock (const MemoryBlock& data) auto* values = ensureSize (numInts); for (int i = 0; i < (int) numInts - 1; ++i) - values[i] = (uint32) ByteOrder::littleEndianInt (addBytesToPointer (data.getData(), sizeof (uint32) * (size_t) i)); + values[i] = (uint32) ByteOrder::littleEndianInt (addBytesToPointer (data.getData(), (size_t) i * sizeof (uint32))); values[numInts - 1] = 0; @@ -1240,7 +1240,7 @@ void writeLittleEndianBitsInBuffer (void* buffer, uint32 startBit, uint32 numBit } if (numBits > 0) - *data = (uint8) ((*data & (0xff << numBits)) | value); + *data = (uint8) ((*data & (uint32) (0xff << numBits)) | value); } uint32 readLittleEndianBitsInBuffer (const void* buffer, uint32 startBit, uint32 numBits) noexcept @@ -1255,7 +1255,7 @@ uint32 readLittleEndianBitsInBuffer (const void* buffer, uint32 startBit, uint32 if (const uint32 offset = (startBit & 7)) { const uint32 bitsInByte = 8 - offset; - result = (*data >> offset); + result = (uint32) (*data >> offset); if (bitsInByte >= numBits) return result & ((1u << numBits) - 1u); @@ -1278,6 +1278,7 @@ uint32 readLittleEndianBitsInBuffer (const void* buffer, uint32 startBit, uint32 return result; } + //============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -1285,7 +1286,9 @@ uint32 readLittleEndianBitsInBuffer (const void* buffer, uint32 startBit, uint32 class BigIntegerTests : public UnitTest { public: - BigIntegerTests() : UnitTest ("BigInteger", "Maths") {} + BigIntegerTests() + : UnitTest ("BigInteger", UnitTestCategories::maths) + {} static BigInteger getBigRandom (Random& r) { diff --git a/JuceLibraryCode/modules/juce_core/maths/juce_BigInteger.h b/JuceLibraryCode/modules/juce_core/maths/juce_BigInteger.h index 7c7b405..5444800 100644 --- a/JuceLibraryCode/modules/juce_core/maths/juce_BigInteger.h +++ b/JuceLibraryCode/modules/juce_core/maths/juce_BigInteger.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_core/maths/juce_Expression.cpp b/JuceLibraryCode/modules/juce_core/maths/juce_Expression.cpp index 9c3ce9e..88ec7bc 100644 --- a/JuceLibraryCode/modules/juce_core/maths/juce_Expression.cpp +++ b/JuceLibraryCode/modules/juce_core/maths/juce_Expression.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. @@ -681,7 +681,7 @@ struct Expression::Helpers } //============================================================================== - static inline bool isDecimalDigit (const juce_wchar c) noexcept + static bool isDecimalDigit (const juce_wchar c) noexcept { return c >= '0' && c <= '9'; } diff --git a/JuceLibraryCode/modules/juce_core/maths/juce_Expression.h b/JuceLibraryCode/modules/juce_core/maths/juce_Expression.h index 7e706aa..41d7b1f 100644 --- a/JuceLibraryCode/modules/juce_core/maths/juce_Expression.h +++ b/JuceLibraryCode/modules/juce_core/maths/juce_Expression.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_core/maths/juce_MathsFunctions.h b/JuceLibraryCode/modules/juce_core/maths/juce_MathsFunctions.h index 2575a7c..fc6cf86 100644 --- a/JuceLibraryCode/modules/juce_core/maths/juce_MathsFunctions.h +++ b/JuceLibraryCode/modules/juce_core/maths/juce_MathsFunctions.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. @@ -91,33 +91,33 @@ using uint32 = unsigned int; /** Returns the larger of two values. */ template -JUCE_CONSTEXPR Type jmax (Type a, Type b) { return a < b ? b : a; } +constexpr Type jmax (Type a, Type b) { return a < b ? b : a; } /** Returns the larger of three values. */ template -JUCE_CONSTEXPR Type jmax (Type a, Type b, Type c) { return a < b ? (b < c ? c : b) : (a < c ? c : a); } +constexpr Type jmax (Type a, Type b, Type c) { return a < b ? (b < c ? c : b) : (a < c ? c : a); } /** Returns the larger of four values. */ template -JUCE_CONSTEXPR Type jmax (Type a, Type b, Type c, Type d) { return jmax (a, jmax (b, c, d)); } +constexpr Type jmax (Type a, Type b, Type c, Type d) { return jmax (a, jmax (b, c, d)); } /** Returns the smaller of two values. */ template -JUCE_CONSTEXPR Type jmin (Type a, Type b) { return b < a ? b : a; } +constexpr Type jmin (Type a, Type b) { return b < a ? b : a; } /** Returns the smaller of three values. */ template -JUCE_CONSTEXPR Type jmin (Type a, Type b, Type c) { return b < a ? (c < b ? c : b) : (c < a ? c : a); } +constexpr Type jmin (Type a, Type b, Type c) { return b < a ? (c < b ? c : b) : (c < a ? c : a); } /** Returns the smaller of four values. */ template -JUCE_CONSTEXPR Type jmin (Type a, Type b, Type c, Type d) { return jmin (a, jmin (b, c, d)); } +constexpr Type jmin (Type a, Type b, Type c, Type d) { return jmin (a, jmin (b, c, d)); } /** Remaps a normalised value (between 0 and 1) to a target range. This effectively returns (targetRangeMin + value0To1 * (targetRangeMax - targetRangeMin)). */ template -JUCE_CONSTEXPR Type jmap (Type value0To1, Type targetRangeMin, Type targetRangeMax) +constexpr Type jmap (Type value0To1, Type targetRangeMin, Type targetRangeMax) { return targetRangeMin + value0To1 * (targetRangeMax - targetRangeMin); } @@ -130,6 +130,50 @@ Type jmap (Type sourceValue, Type sourceRangeMin, Type sourceRangeMax, Type targ return targetRangeMin + ((targetRangeMax - targetRangeMin) * (sourceValue - sourceRangeMin)) / (sourceRangeMax - sourceRangeMin); } +/** Remaps a normalised value (between 0 and 1) to a logarithmic target range. + + The entire target range must be greater than zero. + + @see mapFromLog10 + + @code + mapToLog10 (0.5, 0.4, 40.0) == 4.0 + @endcode +*/ +template +Type mapToLog10 (Type value0To1, Type logRangeMin, Type logRangeMax) +{ + jassert (logRangeMin > 0); + jassert (logRangeMax > 0); + + auto logMin = std::log10 (logRangeMin); + auto logMax = std::log10 (logRangeMax); + + return std::pow ((Type) 10.0, value0To1 * (logMax - logMin) + logMin); +} + +/** Remaps a logarithmic value in a target range to a normalised value (between 0 and 1). + + The entire target range must be greater than zero. + + @see mapToLog10 + + @code + mapFromLog10 (4.0, 0.4, 40.0) == 0.5 + @endcode +*/ +template +Type mapFromLog10 (Type valueInLogRange, Type logRangeMin, Type logRangeMax) +{ + jassert (logRangeMin > 0); + jassert (logRangeMax > 0); + + auto logMin = std::log10 (logRangeMin); + auto logMax = std::log10 (logRangeMax); + + return (std::log10 (valueInLogRange) - logMin) / (logMax - logMin); +} + /** Scans an array of values, returning the minimum value that it contains. */ template Type findMinimum (const Type* data, int numValues) @@ -296,13 +340,8 @@ void ignoreUnused (Types&&...) noexcept {} int numElements = numElementsInArray (myArray) // returns 3 @endcode */ -template -int numElementsInArray (Type (&array)[N]) -{ - (void) array; - (void) sizeof (0[array]); // This line should cause an error if you pass an object with a user-defined subscript operator - return N; -} +template +constexpr int numElementsInArray (Type (&)[N]) noexcept { return N; } //============================================================================== // Some useful maths functions that aren't always present with all compilers and build settings. @@ -331,15 +370,7 @@ inline float juce_hypot (float a, float b) noexcept } #endif -#if JUCE_MSVC && ! defined (DOXYGEN) // The MSVC libraries omit these functions for some reason... - template Type asinh (Type x) { return std::log (x + std::sqrt (x * x + (Type) 1)); } - template Type acosh (Type x) { return std::log (x + std::sqrt (x * x - (Type) 1)); } - template Type atanh (Type x) { return (std::log (x + (Type) 1) - std::log (((Type) 1) - x)) / (Type) 2; } -#endif - //============================================================================== -#if JUCE_HAS_CONSTEXPR - /** Commonly used mathematical constants @tags{Core} @@ -363,71 +394,29 @@ struct MathConstants static constexpr FloatType sqrt2 = static_cast (1.4142135623730950488L); }; -#else - -/** Commonly used mathematical constants - - @tags{Core} -*/ -template -struct MathConstants -{ - /** A predefined value for Pi */ - static const FloatType pi; - - /** A predefined value for 2 * Pi */ - static const FloatType twoPi; - - /** A predefined value for Pi / 2 */ - static const FloatType halfPi; - - /** A predefined value for Euler's number */ - static const FloatType euler; - - /** A predefined value for sqrt(2) */ - static const FloatType sqrt2; -}; - -template -const FloatType MathConstants::pi = static_cast (3.141592653589793238L); - -template -const FloatType MathConstants::twoPi = static_cast (2 * 3.141592653589793238L); - -template -const FloatType MathConstants::halfPi = static_cast (3.141592653589793238L / 2); - -template -const FloatType MathConstants::euler = static_cast (2.71828182845904523536L); - -template -const FloatType MathConstants::sqrt2 = static_cast (1.4142135623730950488L); - -#endif - #ifndef DOXYGEN /** A double-precision constant for pi. @deprecated This is deprecated in favour of MathConstants::pi. The reason is that "double_Pi" was a confusing name, and many people misused it, wrongly thinking it meant 2 * pi ! */ -const JUCE_CONSTEXPR double double_Pi = MathConstants::pi; +const constexpr double double_Pi = MathConstants::pi; /** A single-precision constant for pi. @deprecated This is deprecated in favour of MathConstants::pi. The reason is that "double_Pi" was a confusing name, and many people misused it, wrongly thinking it meant 2 * pi ! */ -const JUCE_CONSTEXPR float float_Pi = MathConstants::pi; +const constexpr float float_Pi = MathConstants::pi; #endif /** Converts an angle in degrees to radians. */ template -JUCE_CONSTEXPR FloatType degreesToRadians (FloatType degrees) noexcept { return degrees * (MathConstants::pi / FloatType (180)); } +constexpr FloatType degreesToRadians (FloatType degrees) noexcept { return degrees * (MathConstants::pi / FloatType (180)); } /** Converts an angle in radians to degrees. */ template -JUCE_CONSTEXPR FloatType radiansToDegrees (FloatType radians) noexcept { return radians * (FloatType (180) / MathConstants::pi); } +constexpr FloatType radiansToDegrees (FloatType radians) noexcept { return radians * (FloatType (180) / MathConstants::pi); } //============================================================================== @@ -532,7 +521,8 @@ template unsigned int truncatePositiveToUnsignedInt (FloatType value) noexcept { jassert (value >= static_cast (0)); - jassert (static_cast (value) <= std::numeric_limits::max()); + jassert (static_cast (value) + <= static_cast (std::numeric_limits::max())); return static_cast (value); } @@ -540,7 +530,7 @@ unsigned int truncatePositiveToUnsignedInt (FloatType value) noexcept //============================================================================== /** Returns true if the specified integer is a power-of-two. */ template -JUCE_CONSTEXPR bool isPowerOfTwo (IntegerType value) +constexpr bool isPowerOfTwo (IntegerType value) { return (value & (value - 1)) == 0; } @@ -593,7 +583,7 @@ IntegerType negativeAwareModulo (IntegerType dividend, const IntegerType divisor /** Returns the square of its argument. */ template -inline JUCE_CONSTEXPR NumericType square (NumericType n) noexcept +inline constexpr NumericType square (NumericType n) noexcept { return n * n; } diff --git a/JuceLibraryCode/modules/juce_core/maths/juce_NormalisableRange.h b/JuceLibraryCode/modules/juce_core/maths/juce_NormalisableRange.h index 47ef00d..5a23092 100644 --- a/JuceLibraryCode/modules/juce_core/maths/juce_NormalisableRange.h +++ b/JuceLibraryCode/modules/juce_core/maths/juce_NormalisableRange.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,32 +44,8 @@ class NormalisableRange NormalisableRange (const NormalisableRange&) = default; NormalisableRange& operator= (const NormalisableRange&) = default; - - // VS2013 can't default move constructors - NormalisableRange (NormalisableRange&& other) - : start (other.start), end (other.end), - interval (other.interval), skew (other.skew), - symmetricSkew (other.symmetricSkew), - convertFrom0To1Function (std::move (other.convertFrom0To1Function)), - convertTo0To1Function (std::move (other.convertTo0To1Function)), - snapToLegalValueFunction (std::move (other.snapToLegalValueFunction)) - { - } - - // VS2013 can't default move assignments - NormalisableRange& operator= (NormalisableRange&& other) - { - start = other.start; - end = other.end; - interval = other.interval; - skew = other.skew; - symmetricSkew = other.symmetricSkew; - convertFrom0To1Function = std::move (other.convertFrom0To1Function); - convertTo0To1Function = std::move (other.convertTo0To1Function); - snapToLegalValueFunction = std::move (other.snapToLegalValueFunction); - - return *this; - } + NormalisableRange (NormalisableRange&&) = default; + NormalisableRange& operator= (NormalisableRange&&) = default; /** Creates a NormalisableRange with a given range, interval and skew factor. */ NormalisableRange (ValueType rangeStart, @@ -112,6 +88,11 @@ class NormalisableRange { } + /** A function object which can remap a value in some way based on the start and end of a range. */ + using ValueRemapFunction = std::function; + /** Creates a NormalisableRange with a given range and an injective mapping function. @param rangeStart The minimum value in the range. @@ -125,14 +106,14 @@ class NormalisableRange */ NormalisableRange (ValueType rangeStart, ValueType rangeEnd, - std::function convertFrom0To1Func, - std::function convertTo0To1Func, - std::function snapToLegalValueFunc = nullptr) noexcept + ValueRemapFunction convertFrom0To1Func, + ValueRemapFunction convertTo0To1Func, + ValueRemapFunction snapToLegalValueFunc = {}) noexcept : start (rangeStart), end (rangeEnd), - convertFrom0To1Function (convertFrom0To1Func), - convertTo0To1Function (convertTo0To1Func), - snapToLegalValueFunction (snapToLegalValueFunc) + convertFrom0To1Function (std::move (convertFrom0To1Func)), + convertTo0To1Function (std::move (convertTo0To1Func)), + snapToLegalValueFunction (std::move (snapToLegalValueFunc)) { checkInvariants(); } @@ -190,7 +171,7 @@ class NormalisableRange } /** Takes a non-normalised value and snaps it based on either the interval property of - this NormalisedRange or the lambda function supplied to the constructor. + this NormalisableRange or the lambda function supplied to the constructor. */ ValueType snapToLegalValue (ValueType v) const noexcept { @@ -274,11 +255,7 @@ class NormalisableRange return clampedValue; } - using ConversionFunction = std::function; - - ConversionFunction convertFrom0To1Function = {}, - convertTo0To1Function = {}, - snapToLegalValueFunction = {}; + ValueRemapFunction convertFrom0To1Function, convertTo0To1Function, snapToLegalValueFunction; }; } // namespace juce diff --git a/JuceLibraryCode/modules/juce_core/maths/juce_Random.cpp b/JuceLibraryCode/modules/juce_core/maths/juce_Random.cpp index 5c3257e..cc67188 100644 --- a/JuceLibraryCode/modules/juce_core/maths/juce_Random.cpp +++ b/JuceLibraryCode/modules/juce_core/maths/juce_Random.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. @@ -58,7 +58,7 @@ void Random::combineSeed (const int64 seedValue) noexcept void Random::setSeedRandomly() { - static int64 globalSeed = 0; + static std::atomic globalSeed { 0 }; combineSeed (globalSeed ^ (int64) (pointer_sized_int) this); combineSeed (Time::getMillisecondCounter()); @@ -105,7 +105,9 @@ bool Random::nextBool() noexcept float Random::nextFloat() noexcept { - return static_cast (nextInt()) / (std::numeric_limits::max() + 1.0f); + auto result = static_cast (static_cast (nextInt())) + / (static_cast (std::numeric_limits::max()) + 1.0f); + return result == 1.0f ? 1.0f - std::numeric_limits::epsilon() : result; } double Random::nextDouble() noexcept @@ -161,13 +163,17 @@ void Random::fillBitsRandomly (BigInteger& arrayToChange, int startBit, int numB arrayToChange.setBit (startBit + numBits, nextBool()); } + +//============================================================================== //============================================================================== #if JUCE_UNIT_TESTS class RandomTests : public UnitTest { public: - RandomTests() : UnitTest ("Random", "Maths") {} + RandomTests() + : UnitTest ("Random", UnitTestCategories::maths) + {} void runTest() override { diff --git a/JuceLibraryCode/modules/juce_core/maths/juce_Random.h b/JuceLibraryCode/modules/juce_core/maths/juce_Random.h index 7d90c5d..faa4ae8 100644 --- a/JuceLibraryCode/modules/juce_core/maths/juce_Random.h +++ b/JuceLibraryCode/modules/juce_core/maths/juce_Random.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_core/maths/juce_Range.h b/JuceLibraryCode/modules/juce_core/maths/juce_Range.h index 6674f04..9e19a4e 100644 --- a/JuceLibraryCode/modules/juce_core/maths/juce_Range.h +++ b/JuceLibraryCode/modules/juce_core/maths/juce_Range.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,22 +41,22 @@ class Range public: //============================================================================== /** Constructs an empty range. */ - JUCE_CONSTEXPR Range() = default; + constexpr Range() = default; /** Constructs a range with given start and end values. */ - JUCE_CONSTEXPR Range (const ValueType startValue, const ValueType endValue) noexcept + constexpr Range (const ValueType startValue, const ValueType endValue) noexcept : start (startValue), end (jmax (startValue, endValue)) { } /** Constructs a copy of another range. */ - JUCE_CONSTEXPR Range (const Range&) = default; + constexpr Range (const Range&) = default; /** Copies another range object. */ Range& operator= (const Range&) = default; /** Returns the range that lies between two positions (in either order). */ - JUCE_CONSTEXPR static Range between (const ValueType position1, const ValueType position2) noexcept + constexpr static Range between (const ValueType position1, const ValueType position2) noexcept { return position1 < position2 ? Range (position1, position2) : Range (position2, position1); @@ -70,23 +70,23 @@ class Range } /** Returns a range with the specified start position and a length of zero. */ - JUCE_CONSTEXPR static Range emptyRange (const ValueType start) noexcept + constexpr static Range emptyRange (const ValueType start) noexcept { return Range (start, start); } //============================================================================== /** Returns the start of the range. */ - JUCE_CONSTEXPR inline ValueType getStart() const noexcept { return start; } + constexpr inline ValueType getStart() const noexcept { return start; } /** Returns the length of the range. */ - JUCE_CONSTEXPR inline ValueType getLength() const noexcept { return end - start; } + constexpr inline ValueType getLength() const noexcept { return end - start; } /** Returns the end of the range. */ - JUCE_CONSTEXPR inline ValueType getEnd() const noexcept { return end; } + constexpr inline ValueType getEnd() const noexcept { return end; } /** Returns true if the range has a length of zero. */ - JUCE_CONSTEXPR inline bool isEmpty() const noexcept { return start == end; } + constexpr inline bool isEmpty() const noexcept { return start == end; } //============================================================================== /** Changes the start position of the range, leaving the end position unchanged. @@ -104,13 +104,13 @@ class Range If the new start position is higher than the current end of the range, the end point will be pushed along to equal it, returning an empty range at the new position. */ - JUCE_CONSTEXPR Range withStart (const ValueType newStart) const noexcept + constexpr Range withStart (const ValueType newStart) const noexcept { return Range (newStart, jmax (newStart, end)); } /** Returns a range with the same length as this one, but moved to have the given start position. */ - JUCE_CONSTEXPR Range movedToStartAt (const ValueType newStart) const noexcept + constexpr Range movedToStartAt (const ValueType newStart) const noexcept { return Range (newStart, end + (newStart - start)); } @@ -130,13 +130,13 @@ class Range If the new end position is below the current start of the range, the start point will be pushed back to equal the new end point. */ - JUCE_CONSTEXPR Range withEnd (const ValueType newEnd) const noexcept + constexpr Range withEnd (const ValueType newEnd) const noexcept { return Range (jmin (start, newEnd), newEnd); } /** Returns a range with the same length as this one, but moved to have the given end position. */ - JUCE_CONSTEXPR Range movedToEndAt (const ValueType newEnd) const noexcept + constexpr Range movedToEndAt (const ValueType newEnd) const noexcept { return Range (start + (newEnd - end), newEnd); } @@ -152,7 +152,7 @@ class Range /** Returns a range with the same start as this one, but a different length. Lengths less than zero are treated as zero. */ - JUCE_CONSTEXPR Range withLength (const ValueType newLength) const noexcept + constexpr Range withLength (const ValueType newLength) const noexcept { return Range (start, start + newLength); } @@ -161,7 +161,7 @@ class Range given amount. @returns The returned range will be (start - amount, end + amount) */ - JUCE_CONSTEXPR Range expanded (ValueType amount) const noexcept + constexpr Range expanded (ValueType amount) const noexcept { return Range (start - amount, end + amount); } @@ -186,27 +186,27 @@ class Range /** Returns a range that is equal to this one with an amount added to its start and end. */ - JUCE_CONSTEXPR Range operator+ (const ValueType amountToAdd) const noexcept + constexpr Range operator+ (const ValueType amountToAdd) const noexcept { return Range (start + amountToAdd, end + amountToAdd); } /** Returns a range that is equal to this one with the specified amount subtracted from its start and end. */ - JUCE_CONSTEXPR Range operator- (const ValueType amountToSubtract) const noexcept + constexpr Range operator- (const ValueType amountToSubtract) const noexcept { return Range (start - amountToSubtract, end - amountToSubtract); } - JUCE_CONSTEXPR bool operator== (Range other) const noexcept { return start == other.start && end == other.end; } - JUCE_CONSTEXPR bool operator!= (Range other) const noexcept { return start != other.start || end != other.end; } + constexpr bool operator== (Range other) const noexcept { return start == other.start && end == other.end; } + constexpr bool operator!= (Range other) const noexcept { return start != other.start || end != other.end; } //============================================================================== /** Returns true if the given position lies inside this range. When making this comparison, the start value is considered to be inclusive, and the end of the range exclusive. */ - JUCE_CONSTEXPR bool contains (const ValueType position) const noexcept + constexpr bool contains (const ValueType position) const noexcept { return start <= position && position < end; } @@ -218,34 +218,34 @@ class Range } /** Returns true if the given range lies entirely inside this range. */ - JUCE_CONSTEXPR bool contains (Range other) const noexcept + constexpr bool contains (Range other) const noexcept { return start <= other.start && end >= other.end; } /** Returns true if the given range intersects this one. */ - JUCE_CONSTEXPR bool intersects (Range other) const noexcept + constexpr bool intersects (Range other) const noexcept { return other.start < end && start < other.end; } /** Returns the range that is the intersection of the two ranges, or an empty range with an undefined start position if they don't overlap. */ - JUCE_CONSTEXPR Range getIntersectionWith (Range other) const noexcept + constexpr Range getIntersectionWith (Range other) const noexcept { return Range (jmax (start, other.start), jmin (end, other.end)); } /** Returns the smallest range that contains both this one and the other one. */ - JUCE_CONSTEXPR Range getUnionWith (Range other) const noexcept + constexpr Range getUnionWith (Range other) const noexcept { return Range (jmin (start, other.start), jmax (end, other.end)); } /** Returns the smallest range that contains both this one and the given value. */ - JUCE_CONSTEXPR Range getUnionWith (const ValueType valueToInclude) const noexcept + constexpr Range getUnionWith (const ValueType valueToInclude) const noexcept { return Range (jmin (valueToInclude, start), jmax (valueToInclude, end)); diff --git a/JuceLibraryCode/modules/juce_core/maths/juce_StatisticsAccumulator.h b/JuceLibraryCode/modules/juce_core/maths/juce_StatisticsAccumulator.h index 6491d33..0bc36a8 100644 --- a/JuceLibraryCode/modules/juce_core/maths/juce_StatisticsAccumulator.h +++ b/JuceLibraryCode/modules/juce_core/maths/juce_StatisticsAccumulator.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_core/memory/juce_AllocationHooks.cpp b/JuceLibraryCode/modules/juce_core/memory/juce_AllocationHooks.cpp new file mode 100644 index 0000000..cc55b69 --- /dev/null +++ b/JuceLibraryCode/modules/juce_core/memory/juce_AllocationHooks.cpp @@ -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. + + ============================================================================== +*/ + +#if JUCE_ENABLE_ALLOCATION_HOOKS + +namespace juce +{ + +static AllocationHooks& getAllocationHooksForThread() +{ + thread_local AllocationHooks hooks; + return hooks; +} + +void notifyAllocationHooksForThread() +{ + getAllocationHooksForThread().listenerList.call ([] (AllocationHooks::Listener& l) + { + l.newOrDeleteCalled(); + }); +} + +} + +void* operator new (size_t s) +{ + juce::notifyAllocationHooksForThread(); + return std::malloc (s); +} + +void* operator new[] (size_t s) +{ + juce::notifyAllocationHooksForThread(); + return std::malloc (s); +} + +void operator delete (void* p) noexcept +{ + juce::notifyAllocationHooksForThread(); + std::free (p); +} + +void operator delete[] (void* p) noexcept +{ + juce::notifyAllocationHooksForThread(); + std::free (p); +} + +#if JUCE_CXX14_IS_AVAILABLE + +void operator delete (void* p, size_t) noexcept +{ + juce::notifyAllocationHooksForThread(); + std::free (p); +} + +void operator delete[] (void* p, size_t) noexcept +{ + juce::notifyAllocationHooksForThread(); + std::free (p); +} + +#endif + +namespace juce +{ + +//============================================================================== +UnitTestAllocationChecker::UnitTestAllocationChecker (UnitTest& test) + : unitTest (test) +{ + getAllocationHooksForThread().addListener (this); +} + +UnitTestAllocationChecker::~UnitTestAllocationChecker() noexcept +{ + getAllocationHooksForThread().removeListener (this); + unitTest.expectEquals (calls, (size_t) 0, "new or delete was incorrectly called while allocation checker was active"); +} + +void UnitTestAllocationChecker::newOrDeleteCalled() noexcept { ++calls; } + +} + +#endif diff --git a/JuceLibraryCode/modules/juce_core/memory/juce_AllocationHooks.h b/JuceLibraryCode/modules/juce_core/memory/juce_AllocationHooks.h new file mode 100644 index 0000000..deb8a05 --- /dev/null +++ b/JuceLibraryCode/modules/juce_core/memory/juce_AllocationHooks.h @@ -0,0 +1,73 @@ +/* + ============================================================================== + + 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. + + ============================================================================== +*/ + +#if JUCE_ENABLE_ALLOCATION_HOOKS + +namespace juce +{ + +class AllocationHooks +{ +public: + struct Listener + { + virtual ~Listener() noexcept = default; + virtual void newOrDeleteCalled() noexcept = 0; + }; + + void addListener (Listener* l) { listenerList.add (l); } + void removeListener (Listener* l) noexcept { listenerList.remove (l); } + +private: + friend void notifyAllocationHooksForThread(); + ListenerList listenerList; +}; + +//============================================================================== +/** Scoped checker which will cause a unit test failure if any new/delete calls + are made during the lifetime of the UnitTestAllocationChecker. +*/ +class UnitTestAllocationChecker : private AllocationHooks::Listener +{ +public: + /** Create a checker which will log a failure to the passed test if + any calls to new/delete are made. + + Remember to call `UnitTest::beginTest` before constructing this checker! + */ + explicit UnitTestAllocationChecker (UnitTest& test); + + /** Will add a failure to the test if the number of new/delete calls during + this object's lifetime was greater than zero. + */ + ~UnitTestAllocationChecker() noexcept override; + +private: + void newOrDeleteCalled() noexcept override; + + UnitTest& unitTest; + size_t calls = 0; +}; + +} + +#endif diff --git a/JuceLibraryCode/modules/juce_core/memory/juce_Atomic.h b/JuceLibraryCode/modules/juce_core/memory/juce_Atomic.h index 113bd1e..bfbf79e 100644 --- a/JuceLibraryCode/modules/juce_core/memory/juce_Atomic.h +++ b/JuceLibraryCode/modules/juce_core/memory/juce_Atomic.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_core/memory/juce_ByteOrder.h b/JuceLibraryCode/modules/juce_core/memory/juce_ByteOrder.h index b9e544c..4ecc99a 100644 --- a/JuceLibraryCode/modules/juce_core/memory/juce_ByteOrder.h +++ b/JuceLibraryCode/modules/juce_core/memory/juce_ByteOrder.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,6 +20,10 @@ ============================================================================== */ +#if ! DOXYGEN && (JUCE_MAC || JUCE_IOS) + #include +#endif + namespace juce { @@ -34,10 +38,10 @@ class JUCE_API ByteOrder public: //============================================================================== /** Swaps the upper and lower bytes of a 16-bit integer. */ - JUCE_CONSTEXPR static uint16 swap (uint16 value) noexcept; + constexpr static uint16 swap (uint16 value) noexcept; /** Swaps the upper and lower bytes of a 16-bit integer. */ - JUCE_CONSTEXPR static int16 swap (int16 value) noexcept; + constexpr static int16 swap (int16 value) noexcept; /** Reverses the order of the 4 bytes in a 32-bit integer. */ static uint32 swap (uint32 value) noexcept; @@ -82,50 +86,50 @@ class JUCE_API ByteOrder //============================================================================== /** Turns 4 bytes into a little-endian integer. */ - JUCE_CONSTEXPR static uint32 littleEndianInt (const void* bytes) noexcept; + constexpr static uint32 littleEndianInt (const void* bytes) noexcept; /** Turns 8 bytes into a little-endian integer. */ - JUCE_CONSTEXPR static uint64 littleEndianInt64 (const void* bytes) noexcept; + constexpr static uint64 littleEndianInt64 (const void* bytes) noexcept; /** Turns 2 bytes into a little-endian integer. */ - JUCE_CONSTEXPR static uint16 littleEndianShort (const void* bytes) noexcept; + constexpr static uint16 littleEndianShort (const void* bytes) noexcept; /** Converts 3 little-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */ - JUCE_CONSTEXPR static int littleEndian24Bit (const void* bytes) noexcept; + constexpr static int littleEndian24Bit (const void* bytes) noexcept; /** Copies a 24-bit number to 3 little-endian bytes. */ static void littleEndian24BitToChars (int32 value, void* destBytes) noexcept; //============================================================================== /** Turns 4 bytes into a big-endian integer. */ - JUCE_CONSTEXPR static uint32 bigEndianInt (const void* bytes) noexcept; + constexpr static uint32 bigEndianInt (const void* bytes) noexcept; /** Turns 8 bytes into a big-endian integer. */ - JUCE_CONSTEXPR static uint64 bigEndianInt64 (const void* bytes) noexcept; + constexpr static uint64 bigEndianInt64 (const void* bytes) noexcept; /** Turns 2 bytes into a big-endian integer. */ - JUCE_CONSTEXPR static uint16 bigEndianShort (const void* bytes) noexcept; + constexpr static uint16 bigEndianShort (const void* bytes) noexcept; /** Converts 3 big-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */ - JUCE_CONSTEXPR static int bigEndian24Bit (const void* bytes) noexcept; + constexpr static int bigEndian24Bit (const void* bytes) noexcept; /** Copies a 24-bit number to 3 big-endian bytes. */ static void bigEndian24BitToChars (int32 value, void* destBytes) noexcept; //============================================================================== /** Constructs a 16-bit integer from its constituent bytes, in order of significance. */ - JUCE_CONSTEXPR static uint16 makeInt (uint8 leastSig, uint8 mostSig) noexcept; + constexpr static uint16 makeInt (uint8 leastSig, uint8 mostSig) noexcept; /** Constructs a 32-bit integer from its constituent bytes, in order of significance. */ - JUCE_CONSTEXPR static uint32 makeInt (uint8 leastSig, uint8 byte1, uint8 byte2, uint8 mostSig) noexcept; + constexpr static uint32 makeInt (uint8 leastSig, uint8 byte1, uint8 byte2, uint8 mostSig) noexcept; /** Constructs a 64-bit integer from its constituent bytes, in order of significance. */ - JUCE_CONSTEXPR static uint64 makeInt (uint8 leastSig, uint8 byte1, uint8 byte2, uint8 byte3, - uint8 byte4, uint8 byte5, uint8 byte6, uint8 mostSig) noexcept; + constexpr static uint64 makeInt (uint8 leastSig, uint8 byte1, uint8 byte2, uint8 byte3, + uint8 byte4, uint8 byte5, uint8 byte6, uint8 mostSig) noexcept; //============================================================================== /** Returns true if the current CPU is big-endian. */ - JUCE_CONSTEXPR static bool isBigEndian() noexcept + constexpr static bool isBigEndian() noexcept { #if JUCE_LITTLE_ENDIAN return false; @@ -140,8 +144,8 @@ class JUCE_API ByteOrder //============================================================================== -JUCE_CONSTEXPR inline uint16 ByteOrder::swap (uint16 v) noexcept { return static_cast ((v << 8) | (v >> 8)); } -JUCE_CONSTEXPR inline int16 ByteOrder::swap (int16 v) noexcept { return static_cast (swap (static_cast (v))); } +constexpr inline uint16 ByteOrder::swap (uint16 v) noexcept { return static_cast ((v << 8) | (v >> 8)); } +constexpr inline int16 ByteOrder::swap (int16 v) noexcept { return static_cast (swap (static_cast (v))); } inline int32 ByteOrder::swap (int32 v) noexcept { return static_cast (swap (static_cast (v))); } inline int64 ByteOrder::swap (int64 v) noexcept { return static_cast (swap (static_cast (v))); } inline float ByteOrder::swap (float v) noexcept { union { uint32 asUInt; float asFloat; } n; n.asFloat = v; n.asUInt = swap (n.asUInt); return n.asFloat; } @@ -178,41 +182,41 @@ inline uint64 ByteOrder::swap (uint64 value) noexcept #endif } -JUCE_CONSTEXPR inline uint16 ByteOrder::makeInt (uint8 b0, uint8 b1) noexcept +constexpr inline uint16 ByteOrder::makeInt (uint8 b0, uint8 b1) noexcept { return static_cast (static_cast (b0) | (static_cast (b1) << 8)); } -JUCE_CONSTEXPR inline uint32 ByteOrder::makeInt (uint8 b0, uint8 b1, uint8 b2, uint8 b3) noexcept +constexpr inline uint32 ByteOrder::makeInt (uint8 b0, uint8 b1, uint8 b2, uint8 b3) noexcept { return static_cast (b0) | (static_cast (b1) << 8) | (static_cast (b2) << 16) | (static_cast (b3) << 24); } -JUCE_CONSTEXPR inline uint64 ByteOrder::makeInt (uint8 b0, uint8 b1, uint8 b2, uint8 b3, uint8 b4, uint8 b5, uint8 b6, uint8 b7) noexcept +constexpr inline uint64 ByteOrder::makeInt (uint8 b0, uint8 b1, uint8 b2, uint8 b3, uint8 b4, uint8 b5, uint8 b6, uint8 b7) noexcept { return static_cast (b0) | (static_cast (b1) << 8) | (static_cast (b2) << 16) | (static_cast (b3) << 24) | (static_cast (b4) << 32) | (static_cast (b5) << 40) | (static_cast (b6) << 48) | (static_cast (b7) << 56); } -JUCE_CONSTEXPR inline uint16 ByteOrder::littleEndianShort (const void* bytes) noexcept { return makeInt (static_cast (bytes)[0], static_cast (bytes)[1]); } -JUCE_CONSTEXPR inline uint32 ByteOrder::littleEndianInt (const void* bytes) noexcept { return makeInt (static_cast (bytes)[0], static_cast (bytes)[1], +constexpr inline uint16 ByteOrder::littleEndianShort (const void* bytes) noexcept { return makeInt (static_cast (bytes)[0], static_cast (bytes)[1]); } +constexpr inline uint32 ByteOrder::littleEndianInt (const void* bytes) noexcept { return makeInt (static_cast (bytes)[0], static_cast (bytes)[1], static_cast (bytes)[2], static_cast (bytes)[3]); } -JUCE_CONSTEXPR inline uint64 ByteOrder::littleEndianInt64 (const void* bytes) noexcept { return makeInt (static_cast (bytes)[0], static_cast (bytes)[1], +constexpr inline uint64 ByteOrder::littleEndianInt64 (const void* bytes) noexcept { return makeInt (static_cast (bytes)[0], static_cast (bytes)[1], static_cast (bytes)[2], static_cast (bytes)[3], static_cast (bytes)[4], static_cast (bytes)[5], static_cast (bytes)[6], static_cast (bytes)[7]); } -JUCE_CONSTEXPR inline uint16 ByteOrder::bigEndianShort (const void* bytes) noexcept { return makeInt (static_cast (bytes)[1], static_cast (bytes)[0]); } -JUCE_CONSTEXPR inline uint32 ByteOrder::bigEndianInt (const void* bytes) noexcept { return makeInt (static_cast (bytes)[3], static_cast (bytes)[2], +constexpr inline uint16 ByteOrder::bigEndianShort (const void* bytes) noexcept { return makeInt (static_cast (bytes)[1], static_cast (bytes)[0]); } +constexpr inline uint32 ByteOrder::bigEndianInt (const void* bytes) noexcept { return makeInt (static_cast (bytes)[3], static_cast (bytes)[2], static_cast (bytes)[1], static_cast (bytes)[0]); } -JUCE_CONSTEXPR inline uint64 ByteOrder::bigEndianInt64 (const void* bytes) noexcept { return makeInt (static_cast (bytes)[7], static_cast (bytes)[6], +constexpr inline uint64 ByteOrder::bigEndianInt64 (const void* bytes) noexcept { return makeInt (static_cast (bytes)[7], static_cast (bytes)[6], static_cast (bytes)[5], static_cast (bytes)[4], static_cast (bytes)[3], static_cast (bytes)[2], static_cast (bytes)[1], static_cast (bytes)[0]); } -JUCE_CONSTEXPR inline int32 ByteOrder::littleEndian24Bit (const void* bytes) noexcept { return (int32) ((((uint32) static_cast (bytes)[2]) << 16) | (((uint32) static_cast (bytes)[1]) << 8) | ((uint32) static_cast (bytes)[0])); } -JUCE_CONSTEXPR inline int32 ByteOrder::bigEndian24Bit (const void* bytes) noexcept { return (int32) ((((uint32) static_cast (bytes)[0]) << 16) | (((uint32) static_cast (bytes)[1]) << 8) | ((uint32) static_cast (bytes)[2])); } +constexpr inline int32 ByteOrder::littleEndian24Bit (const void* bytes) noexcept { return (int32) ((((uint32) static_cast (bytes)[2]) << 16) | (((uint32) static_cast (bytes)[1]) << 8) | ((uint32) static_cast (bytes)[0])); } +constexpr inline int32 ByteOrder::bigEndian24Bit (const void* bytes) noexcept { return (int32) ((((uint32) static_cast (bytes)[0]) << 16) | (((uint32) static_cast (bytes)[1]) << 8) | ((uint32) static_cast (bytes)[2])); } inline void ByteOrder::littleEndian24BitToChars (int32 value, void* destBytes) noexcept { static_cast (destBytes)[0] = (uint8) value; static_cast (destBytes)[1] = (uint8) (value >> 8); static_cast (destBytes)[2] = (uint8) (value >> 16); } inline void ByteOrder::bigEndian24BitToChars (int32 value, void* destBytes) noexcept { static_cast (destBytes)[0] = (uint8) (value >> 16); static_cast (destBytes)[1] = (uint8) (value >> 8); static_cast (destBytes)[2] = (uint8) value; } diff --git a/JuceLibraryCode/modules/juce_core/memory/juce_ContainerDeletePolicy.h b/JuceLibraryCode/modules/juce_core/memory/juce_ContainerDeletePolicy.h index 4061af8..3b38eea 100644 --- a/JuceLibraryCode/modules/juce_core/memory/juce_ContainerDeletePolicy.h +++ b/JuceLibraryCode/modules/juce_core/memory/juce_ContainerDeletePolicy.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,7 +32,7 @@ namespace juce create a specialised version of it for a particular class if you need to delete that type of object in a more appropriate way. - @see ScopedPointer, OwnedArray + @see OwnedArray @tags{Core} */ @@ -45,8 +45,8 @@ struct ContainerDeletePolicy // an incomplete type for ObjectType (for example, a type that is declared // but not defined). This is a problem because then the following delete is // undefined behaviour. The purpose of the sizeof is to capture this situation. - // If this was caused by a ScopedPointer to a forward-declared type, move the - // implementation of all methods trying to use the ScopedPointer (e.g. the destructor + // If this was caused by a OwnedArray of a forward-declared type, move the + // implementation of all methods trying to use the OwnedArray (e.g. the destructor // of the class owning it) into cpp files where they can see to the definition // of ObjectType. This should fix the error. ignoreUnused (sizeof (ObjectType)); diff --git a/JuceLibraryCode/modules/juce_core/memory/juce_HeapBlock.h b/JuceLibraryCode/modules/juce_core/memory/juce_HeapBlock.h index e526d33..b4d0630 100644 --- a/JuceLibraryCode/modules/juce_core/memory/juce_HeapBlock.h +++ b/JuceLibraryCode/modules/juce_core/memory/juce_HeapBlock.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_core/memory/juce_HeavyweightLeakedObjectDetector.h b/JuceLibraryCode/modules/juce_core/memory/juce_HeavyweightLeakedObjectDetector.h index 79d5fa1..973ed45 100644 --- a/JuceLibraryCode/modules/juce_core/memory/juce_HeavyweightLeakedObjectDetector.h +++ b/JuceLibraryCode/modules/juce_core/memory/juce_HeavyweightLeakedObjectDetector.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,14 +44,14 @@ class HeavyweightLeakedObjectDetector { public: //============================================================================== - HeavyweightLeakedObjectDetector() noexcept { getBacktraceMap().set (this, SystemStats::getStackBacktrace()); } - HeavyweightLeakedObjectDetector (const HeavyweightLeakedObjectDetector&) noexcept { getBacktraceMap().set (this, SystemStats::getStackBacktrace()); } + HeavyweightLeakedObjectDetector() noexcept { getBacktraceMap()[this] = SystemStats::getStackBacktrace(); } + HeavyweightLeakedObjectDetector (const HeavyweightLeakedObjectDetector&) noexcept { getBacktraceMap()[this] = SystemStats::getStackBacktrace(); } - ~HeavyweightLeakedObjectDetector() { getBacktraceMap().remove (this); } + ~HeavyweightLeakedObjectDetector() { getBacktraceMap().erase (this); } private: //============================================================================== - typedef HashMap*, String> BacktraceMap; + typedef std::map*, String> BacktraceMap; //============================================================================== struct BacktraceMapHolder @@ -82,11 +82,11 @@ class HeavyweightLeakedObjectDetector String str; int counter = 1; - for (typename BacktraceMap::Iterator i (map); i.next();) + for (auto& bt : map) { str << "\nBacktrace " << String (counter++) << "\n" << "-----------------------------------------------------------------" << "\n" - << i.getValue(); + << bt.second; } return str; diff --git a/JuceLibraryCode/modules/juce_core/memory/juce_LeakedObjectDetector.h b/JuceLibraryCode/modules/juce_core/memory/juce_LeakedObjectDetector.h index ad9ba62..f2e2e91 100644 --- a/JuceLibraryCode/modules/juce_core/memory/juce_LeakedObjectDetector.h +++ b/JuceLibraryCode/modules/juce_core/memory/juce_LeakedObjectDetector.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,6 +46,8 @@ class LeakedObjectDetector LeakedObjectDetector() noexcept { ++(getCounter().numObjects); } LeakedObjectDetector (const LeakedObjectDetector&) noexcept { ++(getCounter().numObjects); } + LeakedObjectDetector& operator= (const LeakedObjectDetector&) noexcept = default; + ~LeakedObjectDetector() { if (--(getCounter().numObjects) < 0) diff --git a/JuceLibraryCode/modules/juce_core/memory/juce_Memory.h b/JuceLibraryCode/modules/juce_core/memory/juce_Memory.h index 77e1efc..3b22f62 100644 --- a/JuceLibraryCode/modules/juce_core/memory/juce_Memory.h +++ b/JuceLibraryCode/modules/juce_core/memory/juce_Memory.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 @@ inline void deleteAndZero (Type& pointer) { delete poi a specific number of bytes, */ template -inline Type* addBytesToPointer (Type* basePointer, IntegerType bytes) noexcept { return (Type*) (const_cast (reinterpret_cast (basePointer)) + bytes); } +inline Type* addBytesToPointer (Type* basePointer, IntegerType bytes) noexcept { return reinterpret_cast (const_cast (reinterpret_cast (basePointer)) + bytes); } /** A handy function to round up a pointer to the nearest multiple of a given number of bytes. alignmentBytes must be a power of two. */ diff --git a/JuceLibraryCode/modules/juce_core/memory/juce_MemoryBlock.cpp b/JuceLibraryCode/modules/juce_core/memory/juce_MemoryBlock.cpp index 1b3e28c..f14153c 100644 --- a/JuceLibraryCode/modules/juce_core/memory/juce_MemoryBlock.cpp +++ b/JuceLibraryCode/modules/juce_core/memory/juce_MemoryBlock.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. @@ -321,7 +321,7 @@ void MemoryBlock::loadFromHexString (StringRef hex) for (;;) { - int byte = 0; + juce_wchar byte = 0; for (int loop = 2; --loop >= 0;) { @@ -356,7 +356,7 @@ String MemoryBlock::toBase64Encoding() const String destString ((unsigned int) size); // store the length, followed by a '.', and then the data. auto initialLen = destString.length(); - destString.preallocateBytes (sizeof (String::CharPointerType::CharType) * (size_t) initialLen + 2 + numChars); + destString.preallocateBytes ((size_t) initialLen * sizeof (String::CharPointerType::CharType) + 2 + numChars); auto d = destString.getCharPointer(); d += initialLen; diff --git a/JuceLibraryCode/modules/juce_core/memory/juce_MemoryBlock.h b/JuceLibraryCode/modules/juce_core/memory/juce_MemoryBlock.h index 40dc9f6..7839ea8 100644 --- a/JuceLibraryCode/modules/juce_core/memory/juce_MemoryBlock.h +++ b/JuceLibraryCode/modules/juce_core/memory/juce_MemoryBlock.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. @@ -88,19 +88,36 @@ class JUCE_API MemoryBlock Note that the pointer returned will probably become invalid when the block is resized. */ - void* getData() const noexcept { return data; } + void* getData() noexcept { return data; } + + /** Returns a void pointer to the data. + + Note that the pointer returned will probably become invalid when the + block is resized. + */ + const void* getData() const noexcept { return data; } /** Returns a byte from the memory block. This returns a reference, so you can also use it to set a byte. */ template - char& operator[] (const Type offset) const noexcept { return data [offset]; } + char& operator[] (const Type offset) noexcept { return data [offset]; } + + /** Returns a byte from the memory block. */ + template + const char& operator[] (const Type offset) const noexcept { return data [offset]; } + + /** Returns an iterator for the data. */ + char* begin() noexcept { return data; } /** Returns an iterator for the data. */ - char* begin() const noexcept { return data; } + const char* begin() const noexcept { return data; } + + /** Returns an end-iterator for the data. */ + char* end() noexcept { return begin() + getSize(); } /** Returns an end-iterator for the data. */ - char* end() const noexcept { return begin() + getSize(); } + const char* end() const noexcept { return begin() + getSize(); } //============================================================================== /** Returns the block's current allocated size, in bytes. */ diff --git a/JuceLibraryCode/modules/juce_core/memory/juce_OptionalScopedPointer.h b/JuceLibraryCode/modules/juce_core/memory/juce_OptionalScopedPointer.h index da5c006..cd27d24 100644 --- a/JuceLibraryCode/modules/juce_core/memory/juce_OptionalScopedPointer.h +++ b/JuceLibraryCode/modules/juce_core/memory/juce_OptionalScopedPointer.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. @@ -28,11 +28,9 @@ namespace juce Holds a pointer to an object which can optionally be deleted when this pointer goes out of scope. - This acts in many ways like a ScopedPointer, but allows you to specify whether or + This acts in many ways like a std::unique_ptr, but allows you to specify whether or not the object is deleted. - @see ScopedPointer - @tags{Core} */ template @@ -46,46 +44,54 @@ class OptionalScopedPointer /** Creates an OptionalScopedPointer to point to a given object, and specifying whether the OptionalScopedPointer will delete it. - If takeOwnership is true, then the OptionalScopedPointer will act like a ScopedPointer, + If takeOwnership is true, then the OptionalScopedPointer will act like a std::unique_ptr, deleting the object when it is itself deleted. If this parameter is false, then the OptionalScopedPointer just holds a normal pointer to the object, and won't delete it. */ OptionalScopedPointer (ObjectType* objectToHold, bool takeOwnership) - : object (objectToHold), shouldDelete (takeOwnership) + : object (objectToHold), + shouldDelete (takeOwnership) { } /** Takes ownership of the object that another OptionalScopedPointer holds. - Like a normal ScopedPointer, the objectToTransferFrom object will become null, + Like a normal std::unique_ptr, the objectToTransferFrom object will become null, as ownership of the managed object is transferred to this object. The flag to indicate whether or not to delete the managed object is also copied from the source object. */ - OptionalScopedPointer (OptionalScopedPointer& objectToTransferFrom) - : object (objectToTransferFrom.release()), - shouldDelete (objectToTransferFrom.shouldDelete) + OptionalScopedPointer (OptionalScopedPointer&& other) noexcept + : object (std::move (other.object)), + shouldDelete (std::move (other.shouldDelete)) + { + } + + /** Takes ownership of the object owned by `ptr`. */ + explicit OptionalScopedPointer (std::unique_ptr&& ptr) noexcept + : OptionalScopedPointer (ptr.release(), true) + { + } + + /** Points to the same object as `ref`, but does not take ownership. */ + explicit OptionalScopedPointer (ObjectType& ref) noexcept + : OptionalScopedPointer (std::addressof (ref), false) { } /** Takes ownership of the object that another OptionalScopedPointer holds. - Like a normal ScopedPointer, the objectToTransferFrom object will become null, + Like a normal std::unique_ptr, the objectToTransferFrom object will become null, as ownership of the managed object is transferred to this object. The ownership flag that says whether or not to delete the managed object is also copied from the source object. */ - OptionalScopedPointer& operator= (OptionalScopedPointer& objectToTransferFrom) + OptionalScopedPointer& operator= (OptionalScopedPointer&& other) noexcept { - if (object != objectToTransferFrom.object) - { - reset(); - object.reset (objectToTransferFrom.object.release()); - } - - shouldDelete = objectToTransferFrom.shouldDelete; + swapWith (other); + other.reset(); return *this; } @@ -93,23 +99,23 @@ class OptionalScopedPointer takeOwnership flag that was specified when the object was first passed into an OptionalScopedPointer constructor. */ - ~OptionalScopedPointer() + ~OptionalScopedPointer() noexcept { reset(); } //============================================================================== /** Returns the object that this pointer is managing. */ - inline operator ObjectType*() const noexcept { return object.get(); } + operator ObjectType*() const noexcept { return object.get(); } /** Returns the object that this pointer is managing. */ - inline ObjectType* get() const noexcept { return object.get(); } + ObjectType* get() const noexcept { return object.get(); } /** Returns the object that this pointer is managing. */ - inline ObjectType& operator*() const noexcept { return *object; } + ObjectType& operator*() const noexcept { return *object; } /** Lets you access methods and properties of the object that this pointer is holding. */ - inline ObjectType* operator->() const noexcept { return object.get(); } + ObjectType* operator->() const noexcept { return object.get(); } //============================================================================== /** Removes the current object from this OptionalScopedPointer without deleting it. @@ -120,10 +126,12 @@ class OptionalScopedPointer /** Resets this pointer to null, possibly deleting the object that it holds, if it has ownership of it. */ - void reset() + void reset() noexcept { if (! shouldDelete) object.release(); + else + object.reset(); } /** Does the same thing as reset(). */ @@ -132,7 +140,7 @@ class OptionalScopedPointer /** Makes this OptionalScopedPointer point at a new object, specifying whether the OptionalScopedPointer will take ownership of the object. - If takeOwnership is true, then the OptionalScopedPointer will act like a ScopedPointer, + If takeOwnership is true, then the OptionalScopedPointer will act like a std::unique_ptr, deleting the object when it is itself deleted. If this parameter is false, then the OptionalScopedPointer just holds a normal pointer to the object, and won't delete it. */ @@ -170,20 +178,14 @@ class OptionalScopedPointer */ void swapWith (OptionalScopedPointer& other) noexcept { - object.swapWith (other.object); - std::swap (shouldDelete, other.shouldDelete); + std::swap (other.object, object); + std::swap (other.shouldDelete, shouldDelete); } private: //============================================================================== - ScopedPointer object; + std::unique_ptr object; bool shouldDelete = false; - - // This is here to avoid people accidentally taking a second owned copy of - // a scoped pointer, which is almost certainly not what you intended to do! - // If you hit a problem with this, you probably meant to say - // myPointer.setOwned (myScopedPointer.release()) - void setOwned (const ScopedPointer&) = delete; }; } // namespace juce diff --git a/JuceLibraryCode/modules/juce_core/memory/juce_ReferenceCountedObject.h b/JuceLibraryCode/modules/juce_core/memory/juce_ReferenceCountedObject.h index a1f7007..64dfa99 100644 --- a/JuceLibraryCode/modules/juce_core/memory/juce_ReferenceCountedObject.h +++ b/JuceLibraryCode/modules/juce_core/memory/juce_ReferenceCountedObject.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,9 +49,14 @@ namespace juce Once a new ReferenceCountedObject has been assigned to a pointer, be careful not to delete the object manually. - This class uses an Atomic value to hold the reference count, so that - the pointers can be passed between threads safely. For a faster but non-thread-safe - version, use SingleThreadedReferenceCountedObject instead. + This class uses an Atomic value to hold the reference count, so + the reference count can be updated on multiple threads. Note that + whilst it's thread-safe to create and delete a ReferenceCountedObjectPtr + to a ReferenceCountedObject shared between threads, it's not thread-safe + to modify or swap the ReferenceCountedObject. + + For a faster but non-thread-safe version, use SingleThreadedReferenceCountedObject + instead. @see ReferenceCountedObjectPtr, ReferenceCountedArray, SingleThreadedReferenceCountedObject diff --git a/JuceLibraryCode/modules/juce_core/memory/juce_ScopedPointer.h b/JuceLibraryCode/modules/juce_core/memory/juce_ScopedPointer.h index 683cbd0..9d75c35 100644 --- a/JuceLibraryCode/modules/juce_core/memory/juce_ScopedPointer.h +++ b/JuceLibraryCode/modules/juce_core/memory/juce_ScopedPointer.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,82 +20,41 @@ ============================================================================== */ +#ifndef DOXYGEN + namespace juce { //============================================================================== /** This class is deprecated. You should use std::unique_ptr instead. - - - A ScopedPointer holds a pointer that is automatically deleted when the ScopedPointer - goes out of scope. - - Once a pointer has been passed to a ScopedPointer, it will make sure that the pointer - gets deleted when the ScopedPointer is deleted. Using the ScopedPointer on the stack or - as member variables is a good way to use RAII to avoid accidentally leaking dynamically - created objects. - - A ScopedPointer can be used in pretty much the same way that you'd use a normal pointer - to an object. If you use the assignment operator to assign a different object to a - ScopedPointer, the old one will be automatically deleted. - - Important note: The class is designed to hold a pointer to an object, NOT to an array! - It calls delete on its payload, not delete[], so do not give it an array to hold! For - that kind of purpose, you should be using HeapBlock or Array instead. - - A const ScopedPointer is guaranteed not to lose ownership of its object or change the - object to which it points during its lifetime. This means that making a copy of a const - ScopedPointer is impossible, as that would involve the new copy taking ownership from the - old one. - - If you need to get a pointer out of a ScopedPointer without it being deleted, you - can use the release() method. - - @tags{Core} */ template class ScopedPointer { public: //============================================================================== - /** Creates a ScopedPointer containing a null pointer. */ - inline ScopedPointer() = default; + // ScopedPointer is deprecated! You should use std::unique_ptr instead. + JUCE_DEPRECATED_ATTRIBUTE inline ScopedPointer() = default; - /** Creates a ScopedPointer containing a null pointer. */ - inline ScopedPointer (decltype (nullptr)) noexcept {} + // ScopedPointer is deprecated! You should use std::unique_ptr instead. + JUCE_DEPRECATED_ATTRIBUTE inline ScopedPointer (decltype (nullptr)) noexcept {} - /** Creates a ScopedPointer that owns the specified object. */ - inline ScopedPointer (ObjectType* objectToTakePossessionOf) noexcept + // ScopedPointer is deprecated! You should use std::unique_ptr instead. + JUCE_DEPRECATED_ATTRIBUTE inline ScopedPointer (ObjectType* objectToTakePossessionOf) noexcept : object (objectToTakePossessionOf) { } - /** Creates a ScopedPointer that takes its pointer from another ScopedPointer. - - Because a pointer can only belong to one ScopedPointer, this transfers - the pointer from the other object to this one, and the other object is reset to - be a null pointer. - */ + // ScopedPointer is deprecated! You should use std::unique_ptr instead. ScopedPointer (ScopedPointer& objectToTransferFrom) noexcept : object (objectToTransferFrom.release()) { } - /** Destructor. - If the ScopedPointer currently refers to an object, it'll be deleted. - */ - inline ~ScopedPointer() { reset(); } + // ScopedPointer is deprecated! You should use std::unique_ptr instead. + JUCE_DEPRECATED_ATTRIBUTE inline ~ScopedPointer() { reset(); } - /** Changes this ScopedPointer to point to a new object. - - Because a pointer can only belong to one ScopedPointer, this transfers - the pointer from the other object to this one, and the other object is reset to - be a null pointer. - - If this ScopedPointer already points to an object, that object - will first be deleted. - */ ScopedPointer& operator= (ScopedPointer& objectToTransferFrom) { if (this != objectToTransferFrom.getAddress()) @@ -109,23 +68,17 @@ class ScopedPointer return *this; } - /** Changes this ScopedPointer to point to a new object. - If this ScopedPointer already points to an object, that object will first be deleted. - The pointer that you pass in may be a nullptr. - */ ScopedPointer& operator= (ObjectType* newObjectToTakePossessionOf) { reset (newObjectToTakePossessionOf); return *this; } - /** Take ownership of another ScopedPointer */ ScopedPointer (ScopedPointer&& other) noexcept : object (other.object) { other.object = nullptr; } - /** Take ownership of another ScopedPointer */ ScopedPointer& operator= (ScopedPointer&& other) noexcept { reset (other.release()); @@ -133,20 +86,11 @@ class ScopedPointer } //============================================================================== - /** Returns the object that this ScopedPointer refers to. */ inline operator ObjectType*() const noexcept { return object; } - - /** Returns the object that this ScopedPointer refers to. */ inline ObjectType* get() const noexcept { return object; } - - /** Returns the object that this ScopedPointer refers to. */ inline ObjectType& operator*() const noexcept { return *object; } - - /** Lets you access methods and properties of the object that this ScopedPointer refers to. */ inline ObjectType* operator->() const noexcept { return object; } - //============================================================================== - /** Clears this pointer, deleting the object it points to if there is one. */ void reset() { auto* oldObject = object; @@ -154,7 +98,6 @@ class ScopedPointer ContainerDeletePolicy::destroy (oldObject); } - /** Sets this pointer to a new object, deleting the old object that it was previously pointing to if there was one. */ void reset (ObjectType* newObject) { if (object != newObject) @@ -171,21 +114,14 @@ class ScopedPointer } } - /** Sets this pointer to a new object, deleting the old object that it was previously pointing to if there was one. */ void reset (ScopedPointer& newObject) { reset (newObject.release()); } - /** Detaches and returns the current object from this ScopedPointer without deleting it. - This will return the current object, and set the ScopedPointer to a null pointer. - */ - ObjectType* release() noexcept { auto* o = object; object = {}; return o; } + ObjectType* release() noexcept { auto* o = object; object = {}; return o; } //============================================================================== - /** Swaps this object with that of another ScopedPointer. - The two objects simply exchange their pointers. - */ void swapWith (ScopedPointer& other) noexcept { // Two ScopedPointers should never be able to refer to the same object - if @@ -195,10 +131,7 @@ class ScopedPointer std::swap (object, other.object); } - /** If the pointer is non-null, this will attempt to return a new copy of the object that is pointed to. - If the pointer is null, this will safely return a nullptr. - */ - inline ObjectType* createCopy() const { return createCopyIfNotNull (object); } + inline ObjectType* createCopy() const { return createCopyIfNotNull (object); } private: //============================================================================== @@ -213,70 +146,60 @@ class ScopedPointer }; //============================================================================== -/** Compares a ScopedPointer with another pointer. */ template bool operator== (ObjectType1* pointer1, const ScopedPointer& pointer2) noexcept { return pointer1 == pointer2.get(); } -/** Compares a ScopedPointer with another pointer. */ template bool operator!= (ObjectType1* pointer1, const ScopedPointer& pointer2) noexcept { return pointer1 != pointer2.get(); } -/** Compares a ScopedPointer with another pointer. */ template bool operator== (const ScopedPointer& pointer1, ObjectType2* pointer2) noexcept { return pointer1.get() == pointer2; } -/** Compares a ScopedPointer with another pointer. */ template bool operator!= (const ScopedPointer& pointer1, ObjectType2* pointer2) noexcept { return pointer1.get() != pointer2; } -/** Compares a ScopedPointer with another pointer. */ template bool operator== (const ScopedPointer& pointer1, const ScopedPointer& pointer2) noexcept { return pointer1.get() == pointer2.get(); } -/** Compares a ScopedPointer with another pointer. */ template bool operator!= (const ScopedPointer& pointer1, const ScopedPointer& pointer2) noexcept { return pointer1.get() != pointer2.get(); } -/** Compares a ScopedPointer with a nullptr. */ template bool operator== (decltype (nullptr), const ScopedPointer& pointer) noexcept { return pointer.get() == nullptr; } -/** Compares a ScopedPointer with a nullptr. */ template bool operator!= (decltype (nullptr), const ScopedPointer& pointer) noexcept { return pointer.get() != nullptr; } -/** Compares a ScopedPointer with a nullptr. */ template bool operator== (const ScopedPointer& pointer, decltype (nullptr)) noexcept { return pointer.get() == nullptr; } -/** Compares a ScopedPointer with a nullptr. */ template bool operator!= (const ScopedPointer& pointer, decltype (nullptr)) noexcept { @@ -284,11 +207,11 @@ bool operator!= (const ScopedPointer& pointer, decltype (nullptr)) n } //============================================================================== -#ifndef DOXYGEN // NB: This is just here to prevent any silly attempts to call deleteAndZero() on a ScopedPointer. template void deleteAndZero (ScopedPointer&) { static_assert (sizeof (Type) == 12345, "Attempt to call deleteAndZero() on a ScopedPointer"); } -#endif } // namespace juce + +#endif diff --git a/JuceLibraryCode/modules/juce_core/memory/juce_SharedResourcePointer.h b/JuceLibraryCode/modules/juce_core/memory/juce_SharedResourcePointer.h index b9b9513..5eebbbf 100644 --- a/JuceLibraryCode/modules/juce_core/memory/juce_SharedResourcePointer.h +++ b/JuceLibraryCode/modules/juce_core/memory/juce_SharedResourcePointer.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. @@ -116,12 +116,10 @@ class SharedResourcePointer /** Returns the shared object. */ SharedObjectType& get() const noexcept { return *sharedObject; } - /** Returns the object that this pointer references. - The pointer returned may be a nullptr, of course. - */ + /** Returns the object that this pointer references. */ SharedObjectType& getObject() const noexcept { return *sharedObject; } - /** Returns the shared object. */ + /** Returns the shared object pointer. */ SharedObjectType* operator->() const noexcept { return sharedObject; } /** Returns the number of SharedResourcePointers that are currently holding the shared object. */ diff --git a/JuceLibraryCode/modules/juce_core/memory/juce_Singleton.h b/JuceLibraryCode/modules/juce_core/memory/juce_Singleton.h index 5d95a22..c671cd0 100644 --- a/JuceLibraryCode/modules/juce_core/memory/juce_Singleton.h +++ b/JuceLibraryCode/modules/juce_core/memory/juce_Singleton.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_core/memory/juce_WeakReference.h b/JuceLibraryCode/modules/juce_core/memory/juce_WeakReference.h index f91e8ad..d0b8898 100644 --- a/JuceLibraryCode/modules/juce_core/memory/juce_WeakReference.h +++ b/JuceLibraryCode/modules/juce_core/memory/juce_WeakReference.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. @@ -105,10 +105,7 @@ class WeakReference operator ObjectType*() const noexcept { return get(); } /** Returns the object that this pointer refers to, or null if the object no longer exists. */ - ObjectType* operator->() noexcept { return get(); } - - /** Returns the object that this pointer refers to, or null if the object no longer exists. */ - const ObjectType* operator->() const noexcept { return get(); } + ObjectType* operator->() const noexcept { return get(); } /** This returns true if this reference has been pointing at an object, but that object has since been deleted. @@ -204,7 +201,7 @@ class WeakReference private: SharedRef holder; - static inline SharedRef getRef (ObjectType* o) + static SharedRef getRef (ObjectType* o) { if (o != nullptr) return o->masterReference.getSharedPointer (o); diff --git a/JuceLibraryCode/modules/juce_core/misc/juce_ConsoleApplication.cpp b/JuceLibraryCode/modules/juce_core/misc/juce_ConsoleApplication.cpp index e7e7029..febe9b8 100644 --- a/JuceLibraryCode/modules/juce_core/misc/juce_ConsoleApplication.cpp +++ b/JuceLibraryCode/modules/juce_core/misc/juce_ConsoleApplication.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,21 +23,36 @@ namespace juce { -static inline File resolveFilename (const String& name) +static File resolveFilename (const String& name) { return File::getCurrentWorkingDirectory().getChildFile (name.unquoted()); } -static inline void checkFileExists (const File& f) +static File checkFileExists (const File& f) { if (! f.exists()) ConsoleApplication::fail ("Could not find file: " + f.getFullPathName()); + + return f; } -static inline void checkFolderExists (const File& f) +static File checkFolderExists (const File& f) { if (! f.isDirectory()) ConsoleApplication::fail ("Could not find folder: " + f.getFullPathName()); + + return f; +} + +static File resolveFilenameForOption (const ArgumentList& args, StringRef option, const String& filename) +{ + if (filename.isEmpty()) + { + args.failIfOptionIsMissing (option); + ConsoleApplication::fail ("Expected a filename after the " + option + " option"); + } + + return resolveFilename (filename); } File ArgumentList::Argument::resolveAsFile() const @@ -47,9 +62,7 @@ File ArgumentList::Argument::resolveAsFile() const File ArgumentList::Argument::resolveAsExistingFile() const { - auto f = resolveAsFile(); - checkFileExists (f); - return f; + return checkFileExists (resolveAsFile()); } File ArgumentList::Argument::resolveAsExistingFolder() const @@ -62,9 +75,9 @@ File ArgumentList::Argument::resolveAsExistingFolder() const return f; } -static inline bool isShortOptionFormat (StringRef s) { return s[0] == '-' && s[1] != '-'; } -static inline bool isLongOptionFormat (StringRef s) { return s[0] == '-' && s[1] == '-' && s[2] != '-'; } -static inline bool isOptionFormat (StringRef s) { return s[0] == '-'; } +static bool isShortOptionFormat (StringRef s) { return s[0] == '-' && s[1] != '-'; } +static bool isLongOptionFormat (StringRef s) { return s[0] == '-' && s[1] == '-' && s[2] != '-'; } +static bool isOptionFormat (StringRef s) { return s[0] == '-'; } bool ArgumentList::Argument::isLongOption() const { return isLongOptionFormat (text); } bool ArgumentList::Argument::isShortOption() const { return isShortOptionFormat (text); } @@ -84,8 +97,12 @@ bool ArgumentList::Argument::isLongOption (const String& option) const String ArgumentList::Argument::getLongOptionValue() const { if (isLongOption()) - if (auto equalsIndex = text.indexOfChar ('=')) + { + auto equalsIndex = text.indexOfChar ('='); + + if (equalsIndex > 0) return text.substring (equalsIndex + 1); + } return {}; } @@ -94,7 +111,7 @@ bool ArgumentList::Argument::isShortOption (char option) const { jassert (option != '-'); // this is probably not what you intended to pass in - return isShortOption() && text.containsChar (option); + return isShortOption() && text.containsChar (String (option)[0]); } bool ArgumentList::Argument::operator== (StringRef wildcard) const @@ -162,9 +179,19 @@ bool ArgumentList::containsOption (StringRef option) const return indexOfOption (option) >= 0; } +bool ArgumentList::removeOptionIfFound (StringRef option) +{ + auto i = indexOfOption (option); + + if (i >= 0) + arguments.remove (i); + + return i >= 0; +} + void ArgumentList::failIfOptionIsMissing (StringRef option) const { - if (! containsOption (option)) + if (indexOfOption (option) < 0) ConsoleApplication::fail ("Expected the option " + option); } @@ -194,31 +221,69 @@ String ArgumentList::getValueForOption (StringRef option) const return {}; } -File ArgumentList::getFileForOption (StringRef option) const +String ArgumentList::removeValueForOption (StringRef option) { - auto text = getValueForOption (option); + jassert (isOptionFormat (option)); // the thing you're searching for must be an option - if (text.isEmpty()) + for (int i = 0; i < arguments.size(); ++i) { - failIfOptionIsMissing (option); - ConsoleApplication::fail ("Expected a filename after the " + option + " option"); + auto& arg = arguments.getReference(i); + + if (arg == option) + { + if (arg.isShortOption()) + { + if (i < arguments.size() - 1 && ! arguments.getReference (i + 1).isOption()) + { + auto result = arguments.getReference (i + 1).text; + arguments.removeRange (i, 2); + return result; + } + + arguments.remove (i); + return {}; + } + + if (arg.isLongOption()) + { + auto result = arg.getLongOptionValue(); + arguments.remove (i); + return result; + } + } } - return resolveFilename (text); + return {}; +} + +File ArgumentList::getFileForOption (StringRef option) const +{ + return resolveFilenameForOption (*this, option, getValueForOption (option)); +} + +File ArgumentList::getFileForOptionAndRemove (StringRef option) +{ + return resolveFilenameForOption (*this, option, removeValueForOption (option)); } File ArgumentList::getExistingFileForOption (StringRef option) const { - auto file = getFileForOption (option); - checkFileExists (file); - return file; + return checkFileExists (getFileForOption (option)); +} + +File ArgumentList::getExistingFileForOptionAndRemove (StringRef option) +{ + return checkFileExists (getFileForOptionAndRemove (option)); } File ArgumentList::getExistingFolderForOption (StringRef option) const { - auto file = getFileForOption (option); - checkFolderExists (file); - return file; + return checkFolderExists (getFileForOption (option)); +} + +File ArgumentList::getExistingFolderForOptionAndRemove (StringRef option) +{ + return checkFolderExists (getFileForOptionAndRemove (option)); } //============================================================================== @@ -243,7 +308,7 @@ int ConsoleApplication::invokeCatchingFailures (std::function&& f) } catch (const ConsoleAppFailureCode& error) { - std::cout << error.errorMessage << std::endl; + std::cerr << error.errorMessage << std::endl; returnCode = error.returnCode; } @@ -268,11 +333,15 @@ const ConsoleApplication::Command* ConsoleApplication::findCommand (const Argume int ConsoleApplication::findAndRunCommand (const ArgumentList& args, bool optionMustBeFirstArg) const { - if (auto c = findCommand (args, optionMustBeFirstArg)) - return invokeCatchingFailures ([=] { c->command (args); return 0; }); + return invokeCatchingFailures ([&args, optionMustBeFirstArg, this] + { + if (auto c = findCommand (args, optionMustBeFirstArg)) + c->command (args); + else + fail ("Unrecognised arguments"); - fail ("Unrecognised arguments"); - return 0; + return 0; + }); } int ConsoleApplication::findAndRunCommand (int argc, char* argv[]) const @@ -320,37 +389,51 @@ const std::vector& ConsoleApplication::getCommands( return commands; } -void ConsoleApplication::printCommandList (const ArgumentList& args) const +static String getExeNameAndArgs (const ArgumentList& args, const ConsoleApplication::Command& command) { auto exeName = args.executableName.fromLastOccurrenceOf ("/", false, false) .fromLastOccurrenceOf ("\\", false, false); - StringArray namesAndArgs; + return " " + exeName + " " + command.argumentDescription; +} + +static void printCommandDescription (const ArgumentList& args, const ConsoleApplication::Command& command, + int descriptionIndent) +{ + auto nameAndArgs = getExeNameAndArgs (args, command); + + if (nameAndArgs.length() > descriptionIndent) + std::cout << nameAndArgs << std::endl << String().paddedRight (' ', descriptionIndent); + else + std::cout << nameAndArgs.paddedRight (' ', descriptionIndent); + + std::cout << command.shortDescription << std::endl; +} + +void ConsoleApplication::printCommandList (const ArgumentList& args) const +{ int descriptionIndent = 0; for (auto& c : commands) - { - auto nameAndArgs = exeName + " " + c.argumentDescription; - namesAndArgs.add (nameAndArgs); - descriptionIndent = std::max (descriptionIndent, nameAndArgs.length()); - } + descriptionIndent = std::max (descriptionIndent, getExeNameAndArgs (args, c).length()); - descriptionIndent = std::min (descriptionIndent + 1, 40); + descriptionIndent = std::min (descriptionIndent + 2, 40); - for (size_t i = 0; i < commands.size(); ++i) - { - auto nameAndArgs = namesAndArgs[(int) i]; - std::cout << ' '; + for (auto& c : commands) + printCommandDescription (args, c, descriptionIndent); - if (nameAndArgs.length() > descriptionIndent) - std::cout << nameAndArgs << std::endl << String::repeatedString (" ", descriptionIndent + 1); - else - std::cout << nameAndArgs.paddedRight (' ', descriptionIndent); + std::cout << std::endl; +} - std::cout << commands[i].shortDescription << std::endl; - } +void ConsoleApplication::printCommandDetails (const ArgumentList& args, const Command& command) const +{ + auto len = getExeNameAndArgs (args, command).length(); - std::cout << std::endl; + printCommandDescription (args, command, std::min (len + 3, 40)); + + if (command.longDescription.isNotEmpty()) + std::cout << std::endl << command.longDescription << std::endl; } + } // namespace juce diff --git a/JuceLibraryCode/modules/juce_core/misc/juce_ConsoleApplication.h b/JuceLibraryCode/modules/juce_core/misc/juce_ConsoleApplication.h index c9b6476..222e8bb 100644 --- a/JuceLibraryCode/modules/juce_core/misc/juce_ConsoleApplication.h +++ b/JuceLibraryCode/modules/juce_core/misc/juce_ConsoleApplication.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,6 +32,8 @@ namespace juce main() function to parse. @see ConsoleApplication + + @tags{Core} */ struct ArgumentList { @@ -50,6 +52,8 @@ struct ArgumentList //============================================================================== /** One of the arguments in an ArgumentList. + + @tags{Core} */ struct Argument { @@ -120,9 +124,17 @@ struct ArgumentList /** Returns true if the given string matches one of the arguments. The option can also be a list of different versions separated by pipes, e.g. "--help|-h" + @see removeOptionIfFound */ bool containsOption (StringRef option) const; + /** Returns true if the given string matches one of the arguments, and also removes the + argument from the list if found. + The option can also be a list of different versions separated by pipes, e.g. "--help|-h" + @see containsOption + */ + bool removeOptionIfFound (StringRef option); + /** Returns the index of the given string if it matches one of the arguments, or -1 if it doesn't. The option can also be a list of different versions separated by pipes, e.g. "--help|-h" */ @@ -142,23 +154,48 @@ struct ArgumentList */ String getValueForOption (StringRef option) const; - /** Looks for the value of argument using getValueForOption() and tries to parse that value - as a file. - If the option isn't found, or if the value can't be parsed as a filename, it will throw - an error. + /** Looks for a given argument and returns either its assigned value (for long options) or the + string that follows it (for short options). + This works like getValueForOption() but also removes the option argument (and any value arguments) + from the list if they are found. + */ + String removeValueForOption (StringRef option); + + /** Looks for the value of argument using getValueForOption() and tries to parse that value as a file. + If the option isn't found, or if the value can't be parsed as a filename, it will throw an error. */ File getFileForOption (StringRef option) const; + /** Looks for the value of argument using getValueForOption() and tries to parse that value as a file. + This works like getFileForOption() but also removes the option argument (and any value arguments) + from the list if they are found. + */ + File getFileForOptionAndRemove (StringRef option); + /** Looks for a file argument using getFileForOption() and fails with a suitable error if the file doesn't exist. */ File getExistingFileForOption (StringRef option) const; + /** Looks for a file argument using getFileForOption() and fails with a suitable error if + the file doesn't exist. + This works like getExistingFileForOption() but also removes the option argument (and any + value arguments) from the list if they are found. + */ + File getExistingFileForOptionAndRemove (StringRef option); + /** Looks for a filename argument using getFileForOption() and fails with a suitable error if the file isn't a folder that exists. */ File getExistingFolderForOption (StringRef option) const; + /** Looks for a filename argument using getFileForOption() and fails with a suitable error if + the file isn't a folder that exists. + This works like getExistingFolderForOption() but also removes the option argument (and any + value arguments) from the list if they are found. + */ + File getExistingFolderForOptionAndRemove (StringRef option); + /** The name or path of the executable that was invoked, as it was specified on the command-line. */ String executableName; @@ -193,13 +230,18 @@ struct ArgumentList @endcode @see ArgumentList + + @tags{Core} */ struct ConsoleApplication { //============================================================================== /** Represents a command that can be executed if its command-line arguments are matched. + @see ConsoleApplication::addCommand(), ConsoleApplication::findAndRunCommand() + + @tags{Core} */ struct Command { @@ -222,7 +264,7 @@ struct ConsoleApplication String longDescription; /** The actual command that should be invoked to perform this action. */ - std::function command; + std::function command; }; //============================================================================== @@ -248,6 +290,11 @@ struct ConsoleApplication */ void printCommandList (const ArgumentList&) const; + /** Prints out a longer description of a particular command, based on its + longDescription member. + */ + void printCommandDetails (const ArgumentList&, const Command&) const; + //============================================================================== /** Throws a failure exception to cause a command-line app to terminate. This is intended to be called from code in a Command, so that the diff --git a/JuceLibraryCode/modules/juce_core/misc/juce_Result.cpp b/JuceLibraryCode/modules/juce_core/misc/juce_Result.cpp index 4fba8d1..7ff2400 100644 --- a/JuceLibraryCode/modules/juce_core/misc/juce_Result.cpp +++ b/JuceLibraryCode/modules/juce_core/misc/juce_Result.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_core/misc/juce_Result.h b/JuceLibraryCode/modules/juce_core/misc/juce_Result.h index 714134b..2d8cd46 100644 --- a/JuceLibraryCode/modules/juce_core/misc/juce_Result.h +++ b/JuceLibraryCode/modules/juce_core/misc/juce_Result.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_core/misc/juce_RuntimePermissions.cpp b/JuceLibraryCode/modules/juce_core/misc/juce_RuntimePermissions.cpp index cb49bf6..e549ee2 100644 --- a/JuceLibraryCode/modules/juce_core/misc/juce_RuntimePermissions.cpp +++ b/JuceLibraryCode/modules/juce_core/misc/juce_RuntimePermissions.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_core/misc/juce_RuntimePermissions.h b/JuceLibraryCode/modules/juce_core/misc/juce_RuntimePermissions.h index 4e1f50e..d97f4e7 100644 --- a/JuceLibraryCode/modules/juce_core/misc/juce_RuntimePermissions.h +++ b/JuceLibraryCode/modules/juce_core/misc/juce_RuntimePermissions.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_core/misc/juce_StdFunctionCompat.cpp b/JuceLibraryCode/modules/juce_core/misc/juce_StdFunctionCompat.cpp deleted file mode 100644 index 58038a8..0000000 --- a/JuceLibraryCode/modules/juce_core/misc/juce_StdFunctionCompat.cpp +++ /dev/null @@ -1,282 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - Permission is granted to use this software 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. - - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD - TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, - OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - OF THIS SOFTWARE. - - ----------------------------------------------------------------------------- - - To release a closed-source product which uses other parts of JUCE not - licensed under the ISC terms, commercial licenses are available: visit - www.juce.com for more information. - - ============================================================================== -*/ - -namespace juce -{ - -#if JUCE_UNIT_TESTS - -namespace FunctionTestsHelpers -{ - static void incrementArgument (int& x) { x++; } - static double multiply (double x, double a) noexcept { return a * x; } - - struct BigData - { - BigData() - { - for (auto i = 0; i < bigDataSize; ++i) - content[i] = i + 1; - } - - int sum() const - { - int result = 0; - for (auto i = 0; i < bigDataSize; ++i) - result += content[i]; - - return result; - } - - static const int bigDataSize = 32, - bigDataSum = bigDataSize * (bigDataSize + 1) / 2; - int content[bigDataSize]; - }; - - struct FunctionObject - { - FunctionObject() = default; - - FunctionObject (const FunctionObject& other) - { - bigData.reset (new BigData (*other.bigData)); - } - - int operator()(int i) const { return bigData->sum() + i; } - - std::unique_ptr bigData { new BigData() }; - - JUCE_LEAK_DETECTOR (FunctionObject) - }; - - struct BigFunctionObject - { - BigFunctionObject() = default; - - BigFunctionObject (const BigFunctionObject& other) - { - bigData.reset (new BigData (*other.bigData)); - } - - int operator()(int i) const { return bigData->sum() + i; } - - std::unique_ptr bigData { new BigData() }; - - int stackUsage[32]; - - JUCE_LEAK_DETECTOR (BigFunctionObject) - }; -} - -class FunctionTests : public UnitTest -{ -public: - FunctionTests() : UnitTest ("Function", "Function") {} - - void runTest() override - { - FunctionTestsHelpers::BigData bigData; - - { - beginTest ("Functions"); - - std::function f1 (FunctionTestsHelpers::incrementArgument); - - auto x = 0; - f1 (x); - expectEquals (x, 1); - - std::function f2 (FunctionTestsHelpers::multiply); - expectEquals (6.0, f2 (2.0, 3.0)); - } - - { - beginTest ("Function objects"); - - std::function f1 = FunctionTestsHelpers::FunctionObject(); - expectEquals (f1 (5), FunctionTestsHelpers::BigData::bigDataSum + 5); - - std::function f2 { FunctionTestsHelpers::BigFunctionObject() }; - expectEquals (f2 (5), FunctionTestsHelpers::BigData::bigDataSum + 5); - } - - { - beginTest ("Lambdas"); - - std::function fStack ([] { return 3; }); - expectEquals (fStack(), 3); - - std::function fHeap ([=] { return bigData.sum(); }); - expectEquals (fHeap(), FunctionTestsHelpers::BigData::bigDataSum); - } - - { - beginTest ("Boolean"); - - std::function f1; - - if (f1) - expect (false); - - std::function f2 ([]() { return 3; }); - - if (! f2) - expect (false); - } - - std::function fEmpty; - - std::function fStack ([] { return 3; }); - - std::function fHeap ([=] { return bigData.sum(); }); - - { - beginTest ("copy constructor"); - - std::function f1 (fStack); - expectEquals (f1(), 3); - - std::function f2 (fHeap); - expectEquals (f2(), FunctionTestsHelpers::BigData::bigDataSum); - - std::function f3 (fEmpty); - if (f3) - expect (false); - } - - { - beginTest ("assignment"); - - std::function f1; - f1 = fStack; - expectEquals (f1(), 3); - - std::function f2; - f2 = fHeap; - expectEquals (f2(), FunctionTestsHelpers::BigData::bigDataSum); - - f1 = fHeap; - expectEquals (f1(), FunctionTestsHelpers::BigData::bigDataSum); - - f2 = fStack; - expectEquals (f2(), 3); - - f1 = fEmpty; - if (f1) - expect (false); - } - - { - beginTest ("move constructor"); - - std::unique_ptr> fStackTmp (new std::function (fStack)); - std::function f1 (std::move (*fStackTmp)); - - fStackTmp.reset(); - expectEquals (f1(), 3); - - std::unique_ptr> fHeapTmp (new std::function (fHeap)); - std::function f2 (std::move (*fHeapTmp)); - if (*fHeapTmp) - expect (false); - - fHeapTmp.reset(); - expectEquals (f2(), FunctionTestsHelpers::BigData::bigDataSum); - - std::unique_ptr> fEmptyTmp (new std::function()); - std::function f3 (std::move (*fEmptyTmp)); - fEmptyTmp.reset(); - if (f3) - expect (false); - } - - { - beginTest ("move assignment"); - - std::function f1 (fHeap); - std::unique_ptr> fStackTmp (new std::function (fStack)); - f1 = std::move (*fStackTmp); - - fStackTmp.reset(); - expectEquals (f1(), 3); - - std::function f2 (fStack); - std::unique_ptr> fHeapTmp (new std::function (fHeap)); - f2 = std::move (*fHeapTmp); - if (*fHeapTmp) - expect (false); - - fHeapTmp.reset(); - expectEquals (f2(), FunctionTestsHelpers::BigData::bigDataSum); - - std::function f3 (fHeap); - std::unique_ptr> fEmptyTmp (new std::function()); - f3 = std::move (*fEmptyTmp); - fEmptyTmp.reset(); - if (f3) - expect (false); - } - - { - beginTest ("nullptr"); - - std::function f1 (nullptr); - if (f1) - expect (false); - - std::function f2 ([]() { return 11; }); - f2 = nullptr; - if (f2) - expect (false); - } - - { - beginTest ("Swap"); - - std::function f1; - std::function f2 (fStack); - f2.swap (f1); - expectEquals (f1(), 3); - if (f2) - expect (false); - - std::function f3 (fHeap); - f3.swap (f1); - expectEquals (f3(), 3); - expectEquals (f1(), FunctionTestsHelpers::BigData::bigDataSum); - } - } -}; - -static FunctionTests functionTests; - -#endif - -} // namespace juce diff --git a/JuceLibraryCode/modules/juce_core/misc/juce_StdFunctionCompat.h b/JuceLibraryCode/modules/juce_core/misc/juce_StdFunctionCompat.h deleted file mode 100644 index 0dd6415..0000000 --- a/JuceLibraryCode/modules/juce_core/misc/juce_StdFunctionCompat.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - Permission is granted to use this software 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. - - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD - TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, - OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - OF THIS SOFTWARE. - - ----------------------------------------------------------------------------- - - To release a closed-source product which uses other parts of JUCE not - licensed under the ISC terms, commercial licenses are available: visit - www.juce.com for more information. - - ============================================================================== -*/ - -namespace std -{ - /** - This class provides an alternative to std::function that is compatible - with OS X 10.6 and earlier. This will only be used in OS X versions 10.6 - and earlier and the Projucer live build. - - @tags{Core} - */ - template - class function; - - #ifndef DOXYGEN - template - class function - { - public: - /** Creates an empty function. */ - function() noexcept {} - - /** Creates an empty function. */ - function (decltype (nullptr)) noexcept {} - - /** Creates a function targeting the provided Functor. */ - template - function (Functor f) - { - functorHolderHelper = getFunctorStorage (sizeof (FunctorHolder)); - new (functorHolderHelper) FunctorHolder (f); - } - - /** Copy constructor. */ - function (function const& other) - { - copy (other); - } - - /** Move constructor */ - function (function&& other) - { - move (other); - } - - /** Destructor. */ - ~function() - { - release(); - } - - /** Replaces the contents of this function with the contents of another. */ - function& operator= (function const& other) - { - release(); - copy (other); - - return *this; - } - - /** Moves the contents of another function into this one. */ - function& operator= (function&& other) - { - release(); - move (other); - - return *this; - } - - /** Allows conditional expressions to test if this function is empty. */ - explicit operator bool() const noexcept - { - return functorHolderHelper != nullptr; - } - - /** Swaps the contents of this function with another. After this operation the - two functions will be pointing at each other's targets. */ - void swap (function& other) - { - function tmp (*this); - *this = other; - other = tmp; - } - - /** Invokes the target of this function. */ - Result operator() (Arguments... args) const - { - return (*functorHolderHelper) (args...); - } - - bool operator== (decltype (nullptr)) const noexcept { return (functorHolderHelper == nullptr); } - bool operator!= (decltype (nullptr)) const noexcept { return (functorHolderHelper != nullptr); } - - private: - //============================================================================== - template - struct FunctorHolderBase - { - virtual ~FunctorHolderBase() {} - virtual int getSize() const noexcept = 0; - virtual void copy (void*) const = 0; - virtual ReturnType operator()(Args...) = 0; - }; - - template - struct FunctorHolder : FunctorHolderBase - { - FunctorHolder (Functor func) : f (func) {} - - int getSize() const noexcept override final - { - return sizeof (*this); - } - - void copy (void* destination) const override final - { - new (destination) FunctorHolder (f); - } - - ReturnType operator()(Args... args) override final - { - return f (args...); - } - - Functor f; - }; - - FunctorHolderBase* getFunctorStorage (int size) - { - return reinterpret_cast*> - (size > functorHolderStackSize ? new char [static_cast (size)] - : &(stackFunctorStorage[0])); - } - - void copy (function const& other) - { - if (other.functorHolderHelper != nullptr) - { - functorHolderHelper = getFunctorStorage (other.functorHolderHelper->getSize()); - other.functorHolderHelper->copy (functorHolderHelper); - } - } - - void move (function& other) - { - if (other.functorHolderHelper != nullptr) - { - if (other.functorHolderHelper->getSize() > functorHolderStackSize) - { - functorHolderHelper = other.functorHolderHelper; - } - else - { - std::copy (other.stackFunctorStorage, other.stackFunctorStorage + functorHolderStackSize, - stackFunctorStorage); - functorHolderHelper = reinterpret_cast*> (&(stackFunctorStorage[0])); - } - - other.functorHolderHelper = nullptr; - } - } - - void release() - { - if (functorHolderHelper != nullptr) - { - functorHolderHelper->~FunctorHolderBase(); - functorHolderHelper = nullptr; - } - } - - static const int functorHolderStackSize = 24; - char stackFunctorStorage[functorHolderStackSize]; - - FunctorHolderBase* functorHolderHelper = nullptr; - }; - #endif -} diff --git a/JuceLibraryCode/modules/juce_core/misc/juce_Uuid.cpp b/JuceLibraryCode/modules/juce_core/misc/juce_Uuid.cpp index eaa2fbb..1077dba 100644 --- a/JuceLibraryCode/modules/juce_core/misc/juce_Uuid.cpp +++ b/JuceLibraryCode/modules/juce_core/misc/juce_Uuid.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_core/misc/juce_Uuid.h b/JuceLibraryCode/modules/juce_core/misc/juce_Uuid.h index c73feb5..363e5b6 100644 --- a/JuceLibraryCode/modules/juce_core/misc/juce_Uuid.h +++ b/JuceLibraryCode/modules/juce_core/misc/juce_Uuid.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_core/misc/juce_WindowsRegistry.h b/JuceLibraryCode/modules/juce_core/misc/juce_WindowsRegistry.h index 785386d..b54f7b3 100644 --- a/JuceLibraryCode/modules/juce_core/misc/juce_WindowsRegistry.h +++ b/JuceLibraryCode/modules/juce_core/misc/juce_WindowsRegistry.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. @@ -90,7 +90,7 @@ class JUCE_API WindowsRegistry static bool JUCE_CALLTYPE valueExists (const String& regValuePath, WoW64Mode mode = WoW64_Default); /** Returns true if the given key exists in the registry. */ - static bool JUCE_CALLTYPE keyExists (const String& regValuePath, WoW64Mode mode = WoW64_Default); + static bool JUCE_CALLTYPE keyExists (const String& regKeyPath, WoW64Mode mode = WoW64_Default); /** Deletes a registry value. */ static bool JUCE_CALLTYPE deleteValue (const String& regValuePath, WoW64Mode mode = WoW64_Default); diff --git a/JuceLibraryCode/modules/juce_core/native/java/README.txt b/JuceLibraryCode/modules/juce_core/native/java/README.txt index 612d87c..55662d1 100644 --- a/JuceLibraryCode/modules/juce_core/native/java/README.txt +++ b/JuceLibraryCode/modules/juce_core/native/java/README.txt @@ -9,30 +9,31 @@ required for the Java source code you wish to compile. 2. If you are creating byte-code for new .java files, move the new files into the native/javacore/app folder of the module, or create one if it doesn't exist. Remember that .java files need to be in nested sub-folders which -resemble their package, i.e. a Java class com.roli.juce.HelloWorld.java -should be in the module's native/javacore/app/com/roli/juce folder. -If you wish to modify existing .java files in the JUCE modules then just rename -native/java to native/javacore. +resemble their package, i.e. a Java class com.rmsl.juce.HelloWorld.java should +be in the module's native/javacore/app/com/rmsl/juce folder. If you wish to +modify existing .java files in the JUCE modules then just rename native/java to +native/javacore. -3. Build your project with AS and run. The app will now use the source code in -the folder created in step 2 so you can debug your Java code this way. +3. Build your project with Android Studio and run. The app will now use the +source code in the folder created in step 2 so you can debug your Java code +this way. 4. Once everything is working rebuild your app in release mode. 5. Go to your app's Builds/Android folder. Inside there you will find -build/intermediates/javac/release_Release/compileRelease_ReleaseJavaWithJavac/classes. +build/intermediates/javac/release_Release/compileRelease_ReleaseJavaWithJavac/classes. Inside of that folder, you will find all your Java byte-code compiled classes. Remove any classes that you are not interested in (typically you'll find -Java.class, JuceApp.class and JuceSharingContentProvider.class which you will -probably want to remove). +Java.class and JuceApp.class which you will probably want to remove). -6. Inside of app/build/intermediates/classes/release_/release execute the -following dx command: +6. Inside of +build/intermediates/javac/release_Release/compileRelease_ReleaseJavaWithJavac/classes +execute the following dx command: /build-tools//dx --dex --verbose --min-sdk-version= --output /tmp/JavaDexByteCode.dex . (Replace with the minimal sdk version you used in step 1.) - + 7. gzip the output: gzip /tmp/JavaDexByteCode.dex diff --git a/JuceLibraryCode/modules/juce_core/native/java/app/com/roli/juce/FragmentOverlay.java b/JuceLibraryCode/modules/juce_core/native/java/app/com/rmsl/juce/FragmentOverlay.java similarity index 64% rename from JuceLibraryCode/modules/juce_core/native/java/app/com/roli/juce/FragmentOverlay.java rename to JuceLibraryCode/modules/juce_core/native/java/app/com/rmsl/juce/FragmentOverlay.java index 0e96761..e81b8c0 100644 --- a/JuceLibraryCode/modules/juce_core/native/java/app/com/roli/juce/FragmentOverlay.java +++ b/JuceLibraryCode/modules/juce_core/native/java/app/com/rmsl/juce/FragmentOverlay.java @@ -1,4 +1,26 @@ -package com.roli.juce; +/* + ============================================================================== + + 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. + + ============================================================================== +*/ + +package com.rmsl.juce; import android.app.DialogFragment; import android.content.Intent; diff --git a/JuceLibraryCode/modules/juce_core/native/java/app/com/roli/juce/JuceHTTPStream.java b/JuceLibraryCode/modules/juce_core/native/java/app/com/rmsl/juce/JuceHTTPStream.java similarity index 93% rename from JuceLibraryCode/modules/juce_core/native/java/app/com/roli/juce/JuceHTTPStream.java rename to JuceLibraryCode/modules/juce_core/native/java/app/com/rmsl/juce/JuceHTTPStream.java index 737ded4..cbce00f 100644 --- a/JuceLibraryCode/modules/juce_core/native/java/app/com/roli/juce/JuceHTTPStream.java +++ b/JuceLibraryCode/modules/juce_core/native/java/app/com/rmsl/juce/JuceHTTPStream.java @@ -1,4 +1,26 @@ -package com.roli.juce; +/* + ============================================================================== + + 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. + + ============================================================================== +*/ + +package com.rmsl.juce; import java.lang.Runnable; import java.io.*; diff --git a/JuceLibraryCode/modules/juce_core/native/java/app/com/rmsl/juce/JuceInvocationHandler.java b/JuceLibraryCode/modules/juce_core/native/java/app/com/rmsl/juce/JuceInvocationHandler.java new file mode 100644 index 0000000..5b52362 --- /dev/null +++ b/JuceLibraryCode/modules/juce_core/native/java/app/com/rmsl/juce/JuceInvocationHandler.java @@ -0,0 +1,60 @@ +/* + ============================================================================== + + 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. + + ============================================================================== +*/ + +package com.rmsl.juce; + +import java.lang.reflect.*; + +public class JuceInvocationHandler implements InvocationHandler +{ + public JuceInvocationHandler (long nativeContextRef) + { + nativeContext = nativeContextRef; + } + + public void clear() + { + nativeContext = 0; + } + + @Override + public void finalize() + { + if (nativeContext != 0) + dispatchFinalize (nativeContext); + } + + @Override + public Object invoke (Object proxy, Method method, Object[] args) throws Throwable + { + if (nativeContext != 0) + return dispatchInvoke (nativeContext, proxy, method, args); + + return null; + } + + //============================================================================== + private long nativeContext = 0; + + private native void dispatchFinalize (long nativeContextRef); + private native Object dispatchInvoke (long nativeContextRef, Object proxy, Method method, Object[] args); +} diff --git a/JuceLibraryCode/modules/juce_core/native/javacore/app/com/rmsl/juce/JuceApp.java b/JuceLibraryCode/modules/juce_core/native/javacore/app/com/rmsl/juce/JuceApp.java new file mode 100644 index 0000000..8d111f0 --- /dev/null +++ b/JuceLibraryCode/modules/juce_core/native/javacore/app/com/rmsl/juce/JuceApp.java @@ -0,0 +1,37 @@ +/* + ============================================================================== + + 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. + + ============================================================================== +*/ + +package com.rmsl.juce; + +import com.rmsl.juce.Java; + +import android.app.Application; + +public class JuceApp extends Application +{ + @Override + public void onCreate() + { + super.onCreate(); + Java.initialiseJUCE (this); + } +} diff --git a/JuceLibraryCode/modules/juce_core/native/javacore/app/com/roli/juce/JuceApp.java b/JuceLibraryCode/modules/juce_core/native/javacore/app/com/roli/juce/JuceApp.java deleted file mode 100644 index a8491e1..0000000 --- a/JuceLibraryCode/modules/juce_core/native/javacore/app/com/roli/juce/JuceApp.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.roli.juce; - -import com.roli.juce.Java; - -import android.app.Application; - -public class JuceApp extends Application -{ - @Override - public void onCreate () - { - super.onCreate (); - Java.initialiseJUCE (this); - } -} diff --git a/JuceLibraryCode/modules/juce_core/native/javacore/init/com/rmsl/juce/Java.java b/JuceLibraryCode/modules/juce_core/native/javacore/init/com/rmsl/juce/Java.java new file mode 100644 index 0000000..2056e42 --- /dev/null +++ b/JuceLibraryCode/modules/juce_core/native/javacore/init/com/rmsl/juce/Java.java @@ -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. + + ============================================================================== +*/ + +package com.rmsl.juce; + +import android.content.Context; + +public class Java +{ + static + { + System.loadLibrary ("juce_jni"); + } + + public native static void initialiseJUCE (Context appContext); +} diff --git a/JuceLibraryCode/modules/juce_core/native/javacore/init/com/roli/juce/Java.java b/JuceLibraryCode/modules/juce_core/native/javacore/init/com/roli/juce/Java.java deleted file mode 100644 index dc79044..0000000 --- a/JuceLibraryCode/modules/juce_core/native/javacore/init/com/roli/juce/Java.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.roli.juce; - -import android.content.Context; - -public class Java -{ - static - { - System.loadLibrary ("juce_jni"); - } - - public native static void initialiseJUCE (Context appContext); -} diff --git a/JuceLibraryCode/modules/juce_core/native/juce_BasicNativeHeaders.h b/JuceLibraryCode/modules/juce_core/native/juce_BasicNativeHeaders.h index 7b25fd2..b919d10 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_BasicNativeHeaders.h +++ b/JuceLibraryCode/modules/juce_core/native/juce_BasicNativeHeaders.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. @@ -28,12 +28,20 @@ #if JUCE_MAC || JUCE_IOS #if JUCE_IOS + #if JUCE_MODULE_AVAILABLE_juce_opengl && defined (__IPHONE_12_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_12_0 + #define GLES_SILENCE_DEPRECATION 1 + #endif + #import #import #import #import #include #else + #if JUCE_MODULE_AVAILABLE_juce_opengl && defined (MAC_OS_X_VERSION_10_14) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 + #define GL_SILENCE_DEPRECATION 1 + #endif + #import #if (! defined MAC_OS_X_VERSION_10_12) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12 #define NSEventModifierFlagCommand NSCommandKeyMask @@ -74,6 +82,12 @@ #define NSAlertStyleInformational NSInformationalAlertStyle #define NSEventTypeTabletPoint NSTabletPoint #define NSEventTypeTabletProximity NSTabletProximity + #define NSEventTypeFlagsChanged NSFlagsChanged + #define NSEventTypeAppKitDefined NSAppKitDefined + #define NSEventTypeSystemDefined NSSystemDefined + #define NSEventTypeApplicationDefined NSApplicationDefined + #define NSEventTypePeriodic NSPeriodic + #define NSEventTypeSmartMagnify NSEventTypeSmartMagnify #endif #import #include @@ -96,6 +110,7 @@ #include #include #include + #include //============================================================================== #elif JUCE_WINDOWS @@ -167,7 +182,7 @@ #pragma warning (4: 4511 4512 4100) #endif - #if JUCE_MSVC && ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES + #if ! JUCE_MINGW && ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES #pragma comment (lib, "kernel32.lib") #pragma comment (lib, "user32.lib") #pragma comment (lib, "wininet.lib") @@ -233,6 +248,7 @@ #include #include #include + #include //============================================================================== #elif JUCE_BSD @@ -261,6 +277,7 @@ #include #include #include + #include //============================================================================== #elif JUCE_ANDROID @@ -282,6 +299,7 @@ #include #include #include + #include // If you are getting include errors here, then you to re-build the Projucer // and re-save your .jucer file. diff --git a/JuceLibraryCode/modules/juce_core/native/juce_android_Files.cpp b/JuceLibraryCode/modules/juce_core/native/juce_android_Files.cpp index 3f9efff..ac83419 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_android_Files.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_android_Files.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. @@ -89,7 +89,7 @@ static File getWellKnownFolder (const char* folderId) auto* env = getEnv(); auto fieldId = env->GetStaticFieldID (AndroidEnvironment, folderId, "Ljava/lang/String;"); - if (fieldId == 0) + if (fieldId == nullptr) { // unknown field in environment jassertfalse; @@ -194,7 +194,7 @@ struct AndroidContentUriResolver auto* env = getEnv(); LocalRef contentResolver (env->CallObjectMethod (getAppContext().get(), AndroidContext.getContentResolver)); - if (contentResolver == 0) + if (contentResolver == nullptr) return {}; auto filename = getStringUsingDataColumn ("_display_name", env, uri, contentResolver); @@ -298,7 +298,7 @@ struct AndroidContentUriResolver auto* env = getEnv(); static jmethodID m = (env->GetMethodID (AndroidContext, "getExternalFilesDirs", "(Ljava/lang/String;)[Ljava/io/File;")); - if (m == 0) + if (m == nullptr) return {}; auto paths = convertFileArray (LocalRef (env->CallObjectMethod (getAppContext().get(), m, nullptr))); @@ -319,9 +319,8 @@ struct AndroidContentUriResolver return {}; auto rootFsDevice = info.st_dev; - DirectoryIterator iter (mountFolder, false, "*", File::findDirectories); - while (iter.next()) + for (const auto& iter : RangedDirectoryIterator (mountFolder, false, "*", File::findDirectories)) { auto candidate = iter.getFile(); @@ -406,7 +405,7 @@ struct AndroidContentUriResolver return {}; } - if (cursor == 0) + if (cursor == nullptr) return {}; String fileName; @@ -439,7 +438,7 @@ struct AndroidContentUriOutputStream : public OutputStream { } - ~AndroidContentUriOutputStream() + ~AndroidContentUriOutputStream() override { stream.callVoidMethod (AndroidOutputStream.close); } @@ -484,7 +483,7 @@ OutputStream* juce_CreateContentURIOutputStream (const URL& url) { auto stream = AndroidContentUriResolver::getStreamForContentUri (url, false); - return (stream.get() != 0 ? new AndroidContentUriOutputStream (std::move (stream)) : nullptr); + return (stream.get() != nullptr ? new AndroidContentUriOutputStream (std::move (stream)) : nullptr); } //============================================================================== @@ -676,7 +675,7 @@ class SingleMediaScanner : public MediaScannerConnectionClient void FileOutputStream::flushInternal() { - if (fileHandle != 0) + if (fileHandle != nullptr) { if (fsync (getFD (fileHandle)) == -1) status = getResultForErrno(); diff --git a/JuceLibraryCode/modules/juce_core/native/juce_android_JNIHelpers.cpp b/JuceLibraryCode/modules/juce_core/native/juce_android_JNIHelpers.cpp index 31aec1d..8466872 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_android_JNIHelpers.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_android_JNIHelpers.cpp @@ -1,51 +1,52 @@ /* - ============================================================================== + ============================================================================== - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. + 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. + 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. + 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. + 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 { //============================================================================== -static const uint8 invocationHandleByteCode[] = { -31,139,8,8,170,94,229,91,0,3,105,110,118,111,99,97,116,105,111,110,95,104,97,110,100,108,101,114,46,100,101,120,0,109, -148,75,107,19,81,20,199,207,189,119,38,169,181,109,98,218,138,72,23,81,20,68,193,169,218,130,144,42,130,162,53,140,15, -104,200,66,187,232,52,185,181,147,78,103,98,58,141,33,184,168,197,47,224,66,168,187,186,241,83,168,184,16,247,162,31,193, -69,151,174,220,40,234,255,62,154,4,237,192,239,62,206,57,115,30,115,239,153,186,236,12,79,95,154,165,159,187,91,95,227, -217,197,247,87,42,31,231,191,156,157,58,241,253,199,220,201,79,75,175,118,58,14,81,147,136,58,213,153,2,217,231,131,32, -154,32,35,63,164,246,0,102,244,13,48,48,129,33,139,121,138,153,125,5,131,131,119,82,204,203,156,168,1,214,65,10,186,224, -53,120,7,62,131,61,144,131,237,57,112,30,92,4,183,192,93,176,4,154,160,11,182,193,11,97,252,171,216,46,200,144,137,59, -100,243,26,6,35,0,46,9,166,116,131,155,89,113,159,27,125,214,214,116,216,174,23,185,241,89,208,181,8,173,99,240,48,106, -247,99,182,198,156,149,231,245,204,232,136,246,203,173,189,65,189,61,7,209,31,60,167,48,239,26,119,90,183,35,84,190,66, -175,201,230,218,204,43,201,81,172,30,76,131,25,66,180,190,133,169,81,107,139,164,243,112,123,25,154,253,194,53,232,17, -231,2,74,190,140,106,212,190,57,205,201,97,99,168,207,209,223,71,61,147,202,182,57,104,59,74,11,45,212,255,56,251,60,251, -50,251,166,157,81,81,71,80,83,129,206,252,238,133,239,101,162,242,72,237,217,186,246,251,171,106,51,248,242,162,183,218, -183,207,204,133,113,152,94,37,86,38,215,47,251,190,79,142,175,198,211,126,45,89,247,90,73,20,122,141,205,154,244,202,24, -110,199,237,164,22,164,97,18,207,7,113,61,146,173,18,29,247,235,65,212,14,215,188,32,142,147,84,235,188,202,106,43,121, -178,81,162,130,223,8,218,129,23,5,241,35,239,222,114,67,214,210,18,77,14,200,180,93,176,28,201,18,162,245,197,45,185,18, -193,214,59,48,218,255,102,119,100,186,154,212,75,196,170,196,171,101,26,127,120,64,84,183,22,201,160,69,249,122,184,209, -12,210,218,234,205,48,14,162,176,43,105,108,95,162,130,173,73,26,90,217,215,100,66,35,25,141,145,66,91,94,79,226,84,118, -82,114,219,65,180,41,137,115,54,62,197,142,57,196,132,186,86,207,182,156,95,156,111,115,98,10,182,43,4,123,43,24,219,19, -185,127,206,70,247,159,237,77,62,208,159,98,160,71,157,129,62,117,169,223,171,25,234,247,171,200,155,181,62,231,162,121, -231,169,178,41,26,185,186,207,44,111,228,234,142,243,162,137,171,250,219,41,246,239,56,217,181,190,251,214,167,250,127, -252,5,76,239,47,69,120,4,0,0}; +static const uint8 invocationHandleByteCode[] = +{31,139,8,8,215,115,161,94,0,3,105,110,118,111,99,97,116,105,111,110,72,97,110,100,108,101,66,121,116,101,67,111,100,101,46, +100,101,120,0,109,148,65,107,19,65,20,199,223,236,78,146,90,211,116,77,141,214,88,33,151,130,7,117,91,172,80,73,17,161,32,53,93, +17,108,233,65,5,217,38,155,102,219,237,110,220,108,99,172,8,173,40,42,244,36,245,226,65,232,165,138,7,15,226,65,193,147,120,244, +166,130,95,192,155,23,189,21,68,252,207,206,180,137,218,133,223,204,155,247,222,206,123,111,119,230,85,156,86,247,208,201, +83,84,121,127,155,63,122,245,209,24,205,141,63,156,124,186,176,229,110,12,151,158,157,126,219,76,39,136,234,68,212,154,25,201, +146,122,38,56,81,158,164,126,15,248,10,160,162,95,128,129,99,24,82,152,71,152,92,123,24,86,116,162,53,204,203,26,209,29,112, +15,108,128,231,224,37,248,2,126,128,4,252,6,192,56,184,6,102,65,21,220,2,171,224,1,120,2,94,128,215,224,29,248,0,62,129,111,224, +59,248,169,203,184,72,157,146,36,115,233,82,185,118,131,189,160,7,232,138,171,154,204,95,200,53,77,218,83,170,214,180,146, +35,77,238,153,139,107,212,99,27,35,141,122,213,218,80,181,239,83,250,108,60,51,234,139,247,213,148,191,68,188,61,13,149,208,142, +97,24,228,180,99,63,194,69,206,122,44,111,233,50,223,186,33,52,7,32,93,30,2,35,68,25,229,1,95,46,235,140,173,5,97,17,107,153, +97,154,203,245,212,89,216,17,103,24,33,71,81,141,88,215,135,52,226,44,131,90,121,252,141,250,184,172,109,170,222,233,219,67,83, +33,234,191,158,186,155,122,156,218,108,38,69,212,52,106,204,210,209,223,180,243,48,53,139,60,214,88,251,219,203,178,116,236, +223,165,190,117,50,254,15,42,243,49,215,119,163,51,196,74,148,47,45,149,157,243,126,51,40,219,145,27,248,19,182,95,241,156,240, +196,188,221,180,41,97,149,44,203,34,110,137,113,208,42,7,139,102,184,216,240,204,121,188,98,238,250,94,145,242,86,197,246,154, +238,130,105,251,126,16,197,54,115,186,22,6,55,26,69,202,90,98,91,211,179,253,57,243,226,236,188,83,142,138,148,235,208,197,126, +246,172,231,20,17,173,173,14,157,170,7,95,115,215,104,255,187,93,112,162,90,80,41,18,155,33,109,166,68,125,87,118,137,202,237, +112,174,65,137,178,231,216,33,25,21,183,81,183,163,114,237,156,235,219,158,187,236,80,102,91,35,66,46,56,212,85,221,182,36,93, +169,73,46,198,81,168,199,71,66,77,103,60,240,35,167,21,145,241,215,242,146,83,165,68,61,12,90,55,137,71,53,23,1,155,182,183, +132,237,216,193,84,70,203,23,181,185,210,113,156,146,84,102,146,246,99,188,127,153,14,235,253,185,94,72,155,164,105,236,208,0, +235,231,196,116,113,134,87,87,248,186,174,225,246,50,1,123,163,235,236,179,206,216,138,248,207,198,63,103,65,204,219,61,66,235, +232,19,122,71,175,224,29,253,34,65,237,158,145,164,118,223,208,13,41,199,231,170,32,223,89,23,62,5,169,23,247,135,25,82,31,223, +169,130,140,43,250,140,174,252,197,61,226,133,246,253,34,37,15,170,196,133,44,122,218,31,165,24,139,249,12,5,0,0,0,0}; //============================================================================== #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ @@ -61,26 +62,26 @@ static const uint8 invocationHandleByteCode[] = { CALLBACK (juce_invokeImplementer, "dispatchInvoke", "(JLjava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;") \ CALLBACK (juce_dispatchDelete, "dispatchFinalize", "(J)V") - DECLARE_JNI_CLASS_WITH_BYTECODE (JuceInvocationHandler, "com/roli/juce/JuceInvocationHandler", 10, invocationHandleByteCode, sizeof (invocationHandleByteCode)) + DECLARE_JNI_CLASS_WITH_BYTECODE (JuceInvocationHandler, "com/rmsl/juce/JuceInvocationHandler", 10, invocationHandleByteCode, sizeof (invocationHandleByteCode)) #undef JNI_CLASS_MEMBERS #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ METHOD (findClass, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;") \ STATICMETHOD (getSystemClassLoader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;") -DECLARE_JNI_CLASS (JavaClassLoader, "java/lang/ClassLoader") + DECLARE_JNI_CLASS (JavaClassLoader, "java/lang/ClassLoader") #undef JNI_CLASS_MEMBERS #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ METHOD (constructor, "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V") -DECLARE_JNI_CLASS (AndroidDexClassLoader, "dalvik/system/DexClassLoader") + DECLARE_JNI_CLASS (AndroidDexClassLoader, "dalvik/system/DexClassLoader") #undef JNI_CLASS_MEMBERS #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ METHOD (constructor, "", "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V") -DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidInMemoryDexClassLoader, "dalvik/system/InMemoryDexClassLoader", 26) + DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidInMemoryDexClassLoader, "dalvik/system/InMemoryDexClassLoader", 26) #undef JNI_CLASS_MEMBERS //============================================================================== @@ -116,7 +117,7 @@ struct SystemJavaClassComparator //============================================================================== JNIClassBase::JNIClassBase (const char* cp, int classMinSDK, const void* bc, size_t n) - : classPath (cp), byteCode (bc), byteCodeSize (n), minSDK (classMinSDK), classRef (0) + : classPath (cp), byteCode (bc), byteCodeSize (n), minSDK (classMinSDK), classRef (nullptr) { SystemJavaClassComparator comparator; @@ -162,13 +163,13 @@ void JNIClassBase::initialise (JNIEnv* env) LocalRef defaultClassLoader (env->CallStaticObjectMethod (JavaClassLoader, JavaClassLoader.getSystemClassLoader)); tryLoadingClassWithClassLoader (env, defaultClassLoader.get()); - if (classRef == 0) + if (classRef == nullptr) { for (auto& byteCodeLoader : byteCodeLoaders) { tryLoadingClassWithClassLoader (env, byteCodeLoader.get()); - if (classRef != 0) + if (classRef != nullptr) break; } @@ -234,10 +235,10 @@ void JNIClassBase::initialise (JNIEnv* env) } } - if (classRef == 0) + if (classRef == nullptr) classRef = (jclass) env->NewGlobalRef (LocalRef (env->FindClass (classPath))); - jassert (classRef != 0); + jassert (classRef != nullptr); initialiseFields (env); } } @@ -253,7 +254,7 @@ void JNIClassBase::tryLoadingClassWithClassLoader (JNIEnv* env, jobject classLoa if (jthrowable exception = env->ExceptionOccurred ()) { env->ExceptionClear(); - classObj = 0; + classObj = nullptr; } // later versions of Android don't throw at all, so re-check the object @@ -263,7 +264,7 @@ void JNIClassBase::tryLoadingClassWithClassLoader (JNIEnv* env, jobject classLoa void JNIClassBase::release (JNIEnv* env) { - if (classRef != 0) + if (classRef != nullptr) env->DeleteGlobalRef (classRef); } @@ -284,28 +285,28 @@ void JNIClassBase::releaseAllClasses (JNIEnv* env) jmethodID JNIClassBase::resolveMethod (JNIEnv* env, const char* methodName, const char* params) { jmethodID m = env->GetMethodID (classRef, methodName, params); - jassert (m != 0); + jassert (m != nullptr); return m; } jmethodID JNIClassBase::resolveStaticMethod (JNIEnv* env, const char* methodName, const char* params) { jmethodID m = env->GetStaticMethodID (classRef, methodName, params); - jassert (m != 0); + jassert (m != nullptr); return m; } jfieldID JNIClassBase::resolveField (JNIEnv* env, const char* fieldName, const char* signature) { jfieldID f = env->GetFieldID (classRef, fieldName, signature); - jassert (f != 0); + jassert (f != nullptr); return f; } jfieldID JNIClassBase::resolveStaticField (JNIEnv* env, const char* fieldName, const char* signature) { jfieldID f = env->GetStaticFieldID (classRef, fieldName, signature); - jassert (f != 0); + jassert (f != nullptr); return f; } @@ -418,13 +419,27 @@ jobject ActivityLifecycleCallbacks::invoke (jobject proxy, jobject method, jobje auto activity = env->GetArrayLength (args) > 0 ? env->GetObjectArrayElement (args, 0) : (jobject) nullptr; auto bundle = env->GetArrayLength (args) > 1 ? env->GetObjectArrayElement (args, 1) : (jobject) nullptr; - if (methodName == "onActivityCreated") { onActivityCreated (activity, bundle); return nullptr; } - else if (methodName == "onActivityDestroyed") { onActivityDestroyed (activity); return nullptr; } - else if (methodName == "onActivityPaused") { onActivityPaused (activity); return nullptr; } - else if (methodName == "onActivityResumed") { onActivityResumed (activity); return nullptr; } - else if (methodName == "onActivitySaveInstanceState") { onActivitySaveInstanceState (activity, bundle); return nullptr; } - else if (methodName == "onActivityStarted") { onActivityStarted (activity); return nullptr; } - else if (methodName == "onActivityStopped") { onActivityStopped (activity); return nullptr; } + if (methodName == "onActivityPreCreated") { onActivityPreCreated (activity, bundle); return nullptr; } + else if (methodName == "onActivityPreDestroyed") { onActivityPreDestroyed (activity); return nullptr; } + else if (methodName == "onActivityPrePaused") { onActivityPrePaused (activity); return nullptr; } + else if (methodName == "onActivityPreResumed") { onActivityPreResumed (activity); return nullptr; } + else if (methodName == "onActivityPreSaveInstanceState") { onActivityPreSaveInstanceState (activity, bundle); return nullptr; } + else if (methodName == "onActivityPreStarted") { onActivityPreStarted (activity); return nullptr; } + else if (methodName == "onActivityPreStopped") { onActivityPreStopped (activity); return nullptr; } + else if (methodName == "onActivityCreated") { onActivityCreated (activity, bundle); return nullptr; } + else if (methodName == "onActivityDestroyed") { onActivityDestroyed (activity); return nullptr; } + else if (methodName == "onActivityPaused") { onActivityPaused (activity); return nullptr; } + else if (methodName == "onActivityResumed") { onActivityResumed (activity); return nullptr; } + else if (methodName == "onActivitySaveInstanceState") { onActivitySaveInstanceState (activity, bundle); return nullptr; } + else if (methodName == "onActivityStarted") { onActivityStarted (activity); return nullptr; } + else if (methodName == "onActivityStopped") { onActivityStopped (activity); return nullptr; } + else if (methodName == "onActivityPostCreated") { onActivityPostCreated (activity, bundle); return nullptr; } + else if (methodName == "onActivityPostDestroyed") { onActivityPostDestroyed (activity); return nullptr; } + else if (methodName == "onActivityPostPaused") { onActivityPostPaused (activity); return nullptr; } + else if (methodName == "onActivityPostResumed") { onActivityPostResumed (activity); return nullptr; } + else if (methodName == "onActivityPostSaveInstanceState") { onActivityPostSaveInstanceState (activity, bundle); return nullptr; } + else if (methodName == "onActivityPostStarted") { onActivityPostStarted (activity); return nullptr; } + else if (methodName == "onActivityPostStopped") { onActivityPostStopped (activity); return nullptr; } return AndroidInterfaceImplementer::invoke (proxy, method, args); } @@ -440,10 +455,10 @@ int getAndroidSDKVersion() auto* env = getEnv(); auto buildVersion = env->FindClass ("android/os/Build$VERSION"); - jassert (buildVersion != 0); + jassert (buildVersion != nullptr); auto sdkVersionField = env->GetStaticFieldID (buildVersion, "SDK_INT", "I"); - jassert (sdkVersionField != 0); + jassert (sdkVersionField != nullptr); return env->GetStaticIntField (buildVersion, sdkVersionField); }(); @@ -476,39 +491,38 @@ bool isPermissionDeclaredInManifest (const String& requestedPermission) } //============================================================================== -// This byte-code is generated from native/java/com/roli/juce/FragmentOverlay.java with min sdk version 16 +// This byte-code is generated from native/java/com/rmsl/juce/FragmentOverlay.java with min sdk version 16 // See juce_core/native/java/README.txt on how to generate this byte-code. static const uint8 javaFragmentOverlay[] = -{31,139,8,8,197,105,229,91,0,3,70,114,97,103,109,101,110,116,79,118,101,114,108,97,121,46,100,101,120,0,133,149,93,136, -28,69,16,199,171,231,243,62,39,235,93,60,206,243,244,214,136,73,4,201,156,104,32,186,107,184,36,34,236,58,248,145,11,251, -112,241,101,216,29,215,137,123,51,155,153,217,35,1,65,61,2,201,131,8,10,126,97,2,17,84,16,204,91,30,228,240,73,130,95,40, -104,124,9,137,47,9,248,230,23,8,65,52,130,255,234,238,201,133,35,226,178,191,169,234,234,238,170,234,154,158,238,78,116, -100,100,254,129,157,116,170,242,197,47,171,219,126,253,250,218,79,107,167,30,234,189,251,229,123,127,239,158,219,187,86, -124,127,193,33,234,19,209,145,214,131,19,164,127,187,96,187,151,148,125,4,108,22,74,214,33,241,167,179,120,84,32,63,213, -237,186,65,244,130,69,244,12,228,121,147,232,34,248,29,252,1,174,130,191,192,63,224,118,140,217,9,154,224,121,240,34,88, -5,39,192,171,224,117,240,14,56,13,62,0,31,129,51,224,51,240,21,56,15,46,128,203,224,55,240,39,112,108,162,105,48,15,30,6, -77,240,44,56,1,94,3,167,193,25,176,6,62,7,223,2,164,73,72,135,176,76,114,193,16,24,214,107,29,5,147,188,102,0,247,114, -125,199,48,216,214,109,210,99,92,173,143,105,253,21,140,25,215,250,219,208,61,173,191,15,125,147,214,63,54,85,221,88,255, -4,250,45,90,63,7,125,66,235,223,200,88,130,166,136,243,52,100,12,3,217,221,169,219,91,116,30,51,196,227,84,63,203,91,181, -156,38,53,255,54,41,77,154,149,210,161,59,164,84,126,108,172,120,78,74,139,170,82,186,116,151,158,191,69,74,155,238,38, -181,102,65,164,163,40,157,127,67,142,146,38,44,108,251,193,86,53,236,87,120,44,103,190,84,229,10,148,253,151,116,127,217, -147,84,28,140,243,80,71,75,190,131,43,182,90,255,34,54,220,20,130,221,15,55,187,208,187,152,161,38,135,197,49,241,134, -251,225,138,51,12,95,30,241,76,94,255,207,152,195,107,74,171,130,14,192,163,11,235,24,205,136,41,74,170,38,170,60,74,75, -11,240,184,112,163,71,87,182,251,11,136,251,180,39,223,163,138,127,245,127,226,187,50,254,184,140,207,181,229,189,195,19, -249,253,165,21,206,231,166,113,230,55,145,37,60,93,55,71,239,57,210,82,233,195,178,46,66,83,238,55,238,45,117,30,97,72, -221,210,99,156,122,156,196,197,110,218,252,88,22,118,151,163,164,120,114,37,202,122,225,209,29,135,194,149,144,68,131,68, -147,140,102,64,34,160,217,32,76,58,89,26,119,252,176,223,247,31,141,195,94,218,45,103,213,104,250,122,111,59,77,10,152, -252,134,20,53,154,188,222,147,230,254,222,65,210,233,69,53,154,11,218,233,178,159,165,189,216,63,52,104,71,254,134,240, -53,154,8,56,3,191,23,38,93,127,177,200,226,164,91,35,209,34,171,213,104,4,252,12,2,50,90,77,178,91,77,54,176,128,197,108, -53,217,12,14,54,104,242,224,77,92,216,237,94,154,71,228,182,251,253,3,207,197,57,89,157,176,8,201,237,196,249,114,156, -231,52,214,141,138,61,89,119,192,169,228,228,162,21,164,73,23,230,44,76,138,253,81,62,232,193,92,73,147,61,237,34,94,137, -139,163,202,68,83,27,45,79,132,104,69,52,148,38,251,178,40,44,34,242,74,77,247,204,164,201,254,232,240,32,202,139,167, -162,140,67,199,105,146,107,111,213,255,238,211,179,221,52,89,44,194,172,160,113,173,104,251,104,127,125,2,141,102,202, -201,190,180,19,209,72,38,231,75,221,206,11,78,201,42,184,0,46,185,158,113,95,141,118,64,62,94,167,237,230,214,109,211, -174,119,252,77,26,19,219,93,175,126,238,248,18,85,205,173,247,204,194,246,22,190,57,215,123,4,22,18,54,62,111,235,229, -151,172,31,45,123,21,39,201,13,216,226,154,101,138,147,182,33,190,3,39,29,72,103,124,195,55,207,178,188,19,120,63,150, -247,130,73,235,119,67,185,103,249,126,224,179,163,188,35,28,90,191,39,68,85,181,249,174,16,21,117,46,240,249,106,84,149, -127,190,63,76,61,134,207,21,62,160,68,121,230,84,148,206,247,211,191,48,134,254,198,216,6,0,0}; +{31,139,8,8,26,116,161,94,0,3,106,97,118,97,70,114,97,103,109,101,110,116,79,118,101,114,108,97,121,46,100,101,120,0,133,149, +77,136,28,69,20,199,255,53,253,181,159,179,147,221,184,140,235,198,140,43,70,197,224,172,104,36,56,99,216,152,32,204,100,226,71, +54,204,97,227,165,153,105,39,189,206,118,79,186,123,150,4,20,53,4,146,131,8,6,252,130,28,114,80,65,48,8,226,65,196,83,8,66,64, +65,146,75,252,184,152,179,160,160,4,17,5,255,175,187,58,27,150,136,195,252,250,189,122,245,234,189,170,215,213,85,93,239,248, +216,226,163,187,96,79,85,156,198,103,91,86,175,30,189,252,253,193,79,203,15,189,242,199,245,246,129,179,245,238,53,27,24,0,56, +222,126,108,26,250,183,155,182,7,145,217,199,200,86,149,201,58,37,255,248,156,143,18,229,87,186,93,47,0,47,155,192,11,148,87, +12,224,7,242,27,249,157,220,32,127,145,127,200,93,244,217,69,154,228,37,242,42,57,73,206,144,55,201,89,242,62,57,79,62,36,31, +147,11,228,34,185,76,174,144,107,228,103,242,43,249,147,216,22,80,38,139,228,9,210,36,47,146,51,228,45,114,158,92,32,95,146,175, +201,183,132,211,4,167,3,46,19,14,25,33,163,122,173,227,100,70,214,76,24,62,93,223,41,58,91,186,13,237,227,104,125,66,235,111, +208,103,82,235,239,81,47,106,253,3,234,83,90,255,196,200,234,38,250,23,212,183,104,253,18,245,105,173,127,147,230,82,152,133, +204,179,144,230,40,112,118,119,235,246,130,158,199,28,196,47,235,23,121,135,150,101,100,227,239,76,165,129,249,84,218,216,150, +202,44,142,197,21,111,79,165,137,74,42,29,220,163,199,47,164,210,194,189,200,214,172,0,157,37,211,229,55,98,103,210,160,69,108, +87,173,172,134,131,146,248,202,204,87,42,82,129,188,255,71,221,159,247,4,37,155,126,69,214,209,76,223,193,117,43,91,255,50,55, +220,44,147,61,194,48,187,217,187,28,177,38,199,212,41,245,182,243,209,186,61,202,88,69,200,72,89,255,47,28,35,107,10,43,10,135, +25,209,161,117,2,115,106,22,65,197,96,149,199,177,178,196,136,75,183,70,116,210,246,96,137,121,159,47,166,239,49,203,127,227, +127,242,59,105,254,201,52,191,212,86,246,142,12,148,247,23,150,100,62,183,205,179,56,5,83,21,117,221,108,189,231,160,101,166, +143,166,117,81,154,124,191,73,111,174,139,71,33,213,77,237,99,215,253,192,79,246,96,235,211,145,219,91,243,130,228,217,117,47, +234,187,39,30,94,117,215,93,168,6,84,19,133,102,11,170,133,249,150,27,116,163,208,239,86,221,193,160,186,223,119,251,97,47,31, +85,67,249,102,111,39,12,18,154,170,141,84,212,48,115,179,39,140,171,79,13,131,110,223,171,97,123,171,19,174,85,163,181,184,95, +93,29,118,188,234,166,244,53,76,183,100,6,213,190,27,244,170,203,73,228,7,189,26,84,27,102,187,209,104,201,179,213,66,161,221, +132,213,110,138,65,4,45,70,187,41,102,114,164,129,153,35,183,9,97,117,250,97,236,193,233,12,6,135,143,250,49,204,174,155,184, +112,186,126,188,230,199,49,38,122,94,178,55,234,13,101,42,49,28,182,90,97,208,163,57,114,131,228,144,23,15,251,52,151,194,96, +111,39,241,215,253,228,68,102,194,236,102,203,51,46,91,30,70,194,96,95,228,185,137,135,98,174,233,158,185,48,56,228,29,27,122, +113,242,156,23,73,106,63,12,98,29,173,242,223,125,122,180,19,6,203,137,27,37,152,212,138,182,143,15,54,6,96,60,202,130,236,11, +187,30,198,162,116,124,170,91,113,34,83,50,19,41,192,54,56,197,194,206,26,246,83,30,168,99,143,177,227,254,178,83,60,253,14,22, +212,3,78,177,126,233,244,10,30,55,118,220,55,79,219,187,216,73,167,39,105,129,178,248,121,155,175,191,102,254,100,90,39,121, +146,220,130,165,254,54,13,117,206,42,168,239,200,57,155,210,158,220,244,205,139,204,239,4,217,143,249,189,96,96,227,110,200,247, +172,220,15,114,118,228,119,132,141,141,123,66,85,178,182,220,21,170,148,157,11,114,190,22,42,89,124,185,63,12,237,35,231,138, +28,80,42,63,115,74,153,46,247,211,191,81,33,150,205,216,6,0,0,0,0}; //============================================================================== #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ @@ -519,7 +533,7 @@ static const uint8 javaFragmentOverlay[] = CALLBACK (FragmentOverlay::onStartNative, "onStartNative", "(J)V") \ CALLBACK (FragmentOverlay::onRequestPermissionsResultNative, "onRequestPermissionsResultNative", "(JI[Ljava/lang/String;[I)V") - DECLARE_JNI_CLASS_WITH_BYTECODE (JuceFragmentOverlay, "com/roli/juce/FragmentOverlay", 16, javaFragmentOverlay, sizeof(javaFragmentOverlay)) + DECLARE_JNI_CLASS_WITH_BYTECODE (JuceFragmentOverlay, "com/rmsl/juce/FragmentOverlay", 16, javaFragmentOverlay, sizeof(javaFragmentOverlay)) #undef JNI_CLASS_MEMBERS #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ @@ -581,7 +595,7 @@ void FragmentOverlay::onRequestPermissionsResultNative (JNIEnv* env, jobject, jl if (n > 0) { - auto* data = env->GetIntArrayElements (jGrantResults, 0); + auto* data = env->GetIntArrayElements (jGrantResults, nullptr); for (int i = 0; i < n; ++i) grantResults.add (data[i]); diff --git a/JuceLibraryCode/modules/juce_core/native/juce_android_JNIHelpers.h b/JuceLibraryCode/modules/juce_core/native/juce_android_JNIHelpers.h index 5860afe..3b2f14b 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_android_JNIHelpers.h +++ b/JuceLibraryCode/modules/juce_core/native/juce_android_JNIHelpers.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. @@ -31,18 +31,18 @@ template class LocalRef { public: - explicit inline LocalRef() noexcept : obj (0) {} + explicit inline LocalRef() noexcept : obj (nullptr) {} explicit inline LocalRef (JavaType o) noexcept : obj (o) {} inline LocalRef (const LocalRef& other) noexcept : obj (retain (other.obj)) {} - inline LocalRef (LocalRef&& other) noexcept : obj (0) { std::swap (obj, other.obj); } + inline LocalRef (LocalRef&& other) noexcept : obj (nullptr) { std::swap (obj, other.obj); } ~LocalRef() { clear(); } void clear() { - if (obj != 0) + if (obj != nullptr) { getEnv()->DeleteLocalRef (obj); - obj = 0; + obj = nullptr; } } @@ -69,7 +69,7 @@ class LocalRef static JavaType retain (JavaType obj) { - return obj == 0 ? 0 : (JavaType) getEnv()->NewLocalRef (obj); + return obj == nullptr ? nullptr : (JavaType) getEnv()->NewLocalRef (obj); } }; @@ -77,21 +77,21 @@ class LocalRef class GlobalRef { public: - inline GlobalRef() noexcept : obj (0) {} + inline GlobalRef() noexcept : obj (nullptr) {} inline explicit GlobalRef (const LocalRef& o) : obj (retain (o.get(), getEnv())) {} inline explicit GlobalRef (const LocalRef& o, JNIEnv* env) : obj (retain (o.get(), env)) {} inline GlobalRef (const GlobalRef& other) : obj (retain (other.obj, getEnv())) {} - inline GlobalRef (GlobalRef && other) noexcept : obj (0) { std::swap (other.obj, obj); } + inline GlobalRef (GlobalRef && other) noexcept : obj (nullptr) { std::swap (other.obj, obj); } ~GlobalRef() { clear(); } - inline void clear() { if (obj != 0) clear (getEnv()); } + inline void clear() { if (obj != nullptr) clear (getEnv()); } inline void clear (JNIEnv* env) { - if (obj != 0) + if (obj != nullptr) { env->DeleteGlobalRef (obj); - obj = 0; + obj = nullptr; } } @@ -147,11 +147,11 @@ class GlobalRef private: //============================================================================== - jobject obj = 0; + jobject obj = nullptr; - static inline jobject retain (jobject obj, JNIEnv* env) + static jobject retain (jobject obj, JNIEnv* env) { - return obj == 0 ? 0 : env->NewGlobalRef (obj); + return obj == nullptr ? nullptr : env->NewGlobalRef (obj); } }; @@ -193,7 +193,7 @@ class JNIClassBase size_t byteCodeSize; int minSDK; - jclass classRef = 0; + jclass classRef = nullptr; static Array& getClasses(); void initialise (JNIEnv*); @@ -523,22 +523,23 @@ DECLARE_JNI_CLASS (AndroidUri, "android/net/Uri") #undef JNI_CLASS_MEMBERS #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ - METHOD (construct, "", "(Landroid/content/Context;)V") \ - METHOD (layout, "layout", "(IIII)V") \ - METHOD (getLeft, "getLeft", "()I") \ - METHOD (getTop, "getTop", "()I") \ - METHOD (getWidth, "getWidth", "()I") \ - METHOD (getHeight, "getHeight", "()I") \ - METHOD (getLocationOnScreen, "getLocationOnScreen", "([I)V") \ - METHOD (getParent, "getParent", "()Landroid/view/ViewParent;") \ - METHOD (bringToFront, "bringToFront", "()V") \ - METHOD (requestFocus, "requestFocus", "()Z") \ - METHOD (hasFocus, "hasFocus", "()Z") \ - METHOD (invalidate, "invalidate", "(IIII)V") \ - METHOD (setVisibility, "setVisibility", "(I)V") \ - METHOD (setLayoutParams, "setLayoutParams", "(Landroid/view/ViewGroup$LayoutParams;)V") \ - METHOD (findViewById, "findViewById", "(I)Landroid/view/View;") \ - METHOD (getRootView, "getRootView", "()Landroid/view/View;") \ + METHOD (construct, "", "(Landroid/content/Context;)V") \ + METHOD (layout, "layout", "(IIII)V") \ + METHOD (getLeft, "getLeft", "()I") \ + METHOD (getTop, "getTop", "()I") \ + METHOD (getWidth, "getWidth", "()I") \ + METHOD (getHeight, "getHeight", "()I") \ + METHOD (getLocationOnScreen, "getLocationOnScreen", "([I)V") \ + METHOD (getParent, "getParent", "()Landroid/view/ViewParent;") \ + METHOD (bringToFront, "bringToFront", "()V") \ + METHOD (requestFocus, "requestFocus", "()Z") \ + METHOD (hasFocus, "hasFocus", "()Z") \ + METHOD (invalidate, "invalidate", "(IIII)V") \ + METHOD (setVisibility, "setVisibility", "(I)V") \ + METHOD (setLayoutParams, "setLayoutParams", "(Landroid/view/ViewGroup$LayoutParams;)V") \ + METHOD (setSystemUiVisibility, "setSystemUiVisibility", "(I)V") \ + METHOD (findViewById, "findViewById", "(I)Landroid/view/View;") \ + METHOD (getRootView, "getRootView", "()Landroid/view/View;") \ METHOD (addOnLayoutChangeListener, "addOnLayoutChangeListener", "(Landroid/view/View$OnLayoutChangeListener;)V") DECLARE_JNI_CLASS (AndroidView, "android/view/View") @@ -755,7 +756,7 @@ namespace { inline String juceString (JNIEnv* env, jstring s) { - if (s == 0) + if (s == nullptr) return {}; const char* const utf8 = env->GetStringUTFChars (s, nullptr); @@ -874,13 +875,29 @@ LocalRef CreateJavaInterface (AndroidInterfaceImplementer* implementer, class ActivityLifecycleCallbacks : public AndroidInterfaceImplementer { public: - virtual void onActivityCreated (jobject /*activity*/, jobject /*bundle*/) {} - virtual void onActivityDestroyed (jobject /*activity*/) {} - virtual void onActivityPaused (jobject /*activity*/) {} - virtual void onActivityResumed (jobject /*activity*/) {} - virtual void onActivitySaveInstanceState (jobject /*activity*/, jobject /*bundle*/) {} - virtual void onActivityStarted (jobject /*activity*/) {} - virtual void onActivityStopped (jobject /*activity*/) {} + virtual void onActivityPreCreated (jobject /*activity*/, jobject /*bundle*/) {} + virtual void onActivityPreDestroyed (jobject /*activity*/) {} + virtual void onActivityPrePaused (jobject /*activity*/) {} + virtual void onActivityPreResumed (jobject /*activity*/) {} + virtual void onActivityPreSaveInstanceState (jobject /*activity*/, jobject /*bundle*/) {} + virtual void onActivityPreStarted (jobject /*activity*/) {} + virtual void onActivityPreStopped (jobject /*activity*/) {} + + virtual void onActivityCreated (jobject /*activity*/, jobject /*bundle*/) {} + virtual void onActivityDestroyed (jobject /*activity*/) {} + virtual void onActivityPaused (jobject /*activity*/) {} + virtual void onActivityResumed (jobject /*activity*/) {} + virtual void onActivitySaveInstanceState (jobject /*activity*/, jobject /*bundle*/) {} + virtual void onActivityStarted (jobject /*activity*/) {} + virtual void onActivityStopped (jobject /*activity*/) {} + + virtual void onActivityPostCreated (jobject /*activity*/, jobject /*bundle*/) {} + virtual void onActivityPostDestroyed (jobject /*activity*/) {} + virtual void onActivityPostPaused (jobject /*activity*/) {} + virtual void onActivityPostResumed (jobject /*activity*/) {} + virtual void onActivityPostSaveInstanceState (jobject /*activity*/, jobject /*bundle*/) {} + virtual void onActivityPostStarted (jobject /*activity*/) {} + virtual void onActivityPostStopped (jobject /*activity*/) {} private: jobject invoke (jobject, jobject, jobjectArray) override; @@ -889,7 +906,7 @@ class ActivityLifecycleCallbacks : public AndroidInterfaceImplementer //============================================================================== struct SurfaceHolderCallback : AndroidInterfaceImplementer { - virtual ~SurfaceHolderCallback() {} + virtual ~SurfaceHolderCallback() override = default; virtual void surfaceChanged (LocalRef holder, int format, int width, int height) = 0; virtual void surfaceCreated (LocalRef holder) = 0; diff --git a/JuceLibraryCode/modules/juce_core/native/juce_android_Misc.cpp b/JuceLibraryCode/modules/juce_core/native/juce_android_Misc.cpp index f43c545..6e511dd 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_android_Misc.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_android_Misc.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,7 +25,20 @@ namespace juce void Logger::outputDebugString (const String& text) { - __android_log_print (ANDROID_LOG_INFO, "JUCE", "%s", text.toUTF8().getAddress()); + char* data = text.toUTF8().getAddress(); + const size_t length = CharPointer_UTF8::getBytesRequiredFor (text.getCharPointer()); + const size_t chunkSize = 1023; + + size_t position = 0; + size_t numToRead = jmin (chunkSize, length); + + while (numToRead > 0) + { + __android_log_print (ANDROID_LOG_INFO, "JUCE", "%s", data + position); + + position += numToRead; + numToRead = jmin (chunkSize, length - position); + } } } // namespace juce diff --git a/JuceLibraryCode/modules/juce_core/native/juce_android_Network.cpp b/JuceLibraryCode/modules/juce_core/native/juce_android_Network.cpp index 64ae418..9f60dff 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_android_Network.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_android_Network.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,165 +24,158 @@ namespace juce { //============================================================================== -// This byte-code is generated from native/java/com/roli/juce/JuceHTTPStream.java with min sdk version 16 +// This byte-code is generated from native/java/com/rmsl/juce/JuceHTTPStream.java with min sdk version 16 // See juce_core/native/java/README.txt on how to generate this byte-code. static const uint8 javaJuceHttpStream[] = -{31,139,8,8,96,105,229,91,0,3,74,117,99,101,72,84,84,80,83,116,114,101,97,109,46,100,101,120,0,125,154,11,124,84,213,157, -199,255,231,222,185,119,30,153,153,220,76,30,147,132,60,38,33,132,4,18,38,32,40,146,128,200,75,32,65,17,6,20,146,181,29, -50,23,50,48,220,9,51,119,32,88,84,64,171,212,218,74,173,86,250,82,139,88,105,87,91,171,237,214,86,187,109,197,118,219, -218,90,109,245,179,174,187,125,91,119,237,167,187,186,218,118,221,246,227,102,127,231,49,153,137,77,33,124,239,255,127, -254,231,127,206,61,143,255,121,204,36,41,123,34,208,119,193,18,58,123,73,224,169,145,163,171,22,29,152,124,110,71,248, -214,145,193,207,157,62,245,139,197,215,175,242,156,233,36,26,39,162,137,237,139,35,164,254,253,114,14,209,11,36,237,139, -192,183,116,162,56,228,9,15,81,61,228,147,38,209,149,144,71,188,68,200,34,79,128,104,101,19,81,10,242,205,90,162,63,130, -183,193,95,192,255,1,173,142,200,0,33,80,5,162,160,27,92,12,54,131,173,224,42,48,2,118,1,27,92,11,174,3,199,192,205,224, -86,112,59,56,5,206,128,179,224,41,240,10,104,140,18,45,3,215,128,27,193,253,224,187,224,183,128,161,193,49,112,17,184,28, -236,6,71,193,221,224,33,240,44,120,5,188,13,194,13,68,237,96,0,92,5,246,129,227,224,62,240,8,248,1,248,37,120,19,248,27, -137,174,6,105,112,45,248,4,120,2,188,6,106,102,161,14,112,13,56,2,62,9,254,5,76,130,30,140,211,213,96,20,236,6,123,129,3, -242,224,125,224,40,184,13,156,4,31,5,119,131,79,130,123,193,253,224,113,240,36,248,30,120,17,252,28,188,10,94,7,255,3, -222,1,70,51,81,16,68,65,12,244,128,53,96,59,24,3,215,130,219,192,167,193,3,224,9,112,14,252,24,188,10,254,2,204,22,244, -17,88,160,17,116,128,249,96,17,184,8,108,2,127,7,28,112,61,184,25,220,13,206,128,175,128,239,128,31,129,127,6,175,129,55, -193,36,240,181,18,213,129,78,208,15,46,3,27,193,86,240,94,176,23,28,2,71,193,9,112,23,184,23,60,0,30,6,143,129,175,129, -103,193,207,192,239,192,155,224,207,128,98,232,59,168,4,115,64,63,216,14,118,131,125,96,28,28,4,71,192,205,224,36,184,23, -60,0,190,0,190,9,94,4,63,3,191,6,255,14,254,12,188,109,68,179,65,31,88,9,182,128,221,96,63,112,193,17,112,2,124,28,60,8, -190,8,190,14,190,15,126,14,222,2,122,59,226,2,52,130,118,208,11,150,131,203,64,2,100,64,1,92,7,110,5,31,1,167,64,16,221, -178,0,194,138,16,62,132,233,37,76,15,97,40,73,117,153,80,61,193,149,102,131,14,128,229,75,88,214,52,23,116,129,110,48,15, -204,7,61,160,23,44,32,185,166,251,192,66,181,206,47,0,139,193,18,112,33,184,8,44,5,23,131,126,48,0,86,128,75,192,74,112, -41,88,5,214,128,117,224,50,176,30,108,4,91,192,54,176,29,92,69,178,31,197,127,33,37,151,98,111,8,43,125,101,153,190,30, -122,165,210,55,215,202,254,51,149,230,251,143,1,70,96,143,148,213,203,245,98,249,6,165,187,202,167,88,87,173,242,91,170, -236,181,202,94,173,244,35,202,30,45,179,71,149,189,70,233,55,65,175,83,250,109,202,94,175,236,181,74,95,170,244,134,50, -157,207,219,157,181,178,28,215,63,165,222,213,92,214,254,150,50,189,181,76,111,47,211,103,151,245,133,207,239,67,170,126, -62,199,93,170,206,121,202,135,207,67,175,210,7,149,206,251,114,133,210,191,12,125,72,233,79,150,233,125,101,58,111,255, -38,165,63,13,125,179,210,249,248,95,174,244,31,150,249,252,91,173,60,27,122,213,248,23,235,121,165,86,198,196,2,213,158, -173,74,255,61,236,9,165,187,170,47,11,213,123,117,204,244,247,136,203,5,244,28,164,7,35,103,11,89,75,123,132,236,161,180, -144,97,250,176,144,221,244,77,226,241,209,68,41,33,165,159,161,252,12,140,88,65,200,249,116,147,144,81,186,69,201,15,8, -41,235,49,240,190,59,72,198,217,105,33,25,125,78,200,56,125,94,200,122,250,130,144,125,244,13,33,139,239,197,154,87,242, -135,64,163,42,186,75,180,191,141,76,33,189,244,30,33,131,66,122,208,30,83,200,86,250,146,40,215,41,210,188,221,59,84,59, -71,133,172,163,221,66,154,52,166,236,7,132,244,211,97,33,13,186,65,201,99,42,255,164,144,58,61,36,100,43,61,172,198,225, -31,136,175,153,118,241,158,16,118,11,46,195,200,79,10,233,17,254,149,72,31,18,114,30,253,68,196,93,5,237,83,241,119,187, -136,189,86,81,46,138,113,217,165,228,135,72,198,246,199,132,92,64,95,23,178,146,190,45,164,37,100,61,86,212,136,144,17, -218,47,164,44,87,143,145,146,82,150,175,87,254,13,234,61,13,88,101,35,66,134,233,25,226,123,225,108,97,111,68,254,19,196, -215,83,43,57,66,250,232,90,33,27,233,125,42,125,68,200,0,93,79,114,221,29,21,50,74,199,133,140,209,99,66,118,211,151,149, -252,138,178,127,85,200,14,122,92,200,57,244,53,226,107,85,142,87,51,118,85,41,235,233,140,144,178,93,173,24,247,247,11, -25,164,123,136,239,205,33,154,32,190,63,7,233,58,37,111,36,190,158,103,145,75,124,45,55,208,157,196,215,113,51,125,139, -248,94,221,66,25,33,155,232,227,196,215,116,47,189,87,200,160,168,103,190,26,143,249,248,145,233,110,122,148,248,158,46, -237,92,222,45,228,124,122,86,165,127,76,242,142,70,36,215,22,223,35,170,32,31,199,198,117,229,28,105,247,148,229,247,169, -252,151,144,191,87,229,243,120,102,84,218,47,121,254,219,200,63,174,242,121,253,63,197,193,243,50,248,77,135,244,253,131, -146,239,116,240,117,128,251,4,124,67,115,164,45,170,100,167,146,151,40,185,126,14,175,75,23,250,167,176,233,249,32,135, -145,24,209,24,141,91,179,68,132,242,92,94,223,153,118,185,71,182,179,32,109,139,49,156,83,22,37,98,68,7,44,175,136,112, -199,234,19,114,60,86,141,18,85,108,122,222,2,33,187,222,228,109,99,226,125,15,183,203,126,58,22,183,4,69,31,77,252,240, -188,71,219,229,121,34,219,48,204,52,26,214,12,26,214,61,52,236,209,105,216,48,197,202,225,237,50,232,71,237,242,60,76, -244,121,80,23,223,105,3,56,63,107,41,177,80,167,102,150,232,51,209,82,31,113,25,137,228,98,235,17,35,45,76,250,94,46,74, -105,200,247,10,233,88,189,194,98,40,139,1,75,237,84,205,155,197,104,132,80,122,46,158,37,91,215,159,144,90,40,83,76,156, -16,132,213,171,3,46,153,58,187,116,113,206,243,158,47,17,82,71,219,47,184,33,116,225,114,172,204,0,241,81,122,165,93,238, -221,188,207,62,140,114,15,180,77,240,28,62,230,71,170,86,216,121,138,231,205,71,106,163,72,85,96,95,226,55,129,32,59,96, -93,198,199,145,13,31,11,208,200,173,149,52,252,193,8,13,223,22,164,29,31,170,163,225,15,215,208,240,237,213,20,249,239, -29,199,162,120,179,69,59,142,90,120,75,21,13,31,13,209,182,27,43,41,113,83,132,18,239,15,210,22,92,253,19,183,132,200, -123,204,123,199,65,175,95,213,232,69,207,53,117,35,168,154,45,227,47,129,185,173,18,177,233,21,49,82,15,123,158,199,135, -175,25,49,176,12,235,216,177,6,240,142,160,175,213,215,68,222,155,90,61,77,20,241,57,177,11,113,18,56,177,197,244,7,60, -47,194,179,209,119,53,180,86,156,3,65,45,162,183,117,45,185,49,78,235,124,154,222,232,215,97,111,166,83,20,48,151,155, -237,194,230,224,114,236,163,128,111,201,205,141,34,29,241,59,184,34,158,50,131,140,167,94,242,155,204,137,197,80,34,232, -229,158,94,120,46,247,97,22,251,46,166,26,239,75,186,206,186,158,79,156,13,161,214,165,104,195,210,96,132,34,245,78,108, -9,215,67,60,70,23,34,166,130,134,131,15,47,47,34,21,69,108,85,121,66,34,42,60,232,85,136,26,253,126,244,172,6,245,207, -245,201,59,206,85,124,70,217,172,61,213,56,23,2,208,15,205,150,247,139,254,112,45,69,194,237,168,193,251,25,246,168,247, -156,247,5,246,91,239,159,124,94,139,52,95,21,249,252,17,58,24,48,197,216,93,28,254,175,201,234,112,95,161,235,119,33,22, -161,174,183,229,216,86,201,122,27,43,68,140,135,233,19,179,249,12,227,126,228,59,201,34,53,17,61,241,128,159,154,141,196, -233,10,180,110,16,30,1,109,41,214,71,139,193,22,85,106,145,200,120,44,136,115,36,168,13,159,14,83,226,116,13,69,204,196, -131,94,120,46,226,35,226,29,244,106,166,180,174,209,52,115,241,241,159,82,68,155,94,130,251,198,81,107,80,203,89,171,149, -92,195,165,153,179,86,96,133,242,183,61,77,57,235,18,232,65,214,202,218,160,95,202,35,5,246,55,38,115,214,42,165,255,110, -50,241,96,53,70,174,1,209,218,133,121,43,122,181,106,81,204,65,55,118,221,160,214,232,243,8,253,56,226,164,209,175,81, -177,116,171,86,67,7,98,98,39,214,74,190,84,244,213,28,107,158,104,153,19,107,199,154,43,175,185,209,27,128,87,19,229,208, -206,139,181,179,147,165,26,99,20,241,230,98,43,145,35,61,15,88,13,178,14,171,81,140,225,142,211,81,234,186,61,36,198,177, -155,70,38,67,106,44,22,137,220,37,199,219,228,104,122,18,159,149,86,140,132,57,104,106,30,233,213,11,175,153,243,101,125, -139,39,103,158,139,110,90,54,25,210,90,140,185,90,72,75,156,249,107,15,143,57,247,93,115,218,77,113,148,232,166,158,73, -212,188,170,155,188,147,124,255,240,99,87,170,22,123,168,87,220,131,121,236,116,136,61,171,90,124,214,184,1,233,199,196, -222,19,18,103,44,63,243,159,83,126,255,170,236,191,80,233,255,84,233,55,196,174,205,232,29,81,111,53,249,152,180,27,55, -132,30,101,191,103,55,116,126,149,189,206,232,247,140,94,103,215,119,190,95,19,70,47,198,129,159,41,175,206,150,159,119, -34,90,98,171,143,154,245,196,149,50,90,25,5,216,82,134,104,213,189,109,56,37,174,12,80,59,246,244,241,62,70,9,51,23,91, -139,207,56,216,113,174,172,69,126,2,207,156,181,65,236,65,173,44,76,93,175,133,88,139,62,151,97,119,106,235,250,141,120, -254,82,158,165,13,240,225,235,206,135,247,206,85,251,172,70,157,90,117,247,156,158,26,232,94,62,23,24,12,126,103,168,198, -135,155,72,232,32,171,64,127,2,214,197,150,33,44,149,214,75,161,16,243,193,182,133,89,116,97,243,255,78,114,61,193,48,31, -250,154,42,166,87,179,94,198,111,151,139,172,26,170,102,11,148,142,177,101,113,165,195,159,93,32,244,11,172,151,85,233, -106,106,212,55,32,26,59,112,195,14,176,151,194,44,80,178,35,150,251,230,208,194,112,160,242,162,215,159,82,254,124,222, -47,16,253,117,172,229,92,250,139,254,78,223,92,250,85,101,176,162,184,187,158,162,246,32,180,190,126,186,173,130,251,6, -17,27,139,238,184,103,234,189,17,93,104,30,148,180,58,49,70,1,143,211,55,155,22,122,132,21,177,226,195,213,178,57,34,189, -203,231,165,82,140,70,75,164,155,38,38,49,218,17,140,118,128,91,186,105,188,172,141,189,240,230,169,109,122,37,201,247, -68,164,52,130,66,110,49,235,100,218,27,66,204,84,83,241,36,225,182,97,212,192,235,95,57,41,107,230,250,170,73,18,247,243, -185,104,233,205,106,255,187,91,204,163,135,62,13,233,133,198,239,125,124,247,127,74,165,117,186,11,91,228,41,118,195,172, -239,176,187,24,169,91,12,209,137,14,185,135,110,141,85,137,207,177,69,251,135,59,100,172,108,137,69,113,103,183,166,206, -179,59,213,125,41,130,29,221,15,111,15,126,62,209,33,63,27,226,76,220,133,157,86,75,36,195,180,148,249,137,203,136,238, -172,172,163,3,55,6,168,69,91,142,246,108,221,85,69,199,60,79,172,218,9,89,73,24,51,13,99,198,186,222,98,36,239,86,30,181, -134,26,85,92,206,154,58,255,27,88,168,137,199,44,67,116,106,244,88,135,252,238,160,29,37,18,7,112,255,200,97,47,206,227, -157,46,110,47,133,90,58,104,242,154,18,57,209,158,3,21,20,169,118,98,67,136,171,8,27,134,119,139,214,110,54,34,50,230, -163,46,199,234,33,126,67,146,109,137,136,27,17,19,223,79,48,241,51,7,111,144,55,212,103,202,250,206,191,75,228,255,52,42, -73,55,32,199,242,8,228,77,1,121,103,44,126,47,192,207,175,147,1,57,166,167,32,239,83,249,229,119,95,158,111,170,122,252, -74,242,239,15,206,42,223,14,85,95,157,146,81,245,222,162,140,171,250,226,170,78,63,201,207,58,113,225,209,39,62,191,68, -85,217,5,101,109,43,239,131,69,53,194,110,168,54,151,202,71,133,125,158,242,227,159,65,25,201,123,167,108,67,84,148,105, -130,165,7,189,233,86,246,102,85,46,78,197,241,96,24,222,46,194,133,141,45,35,109,89,140,216,0,153,3,105,39,237,174,32, -109,69,63,121,86,244,119,111,39,107,117,214,113,236,81,55,157,117,98,118,46,151,205,81,24,22,215,118,220,222,33,219,217, -227,142,81,237,154,116,126,116,202,105,75,193,113,146,187,50,54,177,13,164,109,24,34,125,195,208,6,242,224,129,253,112, -35,85,111,44,140,218,235,19,137,205,91,221,156,157,220,191,96,111,242,96,146,216,16,105,112,210,185,143,54,132,34,67,120, -120,135,134,118,14,13,161,130,128,82,184,174,13,237,164,250,161,164,147,202,101,211,169,184,107,79,184,241,4,30,219,220, -116,38,223,79,177,161,209,236,254,120,46,155,73,199,247,226,53,241,233,239,234,88,216,79,139,207,239,49,99,71,250,169, -229,188,165,250,169,125,40,149,204,28,76,239,139,39,29,39,235,38,121,225,248,90,103,52,147,205,167,157,61,171,51,201,60, -218,54,251,124,62,155,108,119,44,155,226,47,250,107,167,13,104,79,78,85,210,54,67,254,38,123,255,46,229,96,195,165,121,6, -151,173,233,61,78,210,45,228,208,149,198,25,178,19,99,185,236,33,81,148,207,70,60,157,141,175,42,236,222,109,231,236,212, -6,103,188,224,22,123,89,59,149,189,225,138,181,19,163,246,56,47,60,205,92,238,93,55,101,190,162,224,150,217,235,165,61, -147,116,246,196,87,143,37,115,91,237,3,5,219,25,181,167,42,18,57,101,245,87,151,153,55,32,238,246,216,57,62,211,211,141, -185,92,97,220,181,83,101,197,106,202,61,224,32,103,50,82,102,189,98,215,94,76,244,116,207,210,156,151,123,162,237,152, -164,233,109,151,54,57,80,253,212,48,67,78,58,147,226,89,229,21,97,164,237,100,106,122,87,197,232,203,119,54,73,179,99, -187,241,245,174,59,190,109,203,80,105,237,245,83,184,148,139,156,169,214,168,116,185,167,234,81,1,171,66,246,221,205,162, -33,86,153,117,40,157,119,167,154,33,44,155,146,227,29,107,29,55,119,184,159,54,205,100,30,248,235,241,120,87,125,51,120, -172,192,15,85,78,175,110,186,97,171,237,242,176,47,25,176,254,70,11,185,28,182,151,248,234,100,38,35,118,146,214,243,231, -247,83,207,223,114,64,96,193,135,143,74,89,104,116,207,236,189,118,194,30,45,188,203,181,243,124,174,89,4,111,238,96,154, -199,110,236,252,126,249,169,185,125,183,199,186,2,95,151,197,165,55,115,110,63,13,156,47,123,224,188,203,22,19,208,49, -115,105,25,140,235,146,163,104,32,102,125,254,204,94,136,157,253,233,209,248,165,66,172,202,102,51,118,18,227,50,111,102, -231,76,118,116,95,62,190,197,134,158,75,58,238,16,146,253,228,135,16,83,176,140,216,118,210,182,99,143,223,142,61,126,59, -246,120,19,15,190,215,35,177,147,2,219,203,246,249,237,59,137,237,36,109,231,70,0,57,188,10,108,160,234,225,25,86,165,54, -226,80,32,57,58,106,231,243,29,125,125,125,84,33,245,117,153,228,158,60,121,147,169,84,14,41,50,147,227,227,182,147,34, -239,174,100,222,222,150,203,144,185,75,140,22,121,70,17,70,100,142,138,88,33,131,239,200,54,249,177,225,143,39,115,118, -34,75,94,117,34,80,160,116,52,80,93,73,79,100,75,167,6,89,163,24,83,215,46,45,198,162,69,78,21,31,144,162,165,116,128,20, -45,50,37,124,42,213,136,22,135,142,204,148,61,154,77,217,84,147,178,119,39,11,25,119,218,228,241,220,140,237,218,20,72, -149,154,82,155,154,241,84,174,158,102,150,213,144,63,149,85,77,38,102,147,193,167,239,48,249,132,192,2,133,166,226,152, -140,221,105,59,147,130,200,20,242,99,164,239,65,102,13,30,197,133,134,23,168,46,133,97,93,203,111,11,42,93,137,244,122, -188,202,206,173,227,53,228,133,67,89,156,146,137,244,160,125,88,56,150,159,24,84,1,195,102,156,146,98,24,120,238,22,59, -63,158,117,242,24,100,140,7,175,38,129,131,44,163,238,34,188,26,236,134,228,131,220,158,204,20,108,178,198,146,249,85, -136,72,213,70,27,33,0,203,229,184,53,80,197,152,104,209,80,218,177,17,41,50,145,167,160,82,18,217,109,136,132,240,24,118, -226,45,252,144,202,187,171,247,167,168,122,122,90,58,5,184,81,181,151,165,201,155,118,82,246,196,21,187,169,34,93,214,67, -95,218,81,77,170,72,231,215,78,140,37,11,121,151,183,38,157,23,227,64,102,58,143,126,186,60,151,75,89,179,47,173,246,111, -242,236,205,166,17,7,25,217,79,15,95,106,228,113,146,251,49,165,142,125,104,117,114,116,204,78,201,233,220,140,85,74,33, -110,44,133,97,5,146,165,96,66,2,175,16,146,47,5,143,195,71,67,119,10,104,36,30,171,14,187,24,143,26,104,235,178,153,76, -246,144,157,218,98,167,210,57,212,36,173,83,169,68,86,58,80,195,76,86,53,126,89,44,187,178,134,232,89,116,85,31,199,219, -61,120,44,20,207,69,228,27,47,206,48,215,220,53,73,55,73,161,162,38,43,242,136,72,245,230,16,233,88,193,84,153,83,97,176, -94,77,91,205,187,12,178,148,9,43,150,11,233,185,2,222,157,71,188,86,225,161,218,147,72,239,183,121,115,42,96,90,147,149, -81,71,141,121,30,152,121,151,135,139,236,72,169,247,220,113,42,22,195,121,30,139,201,84,177,22,75,164,69,96,200,251,28, -69,74,150,205,57,140,67,206,61,76,70,126,60,147,118,33,220,100,14,115,14,225,22,242,20,144,82,132,116,101,73,151,125,8, -230,69,0,169,163,194,204,23,118,237,71,13,126,200,188,216,2,41,228,142,149,111,57,213,60,249,238,93,167,100,44,219,102, -194,48,150,47,194,74,164,183,150,191,204,227,142,165,17,39,252,217,209,71,126,23,93,197,48,109,194,242,157,82,85,156,186, -89,185,31,83,133,91,182,28,235,248,57,144,223,157,205,237,183,83,151,151,69,160,23,59,139,104,129,89,112,68,36,87,28,76, -102,58,138,43,193,56,40,150,137,113,40,135,232,39,109,162,143,142,104,223,103,228,13,211,81,254,156,92,54,64,71,120,234, -30,205,56,199,190,203,190,195,158,198,231,109,227,159,216,188,117,222,240,64,47,255,71,159,215,224,112,98,249,96,186,117, -100,112,120,240,154,97,109,188,121,109,219,57,170,243,143,220,201,30,98,31,96,207,176,111,178,71,216,25,246,65,230,13, -107,127,209,250,39,38,14,107,199,175,59,35,10,247,14,12,14,177,72,37,89,236,5,228,210,106,115,228,163,236,239,217,9,246, -3,225,253,138,238,249,36,107,30,28,184,100,159,174,221,194,22,49,166,235,31,98,108,249,9,221,124,144,177,207,78,232,236, -80,253,9,221,251,19,86,159,214,14,246,27,204,240,106,225,126,195,28,94,48,180,96,80,55,62,203,172,129,75,12,163,197,208, -12,189,85,167,124,211,0,205,243,79,85,255,143,236,139,236,126,118,43,94,210,59,135,85,69,209,230,94,173,162,191,141,126, -141,94,111,92,126,139,214,219,163,237,104,214,42,14,61,62,113,61,107,180,60,204,109,239,127,154,53,84,178,250,208,138,95, -177,250,106,131,241,42,195,56,52,13,226,218,220,19,95,190,230,71,125,90,203,243,6,105,187,250,207,117,124,76,179,250,233, -32,187,131,121,155,81,89,109,143,182,191,249,229,182,143,172,68,15,40,95,211,218,98,144,208,58,91,233,78,62,202,189,186, -245,37,22,111,211,67,167,25,27,234,213,190,77,61,134,165,93,218,108,90,31,56,172,87,125,131,49,86,95,117,78,15,159,69, -159,245,202,207,49,182,224,156,238,223,87,255,65,189,226,83,172,126,167,238,187,166,101,167,30,188,135,181,12,233,218, -179,172,62,206,44,235,240,3,90,104,135,97,173,68,215,125,70,176,85,15,228,155,52,103,163,17,48,53,211,103,6,77,235,125, -172,165,246,162,86,51,64,111,241,169,163,183,197,243,29,241,252,185,166,189,231,51,24,149,54,157,238,195,80,15,78,180, -247,238,213,38,154,7,232,25,158,253,71,157,198,141,229,123,7,90,119,234,230,129,89,3,13,134,73,199,117,246,105,62,117, -154,151,61,207,26,131,154,79,219,233,161,83,172,69,11,32,221,100,68,123,163,203,163,70,180,35,234,213,42,184,1,3,88,84, -170,52,19,74,189,33,138,248,78,177,104,133,44,227,137,174,86,37,68,210,31,101,209,197,209,206,232,122,84,37,51,124,154, -95,214,224,41,86,213,73,26,211,232,100,140,225,255,209,163,158,71,106,53,246,92,45,251,118,236,190,58,50,24,211,144,41, -126,200,115,236,168,231,201,58,131,253,71,29,85,153,94,175,198,34,226,71,228,49,109,218,143,72,155,240,127,164,158,157, -136,189,212,160,69,222,104,96,13,127,152,197,34,63,108,98,145,163,237,190,170,147,179,141,170,183,59,89,213,201,185,172, -234,44,120,18,60,210,197,170,206,116,139,239,148,168,236,187,6,46,139,127,187,197,191,31,40,254,253,86,241,123,11,254,55, -92,252,59,146,226,223,113,241,239,20,138,127,203,101,82,233,239,185,116,75,254,254,141,127,15,195,98,242,119,191,143,240, -239,79,98,210,135,255,254,144,89,165,223,41,106,49,249,94,254,247,95,186,242,231,191,195,243,196,72,252,238,137,255,126, -144,84,89,241,123,71,75,182,149,255,173,217,255,3,11,139,181,139,164,38,0,0}; +{31,139,8,8,71,116,161,94,0,3,106,97,118,97,74,117,99,101,72,116,116,112,83,116,114,101,97,109,46,100,101,120,0,125,154,11,124, +84,87,157,199,255,231,222,185,119,30,153,153,220,76,30,147,132,60,38,33,132,4,18,38,80,104,41,9,148,242,42,144,80,40,12,84,8, +91,29,50,23,50,48,185,19,102,238,64,168,180,133,62,233,67,75,223,184,86,173,72,45,186,85,171,86,173,182,174,109,105,93,31,181, +85,87,119,171,187,186,186,91,171,246,211,221,118,235,171,171,31,55,251,59,143,201,76,218,44,132,239,253,255,207,255,252,207, +185,231,241,63,143,153,36,101,79,4,250,46,88,66,151,94,114,238,181,147,179,244,212,201,205,225,159,190,152,158,247,165,219,39, +126,178,240,215,230,173,135,207,118,18,141,19,209,196,142,197,17,82,255,94,153,67,244,35,146,246,69,224,105,157,40,14,121,194, +67,84,15,249,148,73,116,5,228,81,47,17,178,200,19,32,90,211,68,148,130,124,171,150,232,15,224,109,240,23,240,191,64,171,35,50, +64,8,84,129,40,232,6,23,131,45,96,27,184,18,236,6,123,128,13,174,6,215,128,227,224,102,112,27,184,19,156,2,103,192,89,240,44, +120,5,52,70,137,150,129,171,192,13,224,19,224,155,224,87,128,161,193,49,112,17,184,28,236,5,199,192,3,224,81,240,34,120,5,188, +13,194,13,68,237,96,0,92,9,14,128,235,193,67,224,49,240,29,240,11,240,22,240,55,18,189,7,164,193,213,224,111,193,147,224,183, +160,102,22,234,0,87,129,163,224,195,224,39,96,18,244,96,156,222,3,70,192,94,176,31,56,32,15,222,15,142,129,59,192,73,112,15,120, +0,124,24,124,12,124,2,60,1,158,2,223,2,63,6,63,7,175,130,55,192,159,192,95,129,209,76,20,4,81,16,3,61,96,13,216,1,70,193,213, +224,14,240,17,240,48,120,18,156,3,47,129,87,193,95,128,217,130,62,2,11,52,130,14,48,31,44,2,23,129,77,224,111,128,3,174,5,55, +131,7,192,25,240,37,240,60,248,30,248,103,240,91,240,22,152,4,190,86,162,58,208,9,250,193,101,96,35,216,6,222,7,246,131,195,224, +24,56,1,238,3,31,3,15,131,207,128,47,130,175,130,23,193,207,192,107,224,45,240,103,64,49,244,29,84,130,57,160,31,236,0,123,193, +1,48,14,14,129,163,224,102,112,18,124,12,60,12,62,11,190,1,126,12,126,6,254,29,252,26,252,25,120,219,136,102,131,62,176,18, +108,5,123,193,24,112,193,81,112,2,124,8,60,2,62,7,190,6,190,13,126,14,126,7,244,118,196,5,104,4,237,160,23,44,7,151,129,4,200, +128,2,184,6,220,6,238,2,167,64,16,221,178,0,194,138,16,62,132,233,37,76,15,97,40,73,117,153,80,61,193,149,102,131,14,128,229, +75,88,214,52,23,116,129,110,48,15,204,7,61,160,23,44,32,185,166,251,192,66,181,206,47,0,139,193,18,112,33,184,8,44,5,23,131,126, +48,0,86,128,75,192,74,112,41,88,5,214,128,117,224,50,176,30,108,4,91,193,118,176,3,92,73,178,31,197,127,33,37,151,98,111,8, +43,125,101,153,190,30,122,165,210,183,212,202,254,51,149,230,251,143,1,118,195,30,41,171,151,235,197,242,13,74,119,149,79,177, +174,90,229,183,84,217,107,149,189,90,233,71,149,61,90,102,143,42,123,141,210,111,132,94,167,244,59,148,189,94,217,107,149,190, +84,233,13,101,58,159,183,123,107,101,57,174,63,168,222,213,92,214,254,150,50,189,181,76,111,47,211,103,151,245,133,207,239,163, +170,126,62,199,93,170,206,121,202,135,207,67,175,210,7,149,206,251,178,89,233,143,67,31,82,250,83,101,122,95,153,206,219,191, +73,233,207,65,223,162,116,62,254,151,43,253,133,50,159,127,173,149,103,67,175,26,255,98,61,175,212,202,152,88,160,218,179,77, +233,175,195,158,80,186,171,250,178,80,189,87,199,76,127,139,184,92,64,223,135,244,96,228,108,33,107,105,159,144,61,148,22,50, +76,31,20,178,155,190,65,60,62,154,40,37,164,244,51,148,159,129,17,43,8,57,159,110,20,50,74,183,40,121,171,144,178,30,3,239,187, +155,100,156,157,22,146,209,167,132,140,211,167,133,172,167,207,10,217,71,95,23,178,248,94,172,121,37,95,0,26,85,209,125,162, +253,109,100,10,233,165,247,10,25,20,210,131,246,152,66,182,210,231,69,185,78,145,230,237,222,169,218,57,34,100,29,237,21,210, +164,81,101,63,40,164,159,142,8,105,208,117,74,30,87,249,39,133,212,233,81,33,91,233,51,106,28,190,76,124,205,180,139,247,132, +176,91,112,25,70,126,82,72,143,240,175,68,250,176,144,243,232,135,34,238,42,232,128,138,191,59,69,236,181,138,114,81,140,203, +30,37,63,64,50,182,239,23,114,1,125,77,200,74,122,70,72,75,200,122,172,168,221,66,70,104,76,72,89,174,30,35,37,165,44,95,175, +252,27,212,123,26,176,202,118,11,25,166,239,18,223,11,103,11,123,35,242,159,36,190,158,90,201,17,210,71,87,11,217,72,239,87,233, +163,66,6,232,90,146,235,238,152,144,81,186,94,200,24,125,81,200,110,122,92,201,47,41,251,87,132,236,160,39,132,156,67,95,37, +190,86,229,120,53,99,87,149,178,158,206,8,41,219,213,138,113,191,73,200,32,125,148,248,222,28,162,9,226,251,115,144,174,81,242, +6,226,235,121,22,185,196,215,114,3,221,75,124,29,55,211,211,196,247,234,22,202,8,217,68,31,34,190,166,123,233,125,66,6,69,61, +243,213,120,204,199,143,76,119,211,23,136,239,233,210,206,229,3,66,206,167,23,85,250,37,146,119,52,34,185,182,248,30,81,5,249, +4,54,174,196,28,105,247,148,229,247,169,252,151,145,63,166,242,121,60,51,42,237,151,60,255,109,228,223,164,242,121,253,255,132, +131,231,103,224,213,14,233,251,39,37,249,97,164,65,248,33,173,57,210,214,168,100,183,146,171,148,28,156,195,235,210,133,254,32, +54,61,31,228,48,18,187,53,70,227,214,44,17,161,60,151,215,247,112,187,220,35,219,89,144,182,199,24,206,41,139,18,49,162,131, +150,87,68,184,99,245,9,57,30,171,70,137,42,54,61,111,129,144,93,111,241,182,49,241,190,207,182,203,126,58,22,183,4,69,31,77, +252,240,188,199,219,229,121,34,219,48,204,52,26,214,12,26,214,61,52,236,209,105,216,48,197,202,225,237,50,232,165,118,121,30,38, +250,60,168,139,239,180,1,156,159,181,148,88,168,83,51,75,244,153,104,169,143,184,140,68,114,177,245,136,145,22,38,125,47,23,165, +52,228,123,133,116,172,94,97,49,148,197,128,165,118,170,230,45,98,52,66,40,61,23,207,146,173,235,143,72,45,148,41,38,78,8, +194,234,213,1,151,76,157,93,186,56,231,121,207,151,8,169,163,237,23,92,23,186,112,57,86,102,128,248,40,189,218,46,247,110,222, +103,31,70,185,7,218,38,120,14,31,247,35,85,43,236,60,197,243,230,35,181,81,164,42,176,47,241,155,64,144,29,180,46,227,227,200, +134,143,7,104,247,109,149,52,124,123,132,134,239,8,210,206,15,212,209,240,7,107,104,248,206,106,138,252,247,206,227,81,188,217, +162,157,199,44,188,165,138,134,143,133,104,251,13,149,148,184,49,66,137,155,130,180,21,87,255,196,45,33,242,30,247,222,125, +200,235,87,53,122,209,115,77,221,8,170,103,203,248,75,96,110,171,68,108,122,69,140,52,194,158,231,241,225,107,70,12,44,195,58, +118,172,1,188,35,232,107,245,53,145,247,198,86,79,19,69,124,78,236,66,156,4,78,108,49,253,30,207,139,240,108,244,189,7,90,43, +206,129,160,22,209,219,186,150,220,16,167,117,62,77,111,244,235,176,55,211,41,10,152,203,205,118,97,115,112,57,246,81,192,183, +228,230,70,145,142,248,29,92,17,79,153,65,198,83,47,251,77,230,196,98,40,17,244,114,79,47,60,151,251,48,139,125,23,83,141,247, +101,93,103,93,63,72,156,13,161,214,165,104,195,210,96,132,34,245,78,108,9,215,67,60,70,23,34,166,130,134,131,15,47,63,70,42, +138,216,170,242,132,68,84,120,208,171,16,53,250,253,232,89,13,234,159,235,147,119,156,43,249,140,178,89,251,170,113,46,4,160,31, +153,45,239,23,253,225,90,138,132,219,81,131,247,227,236,11,222,115,222,31,177,95,121,255,232,243,90,164,249,170,200,231,143,208, +161,128,41,198,238,226,240,127,77,86,135,251,10,93,175,133,88,132,186,222,150,99,91,37,235,109,172,16,49,30,166,7,103,243, +25,198,216,251,78,178,72,77,68,79,60,236,167,102,35,113,186,2,173,27,132,71,64,91,138,245,209,98,176,69,149,90,36,50,30,11,226, +28,9,106,195,167,195,148,56,93,67,17,51,241,136,23,158,139,248,136,120,7,189,154,41,173,107,52,205,92,124,253,63,82,68,155, +94,130,251,198,81,107,80,203,89,171,149,92,195,165,153,179,86,96,133,242,183,61,71,57,235,18,232,65,214,202,218,160,95,202,35, +5,246,55,39,115,214,42,165,191,54,153,120,164,26,35,215,128,104,237,194,188,21,189,90,181,40,230,160,27,187,110,80,107,244,121, +132,126,61,226,164,209,175,81,177,116,171,86,67,7,99,98,39,214,74,190,84,244,213,28,107,158,104,153,19,107,199,154,43,175,185, +209,27,128,87,19,229,208,206,139,181,179,147,165,26,99,20,241,230,98,43,145,35,61,15,90,13,178,14,171,81,140,225,206,211,81, +234,186,51,36,198,177,155,118,79,134,212,88,44,18,185,75,174,111,147,163,233,73,124,82,90,49,18,230,160,169,121,164,87,47,188, +102,206,151,245,45,158,156,121,46,186,105,217,100,72,107,49,230,106,33,45,113,230,221,30,30,115,238,59,230,180,155,226,40,209, +77,61,147,168,121,85,55,121,39,249,254,225,199,174,84,45,246,80,175,184,7,243,216,233,16,123,86,181,248,172,113,29,210,95,20, +123,79,72,156,177,252,204,255,190,242,251,23,101,255,55,149,254,79,149,126,83,236,218,140,254,42,234,173,38,31,147,118,227,186, +208,23,216,235,236,186,206,175,176,55,24,189,206,232,13,118,109,231,77,154,48,122,49,14,252,76,249,205,108,249,121,39,162,37, +182,249,168,89,79,92,33,163,149,81,128,45,101,136,86,221,219,134,83,226,138,0,181,99,79,31,239,99,148,48,115,177,181,248,140, +131,29,231,138,90,228,39,240,204,89,27,196,30,212,202,194,212,245,219,16,107,209,231,50,236,78,109,93,255,33,158,191,144,103, +105,3,124,248,186,243,225,189,115,213,62,171,81,167,86,221,61,167,167,6,186,23,173,15,97,48,248,157,161,26,31,110,34,161,67,172, +2,253,9,88,23,91,134,176,84,90,47,135,66,204,7,219,86,102,209,133,205,255,51,201,245,4,195,124,232,107,170,152,94,205,122,25, +191,93,46,178,106,168,154,45,80,58,198,150,197,149,14,127,118,129,208,47,176,126,170,74,87,83,163,190,1,209,216,129,27,118,128, +189,28,102,129,146,29,177,220,55,135,22,134,3,149,23,189,241,172,242,231,243,126,129,232,175,99,45,231,210,95,244,119,250,230, +210,47,43,131,21,197,221,245,20,181,7,161,245,245,211,29,21,220,55,136,216,88,116,247,71,167,222,27,209,133,230,65,73,171,19, +99,20,240,56,125,179,105,161,71,88,17,43,62,92,45,155,35,210,187,124,94,42,197,104,180,68,186,105,98,18,163,29,193,104,7,184, +165,155,198,203,218,216,11,111,158,218,174,87,146,124,79,68,74,35,40,228,86,179,78,166,189,33,196,76,53,21,79,18,110,27,70,13, +188,254,149,147,178,102,174,175,154,36,113,63,159,139,150,222,172,246,191,7,196,60,122,232,35,144,94,104,252,222,199,119,255, +103,85,90,167,251,176,69,158,98,215,205,122,158,221,199,72,221,98,136,110,239,144,123,232,182,88,149,248,28,91,180,223,213,33, +99,101,107,44,138,59,187,53,117,158,61,208,33,239,75,17,236,232,126,120,123,248,59,59,228,103,67,156,137,123,176,211,106,137, +100,152,150,50,63,113,25,209,157,149,117,116,240,134,0,181,104,203,209,158,109,123,170,232,184,231,201,85,187,32,43,9,99,166, +97,204,88,215,239,24,201,187,149,71,173,161,70,21,151,179,166,206,255,6,22,106,226,49,203,16,157,26,125,185,67,126,119,208,142, +18,137,131,184,127,228,176,23,231,241,78,23,183,151,66,45,29,50,121,77,137,156,104,207,193,10,138,84,59,177,33,196,85,132,13, +195,187,69,107,55,27,17,25,243,81,151,99,245,16,191,33,201,182,68,196,141,136,137,239,39,152,248,153,131,55,200,27,234,139,101, +125,231,223,37,242,127,26,149,164,27,144,99,121,20,242,198,128,188,51,22,191,23,224,231,215,201,128,28,211,83,144,15,169,252, +242,187,47,207,55,85,61,126,37,249,247,7,103,149,111,135,170,175,78,201,168,122,111,81,198,85,125,113,85,167,159,228,103,157, +184,240,232,19,159,95,162,170,236,130,178,182,149,247,193,162,26,97,55,84,155,75,229,163,194,62,79,249,241,207,160,140,228,189, +83,182,33,42,202,52,193,210,131,222,116,43,123,179,42,23,167,226,120,48,12,111,23,225,194,198,150,145,182,44,70,108,128,204,129, +180,147,118,87,144,182,162,159,60,43,250,187,119,144,181,58,235,56,246,136,155,206,58,49,59,151,203,230,40,12,139,107,59,110, +239,144,237,236,115,71,169,118,77,58,63,50,229,180,181,224,56,201,61,25,155,216,6,210,54,12,145,190,97,104,3,121,240,192,126, +184,145,170,55,22,70,236,245,137,196,150,109,110,206,78,142,45,216,159,60,148,36,54,68,26,156,116,238,163,13,161,200,16,30,222, +161,161,93,67,67,168,32,160,20,174,107,67,187,168,126,40,233,164,114,217,116,42,238,218,19,110,60,129,199,118,55,157,201,247, +83,108,104,36,59,22,207,141,229,51,241,253,120,77,124,250,187,58,22,246,211,226,243,123,204,216,145,126,106,57,111,169,126,106, +31,74,37,51,135,210,7,226,73,199,201,186,73,94,56,190,214,25,201,100,243,105,103,223,234,76,50,143,182,205,62,159,207,38,219, +29,205,166,248,139,222,237,180,1,237,201,169,74,218,102,200,223,100,143,237,81,14,54,92,154,103,112,217,150,222,231,36,221,66, +14,93,105,156,33,59,49,154,203,30,22,69,249,108,196,211,217,248,170,194,222,189,118,206,78,109,112,198,11,110,177,151,181,83, +217,27,54,175,157,24,177,199,121,225,105,230,114,239,186,41,243,230,130,91,102,175,151,246,76,210,217,23,95,61,154,204,109,179, +15,22,108,103,196,158,170,72,228,148,213,95,93,102,222,128,184,219,103,231,248,76,79,55,230,114,133,113,215,78,149,21,171,41, +247,128,131,156,201,72,153,117,243,158,253,152,232,233,158,165,57,47,247,68,219,49,73,211,219,46,109,114,160,250,169,97,134,156, +116,38,197,179,202,43,194,72,219,201,212,244,174,138,209,151,239,108,146,102,199,118,227,235,93,119,124,251,214,161,210,218, +235,167,112,41,23,57,83,173,81,233,114,79,213,163,2,86,133,236,187,155,69,67,172,50,235,80,58,239,78,53,67,88,54,37,199,59,214, +58,110,238,72,63,109,154,201,60,240,238,241,120,71,125,51,120,172,192,15,85,78,175,110,186,97,155,237,242,176,47,25,176,254,70, +10,185,28,182,151,248,234,100,38,35,118,146,214,243,231,247,83,207,255,231,128,192,130,15,31,149,178,208,232,158,217,123,237, +132,61,82,120,135,107,231,249,92,179,8,222,220,161,52,143,221,216,249,253,242,83,115,251,78,143,117,5,190,46,139,75,111,230,220, +126,26,56,95,246,192,121,151,45,38,160,99,230,210,50,24,215,37,71,208,64,204,250,252,153,189,16,59,99,233,145,248,165,66,172, +202,102,51,118,18,227,50,111,102,231,76,118,228,64,62,190,213,134,158,75,58,238,16,146,253,228,135,16,83,176,140,216,14,210,118, +96,143,223,129,61,126,7,246,120,19,15,190,215,35,177,139,2,59,202,246,249,29,187,136,237,34,109,215,70,0,57,188,10,108,160, +234,225,25,86,165,182,219,161,64,114,100,196,206,231,59,250,250,250,168,66,234,235,50,201,125,121,242,38,83,169,28,82,100,38, +199,199,109,39,69,222,61,201,188,189,61,151,33,115,143,24,45,242,140,32,140,200,28,17,177,66,6,223,145,109,242,99,195,31,79,230, +236,68,150,188,234,68,160,64,233,104,160,186,146,158,200,150,78,13,178,70,48,166,174,93,90,140,69,139,156,42,62,32,69,75,233,0, +41,90,100,74,248,84,170,17,45,14,29,153,41,123,36,155,178,169,38,101,239,77,22,50,238,180,201,227,185,25,219,181,41,144,42, +53,165,54,53,227,169,92,61,205,44,171,33,127,42,171,154,76,204,38,131,79,223,17,242,9,129,5,10,77,197,49,25,123,211,118,38,5, +145,41,228,71,73,223,135,204,26,60,138,11,13,47,80,93,10,195,186,150,223,22,84,186,18,233,245,120,149,157,91,199,107,200,11,135, +178,56,37,19,233,65,251,136,112,44,63,49,168,2,134,45,56,37,197,48,240,220,173,118,126,60,235,228,49,200,24,15,94,77,2,7,89,70, +221,69,120,53,216,13,201,7,185,35,153,41,216,100,141,38,243,171,16,145,170,141,54,66,0,150,203,113,107,160,138,81,209,162,161, +180,99,35,82,100,34,79,65,165,36,178,219,17,9,225,81,236,196,91,249,33,149,119,87,143,165,168,122,122,90,58,5,184,81,181,151, +165,201,155,118,82,246,196,230,189,84,145,46,235,161,47,237,168,38,85,164,243,107,39,70,147,133,188,203,91,147,206,139,113,32, +51,157,71,63,93,158,203,165,172,217,151,86,251,55,121,246,103,211,136,131,140,236,167,135,47,53,242,56,201,49,76,169,99,31,94, +157,28,25,181,83,114,58,183,96,149,82,136,27,75,97,88,129,100,41,152,144,192,43,132,228,75,193,227,240,209,208,157,2,26,137, +199,170,35,46,198,163,6,218,186,108,38,147,61,108,167,182,218,169,116,14,53,73,235,84,42,145,149,14,212,48,147,85,141,95,22, +203,174,172,33,122,22,93,213,199,241,118,15,30,11,197,115,17,249,198,139,51,204,53,119,77,210,77,82,168,168,201,138,60,34,82,189, +57,68,58,86,48,85,230,84,24,172,87,211,86,243,14,131,44,101,194,138,229,66,122,174,128,119,231,17,175,85,120,168,246,36,210,99, +54,111,78,5,76,107,178,50,234,168,49,207,3,51,239,242,112,145,29,41,245,158,59,78,197,98,56,207,99,49,153,42,214,98,137,180, +8,12,121,159,163,72,201,178,37,135,113,200,185,71,200,200,143,103,210,46,132,155,204,97,206,33,220,66,158,2,82,138,144,174,44, +233,178,15,193,188,8,32,117,84,152,249,194,158,49,212,224,135,204,139,45,144,66,238,104,249,150,83,205,147,239,220,117,74,198, +178,109,38,12,99,249,34,172,68,122,91,249,203,60,238,104,26,113,194,159,29,125,228,119,209,85,12,211,38,44,223,41,85,197,169, +155,149,251,49,85,184,101,203,177,142,159,3,249,189,217,220,152,157,186,188,44,2,189,216,89,68,11,204,130,35,34,185,226,80,50, +211,81,92,9,198,33,177,76,140,195,57,68,63,105,19,125,116,55,211,190,205,200,27,166,251,249,115,114,217,0,44,60,249,184,102, +156,99,223,100,207,179,231,240,137,219,248,7,54,111,157,55,60,208,203,255,209,211,26,28,78,44,31,76,183,238,30,28,30,188,106,88, +27,111,94,219,118,142,122,252,187,239,101,143,178,91,217,119,217,55,216,99,236,12,187,157,121,195,218,95,180,254,137,137,35,218, +245,215,156,17,133,123,7,6,135,88,164,146,58,217,143,144,75,59,205,221,247,176,191,99,39,216,119,132,247,43,186,231,195,172, +121,112,224,146,3,186,118,11,91,196,152,174,127,128,177,229,39,116,243,17,198,62,57,161,179,195,245,39,116,239,15,89,125,90,59, +212,111,48,195,171,133,251,13,115,120,193,208,130,65,221,248,36,179,6,46,49,140,22,67,51,244,86,157,242,77,3,180,210,63,85, +253,223,179,207,177,79,176,219,240,146,222,57,172,42,138,54,247,106,21,253,109,244,54,122,187,113,249,45,90,111,143,182,179,89, +171,56,252,196,196,181,172,209,242,48,183,189,255,57,214,80,201,234,67,43,126,201,234,171,13,198,171,12,227,216,52,136,107, +115,79,60,126,213,247,250,180,150,31,24,164,237,233,63,215,113,191,102,245,211,29,140,221,205,188,205,168,173,182,71,27,107,254, +105,219,93,43,209,5,202,215,180,182,24,36,180,206,86,250,52,31,222,94,221,250,60,139,183,233,161,211,140,13,245,106,207,80, +143,97,105,151,54,155,214,173,71,244,170,175,51,198,234,171,206,233,225,179,232,180,94,249,41,198,22,156,211,253,7,234,111,215, +43,30,100,245,187,116,223,85,45,187,244,224,71,89,203,144,174,189,200,234,227,204,178,142,60,172,133,118,26,214,74,244,221, +103,4,91,245,64,190,73,115,54,26,1,83,51,125,102,208,180,222,207,90,106,47,106,53,3,116,171,206,39,247,131,226,121,143,120,254, +94,211,222,251,113,12,75,155,78,15,97,172,7,39,218,123,247,107,19,205,3,244,75,62,205,127,208,105,220,88,190,127,160,117,151, +110,30,156,53,208,96,152,116,74,103,31,225,115,167,121,217,15,88,99,80,243,105,187,60,116,138,181,104,1,164,155,140,104,111,116, +121,212,136,118,68,189,90,5,55,96,4,139,74,149,102,66,169,55,68,17,223,41,22,173,144,101,60,209,213,170,132,72,250,163,44, +186,56,218,25,93,143,170,100,134,79,243,203,26,60,197,170,58,73,99,26,157,140,49,252,63,118,204,243,88,173,198,190,95,203,158, +137,61,84,71,6,99,26,50,197,15,121,142,31,243,60,85,103,176,223,212,81,149,233,245,106,44,34,126,68,30,211,166,253,136,180,9, +255,199,234,217,137,216,203,13,90,228,205,6,214,240,251,89,44,242,66,19,139,28,107,247,85,157,156,109,84,189,221,201,170,78, +206,101,85,103,193,83,224,177,46,86,117,166,91,254,125,4,149,125,223,192,101,241,239,183,248,119,4,197,191,225,42,126,119,193, +255,142,139,127,79,82,252,91,46,254,189,66,241,239,185,76,42,253,77,151,110,201,223,193,241,239,98,88,76,254,254,247,49,254,29, +74,76,250,240,223,33,50,171,244,123,69,45,38,223,203,255,6,76,87,254,252,247,120,158,24,137,223,63,241,223,17,146,42,43,126, +247,104,201,182,242,191,55,251,63,108,101,104,241,168,38,0,0,0,0}; #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ METHOD (constructor, "", "()V") \ @@ -193,7 +186,7 @@ DECLARE_JNI_CLASS (StringBuffer, "java/lang/StringBuffer") //============================================================================== #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ - STATICMETHOD (createHTTPStream, "createHTTPStream", "(Ljava/lang/String;Z[BLjava/lang/String;I[ILjava/lang/StringBuffer;ILjava/lang/String;)Lcom/roli/juce/JuceHTTPStream;") \ + STATICMETHOD (createHTTPStream, "createHTTPStream", "(Ljava/lang/String;Z[BLjava/lang/String;I[ILjava/lang/StringBuffer;ILjava/lang/String;)Lcom/rmsl/juce/JuceHTTPStream;") \ METHOD (connect, "connect", "()Z") \ METHOD (release, "release", "()V") \ METHOD (read, "read", "([BI)I") \ @@ -202,7 +195,7 @@ DECLARE_JNI_CLASS (StringBuffer, "java/lang/StringBuffer") METHOD (isExhausted, "isExhausted", "()Z") \ METHOD (setPosition, "setPosition", "(J)Z") \ -DECLARE_JNI_CLASS_WITH_BYTECODE (HTTPStream, "com/roli/juce/JuceHTTPStream", 16, javaJuceHttpStream, sizeof(javaJuceHttpStream)) +DECLARE_JNI_CLASS_WITH_BYTECODE (HTTPStream, "com/rmsl/juce/JuceHTTPStream", 16, javaJuceHttpStream, sizeof(javaJuceHttpStream)) #undef JNI_CLASS_MEMBERS //============================================================================== @@ -213,6 +206,62 @@ DECLARE_JNI_CLASS_WITH_BYTECODE (HTTPStream, "com/roli/juce/JuceHTTPStream", 16, DECLARE_JNI_CLASS (AndroidInputStream, "java/io/InputStream") #undef JNI_CLASS_MEMBERS +//============================================================================== +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ + METHOD (acquire, "acquire", "()V") \ + METHOD (release, "release", "()V") \ + +DECLARE_JNI_CLASS (AndroidMulticastLock, "android/net/wifi/WifiManager$MulticastLock") +#undef JNI_CLASS_MEMBERS + +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ + METHOD (createMulticastLock, "createMulticastLock", "(Ljava/lang/String;)Landroid/net/wifi/WifiManager$MulticastLock;") \ + +DECLARE_JNI_CLASS (AndroidWifiManager, "android/net/wifi/WifiManager") +#undef JNI_CLASS_MEMBERS + +static LocalRef getMulticastLock() +{ + static LocalRef multicastLock; + static bool hasChecked = false; + + if (! hasChecked) + { + hasChecked = true; + + auto* env = getEnv(); + + LocalRef wifiManager (env->CallObjectMethod (getAppContext().get(), + AndroidContext.getSystemService, + javaString ("wifi").get())); + + if (wifiManager != nullptr) + { + multicastLock = LocalRef (env->CallObjectMethod (wifiManager.get(), + AndroidWifiManager.createMulticastLock, + javaString ("JUCE_MulticastLock").get())); + } + } + + return multicastLock; +} + +JUCE_API void JUCE_CALLTYPE acquireMulticastLock() +{ + auto multicastLock = getMulticastLock(); + + if (multicastLock != nullptr) + getEnv()->CallVoidMethod (multicastLock.get(), AndroidMulticastLock.acquire); +} + +JUCE_API void JUCE_CALLTYPE releaseMulticastLock() +{ + auto multicastLock = getMulticastLock(); + + if (multicastLock != nullptr) + getEnv()->CallVoidMethod (multicastLock.get(), AndroidMulticastLock.release); +} + //============================================================================== void MACAddress::findAllAddresses (Array& /*result*/) { @@ -297,7 +346,7 @@ class WebInputStream::Pimpl const ScopedLock lock (createStreamLock); - if (stream != 0) + if (stream != nullptr) { stream.callVoidMethod (HTTPStream.release); stream.clear(); @@ -333,7 +382,7 @@ class WebInputStream::Pimpl if (isPost) WebInputStream::createHeadersAndPostData (url, headers, postData); - jbyteArray postDataArray = 0; + jbyteArray postDataArray = nullptr; if (postData.getSize() > 0) { @@ -348,7 +397,7 @@ class WebInputStream::Pimpl jassert (Thread::getCurrentThread() != nullptr); jintArray statusCodeArray = env->NewIntArray (1); - jassert (statusCodeArray != 0); + jassert (statusCodeArray != nullptr); { const ScopedLock lock (createStreamLock); @@ -367,18 +416,18 @@ class WebInputStream::Pimpl javaString (httpRequest).get()))); } - if (stream != 0 && ! stream.callBooleanMethod (HTTPStream.connect)) + if (stream != nullptr && ! stream.callBooleanMethod (HTTPStream.connect)) stream.clear(); - jint* const statusCodeElements = env->GetIntArrayElements (statusCodeArray, 0); + jint* const statusCodeElements = env->GetIntArrayElements (statusCodeArray, nullptr); statusCode = statusCodeElements[0]; env->ReleaseIntArrayElements (statusCodeArray, statusCodeElements, 0); env->DeleteLocalRef (statusCodeArray); - if (postDataArray != 0) + if (postDataArray != nullptr) env->DeleteLocalRef (postDataArray); - if (stream != 0) + if (stream != nullptr) { StringArray headerLines; @@ -498,7 +547,7 @@ class WebInputStream::Pimpl JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl) }; -URL::DownloadTask* URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool shouldUsePost) +std::unique_ptr URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool shouldUsePost) { return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, extraHeaders, listener, shouldUsePost); } @@ -547,12 +596,12 @@ static Array findIPAddresses (int dummySocket) if (item.ifr_addr.sa_family == AF_INET) { InterfaceInfo info; - info.interfaceAddress = makeAddress ((const sockaddr_in*) &item.ifr_addr); + info.interfaceAddress = makeAddress (reinterpret_cast (&item.ifr_addr)); if (! info.interfaceAddress.isNull()) { if (ioctl (dummySocket, SIOCGIFBRDADDR, &item) == 0) - info.broadcastAddress = makeAddress ((const sockaddr_in*) &item.ifr_broadaddr); + info.broadcastAddress = makeAddress (reinterpret_cast (&item.ifr_broadaddr)); result.add (info); } diff --git a/JuceLibraryCode/modules/juce_core/native/juce_android_RuntimePermissions.cpp b/JuceLibraryCode/modules/juce_core/native/juce_android_RuntimePermissions.cpp index 25f8cb5..8aec477 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_android_RuntimePermissions.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_android_RuntimePermissions.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. @@ -95,7 +95,7 @@ struct PermissionsRequest struct PermissionsOverlay : FragmentOverlay { PermissionsOverlay (CriticalSection& cs) : overlayGuard (cs) {} - ~PermissionsOverlay() {} + ~PermissionsOverlay() override = default; struct PermissionResult { @@ -175,7 +175,7 @@ struct PermissionsOverlay : FragmentOverlay // this code should only be reached for SDKs >= 23, so this method should be // be available - jassert(requestPermissionsMethodID != 0); + jassert(requestPermissionsMethodID != nullptr); env->CallVoidMethod (getNativeHandle(), requestPermissionsMethodID, jPermissionsArray.get (), 0); } diff --git a/JuceLibraryCode/modules/juce_core/native/juce_android_SystemStats.cpp b/JuceLibraryCode/modules/juce_core/native/juce_android_SystemStats.cpp index e22c190..126816f 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_android_SystemStats.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_android_SystemStats.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. @@ -40,14 +40,14 @@ namespace AndroidStatsHelpers DECLARE_JNI_CLASS (JavaLocale, "java/util/Locale") #undef JNI_CLASS_MEMBERS - static inline String getSystemProperty (const String& name) + static String getSystemProperty (const String& name) { return juceString (LocalRef ((jstring) getEnv()->CallStaticObjectMethod (SystemClass, SystemClass.getProperty, javaString (name).get()))); } - static inline String getLocaleValue (bool isRegion) + static String getLocaleValue (bool isRegion) { auto* env = getEnv(); LocalRef locale (env->CallStaticObjectMethod (JavaLocale, JavaLocale.getDefault)); @@ -58,7 +58,7 @@ namespace AndroidStatsHelpers return juceString (LocalRef ((jstring) stringResult)); } - static inline String getAndroidOsBuildValue (const char* fieldName) + static String getAndroidOsBuildValue (const char* fieldName) { return juceString (LocalRef ((jstring) getEnv()->GetStaticObjectField ( AndroidBuild, getEnv()->GetStaticFieldID (AndroidBuild, fieldName, "Ljava/lang/String;")))); diff --git a/JuceLibraryCode/modules/juce_core/native/juce_android_Threads.cpp b/JuceLibraryCode/modules/juce_core/native/juce_android_Threads.cpp index 10859c0..0fad8f3 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_android_Threads.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_android_Threads.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. @@ -71,7 +71,7 @@ extern "C" jint JNIEXPORT JNI_OnLoad (JavaVM* vm, void*) auto* env = getEnv(); // register the initialisation function - auto juceJavaClass = env->FindClass("com/roli/juce/Java"); + auto juceJavaClass = env->FindClass("com/rmsl/juce/Java"); if (juceJavaClass != nullptr) { @@ -83,7 +83,7 @@ extern "C" jint JNIEXPORT JNI_OnLoad (JavaVM* vm, void*) } else { - // com.roli.juce.Java class not found. Apparently this project is a library + // com.rmsl.juce.Java class not found. Apparently this project is a library // or was not generated by the Projucer. That's ok, the user will have to // call Thread::initialiseJUCE manually env->ExceptionClear(); @@ -113,7 +113,7 @@ class JuceActivityWatcher : public ActivityLifecycleCallbacks checkActivityIsMain (androidApkContext); } - ~JuceActivityWatcher() + ~JuceActivityWatcher() override { LocalRef appContext (getAppContext()); diff --git a/JuceLibraryCode/modules/juce_core/native/juce_curl_Network.cpp b/JuceLibraryCode/modules/juce_core/native/juce_curl_Network.cpp index b68dda8..1140c10 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_curl_Network.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_curl_Network.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. @@ -642,7 +642,7 @@ class WebInputStream::Pimpl JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl) }; -URL::DownloadTask* URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool shouldUsePost) +std::unique_ptr URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool shouldUsePost) { return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, extraHeaders, listener, shouldUsePost); } diff --git a/JuceLibraryCode/modules/juce_core/native/juce_linux_CommonFile.cpp b/JuceLibraryCode/modules/juce_core/native/juce_linux_CommonFile.cpp index 8000ddb..4543dd8 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_linux_CommonFile.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_linux_CommonFile.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_core/native/juce_linux_Files.cpp b/JuceLibraryCode/modules/juce_core/native/juce_linux_Files.cpp index d4ab60f..88d9dae 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_linux_Files.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_linux_Files.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. @@ -136,7 +136,8 @@ File File::getSpecialLocation (const SpecialLocationType type) case invokedExecutableFile: if (juce_argv != nullptr && juce_argc > 0) return File (CharPointer_UTF8 (juce_argv[0])); - // deliberate fall-through... + // Falls through + JUCE_FALLTHROUGH case currentExecutableFile: case currentApplicationFile: @@ -144,6 +145,7 @@ File File::getSpecialLocation (const SpecialLocationType type) return juce_getExecutableFile(); #endif // deliberate fall-through if this is not a shared-library + JUCE_FALLTHROUGH case hostApplicationPath: { @@ -207,7 +209,7 @@ bool Process::openDocument (const String& fileName, const String& parameters) cmdString = cmdLines.joinIntoString (" || "); } - const char* const argv[4] = { "/bin/sh", "-c", cmdString.toUTF8(), 0 }; + const char* const argv[4] = { "/bin/sh", "-c", cmdString.toUTF8(), nullptr }; auto cpid = fork(); diff --git a/JuceLibraryCode/modules/juce_core/native/juce_linux_Network.cpp b/JuceLibraryCode/modules/juce_core/native/juce_linux_Network.cpp index 860d2e3..bf9a188 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_linux_Network.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_linux_Network.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,14 +25,15 @@ namespace juce void MACAddress::findAllAddresses (Array& result) { - const int s = socket (AF_INET, SOCK_DGRAM, 0); + auto s = socket (AF_INET, SOCK_DGRAM, 0); + if (s != -1) { struct ifaddrs* addrs = nullptr; if (getifaddrs (&addrs) != -1) { - for (struct ifaddrs* i = addrs; i != nullptr; i = i->ifa_next) + for (auto* i = addrs; i != nullptr; i = i->ifa_next) { struct ifreq ifr; strcpy (ifr.ifr_name, i->ifa_name); @@ -69,7 +70,7 @@ bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& /* targetEma class WebInputStream::Pimpl { public: - Pimpl (WebInputStream& pimplOwner, const URL& urlToCopy, const bool shouldUsePost) + Pimpl (WebInputStream& pimplOwner, const URL& urlToCopy, bool shouldUsePost) : owner (pimplOwner), url (urlToCopy), isPost (shouldUsePost), httpRequestCmd (shouldUsePost ? "POST" : "GET") {} @@ -95,19 +96,21 @@ class WebInputStream::Pimpl void withCustomRequestCommand (const String& customRequestCommand) { httpRequestCmd = customRequestCommand; } void withConnectionTimeout (int timeoutInMs) { timeOutMs = timeoutInMs; } void withNumRedirectsToFollow (int maxRedirectsToFollow) { numRedirectsToFollow = maxRedirectsToFollow; } + int getStatusCode() const { return statusCode; } StringPairArray getRequestHeaders() const { return WebInputStream::parseHttpHeaders (headers); } StringPairArray getResponseHeaders() const { StringPairArray responseHeaders; + if (! isError()) { for (int i = 0; i < headerLines.size(); ++i) { - const String& headersEntry = headerLines[i]; - const String key (headersEntry.upToFirstOccurrenceOf (": ", false, false)); - const String value (headersEntry.fromFirstOccurrenceOf (": ", false, false)); - const String previousValue (responseHeaders [key]); + auto& headersEntry = headerLines[i]; + auto key = headersEntry.upToFirstOccurrenceOf (": ", false, false); + auto value = headersEntry.fromFirstOccurrenceOf (": ", false, false); + auto previousValue = responseHeaders[key]; responseHeaders.set (key, previousValue.isEmpty() ? value : (previousValue + "," + value)); } } @@ -115,8 +118,6 @@ class WebInputStream::Pimpl return responseHeaders; } - int getStatusCode() const { return statusCode; } - bool connect (WebInputStream::Listener* listener) { { @@ -129,7 +130,7 @@ class WebInputStream::Pimpl address = url.toString (! isPost); statusCode = createConnection (listener, numRedirectsToFollow); - return (statusCode != 0); + return statusCode != 0; } void cancel() @@ -137,7 +138,6 @@ class WebInputStream::Pimpl const ScopedLock lock (createSocketLock); hasBeenCancelled = true; - statusCode = -1; finished = true; @@ -190,7 +190,7 @@ class WebInputStream::Pimpl chunkLengthBuffer.writeByte (c); } - const int64 chunkSize = chunkLengthBuffer.toString().trimStart().getHexValue64(); + auto chunkSize = chunkLengthBuffer.toString().trimStart().getHexValue64(); if (chunkSize == 0) { @@ -205,18 +205,13 @@ class WebInputStream::Pimpl bytesToRead = static_cast (chunkEnd - position); } - fd_set readbits; - FD_ZERO (&readbits); - FD_SET (socketHandle, &readbits); + pollfd pfd { socketHandle, POLLIN, 0 }; - struct timeval tv; - tv.tv_sec = jmax (1, timeOutMs / 1000); - tv.tv_usec = 0; + if (poll (&pfd, 1, timeOutMs) <= 0) + return 0; // (timeout) - if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0) - return 0; // (timeout) + auto bytesRead = jmax (0, (int) recv (socketHandle, buffer, (size_t) bytesToRead, MSG_WAITALL)); - const int bytesRead = jmax (0, (int) recv (socketHandle, buffer, (size_t) bytesToRead, MSG_WAITALL)); if (bytesRead == 0) finished = true; @@ -238,7 +233,7 @@ class WebInputStream::Pimpl if (wantedPos < position) return false; - int64 numBytesToSkip = wantedPos - position; + auto numBytesToSkip = wantedPos - position; auto skipBufferSize = (int) jmin (numBytesToSkip, (int64) 16384); HeapBlock temp (skipBufferSize); @@ -286,14 +281,14 @@ class WebInputStream::Pimpl levelsOfRedirection = 0; } - int createConnection (WebInputStream::Listener* listener, const int numRedirects) + int createConnection (WebInputStream::Listener* listener, int numRedirects) { closeSocket (false); if (isPost) WebInputStream::createHeadersAndPostData (url, headers, postData); - uint32 timeOutTime = Time::getMillisecondCounter(); + auto timeOutTime = Time::getMillisecondCounter(); if (timeOutMs == 0) timeOutMs = 30000; @@ -305,6 +300,7 @@ class WebInputStream::Pimpl String hostName, hostPath; int hostPort; + if (! decomposeURL (address, hostName, hostPath, hostPort)) return 0; @@ -312,7 +308,8 @@ class WebInputStream::Pimpl int proxyPort = 0; int port = 0; - const String proxyURL (getenv ("http_proxy")); + auto proxyURL = String::fromUTF8 (getenv ("http_proxy")); + if (proxyURL.startsWithIgnoreCase ("http://")) { if (! decomposeURL (proxyURL, proxyName, proxyPath, proxyPort)) @@ -335,7 +332,8 @@ class WebInputStream::Pimpl hints.ai_flags = AI_NUMERICSERV; struct addrinfo* result = nullptr; - if (getaddrinfo (serverName.toUTF8(), String (port).toUTF8(), &hints, &result) != 0 || result == 0) + + if (getaddrinfo (serverName.toUTF8(), String (port).toUTF8(), &hints, &result) != 0 || result == nullptr) return 0; { @@ -353,7 +351,7 @@ class WebInputStream::Pimpl int receiveBufferSize = 16384; setsockopt (socketHandle, SOL_SOCKET, SO_RCVBUF, (char*) &receiveBufferSize, sizeof (receiveBufferSize)); - setsockopt (socketHandle, SOL_SOCKET, SO_KEEPALIVE, 0, 0); + setsockopt (socketHandle, SOL_SOCKET, SO_KEEPALIVE, nullptr, 0); #if JUCE_MAC setsockopt (socketHandle, SOL_SOCKET, SO_NOSIGPIPE, 0, 0); @@ -379,17 +377,17 @@ class WebInputStream::Pimpl } } - String responseHeader (readResponse (timeOutTime)); + auto responseHeader = readResponse (timeOutTime); position = 0; if (responseHeader.isNotEmpty()) { headerLines = StringArray::fromLines (responseHeader); - const int status = responseHeader.fromFirstOccurrenceOf (" ", false, false) - .substring (0, 3).getIntValue(); + auto status = responseHeader.fromFirstOccurrenceOf (" ", false, false) + .substring (0, 3).getIntValue(); - String location (findHeaderItem (headerLines, "Location:")); + auto location = findHeaderItem (headerLines, "Location:"); if (++levelsOfRedirection <= numRedirects && status >= 300 && status < 400 @@ -410,7 +408,7 @@ class WebInputStream::Pimpl return createConnection (listener, numRedirects); } - String contentLengthString (findHeaderItem (headerLines, "Content-Length:")); + auto contentLengthString = findHeaderItem (headerLines, "Content-Length:"); if (contentLengthString.isNotEmpty()) contentLength = contentLengthString.getLargeIntValue(); @@ -425,7 +423,7 @@ class WebInputStream::Pimpl } //============================================================================== - String readResponse (const uint32 timeOutTime) + String readResponse (uint32 timeOutTime) { int numConsecutiveLFs = 0; MemoryOutputStream buffer; @@ -436,6 +434,7 @@ class WebInputStream::Pimpl && ! (finished || isError())) { char c = 0; + if (read (&c, 1) != 1) return {}; @@ -447,7 +446,7 @@ class WebInputStream::Pimpl numConsecutiveLFs = 0; } - const String header (buffer.toString().trimEnd()); + auto header = buffer.toString().trimEnd(); if (header.startsWithIgnoreCase ("HTTP/")) return header; @@ -471,11 +470,11 @@ class WebInputStream::Pimpl dest << ':' << port; } - static MemoryBlock createRequestHeader (const String& hostName, const int hostPort, - const String& proxyName, const int proxyPort, + static MemoryBlock createRequestHeader (const String& hostName, int hostPort, + const String& proxyName, int proxyPort, const String& hostPath, const String& originalURL, const String& userHeaders, const MemoryBlock& postData, - const bool isPost, const String& httpRequestCmd) + bool isPost, const String& httpRequestCmd) { MemoryOutputStream header; @@ -503,7 +502,7 @@ class WebInputStream::Pimpl return header.getMemoryBlock(); } - static bool sendHeader (int socketHandle, const MemoryBlock& requestHeader, const uint32 timeOutTime, + static bool sendHeader (int socketHandle, const MemoryBlock& requestHeader, uint32 timeOutTime, WebInputStream& pimplOwner, WebInputStream::Listener* listener) { size_t totalHeaderSent = 0; @@ -513,7 +512,7 @@ class WebInputStream::Pimpl if (Time::getMillisecondCounter() > timeOutTime) return false; - const int numToSend = jmin (1024, (int) (requestHeader.getSize() - totalHeaderSent)); + auto numToSend = jmin (1024, (int) (requestHeader.getSize() - totalHeaderSent)); if (send (socketHandle, static_cast (requestHeader.getData()) + totalHeaderSent, (size_t) numToSend, 0) != numToSend) return false; @@ -532,8 +531,9 @@ class WebInputStream::Pimpl if (! url.startsWithIgnoreCase ("http://")) return false; - const int nextSlash = url.indexOfChar (7, '/'); - int nextColon = url.indexOfChar (7, ':'); + auto nextSlash = url.indexOfChar (7, '/'); + auto nextColon = url.indexOfChar (7, ':'); + if (nextColon > nextSlash && nextSlash > 0) nextColon = -1; @@ -576,7 +576,7 @@ class WebInputStream::Pimpl JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl) }; -URL::DownloadTask* URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool shouldUsePost) +std::unique_ptr URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool shouldUsePost) { return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, extraHeaders, listener, shouldUsePost); } diff --git a/JuceLibraryCode/modules/juce_core/native/juce_linux_SystemStats.cpp b/JuceLibraryCode/modules/juce_core/native/juce_linux_SystemStats.cpp index 77cf4f6..5860c58 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_linux_SystemStats.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_linux_SystemStats.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. @@ -20,6 +20,10 @@ ============================================================================== */ +#if JUCE_BELA +extern "C" int cobalt_thread_mode(); +#endif + namespace juce { @@ -50,7 +54,7 @@ bool SystemStats::isOperatingSystem64Bit() } //============================================================================== -static inline String getCpuInfo (const char* key) +static String getCpuInfo (const char* key) { return readPosixConfigFileValue ("/proc/cpuinfo", key); } @@ -103,11 +107,11 @@ int SystemStats::getPageSize() //============================================================================== String SystemStats::getLogonName() { - if (const char* user = getenv ("USER")) - return CharPointer_UTF8 (user); + if (auto user = getenv ("USER")) + return String::fromUTF8 (user); - if (struct passwd* const pw = getpwuid (getuid())) - return CharPointer_UTF8 (pw->pw_name); + if (auto pw = getpwuid (getuid())) + return String::fromUTF8 (pw->pw_name); return {}; } @@ -119,7 +123,8 @@ String SystemStats::getFullUserName() String SystemStats::getComputerName() { - char name [256] = { 0 }; + char name[256] = {}; + if (gethostname (name, sizeof (name) - 1) == 0) return name; @@ -128,21 +133,24 @@ String SystemStats::getComputerName() static String getLocaleValue (nl_item key) { - const char* oldLocale = ::setlocale (LC_ALL, ""); - String result (String::fromUTF8 (nl_langinfo (key))); + auto oldLocale = ::setlocale (LC_ALL, ""); + auto result = String::fromUTF8 (nl_langinfo (key)); ::setlocale (LC_ALL, oldLocale); return result; } -String SystemStats::getUserLanguage() { return getLocaleValue (_NL_IDENTIFICATION_LANGUAGE); } -String SystemStats::getUserRegion() { return getLocaleValue (_NL_IDENTIFICATION_TERRITORY); } -String SystemStats::getDisplayLanguage() { return getUserLanguage() + "-" + getUserRegion(); } +String SystemStats::getUserLanguage() { return getLocaleValue (_NL_IDENTIFICATION_LANGUAGE); } +String SystemStats::getUserRegion() { return getLocaleValue (_NL_IDENTIFICATION_TERRITORY); } +String SystemStats::getDisplayLanguage() { return getUserLanguage() + "-" + getUserRegion(); } //============================================================================== void CPUInformation::initialise() noexcept { auto flags = getCpuInfo ("flags"); + hasMMX = flags.contains ("mmx"); + hasFMA3 = flags.contains ("fma"); + hasFMA4 = flags.contains ("fma4"); hasSSE = flags.contains ("sse"); hasSSE2 = flags.contains ("sse2"); hasSSE3 = flags.contains ("sse3"); @@ -175,16 +183,21 @@ void CPUInformation::initialise() noexcept //============================================================================== uint32 juce_millisecondsSinceStartup() noexcept { - timespec t; - clock_gettime (CLOCK_MONOTONIC, &t); - - return (uint32) (t.tv_sec * 1000 + t.tv_nsec / 1000000); + return (uint32) (Time::getHighResolutionTicks() / 1000); } int64 Time::getHighResolutionTicks() noexcept { timespec t; + + #if JUCE_BELA + if (cobalt_thread_mode() == 0x200 /*XNRELAX*/) + clock_gettime (CLOCK_MONOTONIC, &t); + else + __wrap_clock_gettime (CLOCK_MONOTONIC, &t); + #else clock_gettime (CLOCK_MONOTONIC, &t); + #endif return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000); } @@ -196,7 +209,7 @@ int64 Time::getHighResolutionTicksPerSecond() noexcept double Time::getMillisecondCounterHiRes() noexcept { - return getHighResolutionTicks() * 0.001; + return (double) getHighResolutionTicks() * 0.001; } bool Time::setSystemTimeToThisTime() const @@ -205,7 +218,7 @@ bool Time::setSystemTimeToThisTime() const t.tv_sec = millisSinceEpoch / 1000; t.tv_usec = (millisSinceEpoch - t.tv_sec * 1000) * 1000; - return settimeofday (&t, 0) == 0; + return settimeofday (&t, nullptr) == 0; } JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger() noexcept @@ -213,8 +226,7 @@ JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger() noexcept #if JUCE_BSD return false; #else - return readPosixConfigFileValue ("/proc/self/status", "TracerPid") - .getIntValue() > 0; + return readPosixConfigFileValue ("/proc/self/status", "TracerPid").getIntValue() > 0; #endif } diff --git a/JuceLibraryCode/modules/juce_core/native/juce_linux_Threads.cpp b/JuceLibraryCode/modules/juce_core/native/juce_linux_Threads.cpp index 65ce6da..d8eff20 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_linux_Threads.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_linux_Threads.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. @@ -31,9 +31,9 @@ namespace juce //============================================================================== JUCE_API void JUCE_CALLTYPE Process::setPriority (const ProcessPriority prior) { - const int policy = (prior <= NormalPriority) ? SCHED_OTHER : SCHED_RR; - const int minp = sched_get_priority_min (policy); - const int maxp = sched_get_priority_max (policy); + auto policy = (prior <= NormalPriority) ? SCHED_OTHER : SCHED_RR; + auto minp = sched_get_priority_min (policy); + auto maxp = sched_get_priority_max (policy); struct sched_param param; @@ -51,8 +51,8 @@ JUCE_API void JUCE_CALLTYPE Process::setPriority (const ProcessPriority prior) static bool swapUserAndEffectiveUser() { - int result1 = setreuid (geteuid(), getuid()); - int result2 = setregid (getegid(), getgid()); + auto result1 = setreuid (geteuid(), getuid()); + auto result2 = setregid (getegid(), getgid()); return result1 == 0 && result2 == 0; } diff --git a/JuceLibraryCode/modules/juce_core/native/juce_mac_ClangBugWorkaround.h b/JuceLibraryCode/modules/juce_core/native/juce_mac_ClangBugWorkaround.h index b4ab1fe..1c9b0ce 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_mac_ClangBugWorkaround.h +++ b/JuceLibraryCode/modules/juce_core/native/juce_mac_ClangBugWorkaround.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,10 +20,10 @@ ============================================================================== */ - -// 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__)) + + // 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.. #include #undef CF_OPTIONS #define CF_OPTIONS(_type, _name) _type _name; enum @@ -32,4 +32,10 @@ // in the live-build engine. #define _Nullable #define _Nonnull + + // A workaround for compiling the 10.15 headers with an older compiler version + #undef API_UNAVAILABLE_BEGIN + #define API_UNAVAILABLE_BEGIN(...) + #undef API_UNAVAILABLE_END + #define API_UNAVAILABLE_END #endif diff --git a/JuceLibraryCode/modules/juce_core/native/juce_mac_Files.mm b/JuceLibraryCode/modules/juce_core/native/juce_mac_Files.mm index e4515c1..965dfda 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_mac_Files.mm +++ b/JuceLibraryCode/modules/juce_core/native/juce_mac_Files.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. @@ -36,15 +36,9 @@ NSFileManager* fm = [NSFileManager defaultManager]; return [fm fileExistsAtPath: juceStringToNS (fullPath)] - #if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 && [fm copyItemAtPath: juceStringToNS (fullPath) toPath: juceStringToNS (dest.getFullPathName()) error: nil]; - #else - && [fm copyPath: juceStringToNS (fullPath) - toPath: juceStringToNS (dest.getFullPathName()) - handler: nil]; - #endif } } @@ -75,7 +69,7 @@ static bool isFileOnDriveType (const File& f, const char* const* types) static bool isHiddenFile (const String& path) { - #if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 + #if JUCE_MAC JUCE_AUTORELEASEPOOL { NSNumber* hidden = nil; @@ -84,15 +78,8 @@ static bool isHiddenFile (const String& path) return [createNSURLFromFile (path) getResourceValue: &hidden forKey: NSURLIsHiddenKey error: &err] && [hidden boolValue]; } - #elif JUCE_IOS - return File (path).getFileName().startsWithChar ('.'); #else - FSRef ref; - LSItemInfoRecord info; - - return FSPathMakeRefWithOptions ((const UInt8*) path.toRawUTF8(), kFSPathMakeRefDoNotFollowLeafSymlink, &ref, 0) == noErr - && LSCopyItemInfoForRef (&ref, kLSRequestBasicFlagsOnly, &info) == noErr - && (info.flags & kLSItemInfoIsInvisible) != 0; + return File (path).getFileName().startsWithChar ('.'); #endif } @@ -216,6 +203,7 @@ static bool launchExecutable (const String& pathAndArguments) if (juce_argv != nullptr && juce_argc > 0) return File::getCurrentWorkingDirectory().getChildFile (String (juce_argv[0])); // deliberate fall-through... + JUCE_FALLTHROUGH case currentExecutableFile: return juce_getExecutableFile(); @@ -428,10 +416,7 @@ bool next (String& filenameFound, NSWorkspace* workspace = [NSWorkspace sharedWorkspace]; if (parameters.isEmpty()) - // NB: the length check here is because of strange failures involving long filenames, - // probably due to filesystem name length limitations.. - return (fileName.length() < 1024 && [workspace openFile: juceStringToNS (fileName)]) - || [workspace openURL: filenameAsURL]; + return [workspace openURL: filenameAsURL]; const File file (fileName); diff --git a/JuceLibraryCode/modules/juce_core/native/juce_mac_Network.mm b/JuceLibraryCode/modules/juce_core/native/juce_mac_Network.mm index aeb4c54..1357244 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_mac_Network.mm +++ b/JuceLibraryCode/modules/juce_core/native/juce_mac_Network.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. @@ -110,7 +110,7 @@ //============================================================================== // Unfortunately, we need to have this ugly ifdef here as long as some older OS X versions do not support NSURLSession -#if JUCE_IOS || (defined (__MAC_OS_X_VERSION_MIN_REQUIRED) && defined (__MAC_10_10) && __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_10) +#if JUCE_IOS || (defined (MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10) //============================================================================== class URLConnectionState : private Thread @@ -192,11 +192,11 @@ int read (char* dest, int numBytes) while (numBytes > 0) { - const int available = jmin (numBytes, (int) [data length]); + const ScopedLock sl (dataLock); + auto available = jmin (numBytes, (int) [data length]); if (available > 0) { - const ScopedLock sl (dataLock); [data getBytes: dest length: (NSUInteger) available]; [data replaceBytesInRange: NSMakeRange (0, (NSUInteger) available) withBytes: nil length: 0]; @@ -209,6 +209,7 @@ int read (char* dest, int numBytes) if (hasFailed || hasFinished) break; + const ScopedUnlock ul (dataLock); Thread::sleep (1); } } @@ -331,8 +332,8 @@ void run() override NSMutableData* data = nil; NSDictionary* headers = nil; int statusCode = 0; - std::atomic initialised { false }; - bool hasFailed = false, hasFinished = false, isBeingDeleted = false; + std::atomic initialised { false }, hasFailed { false }, hasFinished { false }; + bool isBeingDeleted = false; const int numRedirectsToFollow; int numRedirects = 0; int64 latestTotalBytes = 0; @@ -425,7 +426,8 @@ static void didCompleteWithError (id self, SEL, NSURLConnection*, NSURLSessionTa DelegateClass::setState (delegate, this); activeSessions.set (uniqueIdentifier, this); - NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:juceStringToNS (urlToUse.toString (true))]]; + auto nsUrl = [NSURL URLWithString: juceStringToNS (urlToUse.toString (true))]; + NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL: nsUrl]; if (shouldUsePostRequest) [request setHTTPMethod: @"POST"]; @@ -646,12 +648,12 @@ static void didBecomeInvalidWithError (id self, SEL, NSURLSession*, NSURLSession HashMap BackgroundDownloadTask::activeSessions; -URL::DownloadTask* URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool usePostRequest) +std::unique_ptr URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool usePostRequest) { std::unique_ptr downloadTask (new BackgroundDownloadTask (*this, targetLocation, extraHeaders, listener, usePostRequest)); if (downloadTask->initOK() && downloadTask->connect()) - return downloadTask.release(); + return downloadTask; return nullptr; } @@ -661,7 +663,7 @@ static void didBecomeInvalidWithError (id self, SEL, NSURLSession*, NSURLSession BackgroundDownloadTask::invokeNotify (identifier); } #else -URL::DownloadTask* URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool usePost) +std::unique_ptr URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool usePost) { return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, extraHeaders, listener, usePost); } @@ -674,8 +676,7 @@ static void didBecomeInvalidWithError (id self, SEL, NSURLSession*, NSURLSession // so we'll turn off deprecation warnings. This code will be removed at some point // in the future. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated" +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated") //============================================================================== class URLConnectionState : public Thread @@ -692,7 +693,7 @@ static void didBecomeInvalidWithError (id self, SEL, NSURLSession*, NSURLSession DelegateClass::setState (delegate, this); } - ~URLConnectionState() + ~URLConnectionState() override { stop(); @@ -746,11 +747,11 @@ int read (char* dest, int numBytes) while (numBytes > 0) { - const int available = jmin (numBytes, (int) [data length]); + const ScopedLock sl (dataLock); + auto available = jmin (numBytes, (int) [data length]); if (available > 0) { - const ScopedLock sl (dataLock); [data getBytes: dest length: (NSUInteger) available]; [data replaceBytesInRange: NSMakeRange (0, (NSUInteger) available) withBytes: nil length: 0]; @@ -763,6 +764,7 @@ int read (char* dest, int numBytes) if (hasFailed || hasFinished) break; + const ScopedUnlock sul (dataLock); Thread::sleep (1); } } @@ -927,12 +929,12 @@ static void connectionDidFinishLoading (id self, SEL, NSURLConnection*) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (URLConnectionState) }; -URL::DownloadTask* URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool shouldUsePost) +std::unique_ptr URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool shouldUsePost) { return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, extraHeaders, listener, shouldUsePost); } -#pragma clang diagnostic pop +JUCE_END_IGNORE_WARNINGS_GCC_LIKE #endif @@ -965,10 +967,13 @@ bool connect (WebInputStream::Listener* webInputListener, int numRetries = 0) createConnection(); } + if (connection == nullptr) + return false; + if (! connection->start (owner, webInputListener)) { // Workaround for deployment targets below 10.10 where HTTPS POST requests with keep-alive fail with the NSURLErrorNetworkConnectionLost error code. - #if ! (JUCE_IOS || (defined (__MAC_OS_X_VERSION_MIN_REQUIRED) && defined (__MAC_10_10) && __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_10)) + #if ! (JUCE_IOS || (defined (MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10)) if (numRetries == 0 && connection->nsUrlErrorCode == NSURLErrorNetworkConnectionLost) { connection.reset(); @@ -980,7 +985,7 @@ bool connect (WebInputStream::Listener* webInputListener, int numRetries = 0) return false; } - if (connection != nullptr && connection->headers != nil) + if (connection->headers != nil) { statusCode = connection->statusCode; diff --git a/JuceLibraryCode/modules/juce_core/native/juce_mac_Strings.mm b/JuceLibraryCode/modules/juce_core/native/juce_mac_Strings.mm index a83bf31..e3ee9e4 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_mac_Strings.mm +++ b/JuceLibraryCode/modules/juce_core/native/juce_mac_Strings.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_core/native/juce_mac_SystemStats.mm b/JuceLibraryCode/modules/juce_core/native/juce_mac_SystemStats.mm index 195a3e9..750be11 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_mac_SystemStats.mm +++ b/JuceLibraryCode/modules/juce_core/native/juce_mac_SystemStats.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. @@ -81,10 +81,14 @@ static void doCPUID (uint32& a, uint32& b, uint32& c, uint32& d, uint32 type) has3DNow = (b & (1u << 31)) != 0; hasSSE3 = (c & (1u << 0)) != 0; hasSSSE3 = (c & (1u << 9)) != 0; + hasFMA3 = (c & (1u << 12)) != 0; hasSSE41 = (c & (1u << 19)) != 0; hasSSE42 = (c & (1u << 20)) != 0; hasAVX = (c & (1u << 28)) != 0; + SystemStatsHelpers::doCPUID (a, b, c, d, 0x80000001); + hasFMA4 = (c & (1u << 16)) != 0; + SystemStatsHelpers::doCPUID (a, b, c, d, 7); hasAVX2 = (b & (1u << 5)) != 0; hasAVX512F = (b & (1u << 16)) != 0; @@ -159,11 +163,28 @@ static String getOSXVersion() #endif size_t size; + if (sysctlbyname (name, nullptr, &size, nullptr, 0) >= 0) { HeapBlock model (size); - if (sysctlbyname (name, model, &size, nullptr, 0) >= 0) - return model.get(); + + if (sysctlbyname (name, model, &size, nullptr, 0) >= 0) + { + String description (model.get()); + + #if JUCE_IOS + if (description == "x86_64") // running in the simulator + { + if (auto* userInfo = [[NSProcessInfo processInfo] environment]) + { + if (auto* simDeviceName = [userInfo objectForKey: @"SIMULATOR_DEVICE_NAME"]) + return nsStringToJuce (simDeviceName); + } + } + #endif + + return description; + } } return {}; diff --git a/JuceLibraryCode/modules/juce_core/native/juce_mac_Threads.mm b/JuceLibraryCode/modules/juce_core/native/juce_mac_Threads.mm index bdf9e2f..e4972d9 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_mac_Threads.mm +++ b/JuceLibraryCode/modules/juce_core/native/juce_mac_Threads.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. @@ -65,20 +65,10 @@ } } -JUCE_API void JUCE_CALLTYPE Process::raisePrivilege() -{ - jassertfalse; -} +JUCE_API void JUCE_CALLTYPE Process::raisePrivilege() {} +JUCE_API void JUCE_CALLTYPE Process::lowerPrivilege() {} -JUCE_API void JUCE_CALLTYPE Process::lowerPrivilege() -{ - jassertfalse; -} - -JUCE_API void JUCE_CALLTYPE Process::setPriority (ProcessPriority) -{ - // xxx -} +JUCE_API void JUCE_CALLTYPE Process::setPriority (ProcessPriority) {} //============================================================================== JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger() noexcept diff --git a/JuceLibraryCode/modules/juce_core/native/juce_osx_ObjCHelpers.h b/JuceLibraryCode/modules/juce_core/native/juce_osx_ObjCHelpers.h index edb637e..b651e11 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_osx_ObjCHelpers.h +++ b/JuceLibraryCode/modules/juce_core/native/juce_osx_ObjCHelpers.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,37 +27,37 @@ namespace juce { //============================================================================== -static inline String nsStringToJuce (NSString* s) +inline String nsStringToJuce (NSString* s) { return CharPointer_UTF8 ([s UTF8String]); } -static inline NSString* juceStringToNS (const String& s) +inline NSString* juceStringToNS (const String& s) { return [NSString stringWithUTF8String: s.toUTF8()]; } -static inline NSString* nsStringLiteral (const char* const s) noexcept +inline NSString* nsStringLiteral (const char* const s) noexcept { return [NSString stringWithUTF8String: s]; } -static inline NSString* nsEmptyString() noexcept +inline NSString* nsEmptyString() noexcept { return [NSString string]; } -static inline NSURL* createNSURLFromFile (const String& f) +inline NSURL* createNSURLFromFile (const String& f) { return [NSURL fileURLWithPath: juceStringToNS (f)]; } -static inline NSURL* createNSURLFromFile (const File& f) +inline NSURL* createNSURLFromFile (const File& f) { return createNSURLFromFile (f.getFullPathName()); } -static inline NSArray* createNSArrayFromStringArray (const StringArray& strings) +inline NSArray* createNSArrayFromStringArray (const StringArray& strings) { auto array = [[NSMutableArray alloc] init]; @@ -67,9 +67,9 @@ static inline NSArray* createNSArrayFromStringArray (const StringArray& strings) return [array autorelease]; } -static NSArray* varArrayToNSArray (const var& varToParse); +inline NSArray* varArrayToNSArray (const var& varToParse); -static NSDictionary* varObjectToNSDictionary (const var& varToParse) +inline NSDictionary* varObjectToNSDictionary (const var& varToParse) { auto dictionary = [NSMutableDictionary dictionary]; @@ -109,7 +109,7 @@ static NSDictionary* varObjectToNSDictionary (const var& varToParse) return dictionary; } -static NSArray* varArrayToNSArray (const var& varToParse) +inline NSArray* varArrayToNSArray (const var& varToParse) { jassert (varToParse.isArray()); @@ -145,9 +145,9 @@ static NSArray* varArrayToNSArray (const var& varToParse) return array; } -static var nsObjectToVar (NSObject* array); +var nsObjectToVar (NSObject* array); -static var nsDictionaryToVar (NSDictionary* dictionary) +inline var nsDictionaryToVar (NSDictionary* dictionary) { DynamicObject::Ptr dynamicObject (new DynamicObject()); @@ -157,7 +157,7 @@ static var nsDictionaryToVar (NSDictionary* dictionary) return var (dynamicObject.get()); } -static var nsArrayToVar (NSArray* array) +inline var nsArrayToVar (NSArray* array) { Array resultArray; @@ -167,7 +167,7 @@ static var nsArrayToVar (NSArray* array) return var (resultArray); } -static var nsObjectToVar (NSObject* obj) +inline var nsObjectToVar (NSObject* obj) { if ([obj isKindOfClass: [NSString class]]) return nsStringToJuce ((NSString*) obj); else if ([obj isKindOfClass: [NSNumber class]]) return nsStringToJuce ([(NSNumber*) obj stringValue]); @@ -184,7 +184,7 @@ static var nsObjectToVar (NSObject* obj) #if JUCE_MAC template -static NSRect makeNSRect (const RectangleType& r) noexcept +NSRect makeNSRect (const RectangleType& r) noexcept { return NSMakeRect (static_cast (r.getX()), static_cast (r.getY()), @@ -198,7 +198,7 @@ static NSRect makeNSRect (const RectangleType& r) noexcept // depending on the argument type. The re-cast objc_msgSendSuper to a function // take the same arguments as the target method. template -static inline ReturnValue ObjCMsgSendSuper (struct objc_super* s, SEL sel, Params... params) +ReturnValue ObjCMsgSendSuper (struct objc_super* s, SEL sel, Params... params) { using SuperFn = ReturnValue (*)(struct objc_super*, SEL, Params...); SuperFn fn = reinterpret_cast (objc_msgSendSuper); @@ -207,11 +207,11 @@ static inline ReturnValue ObjCMsgSendSuper (struct objc_super* s, SEL sel, Param // These hacks are a workaround for newer Xcode builds which by default prevent calls to these objc functions.. typedef id (*MsgSendSuperFn) (struct objc_super*, SEL, ...); -static inline MsgSendSuperFn getMsgSendSuperFn() noexcept { return (MsgSendSuperFn) (void*) objc_msgSendSuper; } +inline MsgSendSuperFn getMsgSendSuperFn() noexcept { return (MsgSendSuperFn) (void*) objc_msgSendSuper; } #if ! JUCE_IOS typedef double (*MsgSendFPRetFn) (id, SEL op, ...); -static inline MsgSendFPRetFn getMsgSendFPRetFn() noexcept { return (MsgSendFPRetFn) (void*) objc_msgSend_fpret; } +inline MsgSendFPRetFn getMsgSendFPRetFn() noexcept { return (MsgSendFPRetFn) (void*) objc_msgSend_fpret; } #endif #endif @@ -323,10 +323,9 @@ struct ObjCLifetimeManagedClass : public ObjCClass { addIvar ("cppObject"); - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wundeclared-selector" + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector") addMethod (@selector (initWithJuceObject:), initWithJuceObject, "@@:@"); - #pragma clang diagnostic pop + JUCE_END_IGNORE_WARNINGS_GCC_LIKE addMethod (@selector (dealloc), dealloc, "v@:"); @@ -370,10 +369,9 @@ ObjCLifetimeManagedClass ObjCLifetimeManagedClass::objCLifetimeMan template NSObject* createNSObjectFromJuceClass (Class* obj) { - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wobjc-method-access" + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wobjc-method-access") return [ObjCLifetimeManagedClass::objCLifetimeManagedClass.createInstance() initWithJuceObject:obj]; - #pragma clang diagnostic pop + JUCE_END_IGNORE_WARNINGS_GCC_LIKE } // Get the JUCE class instance that was tied to the life-time of an NSObject with the @@ -412,5 +410,19 @@ class ObjCBlock BlockType block; }; +struct ScopedCFString +{ + ScopedCFString() = default; + ScopedCFString (String s) : cfString (s.toCFString()) {} + + ~ScopedCFString() noexcept + { + if (cfString != nullptr) + CFRelease (cfString); + } + + CFStringRef cfString = {}; +}; + } // namespace juce diff --git a/JuceLibraryCode/modules/juce_core/native/juce_posix_IPAddress.h b/JuceLibraryCode/modules/juce_core/native/juce_posix_IPAddress.h index b72d5c3..f87bf35 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_posix_IPAddress.h +++ b/JuceLibraryCode/modules/juce_core/native/juce_posix_IPAddress.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_core/native/juce_posix_NamedPipe.cpp b/JuceLibraryCode/modules/juce_core/native/juce_posix_NamedPipe.cpp index 379ae07..98e6132 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_posix_NamedPipe.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_posix_NamedPipe.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. @@ -172,15 +172,8 @@ class NamedPipe::Pimpl static void waitForInput (int handle, int timeoutMsecs) noexcept { - struct timeval timeout; - timeout.tv_sec = timeoutMsecs / 1000; - timeout.tv_usec = (timeoutMsecs % 1000) * 1000; - - fd_set rset; - FD_ZERO (&rset); - FD_SET (handle, &rset); - - select (handle + 1, &rset, nullptr, nullptr, &timeout); + pollfd pfd { handle, POLLIN, 0 }; + poll (&pfd, 1, timeoutMsecs); } JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl) diff --git a/JuceLibraryCode/modules/juce_core/native/juce_posix_SharedCode.h b/JuceLibraryCode/modules/juce_core/native/juce_posix_SharedCode.h index 01d883a..15343cd 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_posix_SharedCode.h +++ b/JuceLibraryCode/modules/juce_core/native/juce_posix_SharedCode.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,95 +40,6 @@ void CriticalSection::enter() const noexcept { pthread_mutex_lock (&lock) bool CriticalSection::tryEnter() const noexcept { return pthread_mutex_trylock (&lock) == 0; } void CriticalSection::exit() const noexcept { pthread_mutex_unlock (&lock); } -//============================================================================== -WaitableEvent::WaitableEvent (bool useManualReset) noexcept - : triggered (false), manualReset (useManualReset) -{ - pthread_cond_init (&condition, {}); - - pthread_mutexattr_t atts; - pthread_mutexattr_init (&atts); - #if ! JUCE_ANDROID - pthread_mutexattr_setprotocol (&atts, PTHREAD_PRIO_INHERIT); - #endif - pthread_mutex_init (&mutex, &atts); - pthread_mutexattr_destroy (&atts); -} - -WaitableEvent::~WaitableEvent() noexcept -{ - pthread_cond_destroy (&condition); - pthread_mutex_destroy (&mutex); -} - -bool WaitableEvent::wait (int timeOutMillisecs) const noexcept -{ - pthread_mutex_lock (&mutex); - - if (! triggered) - { - if (timeOutMillisecs < 0) - { - do - { - pthread_cond_wait (&condition, &mutex); - } - while (! triggered); - } - else - { - struct timeval now; - gettimeofday (&now, nullptr); - - struct timespec time; - time.tv_sec = now.tv_sec + (timeOutMillisecs / 1000); - time.tv_nsec = (now.tv_usec + ((timeOutMillisecs % 1000) * 1000)) * 1000; - - if (time.tv_nsec >= 1000000000) - { - time.tv_nsec -= 1000000000; - time.tv_sec++; - } - - do - { - if (pthread_cond_timedwait (&condition, &mutex, &time) == ETIMEDOUT) - { - pthread_mutex_unlock (&mutex); - return false; - } - } - while (! triggered); - } - } - - if (! manualReset) - triggered = false; - - pthread_mutex_unlock (&mutex); - return true; -} - -void WaitableEvent::signal() const noexcept -{ - pthread_mutex_lock (&mutex); - - if (! triggered) - { - triggered = true; - pthread_cond_broadcast (&condition); - } - - pthread_mutex_unlock (&mutex); -} - -void WaitableEvent::reset() const noexcept -{ - pthread_mutex_lock (&mutex); - triggered = false; - pthread_mutex_unlock (&mutex); -} - //============================================================================== void JUCE_CALLTYPE Thread::sleep (int millisecs) { @@ -271,7 +182,7 @@ namespace return statfs (f.getFullPathName().toUTF8(), &result) == 0; } - #if (JUCE_MAC && MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || JUCE_IOS + #if JUCE_MAC || JUCE_IOS static int64 getCreationTime (const juce_statStruct& s) noexcept { return (int64) s.st_birthtime; } #else static int64 getCreationTime (const juce_statStruct& s) noexcept { return (int64) s.st_ctime; } @@ -400,13 +311,19 @@ void File::getFileTimesInternal (int64& modificationTime, int64& accessTime, int if (juce_stat (fullPath, info)) { + #if JUCE_MAC || (JUCE_IOS && __DARWIN_ONLY_64_BIT_INO_T) + modificationTime = (int64) info.st_mtimespec.tv_sec * 1000 + info.st_mtimespec.tv_nsec / 1000000; + accessTime = (int64) info.st_atimespec.tv_sec * 1000 + info.st_atimespec.tv_nsec / 1000000; + creationTime = (int64) info.st_birthtimespec.tv_sec * 1000 + info.st_birthtimespec.tv_nsec / 1000000; + #else modificationTime = (int64) info.st_mtime * 1000; accessTime = (int64) info.st_atime * 1000; - #if (JUCE_MAC && MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || JUCE_IOS + #if JUCE_IOS creationTime = (int64) info.st_birthtime * 1000; #else creationTime = (int64) info.st_ctime * 1000; #endif + #endif } } @@ -416,11 +333,32 @@ bool File::setFileTimesInternal (int64 modificationTime, int64 accessTime, int64 if ((modificationTime != 0 || accessTime != 0) && juce_stat (fullPath, info)) { + #if JUCE_MAC || (JUCE_IOS && __DARWIN_ONLY_64_BIT_INO_T) + struct timeval times[2]; + + bool setModificationTime = (modificationTime != 0); + bool setAccessTime = (accessTime != 0); + + times[0].tv_sec = setAccessTime ? static_cast<__darwin_time_t> (accessTime / 1000) + : info.st_atimespec.tv_sec; + + times[0].tv_usec = setAccessTime ? static_cast<__darwin_suseconds_t> ((accessTime % 1000) * 1000) + : static_cast<__darwin_suseconds_t> (info.st_atimespec.tv_nsec / 1000); + + times[1].tv_sec = setModificationTime ? static_cast<__darwin_time_t> (modificationTime / 1000) + : info.st_mtimespec.tv_sec; + + times[1].tv_usec = setModificationTime ? static_cast<__darwin_suseconds_t> ((modificationTime % 1000) * 1000) + : static_cast<__darwin_suseconds_t> (info.st_mtimespec.tv_nsec / 1000); + + return utimes (fullPath.toUTF8(), times) == 0; + #else struct utimbuf times; times.actime = accessTime != 0 ? static_cast (accessTime / 1000) : static_cast (info.st_atime); times.modtime = modificationTime != 0 ? static_cast (modificationTime / 1000) : static_cast (info.st_mtime); return utime (fullPath.toUTF8(), ×) == 0; + #endif } return false; @@ -477,7 +415,7 @@ int64 juce_fileSetPosition (void* handle, int64 pos) void FileInputStream::openHandle() { - auto f = open (file.getFullPathName().toUTF8(), O_RDONLY, 00644); + auto f = open (file.getFullPathName().toUTF8(), O_RDONLY); if (f != -1) fileHandle = fdToVoidPointer (f); @@ -514,7 +452,7 @@ void FileOutputStream::openHandle() { if (file.exists()) { - auto f = open (file.getFullPathName().toUTF8(), O_RDWR, 00644); + auto f = open (file.getFullPathName().toUTF8(), O_RDWR); if (f != -1) { @@ -537,7 +475,7 @@ void FileOutputStream::openHandle() } else { - auto f = open (file.getFullPathName().toUTF8(), O_RDWR + O_CREAT, 00644); + auto f = open (file.getFullPathName().toUTF8(), O_RDWR | O_CREAT, 00644); if (f != -1) fileHandle = fdToVoidPointer (f); @@ -605,8 +543,12 @@ void MemoryMappedFile::openInternal (const File& file, AccessMode mode, bool exc range.setStart (range.getStart() - (range.getStart() % pageSize)); } - fileHandle = open (file.getFullPathName().toUTF8(), - mode == readWrite ? (O_CREAT + O_RDWR) : O_RDONLY, 00644); + auto filename = file.getFullPathName().toUTF8(); + + if (mode == readWrite) + fileHandle = open (filename, O_CREAT | O_RDWR, 00644); + else + fileHandle = open (filename, O_RDONLY); if (fileHandle != -1) { @@ -887,8 +829,7 @@ void JUCE_API juce_threadEntryPoint (void*); extern JavaVM* androidJNIJavaVM; #endif -extern "C" void* threadEntryProc (void*); -extern "C" void* threadEntryProc (void* userData) +static void* threadEntryProc (void* userData) { auto* myself = static_cast (userData); @@ -1044,8 +985,8 @@ void JUCE_CALLTYPE Thread::setCurrentThreadAffinityMask (uint32 affinityMask) CPU_ZERO (&affinity); for (int i = 0; i < 32; ++i) - if ((affinityMask & (1 << i)) != 0) - CPU_SET (i, &affinity); + if ((affinityMask & (uint32) (1 << i)) != 0) + CPU_SET ((size_t) i, &affinity); #if (! JUCE_ANDROID) && ((! JUCE_LINUX) || ((__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2004)) pthread_setaffinity_np (pthread_self(), sizeof (cpu_set_t), &affinity); @@ -1092,7 +1033,8 @@ void* DynamicLibrary::getFunction (const String& functionName) noexcept //============================================================================== -static inline String readPosixConfigFileValue (const char* file, const char* key) +#if JUCE_LINUX || JUCE_ANDROID +static String readPosixConfigFileValue (const char* file, const char* key) { StringArray lines; File (file).readLines (lines); @@ -1103,6 +1045,7 @@ static inline String readPosixConfigFileValue (const char* file, const char* key return {}; } +#endif //============================================================================== @@ -1155,7 +1098,7 @@ class ChildProcess::ActiveProcess argv.add (nullptr); execvp (exe.toRawUTF8(), argv.getRawDataPointer()); - exit (-1); + _exit (-1); } else { @@ -1176,14 +1119,24 @@ class ChildProcess::ActiveProcess close (pipeHandle); } - bool isRunning() const noexcept + bool isRunning() noexcept { if (childPID == 0) return false; int childState; auto pid = waitpid (childPID, &childState, WNOHANG); - return pid == 0 || ! (WIFEXITED (childState) || WIFSIGNALED (childState)); + + if (pid == 0) + return true; + + if (WIFEXITED (childState)) + { + exitCode = WEXITSTATUS (childState); + return false; + } + + return ! WIFSIGNALED (childState); } int read (void* dest, int numBytes) noexcept @@ -1198,7 +1151,21 @@ class ChildProcess::ActiveProcess readHandle = fdopen (pipeHandle, "r"); if (readHandle != nullptr) - return (int) fread (dest, 1, (size_t) numBytes, readHandle); + { + for (;;) + { + auto numBytesRead = (int) fread (dest, 1, (size_t) numBytes, readHandle); + + if (numBytesRead > 0 || feof (readHandle)) + return numBytesRead; + + // signal occurred during fread() so try again + if (ferror (readHandle) && errno == EINTR) + continue; + + break; + } + } return 0; } @@ -1208,15 +1175,21 @@ class ChildProcess::ActiveProcess return ::kill (childPID, SIGKILL) == 0; } - uint32 getExitCode() const noexcept + uint32 getExitCode() noexcept { + if (exitCode >= 0) + return (uint32) exitCode; + if (childPID != 0) { int childState = 0; auto pid = waitpid (childPID, &childState, WNOHANG); if (pid >= 0 && WIFEXITED (childState)) - return WEXITSTATUS (childState); + { + exitCode = WEXITSTATUS (childState); + return (uint32) exitCode; + } } return 0; @@ -1224,6 +1197,7 @@ class ChildProcess::ActiveProcess int childPID = 0; int pipeHandle = 0; + int exitCode = -1; FILE* readHandle = {}; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ActiveProcess) @@ -1321,7 +1295,7 @@ struct HighResolutionTimer::Pimpl } HighResolutionTimer& owner; - std::atomic periodMs; + std::atomic periodMs { 0 }; private: pthread_t thread = {}; diff --git a/JuceLibraryCode/modules/juce_core/native/juce_win32_ComSmartPtr.h b/JuceLibraryCode/modules/juce_core/native/juce_win32_ComSmartPtr.h index abea32e..55bee8f 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_win32_ComSmartPtr.h +++ b/JuceLibraryCode/modules/juce_core/native/juce_win32_ComSmartPtr.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 @@ inline GUID uuidFromString (const char* s) noexcept for (uint32 digitIndex = 0; digitIndex < 32;) { - auto c = *s++; + auto c = (uint32) *s++; uint32 digit; if (c >= '0' && c <= '9') digit = c - '0'; @@ -114,7 +114,7 @@ class ComSmartPtr HRESULT CoCreateInstance (REFCLSID classUUID, DWORD dwClsContext = CLSCTX_INPROC_SERVER) { - auto hr = ::CoCreateInstance (classUUID, 0, dwClsContext, __uuidof (ComClass), (void**) resetAndGetPointerAddress()); + auto hr = ::CoCreateInstance (classUUID, nullptr, dwClsContext, __uuidof (ComClass), (void**) resetAndGetPointerAddress()); jassert (hr != CO_E_NOTINITIALIZED); // You haven't called CoInitialize for the current thread! return hr; } diff --git a/JuceLibraryCode/modules/juce_core/native/juce_win32_Files.cpp b/JuceLibraryCode/modules/juce_core/native/juce_win32_Files.cpp index 45f4c12..62b609c 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_win32_Files.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_win32_Files.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. @@ -131,7 +131,7 @@ namespace WindowsFileHelpers { WCHAR path[MAX_PATH + 256]; - if (SHGetSpecialFolderPath (0, path, type, FALSE)) + if (SHGetSpecialFolderPath (nullptr, path, type, FALSE)) return File (String (path)); return {}; @@ -147,7 +147,7 @@ namespace WindowsFileHelpers Result getResultForLastError() { - TCHAR messageBuffer[256] = { 0 }; + TCHAR messageBuffer[256] = {}; FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, GetLastError(), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), @@ -239,7 +239,7 @@ bool File::moveToTrash() const doubleNullTermPath.calloc (numBytes, 1); fullPath.copyToUTF16 (doubleNullTermPath, numBytes); - SHFILEOPSTRUCT fos = { 0 }; + SHFILEOPSTRUCT fos = {}; fos.wFunc = FO_DELETE; fos.pFrom = doubleNullTermPath; fos.fFlags = FOF_ALLOWUNDO | FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION @@ -264,14 +264,14 @@ bool File::replaceInternal (const File& dest) const { return ReplaceFile (dest.getFullPathName().toWideCharPointer(), fullPath.toWideCharPointer(), - 0, REPLACEFILE_IGNORE_MERGE_ERRORS | 4 /*REPLACEFILE_IGNORE_ACL_ERRORS*/, + nullptr, REPLACEFILE_IGNORE_MERGE_ERRORS | 4 /*REPLACEFILE_IGNORE_ACL_ERRORS*/, nullptr, nullptr) != 0; } Result File::createDirectoryInternal (const String& fileName) const { - return CreateDirectory (fileName.toWideCharPointer(), 0) ? Result::ok() - : WindowsFileHelpers::getResultForLastError(); + return CreateDirectory (fileName.toWideCharPointer(), nullptr) ? Result::ok() + : WindowsFileHelpers::getResultForLastError(); } //============================================================================== @@ -287,8 +287,8 @@ int64 juce_fileSetPosition (void* handle, int64 pos) void FileInputStream::openHandle() { auto h = CreateFile (file.getFullPathName().toWideCharPointer(), - GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0); + GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, nullptr); if (h != INVALID_HANDLE_VALUE) fileHandle = (void*) h; @@ -303,11 +303,11 @@ FileInputStream::~FileInputStream() size_t FileInputStream::readInternal (void* buffer, size_t numBytes) { - if (fileHandle != 0) + if (fileHandle != nullptr) { DWORD actualNum = 0; - if (! ReadFile ((HANDLE) fileHandle, buffer, (DWORD) numBytes, &actualNum, 0)) + if (! ReadFile ((HANDLE) fileHandle, buffer, (DWORD) numBytes, &actualNum, nullptr)) status = WindowsFileHelpers::getResultForLastError(); return (size_t) actualNum; @@ -320,8 +320,8 @@ size_t FileInputStream::readInternal (void* buffer, size_t numBytes) void FileOutputStream::openHandle() { auto h = CreateFile (file.getFullPathName().toWideCharPointer(), - GENERIC_WRITE, FILE_SHARE_READ, 0, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + GENERIC_WRITE, FILE_SHARE_READ, nullptr, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); if (h != INVALID_HANDLE_VALUE) { @@ -350,7 +350,7 @@ ssize_t FileOutputStream::writeInternal (const void* bufferToWrite, size_t numBy DWORD actualNum = 0; if (fileHandle != nullptr) - if (! WriteFile ((HANDLE) fileHandle, bufferToWrite, (DWORD) numBytes, &actualNum, 0)) + if (! WriteFile ((HANDLE) fileHandle, bufferToWrite, (DWORD) numBytes, &actualNum, nullptr)) status = WindowsFileHelpers::getResultForLastError(); return (ssize_t) actualNum; @@ -398,18 +398,18 @@ void MemoryMappedFile::openInternal (const File& file, AccessMode mode, bool exc } auto h = CreateFile (file.getFullPathName().toWideCharPointer(), accessMode, - exclusive ? 0 : (FILE_SHARE_READ | FILE_SHARE_DELETE | (mode == readWrite ? FILE_SHARE_WRITE : 0)), 0, - createType, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0); + exclusive ? 0 : (FILE_SHARE_READ | FILE_SHARE_DELETE | (mode == readWrite ? FILE_SHARE_WRITE : 0)), nullptr, + createType, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, nullptr); if (h != INVALID_HANDLE_VALUE) { fileHandle = (void*) h; - auto mappingHandle = CreateFileMapping (h, 0, protect, + auto mappingHandle = CreateFileMapping (h, nullptr, protect, (DWORD) (range.getEnd() >> 32), - (DWORD) range.getEnd(), 0); + (DWORD) range.getEnd(), nullptr); - if (mappingHandle != 0) + if (mappingHandle != nullptr) { address = MapViewOfFile (mappingHandle, access, (DWORD) (range.getStart() >> 32), (DWORD) range.getStart(), (SIZE_T) range.getLength()); @@ -465,8 +465,8 @@ bool File::setFileTimesInternal (int64 modificationTime, int64 accessTime, int64 bool ok = false; auto h = CreateFile (fullPath.toWideCharPointer(), - GENERIC_WRITE, FILE_SHARE_READ, 0, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + GENERIC_WRITE, FILE_SHARE_READ, nullptr, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); if (h != INVALID_HANDLE_VALUE) { @@ -486,7 +486,7 @@ bool File::setFileTimesInternal (int64 modificationTime, int64 accessTime, int64 //============================================================================== void File::findFileSystemRoots (Array& destArray) { - TCHAR buffer[2048] = { 0 }; + TCHAR buffer[2048] = {}; GetLogicalDriveStrings (2048, buffer); const TCHAR* n = buffer; @@ -512,7 +512,7 @@ String File::getVolumeLabel() const TCHAR dest[64]; if (! GetVolumeInformation (WindowsFileHelpers::getDriveFromPath (getFullPathName()).toWideCharPointer(), dest, - (DWORD) numElementsInArray (dest), 0, 0, 0, 0, 0)) + (DWORD) numElementsInArray (dest), nullptr, nullptr, nullptr, nullptr, 0)) dest[0] = 0; return dest; @@ -524,7 +524,7 @@ int File::getVolumeSerialNumber() const DWORD serialNum; if (! GetVolumeInformation (WindowsFileHelpers::getDriveFromPath (getFullPathName()).toWideCharPointer(), dest, - (DWORD) numElementsInArray (dest), &serialNum, 0, 0, 0, 0)) + (DWORD) numElementsInArray (dest), &serialNum, nullptr, nullptr, nullptr, 0)) return 0; return (int) serialNum; @@ -544,9 +544,14 @@ uint64 File::getFileIdentifier() const { uint64 result = 0; - auto h = CreateFile (getFullPathName().toWideCharPointer(), + String path = getFullPathName(); + + if (isRoot()) + path += "\\"; + + auto h = CreateFile (path.toWideCharPointer(), GENERIC_READ, FILE_SHARE_READ, nullptr, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); if (h != INVALID_HANDLE_VALUE) { @@ -575,10 +580,8 @@ bool File::isOnHardDisk() const auto n = WindowsFileHelpers::getWindowsDriveType (getFullPathName()); - if (fullPath.toLowerCase()[0] <= 'b' && fullPath[1] == ':') - return n != DRIVE_REMOVABLE; - - return n != DRIVE_CDROM + return n != DRIVE_REMOVABLE + && n != DRIVE_CDROM && n != DRIVE_REMOTE && n != DRIVE_NO_ROOT_DIR; } @@ -637,7 +640,7 @@ File JUCE_CALLTYPE File::getSpecialLocation (const SpecialLocationType type) return WindowsFileHelpers::getModuleFileName ((HINSTANCE) Process::getCurrentModuleInstanceHandle()); case hostApplicationPath: - return WindowsFileHelpers::getModuleFileName (0); + return WindowsFileHelpers::getModuleFileName (nullptr); default: jassertfalse; // unknown type? @@ -712,7 +715,7 @@ static String readWindowsLnkFile (File lnkFile, bool wantsAbsolutePath) if (SUCCEEDED (shellLink.CoCreateInstance (CLSID_ShellLink)) && SUCCEEDED (shellLink.QueryInterface (persistFile)) && SUCCEEDED (persistFile->Load (lnkFile.getFullPathName().toWideCharPointer(), STGM_READ)) - && (! wantsAbsolutePath || SUCCEEDED (shellLink->Resolve (0, SLR_ANY_MATCH | SLR_NO_UI)))) + && (! wantsAbsolutePath || SUCCEEDED (shellLink->Resolve (nullptr, SLR_ANY_MATCH | SLR_NO_UI)))) { WIN32_FIND_DATA winFindData; WCHAR resolvedPath[MAX_PATH]; @@ -738,7 +741,7 @@ static String readWindowsShortcutOrLink (const File& shortcut, bool wantsAbsolut HANDLE h = CreateFile (shortcut.getFullPathName().toWideCharPointer(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, - 0); + nullptr); if (h != INVALID_HANDLE_VALUE) { @@ -806,7 +809,7 @@ static String readWindowsShortcutOrLink (const File& shortcut, bool wantsAbsolut { HANDLE h = CreateFile (shortcut.getFullPathName().toWideCharPointer(), GENERIC_READ, FILE_SHARE_READ, nullptr, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); if (h != INVALID_HANDLE_VALUE) { @@ -858,7 +861,7 @@ bool File::createShortcut (const String& description, const File& linkFileToCrea ComSmartPtr shellLink; ComSmartPtr persistFile; - CoInitialize (0); + CoInitialize (nullptr); return SUCCEEDED (shellLink.CoCreateInstance (CLSID_ShellLink)) && SUCCEEDED (shellLink->SetPath (getFullPathName().toWideCharPointer())) @@ -942,8 +945,8 @@ bool DirectoryIterator::NativeIterator::next (String& filenameFound, //============================================================================== bool JUCE_CALLTYPE Process::openDocument (const String& fileName, const String& parameters) { - HINSTANCE hInstance = ShellExecute (0, 0, fileName.toWideCharPointer(), - parameters.toWideCharPointer(), 0, SW_SHOWDEFAULT); + HINSTANCE hInstance = ShellExecute (nullptr, nullptr, fileName.toWideCharPointer(), + parameters.toWideCharPointer(), nullptr, SW_SHOWDEFAULT); return hInstance > (HINSTANCE) 32; } @@ -972,14 +975,14 @@ class NamedPipe::Pimpl Pimpl (const String& pipeName, const bool createPipe, bool mustNotExist) : filename ("\\\\.\\pipe\\" + File::createLegalFileName (pipeName)), pipeH (INVALID_HANDLE_VALUE), - cancelEvent (CreateEvent (0, FALSE, FALSE, 0)), + cancelEvent (CreateEvent (nullptr, FALSE, FALSE, nullptr)), connected (false), ownsPipe (createPipe), shouldStop (false) { if (createPipe) { pipeH = CreateNamedPipe (filename.toWideCharPointer(), PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, - PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, 0); + PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, nullptr); if (mustNotExist && GetLastError() == ERROR_ALREADY_EXISTS) closePipeHandle(); @@ -1008,8 +1011,8 @@ class NamedPipe::Pimpl if (pipeH == INVALID_HANDLE_VALUE) pipeH = CreateFile (filename.toWideCharPointer(), - GENERIC_READ | GENERIC_WRITE, 0, 0, - OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + GENERIC_READ | GENERIC_WRITE, 0, nullptr, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr); } if (pipeH != INVALID_HANDLE_VALUE) @@ -1133,7 +1136,7 @@ class NamedPipe::Pimpl OverlappedEvent() { zerostruct (over); - over.hEvent = CreateEvent (0, TRUE, FALSE, 0); + over.hEvent = CreateEvent (nullptr, TRUE, FALSE, nullptr); } ~OverlappedEvent() @@ -1151,7 +1154,7 @@ class NamedPipe::Pimpl HANDLE handles[] = { over.over.hEvent, cancelEvent }; DWORD waitResult = WaitForMultipleObjects (2, handles, FALSE, - timeOutMilliseconds >= 0 ? timeOutMilliseconds + timeOutMilliseconds >= 0 ? (DWORD) timeOutMilliseconds : INFINITE); if (waitResult == WAIT_OBJECT_0) diff --git a/JuceLibraryCode/modules/juce_core/native/juce_win32_Network.cpp b/JuceLibraryCode/modules/juce_core/native/juce_win32_Network.cpp index 56a2048..b66a287 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_win32_Network.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_win32_Network.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. @@ -90,7 +90,7 @@ class WebInputStream::Pimpl { HeapBlock buffer (bufferSizeBytes); - if (HttpQueryInfo (request, HTTP_QUERY_RAW_HEADERS_CRLF, buffer.getData(), &bufferSizeBytes, 0)) + if (HttpQueryInfo (request, HTTP_QUERY_RAW_HEADERS_CRLF, buffer.getData(), &bufferSizeBytes, nullptr)) { StringArray headersArray; headersArray.addLines (String (reinterpret_cast (buffer.getData()))); @@ -116,7 +116,7 @@ class WebInputStream::Pimpl DWORD status = 0; DWORD statusSize = sizeof (status); - if (HttpQueryInfo (request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &statusSize, 0)) + if (HttpQueryInfo (request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &statusSize, nullptr)) { statusCode = (int) status; @@ -151,10 +151,10 @@ class WebInputStream::Pimpl break; } - return (request != 0); + return (request != nullptr); } - bool isError() const { return request == 0; } + bool isError() const { return request == nullptr; } bool isExhausted() { return finished; } int64 getPosition() { return position; } @@ -207,7 +207,7 @@ class WebInputStream::Pimpl if (wantedPos != position) { finished = false; - position = (int64) InternetSetFilePointer (request, (LONG) wantedPos, 0, FILE_BEGIN, 0); + position = (int64) InternetSetFilePointer (request, (LONG) wantedPos, nullptr, FILE_BEGIN, 0); if (position == wantedPos) return true; @@ -232,7 +232,7 @@ class WebInputStream::Pimpl //============================================================================== WebInputStream& owner; const URL url; - HINTERNET connection = 0, request = 0; + HINTERNET connection = nullptr, request = nullptr; String headers; MemoryBlock postData; int64 position = 0; @@ -249,25 +249,25 @@ class WebInputStream::Pimpl { HINTERNET requestCopy = request; - request = 0; + request = nullptr; - if (requestCopy != 0) + if (requestCopy != nullptr) InternetCloseHandle (requestCopy); - if (connection != 0) + if (connection != nullptr) { InternetCloseHandle (connection); - connection = 0; + connection = nullptr; } } void createConnection (const String& address, WebInputStream::Listener* listener) { - static HINTERNET sessionHandle = InternetOpen (_T("juce"), INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0); + static HINTERNET sessionHandle = InternetOpen (_T("juce"), INTERNET_OPEN_TYPE_PRECONFIG, nullptr, nullptr, 0); closeConnection(); - if (sessionHandle != 0) + if (sessionHandle != nullptr) { // break up the url.. const int fileNumChars = 65536; @@ -277,7 +277,7 @@ class WebInputStream::Pimpl HeapBlock file (fileNumChars), server (serverNumChars), username (usernameNumChars), password (passwordNumChars); - URL_COMPONENTS uc = { 0 }; + URL_COMPONENTS uc = {}; uc.dwStructSize = sizeof (uc); uc.lpszUrlPath = file; uc.dwUrlPathLength = fileNumChars; @@ -319,7 +319,7 @@ class WebInputStream::Pimpl { const ScopedLock lock (createConnectionLock); - connection = hasBeenCancelled ? 0 + connection = hasBeenCancelled ? nullptr : InternetConnect (sessionHandle, uc.lpszHostName, uc.nPort, uc.lpszUserName, uc.lpszPassword, @@ -328,7 +328,7 @@ class WebInputStream::Pimpl 0, 0); } - if (connection != 0) + if (connection != nullptr) { if (isFtp) request = FtpOpenFile (connection, uc.lpszUrlPath, GENERIC_READ, @@ -345,7 +345,7 @@ class WebInputStream::Pimpl void sendHTTPRequest (INTERNET_BUFFERS& buffers, WebInputStream::Listener* listener) { - if (! HttpSendRequestEx (request, &buffers, 0, HSR_INITIATE, 0)) + if (! HttpSendRequestEx (request, &buffers, nullptr, HSR_INITIATE, 0)) return; int totalBytesSent = 0; @@ -362,7 +362,7 @@ class WebInputStream::Pimpl return; } - totalBytesSent += bytesSent; + totalBytesSent += (int) bytesSent; if (listener != nullptr && ! listener->postDataSendProgress (owner, totalBytesSent, (int) postData.getSize())) @@ -386,14 +386,14 @@ class WebInputStream::Pimpl { const ScopedLock lock (createConnectionLock); - request = hasBeenCancelled ? 0 + request = hasBeenCancelled ? nullptr : HttpOpenRequest (connection, httpRequestCmd.toWideCharPointer(), - uc.lpszUrlPath, 0, 0, mimeTypes, flags, 0); + uc.lpszUrlPath, nullptr, nullptr, mimeTypes, flags, 0); } - if (request != 0) + if (request != nullptr) { - INTERNET_BUFFERS buffers = { 0 }; + INTERNET_BUFFERS buffers = {}; buffers.dwStructSize = sizeof (INTERNET_BUFFERS); buffers.lpcszHeader = headers.toWideCharPointer(); buffers.dwHeadersLength = (DWORD) headers.length(); @@ -403,7 +403,7 @@ class WebInputStream::Pimpl { sendHTTPRequest (buffers, listener); - if (HttpEndRequest (request, 0, 0, 0)) + if (HttpEndRequest (request, nullptr, 0, 0)) return true; return false; @@ -440,10 +440,10 @@ struct GetAdaptersAddressesHelper adaptersAddresses.malloc (1); ULONG len = sizeof (IP_ADAPTER_ADDRESSES); - if (getAdaptersAddresses (AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, adaptersAddresses, &len) == ERROR_BUFFER_OVERFLOW) + if (getAdaptersAddresses (AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, adaptersAddresses, &len) == ERROR_BUFFER_OVERFLOW) adaptersAddresses.malloc (len, 1); - return getAdaptersAddresses (AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, adaptersAddresses, &len) == NO_ERROR; + return getAdaptersAddresses (AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, adaptersAddresses, &len) == NO_ERROR; } HeapBlock adaptersAddresses; @@ -476,12 +476,12 @@ namespace MACAddressHelpers DynamicLibrary dll ("netapi32.dll"); JUCE_LOAD_WINAPI_FUNCTION (dll, Netbios, NetbiosCall, UCHAR, (PNCB)) - if (NetbiosCall != 0) + if (NetbiosCall != nullptr) { - LANA_ENUM enums = { 0 }; + LANA_ENUM enums = {}; { - NCB ncb = { 0 }; + NCB ncb = {}; ncb.ncb_command = NCBENUM; ncb.ncb_buffer = (unsigned char*) &enums; ncb.ncb_length = sizeof (LANA_ENUM); @@ -490,13 +490,13 @@ namespace MACAddressHelpers for (int i = 0; i < enums.length; ++i) { - NCB ncb2 = { 0 }; + NCB ncb2 = {}; ncb2.ncb_command = NCBRESET; ncb2.ncb_lana_num = enums.lana[i]; if (NetbiosCall (&ncb2) == 0) { - NCB ncb = { 0 }; + NCB ncb = {}; memcpy (ncb.ncb_callname, "* ", NCBNAMSZ); ncb.ncb_command = NCBASTAT; ncb.ncb_lana_num = enums.lana[i]; @@ -608,11 +608,11 @@ bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& targetEmailA if (mapiSendMail == nullptr) return false; - MapiMessage message = { 0 }; + MapiMessage message = {}; message.lpszSubject = (LPSTR) emailSubject.toRawUTF8(); message.lpszNoteText = (LPSTR) bodyText.toRawUTF8(); - MapiRecipDesc recip = { 0 }; + MapiRecipDesc recip = {}; recip.ulRecipClass = MAPI_TO; String targetEmailAddress_ (targetEmailAddress); if (targetEmailAddress_.isEmpty()) @@ -636,7 +636,7 @@ bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& targetEmailA return mapiSendMail (0, 0, &message, MAPI_DIALOG | MAPI_LOGON_UI, 0) == SUCCESS_SUCCESS; } -URL::DownloadTask* URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool shouldUsePost) +std::unique_ptr URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool shouldUsePost) { return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, extraHeaders, listener, shouldUsePost); } diff --git a/JuceLibraryCode/modules/juce_core/native/juce_win32_Registry.cpp b/JuceLibraryCode/modules/juce_core/native/juce_win32_Registry.cpp index 514395d..1b47389 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_win32_Registry.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_win32_Registry.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. @@ -40,8 +40,8 @@ struct RegistryKeyWrapper DWORD result; if (createForWriting) - RegCreateKeyEx (rootKey, wideCharName, 0, 0, REG_OPTION_NON_VOLATILE, - KEY_WRITE | KEY_QUERY_VALUE | wow64Flags, 0, &key, &result); + RegCreateKeyEx (rootKey, wideCharName, 0, nullptr, REG_OPTION_NON_VOLATILE, + KEY_WRITE | KEY_QUERY_VALUE | wow64Flags, nullptr, &key, &result); else RegOpenKeyEx (rootKey, wideCharName, 0, KEY_READ | wow64Flags, &key); } @@ -49,7 +49,7 @@ struct RegistryKeyWrapper ~RegistryKeyWrapper() { - if (key != 0) + if (key != nullptr) RegCloseKey (key); } @@ -65,7 +65,7 @@ struct RegistryKeyWrapper if (name.startsWithIgnoreCase ("HKU\\")) return HKEY_USERS; jassertfalse; // The name starts with an unknown root key (or maybe an old Win9x type) - return 0; + return nullptr; } static bool setValue (const String& regValuePath, const DWORD type, @@ -73,7 +73,7 @@ struct RegistryKeyWrapper { const RegistryKeyWrapper key (regValuePath, true, wow64Flags); - return key.key != 0 + return key.key != nullptr && RegSetValueEx (key.key, key.wideCharValueName, 0, type, reinterpret_cast (data), (DWORD) dataSize) == ERROR_SUCCESS; @@ -83,14 +83,14 @@ struct RegistryKeyWrapper { const RegistryKeyWrapper key (regValuePath, false, wow64Flags); - if (key.key != 0) + if (key.key != nullptr) { for (unsigned long bufferSize = 1024; ; bufferSize *= 2) { result.setSize (bufferSize, false); DWORD type = REG_NONE; - auto err = RegQueryValueEx (key.key, key.wideCharValueName, 0, &type, + auto err = RegQueryValueEx (key.key, key.wideCharValueName, nullptr, &type, (LPBYTE) result.getData(), &bufferSize); if (err == ERROR_SUCCESS) @@ -121,16 +121,16 @@ struct RegistryKeyWrapper return defaultValue; } - static bool keyExists (const String& regValuePath, const DWORD wow64Flags) + static bool keyExists (const String& regKeyPath, const DWORD wow64Flags) { - return RegistryKeyWrapper (regValuePath, false, wow64Flags).key != 0; + return RegistryKeyWrapper (regKeyPath + "\\", false, wow64Flags).key != nullptr; } static bool valueExists (const String& regValuePath, const DWORD wow64Flags) { const RegistryKeyWrapper key (regValuePath, false, wow64Flags); - if (key.key == 0) + if (key.key == nullptr) return false; unsigned char buffer [512]; @@ -138,12 +138,12 @@ struct RegistryKeyWrapper DWORD type = 0; auto result = RegQueryValueEx (key.key, key.wideCharValueName, - 0, &type, buffer, &bufferSize); + nullptr, &type, buffer, &bufferSize); return result == ERROR_SUCCESS || result == ERROR_MORE_DATA; } - HKEY key = 0; + HKEY key = nullptr; const wchar_t* wideCharValueName = nullptr; String valueName; @@ -186,23 +186,23 @@ bool JUCE_CALLTYPE WindowsRegistry::valueExists (const String& regValuePath, WoW return RegistryKeyWrapper::valueExists (regValuePath, (DWORD) mode); } -bool JUCE_CALLTYPE WindowsRegistry::keyExists (const String& regValuePath, WoW64Mode mode) +bool JUCE_CALLTYPE WindowsRegistry::keyExists (const String& regKeyPath, WoW64Mode mode) { - return RegistryKeyWrapper::keyExists (regValuePath, (DWORD) mode); + return RegistryKeyWrapper::keyExists (regKeyPath, (DWORD) mode); } bool JUCE_CALLTYPE WindowsRegistry::deleteValue (const String& regValuePath, WoW64Mode mode) { const RegistryKeyWrapper key (regValuePath, true, (DWORD) mode); - return key.key != 0 && RegDeleteValue (key.key, key.wideCharValueName) == ERROR_SUCCESS; + return key.key != nullptr && RegDeleteValue (key.key, key.wideCharValueName) == ERROR_SUCCESS; } static bool deleteKeyNonRecursive (const String& regKeyPath, WindowsRegistry::WoW64Mode mode) { const RegistryKeyWrapper key (regKeyPath, true, (DWORD) mode); - return key.key != 0 && RegDeleteKey (key.key, key.wideCharValueName) == ERROR_SUCCESS; + return key.key != nullptr && RegDeleteKey (key.key, key.wideCharValueName) == ERROR_SUCCESS; } bool JUCE_CALLTYPE WindowsRegistry::deleteKey (const String& regKeyPath, WoW64Mode mode) diff --git a/JuceLibraryCode/modules/juce_core/native/juce_win32_SystemStats.cpp b/JuceLibraryCode/modules/juce_core/native/juce_win32_SystemStats.cpp index 2486e9f..5e10133 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_win32_SystemStats.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_win32_SystemStats.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,7 @@ namespace juce { -#if ! JUCE_MINGW +#if JUCE_MSVC #pragma intrinsic (__cpuid) #pragma intrinsic (__rdtsc) #endif @@ -41,10 +41,11 @@ void Logger::outputDebugString (const String& text) //============================================================================== -#if JUCE_MINGW +#if JUCE_MINGW || JUCE_CLANG static void callCPUID (int result[4], uint32 type) { - uint32 la = result[0], lb = result[1], lc = result[2], ld = result[3]; + uint32 la = (uint32) result[0], lb = (uint32) result[1], + lc = (uint32) result[2], ld = (uint32) result[3]; asm ("mov %%ebx, %%esi \n\t" "cpuid \n\t" @@ -55,7 +56,8 @@ static void callCPUID (int result[4], uint32 type) #endif ); - result[0] = la; result[1] = lb; result[2] = lc; result[3] = ld; + result[0] = (int) la; result[1] = (int) lb; + result[2] = (int) lc; result[3] = (int) ld; } #else static void callCPUID (int result[4], int infoType) @@ -144,24 +146,28 @@ void CPUInformation::initialise() noexcept hasSSE2 = (info[3] & (1 << 26)) != 0; hasSSE3 = (info[2] & (1 << 0)) != 0; hasAVX = (info[2] & (1 << 28)) != 0; + hasFMA3 = (info[2] & (1 << 12)) != 0; hasSSSE3 = (info[2] & (1 << 9)) != 0; hasSSE41 = (info[2] & (1 << 19)) != 0; hasSSE42 = (info[2] & (1 << 20)) != 0; has3DNow = (info[1] & (1 << 31)) != 0; + callCPUID (info, 0x80000001); + hasFMA4 = (info[2] & (1 << 16)) != 0; + callCPUID (info, 7); - hasAVX2 = (info[1] & (1 << 5)) != 0; - hasAVX512F = (info[1] & (1u << 16)) != 0; - hasAVX512DQ = (info[1] & (1u << 17)) != 0; - hasAVX512IFMA = (info[1] & (1u << 21)) != 0; - hasAVX512PF = (info[1] & (1u << 26)) != 0; - hasAVX512ER = (info[1] & (1u << 27)) != 0; - hasAVX512CD = (info[1] & (1u << 28)) != 0; - hasAVX512BW = (info[1] & (1u << 30)) != 0; - hasAVX512VL = (info[1] & (1u << 31)) != 0; - hasAVX512VBMI = (info[2] & (1u << 1)) != 0; - hasAVX512VPOPCNTDQ = (info[2] & (1u << 14)) != 0; + hasAVX2 = ((unsigned int) info[1] & (1 << 5)) != 0; + hasAVX512F = ((unsigned int) info[1] & (1u << 16)) != 0; + hasAVX512DQ = ((unsigned int) info[1] & (1u << 17)) != 0; + hasAVX512IFMA = ((unsigned int) info[1] & (1u << 21)) != 0; + hasAVX512PF = ((unsigned int) info[1] & (1u << 26)) != 0; + hasAVX512ER = ((unsigned int) info[1] & (1u << 27)) != 0; + hasAVX512CD = ((unsigned int) info[1] & (1u << 28)) != 0; + hasAVX512BW = ((unsigned int) info[1] & (1u << 30)) != 0; + hasAVX512VL = ((unsigned int) info[1] & (1u << 31)) != 0; + hasAVX512VBMI = ((unsigned int) info[2] & (1u << 1)) != 0; + hasAVX512VPOPCNTDQ = ((unsigned int) info[2] & (1u << 14)) != 0; SYSTEM_INFO systemInfo; GetNativeSystemInfo (&systemInfo); @@ -185,43 +191,73 @@ static DebugFlagsInitialiser debugFlagsInitialiser; #endif //============================================================================== -static uint32 getWindowsVersion() -{ - auto filename = _T("kernel32.dll"); - DWORD handle = 0; - - if (auto size = GetFileVersionInfoSize (filename, &handle)) - { - HeapBlock data (size); - - if (GetFileVersionInfo (filename, handle, size, data)) - { - VS_FIXEDFILEINFO* info = nullptr; - UINT verSize = 0; - - if (VerQueryValue (data, (LPCTSTR) _T("\\"), (void**) &info, &verSize)) - if (size > 0 && info != nullptr && info->dwSignature == 0xfeef04bd) - return (uint32) info->dwFileVersionMS; - } - } - - return 0; -} +#if JUCE_MINGW + static uint32 getWindowsVersion() + { + auto filename = _T("kernel32.dll"); + DWORD handle = 0; + + if (auto size = GetFileVersionInfoSize (filename, &handle)) + { + HeapBlock data (size); + + if (GetFileVersionInfo (filename, handle, size, data)) + { + VS_FIXEDFILEINFO* info = nullptr; + UINT verSize = 0; + + if (VerQueryValue (data, (LPCTSTR) _T("\\"), (void**) &info, &verSize)) + if (size > 0 && info != nullptr && info->dwSignature == 0xfeef04bd) + return (uint32) info->dwFileVersionMS; + } + } + + return 0; + } +#else + RTL_OSVERSIONINFOW getWindowsVersionInfo() + { + RTL_OSVERSIONINFOW versionInfo = {}; + + if (auto* moduleHandle = ::GetModuleHandleW (L"ntdll.dll")) + { + using RtlGetVersion = LONG (WINAPI*) (PRTL_OSVERSIONINFOW); + + if (auto* rtlGetVersion = (RtlGetVersion) ::GetProcAddress (moduleHandle, "RtlGetVersion")) + { + versionInfo.dwOSVersionInfoSize = sizeof (versionInfo); + LONG STATUS_SUCCESS = 0; + + if (rtlGetVersion (&versionInfo) != STATUS_SUCCESS) + versionInfo = {}; + } + } + + return versionInfo; + } +#endif SystemStats::OperatingSystemType SystemStats::getOperatingSystemType() { + #if JUCE_MINGW auto v = getWindowsVersion(); - auto major = (v >> 16); + auto major = (v >> 16) & 0xff; + auto minor = (v >> 0) & 0xff; + #else + auto versionInfo = getWindowsVersionInfo(); + auto major = versionInfo.dwMajorVersion; + auto minor = versionInfo.dwMinorVersion; + #endif jassert (major <= 10); // need to add support for new version! - if (major == 10) return Windows10; - if (v == 0x00060003) return Windows8_1; - if (v == 0x00060002) return Windows8_0; - if (v == 0x00060001) return Windows7; - if (v == 0x00060000) return WinVista; - if (v == 0x00050000) return Win2000; - if (major == 5) return WinXP; + if (major == 10) return Windows10; + if (major == 6 && minor == 3) return Windows8_1; + if (major == 6 && minor == 2) return Windows8_0; + if (major == 6 && minor == 1) return Windows7; + if (major == 6 && minor == 0) return WinVista; + if (major == 5 && minor == 1) return WinXP; + if (major == 5 && minor == 0) return Win2000; jassertfalse; return UnknownOS; @@ -240,6 +276,26 @@ String SystemStats::getOperatingSystemName() case WinVista: name = "Windows Vista"; break; case WinXP: name = "Windows XP"; break; case Win2000: name = "Windows 2000"; break; + + case MacOSX: JUCE_FALLTHROUGH + case Windows: JUCE_FALLTHROUGH + case Linux: JUCE_FALLTHROUGH + case Android: JUCE_FALLTHROUGH + case iOS: JUCE_FALLTHROUGH + + case MacOSX_10_4: JUCE_FALLTHROUGH + case MacOSX_10_5: JUCE_FALLTHROUGH + case MacOSX_10_6: JUCE_FALLTHROUGH + case MacOSX_10_7: JUCE_FALLTHROUGH + case MacOSX_10_8: JUCE_FALLTHROUGH + case MacOSX_10_9: JUCE_FALLTHROUGH + case MacOSX_10_10: JUCE_FALLTHROUGH + case MacOSX_10_11: JUCE_FALLTHROUGH + case MacOSX_10_12: JUCE_FALLTHROUGH + case MacOSX_10_13: JUCE_FALLTHROUGH + case MacOSX_10_14: JUCE_FALLTHROUGH + + case UnknownOS: JUCE_FALLTHROUGH default: jassertfalse; break; // !! new type of OS? } diff --git a/JuceLibraryCode/modules/juce_core/native/juce_win32_Threads.cpp b/JuceLibraryCode/modules/juce_core/native/juce_win32_Threads.cpp index b1c50fa..75bcee7 100644 --- a/JuceLibraryCode/modules/juce_core/native/juce_win32_Threads.cpp +++ b/JuceLibraryCode/modules/juce_core/native/juce_win32_Threads.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,12 +23,12 @@ namespace juce { -HWND juce_messageWindowHandle = 0; // (this is used by other parts of the codebase) +HWND juce_messageWindowHandle = nullptr; // (this is used by other parts of the codebase) void* getUser32Function (const char* functionName) { HMODULE module = GetModuleHandleA ("user32.dll"); - jassert (module != 0); + jassert (module != nullptr); return (void*) GetProcAddress (module, functionName); } @@ -48,27 +48,13 @@ bool CriticalSection::tryEnter() const noexcept { return TryEnterCriticalSec void CriticalSection::exit() const noexcept { LeaveCriticalSection ((CRITICAL_SECTION*) lock); } -//============================================================================== -WaitableEvent::WaitableEvent (const bool manualReset) noexcept - : handle (CreateEvent (0, manualReset ? TRUE : FALSE, FALSE, 0)) {} - -WaitableEvent::~WaitableEvent() noexcept { CloseHandle (handle); } - -void WaitableEvent::signal() const noexcept { SetEvent (handle); } -void WaitableEvent::reset() const noexcept { ResetEvent (handle); } - -bool WaitableEvent::wait (const int timeOutMs) const noexcept -{ - return WaitForSingleObject (handle, (DWORD) timeOutMs) == WAIT_OBJECT_0; -} - //============================================================================== void JUCE_API juce_threadEntryPoint (void*); static unsigned int __stdcall threadEntryProc (void* userData) { - if (juce_messageWindowHandle != 0) - AttachThreadInput (GetWindowThreadProcessId (juce_messageWindowHandle, 0), + if (juce_messageWindowHandle != nullptr) + AttachThreadInput (GetWindowThreadProcessId (juce_messageWindowHandle, nullptr), GetCurrentThreadId(), TRUE); juce_threadEntryPoint (userData); @@ -80,7 +66,7 @@ static unsigned int __stdcall threadEntryProc (void* userData) void Thread::launchThread() { unsigned int newThreadId; - threadHandle = (void*) _beginthreadex (0, (unsigned int) threadStackSize, + threadHandle = (void*) _beginthreadex (nullptr, (unsigned int) threadStackSize, &threadEntryProc, this, 0, &newThreadId); threadId = (ThreadID) (pointer_sized_int) newThreadId; } @@ -88,13 +74,13 @@ void Thread::launchThread() void Thread::closeThreadHandle() { CloseHandle ((HANDLE) threadHandle.get()); - threadId = 0; - threadHandle = 0; + threadId = nullptr; + threadHandle = nullptr; } void Thread::killThread() { - if (threadHandle.get() != 0) + if (threadHandle.get() != nullptr) { #if JUCE_DEBUG OutputDebugStringA ("** Warning - Forced thread termination **\n"); @@ -146,7 +132,7 @@ bool Thread::setThreadPriority (void* handle, int priority) else if (priority < 9) pri = THREAD_PRIORITY_ABOVE_NORMAL; else if (priority < 10) pri = THREAD_PRIORITY_HIGHEST; - if (handle == 0) + if (handle == nullptr) handle = GetCurrentThread(); return SetThreadPriority (handle, pri) != FALSE; @@ -172,7 +158,7 @@ struct SleepEvent ~SleepEvent() noexcept { CloseHandle (handle); - handle = 0; + handle = nullptr; } HANDLE handle; @@ -184,7 +170,7 @@ void JUCE_CALLTYPE Thread::sleep (const int millisecs) { jassert (millisecs >= 0); - if (millisecs >= 10 || sleepEvent.handle == 0) + if (millisecs >= 10 || sleepEvent.handle == nullptr) Sleep ((DWORD) millisecs); else // unlike Sleep() this is guaranteed to return to the current thread after @@ -258,15 +244,8 @@ void JUCE_CALLTYPE Process::setCurrentModuleInstanceHandle (void* const newHandl currentModuleHandle = newHandle; } -void JUCE_CALLTYPE Process::raisePrivilege() -{ - jassertfalse; // xxx not implemented -} - -void JUCE_CALLTYPE Process::lowerPrivilege() -{ - jassertfalse; // xxx not implemented -} +void JUCE_CALLTYPE Process::raisePrivilege() {} +void JUCE_CALLTYPE Process::lowerPrivilege() {} void JUCE_CALLTYPE Process::terminate() { @@ -281,7 +260,7 @@ void JUCE_CALLTYPE Process::terminate() bool juce_isRunningInWine() { HMODULE ntdll = GetModuleHandleA ("ntdll"); - return ntdll != 0 && GetProcAddress (ntdll, "wine_get_version") != nullptr; + return ntdll != nullptr && GetProcAddress (ntdll, "wine_get_version") != nullptr; } //============================================================================== @@ -313,18 +292,18 @@ class InterProcessLock::Pimpl { public: Pimpl (String name, const int timeOutMillisecs) - : handle (0), refCount (1) + : handle (nullptr), refCount (1) { name = name.replaceCharacter ('\\', '/'); - handle = CreateMutexW (0, TRUE, ("Global\\" + name).toWideCharPointer()); + handle = CreateMutexW (nullptr, TRUE, ("Global\\" + name).toWideCharPointer()); // Not 100% sure why a global mutex sometimes can't be allocated, but if it fails, fall back to // a local one. (A local one also sometimes fails on other machines so neither type appears to be // universally reliable) - if (handle == 0) - handle = CreateMutexW (0, TRUE, ("Local\\" + name).toWideCharPointer()); + if (handle == nullptr) + handle = CreateMutexW (nullptr, TRUE, ("Local\\" + name).toWideCharPointer()); - if (handle != 0 && GetLastError() == ERROR_ALREADY_EXISTS) + if (handle != nullptr && GetLastError() == ERROR_ALREADY_EXISTS) { if (timeOutMillisecs == 0) { @@ -332,7 +311,7 @@ class InterProcessLock::Pimpl return; } - switch (WaitForSingleObject (handle, timeOutMillisecs < 0 ? INFINITE : timeOutMillisecs)) + switch (WaitForSingleObject (handle, timeOutMillisecs < 0 ? INFINITE : (DWORD) timeOutMillisecs)) { case WAIT_OBJECT_0: case WAIT_ABANDONED: @@ -353,11 +332,11 @@ class InterProcessLock::Pimpl void close() { - if (handle != 0) + if (handle != nullptr) { ReleaseMutex (handle); CloseHandle (handle); - handle = 0; + handle = nullptr; } } @@ -382,7 +361,7 @@ bool InterProcessLock::enter (const int timeOutMillisecs) { pimpl.reset (new Pimpl (name, timeOutMillisecs)); - if (pimpl->handle == 0) + if (pimpl->handle == nullptr) pimpl.reset(); } else @@ -409,20 +388,20 @@ class ChildProcess::ActiveProcess { public: ActiveProcess (const String& command, int streamFlags) - : ok (false), readPipe (0), writePipe (0) + : ok (false), readPipe (nullptr), writePipe (nullptr) { - SECURITY_ATTRIBUTES securityAtts = { 0 }; + SECURITY_ATTRIBUTES securityAtts = {}; securityAtts.nLength = sizeof (securityAtts); securityAtts.bInheritHandle = TRUE; if (CreatePipe (&readPipe, &writePipe, &securityAtts, 0) && SetHandleInformation (readPipe, HANDLE_FLAG_INHERIT, 0)) { - STARTUPINFOW startupInfo = { 0 }; + STARTUPINFOW startupInfo = {}; startupInfo.cb = sizeof (startupInfo); - startupInfo.hStdOutput = (streamFlags & wantStdOut) != 0 ? writePipe : 0; - startupInfo.hStdError = (streamFlags & wantStdErr) != 0 ? writePipe : 0; + startupInfo.hStdOutput = (streamFlags & wantStdOut) != 0 ? writePipe : nullptr; + startupInfo.hStdError = (streamFlags & wantStdErr) != 0 ? writePipe : nullptr; startupInfo.dwFlags = STARTF_USESTDHANDLES; ok = CreateProcess (nullptr, const_cast (command.toWideCharPointer()), @@ -439,10 +418,10 @@ class ChildProcess::ActiveProcess CloseHandle (processInfo.hProcess); } - if (readPipe != 0) + if (readPipe != nullptr) CloseHandle (readPipe); - if (writePipe != 0) + if (writePipe != nullptr) CloseHandle (writePipe); } @@ -474,12 +453,12 @@ class ChildProcess::ActiveProcess else { DWORD numRead = 0; - if (! ReadFile ((HANDLE) readPipe, dest, numToDo, &numRead, nullptr)) + if (! ReadFile ((HANDLE) readPipe, dest, (DWORD) numToDo, &numRead, nullptr)) break; - total += numRead; + total += (int) numRead; dest = addBytesToPointer (dest, numRead); - numNeeded -= numRead; + numNeeded -= (int) numRead; } } @@ -560,7 +539,7 @@ struct HighResolutionTimer::Pimpl { const int actualPeriod = jlimit ((int) tc.wPeriodMin, (int) tc.wPeriodMax, newPeriod); - timerID = timeSetEvent (actualPeriod, tc.wPeriodMin, callbackFunction, (DWORD_PTR) this, + timerID = timeSetEvent ((UINT) actualPeriod, tc.wPeriodMin, callbackFunction, (DWORD_PTR) this, TIME_PERIODIC | TIME_CALLBACK_FUNCTION | 0x100 /*TIME_KILL_SYNCHRONOUS*/); } } diff --git a/JuceLibraryCode/modules/juce_core/network/juce_IPAddress.cpp b/JuceLibraryCode/modules/juce_core/network/juce_IPAddress.cpp index ec92df7..770aea0 100644 --- a/JuceLibraryCode/modules/juce_core/network/juce_IPAddress.cpp +++ b/JuceLibraryCode/modules/juce_core/network/juce_IPAddress.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. @@ -90,10 +90,10 @@ IPAddress::IPAddress (uint16 a1, uint16 a2, uint16 a3, uint16 a4, IPAddress::IPAddress (uint32 n) noexcept : isIPv6 (false) { - address[0] = (n >> 24); - address[1] = (n >> 16) & 255; - address[2] = (n >> 8) & 255; - address[3] = (n & 255); + address[0] = static_cast (n >> 24); + address[1] = static_cast ((n >> 16) & 255); + address[2] = static_cast ((n >> 8) & 255); + address[3] = static_cast ((n & 255)); zeroUnusedBytes (address); } @@ -372,15 +372,16 @@ Array IPAddress::getAllAddresses (bool includeIPv6) return addresses; } + +//============================================================================== //============================================================================== #if JUCE_UNIT_TESTS struct IPAddressTests : public UnitTest { IPAddressTests() - : UnitTest ("IPAddress", "Networking") - { - } + : UnitTest ("IPAddress", UnitTestCategories::networking) + {} void runTest() override { diff --git a/JuceLibraryCode/modules/juce_core/network/juce_IPAddress.h b/JuceLibraryCode/modules/juce_core/network/juce_IPAddress.h index ec8cd1b..72d1048 100644 --- a/JuceLibraryCode/modules/juce_core/network/juce_IPAddress.h +++ b/JuceLibraryCode/modules/juce_core/network/juce_IPAddress.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_core/network/juce_MACAddress.cpp b/JuceLibraryCode/modules/juce_core/network/juce_MACAddress.cpp index 0808beb..24931ec 100644 --- a/JuceLibraryCode/modules/juce_core/network/juce_MACAddress.cpp +++ b/JuceLibraryCode/modules/juce_core/network/juce_MACAddress.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_core/network/juce_MACAddress.h b/JuceLibraryCode/modules/juce_core/network/juce_MACAddress.h index e745f8d..bf7b0f5 100644 --- a/JuceLibraryCode/modules/juce_core/network/juce_MACAddress.h +++ b/JuceLibraryCode/modules/juce_core/network/juce_MACAddress.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_core/network/juce_NamedPipe.cpp b/JuceLibraryCode/modules/juce_core/network/juce_NamedPipe.cpp index af6e74b..98ea28e 100644 --- a/JuceLibraryCode/modules/juce_core/network/juce_NamedPipe.cpp +++ b/JuceLibraryCode/modules/juce_core/network/juce_NamedPipe.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. @@ -60,8 +60,9 @@ String NamedPipe::getName() const // other methods for this class are implemented in the platform-specific files -//============================================================================== +//============================================================================== +//============================================================================== #if JUCE_UNIT_TESTS class NamedPipeTests : public UnitTest @@ -69,7 +70,7 @@ class NamedPipeTests : public UnitTest public: //============================================================================== NamedPipeTests() - : UnitTest ("NamedPipe", "Networking") + : UnitTest ("NamedPipe", UnitTestCategories::networking) {} void runTest() override @@ -197,9 +198,9 @@ class NamedPipeTests : public UnitTest //============================================================================== struct NamedPipeThread : public Thread { - NamedPipeThread (const String& threadName, const String& pName, + NamedPipeThread (const String& tName, const String& pName, bool shouldCreatePipe, WaitableEvent& completed) - : Thread (threadName), pipeName (pName), workCompleted (completed) + : Thread (tName), pipeName (pName), workCompleted (completed) { if (shouldCreatePipe) pipe.createNewPipe (pipeName); @@ -207,6 +208,11 @@ class NamedPipeTests : public UnitTest pipe.openExisting (pipeName); } + ~NamedPipeThread() + { + stopThread (100); + } + NamedPipe pipe; const String& pipeName; WaitableEvent& workCompleted; diff --git a/JuceLibraryCode/modules/juce_core/network/juce_NamedPipe.h b/JuceLibraryCode/modules/juce_core/network/juce_NamedPipe.h index b3e8671..2bff8d9 100644 --- a/JuceLibraryCode/modules/juce_core/network/juce_NamedPipe.h +++ b/JuceLibraryCode/modules/juce_core/network/juce_NamedPipe.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_core/network/juce_Socket.cpp b/JuceLibraryCode/modules/juce_core/network/juce_Socket.cpp index 9d7c460..c8ea756 100644 --- a/JuceLibraryCode/modules/juce_core/network/juce_Socket.cpp +++ b/JuceLibraryCode/modules/juce_core/network/juce_Socket.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,29 +23,26 @@ namespace juce { -#if JUCE_MSVC - #pragma warning (push) - #pragma warning (disable : 4127 4389 4018) -#endif +JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4127 4389 4018) #ifndef AI_NUMERICSERV // (missing in older Mac SDKs) #define AI_NUMERICSERV 0x1000 #endif #if JUCE_WINDOWS - typedef int juce_socklen_t; - typedef int juce_recvsend_size_t; - typedef SOCKET SocketHandle; + using juce_socklen_t = int; + using juce_recvsend_size_t = int; + using SocketHandle = SOCKET; static const SocketHandle invalidSocket = INVALID_SOCKET; #elif JUCE_ANDROID - typedef socklen_t juce_socklen_t; - typedef size_t juce_recvsend_size_t; - typedef int SocketHandle; + using juce_socklen_t = socklen_t; + using juce_recvsend_size_t = size_t; + using SocketHandle = int; static const SocketHandle invalidSocket = -1; #else - typedef socklen_t juce_socklen_t; - typedef socklen_t juce_recvsend_size_t; - typedef int SocketHandle; + using juce_socklen_t = socklen_t; + using juce_recvsend_size_t = socklen_t; + using SocketHandle = int; static const SocketHandle invalidSocket = -1; #endif @@ -87,7 +84,7 @@ namespace SocketHelpers static bool resetSocketOptions (SocketHandle handle, bool isDatagram, bool allowBroadcast) noexcept { - return handle > 0 + return handle != invalidSocket && setOption (handle, SO_RCVBUF, (int) 65536) && setOption (handle, SO_SNDBUF, (int) 65536) && (isDatagram ? ((! allowBroadcast) || setOption (handle, SO_BROADCAST, (int) 1)) @@ -97,13 +94,13 @@ namespace SocketHelpers static void closeSocket (std::atomic& handle, CriticalSection& readLock, bool isListener, int portNumber, std::atomic& connected) noexcept { - const SocketHandle h = handle.load(); + const auto h = (SocketHandle) handle.load(); handle = -1; #if JUCE_WINDOWS ignoreUnused (portNumber, isListener, readLock); - if (h != (unsigned) SOCKET_ERROR || connected) + if (h != invalidSocket || connected) closesocket (h); // make sure any read process finishes before we delete the socket @@ -122,7 +119,7 @@ namespace SocketHelpers } } - if (h != -1) + if (h >= 0) { // unblock any pending read requests ::shutdown (h, SHUT_RDWR); @@ -147,7 +144,7 @@ namespace SocketHelpers static bool bindSocket (SocketHandle handle, int port, const String& address) noexcept { - if (handle <= 0 || ! isValidPortNumber (port)) + if (handle == invalidSocket || ! isValidPortNumber (port)) return false; struct sockaddr_in addr; @@ -163,7 +160,7 @@ namespace SocketHelpers static int getBoundPort (SocketHandle handle) noexcept { - if (handle > 0) + if (handle != invalidSocket) { struct sockaddr_in addr; socklen_t len = sizeof (addr); @@ -183,8 +180,35 @@ namespace SocketHelpers if (getpeername (handle, (struct sockaddr*) &addr, &len) >= 0) return inet_ntoa (addr.sin_addr); - return String ("0.0.0.0"); + return "0.0.0.0"; + } + + static bool setSocketBlockingState (SocketHandle handle, bool shouldBlock) noexcept + { + #if JUCE_WINDOWS + u_long nonBlocking = shouldBlock ? 0 : (u_long) 1; + return ioctlsocket (handle, (long) FIONBIO, &nonBlocking) == 0; + #else + int socketFlags = fcntl (handle, F_GETFL, 0); + + if (socketFlags == -1) + return false; + + if (shouldBlock) + socketFlags &= ~O_NONBLOCK; + else + socketFlags |= O_NONBLOCK; + + return fcntl (handle, F_SETFL, socketFlags) == 0; + #endif + } + + #if ! JUCE_WINDOWS + static bool getSocketBlockingState (SocketHandle handle) + { + return (fcntl (handle, F_GETFL, 0) & O_NONBLOCK) == 0; } + #endif static int readSocket (SocketHandle handle, void* destBuffer, int maxBytesToRead, @@ -194,6 +218,11 @@ namespace SocketHelpers String* senderIP = nullptr, int* senderPort = nullptr) noexcept { + #if ! JUCE_WINDOWS + if (blockUntilSpecifiedAmountHasArrived != getSocketBlockingState (handle)) + #endif + setSocketBlockingState (handle, blockUntilSpecifiedAmountHasArrived); + int bytesRead = 0; while (bytesRead < maxBytesToRead) @@ -233,7 +262,7 @@ namespace SocketHelpers break; } - bytesRead += bytesThisTime; + bytesRead = static_cast (bytesRead + bytesThisTime); if (! blockUntilSpecifiedAmountHasArrived) break; @@ -251,8 +280,25 @@ namespace SocketHelpers if (! lock.isLocked()) return -1; - int h = handle.load(); + auto hasErrorOccurred = [&handle]() -> bool + { + auto h = (SocketHandle) handle.load(); + + if (h == invalidSocket) + return true; + int opt; + juce_socklen_t len = sizeof (opt); + + if (getsockopt (h, SOL_SOCKET, SO_ERROR, (char*) &opt, &len) < 0 || opt != 0) + return true; + + return false; + }; + + auto h = handle.load(); + + #if JUCE_WINDOWS || JUCE_MINGW struct timeval timeout; struct timeval* timeoutp; @@ -269,64 +315,37 @@ namespace SocketHelpers fd_set rset, wset; FD_ZERO (&rset); - FD_SET (h, &rset); + FD_SET ((SOCKET) h, &rset); FD_ZERO (&wset); - FD_SET (h, &wset); + FD_SET ((SOCKET) h, &wset); - fd_set* const prset = forReading ? &rset : nullptr; - fd_set* const pwset = forReading ? nullptr : &wset; + fd_set* prset = forReading ? &rset : nullptr; + fd_set* pwset = forReading ? nullptr : &wset; - #if JUCE_WINDOWS - if (select ((int) h + 1, prset, pwset, 0, timeoutp) < 0) + // NB - need to use select() here as WSAPoll is broken on Windows + if (select ((int) h + 1, prset, pwset, nullptr, timeoutp) < 0 || hasErrorOccurred()) return -1; - #else - { - int result; - while ((result = select (h + 1, prset, pwset, nullptr, timeoutp)) < 0 - && errno == EINTR) - { - } - - if (result < 0) - return -1; - } - #endif + return FD_ISSET (h, forReading ? &rset : &wset) ? 1 : 0; + #else + short eventsFlag = (forReading ? POLLIN : POLLOUT); + pollfd pfd { (SocketHandle) h, eventsFlag, 0 }; - // we are closing - if (handle.load() < 0) - return -1; + int result = 0; + for (;;) { - int opt; - juce_socklen_t len = sizeof (opt); + result = poll (&pfd, 1, timeoutMsecs); - if (getsockopt (h, SOL_SOCKET, SO_ERROR, (char*) &opt, &len) < 0 - || opt != 0) - return -1; + if (result >= 0 || errno != EINTR) + break; } - return FD_ISSET (h, forReading ? &rset : &wset) ? 1 : 0; - } - - static bool setSocketBlockingState (SocketHandle handle, bool shouldBlock) noexcept - { - #if JUCE_WINDOWS - u_long nonBlocking = shouldBlock ? 0 : (u_long) 1; - return ioctlsocket (handle, FIONBIO, &nonBlocking) == 0; - #else - int socketFlags = fcntl (handle, F_GETFL, 0); - - if (socketFlags == -1) - return false; - - if (shouldBlock) - socketFlags &= ~O_NONBLOCK; - else - socketFlags |= O_NONBLOCK; + if (result < 0 || hasErrorOccurred()) + return -1; - return fcntl (handle, F_SETFL, socketFlags) == 0; - #endif + return (pfd.revents & eventsFlag) != 0; + #endif } static addrinfo* getAddressInfo (bool isDatagram, const String& hostName, int portNumber) @@ -399,8 +418,9 @@ namespace SocketHelpers if (success) { - setSocketBlockingState (handle, true); - resetSocketOptions (handle, false, false); + auto h = (SocketHandle) handle.load(); + setSocketBlockingState (h, true); + resetSocketOptions (h, false, false); } } @@ -409,7 +429,7 @@ namespace SocketHelpers static void makeReusable (int handle) noexcept { - setOption (handle, SO_REUSEADDR, (int) 1); + setOption ((SocketHandle) handle, SO_REUSEADDR, (int) 1); } static bool multicast (int handle, const String& multicastIPAddress, @@ -424,7 +444,7 @@ namespace SocketHelpers if (interfaceIPAddress.isNotEmpty()) mreq.imr_interface.s_addr = inet_addr (interfaceIPAddress.toRawUTF8()); - return setsockopt (handle, IPPROTO_IP, + return setsockopt ((SocketHandle) handle, IPPROTO_IP, join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, (const char*) &mreq, sizeof (mreq)) == 0; @@ -446,7 +466,7 @@ StreamingSocket::StreamingSocket (const String& host, int portNum, int h) jassert (SocketHelpers::isValidPortNumber (portNum)); SocketHelpers::initSockets(); - SocketHelpers::resetSocketOptions (h, false, false); + SocketHelpers::resetSocketOptions ((SocketHandle) h, false, false); } StreamingSocket::~StreamingSocket() @@ -457,7 +477,7 @@ StreamingSocket::~StreamingSocket() //============================================================================== int StreamingSocket::read (void* destBuffer, int maxBytesToRead, bool shouldBlock) { - return (connected && ! isListener) ? SocketHelpers::readSocket (handle, destBuffer, maxBytesToRead, + return (connected && ! isListener) ? SocketHelpers::readSocket ((SocketHandle) handle.load(), destBuffer,maxBytesToRead, connected, shouldBlock, readLock) : -1; } @@ -467,7 +487,7 @@ int StreamingSocket::write (const void* sourceBuffer, int numBytesToWrite) if (isListener || ! connected) return -1; - return (int) ::send (handle, (const char*) sourceBuffer, (juce_recvsend_size_t) numBytesToWrite, 0); + return (int) ::send ((SocketHandle) handle.load(), (const char*) sourceBuffer, (juce_recvsend_size_t) numBytesToWrite, 0); } //============================================================================== @@ -487,12 +507,12 @@ bool StreamingSocket::bindToPort (int port, const String& addr) { jassert (SocketHelpers::isValidPortNumber (port)); - return SocketHelpers::bindSocket (handle, port, addr); + return SocketHelpers::bindSocket ((SocketHandle) handle.load(), port, addr); } int StreamingSocket::getBoundPort() const noexcept { - return SocketHelpers::getBoundPort (handle); + return SocketHelpers::getBoundPort ((SocketHandle) handle.load()); } bool StreamingSocket::connect (const String& remoteHostName, int remotePortNumber, int timeOutMillisecs) @@ -501,7 +521,8 @@ bool StreamingSocket::connect (const String& remoteHostName, int remotePortNumbe if (isListener) { - jassertfalse; // a listener socket can't connect to another one! + // a listener socket can't connect to another one! + jassertfalse; return false; } @@ -515,7 +536,10 @@ bool StreamingSocket::connect (const String& remoteHostName, int remotePortNumbe connected = SocketHelpers::connectSocket (handle, readLock, remoteHostName, remotePortNumber, timeOutMillisecs); - if (! (connected && SocketHelpers::resetSocketOptions (handle, false, false))) + if (! connected) + return false; + + if (! SocketHelpers::resetSocketOptions ((SocketHandle) handle.load(), false, false)) { close(); return false; @@ -526,7 +550,8 @@ bool StreamingSocket::connect (const String& remoteHostName, int remotePortNumbe void StreamingSocket::close() { - SocketHelpers::closeSocket (handle, readLock, isListener, portNumber, connected); + if (handle >= 0) + SocketHelpers::closeSocket (handle, readLock, isListener, portNumber, connected); hostName.clear(); portNumber = 0; @@ -555,8 +580,8 @@ bool StreamingSocket::createListener (int newPortNumber, const String& localHost SocketHelpers::makeReusable (handle); #endif - if (SocketHelpers::bindSocket (handle, portNumber, localHostName) - && listen (handle, SOMAXCONN) >= 0) + if (SocketHelpers::bindSocket ((SocketHandle) handle.load(), portNumber, localHostName) + && listen ((SocketHandle) handle.load(), SOMAXCONN) >= 0) { connected = true; return true; @@ -576,7 +601,7 @@ StreamingSocket* StreamingSocket::waitForNextConnection() const { struct sockaddr_storage address; juce_socklen_t len = sizeof (address); - auto newSocket = (int) accept (handle, (struct sockaddr*) &address, &len); + auto newSocket = (int) accept ((SocketHandle) handle.load(), (struct sockaddr*) &address, &len); if (newSocket >= 0 && connected) return new StreamingSocket (inet_ntoa (((struct sockaddr_in*) &address)->sin_addr), @@ -591,7 +616,7 @@ bool StreamingSocket::isLocal() const noexcept if (! isConnected()) return false; - IPAddress currentIP (SocketHelpers::getConnectedAddress (handle)); + IPAddress currentIP (SocketHelpers::getConnectedAddress ((SocketHandle) handle.load())); for (auto& a : IPAddress::getAllAddresses()) if (a == currentIP) @@ -611,7 +636,7 @@ DatagramSocket::DatagramSocket (bool canBroadcast) if (handle >= 0) { - SocketHelpers::resetSocketOptions (handle, true, canBroadcast); + SocketHelpers::resetSocketOptions ((SocketHandle) handle.load(), true, canBroadcast); SocketHelpers::makeReusable (handle); } } @@ -631,8 +656,11 @@ void DatagramSocket::shutdown() std::atomic handleCopy { handle.load() }; handle = -1; + std::atomic connected { false }; SocketHelpers::closeSocket (handleCopy, readLock, false, 0, connected); + + isBound = false; } bool DatagramSocket::bindToPort (int port) @@ -644,7 +672,10 @@ bool DatagramSocket::bindToPort (int port, const String& addr) { jassert (SocketHelpers::isValidPortNumber (port)); - if (SocketHelpers::bindSocket (handle, port, addr)) + if (handle < 0) + return false; + + if (SocketHelpers::bindSocket ((SocketHandle) handle.load(), port, addr)) { isBound = true; lastBindAddress = addr; @@ -656,7 +687,7 @@ bool DatagramSocket::bindToPort (int port, const String& addr) int DatagramSocket::getBoundPort() const noexcept { - return (handle >= 0 && isBound) ? SocketHelpers::getBoundPort (handle) : -1; + return (handle >= 0 && isBound) ? SocketHelpers::getBoundPort ((SocketHandle) handle.load()) : -1; } //============================================================================== @@ -674,9 +705,7 @@ int DatagramSocket::read (void* destBuffer, int maxBytesToRead, bool shouldBlock return -1; std::atomic connected { true }; - - SocketHelpers::setSocketBlockingState (handle, shouldBlock); - return SocketHelpers::readSocket (handle, destBuffer, maxBytesToRead, + return SocketHelpers::readSocket ((SocketHandle) handle.load(), destBuffer, maxBytesToRead, connected, shouldBlock, readLock); } @@ -686,9 +715,7 @@ int DatagramSocket::read (void* destBuffer, int maxBytesToRead, bool shouldBlock return -1; std::atomic connected { true }; - - SocketHelpers::setSocketBlockingState (handle, shouldBlock); - return SocketHelpers::readSocket (handle, destBuffer, maxBytesToRead, connected, + return SocketHelpers::readSocket ((SocketHandle) handle.load(), destBuffer, maxBytesToRead, connected, shouldBlock, readLock, &senderIPAddress, &senderPort); } @@ -715,14 +742,14 @@ int DatagramSocket::write (const String& remoteHostname, int remotePortNumber, lastServerPort = remotePortNumber; } - return (int) ::sendto (handle, (const char*) sourceBuffer, + return (int) ::sendto ((SocketHandle) handle.load(), (const char*) sourceBuffer, (juce_recvsend_size_t) numBytesToWrite, 0, info->ai_addr, (socklen_t) info->ai_addrlen); } bool DatagramSocket::joinMulticast (const String& multicastIPAddress) { - if (! isBound || handle < 0) + if (handle < 0 || ! isBound) return false; return SocketHelpers::multicast (handle, multicastIPAddress, lastBindAddress, true); @@ -730,7 +757,7 @@ bool DatagramSocket::joinMulticast (const String& multicastIPAddress) bool DatagramSocket::leaveMulticast (const String& multicastIPAddress) { - if (! isBound || handle < 0) + if (handle < 0 || ! isBound) return false; return SocketHelpers::multicast (handle, multicastIPAddress, lastBindAddress, false); @@ -738,10 +765,10 @@ bool DatagramSocket::leaveMulticast (const String& multicastIPAddress) bool DatagramSocket::setMulticastLoopbackEnabled (bool enable) { - if (! isBound || handle < 0) + if (handle < 0 || ! isBound) return false; - return SocketHelpers::setOption (handle, IPPROTO_IP, IP_MULTICAST_LOOP, enable); + return SocketHelpers::setOption ((SocketHandle) handle.load(), IPPROTO_IP, IP_MULTICAST_LOOP, enable); } bool DatagramSocket::setEnablePortReuse (bool enabled) @@ -750,7 +777,7 @@ bool DatagramSocket::setEnablePortReuse (bool enabled) ignoreUnused (enabled); #else if (handle >= 0) - return SocketHelpers::setOption (handle, + return SocketHelpers::setOption ((SocketHandle) handle.load(), #if JUCE_WINDOWS || JUCE_LINUX SO_REUSEADDR, // port re-use is implied by addr re-use on these platforms #else @@ -762,8 +789,74 @@ bool DatagramSocket::setEnablePortReuse (bool enabled) return false; } -#if JUCE_MSVC - #pragma warning (pop) +JUCE_END_IGNORE_WARNINGS_MSVC + +//============================================================================== +//============================================================================== +#if JUCE_UNIT_TESTS + +struct SocketTests : public UnitTest +{ + SocketTests() + : UnitTest ("Sockets", UnitTestCategories::networking) + { + } + + void runTest() override + { + auto localHost = IPAddress::local(); + int portNum = 12345; + + beginTest ("StreamingSocket"); + { + StreamingSocket socketServer; + + expect (socketServer.isConnected() == false); + expect (socketServer.getHostName().isEmpty()); + expect (socketServer.getBoundPort() == -1); + expect (static_cast (socketServer.getRawSocketHandle()) == invalidSocket); + + expect (socketServer.createListener (portNum, localHost.toString())); + + StreamingSocket socket; + + expect (socket.connect (localHost.toString(), portNum)); + + expect (socket.isConnected() == true); + expect (socket.getHostName() == localHost.toString()); + expect (socket.getBoundPort() != -1); + expect (static_cast (socket.getRawSocketHandle()) != invalidSocket); + + socket.close(); + + expect (socket.isConnected() == false); + expect (socket.getHostName().isEmpty()); + expect (socket.getBoundPort() == -1); + expect (static_cast (socket.getRawSocketHandle()) == invalidSocket); + } + + beginTest ("DatagramSocket"); + { + DatagramSocket socket; + + expect (socket.getBoundPort() == -1); + expect (static_cast (socket.getRawSocketHandle()) != invalidSocket); + + expect (socket.bindToPort (portNum, localHost.toString())); + + expect (socket.getBoundPort() == portNum); + expect (static_cast (socket.getRawSocketHandle()) != invalidSocket); + + socket.shutdown(); + + expect (socket.getBoundPort() == -1); + expect (static_cast (socket.getRawSocketHandle()) == invalidSocket); + } + } +}; + +static SocketTests socketTests; + #endif } // namespace juce diff --git a/JuceLibraryCode/modules/juce_core/network/juce_Socket.h b/JuceLibraryCode/modules/juce_core/network/juce_Socket.h index f41ea7e..f73d789 100644 --- a/JuceLibraryCode/modules/juce_core/network/juce_Socket.h +++ b/JuceLibraryCode/modules/juce_core/network/juce_Socket.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. @@ -55,8 +55,8 @@ class JUCE_API StreamingSocket final //============================================================================== /** Binds the socket to the specified local port. - @returns true on success; false may indicate that another socket is already bound - on the same port + @returns true on success; false may indicate that another socket is already bound + on the same port */ bool bindToPort (int localPortNumber); @@ -66,8 +66,9 @@ class JUCE_API StreamingSocket final as well. This is useful if you would like to bind your socket to a specific network adapter. Note that localAddress must be an IP address assigned to one of your network address otherwise this function will fail. - @returns true on success; false may indicate that another socket is already bound - on the same port + + @returns true on success; false may indicate that another socket is already bound + on the same port @see bindToPort(int localPortNumber), IPAddress::getAllAddresses */ bool bindToPort (int localPortNumber, const String& localAddress); @@ -76,7 +77,9 @@ class JUCE_API StreamingSocket final This is useful if you need to know to which port the OS has actually bound your socket when calling the constructor or bindToPort with zero as the - localPortNumber argument. Returns -1 if the function fails. + localPortNumber argument. + + @returns -1 if the function fails */ int getBoundPort() const noexcept; @@ -85,7 +88,7 @@ class JUCE_API StreamingSocket final If timeOutMillisecs is 0, then this method will block until the operating system rejects the connection (which could take a long time). - @returns true if it succeeds. + @returns true if it succeeds, false if otherwise @see isConnected */ bool connect (const String& remoteHostname, @@ -119,8 +122,8 @@ class JUCE_API StreamingSocket final If the timeout is < 0, it will wait forever, or else will give up after the specified time. - If the socket is ready on return, this returns 1. If it times-out before - the socket becomes ready, it returns 0. If an error occurs, it returns -1. + @returns 1 if the socket is ready on return, 0 if it times-out before + the socket becomes ready, or -1 if an error occurs */ int waitUntilReady (bool readyForReading, int timeoutMsecs); @@ -131,7 +134,7 @@ class JUCE_API StreamingSocket final flag is false, the method will return as much data as is currently available without blocking. - @returns the number of bytes read, or -1 if there was an error. + @returns the number of bytes read, or -1 if there was an error @see waitUntilReady */ int read (void* destBuffer, int maxBytesToRead, @@ -142,7 +145,7 @@ class JUCE_API StreamingSocket final Note that this method will block unless you have checked the socket is ready for writing before calling it (see the waitUntilReady() method). - @returns the number of bytes written, or -1 if there was an error. + @returns the number of bytes written, or -1 if there was an error */ int write (const void* sourceBuffer, int numBytesToWrite); @@ -156,8 +159,8 @@ class JUCE_API StreamingSocket final @param portNumber the port number to listen on @param localHostName the interface address to listen on - pass an empty string to listen on all addresses - @returns true if it manages to open the socket successfully. + @returns true if it manages to open the socket successfully @see waitForNextConnection */ bool createListener (int portNumber, const String& localHostName = String()); @@ -177,8 +180,7 @@ class JUCE_API StreamingSocket final //============================================================================== String hostName; std::atomic portNumber { 0 }, handle { -1 }; - std::atomic connected { false }; - bool isListener = false; + std::atomic connected { false }, isListener { false }; mutable CriticalSection readLock; StreamingSocket (const String& hostname, int portNumber, int handle); @@ -202,8 +204,7 @@ class JUCE_API DatagramSocket final { public: //============================================================================== - /** - Creates a datagram socket. + /** Creates a datagram socket. You first need to bind this socket to a port with bindToPort if you intend to read from this socket. @@ -223,8 +224,8 @@ class JUCE_API DatagramSocket final The localPortNumber is the port on which to bind this socket. If this value is 0, the port number is assigned by the operating system. - @returns true on success; false may indicate that another socket is already bound - on the same port + @returns true on success; false may indicate that another socket is already bound + on the same port */ bool bindToPort (int localPortNumber); @@ -234,8 +235,9 @@ class JUCE_API DatagramSocket final as well. This is useful if you would like to bind your socket to a specific network adapter. Note that localAddress must be an IP address assigned to one of your network address otherwise this function will fail. - @returns true on success; false may indicate that another socket is already bound - on the same port + + @returns true on success; false may indicate that another socket is already bound + on the same port @see bindToPort(int localPortNumber), IPAddress::getAllAddresses */ bool bindToPort (int localPortNumber, const String& localAddress); @@ -245,7 +247,8 @@ class JUCE_API DatagramSocket final This is useful if you need to know to which port the OS has actually bound your socket when bindToPort was called with zero. - Returns -1 if the socket didn't bind to any port yet or an error occurred. */ + @returns -1 if the socket didn't bind to any port yet or an error occurred + */ int getBoundPort() const noexcept; /** Returns the OS's socket handle that's currently open. */ @@ -260,8 +263,8 @@ class JUCE_API DatagramSocket final If the timeout is < 0, it will wait forever, or else will give up after the specified time. - If the socket is ready on return, this returns 1. If it times-out before - the socket becomes ready, it returns 0. If an error occurs, it returns -1. + @returns 1 if the socket is ready on return, 0 if it times-out before the + socket becomes ready, or -1 if an error occurs */ int waitUntilReady (bool readyForReading, int timeoutMsecs); @@ -272,7 +275,7 @@ class JUCE_API DatagramSocket final flag is false, the method will return as much data as is currently available without blocking. - @returns the number of bytes read, or -1 if there was an error. + @returns the number of bytes read, or -1 if there was an error @see waitUntilReady */ int read (void* destBuffer, int maxBytesToRead, @@ -285,8 +288,8 @@ class JUCE_API DatagramSocket final flag is false, the method will return as much data as is currently available without blocking. - @returns the number of bytes read, or -1 if there was an error. On a successful - result, the senderIPAddress value will be set to the IP of the sender. + @returns the number of bytes read, or -1 if there was an error. On a successful + result, the senderIPAddress value will be set to the IP of the sender @see waitUntilReady */ int read (void* destBuffer, int maxBytesToRead, @@ -298,7 +301,7 @@ class JUCE_API DatagramSocket final Note that this method will block unless you have checked the socket is ready for writing before calling it (see the waitUntilReady() method). - @returns the number of bytes written, or -1 if there was an error. + @returns the number of bytes written, or -1 if there was an error */ int write (const String& remoteHostname, int remotePortNumber, const void* sourceBuffer, int numBytesToWrite); @@ -306,8 +309,10 @@ class JUCE_API DatagramSocket final /** Closes the underlying socket object. Closes the underlying socket object and aborts any read or write operations. - Note that all other methods will return an error after this call. This - method is useful if another thread is blocking in a read/write call and you + Note that all other methods will return an error after this call and the object + cannot be re-used. + + This method is useful if another thread is blocking in a read/write call and you would like to abort the read/write thread. Simply deleting the socket object without calling shutdown may cause a race-condition where the read/write returns just before the socket is deleted and the subsequent read/write would @@ -319,17 +324,20 @@ class JUCE_API DatagramSocket final //============================================================================== /** Join a multicast group. - @returns true if it succeeds. + + @returns true if it succeeds */ bool joinMulticast (const String& multicastIPAddress); /** Leave a multicast group. - @returns true if it succeeds. + + @returns true if it succeeds */ bool leaveMulticast (const String& multicastIPAddress); /** Enables or disables multicast loopback. - @returns true if it succeeds. + + @returns true if it succeeds */ bool setMulticastLoopbackEnabled (bool enableLoopback); @@ -340,7 +348,7 @@ class JUCE_API DatagramSocket final Do not use this if your socket handles sensitive data as it could be read by any, possibly malicious, third-party apps. - Returns true on success. + @returns true on success */ bool setEnablePortReuse (bool enabled); diff --git a/JuceLibraryCode/modules/juce_core/network/juce_URL.cpp b/JuceLibraryCode/modules/juce_core/network/juce_URL.cpp index 9b3a09c..08826de 100644 --- a/JuceLibraryCode/modules/juce_core/network/juce_URL.cpp +++ b/JuceLibraryCode/modules/juce_core/network/juce_URL.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. @@ -26,13 +26,13 @@ namespace juce struct FallbackDownloadTask : public URL::DownloadTask, public Thread { - FallbackDownloadTask (FileOutputStream* outputStreamToUse, + FallbackDownloadTask (std::unique_ptr outputStreamToUse, size_t bufferSizeToUse, - WebInputStream* streamToUse, + std::unique_ptr streamToUse, URL::DownloadTask::Listener* listenerToUse) : Thread ("DownloadTask thread"), - fileStream (outputStreamToUse), - stream (streamToUse), + fileStream (std::move (outputStreamToUse)), + stream (std::move (streamToUse)), bufferSize (bufferSizeToUse), buffer (bufferSize), listener (listenerToUse) @@ -62,8 +62,8 @@ struct FallbackDownloadTask : public URL::DownloadTask, if (listener != nullptr) listener->progress (this, downloaded, contentLength); - auto max = jmin ((int) bufferSize, contentLength < 0 ? std::numeric_limits::max() - : static_cast (contentLength - downloaded)); + auto max = (int) jmin ((int64) bufferSize, contentLength < 0 ? std::numeric_limits::max() + : static_cast (contentLength - downloaded)); auto actual = stream->read (buffer.get(), max); @@ -82,7 +82,7 @@ struct FallbackDownloadTask : public URL::DownloadTask, break; } - fileStream->flush(); + fileStream.reset(); if (threadShouldExit() || stream->isError()) error = true; @@ -97,7 +97,7 @@ struct FallbackDownloadTask : public URL::DownloadTask, } //============================================================================== - const std::unique_ptr fileStream; + std::unique_ptr fileStream; const std::unique_ptr stream; const size_t bufferSize; HeapBlock buffer; @@ -110,22 +110,25 @@ void URL::DownloadTask::Listener::progress (DownloadTask*, int64, int64) {} URL::DownloadTask::Listener::~Listener() {} //============================================================================== -URL::DownloadTask* URL::DownloadTask::createFallbackDownloader (const URL& urlToUse, - const File& targetFileToUse, - const String& extraHeadersToUse, - Listener* listenerToUse, - bool usePostRequest) +std::unique_ptr URL::DownloadTask::createFallbackDownloader (const URL& urlToUse, + const File& targetFileToUse, + const String& extraHeadersToUse, + Listener* listenerToUse, + bool usePostRequest) { const size_t bufferSize = 0x8000; targetFileToUse.deleteFile(); - if (auto outputStream = std::unique_ptr (targetFileToUse.createOutputStream (bufferSize))) + if (auto outputStream = targetFileToUse.createOutputStream (bufferSize)) { - std::unique_ptr stream (new WebInputStream (urlToUse, usePostRequest)); + auto stream = std::make_unique (urlToUse, usePostRequest); stream->withExtraHeaders (extraHeadersToUse); if (stream->connect (nullptr)) - return new FallbackDownloadTask (outputStream.release(), bufferSize, stream.release(), listenerToUse); + return std::make_unique (std::move (outputStream), + bufferSize, + std::move (stream), + listenerToUse); } return nullptr; @@ -135,7 +138,7 @@ URL::DownloadTask::DownloadTask() {} URL::DownloadTask::~DownloadTask() {} //============================================================================== -URL::URL() noexcept {} +URL::URL() {} URL::URL (const String& u) : url (u) { @@ -171,7 +174,6 @@ URL::URL (File localFile) url = "/" + url; } - url = "file://" + url; jassert (isWellFormed()); @@ -209,34 +211,6 @@ void URL::init() URL::URL (const String& u, int) : url (u) {} -URL::URL (URL&& other) - : url (std::move (other.url)), - postData (std::move (other.postData)), - parameterNames (std::move (other.parameterNames)), - parameterValues (std::move (other.parameterValues)), - filesToUpload (std::move (other.filesToUpload)) - #if JUCE_IOS - , bookmark (std::move (other.bookmark)) - #endif -{ -} - -URL& URL::operator= (URL&& other) -{ - url = std::move (other.url); - postData = std::move (other.postData); - parameterNames = std::move (other.parameterNames); - parameterValues = std::move (other.parameterValues); - filesToUpload = std::move (other.filesToUpload); - #if JUCE_IOS - bookmark = std::move (other.bookmark); - #endif - - return *this; -} - -URL::~URL() {} - URL URL::createWithoutParsing (const String& u) { return URL (u, 0); @@ -315,6 +289,20 @@ namespace URLHelpers else path += suffix; } + + static String removeLastPathSection (const String& url) + { + auto startOfPath = findStartOfPath (url); + auto lastSlash = url.lastIndexOfChar ('/'); + + if (lastSlash > startOfPath && lastSlash == url.length() - 1) + return removeLastPathSection (url.dropLastCharacters (1)); + + if (lastSlash < 0) + return url; + + return url.substring (0, std::max (startOfPath, lastSlash)); + } } void URL::addParameter (const String& name, const String& value) @@ -325,8 +313,8 @@ void URL::addParameter (const String& name, const String& value) String URL::toString (bool includeGetParameters) const { - if (includeGetParameters && parameterNames.size() > 0) - return url + "?" + URLHelpers::getMangledParameters (*this); + if (includeGetParameters) + return url + getQueryString(); return url; } @@ -347,12 +335,24 @@ String URL::getDomain() const return getDomainInternal (false); } -String URL::getSubPath() const +String URL::getSubPath (bool includeGetParameters) const { auto startOfPath = URLHelpers::findStartOfPath (url); + auto subPath = startOfPath <= 0 ? String() + : url.substring (startOfPath); + + if (includeGetParameters) + subPath += getQueryString(); - return startOfPath <= 0 ? String() - : url.substring (startOfPath); + return subPath; +} + +String URL::getQueryString() const +{ + if (parameterNames.size() > 0) + return "?" + URLHelpers::getMangledParameters (*this); + + return {}; } String URL::getScheme() const @@ -360,10 +360,10 @@ String URL::getScheme() const return url.substring (0, URLHelpers::findEndOfScheme (url) - 1); } -#ifndef JUCE_ANDROID +#if ! JUCE_ANDROID bool URL::isLocalFile() const { - return (getScheme() == "file"); + return getScheme() == "file"; } File URL::getLocalFile() const @@ -387,7 +387,7 @@ File URL::fileFromFileSchemeURL (const URL& fileURL) auto path = removeEscapeChars (fileURL.getDomainInternal (true)).replace ("+", "%2B"); - #ifdef JUCE_WINDOWS + #if JUCE_WINDOWS bool isUncPath = (! fileURL.url.startsWith ("file:///")); #else path = File::getSeparatorString() + path; @@ -398,7 +398,7 @@ File URL::fileFromFileSchemeURL (const URL& fileURL) for (auto urlElement : urlElements) path += File::getSeparatorString() + removeEscapeChars (urlElement.replace ("+", "%2B")); - #ifdef JUCE_WINDOWS + #if JUCE_WINDOWS if (isUncPath) path = "\\\\" + path; #endif @@ -422,10 +422,10 @@ URL URL::withNewDomainAndPath (const String& newURL) const URL URL::withNewSubPath (const String& newPath) const { - const int startOfPath = URLHelpers::findStartOfPath (url); - URL u (*this); + auto startOfPath = URLHelpers::findStartOfPath (url); + if (startOfPath > 0) u.url = url.substring (0, startOfPath); @@ -433,6 +433,13 @@ URL URL::withNewSubPath (const String& newPath) const return u; } +URL URL::getParentURL() const +{ + URL u (*this); + u.url = URLHelpers::removeLastPathSection (u.url); + return u; +} + URL URL::getChildURL (const String& subPath) const { URL u (*this); @@ -498,18 +505,15 @@ void URL::createHeadersAndPostData (String& headers, MemoryBlock& postDataToWrit //============================================================================== bool URL::isProbablyAWebsiteURL (const String& possibleURL) { - static const char* validProtocols[] = { "http:", "ftp:", "https:" }; - - for (auto* protocol : validProtocols) + for (auto* protocol : { "http:", "https:", "ftp:" }) if (possibleURL.startsWithIgnoreCase (protocol)) return true; - if (possibleURL.containsChar ('@') - || possibleURL.containsChar (' ')) + if (possibleURL.containsChar ('@') || possibleURL.containsChar (' ')) return false; - const String topLevelDomain (possibleURL.upToFirstOccurrenceOf ("/", false, false) - .fromLastOccurrenceOf (".", false, false)); + auto topLevelDomain = possibleURL.upToFirstOccurrenceOf ("/", false, false) + .fromLastOccurrenceOf (".", false, false); return topLevelDomain.isNotEmpty() && topLevelDomain.length() <= 3; } @@ -536,8 +540,7 @@ String URL::getDomainInternal (bool ignorePort) const } #if JUCE_IOS -URL::Bookmark::Bookmark (void* bookmarkToUse) - : data (bookmarkToUse) +URL::Bookmark::Bookmark (void* bookmarkToUse) : data (bookmarkToUse) { } @@ -628,12 +631,10 @@ class iOSFileStreamWrapper : public Stream return urlToUse.getLocalFile(); } - else - { - auto desc = [error localizedDescription]; - ignoreUnused (desc); - jassertfalse; - } + + auto desc = [error localizedDescription]; + ignoreUnused (desc); + jassertfalse; } return urlToUse.getLocalFile(); @@ -657,28 +658,27 @@ class iOSFileStreamWrapper : public Stream #endif //============================================================================== -InputStream* URL::createInputStream (bool usePostCommand, - OpenStreamProgressCallback* progressCallback, - void* progressCallbackContext, - String headers, - int timeOutMs, - StringPairArray* responseHeaders, - int* statusCode, - int numRedirectsToFollow, - String httpRequestCmd) const +std::unique_ptr URL::createInputStream (bool usePostCommand, + OpenStreamProgressCallback* progressCallback, + void* progressCallbackContext, + String headers, + int timeOutMs, + StringPairArray* responseHeaders, + int* statusCode, + int numRedirectsToFollow, + String httpRequestCmd) const { if (isLocalFile()) { #if JUCE_IOS // We may need to refresh the embedded bookmark. - return new iOSFileStreamWrapper (const_cast(*this)); + return std::make_unique> (const_cast(*this)); #else return getLocalFile().createInputStream(); #endif - } - std::unique_ptr wi (new WebInputStream (*this, usePostCommand)); + auto wi = std::make_unique (*this, usePostCommand); struct ProgressCallbackCaller : public WebInputStream::Listener { @@ -693,10 +693,6 @@ InputStream* URL::createInputStream (bool usePostCommand, OpenStreamProgressCallback* callback; void* const data; - - // workaround a MSVC 2013 compiler warning - ProgressCallbackCaller (const ProgressCallbackCaller& o) : callback (o.callback), data (o.data) { jassertfalse; } - ProgressCallbackCaller& operator= (const ProgressCallbackCaller&) { jassertfalse; return *this; } }; std::unique_ptr callbackCaller @@ -724,27 +720,29 @@ InputStream* URL::createInputStream (bool usePostCommand, if (! success || wi->isError()) return nullptr; - return wi.release(); + // Older GCCs complain about binding unique_ptr&& to unique_ptr + // if we just `return wi` here. + return std::unique_ptr (std::move (wi)); } #if JUCE_ANDROID OutputStream* juce_CreateContentURIOutputStream (const URL&); #endif -OutputStream* URL::createOutputStream() const +std::unique_ptr URL::createOutputStream() const { if (isLocalFile()) { #if JUCE_IOS // We may need to refresh the embedded bookmark. - return new iOSFileStreamWrapper (const_cast (*this)); + return std::make_unique> (const_cast (*this)); #else - return new FileOutputStream (getLocalFile()); + return std::make_unique (getLocalFile()); #endif } #if JUCE_ANDROID - return juce_CreateContentURIOutputStream (*this); + return std::unique_ptr (juce_CreateContentURIOutputStream (*this)); #else return nullptr; #endif @@ -754,7 +752,7 @@ OutputStream* URL::createOutputStream() const bool URL::readEntireBinaryStream (MemoryBlock& destData, bool usePostCommand) const { const std::unique_ptr in (isLocalFile() ? getLocalFile().createInputStream() - : static_cast (createInputStream (usePostCommand))); + : createInputStream (usePostCommand)); if (in != nullptr) { @@ -768,7 +766,7 @@ bool URL::readEntireBinaryStream (MemoryBlock& destData, bool usePostCommand) co String URL::readEntireTextStream (bool usePostCommand) const { const std::unique_ptr in (isLocalFile() ? getLocalFile().createInputStream() - : static_cast (createInputStream (usePostCommand))); + : createInputStream (usePostCommand)); if (in != nullptr) return in->readEntireStreamAsString(); @@ -776,23 +774,23 @@ String URL::readEntireTextStream (bool usePostCommand) const return {}; } -XmlElement* URL::readEntireXmlStream (bool usePostCommand) const +std::unique_ptr URL::readEntireXmlStream (bool usePostCommand) const { - return XmlDocument::parse (readEntireTextStream (usePostCommand)); + return parseXML (readEntireTextStream (usePostCommand)); } //============================================================================== URL URL::withParameter (const String& parameterName, const String& parameterValue) const { - URL u (*this); + auto u = *this; u.addParameter (parameterName, parameterValue); return u; } URL URL::withParameters (const StringPairArray& parametersToAdd) const { - URL u (*this); + auto u = *this; for (int i = 0; i < parametersToAdd.size(); ++i) u.addParameter (parametersToAdd.getAllKeys()[i], @@ -808,7 +806,7 @@ URL URL::withPOSTData (const String& newPostData) const URL URL::withPOSTData (const MemoryBlock& newPostData) const { - URL u (*this); + auto u = *this; u.postData = newPostData; return u; } @@ -822,7 +820,7 @@ URL::Upload::Upload (const String& param, const String& name, URL URL::withUpload (Upload* const f) const { - URL u (*this); + auto u = *this; for (int i = u.filesToUpload.size(); --i >= 0;) if (u.filesToUpload.getObjectPointerUnchecked(i)->parameterName == f->parameterName) diff --git a/JuceLibraryCode/modules/juce_core/network/juce_URL.h b/JuceLibraryCode/modules/juce_core/network/juce_URL.h index 2085261..29e906e 100644 --- a/JuceLibraryCode/modules/juce_core/network/juce_URL.h +++ b/JuceLibraryCode/modules/juce_core/network/juce_URL.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,7 +39,7 @@ class JUCE_API URL public: //============================================================================== /** Creates an empty URL. */ - URL() noexcept; + URL(); /** Creates a URL from a string. This will parse any embedded parameters after a '?' character and store them @@ -50,16 +50,14 @@ class JUCE_API URL URL (const URL&) = default; URL& operator= (const URL&) = default; - - // VS2013 can't default move constructors and assignments - URL (URL&&); - URL& operator= (URL&&); + URL (URL&&) = default; + URL& operator= (URL&&) = default; /** Creates URL referring to a local file on your disk using the file:// scheme. */ explicit URL (File); /** Destructor. */ - ~URL(); + ~URL() = default; /** Compares two URLs. All aspects of the URLs must be identical for them to match, including any parameters, @@ -90,8 +88,17 @@ class JUCE_API URL /** Returns the path part of the URL. E.g. for "http://www.xyz.com/foo/bar?x=1", this will return "foo/bar". + + If includeGetParameters is true and any parameters have been set with the + withParameter() method, then the string will have these appended on the + end and url-encoded. */ - String getSubPath() const; + String getSubPath (bool includeGetParameters = false) const; + + /** If any parameters are set, returns these URL encoded, including the "?" + * prefix. + */ + String getQueryString() const; /** Returns the scheme of the URL. E.g. for "http://www.xyz.com/foobar", this will return "http". (It won't @@ -141,6 +148,11 @@ class JUCE_API URL */ URL withNewSubPath (const String& newPath) const; + /** Attempts to return a URL which is the parent folder containing this URL. + If there isn't a parent, this method will just return a copy of this URL. + */ + URL getParentURL() const; + /** Returns a new URL that refers to a sub-path relative to this one. E.g. if the URL is "http://www.xyz.com/foo" and you call this with "bar", it'll return "http://www.xyz.com/foo/bar". Note that there's no way for @@ -256,7 +268,7 @@ class JUCE_API URL URL withPOSTData (const MemoryBlock& postData) const; /** Returns the data that was set using withPOSTData(). */ - String getPostData() const noexcept { return postData.toString(); } + String getPostData() const { return postData.toString(); } /** Returns the data that was set using withPOSTData() as MemoryBlock. */ const MemoryBlock& getPostDataAsMemoryBlock() const noexcept { return postData; } @@ -325,25 +337,24 @@ class JUCE_API URL returning a response (ignored for Android which follows up to 5 redirects) @param httpRequestCmd Specify which HTTP Request to use. If this is empty, then doPostRequest will determine the HTTP request. - @returns an input stream that the caller must delete, or a null pointer if there was an - error trying to open it. + @returns a valid input stream, or nullptr if there was an error trying to open it. */ - InputStream* createInputStream (bool doPostLikeRequest, - OpenStreamProgressCallback* progressCallback = nullptr, - void* progressCallbackContext = nullptr, - String extraHeaders = String(), - int connectionTimeOutMs = 0, - StringPairArray* responseHeaders = nullptr, - int* statusCode = nullptr, - int numRedirectsToFollow = 5, - String httpRequestCmd = String()) const; + std::unique_ptr createInputStream (bool doPostLikeRequest, + OpenStreamProgressCallback* progressCallback = nullptr, + void* progressCallbackContext = nullptr, + String extraHeaders = {}, + int connectionTimeOutMs = 0, + StringPairArray* responseHeaders = nullptr, + int* statusCode = nullptr, + int numRedirectsToFollow = 5, + String httpRequestCmd = {}) const; /** Attempts to open an output stream to a URL for writing This method can only be used for certain scheme types such as local files and content:// URIs on Android. */ - OutputStream* createOutputStream() const; + std::unique_ptr createOutputStream() const; //============================================================================== /** Represents a download task. @@ -403,7 +414,7 @@ class JUCE_API URL private: friend class URL; - static DownloadTask* createFallbackDownloader (const URL&, const File&, const String&, Listener*, bool); + static std::unique_ptr createFallbackDownloader (const URL&, const File&, const String&, Listener*, bool); public: #if JUCE_IOS @@ -424,10 +435,10 @@ class JUCE_API URL using a native OS background network task. Such tasks automatically deal with network re-connections and continuing your download while your app is suspended. */ - DownloadTask* downloadToFile (const File& targetLocation, - String extraHeaders = String(), - DownloadTask::Listener* listener = nullptr, - bool usePostCommand = false); + std::unique_ptr downloadToFile (const File& targetLocation, + String extraHeaders = String(), + DownloadTask::Listener* listener = nullptr, + bool usePostCommand = false); //============================================================================== /** Tries to download the entire contents of this URL into a binary data block. @@ -467,9 +478,6 @@ class JUCE_API URL If it fails, or if the text that it reads can't be parsed as XML, this will return nullptr. - When it returns a valid XmlElement object, the caller is responsible for deleting - this object when no longer needed. - Note that on some platforms (Android, for example) it's not permitted to do any network action from the message thread, so you must only call it from a background thread. @@ -478,7 +486,7 @@ class JUCE_API URL @see readEntireBinaryStream, readEntireTextStream */ - XmlElement* readEntireXmlStream (bool usePostCommand = false) const; + std::unique_ptr readEntireXmlStream (bool usePostCommand = false) const; //============================================================================== /** Adds escape sequences to a string to encode any characters that aren't diff --git a/JuceLibraryCode/modules/juce_core/network/juce_WebInputStream.cpp b/JuceLibraryCode/modules/juce_core/network/juce_WebInputStream.cpp index 9afc8af..23be502 100644 --- a/JuceLibraryCode/modules/juce_core/network/juce_WebInputStream.cpp +++ b/JuceLibraryCode/modules/juce_core/network/juce_WebInputStream.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_core/network/juce_WebInputStream.h b/JuceLibraryCode/modules/juce_core/network/juce_WebInputStream.h index da0f6a7..bcbab89 100644 --- a/JuceLibraryCode/modules/juce_core/network/juce_WebInputStream.h +++ b/JuceLibraryCode/modules/juce_core/network/juce_WebInputStream.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. @@ -190,10 +190,10 @@ class JUCE_API WebInputStream : public InputStream The position is an absolute number of bytes from the stream's start. For a WebInputStream, this method will fail if wantedPos is smaller - than the curent position. If wantedPos is greater than the current + than the current position. If wantedPos is greater than the current position, then calling setPosition is the same as calling read, i.e. the skipped data will still be downloaded, although skipped bytes will - be discarded immedietely. + be discarded immediately. @returns true if the stream manages to reposition itself correctly @see getPosition diff --git a/JuceLibraryCode/modules/juce_core/streams/juce_BufferedInputStream.cpp b/JuceLibraryCode/modules/juce_core/streams/juce_BufferedInputStream.cpp index 91acbd7..210521b 100644 --- a/JuceLibraryCode/modules/juce_core/streams/juce_BufferedInputStream.cpp +++ b/JuceLibraryCode/modules/juce_core/streams/juce_BufferedInputStream.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,7 @@ namespace juce { -static inline int calcBufferStreamBufferSize (int requestedSize, InputStream* source) noexcept +static int calcBufferStreamBufferSize (int requestedSize, InputStream* source) noexcept { // You need to supply a real stream when creating a BufferedInputStream jassert (source != nullptr); @@ -196,13 +196,15 @@ String BufferedInputStream::readString() return InputStream::readString(); } + +//============================================================================== //============================================================================== #if JUCE_UNIT_TESTS struct BufferedInputStreamTests : public UnitTest { BufferedInputStreamTests() - : UnitTest ("BufferedInputStream", "Streams") + : UnitTest ("BufferedInputStream", UnitTestCategories::streams) {} void runTest() override diff --git a/JuceLibraryCode/modules/juce_core/streams/juce_BufferedInputStream.h b/JuceLibraryCode/modules/juce_core/streams/juce_BufferedInputStream.h index 3892790..01274ee 100644 --- a/JuceLibraryCode/modules/juce_core/streams/juce_BufferedInputStream.h +++ b/JuceLibraryCode/modules/juce_core/streams/juce_BufferedInputStream.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_core/streams/juce_FileInputSource.cpp b/JuceLibraryCode/modules/juce_core/streams/juce_FileInputSource.cpp index 5055809..a1abb8b 100644 --- a/JuceLibraryCode/modules/juce_core/streams/juce_FileInputSource.cpp +++ b/JuceLibraryCode/modules/juce_core/streams/juce_FileInputSource.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. @@ -34,12 +34,12 @@ FileInputSource::~FileInputSource() InputStream* FileInputSource::createInputStream() { - return file.createInputStream(); + return file.createInputStream().release(); } InputStream* FileInputSource::createInputStreamFor (const String& relatedItemPath) { - return file.getSiblingFile (relatedItemPath).createInputStream(); + return file.getSiblingFile (relatedItemPath).createInputStream().release(); } int64 FileInputSource::hashCode() const diff --git a/JuceLibraryCode/modules/juce_core/streams/juce_FileInputSource.h b/JuceLibraryCode/modules/juce_core/streams/juce_FileInputSource.h index f1cce97..62bf6ce 100644 --- a/JuceLibraryCode/modules/juce_core/streams/juce_FileInputSource.h +++ b/JuceLibraryCode/modules/juce_core/streams/juce_FileInputSource.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_core/streams/juce_InputSource.h b/JuceLibraryCode/modules/juce_core/streams/juce_InputSource.h index 9c4e293..e2e72ac 100644 --- a/JuceLibraryCode/modules/juce_core/streams/juce_InputSource.h +++ b/JuceLibraryCode/modules/juce_core/streams/juce_InputSource.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_core/streams/juce_InputStream.cpp b/JuceLibraryCode/modules/juce_core/streams/juce_InputStream.cpp index f4fe3b8..d9c251d 100644 --- a/JuceLibraryCode/modules/juce_core/streams/juce_InputStream.cpp +++ b/JuceLibraryCode/modules/juce_core/streams/juce_InputStream.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. @@ -33,6 +33,26 @@ int64 InputStream::getNumBytesRemaining() return len; } +ssize_t InputStream::read (void* destBuffer, size_t size) +{ + ssize_t totalRead = 0; + + while (size > 0) + { + auto numToRead = (int) std::min (size, (size_t) 0x70000000); + auto numRead = read (juce::addBytesToPointer (destBuffer, totalRead), numToRead); + jassert (numRead <= numToRead); + + if (numRead < 0) return (ssize_t) numRead; + if (numRead == 0) break; + + size -= (size_t) numRead; + totalRead += numRead; + } + + return totalRead; +} + char InputStream::readByte() { char temp = 0; diff --git a/JuceLibraryCode/modules/juce_core/streams/juce_InputStream.h b/JuceLibraryCode/modules/juce_core/streams/juce_InputStream.h index b1ad21f..7767a16 100644 --- a/JuceLibraryCode/modules/juce_core/streams/juce_InputStream.h +++ b/JuceLibraryCode/modules/juce_core/streams/juce_InputStream.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. @@ -77,6 +77,8 @@ class JUCE_API InputStream */ virtual int read (void* destBuffer, int maxBytesToRead) = 0; + ssize_t read (void* destBuffer, size_t maxBytesToRead); + /** Reads a byte from the stream. If the stream is exhausted, this will return zero. @see OutputStream::writeByte diff --git a/JuceLibraryCode/modules/juce_core/streams/juce_MemoryInputStream.cpp b/JuceLibraryCode/modules/juce_core/streams/juce_MemoryInputStream.cpp index 3ffcc37..1f504d8 100644 --- a/JuceLibraryCode/modules/juce_core/streams/juce_MemoryInputStream.cpp +++ b/JuceLibraryCode/modules/juce_core/streams/juce_MemoryInputStream.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,7 +28,10 @@ MemoryInputStream::MemoryInputStream (const void* sourceData, size_t sourceDataS dataSize (sourceDataSize) { if (keepCopy) - createInternalCopy(); + { + internalCopy = MemoryBlock (sourceData, sourceDataSize); + data = internalCopy.getData(); + } } MemoryInputStream::MemoryInputStream (const MemoryBlock& sourceData, bool keepCopy) @@ -36,14 +39,17 @@ MemoryInputStream::MemoryInputStream (const MemoryBlock& sourceData, bool keepCo dataSize (sourceData.getSize()) { if (keepCopy) - createInternalCopy(); + { + internalCopy = sourceData; + data = internalCopy.getData(); + } } -void MemoryInputStream::createInternalCopy() +MemoryInputStream::MemoryInputStream (MemoryBlock&& source) + : internalCopy (std::move (source)) { - internalCopy.malloc (dataSize); - memcpy (internalCopy, data, dataSize); - data = internalCopy; + data = internalCopy.getData(); + dataSize = internalCopy.getSize(); } MemoryInputStream::~MemoryInputStream() @@ -95,6 +101,8 @@ void MemoryInputStream::skipNextBytes (int64 numBytesToSkip) setPosition (getPosition() + numBytesToSkip); } + +//============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -102,7 +110,7 @@ class MemoryStreamTests : public UnitTest { public: MemoryStreamTests() - : UnitTest ("MemoryInputStream & MemoryOutputStream", "Streams") + : UnitTest ("MemoryInputStream & MemoryOutputStream", UnitTestCategories::streams) {} void runTest() override diff --git a/JuceLibraryCode/modules/juce_core/streams/juce_MemoryInputStream.h b/JuceLibraryCode/modules/juce_core/streams/juce_MemoryInputStream.h index 81aece1..6fbcea1 100644 --- a/JuceLibraryCode/modules/juce_core/streams/juce_MemoryInputStream.h +++ b/JuceLibraryCode/modules/juce_core/streams/juce_MemoryInputStream.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. @@ -62,6 +62,9 @@ class JUCE_API MemoryInputStream : public InputStream MemoryInputStream (const MemoryBlock& data, bool keepInternalCopyOfData); + /** Creates a stream by moving from a MemoryBlock. */ + MemoryInputStream (MemoryBlock&& blockToTake); + /** Destructor. */ ~MemoryInputStream() override; @@ -83,9 +86,7 @@ class JUCE_API MemoryInputStream : public InputStream //============================================================================== const void* data; size_t dataSize, position = 0; - HeapBlock internalCopy; - - void createInternalCopy(); + MemoryBlock internalCopy; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryInputStream) }; diff --git a/JuceLibraryCode/modules/juce_core/streams/juce_MemoryOutputStream.cpp b/JuceLibraryCode/modules/juce_core/streams/juce_MemoryOutputStream.cpp index e498d31..946a12c 100644 --- a/JuceLibraryCode/modules/juce_core/streams/juce_MemoryOutputStream.cpp +++ b/JuceLibraryCode/modules/juce_core/streams/juce_MemoryOutputStream.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_core/streams/juce_MemoryOutputStream.h b/JuceLibraryCode/modules/juce_core/streams/juce_MemoryOutputStream.h index efd9140..b43f451 100644 --- a/JuceLibraryCode/modules/juce_core/streams/juce_MemoryOutputStream.h +++ b/JuceLibraryCode/modules/juce_core/streams/juce_MemoryOutputStream.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,7 +45,7 @@ class JUCE_API MemoryOutputStream : public OutputStream Note that the destination block will always be larger than the amount of data that has been written to the stream, because the MemoryOutputStream keeps some - spare capactity at its end. To trim the block's size down to fit the actual + spare capacity at its end. To trim the block's size down to fit the actual data, call flush(), or delete the MemoryOutputStream. @param memoryBlockToWriteTo the block into which new data will be written. diff --git a/JuceLibraryCode/modules/juce_core/streams/juce_OutputStream.cpp b/JuceLibraryCode/modules/juce_core/streams/juce_OutputStream.cpp index 07978ee..ed04d9a 100644 --- a/JuceLibraryCode/modules/juce_core/streams/juce_OutputStream.cpp +++ b/JuceLibraryCode/modules/juce_core/streams/juce_OutputStream.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,9 +25,10 @@ namespace juce #if JUCE_DEBUG +//============================================================================== struct DanglingStreamChecker { - DanglingStreamChecker() {} + DanglingStreamChecker() = default; ~DanglingStreamChecker() { @@ -38,12 +39,20 @@ struct DanglingStreamChecker nastiness.. */ jassert (activeStreams.size() == 0); + + // We need to flag when this helper struct has been destroyed to prevent some + // nasty order-of-static-destruction issues + hasBeenDestroyed = true; } Array activeStreams; + + static bool hasBeenDestroyed; }; +bool DanglingStreamChecker::hasBeenDestroyed = false; static DanglingStreamChecker danglingStreamChecker; + #endif //============================================================================== @@ -51,14 +60,16 @@ OutputStream::OutputStream() : newLineString (NewLine::getDefault()) { #if JUCE_DEBUG - danglingStreamChecker.activeStreams.add (this); + if (! DanglingStreamChecker::hasBeenDestroyed) + danglingStreamChecker.activeStreams.add (this); #endif } OutputStream::~OutputStream() { #if JUCE_DEBUG - danglingStreamChecker.activeStreams.removeFirstMatchingValue (this); + if (! DanglingStreamChecker::hasBeenDestroyed) + danglingStreamChecker.activeStreams.removeFirstMatchingValue (this); #endif } diff --git a/JuceLibraryCode/modules/juce_core/streams/juce_OutputStream.h b/JuceLibraryCode/modules/juce_core/streams/juce_OutputStream.h index 84a51c6..a0ba1a4 100644 --- a/JuceLibraryCode/modules/juce_core/streams/juce_OutputStream.h +++ b/JuceLibraryCode/modules/juce_core/streams/juce_OutputStream.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_core/streams/juce_SubregionStream.cpp b/JuceLibraryCode/modules/juce_core/streams/juce_SubregionStream.cpp index 8f3e10b..37e3bbe 100644 --- a/JuceLibraryCode/modules/juce_core/streams/juce_SubregionStream.cpp +++ b/JuceLibraryCode/modules/juce_core/streams/juce_SubregionStream.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. @@ -78,13 +78,15 @@ bool SubregionStream::isExhausted() return source->isExhausted(); } + +//============================================================================== //============================================================================== #if JUCE_UNIT_TESTS struct SubregionInputStreamTests : public UnitTest { SubregionInputStreamTests() - : UnitTest ("SubregionInputStream", "Streams") + : UnitTest ("SubregionInputStream", UnitTestCategories::streams) {} void runTest() override diff --git a/JuceLibraryCode/modules/juce_core/streams/juce_SubregionStream.h b/JuceLibraryCode/modules/juce_core/streams/juce_SubregionStream.h index afc12ea..22ece54 100644 --- a/JuceLibraryCode/modules/juce_core/streams/juce_SubregionStream.h +++ b/JuceLibraryCode/modules/juce_core/streams/juce_SubregionStream.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_core/streams/juce_URLInputSource.cpp b/JuceLibraryCode/modules/juce_core/streams/juce_URLInputSource.cpp index c257faf..be7e686 100644 --- a/JuceLibraryCode/modules/juce_core/streams/juce_URLInputSource.cpp +++ b/JuceLibraryCode/modules/juce_core/streams/juce_URLInputSource.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. @@ -39,7 +39,7 @@ URLInputSource::~URLInputSource() InputStream* URLInputSource::createInputStream() { - return u.createInputStream (false); + return u.createInputStream (false).release(); } InputStream* URLInputSource::createInputStreamFor (const String& relatedItemPath) @@ -48,7 +48,7 @@ InputStream* URLInputSource::createInputStreamFor (const String& relatedItemPath auto parent = sub.containsChar (L'/') ? sub.upToLastOccurrenceOf ("/", false, false) : String (); - return u.withNewSubPath (parent).getChildURL (relatedItemPath).createInputStream (false); + return u.withNewSubPath (parent).getChildURL (relatedItemPath).createInputStream (false).release(); } int64 URLInputSource::hashCode() const diff --git a/JuceLibraryCode/modules/juce_core/streams/juce_URLInputSource.h b/JuceLibraryCode/modules/juce_core/streams/juce_URLInputSource.h index e9d88e0..0cef562 100644 --- a/JuceLibraryCode/modules/juce_core/streams/juce_URLInputSource.h +++ b/JuceLibraryCode/modules/juce_core/streams/juce_URLInputSource.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_core/system/juce_CompilerSupport.h b/JuceLibraryCode/modules/juce_core/system/juce_CompilerSupport.h index 67e4a2b..3dabd3a 100644 --- a/JuceLibraryCode/modules/juce_core/system/juce_CompilerSupport.h +++ b/JuceLibraryCode/modules/juce_core/system/juce_CompilerSupport.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,19 +38,13 @@ #error "JUCE requires that GCC has C++11 compatibility enabled" #endif - #define JUCE_COMPILER_SUPPORTS_NOEXCEPT 1 - - #if (__GNUC__ * 100 + __GNUC_MINOR__) >= 500 - #define JUCE_HAS_CONSTEXPR 1 - #endif - #ifndef JUCE_EXCEPTIONS_DISABLED #if ! __EXCEPTIONS #define JUCE_EXCEPTIONS_DISABLED 1 #endif #endif - #define JUCE_CXX14_IS_AVAILABLE (__cplusplus >= 201402L) + #define JUCE_CXX14_IS_AVAILABLE ((__cplusplus >= 201402L) || ((__GNUC__ * 100 + __GNUC_MINOR__) >= 409 && (__cplusplus >= 201300L))) #define JUCE_CXX17_IS_AVAILABLE (__cplusplus >= 201703L) #endif @@ -63,9 +57,6 @@ #error "JUCE requires Clang 3.3 or later" #endif - #define JUCE_COMPILER_SUPPORTS_NOEXCEPT 1 - #define JUCE_HAS_CONSTEXPR 1 - #ifndef JUCE_COMPILER_SUPPORTS_ARC #define JUCE_COMPILER_SUPPORTS_ARC 1 #endif @@ -85,17 +76,8 @@ // MSVC #if JUCE_MSVC - #if _MSC_VER < 1800 // VS2013 - #error "JUCE requires Visual Studio 2013 or later" - #endif - - #if _MSC_VER >= 1900 // VS2015 - #define JUCE_COMPILER_SUPPORTS_NOEXCEPT 1 - #define JUCE_HAS_CONSTEXPR 1 - #else - #define _ALLOW_KEYWORD_MACROS 1 // prevent a warning - #undef noexcept - #define noexcept throw() + #if _MSC_VER < 1900 // VS2015 + #error "JUCE requires Visual Studio 2015 or later" #endif #ifndef JUCE_EXCEPTIONS_DISABLED @@ -115,27 +97,24 @@ #endif //============================================================================== -#if JUCE_HAS_CONSTEXPR - #define JUCE_CONSTEXPR constexpr -#else - #define JUCE_CONSTEXPR -#endif - #if (! JUCE_MSVC) && (! JUCE_CXX14_IS_AVAILABLE) namespace std { template unique_ptr make_unique (Args&&... args) { - return unique_ptr (new T (forward (args)...)); + return unique_ptr (new T (std::forward (args)...)); } } #endif +//============================================================================== #if ! DOXYGEN // These are old flags that are now supported on all compatible build targets #define JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL 1 #define JUCE_COMPILER_SUPPORTS_VARIADIC_TEMPLATES 1 #define JUCE_COMPILER_SUPPORTS_INITIALIZER_LISTS 1 + #define JUCE_COMPILER_SUPPORTS_NOEXCEPT 1 #define JUCE_DELETED_FUNCTION = delete + #define JUCE_CONSTEXPR constexpr #endif diff --git a/JuceLibraryCode/modules/juce_core/system/juce_CompilerWarnings.h b/JuceLibraryCode/modules/juce_core/system/juce_CompilerWarnings.h new file mode 100644 index 0000000..eb64428 --- /dev/null +++ b/JuceLibraryCode/modules/juce_core/system/juce_CompilerWarnings.h @@ -0,0 +1,200 @@ +/* + ============================================================================== + + 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. + + ============================================================================== +*/ + +#pragma once + +#include "juce_TargetPlatform.h" + +/** Return the Nth argument. By passing a variadic pack followed by N other + parameters, we can select one of those N parameter based on the length of + the parameter pack. +*/ +#define JUCE_NTH_ARG_(_00, _01, _02, _03, _04, _05, _06, _07, _08, _09, \ + _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, N, ...)\ + N + +#define JUCE_EACH_00_(FN) +#define JUCE_EACH_01_(FN, X) FN(X) +#define JUCE_EACH_02_(FN, X, ...) FN(X) JUCE_EACH_01_(FN, __VA_ARGS__) +#define JUCE_EACH_03_(FN, X, ...) FN(X) JUCE_EACH_02_(FN, __VA_ARGS__) +#define JUCE_EACH_04_(FN, X, ...) FN(X) JUCE_EACH_03_(FN, __VA_ARGS__) +#define JUCE_EACH_05_(FN, X, ...) FN(X) JUCE_EACH_04_(FN, __VA_ARGS__) +#define JUCE_EACH_06_(FN, X, ...) FN(X) JUCE_EACH_05_(FN, __VA_ARGS__) +#define JUCE_EACH_07_(FN, X, ...) FN(X) JUCE_EACH_06_(FN, __VA_ARGS__) +#define JUCE_EACH_08_(FN, X, ...) FN(X) JUCE_EACH_07_(FN, __VA_ARGS__) +#define JUCE_EACH_09_(FN, X, ...) FN(X) JUCE_EACH_08_(FN, __VA_ARGS__) +#define JUCE_EACH_10_(FN, X, ...) FN(X) JUCE_EACH_09_(FN, __VA_ARGS__) +#define JUCE_EACH_11_(FN, X, ...) FN(X) JUCE_EACH_10_(FN, __VA_ARGS__) +#define JUCE_EACH_12_(FN, X, ...) FN(X) JUCE_EACH_11_(FN, __VA_ARGS__) +#define JUCE_EACH_13_(FN, X, ...) FN(X) JUCE_EACH_12_(FN, __VA_ARGS__) +#define JUCE_EACH_14_(FN, X, ...) FN(X) JUCE_EACH_13_(FN, __VA_ARGS__) +#define JUCE_EACH_15_(FN, X, ...) FN(X) JUCE_EACH_14_(FN, __VA_ARGS__) +#define JUCE_EACH_16_(FN, X, ...) FN(X) JUCE_EACH_15_(FN, __VA_ARGS__) +#define JUCE_EACH_17_(FN, X, ...) FN(X) JUCE_EACH_16_(FN, __VA_ARGS__) +#define JUCE_EACH_18_(FN, X, ...) FN(X) JUCE_EACH_17_(FN, __VA_ARGS__) +#define JUCE_EACH_19_(FN, X, ...) FN(X) JUCE_EACH_18_(FN, __VA_ARGS__) +#define JUCE_EACH_20_(FN, X, ...) FN(X) JUCE_EACH_19_(FN, __VA_ARGS__) +#define JUCE_EACH_21_(FN, X, ...) FN(X) JUCE_EACH_20_(FN, __VA_ARGS__) +#define JUCE_EACH_22_(FN, X, ...) FN(X) JUCE_EACH_21_(FN, __VA_ARGS__) +#define JUCE_EACH_23_(FN, X, ...) FN(X) JUCE_EACH_22_(FN, __VA_ARGS__) +#define JUCE_EACH_24_(FN, X, ...) FN(X) JUCE_EACH_23_(FN, __VA_ARGS__) +#define JUCE_EACH_25_(FN, X, ...) FN(X) JUCE_EACH_24_(FN, __VA_ARGS__) +#define JUCE_EACH_26_(FN, X, ...) FN(X) JUCE_EACH_25_(FN, __VA_ARGS__) +#define JUCE_EACH_27_(FN, X, ...) FN(X) JUCE_EACH_26_(FN, __VA_ARGS__) +#define JUCE_EACH_28_(FN, X, ...) FN(X) JUCE_EACH_27_(FN, __VA_ARGS__) +#define JUCE_EACH_29_(FN, X, ...) FN(X) JUCE_EACH_28_(FN, __VA_ARGS__) +#define JUCE_EACH_30_(FN, X, ...) FN(X) JUCE_EACH_29_(FN, __VA_ARGS__) +#define JUCE_EACH_31_(FN, X, ...) FN(X) JUCE_EACH_30_(FN, __VA_ARGS__) +#define JUCE_EACH_32_(FN, X, ...) FN(X) JUCE_EACH_31_(FN, __VA_ARGS__) +#define JUCE_EACH_33_(FN, X, ...) FN(X) JUCE_EACH_32_(FN, __VA_ARGS__) +#define JUCE_EACH_34_(FN, X, ...) FN(X) JUCE_EACH_33_(FN, __VA_ARGS__) +#define JUCE_EACH_35_(FN, X, ...) FN(X) JUCE_EACH_34_(FN, __VA_ARGS__) +#define JUCE_EACH_36_(FN, X, ...) FN(X) JUCE_EACH_35_(FN, __VA_ARGS__) +#define JUCE_EACH_37_(FN, X, ...) FN(X) JUCE_EACH_36_(FN, __VA_ARGS__) +#define JUCE_EACH_38_(FN, X, ...) FN(X) JUCE_EACH_37_(FN, __VA_ARGS__) +#define JUCE_EACH_39_(FN, X, ...) FN(X) JUCE_EACH_38_(FN, __VA_ARGS__) + +/** Apply the macro FN to each of the other arguments. */ +#define JUCE_EACH(FN, ...) \ + JUCE_NTH_ARG_(, __VA_ARGS__, \ + JUCE_EACH_39_, \ + JUCE_EACH_38_, \ + JUCE_EACH_37_, \ + JUCE_EACH_36_, \ + JUCE_EACH_35_, \ + JUCE_EACH_34_, \ + JUCE_EACH_33_, \ + JUCE_EACH_32_, \ + JUCE_EACH_31_, \ + JUCE_EACH_30_, \ + JUCE_EACH_29_, \ + JUCE_EACH_28_, \ + JUCE_EACH_27_, \ + JUCE_EACH_26_, \ + JUCE_EACH_25_, \ + JUCE_EACH_24_, \ + JUCE_EACH_23_, \ + JUCE_EACH_22_, \ + JUCE_EACH_21_, \ + JUCE_EACH_20_, \ + JUCE_EACH_19_, \ + JUCE_EACH_18_, \ + JUCE_EACH_17_, \ + JUCE_EACH_16_, \ + JUCE_EACH_15_, \ + JUCE_EACH_14_, \ + JUCE_EACH_13_, \ + JUCE_EACH_12_, \ + JUCE_EACH_11_, \ + JUCE_EACH_10_, \ + JUCE_EACH_09_, \ + JUCE_EACH_08_, \ + JUCE_EACH_07_, \ + JUCE_EACH_06_, \ + JUCE_EACH_05_, \ + JUCE_EACH_04_, \ + JUCE_EACH_03_, \ + JUCE_EACH_02_, \ + JUCE_EACH_01_, \ + JUCE_EACH_00_) \ + (FN, __VA_ARGS__) + +/** Concatenate two tokens to form a new token. */ +#define JUCE_CONCAT_(a, b) a##b +#define JUCE_CONCAT(a, b) JUCE_CONCAT_(a, b) + +/** Quote the argument, turning it into a string. */ +#define JUCE_TO_STRING(x) #x + +#if JUCE_CLANG || JUCE_GCC + #define JUCE_IGNORE_GCC_IMPL_(compiler, warning) + #define JUCE_IGNORE_GCC_IMPL_0(compiler, warning) + #define JUCE_IGNORE_GCC_IMPL_1(compiler, warning) \ + _Pragma(JUCE_TO_STRING(compiler diagnostic ignored warning)) + + /** If 'warning' is recognised by this compiler, ignore it. */ + #if defined (__has_warning) + #define JUCE_IGNORE_GCC_LIKE(compiler, warning) \ + JUCE_CONCAT(JUCE_IGNORE_GCC_IMPL_, __has_warning(warning))(compiler, warning) + #else + #define JUCE_IGNORE_GCC_LIKE(compiler, warning) \ + JUCE_IGNORE_GCC_IMPL_1(compiler, warning) + #endif + + /** Ignore GCC/clang-specific warnings. */ + #define JUCE_IGNORE_GCC(warning) JUCE_IGNORE_GCC_LIKE(GCC, warning) + #define JUCE_IGNORE_clang(warning) JUCE_IGNORE_GCC_LIKE(clang, warning) + + #define JUCE_IGNORE_WARNINGS_GCC_LIKE(compiler, ...) \ + _Pragma(JUCE_TO_STRING(compiler diagnostic push)) \ + JUCE_EACH(JUCE_CONCAT(JUCE_IGNORE_, compiler), __VA_ARGS__) + + /** Push a new warning scope, and then ignore each warning for either clang + or gcc. If the compiler doesn't support __has_warning, we add -Wpragmas + as the first disabled warning because otherwise we might get complaints + about unknown warning options. + */ + #if defined (__has_warning) + #define JUCE_PUSH_WARNINGS_GCC_LIKE(compiler, ...) \ + JUCE_IGNORE_WARNINGS_GCC_LIKE(compiler, __VA_ARGS__) + #else + #define JUCE_PUSH_WARNINGS_GCC_LIKE(compiler, ...) \ + JUCE_IGNORE_WARNINGS_GCC_LIKE(compiler, "-Wpragmas", __VA_ARGS__) + #endif + + /** Pop the current warning scope. */ + #define JUCE_POP_WARNINGS_GCC_LIKE(compiler) \ + _Pragma(JUCE_TO_STRING(compiler diagnostic pop)) + + /** Push/pop warnings on compilers with gcc-like warning flags. + These macros expand to nothing on other compilers (like MSVC). + */ + #if JUCE_CLANG + #define JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE(...) JUCE_PUSH_WARNINGS_GCC_LIKE(clang, __VA_ARGS__) + #define JUCE_END_IGNORE_WARNINGS_GCC_LIKE JUCE_POP_WARNINGS_GCC_LIKE(clang) + #else + #define JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE(...) JUCE_PUSH_WARNINGS_GCC_LIKE(GCC, __VA_ARGS__) + #define JUCE_END_IGNORE_WARNINGS_GCC_LIKE JUCE_POP_WARNINGS_GCC_LIKE(GCC) + #endif +#else + #define JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE(...) + #define JUCE_END_IGNORE_WARNINGS_GCC_LIKE +#endif + +/** Push/pop warnings on MSVC. These macros expand to nothing on other + compilers (like clang and gcc). +*/ +#if JUCE_MSVC + #define JUCE_IGNORE_MSVC(warnings) __pragma(warning(disable:warnings)) + #define JUCE_BEGIN_IGNORE_WARNINGS_LEVEL_MSVC(level, warnings) \ + __pragma(warning(push, level)) JUCE_IGNORE_MSVC(warnings) + #define JUCE_BEGIN_IGNORE_WARNINGS_MSVC(warnings) \ + __pragma(warning(push)) JUCE_IGNORE_MSVC(warnings) + #define JUCE_END_IGNORE_WARNINGS_MSVC __pragma(warning(pop)) +#else + #define JUCE_IGNORE_MSVC(warnings) + #define JUCE_BEGIN_IGNORE_WARNINGS_LEVEL_MSVC(level, warnings) + #define JUCE_BEGIN_IGNORE_WARNINGS_MSVC(warnings) + #define JUCE_END_IGNORE_WARNINGS_MSVC +#endif diff --git a/JuceLibraryCode/modules/juce_core/system/juce_PlatformDefs.h b/JuceLibraryCode/modules/juce_core/system/juce_PlatformDefs.h index d9896c7..ffa74f8 100644 --- a/JuceLibraryCode/modules/juce_core/system/juce_PlatformDefs.h +++ b/JuceLibraryCode/modules/juce_core/system/juce_PlatformDefs.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,6 +20,8 @@ ============================================================================== */ +#pragma once + namespace juce { @@ -37,7 +39,7 @@ namespace juce #endif /** This macro defines the C calling convention used as the standard for JUCE calls. */ -#if JUCE_MSVC +#if JUCE_WINDOWS #define JUCE_CALLTYPE __stdcall #define JUCE_CDECL __cdecl #else @@ -92,6 +94,26 @@ namespace juce #define JUCE_ANALYZER_NORETURN #endif +/** Used to silence Wimplicit-fallthrough on Clang and GCC where available + as there are a few places in the codebase where we need to do this + deliberately and want to ignore the warning. +*/ +#if JUCE_CLANG + #if __has_cpp_attribute(clang::fallthrough) + #define JUCE_FALLTHROUGH [[clang::fallthrough]]; + #else + #define JUCE_FALLTHROUGH + #endif +#elif JUCE_GCC + #if __GNUC__ >= 7 + #define JUCE_FALLTHROUGH [[gnu::fallthrough]]; + #else + #define JUCE_FALLTHROUGH + #endif +#else + #define JUCE_FALLTHROUGH +#endif + //============================================================================== #if JUCE_MSVC && ! DOXYGEN #define JUCE_BLOCK_WITH_FORCED_SEMICOLON(x) \ diff --git a/JuceLibraryCode/modules/juce_core/system/juce_StandardHeader.h b/JuceLibraryCode/modules/juce_core/system/juce_StandardHeader.h index 07005d8..6602828 100644 --- a/JuceLibraryCode/modules/juce_core/system/juce_StandardHeader.h +++ b/JuceLibraryCode/modules/juce_core/system/juce_StandardHeader.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,9 +27,9 @@ See also SystemStats::getJUCEVersion() for a string version. */ -#define JUCE_MAJOR_VERSION 5 -#define JUCE_MINOR_VERSION 4 -#define JUCE_BUILDNUMBER 3 +#define JUCE_MAJOR_VERSION 6 +#define JUCE_MINOR_VERSION 0 +#define JUCE_BUILDNUMBER 1 /** Current JUCE version number. @@ -43,33 +43,45 @@ //============================================================================== -#include -#include -#include -#include -#include #include -#include #include -#include +#include +#include +#include +#include #include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include //============================================================================== #include "juce_CompilerSupport.h" +#include "juce_CompilerWarnings.h" #include "juce_PlatformDefs.h" //============================================================================== // Now we'll include some common OS headers.. +JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4514 4245 4100) + #if JUCE_MSVC - #pragma warning (push) - #pragma warning (disable: 4514 4245 4100) #include #endif + #if JUCE_MAC || JUCE_IOS #include #include + #if JUCE_IOS + #include + #endif #endif #if JUCE_LINUX @@ -89,9 +101,7 @@ #include #endif -#if JUCE_MSVC - #pragma warning (pop) -#endif +JUCE_END_IGNORE_WARNINGS_MSVC #if JUCE_MINGW #include @@ -112,11 +122,6 @@ #undef minor #undef KeyPress -// Include a replacement for std::function -#if JUCE_PROJUCER_LIVE_BUILD - #include "../misc/juce_StdFunctionCompat.h" -#endif - //============================================================================== // DLL building settings on Windows #if JUCE_MSVC diff --git a/JuceLibraryCode/modules/juce_core/system/juce_SystemStats.cpp b/JuceLibraryCode/modules/juce_core/system/juce_SystemStats.cpp index c10bdc1..ff866d7 100644 --- a/JuceLibraryCode/modules/juce_core/system/juce_SystemStats.cpp +++ b/JuceLibraryCode/modules/juce_core/system/juce_SystemStats.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. @@ -90,9 +90,9 @@ struct CPUInformation int numLogicalCPUs = 0, numPhysicalCPUs = 0; - bool hasMMX = false, hasSSE = false, hasSSE2 = false, hasSSE3 = false, - has3DNow = false, hasSSSE3 = false, hasSSE41 = false, - hasSSE42 = false, hasAVX = false, hasAVX2 = false, + bool hasMMX = false, hasSSE = false, hasSSE2 = false, hasSSE3 = false, + has3DNow = false, hasFMA3 = false, hasFMA4 = false, hasSSSE3 = false, + hasSSE41 = false, hasSSE42 = false, hasAVX = false, hasAVX2 = false, hasAVX512F = false, hasAVX512BW = false, hasAVX512CD = false, hasAVX512DQ = false, hasAVX512ER = false, hasAVX512IFMA = false, hasAVX512PF = false, hasAVX512VBMI = false, hasAVX512VL = false, @@ -110,6 +110,8 @@ int SystemStats::getNumCpus() noexcept { return getCPUInformation().num int SystemStats::getNumPhysicalCpus() noexcept { return getCPUInformation().numPhysicalCPUs; } bool SystemStats::hasMMX() noexcept { return getCPUInformation().hasMMX; } bool SystemStats::has3DNow() noexcept { return getCPUInformation().has3DNow; } +bool SystemStats::hasFMA3() noexcept { return getCPUInformation().hasFMA3; } +bool SystemStats::hasFMA4() noexcept { return getCPUInformation().hasFMA4; } bool SystemStats::hasSSE() noexcept { return getCPUInformation().hasSSE; } bool SystemStats::hasSSE2() noexcept { return getCPUInformation().hasSSE2; } bool SystemStats::hasSSE3() noexcept { return getCPUInformation().hasSSE3; } @@ -197,7 +199,7 @@ static LONG WINAPI handleCrash (LPEXCEPTION_POINTERS ep) static void handleCrash (int signum) { globalCrashHandler ((void*) (pointer_sized_int) signum); - kill (getpid(), SIGKILL); + ::kill (getpid(), SIGKILL); } int juce_siginterrupt (int sig, int flag); diff --git a/JuceLibraryCode/modules/juce_core/system/juce_SystemStats.h b/JuceLibraryCode/modules/juce_core/system/juce_SystemStats.h index 1d49fb1..1ca327a 100644 --- a/JuceLibraryCode/modules/juce_core/system/juce_SystemStats.h +++ b/JuceLibraryCode/modules/juce_core/system/juce_SystemStats.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. @@ -61,6 +61,8 @@ class JUCE_API SystemStats final MacOSX_10_10 = MacOSX | 10, MacOSX_10_11 = MacOSX | 11, MacOSX_10_12 = MacOSX | 12, + MacOSX_10_13 = MacOSX | 13, + MacOSX_10_14 = MacOSX | 14, Win2000 = Windows | 1, WinXP = Windows | 2, @@ -170,6 +172,8 @@ class JUCE_API SystemStats final static bool hasMMX() noexcept; /**< Returns true if Intel MMX instructions are available. */ static bool has3DNow() noexcept; /**< Returns true if AMD 3DNOW instructions are available. */ + static bool hasFMA3() noexcept; /**< Returns true if AMD FMA3 instructions are available. */ + static bool hasFMA4() noexcept; /**< Returns true if AMD FMA4 instructions are available. */ static bool hasSSE() noexcept; /**< Returns true if Intel SSE instructions are available. */ static bool hasSSE2() noexcept; /**< Returns true if Intel SSE2 instructions are available. */ static bool hasSSE3() noexcept; /**< Returns true if Intel SSE3 instructions are available. */ diff --git a/JuceLibraryCode/modules/juce_core/system/juce_TargetPlatform.h b/JuceLibraryCode/modules/juce_core/system/juce_TargetPlatform.h index dba50f1..02390fc 100644 --- a/JuceLibraryCode/modules/juce_core/system/juce_TargetPlatform.h +++ b/JuceLibraryCode/modules/juce_core/system/juce_TargetPlatform.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. @@ -58,7 +58,6 @@ //============================================================================== #if defined (_WIN32) || defined (_WIN64) - #define JUCE_WIN32 1 #define JUCE_WINDOWS 1 #elif defined (JUCE_ANDROID) #undef JUCE_ANDROID @@ -68,7 +67,9 @@ #elif defined (LINUX) || defined (__linux__) #define JUCE_LINUX 1 #elif defined (__APPLE_CPP__) || defined (__APPLE_CC__) - #include // (needed to find out what platform we're using) + #define CF_EXCLUDE_CSTD_HEADERS 1 + #include // (needed to find out what platform we're using) + #include #include "../native/juce_mac_ClangBugWorkaround.h" #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR @@ -141,12 +142,12 @@ #define JUCE_INTEL 1 #endif - #if JUCE_MAC && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 - #error "Building for OSX 10.4 is no longer supported!" - #endif - - #if JUCE_MAC && ! defined (MAC_OS_X_VERSION_10_6) - #error "To build with 10.5 compatibility, use a later SDK and set the deployment target to 10.5" + #if JUCE_MAC + #if ! defined (MAC_OS_X_VERSION_10_11) + #error "The 10.11 SDK (Xcode 7.3.1+) is required to build JUCE apps. You can create apps that run on macOS 10.7+ by changing the deployment target." + #elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7 + #error "Building for OSX 10.6 is no longer supported!" + #endif #endif #endif @@ -182,7 +183,7 @@ //============================================================================== // Compiler type macros. -#ifdef __clang__ +#if defined (__clang__) #define JUCE_CLANG 1 #elif defined (__GNUC__) diff --git a/JuceLibraryCode/modules/juce_core/text/juce_Base64.cpp b/JuceLibraryCode/modules/juce_core/text/juce_Base64.cpp index 7dd0adb..55a3284 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_Base64.cpp +++ b/JuceLibraryCode/modules/juce_core/text/juce_Base64.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. @@ -127,7 +127,9 @@ String Base64::toBase64 (const String& text) class Base64Tests : public UnitTest { public: - Base64Tests() : UnitTest ("Base64 class", "Text") {} + Base64Tests() + : UnitTest ("Base64 class", UnitTestCategories::text) + {} static MemoryBlock createRandomData (Random& r) { diff --git a/JuceLibraryCode/modules/juce_core/text/juce_Base64.h b/JuceLibraryCode/modules/juce_core/text/juce_Base64.h index ba10775..868880e 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_Base64.h +++ b/JuceLibraryCode/modules/juce_core/text/juce_Base64.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_core/text/juce_CharPointer_ASCII.h b/JuceLibraryCode/modules/juce_core/text/juce_CharPointer_ASCII.h index cb884f6..5a36d45 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_CharPointer_ASCII.h +++ b/JuceLibraryCode/modules/juce_core/text/juce_CharPointer_ASCII.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. @@ -182,7 +182,7 @@ class CharPointer_ASCII final /** Returns the number of bytes that would be needed to represent the given unicode character in this encoding format. */ - static inline size_t getBytesRequiredFor (const juce_wchar) noexcept + static size_t getBytesRequiredFor (const juce_wchar) noexcept { return 1; } diff --git a/JuceLibraryCode/modules/juce_core/text/juce_CharPointer_UTF16.h b/JuceLibraryCode/modules/juce_core/text/juce_CharPointer_UTF16.h index e231c34..5318cb5 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_CharPointer_UTF16.h +++ b/JuceLibraryCode/modules/juce_core/text/juce_CharPointer_UTF16.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_core/text/juce_CharPointer_UTF32.h b/JuceLibraryCode/modules/juce_core/text/juce_CharPointer_UTF32.h index 66d3220..7dc68bd 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_CharPointer_UTF32.h +++ b/JuceLibraryCode/modules/juce_core/text/juce_CharPointer_UTF32.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. @@ -186,7 +186,7 @@ class CharPointer_UTF32 final /** Returns the number of bytes that would be needed to represent the given unicode character in this encoding format. */ - static inline size_t getBytesRequiredFor (juce_wchar) noexcept + static size_t getBytesRequiredFor (juce_wchar) noexcept { return sizeof (CharType); } diff --git a/JuceLibraryCode/modules/juce_core/text/juce_CharPointer_UTF8.h b/JuceLibraryCode/modules/juce_core/text/juce_CharPointer_UTF8.h index 3321711..d919ab0 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_CharPointer_UTF8.h +++ b/JuceLibraryCode/modules/juce_core/text/juce_CharPointer_UTF8.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. @@ -36,44 +36,44 @@ class CharPointer_UTF8 final public: using CharType = char; - inline explicit CharPointer_UTF8 (const CharType* rawPointer) noexcept + explicit CharPointer_UTF8 (const CharType* rawPointer) noexcept : data (const_cast (rawPointer)) { } - inline CharPointer_UTF8 (const CharPointer_UTF8& other) = default; + CharPointer_UTF8 (const CharPointer_UTF8& other) = default; - inline CharPointer_UTF8 operator= (CharPointer_UTF8 other) noexcept + CharPointer_UTF8 operator= (CharPointer_UTF8 other) noexcept { data = other.data; return *this; } - inline CharPointer_UTF8 operator= (const CharType* text) noexcept + CharPointer_UTF8 operator= (const CharType* text) noexcept { data = const_cast (text); return *this; } /** This is a pointer comparison, it doesn't compare the actual text. */ - inline bool operator== (CharPointer_UTF8 other) const noexcept { return data == other.data; } - inline bool operator!= (CharPointer_UTF8 other) const noexcept { return data != other.data; } - inline bool operator<= (CharPointer_UTF8 other) const noexcept { return data <= other.data; } - inline bool operator< (CharPointer_UTF8 other) const noexcept { return data < other.data; } - inline bool operator>= (CharPointer_UTF8 other) const noexcept { return data >= other.data; } - inline bool operator> (CharPointer_UTF8 other) const noexcept { return data > other.data; } + bool operator== (CharPointer_UTF8 other) const noexcept { return data == other.data; } + bool operator!= (CharPointer_UTF8 other) const noexcept { return data != other.data; } + bool operator<= (CharPointer_UTF8 other) const noexcept { return data <= other.data; } + bool operator< (CharPointer_UTF8 other) const noexcept { return data < other.data; } + bool operator>= (CharPointer_UTF8 other) const noexcept { return data >= other.data; } + bool operator> (CharPointer_UTF8 other) const noexcept { return data > other.data; } /** Returns the address that this pointer is pointing to. */ - inline CharType* getAddress() const noexcept { return data; } + CharType* getAddress() const noexcept { return data; } /** Returns the address that this pointer is pointing to. */ - inline operator const CharType*() const noexcept { return data; } + operator const CharType*() const noexcept { return data; } /** Returns true if this pointer is pointing to a null character. */ - inline bool isEmpty() const noexcept { return *data == 0; } + bool isEmpty() const noexcept { return *data == 0; } /** Returns true if this pointer is not pointing to a null character. */ - inline bool isNotEmpty() const noexcept { return *data != 0; } + bool isNotEmpty() const noexcept { return *data != 0; } /** Returns the unicode character that this pointer is pointing to. */ juce_wchar operator*() const noexcept @@ -124,7 +124,7 @@ class CharPointer_UTF8 final while ((static_cast (n) & bit) != 0 && bit > 0x8) { ++data; - bit >>= 1; + bit = static_cast (bit >> 1); } } @@ -348,7 +348,7 @@ class CharPointer_UTF8 final } /** Writes a null character to this string (leaving the pointer's position unchanged). */ - inline void writeNull() const noexcept + void writeNull() const noexcept { *data = 0; } diff --git a/JuceLibraryCode/modules/juce_core/text/juce_CharacterFunctions.cpp b/JuceLibraryCode/modules/juce_core/text/juce_CharacterFunctions.cpp index 8dee93a..a42898f 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_CharacterFunctions.cpp +++ b/JuceLibraryCode/modules/juce_core/text/juce_CharacterFunctions.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,10 +23,7 @@ namespace juce { -#if JUCE_MSVC - #pragma warning (push) - #pragma warning (disable: 4514 4996) -#endif +JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4514 4996) juce_wchar CharacterFunctions::toUpperCase (const juce_wchar character) noexcept { @@ -56,9 +53,7 @@ bool CharacterFunctions::isLowerCase (const juce_wchar character) noexcept #endif } -#if JUCE_MSVC - #pragma warning (pop) -#endif +JUCE_END_IGNORE_WARNINGS_MSVC //============================================================================== bool CharacterFunctions::isWhitespace (const char character) noexcept @@ -179,6 +174,8 @@ juce_wchar CharacterFunctions::getUnicodeCharFromWindows1252Codepage (const uint return (juce_wchar) lookup[c - 0x80]; } + +//============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -197,7 +194,9 @@ juce_wchar CharacterFunctions::getUnicodeCharFromWindows1252Codepage (const uint class CharacterFunctionsTests : public UnitTest { public: - CharacterFunctionsTests() : UnitTest ("CharacterFunctions", "Text") {} + CharacterFunctionsTests() + : UnitTest ("CharacterFunctions", UnitTestCategories::text) + {} void runTest() override { diff --git a/JuceLibraryCode/modules/juce_core/text/juce_CharacterFunctions.h b/JuceLibraryCode/modules/juce_core/text/juce_CharacterFunctions.h index 97dbc26..def6b6c 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_CharacterFunctions.h +++ b/JuceLibraryCode/modules/juce_core/text/juce_CharacterFunctions.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. @@ -149,9 +149,9 @@ class JUCE_API CharacterFunctions #if JUCE_MINGW bool isNegative = false; #else - JUCE_CONSTEXPR const int maxSignificantDigits = 17 + 1; // An additional digit for rounding - JUCE_CONSTEXPR const int bufferSize = maxSignificantDigits + 7 + 1; // -.E-XXX and a trailing null-terminator - char buffer[bufferSize] = {}; + constexpr const int maxSignificantDigits = 17 + 1; // An additional digit for rounding + constexpr const int bufferSize = maxSignificantDigits + 7 + 1; // -.E-XXX and a trailing null-terminator + char buffer[(size_t) bufferSize] = {}; char* currentCharacter = &(buffer[0]); #endif @@ -166,9 +166,12 @@ class JUCE_API CharacterFunctions #else *currentCharacter++ = '-'; #endif - // Fall-through.. + JUCE_FALLTHROUGH case '+': c = *++text; + break; + default: + break; } switch (c) @@ -184,6 +187,9 @@ class JUCE_API CharacterFunctions if ((text[1] == 'n' || text[1] == 'N') && (text[2] == 'f' || text[2] == 'F')) return std::numeric_limits::infinity(); break; + + default: + break; } #if JUCE_MINGW @@ -194,7 +200,7 @@ class JUCE_API CharacterFunctions int exponent = 0, decPointIndex = 0, digit = 0; int lastDigit = 0, numSignificantDigits = 0; bool digitsFound = false; - JUCE_CONSTEXPR const int maxSignificantDigits = 17 + 1; + constexpr const int maxSignificantDigits = 17 + 1; for (;;) { @@ -274,7 +280,7 @@ class JUCE_API CharacterFunctions switch (*++text) { - case '-': negativeExponent = true; // fall-through.. + case '-': negativeExponent = true; JUCE_FALLTHROUGH case '+': ++text; } @@ -337,7 +343,7 @@ class JUCE_API CharacterFunctions c = *text; - auto writeExponentDigits = [](int exponent, char* destination) + auto writeExponentDigits = [] (int exponent, char* destination) { auto exponentDivisor = 100; @@ -359,8 +365,9 @@ class JUCE_API CharacterFunctions switch (*++text) { - case '-': parsedExponentIsPositive = false; // Fall-through.. - case '+': ++text; + case '-': parsedExponentIsPositive = false; JUCE_FALLTHROUGH + case '+': ++text; break; + default: break; } int exponent = 0; @@ -505,12 +512,12 @@ class JUCE_API CharacterFunctions { auto startAddress = dest.getAddress(); auto maxBytes = (ssize_t) maxBytesToWrite; - maxBytes -= sizeof (typename DestCharPointerType::CharType); // (allow for a terminating null) + maxBytes -= (ssize_t) sizeof (typename DestCharPointerType::CharType); // (allow for a terminating null) for (;;) { auto c = src.getAndAdvance(); - auto bytesNeeded = DestCharPointerType::getBytesRequiredFor (c); + auto bytesNeeded = (ssize_t) DestCharPointerType::getBytesRequiredFor (c); maxBytes -= bytesNeeded; if (c == 0 || maxBytes < 0) @@ -544,7 +551,7 @@ class JUCE_API CharacterFunctions } /** Compares two characters. */ - static inline int compare (juce_wchar char1, juce_wchar char2) noexcept + static int compare (juce_wchar char1, juce_wchar char2) noexcept { if (auto diff = static_cast (char1) - static_cast (char2)) return diff < 0 ? -1 : 1; @@ -589,7 +596,7 @@ class JUCE_API CharacterFunctions } /** Compares two characters, using a case-independant match. */ - static inline int compareIgnoreCase (juce_wchar char1, juce_wchar char2) noexcept + static int compareIgnoreCase (juce_wchar char1, juce_wchar char2) noexcept { return char1 != char2 ? compare (toUpperCase (char1), toUpperCase (char2)) : 0; } diff --git a/JuceLibraryCode/modules/juce_core/text/juce_Identifier.cpp b/JuceLibraryCode/modules/juce_core/text/juce_Identifier.cpp index cebb2dd..635330d 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_Identifier.cpp +++ b/JuceLibraryCode/modules/juce_core/text/juce_Identifier.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_core/text/juce_Identifier.h b/JuceLibraryCode/modules/juce_core/text/juce_Identifier.h index ea3377b..f916b84 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_Identifier.h +++ b/JuceLibraryCode/modules/juce_core/text/juce_Identifier.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_core/text/juce_LocalisedStrings.cpp b/JuceLibraryCode/modules/juce_core/text/juce_LocalisedStrings.cpp index a2a34f4..1649724 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_LocalisedStrings.cpp +++ b/JuceLibraryCode/modules/juce_core/text/juce_LocalisedStrings.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_core/text/juce_LocalisedStrings.h b/JuceLibraryCode/modules/juce_core/text/juce_LocalisedStrings.h index 9f126dd..4ba1e00 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_LocalisedStrings.h +++ b/JuceLibraryCode/modules/juce_core/text/juce_LocalisedStrings.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. @@ -161,7 +161,7 @@ class JUCE_API LocalisedStrings countries: fr be mc ch lu @endcode - The country codes are supposed to be 2-character ISO complient codes. + The country codes are supposed to be 2-character ISO compliant codes. */ const StringArray& getCountryCodes() const { return countryCodes; } diff --git a/JuceLibraryCode/modules/juce_core/text/juce_NewLine.h b/JuceLibraryCode/modules/juce_core/text/juce_NewLine.h index c215f35..8f05b10 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_NewLine.h +++ b/JuceLibraryCode/modules/juce_core/text/juce_NewLine.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_core/text/juce_String.cpp b/JuceLibraryCode/modules/juce_core/text/juce_String.cpp index bfae07e..e383bad 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_String.cpp +++ b/JuceLibraryCode/modules/juce_core/text/juce_String.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,10 +23,7 @@ namespace juce { -#if JUCE_MSVC - #pragma warning (push) - #pragma warning (disable: 4514 4996) -#endif +JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4514 4996) NewLine newLine; @@ -42,7 +39,7 @@ NewLine newLine; using CharPointer_wchar_t = CharPointer_UTF32; #endif -static inline CharPointer_wchar_t castToCharPointer_wchar_t (const void* t) noexcept +static CharPointer_wchar_t castToCharPointer_wchar_t (const void* t) noexcept { return CharPointer_wchar_t (static_cast (t)); } @@ -56,7 +53,7 @@ struct EmptyString String::CharPointerType::CharType text; }; -static const EmptyString emptyString = { 0x3fffffff, sizeof (String::CharPointerType::CharType), 0 }; +static const EmptyString emptyString { 0x3fffffff, sizeof (String::CharPointerType::CharType), 0 }; //============================================================================== class StringHolder @@ -156,13 +153,13 @@ class StringHolder { auto* b = bufferFromText (text); - if (b != (StringHolder*) &emptyString) + if (! isEmptyString (b)) ++(b->refCount); } - static inline void release (StringHolder* const b) noexcept + static void release (StringHolder* const b) noexcept { - if (b != (StringHolder*) &emptyString) + if (! isEmptyString (b)) if (--(b->refCount) == -1) delete[] reinterpret_cast (b); } @@ -172,7 +169,7 @@ class StringHolder release (bufferFromText (text)); } - static inline int getReferenceCount (const CharPointerType text) noexcept + static int getReferenceCount (const CharPointerType text) noexcept { return bufferFromText (text)->refCount.get() + 1; } @@ -182,7 +179,7 @@ class StringHolder { auto* b = bufferFromText (text); - if (b == (StringHolder*) &emptyString) + if (isEmptyString (b)) { auto newText = createUninitialisedBytes (numBytes); newText.writeNull(); @@ -210,13 +207,18 @@ class StringHolder CharType text[1]; private: - static inline StringHolder* bufferFromText (const CharPointerType text) noexcept + static StringHolder* bufferFromText (const CharPointerType text) noexcept { // (Can't use offsetof() here because of warnings about this not being a POD) return reinterpret_cast (reinterpret_cast (text.getAddress()) - (reinterpret_cast (reinterpret_cast (128)->text) - 128)); } + static bool isEmptyString (StringHolder* other) + { + return (other->refCount.get() & 0x30000000) != 0; + } + void compileTimeChecks() { // Let me know if any of these assertions fail on your system! @@ -388,7 +390,7 @@ namespace NumberToStringConverters do { - *--t = '0' + (char) (v % 10); + *--t = static_cast ('0' + (char) (v % 10)); v /= 10; } while (v > 0); @@ -566,16 +568,16 @@ JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const wchar_t* s2) noe JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const wchar_t* s2) noexcept { return s1.compare (s2) != 0; } JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) == 0; } JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) != 0; } +JUCE_API bool JUCE_CALLTYPE operator< (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) < 0; } +JUCE_API bool JUCE_CALLTYPE operator<= (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) <= 0; } +JUCE_API bool JUCE_CALLTYPE operator> (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) > 0; } +JUCE_API bool JUCE_CALLTYPE operator>= (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) >= 0; } JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const CharPointer_UTF8 s2) noexcept { return s1.getCharPointer().compare (s2) == 0; } JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const CharPointer_UTF8 s2) noexcept { return s1.getCharPointer().compare (s2) != 0; } JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const CharPointer_UTF16 s2) noexcept { return s1.getCharPointer().compare (s2) == 0; } JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const CharPointer_UTF16 s2) noexcept { return s1.getCharPointer().compare (s2) != 0; } JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const CharPointer_UTF32 s2) noexcept { return s1.getCharPointer().compare (s2) == 0; } JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const CharPointer_UTF32 s2) noexcept { return s1.getCharPointer().compare (s2) != 0; } -JUCE_API bool JUCE_CALLTYPE operator> (const String& s1, const String& s2) noexcept { return s1.compare (s2) > 0; } -JUCE_API bool JUCE_CALLTYPE operator< (const String& s1, const String& s2) noexcept { return s1.compare (s2) < 0; } -JUCE_API bool JUCE_CALLTYPE operator>= (const String& s1, const String& s2) noexcept { return s1.compare (s2) >= 0; } -JUCE_API bool JUCE_CALLTYPE operator<= (const String& s1, const String& s2) noexcept { return s1.compare (s2) <= 0; } bool String::equalsIgnoreCase (const wchar_t* const t) const noexcept { @@ -733,7 +735,7 @@ void String::appendCharPointer (const CharPointerType startOfTextToAppend, if (extraBytesNeeded > 0) { auto byteOffsetOfNull = getByteOffsetOfEnd(); - preallocateBytes (byteOffsetOfNull + (size_t) extraBytesNeeded); + preallocateBytes ((size_t) extraBytesNeeded + byteOffsetOfNull); auto* newStringStart = addBytesToPointer (text.getAddress(), (int) byteOffsetOfNull); memcpy (newStringStart, startOfTextToAppend.getAddress(), (size_t) extraBytesNeeded); @@ -810,9 +812,10 @@ namespace StringHelpers } } -String& String::operator+= (const int number) { return StringHelpers::operationAddAssign (*this, number); } -String& String::operator+= (const int64 number) { return StringHelpers::operationAddAssign (*this, number); } -String& String::operator+= (const uint64 number) { return StringHelpers::operationAddAssign (*this, number); } +String& String::operator+= (const int number) { return StringHelpers::operationAddAssign (*this, number); } +String& String::operator+= (const long number) { return StringHelpers::operationAddAssign (*this, number); } +String& String::operator+= (const int64 number) { return StringHelpers::operationAddAssign (*this, number); } +String& String::operator+= (const uint64 number) { return StringHelpers::operationAddAssign (*this, number); } //============================================================================== JUCE_API String JUCE_CALLTYPE operator+ (const char* s1, const String& s2) { String s (s1); return s += s2; } @@ -1835,6 +1838,10 @@ String String::formattedRaw (const char* pf, ...) va_list args; va_start (args, pf); + #if JUCE_WINDOWS + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") + #endif + #if JUCE_ANDROID HeapBlock temp (bufferSize); int num = (int) vsnprintf (temp.get(), bufferSize - 1, pf, args); @@ -1851,6 +1858,10 @@ String String::formattedRaw (const char* pf, ...) #endif (temp.get(), bufferSize - 1, wideCharVersion.toWideCharPointer(), args); #endif + + #if JUCE_WINDOWS + JUCE_END_IGNORE_WARNINGS_GCC_LIKE + #endif va_end (args); if (num > 0) @@ -1887,7 +1898,7 @@ int String::getTrailingIntValue() const noexcept break; } - n += static_cast (mult) * (*t - '0'); + n += (int) (((juce_wchar) mult) * (*t - '0')); mult *= 10; } @@ -1907,7 +1918,7 @@ static String hexToString (Type v) do { *--t = hexDigits [(int) (v & 15)]; - v >>= 4; + v = static_cast (v >> 4); } while (v != 0); @@ -1929,7 +1940,7 @@ String String::toHexString (const void* const d, const int size, const int group if (groupSize > 0) numChars += size / groupSize; - String s (PreallocationBytes (sizeof (CharPointerType::CharType) * (size_t) numChars)); + String s (PreallocationBytes ((size_t) numChars * sizeof (CharPointerType::CharType))); auto* data = static_cast (d); auto dest = s.text; @@ -2137,9 +2148,7 @@ String String::fromUTF8 (const char* const buffer, int bufferSizeBytes) return {}; } -#if JUCE_MSVC - #pragma warning (pop) -#endif +JUCE_END_IGNORE_WARNINGS_MSVC //============================================================================== StringRef::StringRef() noexcept : text ((const String::CharPointerType::CharType*) "\0\0\0") @@ -2187,7 +2196,7 @@ StringRef::StringRef (const std::string& string) : StringRef (string.c_str //============================================================================== -static String minimiseLengthOfFloatString (const String& input) +static String reduceLengthOfFloatString (const String& input) { const auto start = input.getCharPointer(); const auto end = start + (int) input.length(); @@ -2208,8 +2217,8 @@ static String minimiseLengthOfFloatString (const String& input) } else if (currentChar == '.') { - if (trimStart == c + 1) - --trimStart; + if (trimStart == c + 1 && trimStart != end && *trimStart == '0') + ++trimStart; break; } @@ -2258,6 +2267,49 @@ static String minimiseLengthOfFloatString (const String& input) return input; } +static String serialiseDouble (double input) +{ + auto absInput = std::abs (input); + + if (absInput >= 1.0e6 || absInput <= 1.0e-5) + return reduceLengthOfFloatString ({ input, 15, true }); + + int intInput = (int) input; + + if ((double) intInput == input) + return { input, 1 }; + + auto numberOfDecimalPlaces = [absInput] + { + if (absInput < 1.0) + { + if (absInput >= 1.0e-3) + { + if (absInput >= 1.0e-1) return 16; + if (absInput >= 1.0e-2) return 17; + return 18; + } + + if (absInput >= 1.0e-4) return 19; + return 20; + } + + if (absInput < 1.0e3) + { + if (absInput < 1.0e1) return 15; + if (absInput < 1.0e2) return 14; + return 13; + } + + if (absInput < 1.0e4) return 12; + if (absInput < 1.0e5) return 11; + return 10; + }(); + + return reduceLengthOfFloatString (String (input, numberOfDecimalPlaces)); +} + + //============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -2268,7 +2320,9 @@ static String minimiseLengthOfFloatString (const String& input) class StringTests : public UnitTest { public: - StringTests() : UnitTest ("String class", "Text") {} + StringTests() + : UnitTest ("String class", UnitTestCategories::text) + {} template struct TestUTFConversion @@ -2794,13 +2848,14 @@ class StringTests : public UnitTest { StringPairArray tests; tests.set ("1", "1"); + tests.set ("1.0", "1.0"); tests.set ("-1", "-1"); tests.set ("-100", "-100"); tests.set ("110", "110"); tests.set ("9090", "9090"); - tests.set ("1000.0", "1000"); - tests.set ("1.0", "1"); - tests.set ("-1.00", "-1"); + tests.set ("1000.0", "1000.0"); + tests.set ("1.0", "1.0"); + tests.set ("-1.00", "-1.0"); tests.set ("1.20", "1.2"); tests.set ("1.300", "1.3"); tests.set ("1.301", "1.301"); @@ -2815,7 +2870,7 @@ class StringTests : public UnitTest tests.set ("-1e-000", "-1"); tests.set ("1e100", "1e100"); tests.set ("100e100", "100e100"); - tests.set ("100.0e0100", "100e100"); + tests.set ("100.0e0100", "100.0e100"); tests.set ("-1e1", "-1e1"); tests.set ("1e10", "1e10"); tests.set ("-1e+10", "-1e10"); @@ -2823,34 +2878,78 @@ class StringTests : public UnitTest tests.set ("1e0010", "1e10"); tests.set ("1e-0010", "1e-10"); tests.set ("1e-1", "1e-1"); - tests.set ("-1.0e1", "-1e1"); - tests.set ("1.0e-1", "1e-1"); - tests.set ("1.00e-1", "1e-1"); + tests.set ("-1.0e1", "-1.0e1"); + tests.set ("1.0e-1", "1.0e-1"); + tests.set ("1.00e-1", "1.0e-1"); tests.set ("1.001e1", "1.001e1"); tests.set ("1.010e+1", "1.01e1"); tests.set ("-1.1000e1", "-1.1e1"); for (auto& input : tests.getAllKeys()) - expectEquals (minimiseLengthOfFloatString (input), tests[input]); + expectEquals (reduceLengthOfFloatString (input), tests[input]); } { std::map tests; - tests[1] = "1"; + tests[1] = "1.0"; tests[1.1] = "1.1"; tests[1.01] = "1.01"; tests[0.76378] = "7.6378e-1"; - tests[-10] = "-1e1"; + tests[-10] = "-1.0e1"; tests[10.01] = "1.001e1"; tests[10691.01] = "1.069101e4"; tests[0.0123] = "1.23e-2"; tests[-3.7e-27] = "-3.7e-27"; - tests[1e+40] = "1e40"; + tests[1e+40] = "1.0e40"; for (auto& test : tests) - expectEquals (minimiseLengthOfFloatString (String (test.first, 15, true)), test.second); + expectEquals (reduceLengthOfFloatString (String (test.first, 15, true)), test.second); } } + + { + beginTest ("Serialisation"); + + std::map tests; + + tests[364] = "364.0"; + tests[1e7] = "1.0e7"; + tests[12345678901] = "1.2345678901e10"; + + tests[1234567890123456.7] = "1.234567890123457e15"; + tests[12345678.901234567] = "1.234567890123457e7"; + tests[1234567.8901234567] = "1.234567890123457e6"; + tests[123456.78901234567] = "123456.7890123457"; + tests[12345.678901234567] = "12345.67890123457"; + tests[1234.5678901234567] = "1234.567890123457"; + tests[123.45678901234567] = "123.4567890123457"; + tests[12.345678901234567] = "12.34567890123457"; + tests[1.2345678901234567] = "1.234567890123457"; + tests[0.12345678901234567] = "0.1234567890123457"; + tests[0.012345678901234567] = "0.01234567890123457"; + tests[0.0012345678901234567] = "0.001234567890123457"; + tests[0.00012345678901234567] = "0.0001234567890123457"; + tests[0.000012345678901234567] = "0.00001234567890123457"; + tests[0.0000012345678901234567] = "1.234567890123457e-6"; + tests[0.00000012345678901234567] = "1.234567890123457e-7"; + + for (auto& test : tests) + { + expectEquals (serialiseDouble (test.first), test.second); + expectEquals (serialiseDouble (-test.first), "-" + test.second); + } + } + + { + beginTest ("Loops"); + + String str (CharPointer_UTF8 ("\xc2\xaf\\_(\xe3\x83\x84)_/\xc2\xaf")); + std::vector parts { 175, 92, 95, 40, 12484, 41, 95, 47, 175 }; + size_t index = 0; + + for (auto c : str) + expectEquals (c, parts[index++]); + } } }; diff --git a/JuceLibraryCode/modules/juce_core/text/juce_String.h b/JuceLibraryCode/modules/juce_core/text/juce_String.h index 8281dd6..eb6ce15 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_String.h +++ b/JuceLibraryCode/modules/juce_core/text/juce_String.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,6 +20,20 @@ ============================================================================== */ +#if ! DOXYGEN && (JUCE_MAC || JUCE_IOS) + // Annoyingly we can only forward-declare a typedef by forward-declaring the + // aliased type + #if __has_attribute(objc_bridge) + #define JUCE_CF_BRIDGED_TYPE(T) __attribute__((objc_bridge(T))) + #else + #define JUCE_CF_BRIDGED_TYPE(T) + #endif + + typedef const struct JUCE_CF_BRIDGED_TYPE(NSString) __CFString * CFStringRef; + + #undef JUCE_CF_BRIDGED_TYPE +#endif + namespace juce { @@ -293,13 +307,13 @@ class JUCE_API String final Note that there's also an isNotEmpty() method to help write readable code. @see containsNonWhitespaceChars() */ - inline bool isEmpty() const noexcept { return text.isEmpty(); } + bool isEmpty() const noexcept { return text.isEmpty(); } /** Returns true if the string contains at least one character. Note that there's also an isEmpty() method to help write readable code. @see containsNonWhitespaceChars() */ - inline bool isNotEmpty() const noexcept { return ! text.isEmpty(); } + bool isNotEmpty() const noexcept { return ! text.isEmpty(); } /** Resets this string to be empty. */ void clear() noexcept; @@ -905,6 +919,35 @@ class JUCE_API String final template static String formatted (const String& formatStr, Args... args) { return formattedRaw (formatStr.toRawUTF8(), args...); } + /** Returns an iterator pointing at the beginning of the string. */ + CharPointerType begin() const { return getCharPointer(); } + + /** Returns an iterator pointing at the terminating null of the string. + + Note that this has to find the terminating null before returning it, so prefer to + call this once before looping and then reuse the result, rather than calling 'end()' + each time through the loop. + + @code + String str = ...; + + // BEST + for (auto c : str) + DBG (c); + + // GOOD + for (auto ptr = str.begin(), end = str.end(); ptr != end; ++ptr) + DBG (*ptr); + + std::for_each (str.begin(), str.end(), [] (juce_wchar c) { DBG (c); }); + + // BAD + for (auto ptr = str.begin(); ptr != str.end(); ++ptr) + DBG (*ptr); + @endcode + */ + CharPointerType end() const { return begin().findTerminatingNull(); } + //============================================================================== // Numeric conversions.. @@ -978,13 +1021,16 @@ class JUCE_API String final decimal places, adding trailing zeros as required, and will not use exponent notation. If 0 or less, it will use exponent notation if necessary. + @param useScientificNotation if the number should be formatted using scientific notation @see getFloatValue, getIntValue */ String (double doubleValue, int numberOfDecimalPlaces, bool useScientificNotation = false); + #ifndef DOXYGEN // Automatically creating a String from a bool opens up lots of nasty type conversion edge cases. // If you want a String representation of a bool you can cast the bool to an int first. explicit String (bool) = delete; + #endif /** Reads the value of the string as a decimal number (up to 32 bits in size). @@ -1062,7 +1108,7 @@ class JUCE_API String final /** Returns a string containing a decimal with a set number of significant figures. - @param number the intput number + @param number the input number @param numberOfSignificantFigures the number of significant figures to use */ template @@ -1192,7 +1238,7 @@ class JUCE_API String final that is returned must not be stored anywhere, as it can be deleted whenever the string changes. */ - inline CharPointerType getCharPointer() const noexcept { return text; } + CharPointerType getCharPointer() const noexcept { return text; } /** Returns a pointer to a UTF-8 version of this string. @@ -1481,9 +1527,11 @@ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, float number); /** Appends a decimal number to the end of a string. */ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, double number); +#ifndef DOXYGEN // Automatically creating a String from a bool opens up lots of nasty type conversion edge cases. // If you want a String representation of a bool you can cast the bool to an int first. String& JUCE_CALLTYPE operator<< (String&, bool) = delete; +#endif //============================================================================== /** Case-sensitive comparison of two strings. */ @@ -1512,15 +1560,6 @@ JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, CharPointer_UTF16 /** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, CharPointer_UTF32 string2) noexcept; -/** Case-sensitive comparison of two strings. */ -JUCE_API bool JUCE_CALLTYPE operator> (const String& string1, const String& string2) noexcept; -/** Case-sensitive comparison of two strings. */ -JUCE_API bool JUCE_CALLTYPE operator< (const String& string1, const String& string2) noexcept; -/** Case-sensitive comparison of two strings. */ -JUCE_API bool JUCE_CALLTYPE operator>= (const String& string1, const String& string2) noexcept; -/** Case-sensitive comparison of two strings. */ -JUCE_API bool JUCE_CALLTYPE operator<= (const String& string1, const String& string2) noexcept; - //============================================================================== /** This operator allows you to write a juce String directly to std output streams. This is handy for writing strings to std::cout, std::cerr, etc. diff --git a/JuceLibraryCode/modules/juce_core/text/juce_StringArray.cpp b/JuceLibraryCode/modules/juce_core/text/juce_StringArray.cpp index 1db1bab..7c8785a 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_StringArray.cpp +++ b/JuceLibraryCode/modules/juce_core/text/juce_StringArray.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. @@ -300,7 +300,7 @@ String StringArray::joinIntoString (StringRef separator, int start, int numberTo return strings.getReference (start); auto separatorBytes = separator.text.sizeInBytes() - sizeof (String::CharPointerType::CharType); - auto bytesNeeded = separatorBytes * (size_t) (last - start - 1); + auto bytesNeeded = (size_t) (last - start - 1) * separatorBytes; for (int i = start; i < last; ++i) bytesNeeded += strings.getReference(i).getCharPointer().sizeInBytes() - sizeof (String::CharPointerType::CharType); diff --git a/JuceLibraryCode/modules/juce_core/text/juce_StringArray.h b/JuceLibraryCode/modules/juce_core/text/juce_StringArray.h index 22d27d5..2487433 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_StringArray.h +++ b/JuceLibraryCode/modules/juce_core/text/juce_StringArray.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. @@ -155,12 +155,23 @@ class JUCE_API StringArray /** Returns a pointer to the first String in the array. This method is provided for compatibility with standard C++ iteration mechanisms. */ - inline String* begin() const noexcept { return strings.begin(); } + inline String* begin() noexcept { return strings.begin(); } + + /** Returns a pointer to the first String in the array. + This method is provided for compatibility with standard C++ iteration mechanisms. + */ + inline const String* begin() const noexcept { return strings.begin(); } /** Returns a pointer to the String which follows the last element in the array. This method is provided for compatibility with standard C++ iteration mechanisms. */ - inline String* end() const noexcept { return strings.end(); } + inline String* end() noexcept { return strings.end(); } + + /** Returns a pointer to the String which follows the last element in the array. + This method is provided for compatibility with standard C++ iteration mechanisms. + */ + inline const String* end() const noexcept { return strings.end(); } + /** Searches for a string in the array. diff --git a/JuceLibraryCode/modules/juce_core/text/juce_StringPairArray.cpp b/JuceLibraryCode/modules/juce_core/text/juce_StringPairArray.cpp index b5f77dc..4290ee2 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_StringPairArray.cpp +++ b/JuceLibraryCode/modules/juce_core/text/juce_StringPairArray.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. @@ -99,7 +99,7 @@ String StringPairArray::getValue (StringRef key, const String& defaultReturnValu bool StringPairArray::containsKey (StringRef key) const noexcept { - return keys.contains (key); + return keys.contains (key, ignoreCase); } void StringPairArray::set (const String& key, const String& value) diff --git a/JuceLibraryCode/modules/juce_core/text/juce_StringPairArray.h b/JuceLibraryCode/modules/juce_core/text/juce_StringPairArray.h index aab5b04..e99db6b 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_StringPairArray.h +++ b/JuceLibraryCode/modules/juce_core/text/juce_StringPairArray.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_core/text/juce_StringPool.cpp b/JuceLibraryCode/modules/juce_core/text/juce_StringPool.cpp index bf004da..da1b9fd 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_StringPool.cpp +++ b/JuceLibraryCode/modules/juce_core/text/juce_StringPool.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_core/text/juce_StringPool.h b/JuceLibraryCode/modules/juce_core/text/juce_StringPool.h index 7e1f513..bd7934c 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_StringPool.h +++ b/JuceLibraryCode/modules/juce_core/text/juce_StringPool.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_core/text/juce_StringRef.h b/JuceLibraryCode/modules/juce_core/text/juce_StringRef.h index f6b018c..9de1327 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_StringRef.h +++ b/JuceLibraryCode/modules/juce_core/text/juce_StringRef.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. @@ -111,6 +111,14 @@ class JUCE_API StringRef final bool operator== (const String& s) const noexcept { return text.compare (s.getCharPointer()) == 0; } /** Compares this StringRef with a String. */ bool operator!= (const String& s) const noexcept { return text.compare (s.getCharPointer()) != 0; } + /** Compares this StringRef with a String. */ + bool operator< (const String& s) const noexcept { return text.compare (s.getCharPointer()) < 0; } + /** Compares this StringRef with a String. */ + bool operator<= (const String& s) const noexcept { return text.compare (s.getCharPointer()) <= 0; } + /** Compares this StringRef with a String. */ + bool operator> (const String& s) const noexcept { return text.compare (s.getCharPointer()) > 0; } + /** Compares this StringRef with a String. */ + bool operator>= (const String& s) const noexcept { return text.compare (s.getCharPointer()) >= 0; } /** Case-sensitive comparison of two StringRefs. */ bool operator== (StringRef s) const noexcept { return text.compare (s.text) == 0; } @@ -133,6 +141,14 @@ class JUCE_API StringRef final JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, StringRef string2) noexcept; /** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, StringRef string2) noexcept; +/** Case-sensitive comparison of two strings. */ +JUCE_API bool JUCE_CALLTYPE operator< (const String& string1, StringRef string2) noexcept; +/** Case-sensitive comparison of two strings. */ +JUCE_API bool JUCE_CALLTYPE operator<= (const String& string1, StringRef string2) noexcept; +/** Case-sensitive comparison of two strings. */ +JUCE_API bool JUCE_CALLTYPE operator> (const String& string1, StringRef string2) noexcept; +/** Case-sensitive comparison of two strings. */ +JUCE_API bool JUCE_CALLTYPE operator>= (const String& string1, StringRef string2) noexcept; inline String operator+ (String s1, StringRef s2) { return s1 += String (s2.text); } inline String operator+ (StringRef s1, const String& s2) { return String (s1.text) + s2; } diff --git a/JuceLibraryCode/modules/juce_core/text/juce_TextDiff.cpp b/JuceLibraryCode/modules/juce_core/text/juce_TextDiff.cpp index a087774..11598cf 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_TextDiff.cpp +++ b/JuceLibraryCode/modules/juce_core/text/juce_TextDiff.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. @@ -216,6 +216,7 @@ String TextDiff::Change::appliedTo (const String& text) const noexcept return text.replaceSection (start, length, insertedText); } + //============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -223,7 +224,9 @@ String TextDiff::Change::appliedTo (const String& text) const noexcept class DiffTests : public UnitTest { public: - DiffTests() : UnitTest ("TextDiff class", "Text") {} + DiffTests() + : UnitTest ("TextDiff class", UnitTestCategories::text) + {} static String createString (Random& r) { diff --git a/JuceLibraryCode/modules/juce_core/text/juce_TextDiff.h b/JuceLibraryCode/modules/juce_core/text/juce_TextDiff.h index 84b5662..6c0bfd8 100644 --- a/JuceLibraryCode/modules/juce_core/text/juce_TextDiff.h +++ b/JuceLibraryCode/modules/juce_core/text/juce_TextDiff.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_core/threads/juce_ChildProcess.cpp b/JuceLibraryCode/modules/juce_core/threads/juce_ChildProcess.cpp index edfe458..a67a7a7 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_ChildProcess.cpp +++ b/JuceLibraryCode/modules/juce_core/threads/juce_ChildProcess.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. @@ -80,13 +80,17 @@ String ChildProcess::readAllProcessOutput() return result.toString(); } + +//============================================================================== //============================================================================== #if JUCE_UNIT_TESTS class ChildProcessTests : public UnitTest { public: - ChildProcessTests() : UnitTest ("ChildProcess", "Threads") {} + ChildProcessTests() + : UnitTest ("ChildProcess", UnitTestCategories::threads) + {} void runTest() override { @@ -101,8 +105,8 @@ class ChildProcessTests : public UnitTest expect (p.start ("ls /")); #endif - //String output (p.readAllProcessOutput()); - //expect (output.isNotEmpty()); + auto output = p.readAllProcessOutput(); + expect (output.isNotEmpty()); #endif } }; diff --git a/JuceLibraryCode/modules/juce_core/threads/juce_ChildProcess.h b/JuceLibraryCode/modules/juce_core/threads/juce_ChildProcess.h index e2c46a6..84158d1 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_ChildProcess.h +++ b/JuceLibraryCode/modules/juce_core/threads/juce_ChildProcess.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_core/threads/juce_CriticalSection.h b/JuceLibraryCode/modules/juce_core/threads/juce_CriticalSection.h index 2d929ad..d12b643 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_CriticalSection.h +++ b/JuceLibraryCode/modules/juce_core/threads/juce_CriticalSection.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_core/threads/juce_DynamicLibrary.h b/JuceLibraryCode/modules/juce_core/threads/juce_DynamicLibrary.h index f4f9a84..009d9e2 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_DynamicLibrary.h +++ b/JuceLibraryCode/modules/juce_core/threads/juce_DynamicLibrary.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_core/threads/juce_HighResolutionTimer.cpp b/JuceLibraryCode/modules/juce_core/threads/juce_HighResolutionTimer.cpp index c4ea827..9222405 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_HighResolutionTimer.cpp +++ b/JuceLibraryCode/modules/juce_core/threads/juce_HighResolutionTimer.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_core/threads/juce_HighResolutionTimer.h b/JuceLibraryCode/modules/juce_core/threads/juce_HighResolutionTimer.h index ad4aaea..7c67971 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_HighResolutionTimer.h +++ b/JuceLibraryCode/modules/juce_core/threads/juce_HighResolutionTimer.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_core/threads/juce_InterProcessLock.h b/JuceLibraryCode/modules/juce_core/threads/juce_InterProcessLock.h index 756814c..b58028d 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_InterProcessLock.h +++ b/JuceLibraryCode/modules/juce_core/threads/juce_InterProcessLock.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_core/threads/juce_Process.h b/JuceLibraryCode/modules/juce_core/threads/juce_Process.h index 4012380..2cdf91c 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_Process.h +++ b/JuceLibraryCode/modules/juce_core/threads/juce_Process.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. @@ -133,7 +133,7 @@ class JUCE_API Process static void JUCE_CALLTYPE setCurrentModuleInstanceHandle (void* newHandle) noexcept; #endif - #if JUCE_MAC || DOXYGEN + #if (JUCE_MAC && JUCE_MODULE_AVAILABLE_juce_gui_basics) || DOXYGEN //============================================================================== /** OSX ONLY - Shows or hides the OSX dock icon for this app. */ static void setDockIconVisible (bool isVisible); diff --git a/JuceLibraryCode/modules/juce_core/threads/juce_ReadWriteLock.cpp b/JuceLibraryCode/modules/juce_core/threads/juce_ReadWriteLock.cpp index 7d6756f..255034b 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_ReadWriteLock.cpp +++ b/JuceLibraryCode/modules/juce_core/threads/juce_ReadWriteLock.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. @@ -38,22 +38,20 @@ ReadWriteLock::~ReadWriteLock() noexcept void ReadWriteLock::enterRead() const noexcept { while (! tryEnterRead()) - waitEvent.wait (100); + readWaitEvent.wait (100); } bool ReadWriteLock::tryEnterRead() const noexcept { - const Thread::ThreadID threadId = Thread::getCurrentThreadId(); + auto threadId = Thread::getCurrentThreadId(); const SpinLock::ScopedLockType sl (accessLock); - for (int i = 0; i < readerThreads.size(); ++i) + for (auto& readerThread : readerThreads) { - ThreadRecursionCount& trc = readerThreads.getReference(i); - - if (trc.threadID == threadId) + if (readerThread.threadID == threadId) { - trc.count++; + readerThread.count++; return true; } } @@ -61,8 +59,7 @@ bool ReadWriteLock::tryEnterRead() const noexcept if (numWriters + numWaitingWriters == 0 || (threadId == writerThreadId && numWriters > 0)) { - ThreadRecursionCount trc = { threadId, 1 }; - readerThreads.add (trc); + readerThreads.add ({ threadId, 1 }); return true; } @@ -71,19 +68,21 @@ bool ReadWriteLock::tryEnterRead() const noexcept void ReadWriteLock::exitRead() const noexcept { - const Thread::ThreadID threadId = Thread::getCurrentThreadId(); + auto threadId = Thread::getCurrentThreadId(); const SpinLock::ScopedLockType sl (accessLock); for (int i = 0; i < readerThreads.size(); ++i) { - ThreadRecursionCount& trc = readerThreads.getReference(i); + auto& readerThread = readerThreads.getReference (i); - if (trc.threadID == threadId) + if (readerThread.threadID == threadId) { - if (--(trc.count) == 0) + if (--(readerThread.count) == 0) { readerThreads.remove (i); - waitEvent.signal(); + + readWaitEvent.signal(); + writeWaitEvent.signal(); } return; @@ -96,14 +95,14 @@ void ReadWriteLock::exitRead() const noexcept //============================================================================== void ReadWriteLock::enterWrite() const noexcept { - const Thread::ThreadID threadId = Thread::getCurrentThreadId(); + auto threadId = Thread::getCurrentThreadId(); const SpinLock::ScopedLockType sl (accessLock); while (! tryEnterWriteInternal (threadId)) { ++numWaitingWriters; accessLock.exit(); - waitEvent.wait (100); + writeWaitEvent.wait (100); accessLock.enter(); --numWaitingWriters; } @@ -119,7 +118,7 @@ bool ReadWriteLock::tryEnterWriteInternal (Thread::ThreadID threadId) const noex { if (readerThreads.size() + numWriters == 0 || threadId == writerThreadId - || (readerThreads.size() == 1 && readerThreads.getReference(0).threadID == threadId)) + || (readerThreads.size() == 1 && readerThreads.getReference (0).threadID == threadId)) { writerThreadId = threadId; ++numWriters; @@ -139,7 +138,9 @@ void ReadWriteLock::exitWrite() const noexcept if (--numWriters == 0) { writerThreadId = {}; - waitEvent.signal(); + + readWaitEvent.signal(); + writeWaitEvent.signal(); } } diff --git a/JuceLibraryCode/modules/juce_core/threads/juce_ReadWriteLock.h b/JuceLibraryCode/modules/juce_core/threads/juce_ReadWriteLock.h index 181fa1f..4b9ec00 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_ReadWriteLock.h +++ b/JuceLibraryCode/modules/juce_core/threads/juce_ReadWriteLock.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. @@ -126,7 +126,7 @@ class JUCE_API ReadWriteLock private: //============================================================================== SpinLock accessLock; - WaitableEvent waitEvent; + WaitableEvent readWaitEvent, writeWaitEvent; mutable int numWaitingWriters = 0, numWriters = 0; mutable Thread::ThreadID writerThreadId = {}; diff --git a/JuceLibraryCode/modules/juce_core/threads/juce_ScopedLock.h b/JuceLibraryCode/modules/juce_core/threads/juce_ScopedLock.h index 3d33dd4..ea003bb 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_ScopedLock.h +++ b/JuceLibraryCode/modules/juce_core/threads/juce_ScopedLock.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_core/threads/juce_ScopedReadLock.h b/JuceLibraryCode/modules/juce_core/threads/juce_ScopedReadLock.h index 064d857..e2737d8 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_ScopedReadLock.h +++ b/JuceLibraryCode/modules/juce_core/threads/juce_ScopedReadLock.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_core/threads/juce_ScopedWriteLock.h b/JuceLibraryCode/modules/juce_core/threads/juce_ScopedWriteLock.h index 117c6ca..92cbe2d 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_ScopedWriteLock.h +++ b/JuceLibraryCode/modules/juce_core/threads/juce_ScopedWriteLock.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_core/threads/juce_SpinLock.h b/JuceLibraryCode/modules/juce_core/threads/juce_SpinLock.h index 6b9265f..daf8bb8 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_SpinLock.h +++ b/JuceLibraryCode/modules/juce_core/threads/juce_SpinLock.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. @@ -75,6 +75,9 @@ class JUCE_API SpinLock /** Provides the type of scoped unlocker to use with a SpinLock. */ using ScopedUnlockType = GenericScopedUnlock; + /** Provides the type of scoped try-lock to use for locking a SpinLock. */ + using ScopedTryLockType = GenericScopedTryLock; + private: //============================================================================== mutable Atomic lock; diff --git a/JuceLibraryCode/modules/juce_core/threads/juce_Thread.cpp b/JuceLibraryCode/modules/juce_core/threads/juce_Thread.cpp index 09c803a..160c6f4 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_Thread.cpp +++ b/JuceLibraryCode/modules/juce_core/threads/juce_Thread.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. @@ -315,7 +315,7 @@ struct LambdaThread : public Thread void run() override { fn(); - fn = {}; // free any objects that the lambda might contain while the thread is still active + fn = nullptr; // free any objects that the lambda might contain while the thread is still active } std::function fn; @@ -350,13 +350,17 @@ bool JUCE_CALLTYPE Process::isRunningUnderDebugger() noexcept return juce_isRunningUnderDebugger(); } -#if JUCE_UNIT_TESTS //============================================================================== +//============================================================================== +#if JUCE_UNIT_TESTS + class AtomicTests : public UnitTest { public: - AtomicTests() : UnitTest ("Atomics", "Threads") {} + AtomicTests() + : UnitTest ("Atomics", UnitTestCategories::threads) + {} void runTest() override { @@ -369,7 +373,7 @@ class AtomicTests : public UnitTest expect (ByteOrder::swap ((uint16) 0x1122) == 0x2211); expect (ByteOrder::swap ((uint32) 0x11223344) == 0x44332211); - expect (ByteOrder::swap ((uint64) 0x1122334455667788ULL) == 0x8877665544332211LL); + expect (ByteOrder::swap ((uint64) 0x1122334455667788ULL) == (uint64) 0x8877665544332211LL); beginTest ("Atomic int"); AtomicTester ::testInteger (*this); @@ -480,7 +484,7 @@ class ThreadLocalValueUnitTest : public UnitTest, { public: ThreadLocalValueUnitTest() - : UnitTest ("ThreadLocalValue", "Threads"), + : UnitTest ("ThreadLocalValue", UnitTestCategories::threads), Thread ("ThreadLocalValue Thread") {} diff --git a/JuceLibraryCode/modules/juce_core/threads/juce_Thread.h b/JuceLibraryCode/modules/juce_core/threads/juce_Thread.h index 6432f56..34f37e4 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_Thread.h +++ b/JuceLibraryCode/modules/juce_core/threads/juce_Thread.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. @@ -352,7 +352,7 @@ class JUCE_API Thread following java method: @code - com.roli.juce.Java.initialiseJUCE (myContext); + com.rmsl.juce.Java.initialiseJUCE (myContext); @endcode Note that the above java method is only available in Android Studio projects @@ -361,7 +361,7 @@ class JUCE_API Thread your project: @code - package com.roli.juce; + package com.rmsl.juce; public class Java { diff --git a/JuceLibraryCode/modules/juce_core/threads/juce_ThreadLocalValue.h b/JuceLibraryCode/modules/juce_core/threads/juce_ThreadLocalValue.h index f40617e..eda0d7d 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_ThreadLocalValue.h +++ b/JuceLibraryCode/modules/juce_core/threads/juce_ThreadLocalValue.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_core/threads/juce_ThreadPool.cpp b/JuceLibraryCode/modules/juce_core/threads/juce_ThreadPool.cpp index bf537e7..e596315 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_ThreadPool.cpp +++ b/JuceLibraryCode/modules/juce_core/threads/juce_ThreadPool.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. @@ -176,6 +176,7 @@ void ThreadPool::addJob (std::function jobToRun) int ThreadPool::getNumJobs() const noexcept { + const ScopedLock sl (lock); return jobs.size(); } diff --git a/JuceLibraryCode/modules/juce_core/threads/juce_ThreadPool.h b/JuceLibraryCode/modules/juce_core/threads/juce_ThreadPool.h index 85aafd8..dd10ecc 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_ThreadPool.h +++ b/JuceLibraryCode/modules/juce_core/threads/juce_ThreadPool.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. @@ -76,7 +76,7 @@ class JUCE_API ThreadPoolJob again when a thread is free. */ }; - /** Peforms the actual work that this job needs to do. + /** Performs the actual work that this job needs to do. Your subclass must implement this method, in which is does its work. diff --git a/JuceLibraryCode/modules/juce_core/threads/juce_TimeSliceThread.cpp b/JuceLibraryCode/modules/juce_core/threads/juce_TimeSliceThread.cpp index c8eb3d8..a473b79 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_TimeSliceThread.cpp +++ b/JuceLibraryCode/modules/juce_core/threads/juce_TimeSliceThread.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_core/threads/juce_TimeSliceThread.h b/JuceLibraryCode/modules/juce_core/threads/juce_TimeSliceThread.h index a71aba3..440fb1a 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_TimeSliceThread.h +++ b/JuceLibraryCode/modules/juce_core/threads/juce_TimeSliceThread.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. @@ -57,7 +57,7 @@ class JUCE_API TimeSliceClient @returns Your method should return the number of milliseconds which it would like to wait before being called again. Returning 0 will make the thread call again as soon as possible (after possibly servicing other busy clients). If you return a value below zero, your client will be removed from the list of clients, - and won't be called again. The value you specify isn't a guaranteee, and is only used as a hint by the + and won't be called again. The value you specify isn't a guarantee, and is only used as a hint by the thread - the actual time before the next callback may be more or less than specified. You can force the TimeSliceThread to wake up and poll again immediately by calling its notify() method. */ diff --git a/JuceLibraryCode/modules/juce_core/threads/juce_WaitableEvent.cpp b/JuceLibraryCode/modules/juce_core/threads/juce_WaitableEvent.cpp new file mode 100644 index 0000000..25e1507 --- /dev/null +++ b/JuceLibraryCode/modules/juce_core/threads/juce_WaitableEvent.cpp @@ -0,0 +1,70 @@ +/* + ============================================================================== + + 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 +{ + +WaitableEvent::WaitableEvent (bool manualReset) noexcept + : useManualReset (manualReset) +{ +} + +bool WaitableEvent::wait (int timeOutMilliseconds) const +{ + std::unique_lock lock (mutex); + + if (! triggered) + { + if (timeOutMilliseconds < 0) + { + condition.wait (lock, [this] { return triggered == true; }); + } + else + { + if (! condition.wait_for (lock, std::chrono::milliseconds (timeOutMilliseconds), + [this] { return triggered == true; })) + { + return false; + } + } + } + + if (! useManualReset) + reset(); + + return true; +} + +void WaitableEvent::signal() const +{ + std::unique_lock lock (mutex); + + triggered = true; + condition.notify_all(); +} + +void WaitableEvent::reset() const +{ + triggered = false; +} + +} // namespace juce diff --git a/JuceLibraryCode/modules/juce_core/threads/juce_WaitableEvent.h b/JuceLibraryCode/modules/juce_core/threads/juce_WaitableEvent.h index 0a89661..a7a88ad 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_WaitableEvent.h +++ b/JuceLibraryCode/modules/juce_core/threads/juce_WaitableEvent.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,13 +46,6 @@ class JUCE_API WaitableEvent */ explicit WaitableEvent (bool manualReset = false) noexcept; - /** Destructor. - - If other threads are waiting on this object when it gets deleted, this - can cause nasty errors, so be careful! - */ - ~WaitableEvent() noexcept; - //============================================================================== /** Suspends the calling thread until the event has been signalled. @@ -68,9 +61,8 @@ class JUCE_API WaitableEvent @returns true if the object has been signalled, false if the timeout expires first. @see signal, reset */ - bool wait (int timeOutMilliseconds = -1) const noexcept; + bool wait (int timeOutMilliseconds = -1) const; - //============================================================================== /** Wakes up any threads that are currently waiting on this object. If signal() is called when nothing is waiting, the next thread to call wait() @@ -86,24 +78,20 @@ class JUCE_API WaitableEvent @see wait, reset */ - void signal() const noexcept; + void signal() const; - //============================================================================== /** Resets the event to an unsignalled state. If it's not already signalled, this does nothing. */ - void reset() const noexcept; - + void reset() const; private: //============================================================================== - #if JUCE_WINDOWS - void* handle; - #else - mutable pthread_cond_t condition; - mutable pthread_mutex_t mutex; - mutable bool triggered, manualReset; - #endif + bool useManualReset; + + mutable std::mutex mutex; + mutable std::condition_variable condition; + mutable std::atomic triggered { false }; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WaitableEvent) }; diff --git a/JuceLibraryCode/modules/juce_core/time/juce_PerformanceCounter.cpp b/JuceLibraryCode/modules/juce_core/time/juce_PerformanceCounter.cpp index c32fb5b..510bd65 100644 --- a/JuceLibraryCode/modules/juce_core/time/juce_PerformanceCounter.cpp +++ b/JuceLibraryCode/modules/juce_core/time/juce_PerformanceCounter.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,7 +43,8 @@ PerformanceCounter::PerformanceCounter (const String& name, int runsPerPrintout, PerformanceCounter::~PerformanceCounter() { - printStatistics(); + if (stats.numRuns > 0) + printStatistics(); } PerformanceCounter::Statistics::Statistics() noexcept @@ -113,7 +114,7 @@ void PerformanceCounter::printStatistics() { const String desc (getStatisticsAndReset().toString()); - Logger::outputDebugString (desc); + Logger::writeToLog (desc); appendToFile (outputFile, desc); } @@ -123,7 +124,7 @@ PerformanceCounter::Statistics PerformanceCounter::getStatisticsAndReset() stats.clear(); if (s.numRuns > 0) - s.averageSeconds = s.totalSeconds / s.numRuns; + s.averageSeconds = s.totalSeconds / (float) s.numRuns; return s; } diff --git a/JuceLibraryCode/modules/juce_core/time/juce_PerformanceCounter.h b/JuceLibraryCode/modules/juce_core/time/juce_PerformanceCounter.h index fef5d5e..262c379 100644 --- a/JuceLibraryCode/modules/juce_core/time/juce_PerformanceCounter.h +++ b/JuceLibraryCode/modules/juce_core/time/juce_PerformanceCounter.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_core/time/juce_RelativeTime.cpp b/JuceLibraryCode/modules/juce_core/time/juce_RelativeTime.cpp index b803a70..93d94c5 100644 --- a/JuceLibraryCode/modules/juce_core/time/juce_RelativeTime.cpp +++ b/JuceLibraryCode/modules/juce_core/time/juce_RelativeTime.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,13 +28,13 @@ RelativeTime::RelativeTime (const RelativeTime& other) noexcept : numSeconds ( RelativeTime::~RelativeTime() noexcept {} //============================================================================== -RelativeTime RelativeTime::milliseconds (const int milliseconds) noexcept { return RelativeTime (milliseconds * 0.001); } -RelativeTime RelativeTime::milliseconds (const int64 milliseconds) noexcept { return RelativeTime (milliseconds * 0.001); } +RelativeTime RelativeTime::milliseconds (int milliseconds) noexcept { return RelativeTime ((double) milliseconds * 0.001); } +RelativeTime RelativeTime::milliseconds (int64 milliseconds) noexcept { return RelativeTime ((double) milliseconds * 0.001); } RelativeTime RelativeTime::seconds (double s) noexcept { return RelativeTime (s); } -RelativeTime RelativeTime::minutes (const double numberOfMinutes) noexcept { return RelativeTime (numberOfMinutes * 60.0); } -RelativeTime RelativeTime::hours (const double numberOfHours) noexcept { return RelativeTime (numberOfHours * (60.0 * 60.0)); } -RelativeTime RelativeTime::days (const double numberOfDays) noexcept { return RelativeTime (numberOfDays * (60.0 * 60.0 * 24.0)); } -RelativeTime RelativeTime::weeks (const double numberOfWeeks) noexcept { return RelativeTime (numberOfWeeks * (60.0 * 60.0 * 24.0 * 7.0)); } +RelativeTime RelativeTime::minutes (double numberOfMinutes) noexcept { return RelativeTime (numberOfMinutes * 60.0); } +RelativeTime RelativeTime::hours (double numberOfHours) noexcept { return RelativeTime (numberOfHours * (60.0 * 60.0)); } +RelativeTime RelativeTime::days (double numberOfDays) noexcept { return RelativeTime (numberOfDays * (60.0 * 60.0 * 24.0)); } +RelativeTime RelativeTime::weeks (double numberOfWeeks) noexcept { return RelativeTime (numberOfWeeks * (60.0 * 60.0 * 24.0 * 7.0)); } //============================================================================== int64 RelativeTime::inMilliseconds() const noexcept { return (int64) (numSeconds * 1000.0); } @@ -48,8 +48,8 @@ RelativeTime& RelativeTime::operator= (const RelativeTime& other) noexcept RelativeTime RelativeTime::operator+= (RelativeTime t) noexcept { numSeconds += t.numSeconds; return *this; } RelativeTime RelativeTime::operator-= (RelativeTime t) noexcept { numSeconds -= t.numSeconds; return *this; } -RelativeTime RelativeTime::operator+= (const double secs) noexcept { numSeconds += secs; return *this; } -RelativeTime RelativeTime::operator-= (const double secs) noexcept { numSeconds -= secs; return *this; } +RelativeTime RelativeTime::operator+= (double secs) noexcept { numSeconds += secs; return *this; } +RelativeTime RelativeTime::operator-= (double secs) noexcept { numSeconds -= secs; return *this; } JUCE_API RelativeTime JUCE_CALLTYPE operator+ (RelativeTime t1, RelativeTime t2) noexcept { return t1 += t2; } JUCE_API RelativeTime JUCE_CALLTYPE operator- (RelativeTime t1, RelativeTime t2) noexcept { return t1 -= t2; } @@ -62,77 +62,96 @@ JUCE_API bool JUCE_CALLTYPE operator>= (RelativeTime t1, RelativeTime t2) noexce JUCE_API bool JUCE_CALLTYPE operator<= (RelativeTime t1, RelativeTime t2) noexcept { return t1.inSeconds() <= t2.inSeconds(); } //============================================================================== -static void translateTimeField (String& result, int n, const char* singular, const char* plural) +static String translateTimeField (int n, const char* singular, const char* plural) { - result << TRANS (n == 1 ? singular : plural) - .replace (n == 1 ? "1" : "2", String (n)) - << ' '; + return TRANS (n == 1 ? singular : plural).replace (n == 1 ? "1" : "2", String (n)); +} + +static String describeYears (int n) { return translateTimeField (n, NEEDS_TRANS("1 year"), NEEDS_TRANS("2 years")); } +static String describeMonths (int n) { return translateTimeField (n, NEEDS_TRANS("1 month"), NEEDS_TRANS("2 months")); } +static String describeWeeks (int n) { return translateTimeField (n, NEEDS_TRANS("1 week"), NEEDS_TRANS("2 weeks")); } +static String describeDays (int n) { return translateTimeField (n, NEEDS_TRANS("1 day"), NEEDS_TRANS("2 days")); } +static String describeHours (int n) { return translateTimeField (n, NEEDS_TRANS("1 hr"), NEEDS_TRANS("2 hrs")); } +static String describeMinutes (int n) { return translateTimeField (n, NEEDS_TRANS("1 min"), NEEDS_TRANS("2 mins")); } +static String describeSeconds (int n) { return translateTimeField (n, NEEDS_TRANS("1 sec"), NEEDS_TRANS("2 secs")); } + +String RelativeTime::getApproximateDescription() const +{ + if (numSeconds <= 1.0) + return "< 1 sec"; + + auto weeks = (int) inWeeks(); + + if (weeks > 52) return describeYears (weeks / 52); + if (weeks > 8) return describeMonths ((weeks * 12) / 52); + if (weeks > 1) return describeWeeks (weeks); + + auto days = (int) inWeeks(); + + if (days > 1) + return describeDays (days); + + auto hours = (int) inHours(); + + if (hours > 0) + return describeHours (hours); + + auto minutes = (int) inMinutes(); + + if (minutes > 0) + return describeMinutes (minutes); + + return describeSeconds ((int) numSeconds); } String RelativeTime::getDescription (const String& returnValueForZeroTime) const { - if (numSeconds < 0.001 && numSeconds > -0.001) + if (std::abs (numSeconds) < 0.001) return returnValueForZeroTime; - String result; - result.preallocateBytes (32); - if (numSeconds < 0) - result << '-'; + return "-" + RelativeTime (-numSeconds).getDescription(); + + StringArray fields; + + auto n = (int) inWeeks(); - int fieldsShown = 0; - int n = std::abs ((int) inWeeks()); if (n > 0) - { - translateTimeField (result, n, NEEDS_TRANS("1 week"), NEEDS_TRANS("2 weeks")); - ++fieldsShown; - } + fields.add (describeWeeks (n)); + + n = ((int) inDays()) % 7; - n = std::abs ((int) inDays()) % 7; if (n > 0) - { - translateTimeField (result, n, NEEDS_TRANS("1 day"), NEEDS_TRANS("2 days")); - ++fieldsShown; - } + fields.add (describeDays (n)); - if (fieldsShown < 2) + if (fields.size() < 2) { - n = std::abs ((int) inHours()) % 24; + n = ((int) inHours()) % 24; + if (n > 0) - { - translateTimeField (result, n, NEEDS_TRANS("1 hr"), NEEDS_TRANS("2 hrs")); - ++fieldsShown; - } + fields.add (describeHours (n)); - if (fieldsShown < 2) + if (fields.size() < 2) { - n = std::abs ((int) inMinutes()) % 60; + n = ((int) inMinutes()) % 60; + if (n > 0) - { - translateTimeField (result, n, NEEDS_TRANS("1 min"), NEEDS_TRANS("2 mins")); - ++fieldsShown; - } + fields.add (describeMinutes (n)); - if (fieldsShown < 2) + if (fields.size() < 2) { - n = std::abs ((int) inSeconds()) % 60; + n = ((int) inSeconds()) % 60; + if (n > 0) - { - translateTimeField (result, n, NEEDS_TRANS("1 sec"), NEEDS_TRANS("2 secs")); - ++fieldsShown; - } - - if (fieldsShown == 0) - { - n = std::abs ((int) inMilliseconds()) % 1000; - if (n > 0) - result << n << ' ' << TRANS ("ms"); - } + fields.add (describeSeconds (n)); + + if (fields.isEmpty()) + fields.add (String (((int) inMilliseconds()) % 1000) + " " + TRANS ("ms")); } } } - return result.trimEnd(); + return fields.joinIntoString (" "); } } // namespace juce diff --git a/JuceLibraryCode/modules/juce_core/time/juce_RelativeTime.h b/JuceLibraryCode/modules/juce_core/time/juce_RelativeTime.h index 09cde00..78a26ae 100644 --- a/JuceLibraryCode/modules/juce_core/time/juce_RelativeTime.h +++ b/JuceLibraryCode/modules/juce_core/time/juce_RelativeTime.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. @@ -137,6 +137,13 @@ class JUCE_API RelativeTime */ String getDescription (const String& returnValueForZeroTime = "0") const; + //============================================================================== + /** This returns a string that roughly describes how long ago this time was, which + can be handy for showing ages of files, etc. + This will only attempt to be accurate to within the nearest order of magnitude + so returns strings such as "5 years", "2 weeks", "< 1 minute", "< 1 sec" etc. + */ + String getApproximateDescription() const; //============================================================================== /** Adds another RelativeTime to this one. */ diff --git a/JuceLibraryCode/modules/juce_core/time/juce_Time.cpp b/JuceLibraryCode/modules/juce_core/time/juce_Time.cpp index 7225c4e..7a9974c 100644 --- a/JuceLibraryCode/modules/juce_core/time/juce_Time.cpp +++ b/JuceLibraryCode/modules/juce_core/time/juce_Time.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. @@ -91,7 +91,7 @@ namespace TimeHelpers : (value - ((value / modulo) + 1) * modulo)); } - static inline String formatString (const String& format, const std::tm* const tm) + static String formatString (const String& format, const std::tm* const tm) { #if JUCE_ANDROID using StringType = CharPointer_UTF8; @@ -126,12 +126,12 @@ namespace TimeHelpers } //============================================================================== - static inline bool isLeapYear (int year) noexcept + static bool isLeapYear (int year) noexcept { return (year % 400 == 0) || ((year % 100 != 0) && (year % 4 == 0)); } - static inline int daysFromJan1 (int year, int month) noexcept + static int daysFromJan1 (int year, int month) noexcept { const short dayOfYear[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }; @@ -139,18 +139,18 @@ namespace TimeHelpers return dayOfYear [(isLeapYear (year) ? 12 : 0) + month]; } - static inline int64 daysFromYear0 (int year) noexcept + static int64 daysFromYear0 (int year) noexcept { --year; return 365 * year + (year / 400) - (year / 100) + (year / 4); } - static inline int64 daysFrom1970 (int year) noexcept + static int64 daysFrom1970 (int year) noexcept { return daysFromYear0 (year) - daysFromYear0 (1970); } - static inline int64 daysFrom1970 (int year, int month) noexcept + static int64 daysFrom1970 (int year, int month) noexcept { if (month > 11) { @@ -169,7 +169,7 @@ namespace TimeHelpers // There's no posix function that does a UTC version of mktime, // so annoyingly we need to implement this manually.. - static inline int64 mktime_utc (const std::tm& t) noexcept + static int64 mktime_utc (const std::tm& t) noexcept { return 24 * 3600 * (daysFrom1970 (t.tm_year + 1900, t.tm_mon) + (t.tm_mday - 1)) + 3600 * t.tm_hour @@ -277,7 +277,7 @@ void Time::waitForMillisecondCounter (uint32 targetTime) noexcept //============================================================================== double Time::highResolutionTicksToSeconds (const int64 ticks) noexcept { - return ticks / (double) getHighResolutionTicksPerSecond(); + return (double) ticks / (double) getHighResolutionTicksPerSecond(); } int64 Time::secondsToHighResolutionTicks (const double seconds) noexcept @@ -491,7 +491,7 @@ Time Time::fromISO8601 (StringRef iso) if (seconds < 0) return {}; - if (*t == '.') + if (*t == '.' || *t == ',') { ++t; milliseconds = parseFixedSizeIntAndSkip (t, 3, 0); @@ -612,7 +612,9 @@ Time Time::getCompilationDate() class TimeTests : public UnitTest { public: - TimeTests() : UnitTest ("Time", "Time") {} + TimeTests() + : UnitTest ("Time", UnitTestCategories::time) + {} void runTest() override { @@ -632,15 +634,22 @@ class TimeTests : public UnitTest expect (Time::fromISO8601 (t.toISO8601 (false)) == t); expect (Time::fromISO8601 ("2016-02-16") == Time (2016, 1, 16, 0, 0, 0, 0, false)); - expect (Time::fromISO8601 ("20160216Z") == Time (2016, 1, 16, 0, 0, 0, 0, false)); + expect (Time::fromISO8601 ("20160216Z") == Time (2016, 1, 16, 0, 0, 0, 0, false)); + expect (Time::fromISO8601 ("2016-02-16T15:03:57+00:00") == Time (2016, 1, 16, 15, 3, 57, 0, false)); - expect (Time::fromISO8601 ("20160216T150357+0000") == Time (2016, 1, 16, 15, 3, 57, 0, false)); + expect (Time::fromISO8601 ("20160216T150357+0000") == Time (2016, 1, 16, 15, 3, 57, 0, false)); + expect (Time::fromISO8601 ("2016-02-16T15:03:57.999+00:00") == Time (2016, 1, 16, 15, 3, 57, 999, false)); - expect (Time::fromISO8601 ("20160216T150357.999+0000") == Time (2016, 1, 16, 15, 3, 57, 999, false)); - expect (Time::fromISO8601 ("2016-02-16T15:03:57.999Z") == Time (2016, 1, 16, 15, 3, 57, 999, false)); - expect (Time::fromISO8601 ("20160216T150357.999Z") == Time (2016, 1, 16, 15, 3, 57, 999, false)); + expect (Time::fromISO8601 ("20160216T150357.999+0000") == Time (2016, 1, 16, 15, 3, 57, 999, false)); + expect (Time::fromISO8601 ("2016-02-16T15:03:57.999Z") == Time (2016, 1, 16, 15, 3, 57, 999, false)); + expect (Time::fromISO8601 ("2016-02-16T15:03:57,999Z") == Time (2016, 1, 16, 15, 3, 57, 999, false)); + expect (Time::fromISO8601 ("20160216T150357.999Z") == Time (2016, 1, 16, 15, 3, 57, 999, false)); + expect (Time::fromISO8601 ("20160216T150357,999Z") == Time (2016, 1, 16, 15, 3, 57, 999, false)); + expect (Time::fromISO8601 ("2016-02-16T15:03:57.999-02:30") == Time (2016, 1, 16, 17, 33, 57, 999, false)); - expect (Time::fromISO8601 ("20160216T150357.999-0230") == Time (2016, 1, 16, 17, 33, 57, 999, false)); + expect (Time::fromISO8601 ("2016-02-16T15:03:57,999-02:30") == Time (2016, 1, 16, 17, 33, 57, 999, false)); + expect (Time::fromISO8601 ("20160216T150357.999-0230") == Time (2016, 1, 16, 17, 33, 57, 999, false)); + expect (Time::fromISO8601 ("20160216T150357,999-0230") == Time (2016, 1, 16, 17, 33, 57, 999, false)); expect (Time (1970, 0, 1, 0, 0, 0, 0, false) == Time (0)); expect (Time (2106, 1, 7, 6, 28, 15, 0, false) == Time (4294967295000)); diff --git a/JuceLibraryCode/modules/juce_core/time/juce_Time.h b/JuceLibraryCode/modules/juce_core/time/juce_Time.h index 60ec4ef..5e044f1 100644 --- a/JuceLibraryCode/modules/juce_core/time/juce_Time.h +++ b/JuceLibraryCode/modules/juce_core/time/juce_Time.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_core/unit_tests/juce_UnitTest.cpp b/JuceLibraryCode/modules/juce_core/unit_tests/juce_UnitTest.cpp index 0e78864..f9a858e 100644 --- a/JuceLibraryCode/modules/juce_core/unit_tests/juce_UnitTest.cpp +++ b/JuceLibraryCode/modules/juce_core/unit_tests/juce_UnitTest.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. @@ -199,15 +199,11 @@ void UnitTestRunner::beginNewTest (UnitTest* const test, const String& subCatego endTest(); currentTest = test; - auto* r = new TestResult(); - results.add (r); - r->unitTestName = test->getName(); - r->subcategoryName = subCategory; - r->passes = 0; - r->failures = 0; + auto testName = test->getName(); + results.add (new TestResult (testName, subCategory)); logMessage ("-----------------------------------------------------------------"); - logMessage ("Starting test: " + r->unitTestName + " / " + subCategory + "..."); + logMessage ("Starting test: " + testName + " / " + subCategory + "..."); resultsUpdated(); } @@ -216,6 +212,8 @@ void UnitTestRunner::endTest() { if (auto* r = results.getLast()) { + r->endTime = Time::getCurrentTime(); + if (r->failures > 0) { String m ("FAILED!! "); diff --git a/JuceLibraryCode/modules/juce_core/unit_tests/juce_UnitTest.h b/JuceLibraryCode/modules/juce_core/unit_tests/juce_UnitTest.h index d49e610..bcc1b2b 100644 --- a/JuceLibraryCode/modules/juce_core/unit_tests/juce_UnitTest.h +++ b/JuceLibraryCode/modules/juce_core/unit_tests/juce_UnitTest.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. @@ -376,18 +376,31 @@ class JUCE_API UnitTestRunner */ struct TestResult { + TestResult() = default; + + explicit TestResult (const String& name, const String& subCategory) + : unitTestName (name), + subcategoryName (subCategory) + { + } + /** The main name of this test (i.e. the name of the UnitTest object being run). */ String unitTestName; /** The name of the current subcategory (i.e. the name that was set when UnitTest::beginTest() was called). */ String subcategoryName; /** The number of UnitTest::expect() calls that succeeded. */ - int passes; + int passes = 0; /** The number of UnitTest::expect() calls that failed. */ - int failures; + int failures = 0; /** A list of messages describing the failed tests. */ StringArray messages; + + /** The time at which this test was started. */ + Time startTime = Time::getCurrentTime(); + /** The time at which this test ended. */ + Time endTime; }; /** Returns the number of TestResult objects that have been performed. diff --git a/JuceLibraryCode/modules/juce_core/unit_tests/juce_UnitTestCategories.h b/JuceLibraryCode/modules/juce_core/unit_tests/juce_UnitTestCategories.h new file mode 100644 index 0000000..5a7bcb2 --- /dev/null +++ b/JuceLibraryCode/modules/juce_core/unit_tests/juce_UnitTestCategories.h @@ -0,0 +1,54 @@ +/* + ============================================================================== + + 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 UnitTestCategories +{ + static const String analytics { "Analytics" }; + static const String audio { "Audio" }; + static const String audioProcessorParameters { "AudioProcessorParameters" }; + static const String blocks { "Blocks" }; + static const String compression { "Compression" }; + static const String containers { "Containers" }; + static const String cryptography { "Cryptography" }; + static const String dsp { "DSP" }; + static const String files { "Files" }; + static const String function { "Function" }; + static const String graphics { "Graphics" }; + static const String gui { "GUI" }; + static const String json { "JSON" }; + static const String maths { "Maths" }; + static const String midi { "MIDI" }; + static const String networking { "Networking" }; + static const String osc { "OSC" }; + static const String smoothedValues { "SmoothedValues" }; + static const String streams { "Streams" }; + static const String text { "Text" }; + static const String threads { "Threads" }; + static const String time { "Time" }; + static const String values { "Values" }; + static const String xml { "XML" }; +} + +} // namespace juce diff --git a/JuceLibraryCode/modules/juce_core/xml/juce_XmlDocument.cpp b/JuceLibraryCode/modules/juce_core/xml/juce_XmlDocument.cpp index 23b2ec6..88604c1 100644 --- a/JuceLibraryCode/modules/juce_core/xml/juce_XmlDocument.cpp +++ b/JuceLibraryCode/modules/juce_core/xml/juce_XmlDocument.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,26 +28,34 @@ XmlDocument::XmlDocument (const File& file) : inputSource (new FileInputSource XmlDocument::~XmlDocument() {} -XmlElement* XmlDocument::parse (const File& file) +std::unique_ptr XmlDocument::parse (const File& file) { - XmlDocument doc (file); - return doc.getDocumentElement(); + return XmlDocument (file).getDocumentElement(); } -XmlElement* XmlDocument::parse (const String& xmlData) +std::unique_ptr XmlDocument::parse (const String& textToParse) { - XmlDocument doc (xmlData); - return doc.getDocumentElement(); + return XmlDocument (textToParse).getDocumentElement(); } std::unique_ptr parseXML (const String& textToParse) { - return std::unique_ptr (XmlDocument::parse (textToParse)); + return XmlDocument (textToParse).getDocumentElement(); } -std::unique_ptr parseXML (const File& fileToParse) +std::unique_ptr parseXML (const File& file) { - return std::unique_ptr (XmlDocument::parse (fileToParse)); + return XmlDocument (file).getDocumentElement(); +} + +std::unique_ptr parseXMLIfTagMatches (const String& textToParse, StringRef requiredTag) +{ + return XmlDocument (textToParse).getDocumentElementIfTagMatches (requiredTag); +} + +std::unique_ptr parseXMLIfTagMatches (const File& file, StringRef requiredTag) +{ + return XmlDocument (file).getDocumentElementIfTagMatches (requiredTag); } void XmlDocument::setInputSource (InputSource* newSource) noexcept @@ -72,7 +80,7 @@ namespace XmlIdentifierChars { static const uint32 legalChars[] = { 0, 0x7ff6000, 0x87fffffe, 0x7fffffe, 0 }; - return ((int) c < (int) numElementsInArray (legalChars) * 32) ? ((legalChars [c >> 5] & (1 << (c & 31))) != 0) + return ((int) c < (int) numElementsInArray (legalChars) * 32) ? ((legalChars [c >> 5] & (uint32) (1 << (c & 31))) != 0) : isIdentifierCharSlow (c); } @@ -99,7 +107,7 @@ namespace XmlIdentifierChars } } -XmlElement* XmlDocument::getDocumentElement (const bool onlyReadOuterDocumentElement) +std::unique_ptr XmlDocument::getDocumentElement (const bool onlyReadOuterDocumentElement) { if (originalText.isEmpty() && inputSource != nullptr) { @@ -139,6 +147,15 @@ XmlElement* XmlDocument::getDocumentElement (const bool onlyReadOuterDocumentEle return parseDocumentElement (originalText.getCharPointer(), onlyReadOuterDocumentElement); } +std::unique_ptr XmlDocument::getDocumentElementIfTagMatches (StringRef requiredTag) +{ + if (auto xml = getDocumentElement (true)) + if (xml->hasTagName (requiredTag)) + return getDocumentElement (false); + + return {}; +} + const String& XmlDocument::getLastParseError() const noexcept { return lastError; @@ -176,8 +193,8 @@ juce_wchar XmlDocument::readNextChar() noexcept return c; } -XmlElement* XmlDocument::parseDocumentElement (String::CharPointerType textToParse, - const bool onlyReadOuterDocumentElement) +std::unique_ptr XmlDocument::parseDocumentElement (String::CharPointerType textToParse, + bool onlyReadOuterDocumentElement) { input = textToParse; errorOccurred = false; @@ -202,10 +219,10 @@ XmlElement* XmlDocument::parseDocumentElement (String::CharPointerType textToPar std::unique_ptr result (readNextElement (! onlyReadOuterDocumentElement)); if (! errorOccurred) - return result.release(); + return result; } - return nullptr; + return {}; } bool XmlDocument::parseHeader() diff --git a/JuceLibraryCode/modules/juce_core/xml/juce_XmlDocument.h b/JuceLibraryCode/modules/juce_core/xml/juce_XmlDocument.h index cf71a1d..5088cd3 100644 --- a/JuceLibraryCode/modules/juce_core/xml/juce_XmlDocument.h +++ b/JuceLibraryCode/modules/juce_core/xml/juce_XmlDocument.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,19 +32,16 @@ namespace juce e.g. @code - XmlDocument myDocument (File ("myfile.xml")); - std::unique_ptr mainElement (myDocument.getDocumentElement()); - if (mainElement == nullptr) + if (auto mainElement = myDocument.getDocumentElement()) { - String error = myDocument.getLastParseError(); + ..use the element } else { - ..use the element + String error = myDocument.getLastParseError(); } - @endcode Or you can use the helper functions for much less verbose parsing.. @@ -96,14 +93,18 @@ class JUCE_API XmlDocument allows quick checking of large files to see if they contain the correct type of tag, without having to parse the entire file - @returns a new XmlElement which the caller will need to delete, or null if - there was an error. - @see getLastParseError + @returns a new XmlElement, or nullptr if there was an error. + @see getLastParseError, getDocumentElementIfTagMatches */ - XmlElement* getDocumentElement (bool onlyReadOuterDocumentElement = false); + std::unique_ptr getDocumentElement (bool onlyReadOuterDocumentElement = false); - /** Returns the parsing error that occurred the last time getDocumentElement was called. + /** Does an inexpensive check to see whether the outer element has the given tag name, and + then does a full parse if it matches. + If the tag is different, or the XML parse fails, this will return nullptr. + */ + std::unique_ptr getDocumentElementIfTagMatches (StringRef requiredTag); + /** Returns the parsing error that occurred the last time getDocumentElement was called. @returns the error, or an empty string if there was no error. */ const String& getLastParseError() const noexcept; @@ -134,16 +135,16 @@ class JUCE_API XmlDocument /** A handy static method that parses a file. This is a shortcut for creating an XmlDocument object and calling getDocumentElement() on it. An even better shortcut is the juce::parseXML() function, which returns a std::unique_ptr! - @returns a new XmlElement which the caller will need to delete, or null if there was an error. + @returns a new XmlElement, or nullptr if there was an error. */ - static XmlElement* parse (const File& file); + static std::unique_ptr parse (const File& file); /** A handy static method that parses some XML data. This is a shortcut for creating an XmlDocument object and calling getDocumentElement() on it. An even better shortcut is the juce::parseXML() function, which returns a std::unique_ptr! - @returns a new XmlElement which the caller will need to delete, or null if there was an error. + @returns a new XmlElement, or nullptr if there was an error. */ - static XmlElement* parse (const String& xmlData); + static std::unique_ptr parse (const String& xmlData); //============================================================================== @@ -156,7 +157,7 @@ class JUCE_API XmlDocument bool needToLoadDTD = false, ignoreEmptyTextElements = true; std::unique_ptr inputSource; - XmlElement* parseDocumentElement (String::CharPointerType, bool outer); + std::unique_ptr parseDocumentElement (String::CharPointerType, bool outer); void setLastError (const String&, bool carryOn); bool parseHeader(); bool parseDTD(); @@ -178,18 +179,31 @@ class JUCE_API XmlDocument //============================================================================== /** Attempts to parse some XML text, returning a new XmlElement if it was valid. If the parse fails, this will return a nullptr - if you need more information about - errors or more parsing options, see the XmlDocument instead. - @see XmlDocument + errors or more parsing options, see the XmlDocument class instead. + @see XmlDocument, parseXMLIfTagMatches */ std::unique_ptr parseXML (const String& textToParse); /** Attempts to parse some XML text, returning a new XmlElement if it was valid. If the parse fails, this will return a nullptr - if you need more information about - errors or more parsing options, see the XmlDocument instead. - @see XmlDocument + errors or more parsing options, see the XmlDocument class instead. + @see XmlDocument, parseXMLIfTagMatches */ std::unique_ptr parseXML (const File& fileToParse); +/** Does an inexpensive check to see whether the top-level element has the given tag + name, and if that's true, does a full parse and returns the result. + If the outer tag doesn't match, or the XML has errors, this will return nullptr; + @see parseXML +*/ +std::unique_ptr parseXMLIfTagMatches (const String& textToParse, StringRef requiredTag); + +/** Does an inexpensive check to see whether the top-level element has the given tag + name, and if that's true, does a full parse and returns the result. + If the outer tag doesn't match, or the XML has errors, this will return nullptr; + @see parseXML +*/ +std::unique_ptr parseXMLIfTagMatches (const File& fileToParse, StringRef requiredTag); } // namespace juce diff --git a/JuceLibraryCode/modules/juce_core/xml/juce_XmlElement.cpp b/JuceLibraryCode/modules/juce_core/xml/juce_XmlElement.cpp index 76b3afc..733c7ab 100644 --- a/JuceLibraryCode/modules/juce_core/xml/juce_XmlElement.cpp +++ b/JuceLibraryCode/modules/juce_core/xml/juce_XmlElement.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,7 @@ namespace juce { -inline static bool isValidXmlNameStartCharacter (juce_wchar character) noexcept +static bool isValidXmlNameStartCharacter (juce_wchar character) noexcept { return character == ':' || character == '_' @@ -43,7 +43,7 @@ inline static bool isValidXmlNameStartCharacter (juce_wchar character) noexcept || (character >= 0x10000 && character <= 0xeffff); } -inline static bool isValidXmlNameBodyCharacter (juce_wchar character) noexcept +static bool isValidXmlNameBodyCharacter (juce_wchar character) noexcept { return isValidXmlNameStartCharacter (character) || character == '-' @@ -167,50 +167,46 @@ XmlElement::~XmlElement() noexcept //============================================================================== namespace XmlOutputFunctions { - #if 0 // (These functions are just used to generate the lookup table used below) - bool isLegalXmlCharSlow (const juce_wchar character) noexcept + namespace LegalCharLookupTable { - if ((character >= 'a' && character <= 'z') - || (character >= 'A' && character <= 'Z') - || (character >= '0' && character <= '9')) - return true; - - const char* t = " .,;:-()_+=?!'#@[]/\\*%~{}$|"; - - do + template + struct Bit { - if (((juce_wchar) (uint8) *t) == character) - return true; - } - while (*++t != 0); - - return false; - } - - void generateLegalCharLookupTable() - { - uint8 n[32] = { 0 }; - for (int i = 0; i < 256; ++i) - if (isLegalXmlCharSlow (i)) - n[i >> 3] |= (1 << (i & 7)); - - String s; - for (int i = 0; i < 32; ++i) - s << (int) n[i] << ", "; + enum { v = ((c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9') + || c == ' ' || c == '.' || c == ',' || c == ';' + || c == ':' || c == '-' || c == '(' || c == ')' + || c == '_' || c == '+' || c == '=' || c == '?' + || c == '!' || c == '$' || c == '#' || c == '@' + || c == '[' || c == ']' || c == '/' || c == '|' + || c == '*' || c == '%' || c == '~' || c == '{' + || c == '}' || c == '\'' || c == '\\') + ? (1 << (c & 7)) : 0 }; + }; + + template + struct Byte + { + enum { v = (int) Bit::v | (int) Bit::v + | (int) Bit::v | (int) Bit::v + | (int) Bit::v | (int) Bit::v + | (int) Bit::v | (int) Bit::v }; + }; - DBG (s); - } - #endif + static bool isLegal (uint32 c) noexcept + { + static const unsigned char legalChars[] = { Byte< 0>::v, Byte< 1>::v, Byte< 2>::v, Byte< 3>::v, + Byte< 4>::v, Byte< 5>::v, Byte< 6>::v, Byte< 7>::v, + Byte< 8>::v, Byte< 9>::v, Byte<10>::v, Byte<11>::v, + Byte<12>::v, Byte<13>::v, Byte<14>::v, Byte<15>::v }; - static bool isLegalXmlChar (const uint32 c) noexcept - { - static const unsigned char legalChars[] = { 0, 0, 0, 0, 187, 255, 255, 175, 255, - 255, 255, 191, 254, 255, 255, 127 }; - return c < sizeof (legalChars) * 8 - && (legalChars [c >> 3] & (1 << (c & 7))) != 0; + return c < sizeof (legalChars) * 8 + && (legalChars[c >> 3] & (1 << (c & 7))) != 0; + } } - static void escapeIllegalXmlChars (OutputStream& outputStream, const String& text, const bool changeNewLines) + static void escapeIllegalXmlChars (OutputStream& outputStream, const String& text, bool changeNewLines) { auto t = text.getCharPointer(); @@ -221,7 +217,7 @@ namespace XmlOutputFunctions if (character == 0) break; - if (isLegalXmlChar (character)) + if (LegalCharLookupTable::isLegal (character)) { outputStream << (char) character; } @@ -241,7 +237,7 @@ namespace XmlOutputFunctions outputStream << (char) character; break; } - // Note: Deliberate fall-through here! + JUCE_FALLTHROUGH default: outputStream << "&#" << ((int) character) << ';'; break; @@ -257,13 +253,12 @@ namespace XmlOutputFunctions } void XmlElement::writeElementAsText (OutputStream& outputStream, - const int indentationLevel, - const int lineWrapLength) const + int indentationLevel, + int lineWrapLength, + const char* newLineChars) const { - using namespace XmlOutputFunctions; - if (indentationLevel >= 0) - writeSpaces (outputStream, (size_t) indentationLevel); + XmlOutputFunctions::writeSpaces (outputStream, (size_t) indentationLevel); if (! isTextElement()) { @@ -278,8 +273,8 @@ void XmlElement::writeElementAsText (OutputStream& outputStream, { if (lineLen > lineWrapLength && indentationLevel >= 0) { - outputStream << newLine; - writeSpaces (outputStream, attIndent); + outputStream << newLineChars; + XmlOutputFunctions::writeSpaces (outputStream, attIndent); lineLen = 0; } @@ -287,7 +282,7 @@ void XmlElement::writeElementAsText (OutputStream& outputStream, outputStream.writeByte (' '); outputStream << att->name; outputStream.write ("=\"", 2); - escapeIllegalXmlChars (outputStream, att->value, true); + XmlOutputFunctions::escapeIllegalXmlChars (outputStream, att->value, true); outputStream.writeByte ('"'); lineLen += (int) (outputStream.getPosition() - startPos); } @@ -302,24 +297,25 @@ void XmlElement::writeElementAsText (OutputStream& outputStream, { if (child->isTextElement()) { - escapeIllegalXmlChars (outputStream, child->getText(), false); + XmlOutputFunctions::escapeIllegalXmlChars (outputStream, child->getText(), false); lastWasTextNode = true; } else { if (indentationLevel >= 0 && ! lastWasTextNode) - outputStream << newLine; + outputStream << newLineChars; child->writeElementAsText (outputStream, - lastWasTextNode ? 0 : (indentationLevel + (indentationLevel >= 0 ? 2 : 0)), lineWrapLength); + lastWasTextNode ? 0 : (indentationLevel + (indentationLevel >= 0 ? 2 : 0)), lineWrapLength, + newLineChars); lastWasTextNode = false; } } if (indentationLevel >= 0 && ! lastWasTextNode) { - outputStream << newLine; - writeSpaces (outputStream, (size_t) indentationLevel); + outputStream << newLineChars; + XmlOutputFunctions::writeSpaces (outputStream, (size_t) indentationLevel); } outputStream.write (""; + output << ""; + + if (options.newLineChars == nullptr) output.writeByte (' '); else - output << newLine << newLine; + output << options.newLineChars + << options.newLineChars; } - if (dtdToUse.isNotEmpty()) + if (options.dtd.isNotEmpty()) { - output << dtdToUse; + output << options.dtd; - if (allOnOneLine) + if (options.newLineChars == nullptr) output.writeByte (' '); else - output << newLine; + output << options.newLineChars; } - writeElementAsText (output, allOnOneLine ? -1 : 0, lineWrapLength); + writeElementAsText (output, options.newLineChars == nullptr ? -1 : 0, + options.lineWrapLength, + options.newLineChars); - if (! allOnOneLine) - output << newLine; + if (options.newLineChars != nullptr) + output << options.newLineChars; } -bool XmlElement::writeToFile (const File& file, StringRef dtdToUse, - StringRef encodingType, int lineWrapLength) const +bool XmlElement::writeTo (const File& destinationFile, const TextFormat& options) const { - TemporaryFile tempFile (file); + TemporaryFile tempFile (destinationFile); { FileOutputStream out (tempFile.getFile()); @@ -392,7 +414,7 @@ bool XmlElement::writeToFile (const File& file, StringRef dtdToUse, if (! out.openedOk()) return false; - writeToStream (out, dtdToUse, false, true, encodingType, lineWrapLength); + writeTo (out, options); out.flush(); // (called explicitly to force an fsync on posix) if (out.getStatus().failed()) @@ -402,6 +424,48 @@ bool XmlElement::writeToFile (const File& file, StringRef dtdToUse, return tempFile.overwriteTargetFileWithTemporary(); } +String XmlElement::createDocument (StringRef dtdToUse, bool allOnOneLine, bool includeXmlHeader, + StringRef encodingType, int lineWrapLength) const +{ + TextFormat options; + options.dtd = dtdToUse; + options.customEncoding = encodingType; + options.addDefaultHeader = includeXmlHeader; + options.lineWrapLength = lineWrapLength; + + if (allOnOneLine) + options.newLineChars = nullptr; + + return toString (options); +} + +void XmlElement::writeToStream (OutputStream& output, StringRef dtdToUse, + bool allOnOneLine, bool includeXmlHeader, + StringRef encodingType, int lineWrapLength) const +{ + TextFormat options; + options.dtd = dtdToUse; + options.customEncoding = encodingType; + options.addDefaultHeader = includeXmlHeader; + options.lineWrapLength = lineWrapLength; + + if (allOnOneLine) + options.newLineChars = nullptr; + + writeTo (output, options); +} + +bool XmlElement::writeToFile (const File& file, StringRef dtdToUse, + StringRef encodingType, int lineWrapLength) const +{ + TextFormat options; + options.dtd = dtdToUse; + options.customEncoding = encodingType; + options.lineWrapLength = lineWrapLength; + + return writeTo (file, options); +} + //============================================================================== bool XmlElement::hasTagName (StringRef possibleTagName) const noexcept { @@ -580,8 +644,7 @@ void XmlElement::setAttribute (const Identifier& attributeName, const int number void XmlElement::setAttribute (const Identifier& attributeName, const double number) { - String doubleString (number, 15, true); - setAttribute (attributeName, minimiseLengthOfFloatString (doubleString)); + setAttribute (attributeName, serialiseDouble (number)); } void XmlElement::removeAttribute (const Identifier& attributeName) noexcept @@ -609,7 +672,7 @@ int XmlElement::getNumChildElements() const noexcept XmlElement* XmlElement::getChildElement (const int index) const noexcept { - return firstChildElement [index].get(); + return firstChildElement[index].get(); } XmlElement* XmlElement::getChildByName (StringRef childName) const noexcept @@ -926,13 +989,16 @@ void XmlElement::deleteAllTextElements() noexcept } } +//============================================================================== //============================================================================== #if JUCE_UNIT_TESTS class XmlElementTests : public UnitTest { public: - XmlElementTests() : UnitTest ("XmlElement", "XML") {} + XmlElementTests() + : UnitTest ("XmlElement", UnitTestCategories::xml) + {} void runTest() override { @@ -943,15 +1009,20 @@ class XmlElementTests : public UnitTest Identifier number ("number"); std::map tests; - tests[1] = "1"; + tests[1] = "1.0"; tests[1.1] = "1.1"; tests[1.01] = "1.01"; - tests[0.76378] = "7.6378e-1"; - tests[-10] = "-1e1"; - tests[10.01] = "1.001e1"; - tests[0.0123] = "1.23e-2"; + tests[0.76378] = "0.76378"; + tests[-10] = "-10.0"; + tests[10.01] = "10.01"; + tests[0.0123] = "0.0123"; tests[-3.7e-27] = "-3.7e-27"; - tests[1e+40] = "1e40"; + tests[1e+40] = "1.0e40"; + tests[-12345678901234567.0] = "-1.234567890123457e16"; + tests[192000] = "192000.0"; + tests[1234567] = "1.234567e6"; + tests[0.00006] = "0.00006"; + tests[0.000006] = "6.0e-6"; for (auto& test : tests) { diff --git a/JuceLibraryCode/modules/juce_core/xml/juce_XmlElement.h b/JuceLibraryCode/modules/juce_core/xml/juce_XmlElement.h index fc8cf3e..496c9aa 100644 --- a/JuceLibraryCode/modules/juce_core/xml/juce_XmlElement.h +++ b/JuceLibraryCode/modules/juce_core/xml/juce_XmlElement.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. @@ -126,11 +126,11 @@ namespace juce animalsList.addChildElement (giraffe); } - // now we can turn the whole thing into a text document.. - String myXmlDoc = animalsList.createDocument (String()); + // now we can turn the whole thing into textual XML + auto xmlString = animalsList.toString(); @endcode - @see XmlDocument + @see parseXML, parseXMLIfTagMatches, XmlDocument @tags{Core} */ @@ -184,74 +184,41 @@ class JUCE_API XmlElement bool ignoreOrderOfAttributes) const noexcept; //============================================================================== - /** Returns an XML text document that represents this element. - - The string returned can be parsed to recreate the same XmlElement that - was used to create it. - - @param dtdToUse the DTD to add to the document - @param allOnOneLine if true, this means that the document will not contain any - linefeeds, so it'll be smaller but not very easy to read. - @param includeXmlHeader whether to add the "::Appender; friend class NamedValueSet; - LinkedListPointer nextListItem; - LinkedListPointer firstChildElement; + LinkedListPointer nextListItem, firstChildElement; LinkedListPointer attributes; String tagName; XmlElement (int) noexcept; void copyChildrenAndAttributesFrom (const XmlElement&); - void writeElementAsText (OutputStream&, int indentationLevel, int lineWrapLength) const; + void writeElementAsText (OutputStream&, int, int, const char*) const; void getChildElementsAsArray (XmlElement**) const noexcept; void reorderChildElements (XmlElement**, int) noexcept; XmlAttributeNode* getAttribute (StringRef) const noexcept; diff --git a/JuceLibraryCode/modules/juce_core/zip/juce_GZIPCompressorOutputStream.cpp b/JuceLibraryCode/modules/juce_core/zip/juce_GZIPCompressorOutputStream.cpp index 5a87706..b1f56a8 100644 --- a/JuceLibraryCode/modules/juce_core/zip/juce_GZIPCompressorOutputStream.cpp +++ b/JuceLibraryCode/modules/juce_core/zip/juce_GZIPCompressorOutputStream.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. @@ -92,7 +92,7 @@ class GZIPCompressorOutputStream::GZIPCompressorHelper { case Z_STREAM_END: finished = true; - // Deliberate fall-through.. + JUCE_FALLTHROUGH case Z_OK: { data += dataSize - stream.avail_in; @@ -154,12 +154,16 @@ bool GZIPCompressorOutputStream::setPosition (int64 /*newPosition*/) return false; } + +//============================================================================== //============================================================================== #if JUCE_UNIT_TESTS struct GZIPTests : public UnitTest { - GZIPTests() : UnitTest ("GZIP", "Compression") {} + GZIPTests() + : UnitTest ("GZIP", UnitTestCategories::compression) + {} void runTest() override { diff --git a/JuceLibraryCode/modules/juce_core/zip/juce_GZIPCompressorOutputStream.h b/JuceLibraryCode/modules/juce_core/zip/juce_GZIPCompressorOutputStream.h index 297b258..1a2d503 100644 --- a/JuceLibraryCode/modules/juce_core/zip/juce_GZIPCompressorOutputStream.h +++ b/JuceLibraryCode/modules/juce_core/zip/juce_GZIPCompressorOutputStream.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_core/zip/juce_GZIPDecompressorInputStream.cpp b/JuceLibraryCode/modules/juce_core/zip/juce_GZIPDecompressorInputStream.cpp index 51fe005..19cf6a6 100644 --- a/JuceLibraryCode/modules/juce_core/zip/juce_GZIPDecompressorInputStream.cpp +++ b/JuceLibraryCode/modules/juce_core/zip/juce_GZIPDecompressorInputStream.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,26 +23,21 @@ namespace juce { -#if JUCE_MSVC - #pragma warning (push) - #pragma warning (disable: 4309 4305 4365) -#endif +JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4309 4305 4365) namespace zlibNamespace { #if JUCE_INCLUDE_ZLIB_CODE - #if JUCE_CLANG - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wconversion" - #pragma clang diagnostic ignored "-Wshadow" - #pragma clang diagnostic ignored "-Wdeprecated-register" - #if __has_warning("-Wzero-as-null-pointer-constant") - #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" - #endif - #if __has_warning("-Wcomma") - #pragma clang diagnostic ignored "-Wcomma" - #endif - #endif + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wconversion", + "-Wsign-conversion", + "-Wshadow", + "-Wdeprecated-register", + "-Wswitch-enum", + "-Wswitch-default", + "-Wredundant-decls", + "-Wimplicit-fallthrough", + "-Wzero-as-null-pointer-constant", + "-Wcomma") #undef OS_CODE #undef fdopen @@ -75,9 +70,7 @@ namespace zlibNamespace #undef Dad #undef Len - #if JUCE_CLANG - #pragma clang diagnostic pop - #endif + JUCE_END_IGNORE_WARNINGS_GCC_LIKE #else #include JUCE_ZLIB_INCLUDE_PATH @@ -92,9 +85,7 @@ namespace zlibNamespace #endif } -#if JUCE_MSVC - #pragma warning (pop) -#endif +JUCE_END_IGNORE_WARNINGS_MSVC //============================================================================== // internal helper object that holds the zlib structures so they don't have to be @@ -139,7 +130,7 @@ class GZIPDecompressorInputStream::GZIPDecompressHelper { case Z_STREAM_END: finished = true; - // deliberate fall-through + JUCE_FALLTHROUGH case Z_OK: data += dataSize - stream.avail_in; dataSize = (z_uInt) stream.avail_in; @@ -154,7 +145,7 @@ class GZIPDecompressorInputStream::GZIPDecompressHelper case Z_DATA_ERROR: case Z_MEM_ERROR: error = true; - + JUCE_FALLTHROUGH default: break; } @@ -298,13 +289,15 @@ bool GZIPDecompressorInputStream::setPosition (int64 newPos) return true; } + +//============================================================================== //============================================================================== #if JUCE_UNIT_TESTS struct GZIPDecompressorInputStreamTests : public UnitTest { GZIPDecompressorInputStreamTests() - : UnitTest ("GZIPDecompressorInputStreamTests", "Streams") + : UnitTest ("GZIPDecompressorInputStreamTests", UnitTestCategories::streams) {} void runTest() override diff --git a/JuceLibraryCode/modules/juce_core/zip/juce_GZIPDecompressorInputStream.h b/JuceLibraryCode/modules/juce_core/zip/juce_GZIPDecompressorInputStream.h index cc4cfe8..00948e8 100644 --- a/JuceLibraryCode/modules/juce_core/zip/juce_GZIPDecompressorInputStream.h +++ b/JuceLibraryCode/modules/juce_core/zip/juce_GZIPDecompressorInputStream.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_core/zip/juce_ZipFile.cpp b/JuceLibraryCode/modules/juce_core/zip/juce_ZipFile.cpp index 967956c..03fd7c5 100644 --- a/JuceLibraryCode/modules/juce_core/zip/juce_ZipFile.cpp +++ b/JuceLibraryCode/modules/juce_core/zip/juce_ZipFile.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,21 +46,21 @@ struct ZipFile::ZipEntryHolder entry.uncompressedSize = (int64) readUnalignedLittleEndianInt (buffer + 24); streamOffset = (int64) readUnalignedLittleEndianInt (buffer + 42); - auto externalFileAttributes = (int32) readUnalignedLittleEndianInt (buffer + 38); - auto fileType = (externalFileAttributes >> 28) & 0xf; - + entry.externalFileAttributes = readUnalignedLittleEndianInt (buffer + 38); + auto fileType = (entry.externalFileAttributes >> 28) & 0xf; entry.isSymbolicLink = (fileType == 0xA); + entry.filename = String::fromUTF8 (buffer + 46, fileNameLen); } static Time parseFileTime (uint32 time, uint32 date) noexcept { - int year = 1980 + (date >> 9); - int month = ((date >> 5) & 15) - 1; - int day = date & 31; - int hours = time >> 11; - int minutes = (time >> 5) & 63; - int seconds = (int) ((time & 31) << 1); + auto year = (int) (1980 + (date >> 9)); + auto month = (int) (((date >> 5) & 15) - 1); + auto day = (int) (date & 31); + auto hours = (int) time >> 11; + auto minutes = (int) ((time >> 5) & 63); + auto seconds = (int) ((time & 31) << 1); return { year, month, day, hours, minutes, seconds }; } @@ -369,16 +369,16 @@ void ZipFile::init() break; auto* buffer = static_cast (headerData.getData()) + pos; - auto fileNameLen = readUnalignedLittleEndianShort (buffer + 28); + auto fileNameLen = readUnalignedLittleEndianShort (buffer + 28u); if (pos + 46 + fileNameLen > size) break; entries.add (new ZipEntryHolder (buffer, fileNameLen)); - pos += 46 + fileNameLen - + readUnalignedLittleEndianShort (buffer + 30) - + readUnalignedLittleEndianShort (buffer + 32); + pos += 46u + fileNameLen + + readUnalignedLittleEndianShort (buffer + 30u) + + readUnalignedLittleEndianShort (buffer + 32u); } } } @@ -541,7 +541,7 @@ struct ZipFile::Builder::Item { if (stream == nullptr) { - stream.reset (file.createInputStream()); + stream = file.createInputStream(); if (stream == nullptr) return false; @@ -577,7 +577,7 @@ struct ZipFile::Builder::Item target.writeInt ((int) checksum); target.writeInt ((int) (uint32) compressedSize); target.writeInt ((int) (uint32) uncompressedSize); - target.writeShort ((short) storedPathname.toUTF8().sizeInBytes() - 1); + target.writeShort (static_cast (storedPathname.toUTF8().sizeInBytes() - 1)); target.writeShort (0); // extra field length } @@ -638,12 +638,16 @@ bool ZipFile::Builder::writeToStream (OutputStream& target, double* const progre return true; } + +//============================================================================== //============================================================================== #if JUCE_UNIT_TESTS struct ZIPTests : public UnitTest { - ZIPTests() : UnitTest ("ZIP") {} + ZIPTests() + : UnitTest ("ZIP", UnitTestCategories::compression) + {} void runTest() override { diff --git a/JuceLibraryCode/modules/juce_core/zip/juce_ZipFile.h b/JuceLibraryCode/modules/juce_core/zip/juce_ZipFile.h index 3e11696..a022d32 100644 --- a/JuceLibraryCode/modules/juce_core/zip/juce_ZipFile.h +++ b/JuceLibraryCode/modules/juce_core/zip/juce_ZipFile.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. @@ -82,6 +82,12 @@ class JUCE_API ZipFile /** True if the zip entry is a symbolic link. */ bool isSymbolicLink; + + /** Platform specific data. Depending on how the zip file was created this + may contain macOS and Linux file types, permissions and + setuid/setgid/sticky bits. + */ + uint32 externalFileAttributes; }; //============================================================================== diff --git a/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_ApplicationProperties.cpp b/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_ApplicationProperties.cpp index fb5e813..b39fee9 100644 --- a/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_ApplicationProperties.cpp +++ b/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_ApplicationProperties.cpp @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). diff --git a/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_ApplicationProperties.h b/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_ApplicationProperties.h index 36ac2b0..a55ffac 100644 --- a/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_ApplicationProperties.h +++ b/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_ApplicationProperties.h @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). diff --git a/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp b/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp index 30989fb..bd6b147 100644 --- a/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp +++ b/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -29,13 +28,13 @@ namespace juce namespace PropertyFileConstants { - JUCE_CONSTEXPR static const int magicNumber = (int) ByteOrder::makeInt ('P', 'R', 'O', 'P'); - JUCE_CONSTEXPR static const int magicNumberCompressed = (int) ByteOrder::makeInt ('C', 'P', 'R', 'P'); + constexpr static const int magicNumber = (int) ByteOrder::makeInt ('P', 'R', 'O', 'P'); + constexpr static const int magicNumberCompressed = (int) ByteOrder::makeInt ('C', 'P', 'R', 'P'); - JUCE_CONSTEXPR static const char* const fileTag = "PROPERTIES"; - JUCE_CONSTEXPR static const char* const valueTag = "VALUE"; - JUCE_CONSTEXPR static const char* const nameAttribute = "name"; - JUCE_CONSTEXPR static const char* const valueAttribute = "val"; + constexpr static const char* const fileTag = "PROPERTIES"; + constexpr static const char* const valueTag = "VALUE"; + constexpr static const char* const nameAttribute = "name"; + constexpr static const char* const valueAttribute = "val"; } //============================================================================== @@ -186,33 +185,20 @@ bool PropertiesFile::save() bool PropertiesFile::loadAsXml() { - XmlDocument parser (file); - std::unique_ptr doc (parser.getDocumentElement (true)); - - if (doc != nullptr && doc->hasTagName (PropertyFileConstants::fileTag)) + if (auto doc = parseXMLIfTagMatches (file, PropertyFileConstants::fileTag)) { - doc.reset (parser.getDocumentElement()); - - if (doc != nullptr) + forEachXmlChildElementWithTagName (*doc, e, PropertyFileConstants::valueTag) { - forEachXmlChildElementWithTagName (*doc, e, PropertyFileConstants::valueTag) - { - auto name = e->getStringAttribute (PropertyFileConstants::nameAttribute); - - if (name.isNotEmpty()) - getAllProperties().set (name, - e->getFirstChildElement() != nullptr - ? e->getFirstChildElement()->createDocument ("", true) - : e->getStringAttribute (PropertyFileConstants::valueAttribute)); - } - - return true; + auto name = e->getStringAttribute (PropertyFileConstants::nameAttribute); + + if (name.isNotEmpty()) + getAllProperties().set (name, + e->getFirstChildElement() != nullptr + ? e->getFirstChildElement()->toString (XmlElement::TextFormat().singleLine().withoutHeader()) + : e->getStringAttribute (PropertyFileConstants::valueAttribute)); } - // must be a pretty broken XML file we're trying to parse here, - // or a sign that this object needs an InterProcessLock, - // or just a failure reading the file. This last reason is why - // we don't jassertfalse here. + return true; } return false; @@ -229,8 +215,8 @@ bool PropertiesFile::saveAsXml() e->setAttribute (PropertyFileConstants::nameAttribute, props.getAllKeys() [i]); // if the value seems to contain xml, store it as such.. - if (auto* childElement = XmlDocument::parse (props.getAllValues() [i])) - e->addChildElement (childElement); + if (auto childElement = parseXML (props.getAllValues() [i])) + e->addChildElement (childElement.release()); else e->setAttribute (PropertyFileConstants::valueAttribute, props.getAllValues() [i]); } @@ -240,7 +226,7 @@ bool PropertiesFile::saveAsXml() if (pl != nullptr && ! pl->isLocked()) return false; // locking failure.. - if (doc.writeToFile (file, {})) + if (doc.writeTo (file, {})) { needsWriting = false; return true; diff --git a/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_PropertiesFile.h b/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_PropertiesFile.h index f4704f4..f42269d 100644 --- a/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_PropertiesFile.h +++ b/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_PropertiesFile.h @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). diff --git a/JuceLibraryCode/modules/juce_data_structures/juce_data_structures.cpp b/JuceLibraryCode/modules/juce_data_structures/juce_data_structures.cpp index 9620795..78a3da6 100644 --- a/JuceLibraryCode/modules/juce_data_structures/juce_data_structures.cpp +++ b/JuceLibraryCode/modules/juce_data_structures/juce_data_structures.cpp @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). diff --git a/JuceLibraryCode/modules/juce_data_structures/juce_data_structures.h b/JuceLibraryCode/modules/juce_data_structures/juce_data_structures.h index 41c7f27..4266b34 100644 --- a/JuceLibraryCode/modules/juce_data_structures/juce_data_structures.h +++ b/JuceLibraryCode/modules/juce_data_structures/juce_data_structures.h @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -24,24 +23,25 @@ ============================================================================== */ + /******************************************************************************* 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_data_structures - vendor: juce - version: 5.4.3 - name: JUCE data model helper classes - description: Classes for undo/redo management, and smart data structures. - website: http://www.juce.com/juce - license: GPL/Commercial + ID: juce_data_structures + vendor: juce + version: 6.0.1 + name: JUCE data model helper classes + description: Classes for undo/redo management, and smart data structures. + website: http://www.juce.com/juce + license: GPL/Commercial - dependencies: juce_events + dependencies: juce_events END_JUCE_MODULE_DECLARATION diff --git a/JuceLibraryCode/modules/juce_data_structures/juce_data_structures.mm b/JuceLibraryCode/modules/juce_data_structures/juce_data_structures.mm index 1f5d94a..2e6c117 100644 --- a/JuceLibraryCode/modules/juce_data_structures/juce_data_structures.mm +++ b/JuceLibraryCode/modules/juce_data_structures/juce_data_structures.mm @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). diff --git a/JuceLibraryCode/modules/juce_data_structures/undomanager/juce_UndoManager.cpp b/JuceLibraryCode/modules/juce_data_structures/undomanager/juce_UndoManager.cpp index 4609fca..d9f8603 100644 --- a/JuceLibraryCode/modules/juce_data_structures/undomanager/juce_UndoManager.cpp +++ b/JuceLibraryCode/modules/juce_data_structures/undomanager/juce_UndoManager.cpp @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -146,7 +145,7 @@ bool UndoManager::perform (UndoableAction* newAction) } totalUnitsStored += action->getSizeInUnits(); - actionSet->actions.add (action.release()); + actionSet->actions.add (std::move (action)); newTransaction = false; moveFutureTransactionsToStash(); diff --git a/JuceLibraryCode/modules/juce_data_structures/undomanager/juce_UndoManager.h b/JuceLibraryCode/modules/juce_data_structures/undomanager/juce_UndoManager.h index d86b969..d277fa7 100644 --- a/JuceLibraryCode/modules/juce_data_structures/undomanager/juce_UndoManager.h +++ b/JuceLibraryCode/modules/juce_data_structures/undomanager/juce_UndoManager.h @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). diff --git a/JuceLibraryCode/modules/juce_data_structures/undomanager/juce_UndoableAction.h b/JuceLibraryCode/modules/juce_data_structures/undomanager/juce_UndoableAction.h index b9e2170..46e133e 100644 --- a/JuceLibraryCode/modules/juce_data_structures/undomanager/juce_UndoableAction.h +++ b/JuceLibraryCode/modules/juce_data_structures/undomanager/juce_UndoableAction.h @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). diff --git a/JuceLibraryCode/modules/juce_data_structures/values/juce_CachedValue.cpp b/JuceLibraryCode/modules/juce_data_structures/values/juce_CachedValue.cpp index dd307eb..2588732 100644 --- a/JuceLibraryCode/modules/juce_data_structures/values/juce_CachedValue.cpp +++ b/JuceLibraryCode/modules/juce_data_structures/values/juce_CachedValue.cpp @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -32,7 +31,9 @@ namespace juce class CachedValueTests : public UnitTest { public: - CachedValueTests() : UnitTest ("CachedValues", "Values") {} + CachedValueTests() + : UnitTest ("CachedValues", UnitTestCategories::values) + {} void runTest() override { diff --git a/JuceLibraryCode/modules/juce_data_structures/values/juce_CachedValue.h b/JuceLibraryCode/modules/juce_data_structures/values/juce_CachedValue.h index 8b1886c..8aba0bf 100644 --- a/JuceLibraryCode/modules/juce_data_structures/values/juce_CachedValue.h +++ b/JuceLibraryCode/modules/juce_data_structures/values/juce_CachedValue.h @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -197,10 +196,6 @@ class CachedValue : private ValueTree::Listener Type getTypedValue() const; void valueTreePropertyChanged (ValueTree& changedTree, const Identifier& changedProperty) override; - void valueTreeChildAdded (ValueTree&, ValueTree&) override {} - void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override {} - void valueTreeChildOrderChanged (ValueTree&, int, int) override {} - void valueTreeParentChanged (ValueTree&) override {} //============================================================================== JUCE_DECLARE_WEAK_REFERENCEABLE (CachedValue) diff --git a/JuceLibraryCode/modules/juce_data_structures/values/juce_Value.cpp b/JuceLibraryCode/modules/juce_data_structures/values/juce_Value.cpp index 3c99cc2..4fd6c56 100644 --- a/JuceLibraryCode/modules/juce_data_structures/values/juce_Value.cpp +++ b/JuceLibraryCode/modules/juce_data_structures/values/juce_Value.cpp @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). diff --git a/JuceLibraryCode/modules/juce_data_structures/values/juce_Value.h b/JuceLibraryCode/modules/juce_data_structures/values/juce_Value.h index ca62e21..1f4edbf 100644 --- a/JuceLibraryCode/modules/juce_data_structures/values/juce_Value.h +++ b/JuceLibraryCode/modules/juce_data_structures/values/juce_Value.h @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). diff --git a/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueTree.cpp b/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueTree.cpp index 3750294..d43eecb 100644 --- a/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueTree.cpp +++ b/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueTree.cpp @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -992,9 +991,9 @@ void ValueTree::sendPropertyChangeMessage (const Identifier& property) } //============================================================================== -XmlElement* ValueTree::createXml() const +std::unique_ptr ValueTree::createXml() const { - return object != nullptr ? object->createXml() : nullptr; + return std::unique_ptr (object != nullptr ? object->createXml() : nullptr); } ValueTree ValueTree::fromXml (const XmlElement& xml) @@ -1015,12 +1014,18 @@ ValueTree ValueTree::fromXml (const XmlElement& xml) return {}; } -String ValueTree::toXmlString() const +ValueTree ValueTree::fromXml (const String& xmlText) { - std::unique_ptr xml (createXml()); + if (auto xml = parseXML (xmlText)) + return fromXml (*xml); - if (xml != nullptr) - return xml->createDocument ({}); + return {}; +} + +String ValueTree::toXmlString (const XmlElement::TextFormat& format) const +{ + if (auto xml = createXml()) + return xml->toString (format); return {}; } @@ -1088,15 +1093,24 @@ ValueTree ValueTree::readFromGZIPData (const void* data, size_t numBytes) return readFromStream (gzipStream); } -void ValueTree::Listener::valueTreeRedirected (ValueTree&) {} +void ValueTree::Listener::valueTreePropertyChanged (ValueTree&, const Identifier&) {} +void ValueTree::Listener::valueTreeChildAdded (ValueTree&, ValueTree&) {} +void ValueTree::Listener::valueTreeChildRemoved (ValueTree&, ValueTree&, int) {} +void ValueTree::Listener::valueTreeChildOrderChanged (ValueTree&, int, int) {} +void ValueTree::Listener::valueTreeParentChanged (ValueTree&) {} +void ValueTree::Listener::valueTreeRedirected (ValueTree&) {} + +//============================================================================== //============================================================================== #if JUCE_UNIT_TESTS class ValueTreeTests : public UnitTest { public: - ValueTreeTests() : UnitTest ("ValueTrees", "Values") {} + ValueTreeTests() + : UnitTest ("ValueTrees", UnitTestCategories::values) + {} static String createRandomIdentifier (Random& r) { @@ -1179,8 +1193,8 @@ class ValueTreeTests : public UnitTest } expect (v1.isEquivalentTo (ValueTree::readFromGZIPData (zipped.getData(), zipped.getDataSize()))); - std::unique_ptr xml1 (v1.createXml()); - std::unique_ptr xml2 (v2.createCopy().createXml()); + auto xml1 = v1.createXml(); + auto xml2 = v2.createCopy().createXml(); expect (xml1->isEquivalentTo (xml2.get(), false)); auto v4 = v2.createCopy(); @@ -1195,15 +1209,20 @@ class ValueTreeTests : public UnitTest Identifier number ("number"); std::map tests; - tests[1] = "1"; + tests[1] = "1.0"; tests[1.1] = "1.1"; tests[1.01] = "1.01"; - tests[0.76378] = "7.6378e-1"; - tests[-10] = "-1e1"; - tests[10.01] = "1.001e1"; - tests[0.0123] = "1.23e-2"; + tests[0.76378] = "0.76378"; + tests[-10] = "-10.0"; + tests[10.01] = "10.01"; + tests[0.0123] = "0.0123"; tests[-3.7e-27] = "-3.7e-27"; - tests[1e+40] = "1e40"; + tests[1e+40] = "1.0e40"; + tests[-12345678901234567.0] = "-1.234567890123457e16"; + tests[192000] = "192000.0"; + tests[1234567] = "1.234567e6"; + tests[0.00006] = "0.00006"; + tests[0.000006] = "6.0e-6"; for (auto& test : tests) { diff --git a/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueTree.h b/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueTree.h index 9b62f11..713f906 100644 --- a/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueTree.h +++ b/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueTree.h @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -62,7 +61,7 @@ namespace juce will correspond to the order in which the property was added, or that it will remain constant when other properties are added or removed. - Listeners can be added to a ValueTree to be told when properies change and when + Listeners can be added to a ValueTree to be told when properties change and when sub-trees are added or removed. @see var, XmlElement @@ -427,10 +426,9 @@ class JUCE_API ValueTree final /** Creates an XmlElement that holds a complete image of this tree and all its children. If this tree is invalid, this may return nullptr. Otherwise, the XML that is produced can be used to recreate a similar tree by calling ValueTree::fromXml(). - The caller must delete the object that is returned. @see fromXml, toXmlString */ - XmlElement* createXml() const; + std::unique_ptr createXml() const; /** Tries to recreate a tree from its XML representation. This isn't designed to cope with random XML data - it should only be fed XML that was created @@ -438,11 +436,17 @@ class JUCE_API ValueTree final */ static ValueTree fromXml (const XmlElement& xml); + /** Tries to recreate a tree from its XML representation. + This isn't designed to cope with random XML data - it should only be fed XML that was created + by the createXml() method. + */ + static ValueTree fromXml (const String& xmlText); + /** This returns a string containing an XML representation of the tree. This is quite handy for debugging purposes, as it provides a quick way to view a tree. @see createXml() */ - String toXmlString() const; + String toXmlString (const XmlElement::TextFormat& format = {}) const; //============================================================================== /** Stores this tree (and all its children) in a binary format. @@ -484,7 +488,7 @@ class JUCE_API ValueTree final simply check the tree parameter in this callback to make sure it's the tree you're interested in. */ virtual void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged, - const Identifier& property) = 0; + const Identifier& property); /** This method is called when a child sub-tree is added. Note that when you register a listener to a tree, it will receive this callback for @@ -493,7 +497,7 @@ class JUCE_API ValueTree final just check the parentTree parameter to make sure it's the one that you're interested in. */ virtual void valueTreeChildAdded (ValueTree& parentTree, - ValueTree& childWhichHasBeenAdded) = 0; + ValueTree& childWhichHasBeenAdded); /** This method is called when a child sub-tree is removed. @@ -504,7 +508,7 @@ class JUCE_API ValueTree final */ virtual void valueTreeChildRemoved (ValueTree& parentTree, ValueTree& childWhichHasBeenRemoved, - int indexFromWhichChildWasRemoved) = 0; + int indexFromWhichChildWasRemoved); /** This method is called when a tree's children have been re-shuffled. @@ -514,7 +518,7 @@ class JUCE_API ValueTree final just check the parameter to make sure it's the tree that you're interested in. */ virtual void valueTreeChildOrderChanged (ValueTree& parentTreeWhoseChildrenHaveMoved, - int oldIndex, int newIndex) = 0; + int oldIndex, int newIndex); /** This method is called when a tree has been added or removed from a parent. @@ -522,7 +526,7 @@ class JUCE_API ValueTree final removed from a parent. Unlike the other callbacks, it applies only to the tree to which the listener is registered, and not to any of its children. */ - virtual void valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged) = 0; + virtual void valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged); /** This method is called when a tree is made to point to a different internal shared object. When operator= is used to make a ValueTree refer to a different object, this callback diff --git a/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueTreeSynchroniser.cpp b/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueTreeSynchroniser.cpp index 774f1bb..d9f1d58 100644 --- a/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueTreeSynchroniser.cpp +++ b/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueTreeSynchroniser.cpp @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -159,8 +158,6 @@ void ValueTreeSynchroniser::valueTreeChildOrderChanged (ValueTree& parent, int o stateChanged (m.getData(), m.getDataSize()); } -void ValueTreeSynchroniser::valueTreeParentChanged (ValueTree&) {} // (No action needed here) - bool ValueTreeSynchroniser::applyChange (ValueTree& root, const void* data, size_t dataSize, UndoManager* undoManager) { MemoryInputStream input (data, dataSize, false); @@ -231,6 +228,9 @@ bool ValueTreeSynchroniser::applyChange (ValueTree& root, const void* data, size break; } + case ValueTreeSynchroniserHelpers::fullSync: + break; + default: jassertfalse; // Seem to have received some corrupt data? break; diff --git a/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueTreeSynchroniser.h b/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueTreeSynchroniser.h index 6c8499c..accb8f6 100644 --- a/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueTreeSynchroniser.h +++ b/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueTreeSynchroniser.h @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -91,7 +90,6 @@ class JUCE_API ValueTreeSynchroniser : private ValueTree::Listener void valueTreeChildAdded (ValueTree&, ValueTree&) override; void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override; void valueTreeChildOrderChanged (ValueTree&, int, int) override; - void valueTreeParentChanged (ValueTree&) override; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValueTreeSynchroniser) }; diff --git a/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueWithDefault.cpp b/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueWithDefault.cpp index 5e0ce3b..70ecc51 100644 --- a/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueWithDefault.cpp +++ b/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueWithDefault.cpp @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -32,7 +31,9 @@ namespace juce class ValueWithDefaultTests : public UnitTest { public: - ValueWithDefaultTests() : UnitTest ("ValueWithDefault", "Values") {} + ValueWithDefaultTests() + : UnitTest ("ValueWithDefault", UnitTestCategories::values) + {} void runTest() override { diff --git a/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueWithDefault.h b/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueWithDefault.h index b9eaa1d..42c9058 100644 --- a/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueWithDefault.h +++ b/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueWithDefault.h @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -31,7 +30,7 @@ namespace juce /** This class acts as a wrapper around a property inside a ValueTree. - If the property inside the ValueTree is missing or empty the ValueWithDefault will automatically + If the property inside the ValueTree is missing the ValueWithDefault will automatically return a default value, which can be specified when initialising the ValueWithDefault. @tags{DataStructures} @@ -89,7 +88,7 @@ class ValueWithDefault } //============================================================================== - /** Returns the current value of the property. If the property does not exist or is empty, + /** Returns the current value of the property. If the property does not exist this returns the default value. */ var get() const noexcept diff --git a/JuceLibraryCode/modules/juce_events/broadcasters/juce_ActionBroadcaster.cpp b/JuceLibraryCode/modules/juce_events/broadcasters/juce_ActionBroadcaster.cpp index 1ea521d..5babc9a 100644 --- a/JuceLibraryCode/modules/juce_events/broadcasters/juce_ActionBroadcaster.cpp +++ b/JuceLibraryCode/modules/juce_events/broadcasters/juce_ActionBroadcaster.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. @@ -51,7 +51,7 @@ class ActionBroadcaster::ActionMessage : public MessageManager::MessageBase //============================================================================== ActionBroadcaster::ActionBroadcaster() { - // are you trying to create this object before or after juce has been intialised?? + // are you trying to create this object before or after juce has been initialised?? JUCE_ASSERT_MESSAGE_MANAGER_EXISTS } diff --git a/JuceLibraryCode/modules/juce_events/broadcasters/juce_ActionBroadcaster.h b/JuceLibraryCode/modules/juce_events/broadcasters/juce_ActionBroadcaster.h index 3ddfcf7..3dce904 100644 --- a/JuceLibraryCode/modules/juce_events/broadcasters/juce_ActionBroadcaster.h +++ b/JuceLibraryCode/modules/juce_events/broadcasters/juce_ActionBroadcaster.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_events/broadcasters/juce_ActionListener.h b/JuceLibraryCode/modules/juce_events/broadcasters/juce_ActionListener.h index bbb2cf3..37fd751 100644 --- a/JuceLibraryCode/modules/juce_events/broadcasters/juce_ActionListener.h +++ b/JuceLibraryCode/modules/juce_events/broadcasters/juce_ActionListener.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_events/broadcasters/juce_AsyncUpdater.cpp b/JuceLibraryCode/modules/juce_events/broadcasters/juce_AsyncUpdater.cpp index 1b5d050..b66ee87 100644 --- a/JuceLibraryCode/modules/juce_events/broadcasters/juce_AsyncUpdater.cpp +++ b/JuceLibraryCode/modules/juce_events/broadcasters/juce_AsyncUpdater.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_events/broadcasters/juce_AsyncUpdater.h b/JuceLibraryCode/modules/juce_events/broadcasters/juce_AsyncUpdater.h index ac99a45..6c3a0c8 100644 --- a/JuceLibraryCode/modules/juce_events/broadcasters/juce_AsyncUpdater.h +++ b/JuceLibraryCode/modules/juce_events/broadcasters/juce_AsyncUpdater.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_events/broadcasters/juce_ChangeBroadcaster.cpp b/JuceLibraryCode/modules/juce_events/broadcasters/juce_ChangeBroadcaster.cpp index e06a815..ce7a10f 100644 --- a/JuceLibraryCode/modules/juce_events/broadcasters/juce_ChangeBroadcaster.cpp +++ b/JuceLibraryCode/modules/juce_events/broadcasters/juce_ChangeBroadcaster.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. @@ -39,6 +39,7 @@ void ChangeBroadcaster::addChangeListener (ChangeListener* const listener) JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED changeListeners.add (listener); + anyListeners = true; } void ChangeBroadcaster::removeChangeListener (ChangeListener* const listener) @@ -48,6 +49,7 @@ void ChangeBroadcaster::removeChangeListener (ChangeListener* const listener) JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED changeListeners.remove (listener); + anyListeners = changeListeners.size() > 0; } void ChangeBroadcaster::removeAllChangeListeners() @@ -57,11 +59,12 @@ void ChangeBroadcaster::removeAllChangeListeners() JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED changeListeners.clear(); + anyListeners = false; } void ChangeBroadcaster::sendChangeMessage() { - if (changeListeners.size() > 0) + if (anyListeners) broadcastCallback.triggerAsyncUpdate(); } diff --git a/JuceLibraryCode/modules/juce_events/broadcasters/juce_ChangeBroadcaster.h b/JuceLibraryCode/modules/juce_events/broadcasters/juce_ChangeBroadcaster.h index b3e2841..c62b2f1 100644 --- a/JuceLibraryCode/modules/juce_events/broadcasters/juce_ChangeBroadcaster.h +++ b/JuceLibraryCode/modules/juce_events/broadcasters/juce_ChangeBroadcaster.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. @@ -95,6 +95,8 @@ class JUCE_API ChangeBroadcaster ChangeBroadcasterCallback broadcastCallback; ListenerList changeListeners; + std::atomic anyListeners { false }; + void callListeners(); JUCE_DECLARE_NON_COPYABLE (ChangeBroadcaster) diff --git a/JuceLibraryCode/modules/juce_events/broadcasters/juce_ChangeListener.h b/JuceLibraryCode/modules/juce_events/broadcasters/juce_ChangeListener.h index 085f495..35a41d1 100644 --- a/JuceLibraryCode/modules/juce_events/broadcasters/juce_ChangeListener.h +++ b/JuceLibraryCode/modules/juce_events/broadcasters/juce_ChangeListener.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. @@ -51,13 +51,6 @@ class JUCE_API ChangeListener @param source the ChangeBroadcaster that triggered the callback. */ virtual void changeListenerCallback (ChangeBroadcaster* source) = 0; - - - //============================================================================== - #if JUCE_CATCH_DEPRECATED_CODE_MISUSE - // This method's signature has changed to take a ChangeBroadcaster parameter - please update your code! - private: virtual int changeListenerCallback (void*) { return 0; } - #endif }; } // namespace juce diff --git a/JuceLibraryCode/modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp b/JuceLibraryCode/modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp index 36a17d7..91e9aa0 100644 --- a/JuceLibraryCode/modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp +++ b/JuceLibraryCode/modules/juce_events/interprocess/juce_ConnectedChildProcess.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,7 +30,7 @@ static const char* killMessage = "__ipc_k_"; static const char* pingMessage = "__ipc_p_"; enum { specialMessageSize = 8, defaultTimeoutMs = 8000 }; -static inline bool isMessageType (const MemoryBlock& mb, const char* messageType) noexcept +static bool isMessageType (const MemoryBlock& mb, const char* messageType) noexcept { return mb.matches (messageType, (size_t) specialMessageSize); } diff --git a/JuceLibraryCode/modules/juce_events/interprocess/juce_ConnectedChildProcess.h b/JuceLibraryCode/modules/juce_events/interprocess/juce_ConnectedChildProcess.h index 6f94b07..2979184 100644 --- a/JuceLibraryCode/modules/juce_events/interprocess/juce_ConnectedChildProcess.h +++ b/JuceLibraryCode/modules/juce_events/interprocess/juce_ConnectedChildProcess.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_events/interprocess/juce_InterprocessConnection.cpp b/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnection.cpp index 9b00c03..b92f0ff 100644 --- a/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnection.cpp +++ b/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnection.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. @@ -290,7 +290,7 @@ bool InterprocessConnection::readNextMessage() uint32 messageHeader[2]; auto bytes = readData (messageHeader, sizeof (messageHeader)); - if (bytes == sizeof (messageHeader) + if (bytes == (int) sizeof (messageHeader) && ByteOrder::swapIfBigEndian (messageHeader[0]) == magicMessageHeader) { auto bytesInMessage = (int) ByteOrder::swapIfBigEndian (messageHeader[1]); diff --git a/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnection.h b/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnection.h index 06971fe..975139c 100644 --- a/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnection.h +++ b/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnection.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. @@ -113,7 +113,7 @@ class JUCE_API InterprocessConnection to the pipe, or -1 for an infinite timeout @param mustNotExist if set to true, the method will fail if the pipe already exists @returns true if the pipe was created, or false if it fails (e.g. if another process is - already using using the pipe) + already using the pipe) */ bool createPipe (const String& pipeName, int pipeReceiveMessageTimeoutMs, bool mustNotExist = false); diff --git a/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnectionServer.cpp b/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnectionServer.cpp index 679fe08..ce3cfcd 100644 --- a/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnectionServer.cpp +++ b/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnectionServer.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_events/interprocess/juce_InterprocessConnectionServer.h b/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnectionServer.h index ee7ac20..dee30d5 100644 --- a/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnectionServer.h +++ b/JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnectionServer.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_events/interprocess/juce_NetworkServiceDiscovery.cpp b/JuceLibraryCode/modules/juce_events/interprocess/juce_NetworkServiceDiscovery.cpp index 637c46a..73c2420 100644 --- a/JuceLibraryCode/modules/juce_events/interprocess/juce_NetworkServiceDiscovery.cpp +++ b/JuceLibraryCode/modules/juce_events/interprocess/juce_NetworkServiceDiscovery.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,6 +23,11 @@ namespace juce { +#if JUCE_ANDROID + extern void acquireMulticastLock(); + extern void releaseMulticastLock(); +#endif + NetworkServiceDiscovery::Advertiser::Advertiser (const String& serviceTypeUID, const String& serviceDescription, int broadcastPortToUse, int connectionPort, @@ -62,17 +67,30 @@ void NetworkServiceDiscovery::Advertiser::run() void NetworkServiceDiscovery::Advertiser::sendBroadcast() { - auto localAddress = IPAddress::getLocalAddress(); - message.setAttribute ("address", localAddress.toString()); - auto broadcastAddress = IPAddress::getInterfaceBroadcastAddress (localAddress); - auto data = message.createDocument ({}, true, false); - socket.write (broadcastAddress.toString(), broadcastPort, data.toRawUTF8(), (int) data.getNumBytesAsUTF8()); + static IPAddress local = IPAddress::local(); + + for (auto& address : IPAddress::getAllAddresses()) + { + if (address == local) + continue; + + message.setAttribute ("address", address.toString()); + + auto broadcastAddress = IPAddress::getInterfaceBroadcastAddress (address); + auto data = message.toString (XmlElement::TextFormat().singleLine().withoutHeader()); + + socket.write (broadcastAddress.toString(), broadcastPort, data.toRawUTF8(), (int) data.getNumBytesAsUTF8()); + } } //============================================================================== NetworkServiceDiscovery::AvailableServiceList::AvailableServiceList (const String& serviceType, int broadcastPort) : Thread ("Discovery_listen"), serviceTypeUID (serviceType) { + #if JUCE_ANDROID + acquireMulticastLock(); + #endif + socket.bindToPort (broadcastPort); startThread (2); } @@ -81,6 +99,10 @@ NetworkServiceDiscovery::AvailableServiceList::~AvailableServiceList() { socket.shutdown(); stopThread (2000); + + #if JUCE_ANDROID + releaseMulticastLock(); + #endif } void NetworkServiceDiscovery::AvailableServiceList::run() diff --git a/JuceLibraryCode/modules/juce_events/interprocess/juce_NetworkServiceDiscovery.h b/JuceLibraryCode/modules/juce_events/interprocess/juce_NetworkServiceDiscovery.h index 5487a05..effbb96 100644 --- a/JuceLibraryCode/modules/juce_events/interprocess/juce_NetworkServiceDiscovery.h +++ b/JuceLibraryCode/modules/juce_events/interprocess/juce_NetworkServiceDiscovery.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. @@ -28,6 +28,8 @@ namespace juce Contains classes that implement a simple protocol for broadcasting the availability and location of a discoverable service on the local network, and for maintaining a list of known services. + + @tags{Events} */ struct NetworkServiceDiscovery { @@ -36,6 +38,8 @@ struct NetworkServiceDiscovery To use, simply create an instance of an Advertiser and it'll broadcast until you delete it. + + @tags{Events} */ struct Advertiser : private Thread { @@ -68,7 +72,10 @@ struct NetworkServiceDiscovery //============================================================================== /** Contains information about a service that has been found on the network. + @see AvailableServiceList, Advertiser + + @tags{Events} */ struct Service { @@ -87,7 +94,10 @@ struct NetworkServiceDiscovery Just create an instance of AvailableServiceList and it will start listening - you can register a callback with its onChange member to find out when services appear/disappear, and you can call getServices() to find out the current list. + @see Service, Advertiser + + @tags{Events} */ struct AvailableServiceList : private Thread, private AsyncUpdater @@ -103,7 +113,7 @@ struct NetworkServiceDiscovery /** Destructor */ ~AvailableServiceList() override; - /** A lambda that can be set to recieve a callback when the list changes */ + /** A lambda that can be set to receive a callback when the list changes */ std::function onChange; /** Returns a list of the currently known services. */ diff --git a/JuceLibraryCode/modules/juce_events/juce_events.cpp b/JuceLibraryCode/modules/juce_events/juce_events.cpp index e19d6d8..afba0b9 100644 --- a/JuceLibraryCode/modules/juce_events/juce_events.cpp +++ b/JuceLibraryCode/modules/juce_events/juce_events.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. @@ -35,7 +35,7 @@ #define JUCE_CORE_INCLUDE_COM_SMART_PTR 1 #define JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW 1 -#if JUCE_USE_WINRT_MIDI +#if JUCE_USE_WINRT_MIDI || JUCE_USE_WIN_WEBVIEW2 #define JUCE_EVENTS_INCLUDE_WINRT_WRAPPER 1 #endif @@ -73,10 +73,7 @@ #include "native/juce_osx_MessageQueue.h" - #if JUCE_CLANG - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wundeclared-selector" - #endif + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector") #if JUCE_MAC #include "native/juce_mac_MessageManager.mm" @@ -84,9 +81,7 @@ #include "native/juce_ios_MessageManager.mm" #endif - #if JUCE_CLANG - #pragma clang diagnostic pop - #endif + JUCE_END_IGNORE_WARNINGS_GCC_LIKE #elif JUCE_WINDOWS #include "native/juce_win32_Messaging.cpp" diff --git a/JuceLibraryCode/modules/juce_events/juce_events.h b/JuceLibraryCode/modules/juce_events/juce_events.h index dabbea0..34701be 100644 --- a/JuceLibraryCode/modules/juce_events/juce_events.h +++ b/JuceLibraryCode/modules/juce_events/juce_events.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,24 +20,25 @@ ============================================================================== */ + /******************************************************************************* 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_events - vendor: juce - version: 5.4.3 - name: JUCE message and event handling classes - description: Classes for running an application's main event loop and sending/receiving messages, timers, etc. - website: http://www.juce.com/juce - license: ISC + ID: juce_events + vendor: juce + version: 6.0.1 + name: JUCE message and event handling classes + description: Classes for running an application's main event loop and sending/receiving messages, timers, etc. + website: http://www.juce.com/juce + license: ISC - dependencies: juce_core + dependencies: juce_core END_JUCE_MODULE_DECLARATION @@ -50,7 +51,7 @@ #include //============================================================================== -/** Config: JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK +/** Config: JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK Will execute your application's suspend method on an iOS background task, giving you extra time to save your applications state. */ @@ -58,7 +59,7 @@ #define JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK 0 #endif -#if JUCE_EVENTS_INCLUDE_WINRT_WRAPPER && JUCE_WINDOWS +#if JUCE_WINDOWS && JUCE_EVENTS_INCLUDE_WINRT_WRAPPER // If this header file is missing then you are probably attempting to use WinRT // functionality without the WinRT libraries installed on your system. Try installing // the latest Windows Standalone SDK and maybe also adding the path to the WinRT diff --git a/JuceLibraryCode/modules/juce_events/juce_events.mm b/JuceLibraryCode/modules/juce_events/juce_events.mm index e6b7946..15262e4 100644 --- a/JuceLibraryCode/modules/juce_events/juce_events.mm +++ b/JuceLibraryCode/modules/juce_events/juce_events.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_events/messages/juce_ApplicationBase.cpp b/JuceLibraryCode/modules/juce_events/messages/juce_ApplicationBase.cpp index 33a9a0a..15773ff 100644 --- a/JuceLibraryCode/modules/juce_events/messages/juce_ApplicationBase.cpp +++ b/JuceLibraryCode/modules/juce_events/messages/juce_ApplicationBase.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. @@ -175,7 +175,7 @@ StringArray JUCE_CALLTYPE JUCEApplicationBase::getCommandLineParameterArray() #else -#if JUCE_IOS +#if JUCE_IOS && JUCE_MODULE_AVAILABLE_juce_gui_basics extern int juce_iOSMain (int argc, const char* argv[], void* classPtr); #endif @@ -233,7 +233,7 @@ int JUCEApplicationBase::main (int argc, const char* argv[]) return juce_gtkWebkitMain (argc, argv); #endif - #if JUCE_IOS + #if JUCE_IOS && JUCE_MODULE_AVAILABLE_juce_gui_basics return juce_iOSMain (argc, argv, iOSCustomDelegate); #else diff --git a/JuceLibraryCode/modules/juce_events/messages/juce_ApplicationBase.h b/JuceLibraryCode/modules/juce_events/messages/juce_ApplicationBase.h index e0ab7ec..3eddc09 100644 --- a/JuceLibraryCode/modules/juce_events/messages/juce_ApplicationBase.h +++ b/JuceLibraryCode/modules/juce_events/messages/juce_ApplicationBase.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. @@ -206,10 +206,17 @@ class JUCE_API JUCEApplicationBase virtual void memoryWarningReceived() { jassertfalse; } //============================================================================== - /** Override this method to be informed when the back button is pressed on a device. + /** This will be called when the back button on a device is pressed. The return value + should be used to indicate whether the back button event has been handled by + the application, for example if you want to implement custom navigation instead + of the standard behaviour on Android. + This is currently only implemented on Android devices. + + @returns true if the event has been handled, or false if the default OS + behaviour should happen */ - virtual void backButtonPressed() {} + virtual bool backButtonPressed() { return false; } //============================================================================== /** Signals that the main message loop should stop and the application should terminate. diff --git a/JuceLibraryCode/modules/juce_events/messages/juce_CallbackMessage.h b/JuceLibraryCode/modules/juce_events/messages/juce_CallbackMessage.h index 9796c14..1a46f8d 100644 --- a/JuceLibraryCode/modules/juce_events/messages/juce_CallbackMessage.h +++ b/JuceLibraryCode/modules/juce_events/messages/juce_CallbackMessage.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_events/messages/juce_DeletedAtShutdown.cpp b/JuceLibraryCode/modules/juce_events/messages/juce_DeletedAtShutdown.cpp index 8ed76fe..ab2d044 100644 --- a/JuceLibraryCode/modules/juce_events/messages/juce_DeletedAtShutdown.cpp +++ b/JuceLibraryCode/modules/juce_events/messages/juce_DeletedAtShutdown.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,12 +43,9 @@ DeletedAtShutdown::~DeletedAtShutdown() getDeletedAtShutdownObjects().removeFirstMatchingValue (this); } -#if JUCE_MSVC - // Disable unreachable code warning, in case the compiler manages to figure out that - // you have no classes of DeletedAtShutdown that could throw an exception in their destructor. - #pragma warning (push) - #pragma warning (disable: 4702) -#endif +// Disable unreachable code warning, in case the compiler manages to figure out that +// you have no classes of DeletedAtShutdown that could throw an exception in their destructor. +JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4702) void DeletedAtShutdown::deleteAll() { @@ -87,8 +84,6 @@ void DeletedAtShutdown::deleteAll() getDeletedAtShutdownObjects().clear(); // just to make sure the array doesn't have any memory still allocated } -#if JUCE_MSVC - #pragma warning (pop) -#endif +JUCE_END_IGNORE_WARNINGS_MSVC } // namespace juce diff --git a/JuceLibraryCode/modules/juce_events/messages/juce_DeletedAtShutdown.h b/JuceLibraryCode/modules/juce_events/messages/juce_DeletedAtShutdown.h index 221c1b1..d879f23 100644 --- a/JuceLibraryCode/modules/juce_events/messages/juce_DeletedAtShutdown.h +++ b/JuceLibraryCode/modules/juce_events/messages/juce_DeletedAtShutdown.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_events/messages/juce_Initialisation.h b/JuceLibraryCode/modules/juce_events/messages/juce_Initialisation.h index 12bdb63..a21322f 100644 --- a/JuceLibraryCode/modules/juce_events/messages/juce_Initialisation.h +++ b/JuceLibraryCode/modules/juce_events/messages/juce_Initialisation.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_events/messages/juce_Message.h b/JuceLibraryCode/modules/juce_events/messages/juce_Message.h index 5465fcb..6a10603 100644 --- a/JuceLibraryCode/modules/juce_events/messages/juce_Message.h +++ b/JuceLibraryCode/modules/juce_events/messages/juce_Message.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_events/messages/juce_MessageListener.cpp b/JuceLibraryCode/modules/juce_events/messages/juce_MessageListener.cpp index b2bdb61..37e89c0 100644 --- a/JuceLibraryCode/modules/juce_events/messages/juce_MessageListener.cpp +++ b/JuceLibraryCode/modules/juce_events/messages/juce_MessageListener.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. @@ -34,7 +34,7 @@ void Message::messageCallback() MessageListener::MessageListener() noexcept { - // Are you trying to create a messagelistener before or after juce has been intialised?? + // Are you trying to create a messagelistener before or after juce has been initialised?? JUCE_ASSERT_MESSAGE_MANAGER_EXISTS } diff --git a/JuceLibraryCode/modules/juce_events/messages/juce_MessageListener.h b/JuceLibraryCode/modules/juce_events/messages/juce_MessageListener.h index f25734e..d3d1230 100644 --- a/JuceLibraryCode/modules/juce_events/messages/juce_MessageListener.h +++ b/JuceLibraryCode/modules/juce_events/messages/juce_MessageListener.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_events/messages/juce_MessageManager.cpp b/JuceLibraryCode/modules/juce_events/messages/juce_MessageManager.cpp index ac2858d..6e5a6b0 100644 --- a/JuceLibraryCode/modules/juce_events/messages/juce_MessageManager.cpp +++ b/JuceLibraryCode/modules/juce_events/messages/juce_MessageManager.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. @@ -164,7 +164,7 @@ class AsyncFunctionCallback : public MessageManager::MessageBase JUCE_DECLARE_NON_COPYABLE (AsyncFunctionCallback) }; -void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* const func, void* const parameter) +void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* func, void* parameter) { if (isThisTheMessageThread()) return func (parameter); @@ -184,6 +184,18 @@ void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* cons return nullptr; } +bool MessageManager::callAsync (std::function fn) +{ + struct AsyncCallInvoker : public MessageBase + { + AsyncCallInvoker (std::function f) : callback (std::move (f)) {} + void messageCallback() override { callback(); } + std::function callback; + }; + + return (new AsyncCallInvoker (std::move (fn)))->post(); +} + //============================================================================== void MessageManager::deliverBroadcastMessage (const String& value) { @@ -261,8 +273,8 @@ bool MessageManager::existsAndIsCurrentThread() noexcept struct MessageManager::Lock::BlockingMessage : public MessageManager::MessageBase { BlockingMessage (const MessageManager::Lock* parent) noexcept - // need a const_cast here as VS2013 doesn't like a const pointer to be in an atomic - : owner (const_cast (parent)) {} + : owner (parent) + {} void messageCallback() override { @@ -277,7 +289,7 @@ struct MessageManager::Lock::BlockingMessage : public MessageManager::MessageB } CriticalSection ownerCriticalSection; - Atomic owner; + Atomic owner; WaitableEvent releaseEvent; JUCE_DECLARE_NON_COPYABLE (BlockingMessage) @@ -441,7 +453,6 @@ void MessageManagerLock::exitSignalSent() } //============================================================================== -JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI(); JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI() { JUCE_AUTORELEASEPOOL @@ -450,7 +461,6 @@ JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI() } } -JUCE_API void JUCE_CALLTYPE shutdownJuce_GUI(); JUCE_API void JUCE_CALLTYPE shutdownJuce_GUI() { JUCE_AUTORELEASEPOOL diff --git a/JuceLibraryCode/modules/juce_events/messages/juce_MessageManager.h b/JuceLibraryCode/modules/juce_events/messages/juce_MessageManager.h index 9b36716..e050266 100644 --- a/JuceLibraryCode/modules/juce_events/messages/juce_MessageManager.h +++ b/JuceLibraryCode/modules/juce_events/messages/juce_MessageManager.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. @@ -28,11 +28,6 @@ class ThreadPoolJob; class ActionListener; class ActionBroadcaster; -//============================================================================== -#if JUCE_MODULE_AVAILABLE_juce_opengl -class OpenGLContext; -#endif - //============================================================================== /** See MessageManager::callFunctionOnMessageThread() for use of this function type. */ using MessageCallbackFunction = void* (void* userData); @@ -94,12 +89,12 @@ class JUCE_API MessageManager final #endif //============================================================================== - /** Asynchronously invokes a function or C++11 lambda on the message thread. */ - template - static void callAsync (FunctionType functionToCall) - { - new AsyncCallInvoker (functionToCall); - } + /** Asynchronously invokes a function or C++11 lambda on the message thread. + + @returns true if the message was successfully posted to the message queue, + or false otherwise. + */ + static bool callAsync (std::function functionToCall); /** Calls a function using the message-thread. @@ -201,7 +196,7 @@ class JUCE_API MessageManager final /** A lock you can use to lock the message manager. You can use this class with the RAII-based ScopedLock classes. */ - class Lock + class JUCE_API Lock { public: /** @@ -223,14 +218,14 @@ class JUCE_API MessageManager final If another thread is currently using the MessageManager, this will wait until that thread releases the lock to the MessageManager. - This call will only exit if the lock was accquired by this thread. Calling abort while + This call will only exit if the lock was acquired by this thread. Calling abort while a thread is waiting for enter to finish, will have no effect. @see exit, abort */ void enter() const noexcept; - /** Attempts to lock the meesage manager and exits if abort is called. + /** Attempts to lock the message manager and exits if abort is called. This method behaves identically to enter, except that it will abort waiting for the lock if the abort method is called. @@ -270,7 +265,7 @@ class JUCE_API MessageManager final messageManagerLock.abort(); } - @returns false if waiting for a lock was aborted, true if the lock was accquired. + @returns false if waiting for a lock was aborted, true if the lock was acquired. @see enter, abort, ScopedTryLock */ bool tryEnter() const noexcept; @@ -283,7 +278,7 @@ class JUCE_API MessageManager final /** Unblocks a thread which is waiting in tryEnter Call this method if you want to unblock a thread which is waiting for the MessageManager lock in tryEnter. - This method does not have any effetc on a thread waiting for a lock in enter. + This method does not have any effect on a thread waiting for a lock in enter. @see tryEnter */ void abort() const noexcept; @@ -340,16 +335,6 @@ class JUCE_API MessageManager final static void doPlatformSpecificShutdown(); static bool dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages); - template - struct AsyncCallInvoker : public MessageBase - { - AsyncCallInvoker (FunctionType f) : callback (f) { post(); } - void messageCallback() override { callback(); } - FunctionType callback; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AsyncCallInvoker) - }; - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MessageManager) }; diff --git a/JuceLibraryCode/modules/juce_events/messages/juce_MountedVolumeListChangeDetector.h b/JuceLibraryCode/modules/juce_events/messages/juce_MountedVolumeListChangeDetector.h index 510429b..fa0c081 100644 --- a/JuceLibraryCode/modules/juce_events/messages/juce_MountedVolumeListChangeDetector.h +++ b/JuceLibraryCode/modules/juce_events/messages/juce_MountedVolumeListChangeDetector.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_events/messages/juce_NotificationType.h b/JuceLibraryCode/modules/juce_events/messages/juce_NotificationType.h index bfaae65..ca049fb 100644 --- a/JuceLibraryCode/modules/juce_events/messages/juce_NotificationType.h +++ b/JuceLibraryCode/modules/juce_events/messages/juce_NotificationType.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_events/native/juce_android_Messaging.cpp b/JuceLibraryCode/modules/juce_events/native/juce_android_Messaging.cpp index a3b9e33..953cb44 100644 --- a/JuceLibraryCode/modules/juce_events/native/juce_android_Messaging.cpp +++ b/JuceLibraryCode/modules/juce_events/native/juce_android_Messaging.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. @@ -76,7 +76,7 @@ struct AndroidMessageQueue : private Android::Runnable { } - ~AndroidMessageQueue() + ~AndroidMessageQueue() override { JUCE_ASSERT_MESSAGE_THREAD clearSingletonInstance(); @@ -156,14 +156,14 @@ void MessageManager::stopDispatchLoop() { jmethodID quitMethod = env->GetMethodID (AndroidActivity, "finishAndRemoveTask", "()V"); - if (quitMethod != 0) + if (quitMethod != nullptr) { env->CallVoidMethod (activity.get(), quitMethod); return; } quitMethod = env->GetMethodID (AndroidActivity, "finish", "()V"); - jassert (quitMethod != 0); + jassert (quitMethod != nullptr); env->CallVoidMethod (activity.get(), quitMethod); } else @@ -195,7 +195,7 @@ class JuceAppLifecycle : public ActivityLifecycleCallbacks } } - ~JuceAppLifecycle() + ~JuceAppLifecycle() override { LocalRef appContext (getAppContext()); diff --git a/JuceLibraryCode/modules/juce_events/native/juce_ios_MessageManager.mm b/JuceLibraryCode/modules/juce_events/native/juce_ios_MessageManager.mm index 81c6df4..cb15732 100644 --- a/JuceLibraryCode/modules/juce_events/native/juce_ios_MessageManager.mm +++ b/JuceLibraryCode/modules/juce_events/native/juce_ios_MessageManager.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_events/native/juce_linux_EventLoop.h b/JuceLibraryCode/modules/juce_events/native/juce_linux_EventLoop.h index 1dc9c43..71bc6dc 100644 --- a/JuceLibraryCode/modules/juce_events/native/juce_linux_EventLoop.h +++ b/JuceLibraryCode/modules/juce_events/native/juce_linux_EventLoop.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. @@ -25,31 +25,26 @@ namespace juce namespace LinuxEventLoop { - struct CallbackFunctionBase - { - virtual ~CallbackFunctionBase() {} - virtual bool operator()(int fd) = 0; - bool active = true; - }; - - template - struct CallbackFunction : public CallbackFunctionBase - { - FdCallbackFunction callback; - - CallbackFunction (FdCallbackFunction c) : callback (c) {} - - bool operator() (int fd) override { return callback (fd); } - }; - - template - void setWindowSystemFd (int fd, FdCallbackFunction readCallback) - { - setWindowSystemFdInternal (fd, new CallbackFunction (readCallback)); - } - void removeWindowSystemFd() noexcept; - - void setWindowSystemFdInternal (int fd, CallbackFunctionBase* readCallback) noexcept; + /** Registers a callback that will be called when a file descriptor is ready for I/O. + + This will add the given file descriptor to the internal set of file descriptors + that will be passed to the poll() call. When this file descriptor has data to read + the readCallback will be called. + + @param fd the file descriptor to be monitored + @param readCallback a callback that will be called when the file descriptor has + data to read. The file descriptor will be passed as an argument + @param eventMask a bit mask specifying the events you are interested in for the + file descriptor. The possible values for this are defined in + + */ + void registerFdCallback (int fd, std::function readCallback, short eventMask = 1 /*POLLIN*/); + + /** Unregisters a previously registered file descriptor. + + @see registerFdCallback + */ + void unregisterFdCallback (int fd); } } // namespace juce diff --git a/JuceLibraryCode/modules/juce_events/native/juce_linux_Messaging.cpp b/JuceLibraryCode/modules/juce_events/native/juce_linux_Messaging.cpp index c0671fc..200fb93 100644 --- a/JuceLibraryCode/modules/juce_events/native/juce_linux_Messaging.cpp +++ b/JuceLibraryCode/modules/juce_events/native/juce_linux_Messaging.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. @@ -20,15 +20,6 @@ ============================================================================== */ -#include - -enum FdType -{ - INTERNAL_QUEUE_FD, - WINDOW_SYSTEM_FD, - FD_COUNT, -}; - namespace juce { @@ -38,30 +29,28 @@ class InternalMessageQueue public: InternalMessageQueue() { - auto ret = ::socketpair (AF_LOCAL, SOCK_STREAM, 0, fd); - ignoreUnused (ret); jassert (ret == 0); - - auto internalQueueCb = [this] (int _fd) - { - if (const MessageManager::MessageBase::Ptr msg = this->popNextMessage (_fd)) - { - JUCE_TRY - { - msg->messageCallback(); - return true; - } - JUCE_CATCH_EXCEPTION - } - return false; - }; - - pfds[INTERNAL_QUEUE_FD].fd = getReadHandle(); - pfds[INTERNAL_QUEUE_FD].events = POLLIN; - readCallback[INTERNAL_QUEUE_FD].reset (new LinuxEventLoop::CallbackFunction (internalQueueCb)); + auto err = ::socketpair (AF_LOCAL, SOCK_STREAM, 0, msgpipe); + jassert (err == 0); + ignoreUnused (err); + + LinuxEventLoop::registerFdCallback (getReadHandle(), + [this] (int fd) + { + while (auto msg = popNextMessage (fd)) + { + JUCE_TRY + { + msg->messageCallback(); + } + JUCE_CATCH_EXCEPTION + } + }); } ~InternalMessageQueue() { + LinuxEventLoop::unregisterFdCallback (getReadHandle()); + close (getReadHandle()); close (getWriteHandle()); @@ -74,106 +63,180 @@ class InternalMessageQueue ScopedLock sl (lock); queue.add (msg); - const int maxBytesInSocketQueue = 128; - if (bytesInSocket < maxBytesInSocketQueue) { bytesInSocket++; ScopedUnlock ul (lock); - const unsigned char x = 0xff; - ssize_t bytesWritten = write (getWriteHandle(), &x, 1); - ignoreUnused (bytesWritten); + unsigned char x = 0xff; + auto numBytes = write (getWriteHandle(), &x, 1); + ignoreUnused (numBytes); } } - void setWindowSystemFd (int _fd, LinuxEventLoop::CallbackFunctionBase* _readCallback) - { - jassert (fdCount == 1); + //============================================================================== + JUCE_DECLARE_SINGLETON (InternalMessageQueue, false) - ScopedLock sl (lock); +private: + CriticalSection lock; + ReferenceCountedArray queue; - fdCount = 2; - pfds[WINDOW_SYSTEM_FD].fd = _fd; - pfds[WINDOW_SYSTEM_FD].events = POLLIN; - readCallback[WINDOW_SYSTEM_FD].reset (_readCallback); - readCallback[WINDOW_SYSTEM_FD]->active = true; - } + int msgpipe[2]; + int bytesInSocket = 0; + static constexpr int maxBytesInSocketQueue = 128; + + int getWriteHandle() const noexcept { return msgpipe[0]; } + int getReadHandle() const noexcept { return msgpipe[1]; } - void removeWindowSystemFd() + MessageManager::MessageBase::Ptr popNextMessage (int fd) noexcept { - jassert (fdCount == FD_COUNT); + const ScopedLock sl (lock); - ScopedLock sl (lock); + if (bytesInSocket > 0) + { + --bytesInSocket; + + ScopedUnlock ul (lock); + unsigned char x; + auto numBytes = read (fd, &x, 1); + ignoreUnused (numBytes); + } + + return queue.removeAndReturn (0); + } +}; + +JUCE_IMPLEMENT_SINGLETON (InternalMessageQueue) - fdCount = 1; - readCallback[WINDOW_SYSTEM_FD]->active = false; +//============================================================================== +struct InternalRunLoop +{ +public: + InternalRunLoop() + { + fdReadCallbacks.reserve (16); } - bool dispatchNextEvent() noexcept + void registerFdCallback (int fd, std::function&& cb, short eventMask) { - for (int counter = 0; counter < fdCount; counter++) - { - const int i = loopCount++; - loopCount %= fdCount; + const ScopedLock sl (lock); - if (readCallback[i] != nullptr && readCallback[i]->active) - if ((*readCallback[i]) (pfds[i].fd)) - return true; + if (shouldDeferModifyingReadCallbacks) + { + deferredReadCallbackModifications.emplace_back ([this, fd, cb, eventMask]() mutable + { + registerFdCallback (fd, std::move (cb), eventMask); + }); + return; } - return false; + fdReadCallbacks.push_back ({ fd, std::move (cb) }); + pfds.push_back ({ fd, eventMask, 0 }); } - bool sleepUntilEvent (const int timeoutMs) + void unregisterFdCallback (int fd) { - const int pnum = poll (pfds, static_cast (fdCount), timeoutMs); - return (pnum > 0); - } + const ScopedLock sl (lock); - //============================================================================== - JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL (InternalMessageQueue) + if (shouldDeferModifyingReadCallbacks) + { + deferredReadCallbackModifications.emplace_back ([this, fd] { unregisterFdCallback (fd); }); + return; + } -private: - CriticalSection lock; - ReferenceCountedArray queue; - int fd[2]; - pollfd pfds[FD_COUNT]; - std::unique_ptr readCallback[FD_COUNT]; - int fdCount = 1; - int loopCount = 0; - int bytesInSocket = 0; + { + auto removePredicate = [=] (const std::pair>& cb) { return cb.first == fd; }; + + fdReadCallbacks.erase (std::remove_if (std::begin (fdReadCallbacks), std::end (fdReadCallbacks), removePredicate), + std::end (fdReadCallbacks)); + } + + { + auto removePredicate = [=] (const pollfd& pfd) { return pfd.fd == fd; }; - int getWriteHandle() const noexcept { return fd[0]; } - int getReadHandle() const noexcept { return fd[1]; } + pfds.erase (std::remove_if (std::begin (pfds), std::end (pfds), removePredicate), + std::end (pfds)); + } + } - MessageManager::MessageBase::Ptr popNextMessage (int _fd) noexcept + bool dispatchPendingEvents() { const ScopedLock sl (lock); - if (bytesInSocket > 0) + if (poll (&pfds.front(), static_cast (pfds.size()), 0) == 0) + return false; + + bool eventWasSent = false; + + for (auto& pfd : pfds) { - --bytesInSocket; + if (pfd.revents == 0) + continue; - const ScopedUnlock ul (lock); - unsigned char x; - ssize_t numBytes = read (_fd, &x, 1); - ignoreUnused (numBytes); + pfd.revents = 0; + + auto fd = pfd.fd; + + for (auto& fdAndCallback : fdReadCallbacks) + { + if (fdAndCallback.first == fd) + { + { + ScopedValueSetter insideFdReadCallback (shouldDeferModifyingReadCallbacks, true); + fdAndCallback.second (fd); + } + + if (! deferredReadCallbackModifications.empty()) + { + for (auto& deferredRegisterEvent : deferredReadCallbackModifications) + deferredRegisterEvent(); + + deferredReadCallbackModifications.clear(); + + // elements may have been removed from the fdReadCallbacks/pfds array so we really need + // to call poll again + return true; + } + + eventWasSent = true; + } + } } - return queue.removeAndReturn (0); + return eventWasSent; } -}; -JUCE_IMPLEMENT_SINGLETON (InternalMessageQueue) + void sleepUntilNextEvent (int timeoutMs) + { + poll (&pfds.front(), static_cast (pfds.size()), timeoutMs); + } + + std::vector>> getFdReadCallbacks() + { + const ScopedLock sl (lock); + return fdReadCallbacks; + } + + //============================================================================== + JUCE_DECLARE_SINGLETON (InternalRunLoop, false) + +private: + CriticalSection lock; + + std::vector>> fdReadCallbacks; + std::vector pfds; + + bool shouldDeferModifyingReadCallbacks = false; + std::vector> deferredReadCallbackModifications; +}; +JUCE_IMPLEMENT_SINGLETON (InternalRunLoop) //============================================================================== namespace LinuxErrorHandling { static bool keyboardBreakOccurred = false; - //============================================================================== void keyboardBreakSignalHandler (int sig) { if (sig == SIGINT) @@ -188,7 +251,7 @@ namespace LinuxErrorHandling saction.sa_handler = keyboardBreakSignalHandler; saction.sa_mask = maskSet; saction.sa_flags = 0; - sigaction (SIGINT, &saction, 0); + sigaction (SIGINT, &saction, nullptr); } } @@ -198,14 +261,14 @@ void MessageManager::doPlatformSpecificInitialisation() if (JUCEApplicationBase::isStandaloneApp()) LinuxErrorHandling::installKeyboardBreakHandler(); - // Create the internal message queue - auto* queue = InternalMessageQueue::getInstance(); - ignoreUnused (queue); + InternalRunLoop::getInstance(); + InternalMessageQueue::getInstance(); } void MessageManager::doPlatformSpecificShutdown() { InternalMessageQueue::deleteInstance(); + InternalRunLoop::deleteInstance(); } bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message) @@ -230,18 +293,17 @@ bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMes for (;;) { if (LinuxErrorHandling::keyboardBreakOccurred) - JUCEApplicationBase::getInstance()->quit(); + JUCEApplicationBase::quit(); - if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating()) + if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating()) { - if (queue->dispatchNextEvent()) + if (runLoop->dispatchPendingEvents()) break; if (returnIfNoPendingMessages) return false; - // wait for 2000ms for next events if necessary - queue->sleepUntilEvent (2000); + runLoop->sleepUntilNextEvent (2000); } } @@ -249,17 +311,27 @@ bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMes } //============================================================================== -void LinuxEventLoop::setWindowSystemFdInternal (int fd, LinuxEventLoop::CallbackFunctionBase* readCallback) noexcept +void LinuxEventLoop::registerFdCallback (int fd, std::function readCallback, short eventMask) { - if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating()) - queue->setWindowSystemFd (fd, readCallback); + if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating()) + runLoop->registerFdCallback (fd, std::move (readCallback), eventMask); } -void LinuxEventLoop::removeWindowSystemFd() noexcept +void LinuxEventLoop::unregisterFdCallback (int fd) { - if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating()) - queue->removeWindowSystemFd(); + if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating()) + runLoop->unregisterFdCallback (fd); } - } // namespace juce + +JUCE_API std::vector>> getFdReadCallbacks() +{ + using namespace juce; + + if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating()) + return runLoop->getFdReadCallbacks(); + + jassertfalse; + return {}; +} diff --git a/JuceLibraryCode/modules/juce_events/native/juce_mac_MessageManager.mm b/JuceLibraryCode/modules/juce_events/native/juce_mac_MessageManager.mm index 129b352..7d45219 100644 --- a/JuceLibraryCode/modules/juce_events/native/juce_mac_MessageManager.mm +++ b/JuceLibraryCode/modules/juce_events/native/juce_mac_MessageManager.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. @@ -389,18 +389,19 @@ static void shutdownNSApp() { JUCE_AUTORELEASEPOOL { - CFRunLoopRunInMode (kCFRunLoopDefaultMode, 0.001, true); + auto msRemaining = endTime - Time::currentTimeMillis(); - NSEvent* e = [NSApp nextEventMatchingMask: NSEventMaskAny - untilDate: [NSDate dateWithTimeIntervalSinceNow: 0.001] - inMode: NSDefaultRunLoopMode - dequeue: YES]; + if (msRemaining <= 0) + break; - if (e != nil && (isEventBlockedByModalComps == nullptr || ! (*isEventBlockedByModalComps) (e))) - [NSApp sendEvent: e]; + CFRunLoopRunInMode (kCFRunLoopDefaultMode, jmin (1.0, msRemaining * 0.001), true); - if (Time::currentTimeMillis() >= endTime) - break; + if (NSEvent* e = [NSApp nextEventMatchingMask: NSEventMaskAny + untilDate: [NSDate dateWithTimeIntervalSinceNow: 0.001] + inMode: NSDefaultRunLoopMode + dequeue: YES]) + if (isEventBlockedByModalComps == nullptr || ! (*isEventBlockedByModalComps) (e)) + [NSApp sendEvent: e]; } } diff --git a/JuceLibraryCode/modules/juce_events/native/juce_osx_MessageQueue.h b/JuceLibraryCode/modules/juce_events/native/juce_osx_MessageQueue.h index b461282..29388ad 100644 --- a/JuceLibraryCode/modules/juce_events/native/juce_osx_MessageQueue.h +++ b/JuceLibraryCode/modules/juce_events/native/juce_osx_MessageQueue.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_events/native/juce_win32_HiddenMessageWindow.h b/JuceLibraryCode/modules/juce_events/native/juce_win32_HiddenMessageWindow.h index e3c3241..cc77e4b 100644 --- a/JuceLibraryCode/modules/juce_events/native/juce_win32_HiddenMessageWindow.h +++ b/JuceLibraryCode/modules/juce_events/native/juce_win32_HiddenMessageWindow.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. @@ -34,7 +34,7 @@ class HiddenMessageWindow HMODULE moduleHandle = (HMODULE) Process::getCurrentModuleInstanceHandle(); - WNDCLASSEX wc = { 0 }; + WNDCLASSEX wc = {}; wc.cbSize = sizeof (wc); wc.lpfnWndProc = wndProc; wc.cbWndExtra = 4; @@ -45,14 +45,15 @@ class HiddenMessageWindow jassert (atom != 0); hwnd = CreateWindow (getClassNameFromAtom(), messageWindowName, - 0, 0, 0, 0, 0, 0, 0, moduleHandle, 0); - jassert (hwnd != 0); + 0, 0, 0, 0, 0, + nullptr, nullptr, moduleHandle, nullptr); + jassert (hwnd != nullptr); } ~HiddenMessageWindow() { DestroyWindow (hwnd); - UnregisterClass (getClassNameFromAtom(), 0); + UnregisterClass (getClassNameFromAtom(), nullptr); } inline HWND getHWND() const noexcept { return hwnd; } diff --git a/JuceLibraryCode/modules/juce_events/native/juce_win32_Messaging.cpp b/JuceLibraryCode/modules/juce_events/native/juce_win32_Messaging.cpp index 03d9525..5a820a8 100644 --- a/JuceLibraryCode/modules/juce_events/native/juce_win32_Messaging.cpp +++ b/JuceLibraryCode/modules/juce_events/native/juce_win32_Messaging.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,81 +25,141 @@ namespace juce extern HWND juce_messageWindowHandle; +#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity + bool juce_isRunningInUnity(); +#endif + +#if JUCE_MODULE_AVAILABLE_juce_gui_extra + LRESULT juce_offerEventToActiveXControl (::MSG&); +#endif + using CheckEventBlockedByModalComps = bool (*)(const MSG&); CheckEventBlockedByModalComps isEventBlockedByModalComps = nullptr; using SettingChangeCallbackFunc = void (*)(void); SettingChangeCallbackFunc settingChangeCallback = nullptr; -#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity - bool juce_isRunningInUnity(); -#endif - //============================================================================== -namespace WindowsMessageHelpers +class InternalMessageQueue { - const unsigned int customMessageID = WM_USER + 123; - const unsigned int broadcastMessageMagicNumber = 0xc403; +public: + InternalMessageQueue() + { + messageWindow = std::make_unique (messageWindowName, (WNDPROC) messageWndProc); + juce_messageWindowHandle = messageWindow->getHWND(); + } - const TCHAR messageWindowName[] = _T("JUCEWindow"); - std::unique_ptr messageWindow; + ~InternalMessageQueue() + { + juce_messageWindowHandle = nullptr; + clearSingletonInstance(); + } + + JUCE_DECLARE_SINGLETON (InternalMessageQueue, false) - void dispatchMessageFromLParam (LPARAM lParam) + //============================================================================== + void broadcastMessage (const String& message) { - if (auto message = reinterpret_cast (lParam)) - { - JUCE_TRY - { - message->messageCallback(); - } - JUCE_CATCH_EXCEPTION + auto localCopy = message; - message->decReferenceCount(); + Array windows; + EnumWindows (&broadcastEnumWindowProc, (LPARAM) &windows); + + for (int i = windows.size(); --i >= 0;) + { + COPYDATASTRUCT data; + data.dwData = broadcastMessageMagicNumber; + data.cbData = ((size_t) localCopy.length() + 1) * sizeof (CharPointer_UTF32::CharType); + data.lpData = (void*) localCopy.toUTF32().getAddress(); + + DWORD_PTR result; + SendMessageTimeout (windows.getUnchecked (i), WM_COPYDATA, + (WPARAM) juce_messageWindowHandle, + (LPARAM) &data, + SMTO_BLOCK | SMTO_ABORTIFHUNG, 8000, &result); } } - BOOL CALLBACK broadcastEnumWindowProc (HWND hwnd, LPARAM lParam) + void postMessage (MessageManager::MessageBase* message) { - if (hwnd != juce_messageWindowHandle) + bool shouldTriggerMessageQueueDispatch = false; + { - TCHAR windowName[64] = { 0 }; // no need to read longer strings than this - GetWindowText (hwnd, windowName, 63); + const ScopedLock sl (lock); - if (String (windowName) == messageWindowName) - reinterpret_cast*> (lParam)->add (hwnd); + shouldTriggerMessageQueueDispatch = messageQueue.isEmpty(); + messageQueue.add (message); } - return TRUE; + if (! shouldTriggerMessageQueueDispatch) + return; + + #if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity + if (juce_isRunningInUnity()) + { + SendNotifyMessage (juce_messageWindowHandle, customMessageID, 0, 0); + return; + } + #endif + + PostMessage (juce_messageWindowHandle, customMessageID, 0, 0); } - void handleBroadcastMessage (const COPYDATASTRUCT* data) + bool dispatchNextMessage (bool returnIfNoPendingMessages) { - if (data != nullptr && data->dwData == broadcastMessageMagicNumber) - { - struct BroadcastMessage : public CallbackMessage - { - BroadcastMessage (CharPointer_UTF32 text, size_t length) : message (text, length) {} - void messageCallback() override { MessageManager::getInstance()->deliverBroadcastMessage (message); } + MSG m; - String message; - }; + if (returnIfNoPendingMessages && ! PeekMessage (&m, nullptr, 0, 0, PM_NOREMOVE)) + return false; - (new BroadcastMessage (CharPointer_UTF32 ((const CharPointer_UTF32::CharType*) data->lpData), - data->cbData / sizeof (CharPointer_UTF32::CharType))) - ->post(); + if (GetMessage (&m, nullptr, 0, 0) >= 0) + { + #if JUCE_MODULE_AVAILABLE_juce_gui_extra + if (juce_offerEventToActiveXControl (m) != S_FALSE) + return true; + #endif + + if (m.message == customMessageID && m.hwnd == juce_messageWindowHandle) + { + dispatchMessages(); + } + else if (m.message == WM_QUIT) + { + if (auto* app = JUCEApplicationBase::getInstance()) + app->systemRequestedQuit(); + } + else if (isEventBlockedByModalComps == nullptr || ! isEventBlockedByModalComps (m)) + { + if ((m.message == WM_LBUTTONDOWN || m.message == WM_RBUTTONDOWN) + && ! JuceWindowIdentifier::isJUCEWindow (m.hwnd)) + { + // if it's someone else's window being clicked on, and the focus is + // currently on a juce window, pass the kb focus over.. + auto currentFocus = GetFocus(); + + if (currentFocus == nullptr || JuceWindowIdentifier::isJUCEWindow (currentFocus)) + SetFocus (m.hwnd); + } + + TranslateMessage (&m); + DispatchMessage (&m); + } } + + return true; } +private: //============================================================================== - LRESULT CALLBACK messageWndProc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) noexcept + static LRESULT CALLBACK messageWndProc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) noexcept { if (h == juce_messageWindowHandle) { if (message == customMessageID) { - // (These are trapped early in our dispatch loop, but must also be checked - // here in case some 3rd-party code is running the dispatch loop). - dispatchMessageFromLParam (lParam); + if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating()) + queue->dispatchMessages(); + return 0; } @@ -116,106 +176,125 @@ namespace WindowsMessageHelpers return DefWindowProc (h, message, wParam, lParam); } -} -#if JUCE_MODULE_AVAILABLE_juce_gui_extra -LRESULT juce_offerEventToActiveXControl (::MSG&); -#endif + static BOOL CALLBACK broadcastEnumWindowProc (HWND hwnd, LPARAM lParam) + { + if (hwnd != juce_messageWindowHandle) + { + TCHAR windowName[64] = { 0 }; // no need to read longer strings than this + GetWindowText (hwnd, windowName, 63); -//============================================================================== -bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages) -{ - using namespace WindowsMessageHelpers; - MSG m; + if (String (windowName) == messageWindowName) + reinterpret_cast*> (lParam)->add (hwnd); + } - if (returnIfNoPendingMessages && ! PeekMessage (&m, (HWND) 0, 0, 0, PM_NOREMOVE)) - return false; + return TRUE; + } - if (GetMessage (&m, (HWND) 0, 0, 0) >= 0) + static void dispatchMessage (MessageManager::MessageBase* message) { - #if JUCE_MODULE_AVAILABLE_juce_gui_extra - if (juce_offerEventToActiveXControl (m) != S_FALSE) - return true; - #endif - - if (m.message == customMessageID && m.hwnd == juce_messageWindowHandle) + JUCE_TRY { - dispatchMessageFromLParam (m.lParam); + message->messageCallback(); } - else if (m.message == WM_QUIT) + JUCE_CATCH_EXCEPTION + + message->decReferenceCount(); + } + + static void handleBroadcastMessage (const COPYDATASTRUCT* data) + { + if (data != nullptr && data->dwData == broadcastMessageMagicNumber) { - if (auto* app = JUCEApplicationBase::getInstance()) - app->systemRequestedQuit(); + struct BroadcastMessage : public CallbackMessage + { + BroadcastMessage (CharPointer_UTF32 text, size_t length) : message (text, length) {} + void messageCallback() override { MessageManager::getInstance()->deliverBroadcastMessage (message); } + + String message; + }; + + (new BroadcastMessage (CharPointer_UTF32 ((const CharPointer_UTF32::CharType*) data->lpData), + data->cbData / sizeof (CharPointer_UTF32::CharType))) + ->post(); } - else if (isEventBlockedByModalComps == nullptr || ! isEventBlockedByModalComps (m)) + } + + void dispatchMessages() + { + ReferenceCountedArray messagesToDispatch; + { - if ((m.message == WM_LBUTTONDOWN || m.message == WM_RBUTTONDOWN) - && ! JuceWindowIdentifier::isJUCEWindow (m.hwnd)) - { - // if it's someone else's window being clicked on, and the focus is - // currently on a juce window, pass the kb focus over.. - auto currentFocus = GetFocus(); + const ScopedLock sl (lock); - if (currentFocus == 0 || JuceWindowIdentifier::isJUCEWindow (currentFocus)) - SetFocus (m.hwnd); - } + if (messageQueue.isEmpty()) + return; - TranslateMessage (&m); - DispatchMessage (&m); + messagesToDispatch.swapWith (messageQueue); + } + + for (int i = 0; i < messagesToDispatch.size(); ++i) + { + auto message = messagesToDispatch.getUnchecked (i); + message->incReferenceCount(); + dispatchMessage (message.get()); } } - return true; -} + //============================================================================== + static constexpr unsigned int customMessageID = WM_USER + 123; + static constexpr unsigned int broadcastMessageMagicNumber = 0xc403; + static const TCHAR messageWindowName[]; -bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message) -{ - message->incReferenceCount(); + std::unique_ptr messageWindow; - #if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity - if (juce_isRunningInUnity()) - return SendNotifyMessage (juce_messageWindowHandle, WindowsMessageHelpers::customMessageID, 0, (LPARAM) message) != 0; - #endif + CriticalSection lock; + ReferenceCountedArray messageQueue; - return PostMessage (juce_messageWindowHandle, WindowsMessageHelpers::customMessageID, 0, (LPARAM) message) != 0; -} + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InternalMessageQueue) +}; -void MessageManager::broadcastMessage (const String& value) +JUCE_IMPLEMENT_SINGLETON (InternalMessageQueue) + +const TCHAR InternalMessageQueue::messageWindowName[] = _T("JUCEWindow"); + +//============================================================================== +bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages) { - auto localCopy = value; + if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating()) + return queue->dispatchNextMessage (returnIfNoPendingMessages); - Array windows; - EnumWindows (&WindowsMessageHelpers::broadcastEnumWindowProc, (LPARAM) &windows); + return false; +} - for (int i = windows.size(); --i >= 0;) +bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message) +{ + if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating()) { - COPYDATASTRUCT data; - data.dwData = WindowsMessageHelpers::broadcastMessageMagicNumber; - data.cbData = (localCopy.length() + 1) * sizeof (CharPointer_UTF32::CharType); - data.lpData = (void*) localCopy.toUTF32().getAddress(); - - DWORD_PTR result; - SendMessageTimeout (windows.getUnchecked (i), WM_COPYDATA, - (WPARAM) juce_messageWindowHandle, - (LPARAM) &data, - SMTO_BLOCK | SMTO_ABORTIFHUNG, 8000, &result); + queue->postMessage (message); + return true; } + + return false; +} + +void MessageManager::broadcastMessage (const String& value) +{ + if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating()) + queue->broadcastMessage (value); } //============================================================================== void MessageManager::doPlatformSpecificInitialisation() { - OleInitialize (0); - - using namespace WindowsMessageHelpers; - messageWindow.reset (new HiddenMessageWindow (messageWindowName, (WNDPROC) messageWndProc)); - juce_messageWindowHandle = messageWindow->getHWND(); + OleInitialize (nullptr); + InternalMessageQueue::getInstance(); } void MessageManager::doPlatformSpecificShutdown() { - WindowsMessageHelpers::messageWindow = nullptr; - + InternalMessageQueue::deleteInstance(); OleUninitialize(); } diff --git a/JuceLibraryCode/modules/juce_events/native/juce_win32_WinRTWrapper.cpp b/JuceLibraryCode/modules/juce_events/native/juce_win32_WinRTWrapper.cpp index 9269140..f1ccf4d 100644 --- a/JuceLibraryCode/modules/juce_events/native/juce_win32_WinRTWrapper.cpp +++ b/JuceLibraryCode/modules/juce_events/native/juce_win32_WinRTWrapper.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_events/native/juce_win32_WinRTWrapper.h b/JuceLibraryCode/modules/juce_events/native/juce_win32_WinRTWrapper.h index f8ddbee..4229104 100644 --- a/JuceLibraryCode/modules/juce_events/native/juce_win32_WinRTWrapper.h +++ b/JuceLibraryCode/modules/juce_events/native/juce_win32_WinRTWrapper.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. @@ -51,6 +51,7 @@ class WinRTWrapper : public DeletedAtShutdown ~ComPtr() { release(); } operator ComClass*() const noexcept { return p; } + ComClass* get() const noexcept { return p; } ComClass& operator*() const noexcept { return *p; } ComClass* operator->() const noexcept { return p; } diff --git a/JuceLibraryCode/modules/juce_events/timers/juce_MultiTimer.cpp b/JuceLibraryCode/modules/juce_events/timers/juce_MultiTimer.cpp index dc3d0e6..b0d9ef6 100644 --- a/JuceLibraryCode/modules/juce_events/timers/juce_MultiTimer.cpp +++ b/JuceLibraryCode/modules/juce_events/timers/juce_MultiTimer.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_events/timers/juce_MultiTimer.h b/JuceLibraryCode/modules/juce_events/timers/juce_MultiTimer.h index c7c12a0..0362678 100644 --- a/JuceLibraryCode/modules/juce_events/timers/juce_MultiTimer.h +++ b/JuceLibraryCode/modules/juce_events/timers/juce_MultiTimer.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_events/timers/juce_Timer.cpp b/JuceLibraryCode/modules/juce_events/timers/juce_Timer.cpp index dcaf49a..2300c82 100644 --- a/JuceLibraryCode/modules/juce_events/timers/juce_Timer.cpp +++ b/JuceLibraryCode/modules/juce_events/timers/juce_Timer.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. @@ -136,7 +136,7 @@ class Timer::TimerThread : private Thread, callTimers(); } - static inline void add (Timer* tim) noexcept + static void add (Timer* tim) noexcept { if (instance == nullptr) instance = new TimerThread(); @@ -144,13 +144,13 @@ class Timer::TimerThread : private Thread, instance->addTimer (tim); } - static inline void remove (Timer* tim) noexcept + static void remove (Timer* tim) noexcept { if (instance != nullptr) instance->removeTimer (tim); } - static inline void resetCounter (Timer* tim) noexcept + static void resetCounter (Timer* tim) noexcept { if (instance != nullptr) instance->resetTimerCounter (tim); @@ -187,7 +187,7 @@ class Timer::TimerThread : private Thread, // Trying to add a timer that's already here - shouldn't get to this point, // so if you get this assertion, let me know! jassert (std::find_if (timers.begin(), timers.end(), - [t](TimerCountdown i) { return i.timer == t; }) == timers.end()); + [t] (TimerCountdown i) { return i.timer == t; }) == timers.end()); auto pos = timers.size(); diff --git a/JuceLibraryCode/modules/juce_events/timers/juce_Timer.h b/JuceLibraryCode/modules/juce_events/timers/juce_Timer.h index f3a752b..045bff6 100644 --- a/JuceLibraryCode/modules/juce_events/timers/juce_Timer.h +++ b/JuceLibraryCode/modules/juce_events/timers/juce_Timer.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_osc/juce_osc.cpp b/JuceLibraryCode/modules/juce_osc/juce_osc.cpp index 63f5acb..94439bc 100644 --- a/JuceLibraryCode/modules/juce_osc/juce_osc.cpp +++ b/JuceLibraryCode/modules/juce_osc/juce_osc.cpp @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). diff --git a/JuceLibraryCode/modules/juce_osc/juce_osc.h b/JuceLibraryCode/modules/juce_osc/juce_osc.h index 7fde049..fa7e78d 100644 --- a/JuceLibraryCode/modules/juce_osc/juce_osc.h +++ b/JuceLibraryCode/modules/juce_osc/juce_osc.h @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -24,24 +23,25 @@ ============================================================================== */ + /******************************************************************************* 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_osc - vendor: juce - version: 5.4.3 - name: JUCE OSC classes - description: Open Sound Control implementation. - website: http://www.juce.com/juce - license: GPL/Commercial + ID: juce_osc + vendor: juce + version: 6.0.1 + name: JUCE OSC classes + description: Open Sound Control implementation. + website: http://www.juce.com/juce + license: GPL/Commercial - dependencies: juce_core, juce_events + dependencies: juce_events END_JUCE_MODULE_DECLARATION diff --git a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCAddress.cpp b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCAddress.cpp index a4abb9f..2b81d3b 100644 --- a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCAddress.cpp +++ b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCAddress.cpp @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -175,6 +174,7 @@ namespace break; } // else = special case: fall through to default and treat '!' as a non-special character. + JUCE_FALLTHROUGH default: set.add (c); @@ -394,6 +394,7 @@ String OSCAddressPattern::toString() const noexcept return asString; } + //============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -401,7 +402,9 @@ String OSCAddressPattern::toString() const noexcept class OSCAddressTests : public UnitTest { public: - OSCAddressTests() : UnitTest ("OSCAddress class", "OSC") {} + OSCAddressTests() + : UnitTest ("OSCAddress class", UnitTestCategories::osc) + {} void runTest() { @@ -445,7 +448,9 @@ static OSCAddressTests OSCAddressUnitTests; class OSCAddressPatternTests : public UnitTest { public: - OSCAddressPatternTests() : UnitTest ("OSCAddressPattern class", "OSC") {} + OSCAddressPatternTests() + : UnitTest ("OSCAddressPattern class", UnitTestCategories::osc) + {} void runTest() { @@ -584,7 +589,9 @@ static OSCAddressPatternTests OSCAddressPatternUnitTests; class OSCPatternMatcherTests : public UnitTest { public: - OSCPatternMatcherTests() : UnitTest ("OSCAddress class / pattern matching", "OSC") {} + OSCPatternMatcherTests() + : UnitTest ("OSCAddress class / pattern matching", UnitTestCategories::osc) + {} void runTest() { @@ -780,6 +787,6 @@ class OSCPatternMatcherTests : public UnitTest static OSCPatternMatcherTests OSCPatternMatcherUnitTests; -#endif // JUCE_UNIT_TESTS +#endif } // namespace juce diff --git a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCAddress.h b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCAddress.h index a5d84d3..3375ce4 100644 --- a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCAddress.h +++ b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCAddress.h @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -130,7 +129,7 @@ class JUCE_API OSCAddressPattern bool matches (const OSCAddress& address) const noexcept; /** Checks whether the OSCAddressPattern contains any of the allowed OSC - address patttern wildcards: ?, *, [], {} + address pattern wildcards: ?, *, [], {} @returns true if the OSCAddressPattern contains OSC wildcards, false otherwise. */ diff --git a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCArgument.cpp b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCArgument.cpp index 086510d..f2a80ce 100644 --- a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCArgument.cpp +++ b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCArgument.cpp @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -78,6 +77,7 @@ OSCColour OSCArgument::getColour() const noexcept return { 0, 0, 0, 0 }; } + //============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -85,7 +85,9 @@ OSCColour OSCArgument::getColour() const noexcept class OSCArgumentTests : public UnitTest { public: - OSCArgumentTests() : UnitTest ("OSCArgument class", "OSC") {} + OSCArgumentTests() + : UnitTest ("OSCArgument class", UnitTestCategories::osc) + {} MemoryBlock getMemoryBlockWithRandomData (size_t numBytes) @@ -242,6 +244,6 @@ class OSCArgumentTests : public UnitTest static OSCArgumentTests OSCArgumentUnitTests; -#endif // JUCE_UNIT_TESTS +#endif } // namespace juce diff --git a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCArgument.h b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCArgument.h index 60abaa4..dc93d6f 100644 --- a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCArgument.h +++ b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCArgument.h @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). diff --git a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCBundle.cpp b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCBundle.cpp index ff6d503..3410a62 100644 --- a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCBundle.cpp +++ b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCBundle.cpp @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -108,13 +107,17 @@ const OSCBundle& OSCBundle::Element::getBundle() const return *bundle; } + +//============================================================================== //============================================================================== #if JUCE_UNIT_TESTS class OSCBundleTests : public UnitTest { public: - OSCBundleTests() : UnitTest ("OSCBundle class", "OSC") {} + OSCBundleTests() + : UnitTest ("OSCBundle class", UnitTestCategories::osc) + {} void runTest() { @@ -217,7 +220,9 @@ static OSCBundleTests OSCBundleUnitTests; class OSCBundleElementTests : public UnitTest { public: - OSCBundleElementTests() : UnitTest ("OSCBundle::Element class", "OSC") {} + OSCBundleElementTests() + : UnitTest ("OSCBundle::Element class", UnitTestCategories::osc) + {} void runTest() { @@ -239,6 +244,6 @@ class OSCBundleElementTests : public UnitTest static OSCBundleElementTests OSCBundleElementUnitTests; -#endif // JUCE_UNIT_TESTS +#endif } // namespace juce diff --git a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCBundle.h b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCBundle.h index 8e6453a..ce49c18 100644 --- a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCBundle.h +++ b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCBundle.h @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -64,7 +63,7 @@ class JUCE_API OSCBundle An OSCBundle Element contains either one OSCMessage or one OSCBundle. */ - class Element + class JUCE_API Element { public: //============================================================================== @@ -127,10 +126,16 @@ class JUCE_API OSCBundle void addElement (const OSCBundle::Element& element) { elements.add (element); } /** Returns a pointer to the first element of the OSCBundle. */ - OSCBundle::Element* begin() const noexcept { return elements.begin(); } + OSCBundle::Element* begin() noexcept { return elements.begin(); } + + /** Returns a pointer to the first element of the OSCBundle. */ + const OSCBundle::Element* begin() const noexcept { return elements.begin(); } + + /** Returns a pointer past the last element of the OSCBundle. */ + OSCBundle::Element* end() noexcept { return elements.end(); } /** Returns a pointer past the last element of the OSCBundle. */ - OSCBundle::Element* end() const noexcept { return elements.end(); } + const OSCBundle::Element* end() const noexcept { return elements.end(); } private: //============================================================================== diff --git a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCMessage.cpp b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCMessage.cpp index 4acf201..d72a63f 100644 --- a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCMessage.cpp +++ b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCMessage.cpp @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -63,12 +62,22 @@ const OSCArgument& OSCMessage::operator[] (const int i) const noexcept return arguments.getReference (i); } -OSCArgument* OSCMessage::begin() const noexcept +OSCArgument* OSCMessage::begin() noexcept { return arguments.begin(); } -OSCArgument* OSCMessage::end() const noexcept +const OSCArgument* OSCMessage::begin() const noexcept +{ + return arguments.begin(); +} + +OSCArgument* OSCMessage::end() noexcept +{ + return arguments.end(); +} + +const OSCArgument* OSCMessage::end() const noexcept { return arguments.end(); } @@ -86,6 +95,7 @@ void OSCMessage::addBlob (MemoryBlock blob) { arguments.add (OSCArgument void OSCMessage::addColour (OSCColour colour) { arguments.add (OSCArgument (colour)); } void OSCMessage::addArgument (OSCArgument arg) { arguments.add (arg); } + //============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -93,7 +103,9 @@ void OSCMessage::addArgument (OSCArgument arg) { arguments.add (arg); } class OSCMessageTests : public UnitTest { public: - OSCMessageTests() : UnitTest ("OSCMessage class", "OSC") {} + OSCMessageTests() + : UnitTest ("OSCMessage class", UnitTestCategories::osc) + {} void runTest() { @@ -210,6 +222,6 @@ class OSCMessageTests : public UnitTest static OSCMessageTests OSCMessageUnitTests; -#endif // JUCE_UNIT_TESTS +#endif } // namespace juce diff --git a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCMessage.h b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCMessage.h index 8bcc8df..6cd0a18 100644 --- a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCMessage.h +++ b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCMessage.h @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -99,12 +98,22 @@ class JUCE_API OSCMessage /** Returns a pointer to the first OSCArgument in the OSCMessage object. This method is provided for compatibility with standard C++ iteration mechanisms. */ - OSCArgument* begin() const noexcept; + OSCArgument* begin() noexcept; + + /** Returns a pointer to the first OSCArgument in the OSCMessage object. + This method is provided for compatibility with standard C++ iteration mechanisms. + */ + const OSCArgument* begin() const noexcept; + + /** Returns a pointer to the last OSCArgument in the OSCMessage object. + This method is provided for compatibility with standard C++ iteration mechanisms. + */ + OSCArgument* end() noexcept; /** Returns a pointer to the last OSCArgument in the OSCMessage object. This method is provided for compatibility with standard C++ iteration mechanisms. */ - OSCArgument* end() const noexcept; + const OSCArgument* end() const noexcept; /** Removes all arguments from the OSCMessage. */ void clear(); diff --git a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCReceiver.cpp b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCReceiver.cpp index 3c97018..54082f8 100644 --- a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCReceiver.cpp +++ b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCReceiver.cpp @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -321,7 +320,7 @@ struct OSCReceiver::Pimpl : private Thread, { } - ~Pimpl() + ~Pimpl() override { disconnect(); } @@ -526,33 +525,33 @@ struct OSCReceiver::Pimpl : private Thread, //============================================================================== void callListeners (const OSCBundle::Element& content) { - using Listener = OSCReceiver::Listener; + using OSCListener = OSCReceiver::Listener; if (content.isMessage()) { auto&& message = content.getMessage(); - listeners.call ([&] (Listener& l) { l.oscMessageReceived (message); }); + listeners.call ([&] (OSCListener& l) { l.oscMessageReceived (message); }); } else if (content.isBundle()) { auto&& bundle = content.getBundle(); - listeners.call ([&] (Listener& l) { l.oscBundleReceived (bundle); }); + listeners.call ([&] (OSCListener& l) { l.oscBundleReceived (bundle); }); } } void callRealtimeListeners (const OSCBundle::Element& content) { - using Listener = OSCReceiver::Listener; + using OSCListener = OSCReceiver::Listener; if (content.isMessage()) { auto&& message = content.getMessage(); - realtimeListeners.call ([&] (Listener& l) { l.oscMessageReceived (message); }); + realtimeListeners.call ([&] (OSCListener& l) { l.oscMessageReceived (message); }); } else if (content.isBundle()) { auto&& bundle = content.getBundle(); - realtimeListeners.call ([&] (Listener& l) { l.oscBundleReceived (bundle); }); + realtimeListeners.call ([&] (OSCListener& l) { l.oscBundleReceived (bundle); }); } } @@ -668,7 +667,9 @@ void OSCReceiver::registerFormatErrorHandler (FormatErrorHandler handler) class OSCInputStreamTests : public UnitTest { public: - OSCInputStreamTests() : UnitTest ("OSCInputStream class", "OSC") {} + OSCInputStreamTests() + : UnitTest ("OSCInputStream class", UnitTestCategories::osc) + {} void runTest() { @@ -1188,6 +1189,6 @@ class OSCInputStreamTests : public UnitTest static OSCInputStreamTests OSCInputStreamUnitTests; -#endif // JUCE_UNIT_TESTS +#endif } // namespace juce diff --git a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCReceiver.h b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCReceiver.h index b5b719a..0e9ed56 100644 --- a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCReceiver.h +++ b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCReceiver.h @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). diff --git a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCSender.cpp b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCSender.cpp index 64115a0..0c179d0 100644 --- a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCSender.cpp +++ b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCSender.cpp @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -69,7 +68,7 @@ namespace if (! output.writeString (value)) return false; - const size_t numPaddingZeros = ~value.length() & 3; + const size_t numPaddingZeros = ~value.getNumBytesAsUTF8() & 3; return output.writeRepeatedByte ('\0', numPaddingZeros); } @@ -332,6 +331,7 @@ bool OSCSender::send (const OSCBundle& bundle) { return pimpl->send (bundle bool OSCSender::sendToIPAddress (const String& host, int port, const OSCMessage& message) { return pimpl->send (message, host, port); } bool OSCSender::sendToIPAddress (const String& host, int port, const OSCBundle& bundle) { return pimpl->send (bundle, host, port); } + //============================================================================== //============================================================================== #if JUCE_UNIT_TESTS @@ -339,7 +339,9 @@ bool OSCSender::sendToIPAddress (const String& host, int port, const OSCBundle& class OSCBinaryWriterTests : public UnitTest { public: - OSCBinaryWriterTests() : UnitTest ("OSCBinaryWriter class", "OSC") {} + OSCBinaryWriterTests() + : UnitTest ("OSCBinaryWriter class", UnitTestCategories::osc) + {} void runTest() { @@ -666,7 +668,9 @@ static OSCBinaryWriterTests OSCBinaryWriterUnitTests; class OSCRoundTripTests : public UnitTest { public: - OSCRoundTripTests() : UnitTest ("OSCRoundTripTests class", "OSC") {} + OSCRoundTripTests() + : UnitTest ("OSCRoundTripTests class", UnitTestCategories::osc) + {} void runTest() { @@ -867,7 +871,6 @@ class OSCRoundTripTests : public UnitTest static OSCRoundTripTests OSCRoundTripUnitTests; -//============================================================================== -#endif // JUCE_UNIT_TESTS +#endif } // namespace juce diff --git a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCSender.h b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCSender.h index fd196c0..b97ea8b 100644 --- a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCSender.h +++ b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCSender.h @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). diff --git a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCTimeTag.cpp b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCTimeTag.cpp index 79fb77c..c6fba14 100644 --- a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCTimeTag.cpp +++ b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCTimeTag.cpp @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -57,12 +56,12 @@ Time OSCTimeTag::toTime() const noexcept const uint64 seconds = rawTimeTag >> 32; const uint32 fractionalPart = (rawTimeTag & 0x00000000FFFFFFFFULL); - const double fractionalPartInMillis = (double) fractionalPart / 4294967.296; + const auto fractionalPartInMillis = (double) fractionalPart / 4294967.296; // now using signed integer, because this is allowed to become negative: - const int64 juceTimeInMillis = int64 ((seconds * 1000) - + (uint64) roundToInt(fractionalPartInMillis) - - millisecondsBetweenOscAndJuceEpochs); + const auto juceTimeInMillis = (int64) (seconds * 1000) + + (int64) roundToInt (fractionalPartInMillis) + - (int64) millisecondsBetweenOscAndJuceEpochs; return Time (juceTimeInMillis); } @@ -80,7 +79,9 @@ bool OSCTimeTag::isImmediately() const noexcept class OSCTimeTagTests : public UnitTest { public: - OSCTimeTagTests() : UnitTest ("OSCTimeTag class", "OSC") {} + OSCTimeTagTests() + : UnitTest ("OSCTimeTag class", UnitTestCategories::osc) + {} void runTest() { @@ -131,8 +132,8 @@ class OSCTimeTagTests : public UnitTest uint64 diff = laterTimeTagRaw - currentTimeTagRaw; double acceptableErrorInSeconds = 0.000001; // definitely not audible anymore. - expect (diff / float (1ULL << 32) < deltaInSeconds + acceptableErrorInSeconds ); - expect (diff / float (1ULL << 32) > deltaInSeconds - acceptableErrorInSeconds ); + expect ((float) diff / float (1ULL << 32) < deltaInSeconds + acceptableErrorInSeconds ); + expect ((float) diff / float (1ULL << 32) > deltaInSeconds - acceptableErrorInSeconds ); // round trip: diff --git a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCTimeTag.h b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCTimeTag.h index 8c14cd8..f6cffb5 100644 --- a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCTimeTag.h +++ b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCTimeTag.h @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). @@ -70,7 +69,7 @@ class JUCE_API OSCTimeTag */ Time toTime() const noexcept; - /** Returns true if the OSCTimeTag object has the special value representing "immedately". */ + /** Returns true if the OSCTimeTag object has the special value representing "immediately". */ bool isImmediately() const noexcept; /** Returns the raw binary OSC time tag representation. */ diff --git a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCTypes.cpp b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCTypes.cpp index f190761..7522d84 100644 --- a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCTypes.cpp +++ b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCTypes.cpp @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). diff --git a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCTypes.h b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCTypes.h index 542a67f..e7e783b 100644 --- a/JuceLibraryCode/modules/juce_osc/osc/juce_OSCTypes.h +++ b/JuceLibraryCode/modules/juce_osc/osc/juce_OSCTypes.h @@ -2,17 +2,16 @@ ============================================================================== 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. - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). + 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-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy + 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). diff --git a/Source/Main.cpp b/Source/Main.cpp index 36d1050..f641db7 100644 --- a/Source/Main.cpp +++ b/Source/Main.cpp @@ -17,6 +17,7 @@ */ #include "JuceHeader.h" +#include "MidiRPN.h" #include "ScriptMidiMessageClass.h" #include "ScriptOscClass.h" #include "ScriptUtilClass.h" @@ -43,6 +44,11 @@ enum CommandIndex NOTE_OFF, POLY_PRESSURE, CONTROL_CHANGE, + CONTROL_CHANGE_14BIT, + NRPN, + NRPN_FULL, + RPN, + RPN_FULL, PROGRAM_CHANGE, CHANNEL_PRESSURE, PITCH_BEND, @@ -103,42 +109,47 @@ class receiveMidiApplication : public JUCEApplicationBase, public MidiInputCall public: receiveMidiApplication() { - commands_.add({"dev", "device", DEVICE, 1, "name", "Set the name of the MIDI input port"}); - commands_.add({"virt", "virtual", VIRTUAL, -1, "(name)", "Use virtual MIDI port with optional name (Linux/macOS)"}); - commands_.add({"pass", "pass-through", PASSTHROUGH, 1, "name", "Set name of MIDI output port for MIDI pass-through"}); - commands_.add({"list", "", LIST, 0, "", "Lists the MIDI input ports"}); - commands_.add({"file", "", TXTFILE, 1, "path", "Loads commands from the specified program file"}); - commands_.add({"dec", "decimal", DECIMAL, 0, "", "Interpret the next numbers as decimals by default"}); - commands_.add({"hex", "hexadecimal", HEXADECIMAL, 0, "", "Interpret the next numbers as hexadecimals by default"}); - commands_.add({"ch", "channel", CHANNEL, 1, "number", "Set MIDI channel for the commands (0-16), defaults to 0"}); - commands_.add({"ts", "timestamp", TIMESTAMP, 0, "", "Output a timestamp for each received MIDI message"}); - commands_.add({"nn", "note-numbers", NOTE_NUMBERS, 0, "", "Output notes as numbers instead of names"}); - commands_.add({"omc", "octave-middle-c", OCTAVE_MIDDLE_C, 1, "number", "Set octave for middle C, defaults to 3"}); - commands_.add({"voice", "", VOICE, 0, "", "Show all Channel Voice messages"}); - commands_.add({"note", "", NOTE, 0, "", "Show all Note messages"}); - commands_.add({"on", "note-on", NOTE_ON, -1, "(note)", "Show Note On, optionally for note (0-127)"}); - commands_.add({"off", "note-off", NOTE_OFF, -1, "(note)", "Show Note Off, optionally for note (0-127)"}); - commands_.add({"pp", "poly-pressure", POLY_PRESSURE, -1, "(note)", "Show Poly Pressure, optionally for note (0-127)"}); - commands_.add({"cc", "control-change", CONTROL_CHANGE, -1, "(number)", "Show Control Change, optionally for controller (0-127)"}); - commands_.add({"pc", "program-change", PROGRAM_CHANGE, -1, "(number)", "Show Program Change, optionally for program (0-127)"}); - commands_.add({"cp", "channel-pressure", CHANNEL_PRESSURE, 0, "", "Show Channel Pressure"}); - commands_.add({"pb", "pitch-bend", PITCH_BEND, 0, "", "Show Pitch Bend"}); - commands_.add({"sr", "system-realtime", SYSTEM_REALTIME, 0, "", "Show all System Real-Time messages"}); - commands_.add({"clock", "", CLOCK, 0, "", "Show Timing Clock"}); - commands_.add({"start", "", START, 0, "", "Show Start"}); - commands_.add({"stop", "", STOP, 0, "", "Show Stop"}); - commands_.add({"cont", "continue", CONTINUE, 0, "", "Show Continue"}); - commands_.add({"as", "active-sensing", ACTIVE_SENSING, 0, "", "Show Active Sensing"}); - commands_.add({"rst", "reset", RESET, 0, "", "Show Reset"}); - commands_.add({"sc", "system-common", SYSTEM_COMMON, 0, "", "Show all System Common messages"}); - commands_.add({"syx", "system-exclusive", SYSTEM_EXCLUSIVE, 0, "", "Show System Exclusive"}); - commands_.add({"tc", "time-code", TIME_CODE, 0, "", "Show MIDI Time Code Quarter Frame"}); - commands_.add({"spp", "song-position", SONG_POSITION, 0, "", "Show Song Position Pointer"}); - commands_.add({"ss", "song-select", SONG_SELECT, 0, "", "Show Song Select"}); - commands_.add({"tun", "tune-request", TUNE_REQUEST, 0, "", "Show Tune Request"}); - commands_.add({"q", "quiet", QUIET, 0, "", "Don't show the received messages on standard output"}); - commands_.add({"js", "javascript", JAVASCRIPT, 1, "code", "Execute this script for each received MIDI message"}); - commands_.add({"jsf", "javascript-file", JAVASCRIPT_FILE, 1, "path", "Execute the script in this file for each message"}); + commands_.add({"dev", "device", DEVICE, 1, "name", "Set the name of the MIDI input port"}); + commands_.add({"virt", "virtual", VIRTUAL, -1, "(name)", "Use virtual MIDI port with optional name (Linux/macOS)"}); + commands_.add({"pass", "pass-through", PASSTHROUGH, 1, "name", "Set name of MIDI output port for MIDI pass-through"}); + commands_.add({"list", "", LIST, 0, "", "Lists the MIDI input ports"}); + commands_.add({"file", "", TXTFILE, 1, "path", "Loads commands from the specified program file"}); + commands_.add({"dec", "decimal", DECIMAL, 0, "", "Interpret the next numbers as decimals by default"}); + commands_.add({"hex", "hexadecimal", HEXADECIMAL, 0, "", "Interpret the next numbers as hexadecimals by default"}); + commands_.add({"ch", "channel", CHANNEL, 1, "number", "Set MIDI channel for the commands (0-16), defaults to 0"}); + commands_.add({"ts", "timestamp", TIMESTAMP, 0, "", "Output a timestamp for each received MIDI message"}); + commands_.add({"nn", "note-numbers", NOTE_NUMBERS, 0, "", "Output notes as numbers instead of names"}); + commands_.add({"omc", "octave-middle-c", OCTAVE_MIDDLE_C, 1, "number", "Set octave for middle C, defaults to 3"}); + commands_.add({"voice", "", VOICE, 0, "", "Show all Channel Voice messages"}); + commands_.add({"note", "", NOTE, 0, "", "Show all Note messages"}); + commands_.add({"on", "note-on", NOTE_ON, -1, "(note)", "Show Note On, optionally for note (0-127)"}); + commands_.add({"off", "note-off", NOTE_OFF, -1, "(note)", "Show Note Off, optionally for note (0-127)"}); + commands_.add({"pp", "poly-pressure", POLY_PRESSURE, -1, "(note)", "Show Poly Pressure, optionally for note (0-127)"}); + commands_.add({"cc", "control-change", CONTROL_CHANGE, -1, "(number)", "Show Control Change, optionally for controller (0-127)"}); + commands_.add({"cc14", "control-change-14", CONTROL_CHANGE_14BIT, -1, "(number)", "Show 14-bit CC, optionally for controller (0-63)"}); + commands_.add({"nrpn", "", NRPN, -1, "(number)", "Show NRPN, optionally for parameter (0-16383)"}); + commands_.add({"nrpnf", "nrpn-full", NRPN_FULL, -1, "(number)", "Show full NRPN (MSB+LSB), optionally for parameter (0-16383)"}); + commands_.add({"rpn", "", RPN, -1, "(number)", "Show RPN, optionally for parameter (0-16383)"}); + commands_.add({"rpnf", "rpn-full", RPN_FULL, -1, "(number)", "Show full RPN (MSB+LSB), optionally for parameter (0-16383)"}); + commands_.add({"pc", "program-change", PROGRAM_CHANGE, -1, "(number)", "Show Program Change, optionally for program (0-127)"}); + commands_.add({"cp", "channel-pressure", CHANNEL_PRESSURE, 0, "", "Show Channel Pressure"}); + commands_.add({"pb", "pitch-bend", PITCH_BEND, 0, "", "Show Pitch Bend"}); + commands_.add({"sr", "system-realtime", SYSTEM_REALTIME, 0, "", "Show all System Real-Time messages"}); + commands_.add({"clock", "", CLOCK, 0, "", "Show Timing Clock"}); + commands_.add({"start", "", START, 0, "", "Show Start"}); + commands_.add({"stop", "", STOP, 0, "", "Show Stop"}); + commands_.add({"cont", "continue", CONTINUE, 0, "", "Show Continue"}); + commands_.add({"as", "active-sensing", ACTIVE_SENSING, 0, "", "Show Active Sensing"}); + commands_.add({"rst", "reset", RESET, 0, "", "Show Reset"}); + commands_.add({"sc", "system-common", SYSTEM_COMMON, 0, "", "Show all System Common messages"}); + commands_.add({"syx", "system-exclusive", SYSTEM_EXCLUSIVE, 0, "", "Show System Exclusive"}); + commands_.add({"tc", "time-code", TIME_CODE, 0, "", "Show MIDI Time Code Quarter Frame"}); + commands_.add({"spp", "song-position", SONG_POSITION, 0, "", "Show Song Position Pointer"}); + commands_.add({"ss", "song-select", SONG_SELECT, 0, "", "Show Song Select"}); + commands_.add({"tun", "tune-request", TUNE_REQUEST, 0, "", "Show Tune Request"}); + commands_.add({"q", "quiet", QUIET, 0, "", "Don't show the received messages on standard output"}); + commands_.add({"js", "javascript", JAVASCRIPT, 1, "code", "Execute this script for each received MIDI message"}); + commands_.add({"jsf", "javascript-file", JAVASCRIPT_FILE, 1, "path", "Execute the script in this file for each message"}); timestampOutput_ = false; noteNumbersOutput_ = false; @@ -146,6 +157,14 @@ class receiveMidiApplication : public JUCEApplicationBase, public MidiInputCall useHexadecimalsByDefault_ = false; quiet_ = false; currentCommand_ = ApplicationCommand::Dummy(); + // initialize last CC MSB values + for (int ch = 0; ch < 16; ++ch) + { + for (int cc = 0; cc < 128; ++cc) + { + lastCC_[ch][cc] = -1; + } + } } const String getApplicationName() override { return ProjectInfo::projectName; } @@ -337,10 +356,19 @@ class receiveMidiApplication : public JUCEApplicationBase, public MidiInputCall void handleIncomingMidiMessage(MidiInput*, const MidiMessage& msg) override { + bool display_control_change = true; + bool display_control_change_14bit = false; + bool display_nrpn = false; + bool display_rpn = false; + if (!filterCommands_.isEmpty()) { + // handle individual commands bool filtered = false; int channel = 0; + display_control_change = false; + display_control_change_14bit = false; + for (ApplicationCommand& cmd : filterCommands_) { switch (cmd.command_) @@ -373,9 +401,75 @@ class receiveMidiApplication : public JUCEApplicationBase, public MidiInputCall (cmd.opts_.isEmpty() || (msg.getNoteNumber() == asNoteNumber(cmd.opts_[0]))); break; case CONTROL_CHANGE: - filtered |= checkChannel(msg, channel) && + display_control_change = checkChannel(msg, channel) && msg.isController() && (cmd.opts_.isEmpty() || (msg.getControllerNumber() == asDecOrHex7BitValue(cmd.opts_[0]))); + filtered |= display_control_change; + break; + case CONTROL_CHANGE_14BIT: + if (checkChannel(msg, channel) && + msg.isController() && + msg.getControllerNumber() < 64 && + (cmd.opts_.isEmpty() || (msg.getControllerNumber() == asDecOrHex7BitValue(cmd.opts_[0])))) + { + uint8 ch = msg.getChannel() - 1; + uint8 cc = msg.getControllerNumber(); + uint8 v = msg.getControllerValue(); + uint8 prev_v = lastCC_[ch][cc]; + lastCC_[ch][cc] = v; + + // handle 14-bit MIDI CC values as appropriate + if (cc < 32) + { + // only trigger an MSB-initiated change when its value is different than before + // if it's the same, wait for the LSB to trigger the change + if (v != prev_v) + { + uint8 lsb_cc = cc + 32; + lastCC_[ch][lsb_cc] = 0; + display_control_change_14bit = true; + } + } + // handle 14-bit MIDI CC LSB values + else if (cc >= 32 && cc < 64) + { + uint8 msb_cc = cc - 32; + char msb = lastCC_[ch][msb_cc]; + if (msb >= 0) + { + display_control_change_14bit = true; + } + } + } + + display_control_change = display_control_change_14bit; + filtered |= display_control_change; + break; + case NRPN: + case NRPN_FULL: + if (checkChannel(msg, channel) && msg.isController()) + { + if (rpnDetector_.parseControllerMessage(msg.getChannel(), msg.getControllerNumber(), msg.getControllerValue(), rpnMsg_)) + { + display_nrpn = rpnMsg_.isNRPN && + (cmd.command_ == NRPN || (cmd.command_ == NRPN_FULL && rpnMsg_.usesBothMSBandLSB)) && + (cmd.opts_.isEmpty() || (rpnMsg_.parameterNumber == asDecOrHex14BitValue(cmd.opts_[0]))); + filtered |= display_nrpn; + } + } + break; + case RPN: + case RPN_FULL: + if (checkChannel(msg, channel) && msg.isController()) + { + if (rpnDetector_.parseControllerMessage(msg.getChannel(), msg.getControllerNumber(), msg.getControllerValue(), rpnMsg_)) + { + display_rpn = !rpnMsg_.isNRPN && + (cmd.command_ == RPN || (cmd.command_ == RPN_FULL && rpnMsg_.usesBothMSBandLSB)) && + (cmd.opts_.isEmpty() || (rpnMsg_.parameterNumber == asDecOrHex14BitValue(cmd.opts_[0]))); + filtered |= display_rpn; + } + } break; case PROGRAM_CHANGE: filtered |= checkChannel(msg, channel) && @@ -459,11 +553,11 @@ class receiveMidiApplication : public JUCEApplicationBase, public MidiInputCall if (!quiet_) { - outputMessage(msg); + outputMessage(msg, display_control_change, display_control_change_14bit, display_nrpn, display_rpn); } } - void outputMessage(const MidiMessage& msg) + void outputMessage(const MidiMessage& msg, bool displayControlChange, bool displayControlChange14Bit, bool displayNrpn, bool displayRpn) { if (timestampOutput_) { @@ -491,9 +585,42 @@ class receiveMidiApplication : public JUCEApplicationBase, public MidiInputCall } else if (msg.isController()) { - std::cout << "channel " << outputChannel(msg) << " " << - "control-change " << output7Bit(msg.getControllerNumber()).paddedLeft(' ', 3) << " " - << output7Bit(msg.getControllerValue()).paddedLeft(' ', 3) << std::endl; + if (displayControlChange) + { + if (displayControlChange14Bit) + { + uint8 msb_cc = msg.getControllerNumber(); + if (msb_cc >= 32) + { + msb_cc -= 32; + } + uint8 lsb_cc = msb_cc + 32; + uint8 ch = msg.getChannel() - 1; + uint16 v = ((lastCC_[ch][msb_cc] & 0x7f) << 7) | (lastCC_[ch][lsb_cc] & 0x7f); + std::cout << "channel " << outputChannel(msg) << " " << + "cc-14 " << output7Bit(msb_cc).paddedLeft(' ', 3) << " " + << output14Bit(v).paddedLeft(' ', 5) << std::endl; + } + else + { + std::cout << "channel " << outputChannel(msg) << " " << + "control-change " << output7Bit(msg.getControllerNumber()).paddedLeft(' ', 3) << " " + << output7Bit(msg.getControllerValue()).paddedLeft(' ', 3) << std::endl; + } + } + + if (displayNrpn) + { + std::cout << "channel " << outputChannel(msg) << " " << + "nrpn " << output14Bit(rpnMsg_.parameterNumber).paddedLeft(' ', 5) << " " + << output14Bit(rpnMsg_.value).paddedLeft(' ', 5) << std::endl; + } + else if (displayRpn) + { + std::cout << "channel " << outputChannel(msg) << " " << + "rpn " << output14Bit(rpnMsg_.parameterNumber).paddedLeft(' ', 5) << " " + << output14Bit(rpnMsg_.value).paddedLeft(' ', 5) << std::endl; + } } else if (msg.isProgramChange()) { @@ -627,7 +754,7 @@ class receiveMidiApplication : public JUCEApplicationBase, public MidiInputCall bool tryToConnectMidiInput() { - MidiInput* midi_input = nullptr; + std::unique_ptr midi_input = nullptr; String midi_input_name; int index = MidiInput::getDevices().indexOf(midiInName_); @@ -653,7 +780,7 @@ class receiveMidiApplication : public JUCEApplicationBase, public MidiInputCall if (midi_input) { midi_input->start(); - midiIn_ = midi_input; + midiIn_.swap(midi_input); fullMidiInName_ = midi_input_name; return true; } @@ -888,18 +1015,18 @@ class receiveMidiApplication : public JUCEApplicationBase, public MidiInputCall std::cout << " " << cmd.param_.paddedRight(' ', 5); if (cmd.optionsDescription_.isNotEmpty()) { - std::cout << " " << cmd.optionsDescription_.paddedRight(' ', 13); + std::cout << " " << cmd.optionsDescription_.paddedRight(' ', 9); } else { - std::cout << " "; + std::cout << " "; } std::cout << " " << cmd.commandDescription_; std::cout << std::endl; } - std::cout << " -h or --help Print Help (this message) and exit" << std::endl; - std::cout << " --version Print version information and exit" << std::endl; - std::cout << " -- Read commands from standard input until it's closed" << std::endl; + std::cout << " -h or --help Print Help (this message) and exit" << std::endl; + std::cout << " --version Print version information and exit" << std::endl; + std::cout << " -- Read commands from standard input until it's closed" << std::endl; std::cout << std::endl; std::cout << "Alternatively, you can use the following long versions of the commands:" << std::endl; String line = " "; @@ -943,14 +1070,17 @@ class receiveMidiApplication : public JUCEApplicationBase, public MidiInputCall bool useHexadecimalsByDefault_; bool quiet_; String midiInName_; - ScopedPointer midiIn_; + std::unique_ptr midiIn_; String fullMidiInName_; String midiOutName_; - ScopedPointer midiOut_; + std::unique_ptr midiOut_; ApplicationCommand currentCommand_; JavascriptEngine scriptEngine_; String scriptCode_; ScriptMidiMessageClass* scriptMidiMessage_; + RPNDetector rpnDetector_; + RPNMessage rpnMsg_; + uint8 lastCC_[16][128]; }; START_JUCE_APPLICATION (receiveMidiApplication) diff --git a/Source/MidiRPN.cpp b/Source/MidiRPN.cpp new file mode 100644 index 0000000..36f4175 --- /dev/null +++ b/Source/MidiRPN.cpp @@ -0,0 +1,121 @@ +/* + ============================================================================== + + 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. + + ============================================================================== +*/ + +//============================================================================== +/** This is derived from JUCE's MidiRPNMessage classes and tweaks it for more + appropriate behavior. + */ +//============================================================================== + +#include "MidiRPN.h" + +RPNDetector::RPNDetector() noexcept +{ +} + +RPNDetector::~RPNDetector() noexcept +{ +} + +bool RPNDetector::parseControllerMessage (int midiChannel, + int controllerNumber, + int controllerValue, + RPNMessage& result) noexcept +{ + jassert (midiChannel >= 1 && midiChannel <= 16); + jassert (controllerNumber >= 0 && controllerNumber < 128); + jassert (controllerValue >= 0 && controllerValue < 128); + + return states[midiChannel - 1].handleController (midiChannel, controllerNumber, controllerValue, result); +} + +void RPNDetector::reset() noexcept +{ + for (int i = 0; i < 16; ++i) + { + states[i].parameterMSB = 0xff; + states[i].parameterLSB = 0xff; + states[i].resetValue(); + states[i].isNRPN = false; + } +} + +//============================================================================== +RPNDetector::ChannelState::ChannelState() noexcept + : parameterMSB (0xff), parameterLSB (0xff), valueMSB (0xff), valueLSB (0xff), isNRPN (false) +{ +} + +bool RPNDetector::ChannelState::handleController (int channel, + int controllerNumber, + int value, + RPNMessage& result) noexcept +{ + switch (controllerNumber) + { + case 0x62: parameterLSB = uint8 (value); resetValue(); isNRPN = true; break; + case 0x63: parameterMSB = uint8 (value); resetValue(); isNRPN = true; break; + + case 0x64: parameterLSB = uint8 (value); resetValue(); isNRPN = false; break; + case 0x65: parameterMSB = uint8 (value); resetValue(); isNRPN = false; break; + + case 0x06: valueMSB = uint8 (value); valueLSB = 0xff; return sendIfReady (channel, result); + case 0x26: valueLSB = uint8 (value); return sendIfReady (channel, result); + + default: break; + } + + return false; +} + +void RPNDetector::ChannelState::resetValue() noexcept +{ + valueMSB = 0xff; + valueLSB = 0xff; +} + +//============================================================================== +bool RPNDetector::ChannelState::sendIfReady (int channel, RPNMessage& result) noexcept +{ + if (parameterMSB < 0x80 && parameterLSB < 0x80) + { + if (valueMSB < 0x80) + { + result.channel = channel; + result.parameterNumber = (parameterMSB << 7) + parameterLSB; + result.isNRPN = isNRPN; + + result.value = (valueMSB << 7); + result.usesBothMSBandLSB = false; + + if (valueLSB < 0x80) + { + result.value += valueLSB; + result.usesBothMSBandLSB = true; + } + + return true; + } + } + + return false; +} diff --git a/Source/MidiRPN.h b/Source/MidiRPN.h new file mode 100644 index 0000000..2bc2d24 --- /dev/null +++ b/Source/MidiRPN.h @@ -0,0 +1,116 @@ +/* + ============================================================================== + + 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. + + ============================================================================== +*/ + +#include "JuceHeader.h" + +//============================================================================== +/** This is derived from JUCE's MidiRPNMessage classes and tweaks it for more + appropriate behavior. + */ +//============================================================================== + + +//============================================================================== +/** Represents a MIDI RPN (registered parameter number) or NRPN (non-registered + parameter number) message. + + @tags{Audio} +*/ +struct RPNMessage +{ + /** Midi channel of the message, in the range 1 to 16. */ + int channel; + + /** The 14-bit parameter index, in the range 0 to 16383 (0x3fff). */ + int parameterNumber; + + /** The parameter value, in the range 0 to 16383 (0x3fff). + If the message contains no value LSB, the value will be in the range + 0 to 127 (0x7f). + */ + int value; + + /** True if this message is an NRPN; false if it is an RPN. */ + bool isNRPN; + + /** True if both MSB and LSB are used. */ + bool usesBothMSBandLSB; +}; + +//============================================================================== +/** + Parses a stream of MIDI data to assemble RPN and NRPN messages from their + constituent MIDI CC messages. + + The detector uses the following parsing rules: the parameter number + LSB/MSB can be sent/received in either order and must both come before the + parameter value; for the parameter value, LSB always has to be sent/received + before the value MSB, otherwise it will be treated as 7-bit (MSB only). + + @tags{Audio} +*/ +class RPNDetector +{ +public: + /** Constructor. */ + RPNDetector() noexcept; + + /** Destructor. */ + ~RPNDetector() noexcept; + + /** Resets the RPN detector's internal state, so that it forgets about + previously received MIDI CC messages. + */ + void reset() noexcept; + + //============================================================================== + /** Takes the next in a stream of incoming MIDI CC messages and returns true + if it forms the last of a sequence that makes an RPN or NPRN. + + If this returns true, then the RPNMessage object supplied will be + filled-out with the message's details. + (If it returns false then the RPNMessage object will be unchanged). + */ + bool parseControllerMessage (int midiChannel, + int controllerNumber, + int controllerValue, + RPNMessage& result) noexcept; + +private: + //============================================================================== + struct ChannelState + { + ChannelState() noexcept; + bool handleController (int channel, int controllerNumber, + int value, RPNMessage&) noexcept; + void resetValue() noexcept; + bool sendIfReady (int channel, RPNMessage&) noexcept; + + uint8 parameterMSB, parameterLSB, valueMSB, valueLSB; + bool isNRPN; + }; + + //============================================================================== + ChannelState states[16]; + + JUCE_LEAK_DETECTOR (RPNDetector) +}; diff --git a/receivemidi.jucer b/receivemidi.jucer index 04a157f..aab443f 100644 --- a/receivemidi.jucer +++ b/receivemidi.jucer @@ -2,12 +2,14 @@ + companyName="Uwyn" companyWebsite="http://www.uwyn.com" companyEmail="info@uwyn.com" + displaySplashScreen="1" reportAppUsage="1" splashScreenColour="Dark" + jucerFormatVersion="1"> + +