Upgraded to JUCE 3.2. Added Dexed_data user direcotry and fixed Linux display issues.

pull/1/head
asb2m10 9 years ago
parent 39d3c28853
commit b2517b47dd
  1. 16
      Builds/Linux/Makefile
  2. 5215
      Builds/MacOSX/Dexed.xcodeproj/project.pbxproj
  3. BIN
      Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate
  4. 25
      Builds/VisualStudio2012/Dexed.vcxproj
  5. 27
      Builds/VisualStudio2012/Dexed.vcxproj.filters
  6. 6
      Dexed.jucer
  7. 13
      JuceLibraryCode/AppConfig.h
  8. 2
      JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp
  9. 44
      JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h
  10. 9
      JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.cpp
  11. 2
      JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h
  12. 292
      JuceLibraryCode/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp
  13. 44
      JuceLibraryCode/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h
  14. 2
      JuceLibraryCode/modules/juce_audio_basics/effects/juce_Decibels.h
  15. 277
      JuceLibraryCode/modules/juce_audio_basics/effects/juce_FFT.cpp
  16. 92
      JuceLibraryCode/modules/juce_audio_basics/effects/juce_FFT.h
  17. 8
      JuceLibraryCode/modules/juce_audio_basics/effects/juce_IIRFilter.cpp
  18. 2
      JuceLibraryCode/modules/juce_audio_basics/effects/juce_IIRFilter.h
  19. 12
      JuceLibraryCode/modules/juce_audio_basics/effects/juce_LagrangeInterpolator.cpp
  20. 2
      JuceLibraryCode/modules/juce_audio_basics/effects/juce_LagrangeInterpolator.h
  21. 137
      JuceLibraryCode/modules/juce_audio_basics/effects/juce_Reverb.h
  22. 6
      JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.cpp
  23. 6
      JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.h
  24. 2
      JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.mm
  25. 2
      JuceLibraryCode/modules/juce_audio_basics/juce_module_info
  26. 10
      JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiBuffer.cpp
  27. 2
      JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiBuffer.h
  28. 2
      JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiFile.cpp
  29. 2
      JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiFile.h
  30. 4
      JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiKeyboardState.cpp
  31. 2
      JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiKeyboardState.h
  32. 2
      JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.cpp
  33. 2
      JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessage.h
  34. 38
      JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp
  35. 4
      JuceLibraryCode/modules/juce_audio_basics/midi/juce_MidiMessageSequence.h
  36. 2
      JuceLibraryCode/modules/juce_audio_basics/sources/juce_AudioSource.h
  37. 2
      JuceLibraryCode/modules/juce_audio_basics/sources/juce_BufferingAudioSource.cpp
  38. 2
      JuceLibraryCode/modules/juce_audio_basics/sources/juce_BufferingAudioSource.h
  39. 2
      JuceLibraryCode/modules/juce_audio_basics/sources/juce_ChannelRemappingAudioSource.cpp
  40. 2
      JuceLibraryCode/modules/juce_audio_basics/sources/juce_ChannelRemappingAudioSource.h
  41. 2
      JuceLibraryCode/modules/juce_audio_basics/sources/juce_IIRFilterAudioSource.cpp
  42. 2
      JuceLibraryCode/modules/juce_audio_basics/sources/juce_IIRFilterAudioSource.h
  43. 2
      JuceLibraryCode/modules/juce_audio_basics/sources/juce_MixerAudioSource.cpp
  44. 2
      JuceLibraryCode/modules/juce_audio_basics/sources/juce_MixerAudioSource.h
  45. 2
      JuceLibraryCode/modules/juce_audio_basics/sources/juce_PositionableAudioSource.h
  46. 18
      JuceLibraryCode/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp
  47. 2
      JuceLibraryCode/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.h
  48. 2
      JuceLibraryCode/modules/juce_audio_basics/sources/juce_ReverbAudioSource.cpp
  49. 2
      JuceLibraryCode/modules/juce_audio_basics/sources/juce_ReverbAudioSource.h
  50. 2
      JuceLibraryCode/modules/juce_audio_basics/sources/juce_ToneGeneratorAudioSource.cpp
  51. 2
      JuceLibraryCode/modules/juce_audio_basics/sources/juce_ToneGeneratorAudioSource.h
  52. 200
      JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp
  53. 70
      JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h
  54. 2
      JuceLibraryCode/modules/juce_audio_devices/audio_cd/juce_AudioCDBurner.h
  55. 2
      JuceLibraryCode/modules/juce_audio_devices/audio_cd/juce_AudioCDReader.cpp
  56. 2
      JuceLibraryCode/modules/juce_audio_devices/audio_cd/juce_AudioCDReader.h
  57. 36
      JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp
  58. 3
      JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h
  59. 2
      JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODevice.cpp
  60. 2
      JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODevice.h
  61. 4
      JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.cpp
  62. 4
      JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h
  63. 2
      JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_SystemAudioVolume.h
  64. 4
      JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.cpp
  65. 13
      JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.h
  66. 2
      JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.mm
  67. 2
      JuceLibraryCode/modules/juce_audio_devices/juce_module_info
  68. 16
      JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiInput.h
  69. 2
      JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.cpp
  70. 2
      JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.h
  71. 2
      JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiOutput.cpp
  72. 31
      JuceLibraryCode/modules/juce_audio_devices/midi_io/juce_MidiOutput.h
  73. 2
      JuceLibraryCode/modules/juce_audio_devices/native/juce_MidiDataConcatenator.h
  74. 2
      JuceLibraryCode/modules/juce_audio_devices/native/juce_android_Audio.cpp
  75. 2
      JuceLibraryCode/modules/juce_audio_devices/native/juce_android_Midi.cpp
  76. 14
      JuceLibraryCode/modules/juce_audio_devices/native/juce_android_OpenSL.cpp
  77. 2
      JuceLibraryCode/modules/juce_audio_devices/native/juce_ios_Audio.cpp
  78. 92
      JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_ALSA.cpp
  79. 2
      JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_AudioCDReader.cpp
  80. 2
      JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_JackAudio.cpp
  81. 31
      JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_Midi.cpp
  82. 2
      JuceLibraryCode/modules/juce_audio_devices/native/juce_mac_AudioCDBurner.mm
  83. 2
      JuceLibraryCode/modules/juce_audio_devices/native/juce_mac_AudioCDReader.mm
  84. 12
      JuceLibraryCode/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp
  85. 72
      JuceLibraryCode/modules/juce_audio_devices/native/juce_mac_CoreMidi.cpp
  86. 116
      JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_ASIO.cpp
  87. 2
      JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_AudioCDBurner.cpp
  88. 2
      JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_AudioCDReader.cpp
  89. 8
      JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_DirectSound.cpp
  90. 18
      JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_Midi.cpp
  91. 494
      JuceLibraryCode/modules/juce_audio_devices/native/juce_win32_WASAPI.cpp
  92. 2
      JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioSourcePlayer.cpp
  93. 2
      JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioSourcePlayer.h
  94. 2
      JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp
  95. 2
      JuceLibraryCode/modules/juce_audio_devices/sources/juce_AudioTransportSource.h
  96. 2
      JuceLibraryCode/modules/juce_audio_formats/codecs/flac/all.h
  97. 4
      JuceLibraryCode/modules/juce_audio_formats/codecs/flac/alloc.h
  98. 2
      JuceLibraryCode/modules/juce_audio_formats/codecs/flac/assert.h
  99. 2
      JuceLibraryCode/modules/juce_audio_formats/codecs/flac/callback.h
  100. 35
      JuceLibraryCode/modules/juce_audio_formats/codecs/flac/compat.h
  101. Some files were not shown because too many files have changed in this diff Show More

@ -20,10 +20,9 @@ ifeq ($(CONFIG),Debug)
CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -D "JUCER_LINUX_MAKE_7346DA2A=1" -D "JUCE_APP_VERSION=1.0.0" -D "JUCE_APP_VERSION_HEX=0x10000" -I /usr/include -I /usr/include/freetype2 -I ~/src/vstsdk2.4 -I ../../JuceLibraryCode -I ../../JuceLibraryCode/modules
CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -g -ggdb -fPIC -O0
CXXFLAGS += $(CFLAGS)
LDFLAGS += $(TARGET_ARCH) -L$(BINDIR) -L$(LIBDIR) -shared -L/usr/X11R6/lib/ -lX11 -lXext -lXinerama -lasound -ldl -lfreetype -lpthread -lrt
LDDEPS :=
RESFLAGS := -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -D "JUCER_LINUX_MAKE_7346DA2A=1" -D "JUCE_APP_VERSION=1.0.0" -D "JUCE_APP_VERSION_HEX=0x10000" -I /usr/include -I /usr/include/freetype2 -I ~/src/vstsdk2.4 -I ../../JuceLibraryCode -I ../../JuceLibraryCode/modules
CXXFLAGS += $(CFLAGS) -std=c++11
LDFLAGS += $(TARGET_ARCH) -L$(BINDIR) -L$(LIBDIR) -Wl,--no-undefined -shared -L/usr/X11R6/lib/ -lX11 -lXext -lXinerama -lasound -ldl -lfreetype -lpthread -lrt
TARGET := Dexed.so
BLDCMD = $(CXX) -o $(OUTDIR)/$(TARGET) $(OBJECTS) $(LDFLAGS) $(RESOURCES) $(TARGET_ARCH)
CLEANCMD = rm -rf $(OUTDIR)/$(TARGET) $(OBJDIR)
@ -41,10 +40,9 @@ ifeq ($(CONFIG),Release)
CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "NDEBUG=1" -D "JUCER_LINUX_MAKE_7346DA2A=1" -D "JUCE_APP_VERSION=1.0.0" -D "JUCE_APP_VERSION_HEX=0x10000" -I /usr/include -I /usr/include/freetype2 -I ~/src/vstsdk2.4 -I ../../JuceLibraryCode -I ../../JuceLibraryCode/modules
CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -fPIC -Os
CXXFLAGS += $(CFLAGS)
LDFLAGS += $(TARGET_ARCH) -L$(BINDIR) -L$(LIBDIR) -shared -fvisibility=hidden -L/usr/X11R6/lib/ -lX11 -lXext -lXinerama -lasound -ldl -lfreetype -lpthread -lrt
LDDEPS :=
RESFLAGS := -D "LINUX=1" -D "NDEBUG=1" -D "JUCER_LINUX_MAKE_7346DA2A=1" -D "JUCE_APP_VERSION=1.0.0" -D "JUCE_APP_VERSION_HEX=0x10000" -I /usr/include -I /usr/include/freetype2 -I ~/src/vstsdk2.4 -I ../../JuceLibraryCode -I ../../JuceLibraryCode/modules
CXXFLAGS += $(CFLAGS) -std=c++11
LDFLAGS += $(TARGET_ARCH) -L$(BINDIR) -L$(LIBDIR) -Wl,--no-undefined -shared -fvisibility=hidden -L/usr/X11R6/lib/ -lX11 -lXext -lXinerama -lasound -ldl -lfreetype -lpthread -lrt
TARGET := Dexed.so
BLDCMD = $(CXX) -o $(OUTDIR)/$(TARGET) $(OBJECTS) $(LDFLAGS) $(RESOURCES) $(TARGET_ARCH)
CLEANCMD = rm -rf $(OUTDIR)/$(TARGET) $(OBJDIR)
@ -94,7 +92,7 @@ OBJECTS := \
.PHONY: clean
$(OUTDIR)/$(TARGET): $(OBJECTS) $(LDDEPS) $(RESOURCES)
$(OUTDIR)/$(TARGET): $(OBJECTS) $(RESOURCES)
@echo Linking Dexed
-@mkdir -p $(BINDIR)
-@mkdir -p $(LIBDIR)

File diff suppressed because it is too large Load Diff

@ -38,10 +38,8 @@
</PropertyGroup>
<PropertyGroup>
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\</OutDir>
<TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Dexed</TargetName>
<GenerateManifest Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</GenerateManifest>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\Release\</OutDir>
<TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Dexed</TargetName>
<GenerateManifest Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</GenerateManifest>
<PlatformToolset>v110</PlatformToolset>
@ -58,7 +56,7 @@
<Optimization>Disabled</Optimization>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;C:\work\vstsdk2.4;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2012_78A501F=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2012_78A501F=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<PrecompiledHeader/>
@ -100,7 +98,7 @@
<ClCompile>
<Optimization>MinSpace</Optimization>
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;C:\work\vstsdk2.4;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;JUCER_VS2012_78A501F=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2012_78A501F=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<PrecompiledHeader/>
@ -182,6 +180,9 @@
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_basics\midi\juce_MidiMessageSequence.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_basics\effects\juce_FFT.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_basics\effects\juce_IIRFilter.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
@ -251,6 +252,9 @@
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_processors\scanning\juce_PluginListComponent.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_utils\gui\juce_AudioAppComponent.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_utils\gui\juce_AudioDeviceSelectorComponent.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
@ -458,6 +462,9 @@
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_core\native\juce_android_Threads.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_core\native\juce_curl_Network.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_core\native\juce_linux_CommonFile.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
@ -497,6 +504,9 @@
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_data_structures\values\juce_ValueTree.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_data_structures\values\juce_ValueTreeSynchroniser.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_data_structures\undomanager\juce_UndoManager.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
@ -1031,6 +1041,9 @@
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_extra\documents\juce_FileBasedDocument.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_extra\misc\juce_AnimatedAppComponent.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_extra\misc\juce_BubbleMessageComponent.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
@ -1148,6 +1161,7 @@
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_audio_basics\midi\juce_MidiMessage.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_audio_basics\midi\juce_MidiMessageSequence.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_audio_basics\effects\juce_Decibels.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_audio_basics\effects\juce_FFT.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_audio_basics\effects\juce_IIRFilter.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_audio_basics\effects\juce_LagrangeInterpolator.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_audio_basics\effects\juce_Reverb.h"/>
@ -1193,6 +1207,7 @@
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_audio_processors\scanning\juce_PluginDirectoryScanner.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_audio_processors\scanning\juce_PluginListComponent.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_audio_processors\juce_audio_processors.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_audio_utils\gui\juce_AudioAppComponent.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_audio_utils\gui\juce_AudioDeviceSelectorComponent.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_audio_utils\gui\juce_AudioThumbnail.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_audio_utils\gui\juce_AudioThumbnailBase.h"/>
@ -1315,6 +1330,7 @@
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_core\juce_core.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_data_structures\values\juce_Value.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_data_structures\values\juce_ValueTree.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_data_structures\values\juce_ValueTreeSynchroniser.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_data_structures\undomanager\juce_UndoableAction.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_data_structures\undomanager\juce_UndoManager.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_data_structures\app_properties\juce_ApplicationProperties.h"/>
@ -1521,6 +1537,7 @@
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_gui_extra\embedding\juce_ActiveXControlComponent.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_gui_extra\embedding\juce_NSViewComponent.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_gui_extra\embedding\juce_UIViewComponent.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_gui_extra\misc\juce_AnimatedAppComponent.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_gui_extra\misc\juce_AppleRemote.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_gui_extra\misc\juce_BubbleMessageComponent.h"/>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_gui_extra\misc\juce_ColourSelector.h"/>

@ -376,6 +376,9 @@
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_basics\midi\juce_MidiMessageSequence.cpp">
<Filter>Juce Modules\juce_audio_basics\midi</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_basics\effects\juce_FFT.cpp">
<Filter>Juce Modules\juce_audio_basics\effects</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_basics\effects\juce_IIRFilter.cpp">
<Filter>Juce Modules\juce_audio_basics\effects</Filter>
</ClCompile>
@ -463,6 +466,9 @@
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_processors\scanning\juce_PluginListComponent.cpp">
<Filter>Juce Modules\juce_audio_processors\scanning</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_utils\gui\juce_AudioAppComponent.cpp">
<Filter>Juce Modules\juce_audio_utils\gui</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_utils\gui\juce_AudioDeviceSelectorComponent.cpp">
<Filter>Juce Modules\juce_audio_utils\gui</Filter>
</ClCompile>
@ -670,6 +676,9 @@
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_core\native\juce_android_Threads.cpp">
<Filter>Juce Modules\juce_core\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_core\native\juce_curl_Network.cpp">
<Filter>Juce Modules\juce_core\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_core\native\juce_linux_CommonFile.cpp">
<Filter>Juce Modules\juce_core\native</Filter>
</ClCompile>
@ -724,6 +733,9 @@
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_data_structures\values\juce_ValueTree.cpp">
<Filter>Juce Modules\juce_data_structures\values</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_data_structures\values\juce_ValueTreeSynchroniser.cpp">
<Filter>Juce Modules\juce_data_structures\values</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_data_structures\undomanager\juce_UndoManager.cpp">
<Filter>Juce Modules\juce_data_structures\undomanager</Filter>
</ClCompile>
@ -1291,6 +1303,9 @@
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_extra\documents\juce_FileBasedDocument.cpp">
<Filter>Juce Modules\juce_gui_extra\documents</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_extra\misc\juce_AnimatedAppComponent.cpp">
<Filter>Juce Modules\juce_gui_extra\misc</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_extra\misc\juce_BubbleMessageComponent.cpp">
<Filter>Juce Modules\juce_gui_extra\misc</Filter>
</ClCompile>
@ -1530,6 +1545,9 @@
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_audio_basics\effects\juce_Decibels.h">
<Filter>Juce Modules\juce_audio_basics\effects</Filter>
</ClInclude>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_audio_basics\effects\juce_FFT.h">
<Filter>Juce Modules\juce_audio_basics\effects</Filter>
</ClInclude>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_audio_basics\effects\juce_IIRFilter.h">
<Filter>Juce Modules\juce_audio_basics\effects</Filter>
</ClInclude>
@ -1665,6 +1683,9 @@
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_audio_processors\juce_audio_processors.h">
<Filter>Juce Modules\juce_audio_processors</Filter>
</ClInclude>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_audio_utils\gui\juce_AudioAppComponent.h">
<Filter>Juce Modules\juce_audio_utils\gui</Filter>
</ClInclude>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_audio_utils\gui\juce_AudioDeviceSelectorComponent.h">
<Filter>Juce Modules\juce_audio_utils\gui</Filter>
</ClInclude>
@ -2031,6 +2052,9 @@
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_data_structures\values\juce_ValueTree.h">
<Filter>Juce Modules\juce_data_structures\values</Filter>
</ClInclude>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_data_structures\values\juce_ValueTreeSynchroniser.h">
<Filter>Juce Modules\juce_data_structures\values</Filter>
</ClInclude>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_data_structures\undomanager\juce_UndoableAction.h">
<Filter>Juce Modules\juce_data_structures\undomanager</Filter>
</ClInclude>
@ -2649,6 +2673,9 @@
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_gui_extra\embedding\juce_UIViewComponent.h">
<Filter>Juce Modules\juce_gui_extra\embedding</Filter>
</ClInclude>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_gui_extra\misc\juce_AnimatedAppComponent.h">
<Filter>Juce Modules\juce_gui_extra\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\JuceLibraryCode\modules\juce_gui_extra\misc\juce_AppleRemote.h">
<Filter>Juce Modules\juce_gui_extra\misc</Filter>
</ClInclude>

@ -8,7 +8,7 @@
pluginWantsMidiIn="1" pluginProducesMidiOut="0" pluginSilenceInIsSilenceOut="0"
pluginEditorRequiresKeys="0" pluginAUExportPrefix="DexedAU" pluginRTASCategory=""
aaxIdentifier="com.yourcompany.Dexed" pluginAAXCategory="AAX_ePlugInCategory_Dynamics"
jucerVersion="3.1.0" companyName="Digital Suburban" buildVST3="0"
jucerVersion="3.2.0" companyName="Digital Suburban" buildVST3="0"
buildRTAS="0" buildAAX="0" pluginManufacturerEmail="support@yourcompany.com">
<MAINGROUP id="kHXTgw" name="Dexed">
<GROUP id="{F12593AE-639A-6F59-5819-ACE25AF86F95}" name="Resources">
@ -110,11 +110,11 @@
</MAINGROUP>
<EXPORTFORMATS>
<XCODE_MAC targetFolder="Builds/MacOSX" vstFolder="~/Documents/src/vstsdk2.4"
postbuildCommand="&#13;&#10;# This script takes the build product and copies it to the AU, VST, and RTAS folders, depending on &#13;&#10;# which plugin types you've built&#13;&#10;&#13;&#10;original=$CONFIGURATION_BUILD_DIR/$FULL_PRODUCT_NAME&#13;&#10;&#13;&#10;# this looks inside the binary to detect which platforms are needed.. &#13;&#10;copyAU=&#96;nm -g &quot;$CONFIGURATION_BUILD_DIR/$EXECUTABLE_PATH&quot; | grep -i 'AudioUnit' | wc -l&#96;&#13;&#10;copyVST=&#96;nm -g &quot;$CONFIGURATION_BUILD_DIR/$EXECUTABLE_PATH&quot; | grep -i 'VSTPlugin' | wc -l&#96;&#13;&#10;copyRTAS=&#96;nm -g &quot;$CONFIGURATION_BUILD_DIR/$EXECUTABLE_PATH&quot; | grep -i 'CProcess' | wc -l&#96;&#13;&#10;copyAAX=&#96;nm -g &quot;$CONFIGURATION_BUILD_DIR/$EXECUTABLE_PATH&quot; | grep -i 'ACFStartup' | wc -l&#96;&#13;&#10;&#13;&#10;if [ $copyAU -gt 0 ]; then&#13;&#10; echo &quot;Copying to AudioUnit folder...&quot;&#13;&#10; AU=~/Library/Audio/Plug-Ins/Components/$PRODUCT_NAME.component&#13;&#10; if [ -d &quot;$AU&quot; ]; then &#13;&#10; rm -r &quot;$AU&quot;&#13;&#10; fi&#13;&#10;&#13;&#10; cp -r &quot;$original&quot; &quot;$AU&quot;&#13;&#10; sed -i &quot;&quot; -e 's/TDMwPTul/BNDLPTul/g' &quot;$AU/Contents/PkgInfo&quot;&#13;&#10; sed -i &quot;&quot; -e 's/TDMw/BNDL/g' &quot;$AU/Contents/$INFOPLIST_FILE&quot;&#13;&#10;&#13;&#10; # Fix info.plist for AUs built with Xcode 3&#13;&#10; if [ -f &quot;$DEVELOPER_DIR/Library/Developer/CoreAudio/AudioUnits/AUPublic/AUBase/AUPlugInDispatch.cpp&quot; ]; then&#13;&#10; echo&#13;&#10; else&#13;&#10; echo &quot;Removing AudioComponents entry from Info.plist because this is not a new-format AU&quot;&#13;&#10; /usr/libexec/PlistBuddy -c &quot;Delete AudioComponents&quot; &quot;$AU/Contents/Info.plist&quot;&#13;&#10; fi&#13;&#10;fi&#13;&#10;&#13;&#10;if [ $copyVST -gt 0 ]; then&#13;&#10; echo &quot;Copying to VST folder...&quot;&#13;&#10; VST=~/Library/Audio/Plug-Ins/VST/$PRODUCT_NAME.vst&#13;&#10; if [ -d &quot;$VST&quot; ]; then &#13;&#10; rm -r &quot;$VST&quot;&#13;&#10; fi&#13;&#10;&#13;&#10; cp -r &quot;$original&quot; &quot;$VST&quot;&#13;&#10; sed -i &quot;&quot; -e 's/TDMwPTul/BNDLPTul/g' &quot;$VST/Contents/PkgInfo&quot;&#13;&#10; sed -i &quot;&quot; -e 's/TDMw/BNDL/g' &quot;$VST/Contents/$INFOPLIST_FILE&quot;&#13;&#10;fi&#13;&#10;&#13;&#10;if [ $copyRTAS -gt 0 ]; then&#13;&#10; echo &quot;Copying to RTAS folder...&quot;&#13;&#10; RTAS=/Library/Application\ Support/Digidesign/Plug-Ins/$PRODUCT_NAME.dpm&#13;&#10; if [ -d &quot;$RTAS&quot; ]; then&#13;&#10; rm -r &quot;$RTAS&quot;&#13;&#10; fi&#13;&#10;&#13;&#10; cp -r &quot;$original&quot; &quot;$RTAS&quot;&#13;&#10;fi&#13;&#10;&#13;&#10;if [ $copyAAX -gt 0 ]; then&#13;&#10; echo &quot;Copying to AAX folder...&quot;&#13;&#10;&#13;&#10; if [ -d &quot;/Applications/ProTools_3PDev/Plug-Ins&quot; ]; then&#13;&#10; AAX1=&quot;/Applications/ProTools_3PDev/Plug-Ins/$PRODUCT_NAME.aaxplugin&quot;&#13;&#10;&#13;&#10; if [ -d &quot;$AAX1&quot; ]; then&#13;&#10; rm -r &quot;$AAX1&quot;&#13;&#10; fi&#13;&#10;&#13;&#10; cp -r &quot;$original&quot; &quot;$AAX1&quot;&#13;&#10; fi&#13;&#10;&#13;&#10; if [ -d &quot;/Library/Application Support/Avid/Audio/Plug-Ins&quot; ]; then&#13;&#10; AAX2=&quot;/Library/Application Support/Avid/Audio/Plug-Ins/$PRODUCT_NAME.aaxplugin&quot;&#13;&#10;&#13;&#10; if [ -d &quot;$AAX2&quot; ]; then&#13;&#10; rm -r &quot;$AAX2&quot;&#13;&#10; fi&#13;&#10;&#13;&#10; cp -r &quot;$original&quot; &quot;$AAX2&quot;&#13;&#10; fi&#13;&#10;fi&#13;&#10;">
postbuildCommand="&#10;# This script takes the build product and copies it to the AU, VST, and RTAS folders, depending on &#10;# which plugin types you've built&#10;&#10;original=$CONFIGURATION_BUILD_DIR/$FULL_PRODUCT_NAME&#10;&#10;# this looks inside the binary to detect which platforms are needed.. &#10;copyAU=&#96;nm -g &quot;$CONFIGURATION_BUILD_DIR/$EXECUTABLE_PATH&quot; | grep -i 'AudioUnit' | wc -l&#96;&#10;copyVST=&#96;nm -g &quot;$CONFIGURATION_BUILD_DIR/$EXECUTABLE_PATH&quot; | grep -i 'VSTPlugin' | wc -l&#96;&#10;copyRTAS=&#96;nm -g &quot;$CONFIGURATION_BUILD_DIR/$EXECUTABLE_PATH&quot; | grep -i 'CProcess' | wc -l&#96;&#10;copyAAX=&#96;nm -g &quot;$CONFIGURATION_BUILD_DIR/$EXECUTABLE_PATH&quot; | grep -i 'ACFStartup' | wc -l&#96;&#10;&#10;if [ $copyAU -gt 0 ]; then&#10; echo &quot;Copying to AudioUnit folder...&quot;&#10; AU=~/Library/Audio/Plug-Ins/Components/$PRODUCT_NAME.component&#10; if [ -d &quot;$AU&quot; ]; then &#10; rm -r &quot;$AU&quot;&#10; fi&#10;&#10; cp -r &quot;$original&quot; &quot;$AU&quot;&#10; sed -i &quot;&quot; -e 's/TDMwPTul/BNDLPTul/g' &quot;$AU/Contents/PkgInfo&quot;&#10; sed -i &quot;&quot; -e 's/TDMw/BNDL/g' &quot;$AU/Contents/$INFOPLIST_FILE&quot;&#10;&#10; # Fix info.plist for AUs built with Xcode 3&#10; if [ -f &quot;$DEVELOPER_DIR/Library/Developer/CoreAudio/AudioUnits/AUPublic/AUBase/AUPlugInDispatch.cpp&quot; ]; then&#10; echo&#10; else&#10; echo &quot;Removing AudioComponents entry from Info.plist because this is not a new-format AU&quot;&#10; /usr/libexec/PlistBuddy -c &quot;Delete AudioComponents&quot; &quot;$AU/Contents/Info.plist&quot;&#10; fi&#10;fi&#10;&#10;if [ $copyVST -gt 0 ]; then&#10; echo &quot;Copying to VST folder...&quot;&#10; VST=~/Library/Audio/Plug-Ins/VST/$PRODUCT_NAME.vst&#10; if [ -d &quot;$VST&quot; ]; then &#10; rm -r &quot;$VST&quot;&#10; fi&#10;&#10; cp -r &quot;$original&quot; &quot;$VST&quot;&#10; sed -i &quot;&quot; -e 's/TDMwPTul/BNDLPTul/g' &quot;$VST/Contents/PkgInfo&quot;&#10; sed -i &quot;&quot; -e 's/TDMw/BNDL/g' &quot;$VST/Contents/$INFOPLIST_FILE&quot;&#10;fi&#10;&#10;if [ $copyRTAS -gt 0 ]; then&#10; echo &quot;Copying to RTAS folder...&quot;&#10; RTAS=/Library/Application\ Support/Digidesign/Plug-Ins/$PRODUCT_NAME.dpm&#10; if [ -d &quot;$RTAS&quot; ]; then&#10; rm -r &quot;$RTAS&quot;&#10; fi&#10;&#10; cp -r &quot;$original&quot; &quot;$RTAS&quot;&#10;fi&#10;&#10;if [ $copyAAX -gt 0 ]; then&#10; echo &quot;Copying to AAX folder...&quot;&#10;&#10; if [ -d &quot;/Applications/ProTools_3PDev/Plug-Ins&quot; ]; then&#10; AAX1=&quot;/Applications/ProTools_3PDev/Plug-Ins/$PRODUCT_NAME.aaxplugin&quot;&#10;&#10; if [ -d &quot;$AAX1&quot; ]; then&#10; rm -r &quot;$AAX1&quot;&#10; fi&#10;&#10; cp -r &quot;$original&quot; &quot;$AAX1&quot;&#10; fi&#10;&#10; if [ -d &quot;/Library/Application Support/Avid/Audio/Plug-Ins&quot; ]; then&#10; AAX2=&quot;/Library/Application Support/Avid/Audio/Plug-Ins/$PRODUCT_NAME.aaxplugin&quot;&#10;&#10; if [ -d &quot;$AAX2&quot; ]; then&#10; rm -r &quot;$AAX2&quot;&#10; fi&#10;&#10; cp -r &quot;$original&quot; &quot;$AAX2&quot;&#10; fi&#10;fi&#10;">
<CONFIGURATIONS>
<CONFIGURATION name="Debug" osxSDK="default" osxCompatibility="default" osxArchitecture="default"
isDebug="1" optimisation="1" targetName="Dexed"/>
<CONFIGURATION name="Release" osxSDK="default" osxCompatibility="default" osxArchitecture="default"
<CONFIGURATION name="Release" osxSDK="default" osxCompatibility="default" osxArchitecture="64BitUniversal"
isDebug="0" optimisation="2" targetName="Dexed"/>
</CONFIGURATIONS>
<MODULEPATHS>

@ -35,6 +35,11 @@
#define JUCE_MODULE_AVAILABLE_juce_gui_basics 1
#define JUCE_MODULE_AVAILABLE_juce_gui_extra 1
//==============================================================================
#ifndef JUCE_STANDALONE_APPLICATION
#define JUCE_STANDALONE_APPLICATION 0
#endif
//==============================================================================
// juce_audio_devices flags:
@ -46,6 +51,10 @@
//#define JUCE_WASAPI
#endif
#ifndef JUCE_WASAPI_EXCLUSIVE
//#define JUCE_WASAPI_EXCLUSIVE
#endif
#ifndef JUCE_DIRECTSOUND
//#define JUCE_DIRECTSOUND
#endif
@ -131,6 +140,10 @@
//#define JUCE_INCLUDE_ZLIB_CODE
#endif
#ifndef JUCE_USE_CURL
//#define JUCE_USE_CURL
#endif
//==============================================================================
// juce_graphics flags:

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -487,13 +487,10 @@ public:
}
/** Scans a block of data, returning the lowest and highest levels as floats */
void findMinAndMax (size_t numSamples, float& minValue, float& maxValue) const noexcept
Range<float> findMinAndMax (size_t numSamples) const noexcept
{
if (numSamples == 0)
{
minValue = maxValue = 0;
return;
}
return Range<float>();
Pointer dest (*this);
@ -512,27 +509,32 @@ public:
if (v < mn) mn = v;
}
minValue = mn;
maxValue = mx;
return Range<float> (mn, mx);
}
else
int32 mn = dest.getAsInt32();
dest.advance();
int32 mx = mn;
while (--numSamples > 0)
{
int32 mn = dest.getAsInt32();
const int v = dest.getAsInt32();
dest.advance();
int32 mx = mn;
while (--numSamples > 0)
{
const int v = dest.getAsInt32();
dest.advance();
if (mx < v) mx = v;
if (v < mn) mn = v;
}
if (mx < v) mx = v;
if (v < mn) mn = v;
}
return Range<float> (mn * (float) (1.0 / (1.0 + Int32::maxValue)),
mx * (float) (1.0 / (1.0 + Int32::maxValue)));
}
minValue = mn * (float) (1.0 / (1.0 + Int32::maxValue));
maxValue = mx * (float) (1.0 / (1.0 + Int32::maxValue));
}
/** Scans a block of data, returning the lowest and highest levels as floats */
void findMinAndMax (size_t numSamples, float& minValue, float& maxValue) const noexcept
{
Range<float> r (findMinAndMax (numSamples));
minValue = r.getStart();
maxValue = r.getEnd();
}
/** Returns true if the pointer is using a floating-point format. */

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -116,8 +116,11 @@ void AudioSampleBuffer::setDataToReferTo (float** dataToReferTo,
jassert (dataToReferTo != nullptr);
jassert (newNumChannels >= 0 && newNumSamples >= 0);
allocatedBytes = 0;
allocatedData.free();
if (allocatedBytes != 0)
{
allocatedBytes = 0;
allocatedData.free();
}
numChannels = newNumChannels;
size = newNumSamples;

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -49,8 +49,13 @@ namespace FloatVectorHelpers
{
typedef float Type;
typedef __m128 ParallelType;
typedef __m128 IntegerType;
enum { numParallel = 4 };
// Integer and parallel types are the same for SSE. On neon they have different types
static forcedinline IntegerType toint (ParallelType v) noexcept { return v; }
static forcedinline ParallelType toflt (IntegerType v) noexcept { return v; }
static forcedinline ParallelType load1 (Type v) noexcept { return _mm_load1_ps (&v); }
static forcedinline ParallelType loadA (const Type* v) noexcept { return _mm_load_ps (v); }
static forcedinline ParallelType loadU (const Type* v) noexcept { return _mm_loadu_ps (v); }
@ -63,6 +68,11 @@ namespace FloatVectorHelpers
static forcedinline ParallelType max (ParallelType a, ParallelType b) noexcept { return _mm_max_ps (a, b); }
static forcedinline ParallelType min (ParallelType a, ParallelType b) noexcept { return _mm_min_ps (a, b); }
static forcedinline ParallelType bit_and (ParallelType a, ParallelType b) noexcept { return _mm_and_ps (a, b); }
static forcedinline ParallelType bit_not (ParallelType a, ParallelType b) noexcept { return _mm_andnot_ps (a, b); }
static forcedinline ParallelType bit_or (ParallelType a, ParallelType b) noexcept { return _mm_or_ps (a, b); }
static forcedinline ParallelType bit_xor (ParallelType a, ParallelType b) noexcept { return _mm_xor_ps (a, b); }
static forcedinline Type max (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmax (v[0], v[1], v[2], v[3]); }
static forcedinline Type min (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmin (v[0], v[1], v[2], v[3]); }
};
@ -71,8 +81,13 @@ namespace FloatVectorHelpers
{
typedef double Type;
typedef __m128d ParallelType;
typedef __m128d IntegerType;
enum { numParallel = 2 };
// Integer and parallel types are the same for SSE. On neon they have different types
static forcedinline IntegerType toint (ParallelType v) noexcept { return v; }
static forcedinline ParallelType toflt (IntegerType v) noexcept { return v; }
static forcedinline ParallelType load1 (Type v) noexcept { return _mm_load1_pd (&v); }
static forcedinline ParallelType loadA (const Type* v) noexcept { return _mm_load_pd (v); }
static forcedinline ParallelType loadU (const Type* v) noexcept { return _mm_loadu_pd (v); }
@ -85,10 +100,17 @@ namespace FloatVectorHelpers
static forcedinline ParallelType max (ParallelType a, ParallelType b) noexcept { return _mm_max_pd (a, b); }
static forcedinline ParallelType min (ParallelType a, ParallelType b) noexcept { return _mm_min_pd (a, b); }
static forcedinline ParallelType bit_and (ParallelType a, ParallelType b) noexcept { return _mm_and_pd (a, b); }
static forcedinline ParallelType bit_not (ParallelType a, ParallelType b) noexcept { return _mm_andnot_pd (a, b); }
static forcedinline ParallelType bit_or (ParallelType a, ParallelType b) noexcept { return _mm_or_pd (a, b); }
static forcedinline ParallelType bit_xor (ParallelType a, ParallelType b) noexcept { return _mm_xor_pd (a, b); }
static forcedinline Type max (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmax (v[0], v[1]); }
static forcedinline Type min (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmin (v[0], v[1]); }
};
#define JUCE_BEGIN_VEC_OP \
typedef FloatVectorHelpers::ModeType<sizeof(*dest)>::Mode Mode; \
if (FloatVectorHelpers::isSSE2Available()) \
@ -126,14 +148,66 @@ namespace FloatVectorHelpers
#define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST(normalOp, vecOp, locals, increment, setupOp) \
JUCE_BEGIN_VEC_OP \
setupOp \
if (FloatVectorHelpers::isAligned (dest)) \
{ \
if (FloatVectorHelpers::isAligned (src1)) \
{ \
if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadA, Mode::loadA, Mode::storeA, locals, increment) \
else JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadA, Mode::loadU, Mode::storeA, locals, increment) \
} \
else \
{ \
if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadA, Mode::storeA, locals, increment) \
else JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadU, Mode::storeA, locals, increment) \
} \
} \
else \
{ \
if (FloatVectorHelpers::isAligned (src1)) \
{ \
if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadA, Mode::loadA, Mode::storeU, locals, increment) \
else JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadA, Mode::loadU, Mode::storeU, locals, increment) \
} \
else \
{ \
if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadA, Mode::storeU, locals, increment) \
else JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
} \
} \
JUCE_FINISH_VEC_OP (normalOp)
#define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST(normalOp, vecOp, locals, increment, setupOp) \
JUCE_BEGIN_VEC_OP \
setupOp \
if (FloatVectorHelpers::isAligned (dest)) \
{ \
Mode::ParallelType (&loadSrc1) (const Mode::Type* v) = FloatVectorHelpers::isAligned (src1) ? Mode::loadA : Mode::loadU; \
Mode::ParallelType (&loadSrc2) (const Mode::Type* v) = FloatVectorHelpers::isAligned (src2) ? Mode::loadA : Mode::loadU; \
void (&storeDst) (Mode::Type* dest, Mode::ParallelType a) = FloatVectorHelpers::isAligned (dest) ? Mode::storeA : Mode::storeU; \
JUCE_VEC_LOOP_TWO_SOURCES (vecOp, loadSrc1, loadSrc2, storeDst, locals, increment); \
if (FloatVectorHelpers::isAligned (src1)) \
{ \
if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadA, Mode::loadA, Mode::loadA, Mode::storeA, locals, increment) \
else JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadA, Mode::loadU, Mode::loadA, Mode::storeA, locals, increment) \
} \
else \
{ \
if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadU, Mode::loadA, Mode::loadA, Mode::storeA, locals, increment) \
else JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadU, Mode::loadU, Mode::loadA, Mode::storeA, locals, increment) \
} \
} \
else \
{ \
if (FloatVectorHelpers::isAligned (src1)) \
{ \
if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadA, Mode::loadA, Mode::loadU, Mode::storeU, locals, increment) \
else JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadA, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
} \
else \
{ \
if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadU, Mode::loadA, Mode::loadU, Mode::storeU, locals, increment) \
else JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadU, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
} \
} \
JUCE_FINISH_VEC_OP (normalOp)
//==============================================================================
#elif JUCE_USE_ARM_NEON
@ -141,8 +215,12 @@ namespace FloatVectorHelpers
{
typedef float Type;
typedef float32x4_t ParallelType;
typedef uint32x4_t IntegerType;
enum { numParallel = 4 };
static forcedinline IntegerType toint (ParallelType v) noexcept { union { ParallelType f; IntegerType i; } u; u.f = v; return u.i; }
static forcedinline ParallelType toflt (IntegerType v) noexcept { union { ParallelType f; IntegerType i; } u; u.i = v; return u.f; }
static forcedinline ParallelType load1 (Type v) noexcept { return vld1q_dup_f32 (&v); }
static forcedinline ParallelType loadA (const Type* v) noexcept { return vld1q_f32 (v); }
static forcedinline ParallelType loadU (const Type* v) noexcept { return vld1q_f32 (v); }
@ -155,6 +233,11 @@ namespace FloatVectorHelpers
static forcedinline ParallelType max (ParallelType a, ParallelType b) noexcept { return vmaxq_f32 (a, b); }
static forcedinline ParallelType min (ParallelType a, ParallelType b) noexcept { return vminq_f32 (a, b); }
static forcedinline ParallelType bit_and (ParallelType a, ParallelType b) noexcept { return toflt (vandq_u32 (toint (a), toint (b))); }
static forcedinline ParallelType bit_not (ParallelType a, ParallelType b) noexcept { return toflt (vbicq_u32 (toint (a), toint (b))); }
static forcedinline ParallelType bit_or (ParallelType a, ParallelType b) noexcept { return toflt (vorrq_u32 (toint (a), toint (b))); }
static forcedinline ParallelType bit_xor (ParallelType a, ParallelType b) noexcept { return toflt (veorq_u32 (toint (a), toint (b))); }
static forcedinline Type max (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmax (v[0], v[1], v[2], v[3]); }
static forcedinline Type min (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmin (v[0], v[1], v[2], v[3]); }
};
@ -163,8 +246,12 @@ namespace FloatVectorHelpers
{
typedef double Type;
typedef double ParallelType;
typedef uint64 IntegerType;
enum { numParallel = 1 };
static forcedinline IntegerType toint (ParallelType v) noexcept { union { ParallelType f; IntegerType i; } u; u.f = v; return u.i; }
static forcedinline ParallelType toflt (IntegerType v) noexcept { union { ParallelType f; IntegerType i; } u; u.i = v; return u.f; }
static forcedinline ParallelType load1 (Type v) noexcept { return v; }
static forcedinline ParallelType loadA (const Type* v) noexcept { return *v; }
static forcedinline ParallelType loadU (const Type* v) noexcept { return *v; }
@ -177,6 +264,11 @@ namespace FloatVectorHelpers
static forcedinline ParallelType max (ParallelType a, ParallelType b) noexcept { return jmax (a, b); }
static forcedinline ParallelType min (ParallelType a, ParallelType b) noexcept { return jmin (a, b); }
static forcedinline ParallelType bit_and (ParallelType a, ParallelType b) noexcept { return toflt (toint (a) & toint (b)); }
static forcedinline ParallelType bit_not (ParallelType a, ParallelType b) noexcept { return toflt ((~toint (a)) & toint (b)); }
static forcedinline ParallelType bit_or (ParallelType a, ParallelType b) noexcept { return toflt (toint (a) | toint (b)); }
static forcedinline ParallelType bit_xor (ParallelType a, ParallelType b) noexcept { return toflt (toint (a) ^ toint (b)); }
static forcedinline Type max (ParallelType a) noexcept { return a; }
static forcedinline Type min (ParallelType a) noexcept { return a; }
};
@ -211,6 +303,13 @@ namespace FloatVectorHelpers
JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
JUCE_FINISH_VEC_OP (normalOp)
#define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST(normalOp, vecOp, locals, increment, setupOp) \
JUCE_BEGIN_VEC_OP \
setupOp \
JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadU, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
JUCE_FINISH_VEC_OP (normalOp)
//==============================================================================
#else
#define JUCE_PERFORM_VEC_OP_DEST(normalOp, vecOp, locals, setupOp) \
@ -221,6 +320,10 @@ namespace FloatVectorHelpers
#define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST(normalOp, vecOp, locals, increment, setupOp) \
for (int i = 0; i < num; ++i) normalOp;
#define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST(normalOp, vecOp, locals, increment, setupOp) \
for (int i = 0; i < num; ++i) normalOp;
#endif
//==============================================================================
@ -240,11 +343,20 @@ namespace FloatVectorHelpers
increment; \
}
#define JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD(vecOp, src1Load, src2Load, dstLoad, dstStore, locals, increment) \
for (int i = 0; i < numLongOps; ++i) \
{ \
locals (src1Load, src2Load, dstLoad); \
dstStore (dest, vecOp); \
increment; \
}
#define JUCE_LOAD_NONE(srcLoad, dstLoad)
#define JUCE_LOAD_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest);
#define JUCE_LOAD_SRC(srcLoad, dstLoad) const Mode::ParallelType s = srcLoad (src);
#define JUCE_LOAD_SRC1_SRC2(src1Load, src2Load) const Mode::ParallelType s1 = src1Load (src1), s2 = src2Load (src2);
#define JUCE_LOAD_SRC_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest), s = srcLoad (src);
#define JUCE_LOAD_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest);
#define JUCE_LOAD_SRC(srcLoad, dstLoad) const Mode::ParallelType s = srcLoad (src);
#define JUCE_LOAD_SRC1_SRC2(src1Load, src2Load) const Mode::ParallelType s1 = src1Load (src1), s2 = src2Load (src2);
#define JUCE_LOAD_SRC1_SRC2_DEST(src1Load, src2Load, dstLoad) const Mode::ParallelType d = dstLoad (dest), s1 = src1Load (src1), s2 = src2Load (src2);
#define JUCE_LOAD_SRC_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest), s = srcLoad (src);
#if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
template<int typeSize> struct ModeType { typedef BasicOps32 Mode; };
@ -395,7 +507,7 @@ void JUCE_CALLTYPE FloatVectorOperations::clear (float* dest, int num) noexcept
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vclr (dest, 1, (size_t) num);
#else
zeromem (dest, num * sizeof (float));
zeromem (dest, (size_t) num * sizeof (float));
#endif
}
@ -404,7 +516,7 @@ void JUCE_CALLTYPE FloatVectorOperations::clear (double* dest, int num) noexcept
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vclrD (dest, 1, (size_t) num);
#else
zeromem (dest, num * sizeof (double));
zeromem (dest, (size_t) num * sizeof (double));
#endif
}
@ -462,8 +574,12 @@ void JUCE_CALLTYPE FloatVectorOperations::copyWithMultiply (double* dest, const
void JUCE_CALLTYPE FloatVectorOperations::add (float* dest, float amount, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vsadd (dest, 1, &amount, dest, 1, (vDSP_Length) num);
#else
JUCE_PERFORM_VEC_OP_DEST (dest[i] += amount, Mode::add (d, amountToAdd), JUCE_LOAD_DEST,
const Mode::ParallelType amountToAdd = Mode::load1 (amount);)
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::add (double* dest, double amount, int num) noexcept
@ -568,9 +684,13 @@ void JUCE_CALLTYPE FloatVectorOperations::subtract (double* dest, const double*
void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (float* dest, const float* src, float multiplier, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vsma (src, 1, &multiplier, dest, 1, dest, 1, (vDSP_Length) num);
#else
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i] * multiplier, Mode::add (d, Mode::mul (mult, s)),
JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST,
const Mode::ParallelType mult = Mode::load1 (multiplier);)
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (double* dest, const double* src, double multiplier, int num) noexcept
@ -580,6 +700,28 @@ void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (double* dest, const d
const Mode::ParallelType mult = Mode::load1 (multiplier);)
}
void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (float* dest, const float* src1, const float* src2, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vma ((float*) src1, 1, (float*) src2, 1, dest, 1, dest, 1, (vDSP_Length) num);
#else
JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST (dest[i] += src1[i] * src2[i], Mode::add (d, Mode::mul (s1, s2)),
JUCE_LOAD_SRC1_SRC2_DEST,
JUCE_INCREMENT_SRC1_SRC2_DEST, )
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (double* dest, const double* src1, const double* src2, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vmaD ((double*) src1, 1, (double*) src2, 1, dest, 1, dest, 1, (vDSP_Length) num);
#else
JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST (dest[i] += src1[i] * src2[i], Mode::add (d, Mode::mul (s1, s2)),
JUCE_LOAD_SRC1_SRC2_DEST,
JUCE_INCREMENT_SRC1_SRC2_DEST, )
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, const float* src, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
@ -668,6 +810,33 @@ void FloatVectorOperations::negate (double* dest, const double* src, int num) no
#endif
}
void FloatVectorOperations::abs (float* dest, const float* src, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vabs ((float*) src, 1, dest, 1, (vDSP_Length) num);
#else
union {float f; uint32 i;} signMask;
signMask.i = 0x7fffffffUL;
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = fabsf (src[i]), Mode::bit_and (s, mask),
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST,
const Mode::ParallelType mask = Mode::load1 (signMask.f);)
#endif
}
void FloatVectorOperations::abs (double* dest, const double* src, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vabsD ((double*) src, 1, dest, 1, (vDSP_Length) num);
#else
union {double d; uint64 i;} signMask;
signMask.i = 0x7fffffffffffffffULL;
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = fabs (src[i]), Mode::bit_and (s, mask),
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST,
const Mode::ParallelType mask = Mode::load1 (signMask.d);)
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::convertFixedToFloat (float* dest, const int* src, float multiplier, int num) noexcept
{
#if JUCE_USE_ARM_NEON
@ -682,6 +851,96 @@ void JUCE_CALLTYPE FloatVectorOperations::convertFixedToFloat (float* dest, cons
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::min (float* dest, const float* src, float comp, int num) noexcept
{
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmin (src[i], comp), Mode::min (s, cmp),
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST,
const Mode::ParallelType cmp = Mode::load1 (comp);)
}
void JUCE_CALLTYPE FloatVectorOperations::min (double* dest, const double* src, double comp, int num) noexcept
{
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmin (src[i], comp), Mode::min (s, cmp),
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST,
const Mode::ParallelType cmp = Mode::load1 (comp);)
}
void JUCE_CALLTYPE FloatVectorOperations::min (float* dest, const float* src1, const float* src2, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vmin ((float*) src1, 1, (float*) src2, 1, dest, 1, (vDSP_Length) num);
#else
JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmin (src1[i], src2[i]), Mode::min (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, )
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::min (double* dest, const double* src1, const double* src2, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vminD ((double*) src1, 1, (double*) src2, 1, dest, 1, (vDSP_Length) num);
#else
JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmin (src1[i], src2[i]), Mode::min (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, )
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::max (float* dest, const float* src, float comp, int num) noexcept
{
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (src[i], comp), Mode::max (s, cmp),
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST,
const Mode::ParallelType cmp = Mode::load1 (comp);)
}
void JUCE_CALLTYPE FloatVectorOperations::max (double* dest, const double* src, double comp, int num) noexcept
{
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (src[i], comp), Mode::max (s, cmp),
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST,
const Mode::ParallelType cmp = Mode::load1 (comp);)
}
void JUCE_CALLTYPE FloatVectorOperations::max (float* dest, const float* src1, const float* src2, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vmax ((float*) src1, 1, (float*) src2, 1, dest, 1, (vDSP_Length) num);
#else
JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmax (src1[i], src2[i]), Mode::max (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, )
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::max (double* dest, const double* src1, const double* src2, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vmaxD ((double*) src1, 1, (double*) src2, 1, dest, 1, (vDSP_Length) num);
#else
JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmax (src1[i], src2[i]), Mode::max (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, )
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::clip (float* dest, const float* src, float low, float high, int num) noexcept
{
jassert(high >= low);
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vclip ((float*) src, 1, &low, &high, dest, 1, (vDSP_Length) num);
#else
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (jmin (src[i], high), low), Mode::max (Mode::min (s, hi), lo),
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST,
const Mode::ParallelType lo = Mode::load1 (low); const Mode::ParallelType hi = Mode::load1 (high);)
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::clip (double* dest, const double* src, double low, double high, int num) noexcept
{
jassert(high >= low);
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vclipD ((double*) src, 1, &low, &high, dest, 1, (vDSP_Length) num);
#else
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (jmin (src[i], high), low), Mode::max (Mode::min (s, hi), lo),
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST,
const Mode::ParallelType lo = Mode::load1 (low); const Mode::ParallelType hi = Mode::load1 (high);)
#endif
}
Range<float> JUCE_CALLTYPE FloatVectorOperations::findMinAndMax (const float* src, int num) noexcept
{
#if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
@ -821,8 +1080,19 @@ public:
FloatVectorOperations::subtract (data1, data2, num);
u.expect (areAllValuesEqual (data1, num, (ValueType) 512));
FloatVectorOperations::abs (data1, data2, num);
u.expect (areAllValuesEqual (data1, num, (ValueType) 256));
FloatVectorOperations::abs (data2, data1, num);
u.expect (areAllValuesEqual (data2, num, (ValueType) 256));
fillRandomly (random, int1, num);
doConversionTest (u, data1, data2, int1, num);
FloatVectorOperations::fill (data1, (ValueType) 2, num);
FloatVectorOperations::fill (data2, (ValueType) 3, num);
FloatVectorOperations::addWithMultiply (data1, data1, data2, num);
u.expect (areAllValuesEqual (data1, num, (ValueType) 8));
}
static void doConversionTest (UnitTest& u, float* data1, float* data2, int* const int1, int num)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -101,6 +101,12 @@ public:
/** Multiplies each source value by the given multiplier, then adds it to the destination value. */
static void JUCE_CALLTYPE addWithMultiply (double* dest, const double* src, double multiplier, int numValues) noexcept;
/** Multiplies each source1 value by the corresponding source2 value, then adds it to the destination value. */
static void JUCE_CALLTYPE addWithMultiply (float* dest, const float* src1, const float* src2, int num) noexcept;
/** Multiplies each source1 value by the corresponding source2 value, then adds it to the destination value. */
static void JUCE_CALLTYPE addWithMultiply (double* dest, const double* src1, const double* src2, int num) noexcept;
/** Multiplies the destination values by the source values. */
static void JUCE_CALLTYPE multiply (float* dest, const float* src, int numValues) noexcept;
@ -131,9 +137,45 @@ public:
/** Copies a source vector to a destination, negating each value. */
static void JUCE_CALLTYPE negate (double* dest, const double* src, int numValues) noexcept;
/** Copies a source vector to a destination, taking the absolute of each value. */
static void JUCE_CALLTYPE abs (float* dest, const float* src, int numValues) noexcept;
/** Copies a source vector to a destination, taking the absolute of each value. */
static void JUCE_CALLTYPE abs (double* dest, const double* src, int numValues) noexcept;
/** Converts a stream of integers to floats, multiplying each one by the given multiplier. */
static void JUCE_CALLTYPE convertFixedToFloat (float* dest, const int* src, float multiplier, int numValues) noexcept;
/** Each element of dest will be the minimum of the corresponding element of the source array and the given comp value. */
static void JUCE_CALLTYPE min (float* dest, const float* src, float comp, int num) noexcept;
/** Each element of dest will be the minimum of the corresponding element of the source array and the given comp value. */
static void JUCE_CALLTYPE min (double* dest, const double* src, double comp, int num) noexcept;
/** Each element of dest will be the minimum of the corresponding source1 and source2 values. */
static void JUCE_CALLTYPE min (float* dest, const float* src1, const float* src2, int num) noexcept;
/** Each element of dest will be the minimum of the corresponding source1 and source2 values. */
static void JUCE_CALLTYPE min (double* dest, const double* src1, const double* src2, int num) noexcept;
/** Each element of dest will be the maximum of the corresponding element of the source array and the given comp value. */
static void JUCE_CALLTYPE max (float* dest, const float* src, float comp, int num) noexcept;
/** Each element of dest will be the maximum of the corresponding element of the source array and the given comp value. */
static void JUCE_CALLTYPE max (double* dest, const double* src, double comp, int num) noexcept;
/** Each element of dest will be the maximum of the corresponding source1 and source2 values. */
static void JUCE_CALLTYPE max (float* dest, const float* src1, const float* src2, int num) noexcept;
/** Each element of dest will be the maximum of the corresponding source1 and source2 values. */
static void JUCE_CALLTYPE max (double* dest, const double* src1, const double* src2, int num) noexcept;
/** Each element of dest is calculated by hard clipping the corresponding src element so that it is in the range specified by the arguments low and high. */
static void JUCE_CALLTYPE clip (float* dest, const float* src, float low, float high, int num) noexcept;
/** Each element of dest is calculated by hard clipping the corresponding src element so that it is in the range specified by the arguments low and high. */
static void JUCE_CALLTYPE clip (double* dest, const double* src, double low, double high, int num) noexcept;
/** Finds the miniumum and maximum values in the given array. */
static Range<float> JUCE_CALLTYPE findMinAndMax (const float* src, int numValues) noexcept;

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -0,0 +1,277 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
// (For the moment, we'll implement a few local operators for this complex class - one
// day we'll probably either have a juce complex class, or use the C++11 one)
static FFT::Complex operator+ (FFT::Complex a, FFT::Complex b) noexcept { FFT::Complex c = { a.r + b.r, a.i + b.i }; return c; }
static FFT::Complex operator- (FFT::Complex a, FFT::Complex b) noexcept { FFT::Complex c = { a.r - b.r, a.i - b.i }; return c; }
static FFT::Complex operator* (FFT::Complex a, FFT::Complex b) noexcept { FFT::Complex c = { a.r * b.r - a.i * b.i, a.r * b.i + a.i * b.r }; return c; }
static FFT::Complex& operator+= (FFT::Complex& a, FFT::Complex b) noexcept { a.r += b.r; a.i += b.i; return a; }
//==============================================================================
struct FFT::FFTConfig
{
FFTConfig (int sizeOfFFT, bool isInverse)
: fftSize (sizeOfFFT), inverse (isInverse), twiddleTable ((size_t) sizeOfFFT)
{
for (int i = 0; i < fftSize; ++i)
{
const double phase = (isInverse ? 2.0 : -2.0) * double_Pi * i / fftSize;
twiddleTable[i].r = (float) cos (phase);
twiddleTable[i].i = (float) sin (phase);
}
const int root = (int) std::sqrt ((double) fftSize);
int divisor = 4, n = fftSize;
for (int i = 0; i < numElementsInArray (factors); ++i)
{
while ((n % divisor) != 0)
{
if (divisor == 2) divisor = 3;
else if (divisor == 4) divisor = 2;
else divisor += 2;
if (divisor > root)
divisor = n;
}
n /= divisor;
jassert (divisor == 1 || divisor == 2 || divisor == 4);
factors[i].radix = divisor;
factors[i].length = n;
}
}
void perform (const Complex* input, Complex* output) const noexcept
{
perform (input, output, 1, 1, factors);
}
const int fftSize;
const bool inverse;
struct Factor { int radix, length; };
Factor factors[32];
HeapBlock<Complex> twiddleTable;
void perform (const Complex* input, Complex* output, const int stride, const int strideIn, const Factor* facs) const noexcept
{
const Factor factor (*facs++);
Complex* const originalOutput = output;
const Complex* const outputEnd = output + factor.radix * factor.length;
if (stride == 1 && factor.radix <= 5)
{
for (int i = 0; i < factor.radix; ++i)
perform (input + stride * strideIn * i, output + i * factor.length, stride * factor.radix, strideIn, facs);
butterfly (factor, output, stride);
return;
}
if (factor.length == 1)
{
do
{
*output++ = *input;
input += stride * strideIn;
}
while (output < outputEnd);
}
else
{
do
{
perform (input, output, stride * factor.radix, strideIn, facs);
input += stride * strideIn;
output += factor.length;
}
while (output < outputEnd);
}
butterfly (factor, originalOutput, stride);
}
void butterfly (const Factor factor, Complex* data, const int stride) const noexcept
{
switch (factor.radix)
{
case 1: break;
case 2: butterfly2 (data, stride, factor.length); return;
case 4: butterfly4 (data, stride, factor.length); return;
default: jassertfalse; break;
}
Complex* scratch = static_cast<Complex*> (alloca (sizeof (Complex) * (size_t) factor.radix));
for (int i = 0; i < factor.length; ++i)
{
for (int k = i, q1 = 0; q1 < factor.radix; ++q1)
{
scratch[q1] = data[k];
k += factor.length;
}
for (int k = i, q1 = 0; q1 < factor.radix; ++q1)
{
int twiddleIndex = 0;
data[k] = scratch[0];
for (int q = 1; q < factor.radix; ++q)
{
twiddleIndex += stride * k;
if (twiddleIndex >= fftSize)
twiddleIndex -= fftSize;
data[k] += scratch[q] * twiddleTable[twiddleIndex];
}
k += factor.length;
}
}
}
void butterfly2 (Complex* data, const int stride, const int length) const noexcept
{
Complex* dataEnd = data + length;
const Complex* tw = twiddleTable;
for (int i = length; --i >= 0;)
{
const Complex s (*dataEnd * *tw);
tw += stride;
*dataEnd++ = *data - s;
*data++ += s;
}
}
void butterfly4 (Complex* data, const int stride, const int length) const noexcept
{
const int lengthX2 = length * 2;
const int lengthX3 = length * 3;
const Complex* twiddle1 = twiddleTable;
const Complex* twiddle2 = twiddle1;
const Complex* twiddle3 = twiddle1;
for (int i = length; --i >= 0;)
{
const Complex s0 = data[length] * *twiddle1;
const Complex s1 = data[lengthX2] * *twiddle2;
const Complex s2 = data[lengthX3] * *twiddle3;
const Complex s3 = s0 + s2;
const Complex s4 = s0 - s2;
const Complex s5 = *data - s1;
*data += s1;
data[lengthX2] = *data - s3;
twiddle1 += stride;
twiddle2 += stride * 2;
twiddle3 += stride * 3;
*data += s3;
if (inverse)
{
data[length].r = s5.r - s4.i;
data[length].i = s5.i + s4.r;
data[lengthX3].r = s5.r + s4.i;
data[lengthX3].i = s5.i - s4.r;
}
else
{
data[length].r = s5.r + s4.i;
data[length].i = s5.i - s4.r;
data[lengthX3].r = s5.r - s4.i;
data[lengthX3].i = s5.i + s4.r;
}
++data;
}
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FFTConfig)
};
//==============================================================================
FFT::FFT (int order, bool inverse) : config (new FFTConfig (1 << order, inverse)), size (1 << order) {}
FFT::~FFT() {}
void FFT::perform (const Complex* const input, Complex* const output) const noexcept
{
config->perform (input, output);
}
void FFT::performRealOnlyForwardTransform (float* d) const noexcept
{
// This can only be called on an FFT object that was created to do forward transforms.
jassert (! config->inverse);
Complex* const scratch = static_cast<Complex*> (alloca (16 + sizeof (Complex) * (size_t) size));
for (int i = 0; i < size; ++i)
{
scratch[i].r = d[i];
scratch[i].i = 0;
}
perform (scratch, reinterpret_cast<Complex*> (d));
}
void FFT::performRealOnlyInverseTransform (float* d) const noexcept
{
// This can only be called on an FFT object that was created to do inverse transforms.
jassert (config->inverse);
Complex* const scratch = static_cast<Complex*> (alloca (16 + sizeof (Complex) * (size_t) size));
perform (reinterpret_cast<const Complex*> (d), scratch);
const float scaleFactor = 1.0f / size;
for (int i = 0; i < size; ++i)
{
d[i] = scratch[i].r * scaleFactor;
d[i + size] = scratch[i].i * scaleFactor;
}
}
void FFT::performFrequencyOnlyForwardTransform (float* d) const noexcept
{
performRealOnlyForwardTransform (d);
const int twiceSize = size * 2;
for (int i = 0; i < twiceSize; i += 2)
{
d[i / 2] = juce_hypot (d[i], d[i + 1]);
if (i >= size)
{
d[i] = 0;
d[i + 1] = 0;
}
}
}

@ -0,0 +1,92 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
/**
A very minimal FFT class.
This is only a simple low-footprint implementation and isn't tuned for speed - it may
be useful for simple applications where one of the more complex FFT libraries would be
overkill. (But in the future it may end up becoming optimised of course...)
The FFT class itself contains lookup tables, so there's some overhead in creating
one, you should create and cache an FFT object for each size/direction of transform
that you need, and re-use them to perform the actual operation.
*/
class JUCE_API FFT
{
public:
/** Initialises an object for performing either a forward or inverse FFT with the given size.
The the number of points the FFT will operate on will be 2 ^ order.
*/
FFT (int order, bool isInverse);
/** Destructor. */
~FFT();
/** A complex number, for the purposes of the FFT class. */
struct Complex
{
float r; /**< Real part. */
float i; /**< Imaginary part. */
};
/** Performs an out-of-place FFT, either forward or inverse depending on the mode
that was passed to this object's constructor.
The arrays must contain at least getSize() elements.
*/
void perform (const Complex* input, Complex* output) const noexcept;
/** Performs an in-place forward transform on a block of real data.
The size of the array passed in must be 2 * getSize(), and the first half
should contain your raw input sample data. On return, the array will contain
complex frequency + phase data, and can be passed to performRealOnlyInverseTransform()
in order to convert it back to reals.
*/
void performRealOnlyForwardTransform (float* inputOutputData) const noexcept;
/** Performs a reverse operation to data created in performRealOnlyForwardTransform().
The size of the array passed in must be 2 * getSize(), containing complex
frequency and phase data. On return, the first half of the array will contain
the reconstituted samples.
*/
void performRealOnlyInverseTransform (float* inputOutputData) const noexcept;
/** Takes an array and simply transforms it to the frequency spectrum.
This may be handy for things like frequency displays or analysis.
*/
void performFrequencyOnlyForwardTransform (float* inputOutputData) const noexcept;
/** Returns the number of data points that this FFT was created to work with. */
int getSize() const noexcept { return size; }
private:
struct FFTConfig;
ScopedPointer<FFTConfig> config;
const int size;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FFT)
};

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -23,7 +23,7 @@
*/
#if JUCE_INTEL
#define JUCE_SNAP_TO_ZERO(n) if (! (n < -1.0e-8 || n > 1.0e-8)) n = 0;
#define JUCE_SNAP_TO_ZERO(n) if (! (n < -1.0e-8f || n > 1.0e-8f)) n = 0;
#else
#define JUCE_SNAP_TO_ZERO(n)
#endif
@ -64,7 +64,7 @@ IIRCoefficients IIRCoefficients::makeLowPass (const double sampleRate,
{
jassert (sampleRate > 0);
const double n = 1.0 / tan (double_Pi * frequency / sampleRate);
const double n = 1.0 / std::tan (double_Pi * frequency / sampleRate);
const double nSquared = n * n;
const double c1 = 1.0 / (1.0 + std::sqrt (2.0) * n + nSquared);
@ -79,7 +79,7 @@ IIRCoefficients IIRCoefficients::makeLowPass (const double sampleRate,
IIRCoefficients IIRCoefficients::makeHighPass (const double sampleRate,
const double frequency) noexcept
{
const double n = tan (double_Pi * frequency / sampleRate);
const double n = std::tan (double_Pi * frequency / sampleRate);
const double nSquared = n * n;
const double c1 = 1.0 / (1.0 + std::sqrt (2.0) * n + nSquared);

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -87,7 +87,10 @@ int LagrangeInterpolator::process (const double actualRatio, const float* in,
if (numOut >= 4)
{
memcpy (lastInputSamples, in + (numOut - 4), 4 * sizeof (float));
const float* end = in + numOut;
for (int i = 0; i < 4; ++i)
lastInputSamples[i] = *--end;
}
else
{
@ -152,7 +155,10 @@ int LagrangeInterpolator::processAdding (const double actualRatio, const float*
if (numOut >= 4)
{
memcpy (lastInputSamples, in + (numOut - 4), 4 * sizeof (float));
const float* end = in + numOut;
for (int i = 0; i < 4; ++i)
lastInputSamples[i] = *--end;
}
else
{

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -82,12 +82,13 @@ public:
const float dryScaleFactor = 2.0f;
const float wet = newParams.wetLevel * wetScaleFactor;
wet1 = wet * (newParams.width * 0.5f + 0.5f);
wet2 = wet * (1.0f - newParams.width) * 0.5f;
dry = newParams.dryLevel * dryScaleFactor;
dryGain.setValue (newParams.dryLevel * dryScaleFactor);
wetGain1.setValue (0.5f * wet * (1.0f + newParams.width));
wetGain2.setValue (0.5f * wet * (1.0f - newParams.width));
gain = isFrozen (newParams.freezeMode) ? 0.0f : 0.015f;
parameters = newParams;
shouldUpdateDamping = true;
updateDamping();
}
//==============================================================================
@ -115,7 +116,12 @@ public:
allPass[1][i].setSize ((intSampleRate * (allPassTunings[i] + stereoSpread)) / 44100);
}
shouldUpdateDamping = true;
const double smoothTime = 0.01;
damping .reset (sampleRate, smoothTime);
feedback.reset (sampleRate, smoothTime);
dryGain .reset (sampleRate, smoothTime);
wetGain1.reset (sampleRate, smoothTime);
wetGain2.reset (sampleRate, smoothTime);
}
/** Clears the reverb's buffers. */
@ -137,18 +143,18 @@ public:
{
jassert (left != nullptr && right != nullptr);
if (shouldUpdateDamping)
updateDamping();
for (int i = 0; i < numSamples; ++i)
{
const float input = (left[i] + right[i]) * gain;
float outL = 0, outR = 0;
const float damp = damping.getNextValue();
const float feedbck = feedback.getNextValue();
for (int j = 0; j < numCombs; ++j) // accumulate the comb filters in parallel
{
outL += comb[0][j].process (input);
outR += comb[1][j].process (input);
outL += comb[0][j].process (input, damp, feedbck);
outR += comb[1][j].process (input, damp, feedbck);
}
for (int j = 0; j < numAllPasses; ++j) // run the allpass filters in series
@ -157,6 +163,10 @@ public:
outR = allPass[1][j].process (outR);
}
const float dry = dryGain.getNextValue();
const float wet1 = wetGain1.getNextValue();
const float wet2 = wetGain2.getNextValue();
left[i] = outL * wet1 + outR * wet2 + left[i] * dry;
right[i] = outR * wet1 + outL * wet2 + right[i] * dry;
}
@ -167,32 +177,30 @@ public:
{
jassert (samples != nullptr);
if (shouldUpdateDamping)
updateDamping();
for (int i = 0; i < numSamples; ++i)
{
const float input = samples[i] * gain;
float output = 0;
const float damp = damping.getNextValue();
const float feedbck = feedback.getNextValue();
for (int j = 0; j < numCombs; ++j) // accumulate the comb filters in parallel
output += comb[0][j].process (input);
output += comb[0][j].process (input, damp, feedbck);
for (int j = 0; j < numAllPasses; ++j) // run the allpass filters in series
output = allPass[0][j].process (output);
const float dry = dryGain.getNextValue();
const float wet1 = wetGain1.getNextValue();
samples[i] = output * wet1 + samples[i] * dry;
}
}
private:
//==============================================================================
Parameters parameters;
volatile bool shouldUpdateDamping;
float gain, wet1, wet2, dry;
inline static bool isFrozen (const float freezeMode) noexcept { return freezeMode >= 0.5f; }
static bool isFrozen (const float freezeMode) noexcept { return freezeMode >= 0.5f; }
void updateDamping() noexcept
{
@ -200,8 +208,6 @@ private:
const float roomOffset = 0.7f;
const float dampScaleFactor = 0.4f;
shouldUpdateDamping = false;
if (isFrozen (parameters.freezeMode))
setDamping (0.0f, 1.0f);
else
@ -211,19 +217,15 @@ private:
void setDamping (const float dampingToUse, const float roomSizeToUse) noexcept
{
for (int j = 0; j < numChannels; ++j)
for (int i = numCombs; --i >= 0;)
comb[j][i].setFeedbackAndDamp (roomSizeToUse, dampingToUse);
damping.setValue (dampingToUse);
feedback.setValue (roomSizeToUse);
}
//==============================================================================
class CombFilter
{
public:
CombFilter() noexcept
: bufferSize (0), bufferIndex (0),
feedback (0), last (0), damp1 (0), damp2 (0)
{}
CombFilter() noexcept : bufferSize (0), bufferIndex (0), last (0) {}
void setSize (const int size)
{
@ -243,22 +245,15 @@ private:
buffer.clear ((size_t) bufferSize);
}
void setFeedbackAndDamp (const float f, const float d) noexcept
{
damp1 = d;
damp2 = 1.0f - d;
feedback = f;
}
inline float process (const float input) noexcept
float process (const float input, const float damp, const float feedbackLevel) noexcept
{
const float output = buffer [bufferIndex];
last = (output * damp2) + (last * damp1);
const float output = buffer[bufferIndex];
last = (output * (1.0f - damp)) + (last * damp);
JUCE_UNDENORMALISE (last);
float temp = input + (last * feedback);
float temp = input + (last * feedbackLevel);
JUCE_UNDENORMALISE (temp);
buffer [bufferIndex] = temp;
buffer[bufferIndex] = temp;
bufferIndex = (bufferIndex + 1) % bufferSize;
return output;
}
@ -266,7 +261,7 @@ private:
private:
HeapBlock<float> buffer;
int bufferSize, bufferIndex;
float feedback, last, damp1, damp2;
float last;
JUCE_DECLARE_NON_COPYABLE (CombFilter)
};
@ -294,7 +289,7 @@ private:
buffer.clear ((size_t) bufferSize);
}
inline float process (const float input) noexcept
float process (const float input) noexcept
{
const float bufferedValue = buffer [bufferIndex];
float temp = input + (bufferedValue * 0.5f);
@ -311,11 +306,65 @@ private:
JUCE_DECLARE_NON_COPYABLE (AllPassFilter)
};
//==============================================================================
class LinearSmoothedValue
{
public:
LinearSmoothedValue() noexcept
: currentValue (0), target (0), step (0), countdown (0), stepsToTarget (0)
{
}
void reset (double sampleRate, double fadeLengthSeconds) noexcept
{
jassert (sampleRate > 0 && fadeLengthSeconds >= 0);
stepsToTarget = (int) std::floor (fadeLengthSeconds * sampleRate);
currentValue = target;
countdown = 0;
}
void setValue (float newValue) noexcept
{
if (target != newValue)
{
target = newValue;
countdown = stepsToTarget;
if (countdown <= 0)
currentValue = target;
else
step = (target - currentValue) / (float) countdown;
}
}
float getNextValue() noexcept
{
if (countdown <= 0)
return target;
--countdown;
currentValue += step;
return currentValue;
}
private:
float currentValue, target, step;
int countdown, stepsToTarget;
JUCE_DECLARE_NON_COPYABLE (LinearSmoothedValue)
};
//==============================================================================
enum { numCombs = 8, numAllPasses = 4, numChannels = 2 };
Parameters parameters;
float gain;
CombFilter comb [numChannels][numCombs];
AllPassFilter allPass [numChannels][numAllPasses];
LinearSmoothedValue damping, feedback, dryGain, wetGain1, wetGain2;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Reverb)
};

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -66,6 +66,9 @@
#if __ARM_NEON__ && ! (JUCE_USE_VDSP_FRAMEWORK || defined (JUCE_USE_ARM_NEON))
#define JUCE_USE_ARM_NEON 1
#endif
#if JUCE_USE_ARM_NEON
#include <arm_neon.h>
#endif
@ -77,6 +80,7 @@ namespace juce
#include "buffers/juce_FloatVectorOperations.cpp"
#include "effects/juce_IIRFilter.cpp"
#include "effects/juce_LagrangeInterpolator.cpp"
#include "effects/juce_FFT.cpp"
#include "midi/juce_MidiBuffer.cpp"
#include "midi/juce_MidiFile.cpp"
#include "midi/juce_MidiKeyboardState.cpp"

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -31,12 +31,16 @@
namespace juce
{
#undef Complex // apparently some C libraries actually define these symbols (!)
#undef Factor
#include "buffers/juce_AudioDataConverters.h"
#include "buffers/juce_AudioSampleBuffer.h"
#include "buffers/juce_FloatVectorOperations.h"
#include "effects/juce_Decibels.h"
#include "effects/juce_IIRFilter.h"
#include "effects/juce_LagrangeInterpolator.h"
#include "effects/juce_FFT.h"
#include "effects/juce_Reverb.h"
#include "midi/juce_MidiMessage.h"
#include "midi/juce_MidiBuffer.h"

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -1,7 +1,7 @@
{
"id": "juce_audio_basics",
"name": "JUCE audio and midi data classes",
"version": "3.0.8",
"version": "3.2.0",
"description": "Classes for audio buffer manipulation, midi message handling, synthesis, etc",
"website": "http://www.juce.com/juce",
"license": "GPL/Commercial",

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -26,12 +26,12 @@ namespace MidiBufferHelpers
{
inline int getEventTime (const void* const d) noexcept
{
return *static_cast<const int32*> (d);
return readUnaligned<int32> (d);
}
inline uint16 getEventDataSize (const void* const d) noexcept
{
return *reinterpret_cast<const uint16*> (static_cast<const char*> (d) + sizeof (int32));
return readUnaligned<uint16> (static_cast<const char*> (d) + sizeof (int32));
}
inline uint16 getEventTotalSize (const void* const d) noexcept
@ -124,8 +124,8 @@ void MidiBuffer::addEvent (const void* const newData, const int maxBytes, const
data.insertMultiple (offset, 0, (int) newItemSize);
uint8* const d = data.begin() + offset;
*reinterpret_cast<int32*> (d) = sampleNumber;
*reinterpret_cast<uint16*> (d + 4) = (uint16) numBytes;
writeUnaligned<int32> (d, sampleNumber);
writeUnaligned<uint16> (d + 4, static_cast<uint16> (numBytes));
memcpy (d + 6, newData, (size_t) numBytes);
}
}

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -145,7 +145,7 @@ void MidiKeyboardState::processNextMidiBuffer (MidiBuffer& buffer,
const bool injectIndirectEvents)
{
MidiBuffer::Iterator i (buffer);
MidiMessage message (0xf4, 0.0);
MidiMessage message;
int time;
const ScopedLock sl (lock);

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -276,14 +276,11 @@ void MidiMessageSequence::deleteSysExMessages()
}
//==============================================================================
void MidiMessageSequence::createControllerUpdatesForTime (const int channelNumber,
const double time,
OwnedArray<MidiMessage>& dest)
void MidiMessageSequence::createControllerUpdatesForTime (const int channelNumber, const double time, Array<MidiMessage>& dest)
{
bool doneProg = false;
bool donePitchWheel = false;
Array<int> doneControllers;
doneControllers.ensureStorageAllocated (32);
bool doneControllers[128] = { 0 };
for (int i = list.size(); --i >= 0;)
{
@ -291,28 +288,25 @@ void MidiMessageSequence::createControllerUpdatesForTime (const int channelNumbe
if (mm.isForChannel (channelNumber) && mm.getTimeStamp() <= time)
{
if (mm.isProgramChange())
if (mm.isProgramChange() && ! doneProg)
{
if (! doneProg)
{
dest.add (new MidiMessage (mm, 0.0));
doneProg = true;
}
doneProg = true;
dest.add (MidiMessage (mm, 0.0));
}
else if (mm.isController())
else if (mm.isPitchWheel() && ! donePitchWheel)
{
if (! doneControllers.contains (mm.getControllerNumber()))
{
dest.add (new MidiMessage (mm, 0.0));
doneControllers.add (mm.getControllerNumber());
}
donePitchWheel = true;
dest.add (MidiMessage (mm, 0.0));
}
else if (mm.isPitchWheel())
else if (mm.isController())
{
if (! donePitchWheel)
const int controllerNumber = mm.getControllerNumber();
jassert (isPositiveAndBelow (controllerNumber, 128));
if (! doneControllers[controllerNumber])
{
dest.add (new MidiMessage (mm, 0.0));
donePitchWheel = true;
doneControllers[controllerNumber] = true;
dest.add (MidiMessage (mm, 0.0));
}
}
}

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -247,7 +247,7 @@ public:
state at the required time.
*/
void createControllerUpdatesForTime (int channelNumber, double time,
OwnedArray<MidiMessage>& resultMessages);
Array<MidiMessage>& resultMessages);
//==============================================================================
/** Swaps this sequence with another one. */

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -24,14 +24,14 @@
ResamplingAudioSource::ResamplingAudioSource (AudioSource* const inputSource,
const bool deleteInputWhenDeleted,
const int numChannels_)
const int channels)
: input (inputSource, deleteInputWhenDeleted),
ratio (1.0),
lastRatio (1.0),
bufferPos (0),
sampsInBuffer (0),
subSampleOffset (0),
numChannels (numChannels_)
numChannels (channels)
{
jassert (input != nullptr);
zeromem (coefficients, sizeof (coefficients));
@ -51,9 +51,10 @@ void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected, double s
{
const SpinLock::ScopedLockType sl (ratioLock);
input->prepareToPlay (samplesPerBlockExpected, sampleRate);
const int scaledBlockSize = roundToInt (samplesPerBlockExpected * ratio);
input->prepareToPlay (scaledBlockSize, sampleRate * ratio);
buffer.setSize (numChannels, roundToInt (samplesPerBlockExpected * ratio) + 32);
buffer.setSize (numChannels, scaledBlockSize + 32);
filterStates.calloc ((size_t) numChannels);
srcBuffers.calloc ((size_t) numChannels);
@ -93,7 +94,7 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf
lastRatio = localRatio;
}
const int sampsNeeded = roundToInt (info.numSamples * localRatio) + 2;
const int sampsNeeded = roundToInt (info.numSamples * localRatio) + 3;
int bufferSize = buffer.getNumSamples();
@ -138,8 +139,11 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf
}
int nextPos = (bufferPos + 1) % bufferSize;
for (int m = info.numSamples; --m >= 0;)
{
jassert (sampsInBuffer > 0 && nextPos != endOfBufferPos);
const float alpha = (float) subSampleOffset;
for (int channel = 0; channel < channelsToProcess; ++channel)
@ -148,8 +152,6 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf
subSampleOffset += localRatio;
jassert (sampsInBuffer > 0);
while (subSampleOffset >= 1.0)
{
if (++bufferPos >= bufferSize)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -29,8 +29,10 @@ SynthesiserSound::~SynthesiserSound() {}
SynthesiserVoice::SynthesiserVoice()
: currentSampleRate (44100.0),
currentlyPlayingNote (-1),
currentPlayingMidiChannel (0),
noteOnTime (0),
keyIsDown (false),
sustainPedalDown (false),
sostenutoPedalDown (false)
{
}
@ -41,8 +43,7 @@ SynthesiserVoice::~SynthesiserVoice()
bool SynthesiserVoice::isPlayingChannel (const int midiChannel) const
{
return currentlyPlayingSound != nullptr
&& currentlyPlayingSound->appliesToChannel (midiChannel);
return currentPlayingMidiChannel == midiChannel;
}
void SynthesiserVoice::setCurrentPlaybackSampleRate (const double newRate)
@ -59,9 +60,11 @@ void SynthesiserVoice::clearCurrentNote()
{
currentlyPlayingNote = -1;
currentlyPlayingSound = nullptr;
currentPlayingMidiChannel = 0;
}
void SynthesiserVoice::aftertouchChanged (int) {}
void SynthesiserVoice::channelPressureChanged (int) {}
bool SynthesiserVoice::wasStartedBefore (const SynthesiserVoice& other) const noexcept
{
@ -72,6 +75,7 @@ bool SynthesiserVoice::wasStartedBefore (const SynthesiserVoice& other) const no
Synthesiser::Synthesiser()
: sampleRate (0),
lastNoteOnCounter (0),
minimumSubBlockSize (32),
shouldStealNotes (true)
{
for (int i = 0; i < numElementsInArray (lastPitchWheelValues); ++i)
@ -130,6 +134,12 @@ void Synthesiser::setNoteStealingEnabled (const bool shouldSteal)
shouldStealNotes = shouldSteal;
}
void Synthesiser::setMinimumRenderingSubdivisionSize (int numSamples) noexcept
{
jassert (numSamples > 0); // it wouldn't make much sense for this to be less than 1
minimumSubBlockSize = numSamples;
}
//==============================================================================
void Synthesiser::setCurrentPlaybackSampleRate (const double newRate)
{
@ -152,30 +162,45 @@ void Synthesiser::renderNextBlock (AudioSampleBuffer& outputBuffer, const MidiBu
// must set the sample rate before using this!
jassert (sampleRate != 0);
const ScopedLock sl (lock);
MidiBuffer::Iterator midiIterator (midiData);
midiIterator.setNextSamplePosition (startSample);
MidiMessage m (0xf4, 0.0);
int midiEventPos;
MidiMessage m;
const ScopedLock sl (lock);
while (numSamples > 0)
{
int midiEventPos;
const bool useEvent = midiIterator.getNextEvent (m, midiEventPos)
&& midiEventPos < startSample + numSamples;
if (! midiIterator.getNextEvent (m, midiEventPos))
{
renderVoices (outputBuffer, startSample, numSamples);
return;
}
const int numThisTime = useEvent ? midiEventPos - startSample
: numSamples;
const int samplesToNextMidiMessage = midiEventPos - startSample;
if (numThisTime > 0)
renderVoices (outputBuffer, startSample, numThisTime);
if (samplesToNextMidiMessage >= numSamples)
{
renderVoices (outputBuffer, startSample, numSamples);
handleMidiEvent (m);
break;
}
if (useEvent)
if (samplesToNextMidiMessage < minimumSubBlockSize)
{
handleMidiEvent (m);
continue;
}
startSample += numThisTime;
numSamples -= numThisTime;
renderVoices (outputBuffer, startSample, samplesToNextMidiMessage);
handleMidiEvent (m);
startSample += samplesToNextMidiMessage;
numSamples -= samplesToNextMidiMessage;
}
while (midiIterator.getNextEvent (m, midiEventPos))
handleMidiEvent (m);
}
void Synthesiser::renderVoices (AudioSampleBuffer& buffer, int startSample, int numSamples)
@ -186,33 +211,41 @@ void Synthesiser::renderVoices (AudioSampleBuffer& buffer, int startSample, int
void Synthesiser::handleMidiEvent (const MidiMessage& m)
{
const int channel = m.getChannel();
if (m.isNoteOn())
{
noteOn (m.getChannel(), m.getNoteNumber(), m.getFloatVelocity());
noteOn (channel, m.getNoteNumber(), m.getFloatVelocity());
}
else if (m.isNoteOff())
{
noteOff (m.getChannel(), m.getNoteNumber(), m.getFloatVelocity(), true);
noteOff (channel, m.getNoteNumber(), m.getFloatVelocity(), true);
}
else if (m.isAllNotesOff() || m.isAllSoundOff())
{
allNotesOff (m.getChannel(), true);
allNotesOff (channel, true);
}
else if (m.isPitchWheel())
{
const int channel = m.getChannel();
const int wheelPos = m.getPitchWheelValue();
lastPitchWheelValues [channel - 1] = wheelPos;
handlePitchWheel (channel, wheelPos);
}
else if (m.isAftertouch())
{
handleAftertouch (m.getChannel(), m.getNoteNumber(), m.getAfterTouchValue());
handleAftertouch (channel, m.getNoteNumber(), m.getAfterTouchValue());
}
else if (m.isChannelPressure())
{
handleChannelPressure (channel, m.getChannelPressureValue());
}
else if (m.isController())
{
handleController (m.getChannel(), m.getControllerNumber(), m.getControllerValue());
handleController (channel, m.getControllerNumber(), m.getControllerValue());
}
else if (m.isProgramChange())
{
handleProgramChange (channel, m.getProgramChangeNumber());
}
}
@ -258,14 +291,16 @@ void Synthesiser::startVoice (SynthesiserVoice* const voice,
if (voice->currentlyPlayingSound != nullptr)
voice->stopNote (0.0f, false);
voice->startNote (midiNoteNumber, velocity, sound,
lastPitchWheelValues [midiChannel - 1]);
voice->currentlyPlayingNote = midiNoteNumber;
voice->currentPlayingMidiChannel = midiChannel;
voice->noteOnTime = ++lastNoteOnCounter;
voice->currentlyPlayingSound = sound;
voice->keyIsDown = true;
voice->sostenutoPedalDown = false;
voice->sustainPedalDown = sustainPedalsDown[midiChannel];
voice->startNote (midiNoteNumber, velocity, sound,
lastPitchWheelValues [midiChannel - 1]);
}
}
@ -290,16 +325,19 @@ void Synthesiser::noteOff (const int midiChannel,
{
SynthesiserVoice* const voice = voices.getUnchecked (i);
if (voice->getCurrentlyPlayingNote() == midiNoteNumber)
if (voice->getCurrentlyPlayingNote() == midiNoteNumber
&& voice->isPlayingChannel (midiChannel))
{
if (SynthesiserSound* const sound = voice->getCurrentlyPlayingSound())
{
if (sound->appliesToNote (midiNoteNumber)
&& sound->appliesToChannel (midiChannel))
{
jassert (! voice->keyIsDown || voice->sustainPedalDown == sustainPedalsDown [midiChannel]);
voice->keyIsDown = false;
if (! (sustainPedalsDown [midiChannel] || voice->sostenutoPedalDown))
if (! (voice->sustainPedalDown || voice->sostenutoPedalDown))
stopVoice (voice, velocity, allowTailOff);
}
}
@ -372,6 +410,19 @@ void Synthesiser::handleAftertouch (int midiChannel, int midiNoteNumber, int aft
}
}
void Synthesiser::handleChannelPressure (int midiChannel, int channelPressureValue)
{
const ScopedLock sl (lock);
for (int i = voices.size(); --i >= 0;)
{
SynthesiserVoice* const voice = voices.getUnchecked (i);
if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
voice->channelPressureChanged (channelPressureValue);
}
}
void Synthesiser::handleSustainPedal (int midiChannel, bool isDown)
{
jassert (midiChannel > 0 && midiChannel <= 16);
@ -380,6 +431,14 @@ void Synthesiser::handleSustainPedal (int midiChannel, bool isDown)
if (isDown)
{
sustainPedalsDown.setBit (midiChannel);
for (int i = voices.size(); --i >= 0;)
{
SynthesiserVoice* const voice = voices.getUnchecked (i);
if (voice->isPlayingChannel (midiChannel) && voice->isKeyDown())
voice->sustainPedalDown = true;
}
}
else
{
@ -387,8 +446,13 @@ void Synthesiser::handleSustainPedal (int midiChannel, bool isDown)
{
SynthesiserVoice* const voice = voices.getUnchecked (i);
if (voice->isPlayingChannel (midiChannel) && ! voice->keyIsDown)
stopVoice (voice, 1.0f, true);
if (voice->isPlayingChannel (midiChannel))
{
voice->sustainPedalDown = false;
if (! voice->isKeyDown())
stopVoice (voice, 1.0f, true);
}
}
sustainPedalsDown.clearBit (midiChannel);
@ -420,6 +484,12 @@ void Synthesiser::handleSoftPedal (int midiChannel, bool /*isDown*/)
jassert (midiChannel > 0 && midiChannel <= 16);
}
void Synthesiser::handleProgramChange (int midiChannel, int programNumber)
{
(void) midiChannel; (void) programNumber;
jassert (midiChannel > 0 && midiChannel <= 16);
}
//==============================================================================
SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay,
int midiChannel, int midiNoteNumber,
@ -445,15 +515,20 @@ struct VoiceAgeSorter
{
static int compareElements (SynthesiserVoice* v1, SynthesiserVoice* v2) noexcept
{
return v1->wasStartedBefore (*v2) ? 1 : (v2->wasStartedBefore (*v1) ? -1 : 0);
return v1->wasStartedBefore (*v2) ? -1 : (v2->wasStartedBefore (*v1) ? 1 : 0);
}
};
SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay,
int /*midiChannel*/, int midiNoteNumber) const
{
SynthesiserVoice* bottom = nullptr;
SynthesiserVoice* top = nullptr;
// This voice-stealing algorithm applies the following heuristics:
// - Re-use the oldest notes first
// - Protect the lowest & topmost notes, even if sustained, but not if they've been released.
// These are the voices we want to protect (ie: only steal if unavoidable)
SynthesiserVoice* low = nullptr; // Lowest sounding note, might be sustained, but NOT in release phase
SynthesiserVoice* top = nullptr; // Highest sounding note, might be sustained, but NOT in release phase
// this is a list of voices we can steal, sorted by how long they've been running
Array<SynthesiserVoice*> usableVoices;
@ -465,23 +540,32 @@ SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay,
if (voice->canPlaySound (soundToPlay))
{
jassert (voice->isVoiceActive()); // We wouldn't be here otherwise
VoiceAgeSorter sorter;
usableVoices.addSorted (sorter, voice);
const int note = voice->getCurrentlyPlayingNote();
if (! voice->isPlayingButReleased()) // Don't protect released notes
{
const int note = voice->getCurrentlyPlayingNote();
if (bottom == nullptr || note < bottom->getCurrentlyPlayingNote())
bottom = voice;
if (low == nullptr || note < low->getCurrentlyPlayingNote())
low = voice;
if (top == nullptr || note > top->getCurrentlyPlayingNote())
top = voice;
if (top == nullptr || note > top->getCurrentlyPlayingNote())
top = voice;
}
}
}
jassert (bottom != nullptr && top != nullptr);
// Eliminate pathological cases (ie: only 1 note playing): we always give precedence to the lowest note(s)
if (top == low)
top = nullptr;
const int numUsableVoices = usableVoices.size();
// The oldest note that's playing with the target pitch playing is ideal..
for (int i = 0; i < usableVoices.size(); ++i)
// The oldest note that's playing with the target pitch is ideal..
for (int i = 0; i < numUsableVoices; ++i)
{
SynthesiserVoice* const voice = usableVoices.getUnchecked (i);
@ -489,15 +573,39 @@ SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay,
return voice;
}
// ..otherwise, look for the oldest note that isn't the top or bottom note..
for (int i = 0; i < usableVoices.size(); ++i)
// Oldest voice that has been released (no finger on it and not held by sustain pedal)
for (int i = 0; i < numUsableVoices; ++i)
{
SynthesiserVoice* const voice = usableVoices.getUnchecked (i);
if (voice != bottom && voice != top)
if (voice != low && voice != top && voice->isPlayingButReleased())
return voice;
}
// ..otherwise, there's only one or two voices to choose from - we'll return the top one..
return top;
// Oldest voice that doesn't have a finger on it:
for (int i = 0; i < numUsableVoices; ++i)
{
SynthesiserVoice* const voice = usableVoices.getUnchecked (i);
if (voice != low && voice != top && ! voice->isKeyDown())
return voice;
}
// Oldest voice that isn't protected
for (int i = 0; i < numUsableVoices; ++i)
{
SynthesiserVoice* const voice = usableVoices.getUnchecked (i);
if (voice != low && voice != top)
return voice;
}
// We've only got "protected" voices now: lowest note takes priority
jassert (low != nullptr);
// Duophonic synth: give priority to the bass note:
if (top != nullptr)
return top;
return low;
}

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -161,6 +161,11 @@ public:
*/
virtual void aftertouchChanged (int newAftertouchValue);
/** Called to let the voice know that the channel pressure has changed.
This will be called during the rendering callback, so must be fast and thread-safe.
*/
virtual void channelPressureChanged (int newChannelPressureValue);
//==============================================================================
/** Renders the next block of data for this voice.
@ -191,17 +196,17 @@ public:
*/
virtual void setCurrentPlaybackSampleRate (double newRate);
/** Returns the current target sample rate at which rendering is being done.
Subclasses may need to know this so that they can pitch things correctly.
*/
double getSampleRate() const noexcept { return currentSampleRate; }
/** Returns true if the voice is currently playing a sound which is mapped to the given
midi channel.
If it's not currently playing, this will return false.
*/
bool isPlayingChannel (int midiChannel) const;
virtual bool isPlayingChannel (int midiChannel) const;
/** Returns the current target sample rate at which rendering is being done.
Subclasses may need to know this so that they can pitch things correctly.
*/
double getSampleRate() const noexcept { return currentSampleRate; }
/** Returns true if the key that triggered this voice is still held down.
Note that the voice may still be playing after the key was released (e.g because the
@ -209,9 +214,18 @@ public:
*/
bool isKeyDown() const noexcept { return keyIsDown; }
/** Returns true if the sustain pedal is currently active for this voice. */
bool isSustainPedalDown() const noexcept { return sustainPedalDown; }
/** Returns true if the sostenuto pedal is currently active for this voice. */
bool isSostenutoPedalDown() const noexcept { return sostenutoPedalDown; }
/** Returns true if a voice is sounding in its release phase **/
bool isPlayingButReleased() const noexcept
{
return isVoiceActive() && ! (isKeyDown() || isSostenutoPedalDown() || isSustainPedalDown());
}
/** Returns true if this voice started playing its current note before the other voice did. */
bool wasStartedBefore (const SynthesiserVoice& other) const noexcept;
@ -236,10 +250,10 @@ private:
friend class Synthesiser;
double currentSampleRate;
int currentlyPlayingNote;
int currentlyPlayingNote, currentPlayingMidiChannel;
uint32 noteOnTime;
SynthesiserSound::Ptr currentlyPlayingSound;
bool keyIsDown, sostenutoPedalDown;
bool keyIsDown, sustainPedalDown, sostenutoPedalDown;
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
// Note the new parameters for this method.
@ -440,6 +454,20 @@ public:
*/
virtual void handleAftertouch (int midiChannel, int midiNoteNumber, int aftertouchValue);
/** Sends a channel pressure message.
This will send a channel pressure message to any voices that are playing sounds on
the given midi channel.
This method will be called automatically according to the midi data passed into
renderNextBlock(), but may be called explicitly too.
@param midiChannel the midi channel, from 1 to 16 inclusive
@param channelPressureValue the pressure value, between 0 and 127, as returned
by MidiMessage::getChannelPressureValue()
*/
virtual void handleChannelPressure (int midiChannel, int channelPressureValue);
/** Handles a sustain pedal event. */
virtual void handleSustainPedal (int midiChannel, bool isDown);
@ -449,6 +477,13 @@ public:
/** Can be overridden to handle soft pedal events. */
virtual void handleSoftPedal (int midiChannel, bool isDown);
/** Can be overridden to handle an incoming program change message.
The base class implementation of this has no effect, but you may want to make your
own synth react to program changes.
*/
virtual void handleProgramChange (int midiChannel,
int programNumber);
//==============================================================================
/** Tells the synthesiser what the sample rate is for the audio it's being used to render.
@ -479,6 +514,22 @@ public:
*/
double getSampleRate() const noexcept { return sampleRate; }
/** Sets a minimum limit on the size to which audio sub-blocks will be divided when rendering.
When rendering, the audio blocks that are passed into renderNextBlock() will be split up
into smaller blocks that lie between all the incoming midi messages, and it is these smaller
sub-blocks that are rendered with multiple calls to renderVoices().
Obviously in a pathological case where there are midi messages on every sample, then
renderVoices() could be called once per sample and lead to poor performance, so this
setting allows you to set a lower limit on the block size.
The default setting is 32, which means that midi messages are accurate to about < 1ms
accuracy, which is probably fine for most purposes, but you may want to increase or
decrease this value for your synth.
*/
void setMinimumRenderingSubdivisionSize (int numSamples) noexcept;
protected:
//==============================================================================
/** This is used to control access to the rendering callback and the note trigger methods. */
@ -537,6 +588,7 @@ private:
//==============================================================================
double sampleRate;
uint32 lastNoteOnCounter;
int minimumSubBlockSize;
bool shouldStealNotes;
BigInteger sustainPedalsDown;

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -92,7 +92,6 @@ AudioDeviceManager::AudioDeviceManager()
: numInputChansNeeded (0),
numOutputChansNeeded (2),
listNeedsScanning (true),
useInputNames (false),
inputLevel (0),
testSoundPosition (0),
cpuUsageMs (0),
@ -154,7 +153,8 @@ static void addIfNotNull (OwnedArray<AudioIODeviceType>& list, AudioIODeviceType
void AudioDeviceManager::createAudioDeviceTypes (OwnedArray<AudioIODeviceType>& list)
{
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI());
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI (false));
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI (true));
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_DirectSound());
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_ASIO());
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_CoreAudio());
@ -177,6 +177,17 @@ void AudioDeviceManager::addAudioDeviceType (AudioIODeviceType* newDeviceType)
}
}
static bool deviceListContains (AudioIODeviceType* type, bool isInput, const String& name)
{
StringArray devices (type->getDeviceNames (isInput));
for (int i = devices.size(); --i >= 0;)
if (devices[i].trim().equalsIgnoreCase (name.trim()))
return true;
return false;
}
//==============================================================================
String AudioDeviceManager::initialise (const int numInputChannelsNeeded,
const int numOutputChannelsNeeded,
@ -363,8 +374,8 @@ AudioIODeviceType* AudioDeviceManager::findType (const String& inputName, const
{
AudioIODeviceType* const type = availableDeviceTypes.getUnchecked(i);
if ((inputName.isNotEmpty() && type->getDeviceNames (true).contains (inputName, true))
|| (outputName.isNotEmpty() && type->getDeviceNames (false).contains (outputName, true)))
if ((inputName.isNotEmpty() && deviceListContains (type, true, inputName))
|| (outputName.isNotEmpty() && deviceListContains (type, false, outputName)))
{
return type;
}
@ -458,17 +469,11 @@ String AudioDeviceManager::setAudioDeviceSetup (const AudioDeviceSetup& newSetup
deleteCurrentDevice();
scanDevicesIfNeeded();
if (newOutputDeviceName.isNotEmpty()
&& ! type->getDeviceNames (false).contains (newOutputDeviceName))
{
if (newOutputDeviceName.isNotEmpty() && ! deviceListContains (type, false, newOutputDeviceName))
return "No such device: " + newOutputDeviceName;
}
if (newInputDeviceName.isNotEmpty()
&& ! type->getDeviceNames (true).contains (newInputDeviceName))
{
if (newInputDeviceName.isNotEmpty() && ! deviceListContains (type, true, newInputDeviceName))
return "No such device: " + newInputDeviceName;
}
currentAudioDevice = type->createDevice (newOutputDeviceName, newInputDeviceName);
@ -546,6 +551,11 @@ double AudioDeviceManager::chooseBestSampleRate (double rate) const
const Array<double> rates (currentAudioDevice->getAvailableSampleRates());
if (rate > 0 && rates.contains (rate))
return rate;
rate = currentAudioDevice->getCurrentSampleRate();
if (rate > 0 && rates.contains (rate))
return rate;

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -450,7 +450,6 @@ private:
BigInteger inputChannels, outputChannels;
ScopedPointer<XmlElement> lastExplicitSettings;
mutable bool listNeedsScanning;
bool useInputNames;
Atomic<int> inputLevelMeasurementEnabledCount;
double inputLevel;
ScopedPointer<AudioSampleBuffer> testSound;

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -50,7 +50,7 @@ AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_iOSAudio()
#endif
#if ! (JUCE_WINDOWS && JUCE_WASAPI)
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_WASAPI() { return nullptr; }
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_WASAPI (bool) { return nullptr; }
#endif
#if ! (JUCE_WINDOWS && JUCE_DIRECTSOUND)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -151,7 +151,7 @@ public:
/** Creates an iOS device type if it's available on this platform, or returns null. */
static AudioIODeviceType* createAudioIODeviceType_iOSAudio();
/** Creates a WASAPI device type if it's available on this platform, or returns null. */
static AudioIODeviceType* createAudioIODeviceType_WASAPI();
static AudioIODeviceType* createAudioIODeviceType_WASAPI (bool exclusiveMode);
/** Creates a DirectSound device type if it's available on this platform, or returns null. */
static AudioIODeviceType* createAudioIODeviceType_DirectSound();
/** Creates an ASIO device type if it's available on this platform, or returns null. */

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -72,7 +72,7 @@
This means that anyone who wants to use JUCE's ASIO abilities will have to:
1) Agree to Steinberg's licensing terms and download the ASIO SDK
(see www.steinberg.net/Steinberg/Developers.asp).
(see http://www.steinberg.net/en/company/developers.html).
2) Enable this code with a global definition #define JUCE_ASIO 1.

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -43,12 +43,21 @@
#endif
/** Config: JUCE_WASAPI
Enables WASAPI audio devices (Windows Vista and above).
Enables WASAPI audio devices (Windows Vista and above). See also the
JUCE_WASAPI_EXCLUSIVE flag.
*/
#ifndef JUCE_WASAPI
#define JUCE_WASAPI 1
#endif
/** Config: JUCE_WASAPI_EXCLUSIVE
Enables WASAPI audio devices in exclusive mode (Windows Vista and above).
*/
#ifndef JUCE_WASAPI_EXCLUSIVE
#define JUCE_WASAPI_EXCLUSIVE 0
#endif
/** Config: JUCE_DIRECTSOUND
Enables DirectSound audio (MS Windows only).
*/

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -1,7 +1,7 @@
{
"id": "juce_audio_devices",
"name": "JUCE audio and midi I/O device classes",
"version": "3.0.8",
"version": "3.2.0",
"description": "Classes to play and record from audio and midi i/o devices.",
"website": "http://www.juce.com/juce",
"license": "GPL/Commercial",

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -139,7 +139,7 @@ public:
//==============================================================================
/** Destructor. */
virtual ~MidiInput();
~MidiInput();
/** Returns the name of this device. */
const String& getName() const noexcept { return name; }
@ -158,23 +158,21 @@ public:
@see stop
*/
virtual void start();
void start();
/** Stops the device running.
@see start
*/
virtual void stop();
void stop();
protected:
private:
//==============================================================================
String name;
void* internal;
explicit MidiInput (const String& name);
// The input objects are created with the openDevice() method.
explicit MidiInput (const String&);
private:
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiInput)
};

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -82,13 +82,12 @@ public:
//==============================================================================
/** Destructor. */
virtual ~MidiOutput();
~MidiOutput();
/** Makes this device output a midi message.
@see MidiMessage
*/
virtual void sendMessageNow (const MidiMessage& message);
void sendMessageNow (const MidiMessage& message);
//==============================================================================
/** This lets you supply a block of messages that will be sent out at some point
@ -100,7 +99,7 @@ public:
This will only work if you've already started the thread with startBackgroundThread().
A time is supplied, at which the block of messages should be sent. This time uses
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
@ -108,38 +107,34 @@ public:
samplesPerSecondForBuffer value is needed to convert this sample position to a
real time.
*/
virtual void sendBlockOfMessages (const MidiBuffer& buffer,
double millisecondCounterToStartAt,
double samplesPerSecondForBuffer);
void sendBlockOfMessages (const MidiBuffer& buffer,
double millisecondCounterToStartAt,
double samplesPerSecondForBuffer);
/** Gets rid of any midi messages that had been added by sendBlockOfMessages().
*/
virtual void clearAllPendingMessages();
/** 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().
*/
virtual void startBackgroundThread();
void startBackgroundThread();
/** Stops the background thread, and clears any pending midi events.
@see startBackgroundThread
*/
virtual void stopBackgroundThread();
void stopBackgroundThread();
protected:
private:
//==============================================================================
void* internal;
CriticalSection lock;
struct PendingMessage;
PendingMessage* firstMessage;
MidiOutput();
MidiOutput(); // These objects are created with the openDevice() method.
void run() override;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiOutput)
};

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -47,13 +47,13 @@ public:
// this is a total guess about how to calculate the latency, but seems to vaguely agree
// with the devices I've tested.. YMMV
inputLatency = ((javaDevice.minBufferSizeIn * 2) / 3);
outputLatency = ((javaDevice.minBufferSizeOut * 2) / 3);
inputLatency = (javaDevice.minBufferSizeIn * 2) / 3;
outputLatency = (javaDevice.minBufferSizeOut * 2) / 3;
const int longestLatency = jmax (inputLatency, outputLatency);
const int totalLatency = inputLatency + outputLatency;
inputLatency = ((longestLatency * inputLatency) / totalLatency) & ~15;
outputLatency = ((longestLatency * outputLatency) / totalLatency) & ~15;
const int64 longestLatency = jmax (inputLatency, outputLatency);
const int64 totalLatency = inputLatency + outputLatency;
inputLatency = (int) ((longestLatency * inputLatency) / totalLatency) & ~15;
outputLatency = (int) ((longestLatency * outputLatency) / totalLatency) & ~15;
}
~OpenSLAudioIODevice()

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -30,7 +30,7 @@ namespace
#endif
#if JUCE_ALSA_LOGGING
#define JUCE_ALSA_LOG(dbgtext) { juce::String tempDbgBuf ("ALSA: "); tempDbgBuf << dbgtext; Logger::writeToLog (tempDbgBuf); DBG (tempDbgBuf) }
#define JUCE_ALSA_LOG(dbgtext) { juce::String tempDbgBuf ("ALSA: "); tempDbgBuf << dbgtext; Logger::writeToLog (tempDbgBuf); DBG (tempDbgBuf); }
#define JUCE_CHECKED_RESULT(x) (logErrorMessage (x, __LINE__))
static int logErrorMessage (int err, int lineNum)
@ -57,7 +57,7 @@ static void getDeviceSampleRates (snd_pcm_t* handle, Array<double>& rates)
for (int i = 0; ratesToTry[i] != 0; ++i)
{
if (snd_pcm_hw_params_any (handle, hwParams) >= 0
&& snd_pcm_hw_params_test_rate (handle, hwParams, ratesToTry[i], 0) == 0)
&& snd_pcm_hw_params_test_rate (handle, hwParams, (unsigned int) ratesToTry[i], 0) == 0)
{
rates.addIfNotAlreadyThere ((double) ratesToTry[i]);
}
@ -149,7 +149,7 @@ class ALSADevice
{
public:
ALSADevice (const String& devID, bool forInput)
: handle (0),
: handle (nullptr),
bitDepth (16),
numChannelsRunning (0),
latency (0),
@ -183,16 +183,16 @@ public:
void closeNow()
{
if (handle != 0)
if (handle != nullptr)
{
snd_pcm_close (handle);
handle = 0;
handle = nullptr;
}
}
bool setParameters (unsigned int sampleRate, int numChannels, int bufferSize)
{
if (handle == 0)
if (handle == nullptr)
return false;
JUCE_ALSA_LOG ("ALSADevice::setParameters(" << deviceID << ", "
@ -257,10 +257,10 @@ public:
int dir = 0;
unsigned int periods = 4;
snd_pcm_uframes_t samplesPerPeriod = bufferSize;
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))
|| JUCE_ALSA_FAILED (snd_pcm_hw_params_set_channels (handle, hwParams, numChannels))
|| 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))
|| JUCE_ALSA_FAILED (snd_pcm_hw_params (handle, hwParams)))
@ -274,7 +274,7 @@ public:
|| JUCE_ALSA_FAILED (snd_pcm_hw_params_get_periods (hwParams, &periods, &dir)))
latency = 0;
else
latency = frames * (periods - 1); // (this is the method JACK uses to guess the latency..)
latency = (int) frames * ((int) periods - 1); // (this is the method JACK uses to guess the latency..)
JUCE_ALSA_LOG ("frames: " << (int) frames << ", periods: " << (int) periods
<< ", samplesPerPeriod: " << (int) samplesPerPeriod);
@ -316,22 +316,22 @@ public:
if (isInterleaved)
{
scratch.ensureSize (sizeof (float) * numSamples * numChannelsRunning, false);
scratch.ensureSize ((size_t) ((int) sizeof (float) * numSamples * numChannelsRunning), false);
for (int i = 0; i < numChannelsRunning; ++i)
converter->convertSamples (scratch.getData(), i, data[i], 0, numSamples);
numDone = snd_pcm_writei (handle, scratch.getData(), numSamples);
numDone = snd_pcm_writei (handle, scratch.getData(), (snd_pcm_uframes_t) numSamples);
}
else
{
for (int i = 0; i < numChannelsRunning; ++i)
converter->convertSamples (data[i], data[i], numSamples);
numDone = snd_pcm_writen (handle, (void**) data, numSamples);
numDone = snd_pcm_writen (handle, (void**) data, (snd_pcm_uframes_t) numSamples);
}
if (numDone < 0 && JUCE_ALSA_FAILED (snd_pcm_recover (handle, numDone, 1 /* silent */)))
if (numDone < 0 && JUCE_ALSA_FAILED (snd_pcm_recover (handle, (int) numDone, 1 /* silent */)))
return false;
if (numDone < numSamples)
@ -347,12 +347,12 @@ public:
if (isInterleaved)
{
scratch.ensureSize (sizeof (float) * numSamples * numChannelsRunning, false);
scratch.ensureSize ((size_t) ((int) sizeof (float) * numSamples * numChannelsRunning), false);
scratch.fillWith (0); // (not clearing this data causes warnings in valgrind)
snd_pcm_sframes_t num = snd_pcm_readi (handle, scratch.getData(), numSamples);
snd_pcm_sframes_t num = snd_pcm_readi (handle, scratch.getData(), (snd_pcm_uframes_t) numSamples);
if (num < 0 && JUCE_ALSA_FAILED (snd_pcm_recover (handle, num, 1 /* silent */)))
if (num < 0 && JUCE_ALSA_FAILED (snd_pcm_recover (handle, (int) num, 1 /* silent */)))
return false;
if (num < numSamples)
@ -363,9 +363,9 @@ public:
}
else
{
snd_pcm_sframes_t num = snd_pcm_readn (handle, (void**) data, numSamples);
snd_pcm_sframes_t num = snd_pcm_readn (handle, (void**) data, (snd_pcm_uframes_t) numSamples);
if (num < 0 && JUCE_ALSA_FAILED (snd_pcm_recover (handle, num, 1 /* silent */)))
if (num < 0 && JUCE_ALSA_FAILED (snd_pcm_recover (handle, (int) num, 1 /* silent */)))
return false;
if (num < numSamples)
@ -486,14 +486,17 @@ public:
sampleRate = newSampleRate;
bufferSize = newBufferSize;
inputChannelBuffer.setSize (jmax ((int) minChansIn, inputChannels.getHighestBit()) + 1, bufferSize);
int maxInputsRequested = inputChannels.getHighestBit() + 1;
maxInputsRequested = jmax ((int) minChansIn, jmin ((int) maxChansIn, maxInputsRequested));
inputChannelBuffer.setSize (maxInputsRequested, bufferSize);
inputChannelBuffer.clear();
inputChannelDataForCallback.clear();
currentInputChans.clear();
if (inputChannels.getHighestBit() >= 0)
{
for (int i = 0; i <= jmax (inputChannels.getHighestBit(), (int) minChansIn); ++i)
for (int i = 0; i < maxInputsRequested; ++i)
{
if (inputChannels[i])
{
@ -503,16 +506,19 @@ public:
}
}
ensureMinimumNumBitsSet (outputChannels, minChansOut);
ensureMinimumNumBitsSet (outputChannels, (int) minChansOut);
int maxOutputsRequested = outputChannels.getHighestBit() + 1;
maxOutputsRequested = jmax ((int) minChansOut, jmin ((int) maxChansOut, maxOutputsRequested));
outputChannelBuffer.setSize (jmax ((int) minChansOut, outputChannels.getHighestBit()) + 1, bufferSize);
outputChannelBuffer.setSize (maxOutputsRequested, bufferSize);
outputChannelBuffer.clear();
outputChannelDataForCallback.clear();
currentOutputChans.clear();
if (outputChannels.getHighestBit() >= 0)
{
for (int i = 0; i <= jmax (outputChannels.getHighestBit(), (int) minChansOut); ++i)
for (int i = 0; i < maxOutputsRequested; ++i)
{
if (outputChannels[i])
{
@ -557,7 +563,7 @@ public:
return;
}
ensureMinimumNumBitsSet (currentInputChans, minChansIn);
ensureMinimumNumBitsSet (currentInputChans, (int) minChansIn);
if (! inputDevice->setParameters ((unsigned int) sampleRate,
jlimit ((int) minChansIn, (int) maxChansIn, currentInputChans.getHighestBit() + 1),
@ -644,8 +650,21 @@ public:
{
while (! threadShouldExit())
{
if (inputDevice != nullptr && inputDevice->handle)
if (inputDevice != nullptr && inputDevice->handle != nullptr)
{
if (outputDevice == nullptr || outputDevice->handle == nullptr)
{
JUCE_ALSA_FAILED (snd_pcm_wait (inputDevice->handle, 2000));
if (threadShouldExit())
break;
snd_pcm_sframes_t avail = snd_pcm_avail_update (inputDevice->handle);
if (avail < 0)
JUCE_ALSA_FAILED (snd_pcm_recover (inputDevice->handle, (int) avail, 0));
}
audioIoInProgress = true;
if (! inputDevice->readFromInputDevice (inputChannelBuffer, bufferSize))
@ -675,11 +694,11 @@ public:
else
{
for (int i = 0; i < outputChannelDataForCallback.size(); ++i)
zeromem (outputChannelDataForCallback[i], sizeof (float) * bufferSize);
zeromem (outputChannelDataForCallback[i], sizeof (float) * (size_t) bufferSize);
}
}
if (outputDevice != nullptr && outputDevice->handle)
if (outputDevice != nullptr && outputDevice->handle != nullptr)
{
JUCE_ALSA_FAILED (snd_pcm_wait (outputDevice->handle, 2000));
@ -689,7 +708,7 @@ public:
snd_pcm_sframes_t avail = snd_pcm_avail_update (outputDevice->handle);
if (avail < 0)
JUCE_ALSA_FAILED (snd_pcm_recover (outputDevice->handle, avail, 0));
JUCE_ALSA_FAILED (snd_pcm_recover (outputDevice->handle, (int) avail, 0));
audioIoInProgress = true;
@ -702,6 +721,7 @@ public:
audioIoInProgress = false;
}
}
audioIoInProgress = false;
}
@ -782,10 +802,10 @@ class ALSAAudioIODevice : public AudioIODevice
{
public:
ALSAAudioIODevice (const String& deviceName,
const String& typeName,
const String& deviceTypeName,
const String& inputDeviceID,
const String& outputDeviceID)
: AudioIODevice (deviceName, typeName),
: AudioIODevice (deviceName, deviceTypeName),
inputId (inputDeviceID),
outputId (outputDeviceID),
isOpen_ (false),
@ -910,8 +930,8 @@ private:
class ALSAAudioIODeviceType : public AudioIODeviceType
{
public:
ALSAAudioIODeviceType (bool onlySoundcards, const String &typeName)
: AudioIODeviceType (typeName),
ALSAAudioIODeviceType (bool onlySoundcards, const String &deviceTypeName)
: AudioIODeviceType (deviceTypeName),
hasScanned (false),
listOnlySoundcards (onlySoundcards)
{
@ -1078,9 +1098,9 @@ private:
if (snd_ctl_pcm_next_device (handle, &device) < 0 || device < 0)
break;
snd_pcm_info_set_device (pcmInfo, device);
snd_pcm_info_set_device (pcmInfo, (unsigned int) device);
for (int subDevice = 0, nbSubDevice = 1; subDevice < nbSubDevice; ++subDevice)
for (unsigned int subDevice = 0, nbSubDevice = 1; subDevice < nbSubDevice; ++subDevice)
{
snd_pcm_info_set_subdevice (pcmInfo, subDevice);
snd_pcm_info_set_stream (pcmInfo, SND_PCM_STREAM_CAPTURE);
@ -1104,7 +1124,7 @@ private:
}
else
{
id << "hw:" << cardId << "," << device << "," << subDevice;
id << "hw:" << cardId << "," << device << "," << (int) subDevice;
name << cardName << ", " << snd_pcm_info_get_name (pcmInfo)
<< " {" << snd_pcm_info_get_subdevice_name (pcmInfo) << "}";
}

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -133,14 +133,14 @@ private:
if (snd_midi_event_new (maxEventSize, &midiParser) >= 0)
{
const int numPfds = snd_seq_poll_descriptors_count (seqHandle, POLLIN);
HeapBlock<pollfd> pfd (numPfds);
snd_seq_poll_descriptors (seqHandle, pfd, numPfds, POLLIN);
HeapBlock<pollfd> pfd ((size_t) numPfds);
snd_seq_poll_descriptors (seqHandle, pfd, (unsigned int) numPfds, POLLIN);
HeapBlock <uint8> buffer (maxEventSize);
while (! threadShouldExit())
{
if (poll (pfd, numPfds, 100) > 0) // there was a "500" here which is a bit long when we exit the program and have to wait for a timeout on this poll call
if (poll (pfd, (nfds_t) numPfds, 100) > 0) // there was a "500" here which is a bit long when we exit the program and have to wait for a timeout on this poll call
{
if (threadShouldExit())
break;
@ -154,14 +154,14 @@ private:
if (snd_seq_event_input (seqHandle, &inputEvent) >= 0)
{
// xxx what about SYSEXes that are too big for the buffer?
const int numBytes = snd_midi_event_decode (midiParser, buffer,
const long numBytes = snd_midi_event_decode (midiParser, buffer,
maxEventSize, inputEvent);
snd_midi_event_reset_decode (midiParser);
if (numBytes > 0)
{
const MidiMessage message ((const uint8*) buffer, numBytes,
const MidiMessage message ((const uint8*) buffer, (int) numBytes,
Time::getMillisecondCounter() * 0.001);
client.handleIncomingMidiMessage (message, inputEvent->dest.port);
@ -410,7 +410,7 @@ public:
maxEventSize (16 * 1024)
{
jassert (port.isValid() && midiOutput != nullptr);
snd_midi_event_new (maxEventSize, &midiParser);
snd_midi_event_new ((size_t) maxEventSize, &midiParser);
}
~MidiOutputDevice()
@ -419,13 +419,13 @@ public:
port.deletePort();
}
void sendMessageNow (const MidiMessage& message)
bool sendMessageNow (const MidiMessage& message)
{
if (message.getRawDataSize() > maxEventSize)
{
maxEventSize = message.getRawDataSize();
snd_midi_event_free (midiParser);
snd_midi_event_new (maxEventSize, &midiParser);
snd_midi_event_new ((size_t) maxEventSize, &midiParser);
}
snd_seq_event_t event;
@ -435,12 +435,17 @@ public:
const uint8* data = message.getRawData();
snd_seq_t* seqHandle = port.client->get();
bool success = true;
while (numBytes > 0)
{
const long numSent = snd_midi_event_encode (midiParser, data, numBytes, &event);
if (numSent <= 0)
{
success = numSent == 0;
break;
}
numBytes -= numSent;
data += numSent;
@ -449,11 +454,15 @@ public:
snd_seq_ev_set_subs (&event);
snd_seq_ev_set_direct (&event);
snd_seq_event_output (seqHandle, &event);
if (snd_seq_event_output_direct (seqHandle, &event) < 0)
{
success = false;
break;
}
}
snd_seq_drain_output (seqHandle);
snd_midi_event_reset_encode (midiParser);
return success;
}
private:

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -277,7 +277,7 @@ public:
if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, ranges)))
{
static const double possibleRates[] = { 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0 };
static const double possibleRates[] = { 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0, 384000.0 };
for (int i = 0; i < numElementsInArray (possibleRates); ++i)
{
@ -543,7 +543,7 @@ public:
// set sample rate
AudioObjectPropertyAddress pa;
pa.mSelector = kAudioDevicePropertyNominalSampleRate;
pa.mScope = kAudioObjectPropertyScopeWildcard;
pa.mScope = kAudioObjectPropertyScopeGlobal;
pa.mElement = kAudioObjectPropertyElementMaster;
Float64 sr = newSampleRate;
@ -1067,6 +1067,12 @@ public:
jassert (! isOpen());
jassert (! device->isOpen());
devices.add (new DeviceWrapper (*this, device, useInputs, useOutputs));
if (currentSampleRate == 0)
currentSampleRate = device->getCurrentSampleRate();
if (currentBufferSize == 0)
currentBufferSize = device->getCurrentBufferSizeSamples();
}
Array<AudioIODevice*> getDevices() const

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -45,6 +45,14 @@ namespace CoreMidiHelpers
#define CHECK_ERROR(a) CoreMidiHelpers::checkError (a, __LINE__)
//==============================================================================
struct ScopedCFString
{
ScopedCFString() noexcept : cfString (nullptr) {}
~ScopedCFString() noexcept { if (cfString != nullptr) CFRelease (cfString); }
CFStringRef cfString;
};
static String getMidiObjectName (MIDIObjectRef entity)
{
String result;
@ -116,7 +124,7 @@ namespace CoreMidiHelpers
if (numConnections > 0)
{
const SInt32* pid = reinterpret_cast <const SInt32*> (CFDataGetBytePtr (connections));
const SInt32* pid = reinterpret_cast<const SInt32*> (CFDataGetBytePtr (connections));
for (int i = 0; i < numConnections; ++i, ++pid)
{
@ -133,7 +141,7 @@ namespace CoreMidiHelpers
|| connObjectType == kMIDIObjectType_ExternalDestination)
{
// Connected to an external device's endpoint (10.3 and later).
s = getEndpointName (static_cast <MIDIEndpointRef> (connObject), true);
s = getEndpointName (static_cast<MIDIEndpointRef> (connObject), true);
}
else
{
@ -208,9 +216,9 @@ namespace CoreMidiHelpers
// correctly when called from the message thread!
jassert (MessageManager::getInstance()->isThisTheMessageThread());
CFStringRef name = getGlobalMidiClientName().toCFString();
CHECK_ERROR (MIDIClientCreate (name, &globalSystemChangeCallback, nullptr, &globalMidiClient));
CFRelease (name);
CoreMidiHelpers::ScopedCFString name;
name.cfString = getGlobalMidiClientName().toCFString();
CHECK_ERROR (MIDIClientCreate (name.cfString, &globalSystemChangeCallback, nullptr, &globalMidiClient));
}
return globalMidiClient;
@ -220,12 +228,12 @@ namespace CoreMidiHelpers
class MidiPortAndEndpoint
{
public:
MidiPortAndEndpoint (MIDIPortRef p, MIDIEndpointRef ep)
MidiPortAndEndpoint (MIDIPortRef p, MIDIEndpointRef ep) noexcept
: port (p), endPoint (ep)
{
}
~MidiPortAndEndpoint()
~MidiPortAndEndpoint() noexcept
{
if (port != 0)
MIDIPortDispose (port);
@ -234,7 +242,7 @@ namespace CoreMidiHelpers
MIDIEndpointDispose (endPoint);
}
void send (const MIDIPacketList* const packets)
void send (const MIDIPacketList* const packets) noexcept
{
if (port != 0)
MIDISend (port, endPoint, packets);
@ -302,7 +310,7 @@ namespace CoreMidiHelpers
static void midiInputProc (const MIDIPacketList* pktlist, void* readProcRefCon, void* /*srcConnRefCon*/)
{
static_cast <MidiPortAndCallback*> (readProcRefCon)->handlePackets (pktlist);
static_cast<MidiPortAndCallback*> (readProcRefCon)->handlePackets (pktlist);
}
}
@ -318,19 +326,18 @@ MidiOutput* MidiOutput::openDevice (int index)
{
MIDIEndpointRef endPoint = MIDIGetDestination ((ItemCount) index);
CFStringRef pname;
if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname)))
CoreMidiHelpers::ScopedCFString pname;
if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname.cfString)))
{
MIDIClientRef client = CoreMidiHelpers::getGlobalMidiClient();
MIDIPortRef port;
if (client != 0 && CHECK_ERROR (MIDIOutputPortCreate (client, pname, &port)))
if (client != 0 && CHECK_ERROR (MIDIOutputPortCreate (client, pname.cfString, &port)))
{
mo = new MidiOutput();
mo->internal = new CoreMidiHelpers::MidiPortAndEndpoint (port, endPoint);
}
CFRelease (pname);
}
}
@ -339,20 +346,20 @@ MidiOutput* MidiOutput::openDevice (int index)
MidiOutput* MidiOutput::createNewDevice (const String& deviceName)
{
MidiOutput* mo = nullptr;
MIDIClientRef client = CoreMidiHelpers::getGlobalMidiClient();
MIDIEndpointRef endPoint;
CFStringRef name = deviceName.toCFString();
if (client != 0 && CHECK_ERROR (MIDISourceCreate (client, name, &endPoint)))
CoreMidiHelpers::ScopedCFString name;
name.cfString = deviceName.toCFString();
if (client != 0 && CHECK_ERROR (MIDISourceCreate (client, name.cfString, &endPoint)))
{
mo = new MidiOutput();
MidiOutput* mo = new MidiOutput();
mo->internal = new CoreMidiHelpers::MidiPortAndEndpoint (0, endPoint);
return mo;
}
CFRelease (name);
return mo;
return nullptr;
}
MidiOutput::~MidiOutput()
@ -370,7 +377,7 @@ void MidiOutput::sendMessageNow (const MidiMessage& message)
const MIDITimeStamp timeStamp = AudioGetCurrentHostTime();
#endif
HeapBlock <MIDIPacketList> allocatedPackets;
HeapBlock<MIDIPacketList> allocatedPackets;
MIDIPacketList stackPacket;
MIDIPacketList* packetToSend = &stackPacket;
const size_t dataSize = (size_t) message.getRawDataSize();
@ -436,16 +443,16 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback)
{
if (MIDIEndpointRef endPoint = MIDIGetSource ((ItemCount) index))
{
CFStringRef name;
ScopedCFString name;
if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &name)))
if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &name.cfString)))
{
if (MIDIClientRef client = getGlobalMidiClient())
{
MIDIPortRef port;
ScopedPointer <MidiPortAndCallback> mpc (new MidiPortAndCallback (*callback));
ScopedPointer<MidiPortAndCallback> mpc (new MidiPortAndCallback (*callback));
if (CHECK_ERROR (MIDIInputPortCreate (client, name, midiInputProc, mpc, &port)))
if (CHECK_ERROR (MIDIInputPortCreate (client, name.cfString, midiInputProc, mpc, &port)))
{
if (CHECK_ERROR (MIDIPortConnectSource (port, endPoint, nullptr)))
{
@ -465,8 +472,6 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback)
}
}
}
CFRelease (name);
}
}
@ -482,13 +487,14 @@ MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallba
if (MIDIClientRef client = getGlobalMidiClient())
{
ScopedPointer <MidiPortAndCallback> mpc (new MidiPortAndCallback (*callback));
ScopedPointer<MidiPortAndCallback> mpc (new MidiPortAndCallback (*callback));
mpc->active = false;
MIDIEndpointRef endPoint;
CFStringRef name = deviceName.toCFString();
ScopedCFString name;
name.cfString = deviceName.toCFString();
if (CHECK_ERROR (MIDIDestinationCreate (client, name, midiInputProc, mpc, &endPoint)))
if (CHECK_ERROR (MIDIDestinationCreate (client, name.cfString, midiInputProc, mpc, &endPoint)))
{
mpc->portAndEndpoint = new MidiPortAndEndpoint (0, endPoint);
@ -499,8 +505,6 @@ MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallba
const ScopedLock sl (callbackLock);
activeCallbacks.add (mpc.release());
}
CFRelease (name);
}
return mi;

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -123,9 +123,9 @@ struct ASIOSampleFormat
{
switch (bitDepth)
{
case 16: convertInt16ToFloat (static_cast <const char*> (src), dst, byteStride, samps, littleEndian); break;
case 24: convertInt24ToFloat (static_cast <const char*> (src), dst, byteStride, samps, littleEndian); break;
case 32: convertInt32ToFloat (static_cast <const char*> (src), dst, byteStride, samps, littleEndian); break;
case 16: convertInt16ToFloat (static_cast<const char*> (src), dst, byteStride, samps, littleEndian); break;
case 24: convertInt24ToFloat (static_cast<const char*> (src), dst, byteStride, samps, littleEndian); break;
case 32: convertInt32ToFloat (static_cast<const char*> (src), dst, byteStride, samps, littleEndian); break;
default: jassertfalse; break;
}
}
@ -141,9 +141,9 @@ struct ASIOSampleFormat
{
switch (bitDepth)
{
case 16: convertFloatToInt16 (src, static_cast <char*> (dst), byteStride, samps, littleEndian); break;
case 24: convertFloatToInt24 (src, static_cast <char*> (dst), byteStride, samps, littleEndian); break;
case 32: convertFloatToInt32 (src, static_cast <char*> (dst), byteStride, samps, littleEndian); break;
case 16: convertFloatToInt16 (src, static_cast<char*> (dst), byteStride, samps, littleEndian); break;
case 24: convertFloatToInt24 (src, static_cast<char*> (dst), byteStride, samps, littleEndian); break;
case 32: convertFloatToInt32 (src, static_cast<char*> (dst), byteStride, samps, littleEndian); break;
default: jassertfalse; break;
}
}
@ -300,7 +300,7 @@ private:
//==============================================================================
class ASIOAudioIODevice;
static ASIOAudioIODevice* volatile currentASIODev[3] = { 0 };
static ASIOAudioIODevice* volatile currentASIODev[16] = { 0 };
extern HWND juce_messageWindowHandle;
@ -438,8 +438,6 @@ public:
currentBlockSizeSamples = bufferSizeSamples;
currentChansOut.clear();
currentChansIn.clear();
inBuffers.clear (totalNumInputChans + 1);
outBuffers.clear (totalNumOutputChans + 1);
updateSampleRates();
@ -458,6 +456,13 @@ public:
setSampleRate (sampleRate);
// (need to get this again in case a sample rate change affected the channel count)
err = asioObject->getChannels (&totalNumInputChans, &totalNumOutputChans);
jassert (err == ASE_OK);
inBuffers.calloc (totalNumInputChans + 8);
outBuffers.calloc (totalNumOutputChans + 8);
if (needToReset)
{
JUCE_ASIO_LOG (" Resetting");
@ -1320,7 +1325,7 @@ private:
inputFormat[i].convertToFloat (infos[i].buffers[bi], inBuffers[i], samps);
}
currentCallback->audioDeviceIOCallback (const_cast <const float**> (inBuffers.getData()), numActiveInputChans,
currentCallback->audioDeviceIOCallback (const_cast<const float**> (inBuffers.getData()), numActiveInputChans,
outBuffers, numActiveOutputChans, samps);
for (int i = 0; i < numActiveOutputChans; ++i)
@ -1340,6 +1345,29 @@ private:
asioObject->outputReady();
}
long asioMessagesCallback (long selector, long value)
{
switch (selector)
{
case kAsioSelectorSupported:
if (value == kAsioResetRequest || value == kAsioEngineVersion || value == kAsioResyncRequest
|| value == kAsioLatenciesChanged || value == kAsioSupportsInputMonitor)
return 1;
break;
case kAsioBufferSizeChange: JUCE_ASIO_LOG ("kAsioBufferSizeChange"); resetRequest(); return 1;
case kAsioResetRequest: JUCE_ASIO_LOG ("kAsioResetRequest"); resetRequest(); return 1;
case kAsioResyncRequest: JUCE_ASIO_LOG ("kAsioResyncRequest"); resetRequest(); return 1;
case kAsioLatenciesChanged: JUCE_ASIO_LOG ("kAsioLatenciesChanged"); return 1;
case kAsioEngineVersion: return 2;
case kAsioSupportsTimeInfo:
case kAsioSupportsTimeCode: return 0;
}
return 0;
}
//==============================================================================
template <int deviceIndex>
struct ASIOCallbackFunctions
@ -1360,56 +1388,43 @@ private:
static long JUCE_ASIOCALLBACK asioMessagesCallback (long selector, long value, void*, double*)
{
switch (selector)
{
case kAsioSelectorSupported:
if (value == kAsioResetRequest || value == kAsioEngineVersion || value == kAsioResyncRequest
|| value == kAsioLatenciesChanged || value == kAsioSupportsInputMonitor)
return 1;
break;
case kAsioBufferSizeChange: JUCE_ASIO_LOG ("kAsioBufferSizeChange"); return sendResetRequest (deviceIndex);
case kAsioResetRequest: JUCE_ASIO_LOG ("kAsioResetRequest"); return sendResetRequest (deviceIndex);
case kAsioResyncRequest: JUCE_ASIO_LOG ("kAsioResyncRequest"); return sendResetRequest (deviceIndex);
case kAsioLatenciesChanged: JUCE_ASIO_LOG ("kAsioLatenciesChanged"); return 1;
case kAsioEngineVersion: return 2;
case kAsioSupportsTimeInfo:
case kAsioSupportsTimeCode:
return 0;
}
return 0;
return currentASIODev[deviceIndex] != nullptr
? currentASIODev[deviceIndex]->asioMessagesCallback (selector, value)
: 0;
}
static void JUCE_ASIOCALLBACK sampleRateChangedCallback (ASIOSampleRate)
{
sendResetRequest (deviceIndex);
if (currentASIODev[deviceIndex] != nullptr)
currentASIODev[deviceIndex]->resetRequest();
}
static long sendResetRequest (int index)
static void setCallbacks (ASIOCallbacks& callbacks) noexcept
{
if (currentASIODev[index] != nullptr)
currentASIODev[index]->resetRequest();
return 1;
callbacks.bufferSwitch = &bufferSwitchCallback;
callbacks.asioMessage = &asioMessagesCallback;
callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback;
callbacks.sampleRateDidChange = &sampleRateChangedCallback;
}
static void setCallbacks (ASIOCallbacks& callbacks)
static void setCallbacksForDevice (ASIOCallbacks& callbacks, ASIOAudioIODevice* device) noexcept
{
callbacks.bufferSwitch = &bufferSwitchCallback;
callbacks.asioMessage = &asioMessagesCallback;
callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback;
callbacks.sampleRateDidChange = &sampleRateChangedCallback;
if (currentASIODev[deviceIndex] == device)
setCallbacks (callbacks);
else
ASIOCallbackFunctions<deviceIndex + 1>::setCallbacksForDevice (callbacks, device);
}
};
void setCallbackFunctions()
template <>
struct ASIOCallbackFunctions <sizeof(currentASIODev) / sizeof(currentASIODev[0])>
{
static void setCallbacksForDevice (ASIOCallbacks&, ASIOAudioIODevice*) noexcept {}
};
void setCallbackFunctions() noexcept
{
if (currentASIODev[0] == this) ASIOCallbackFunctions<0>::setCallbacks (callbacks);
else if (currentASIODev[1] == this) ASIOCallbackFunctions<1>::setCallbacks (callbacks);
else if (currentASIODev[2] == this) ASIOCallbackFunctions<2>::setCallbacks (callbacks);
else jassertfalse;
ASIOCallbackFunctions<0>::setCallbacksForDevice (callbacks, this);
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ASIOAudioIODevice)
@ -1503,15 +1518,16 @@ public:
jassert (inputDeviceName == outputDeviceName || outputDeviceName.isEmpty() || inputDeviceName.isEmpty());
jassert (hasScanned); // need to call scanForDevices() before doing this
const int index = deviceNames.indexOf (outputDeviceName.isNotEmpty() ? outputDeviceName
: inputDeviceName);
const String deviceName (outputDeviceName.isNotEmpty() ? outputDeviceName
: inputDeviceName);
const int index = deviceNames.indexOf (deviceName);
if (index >= 0)
{
const int freeSlot = findFreeSlot();
if (freeSlot >= 0)
return new ASIOAudioIODevice (this, outputDeviceName,
return new ASIOAudioIODevice (this, deviceName,
classIds.getReference (index), freeSlot);
}

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -640,7 +640,7 @@ public:
DWORD dwsize1 = 0;
DWORD dwsize2 = 0;
HRESULT hr = pInputBuffer->Lock ((DWORD) readOffset, (DWORD) bytesPerBuffer,
hr = pInputBuffer->Lock ((DWORD) readOffset, (DWORD) bytesPerBuffer,
(void**) &buf1, &dwsize1,
(void**) &buf2, &dwsize2, 0);
@ -753,9 +753,9 @@ public:
String open (const BigInteger& inputChannels,
const BigInteger& outputChannels,
double sampleRate, int bufferSizeSamples) override
double newSampleRate, int newBufferSize) override
{
lastError = openDevice (inputChannels, outputChannels, sampleRate, bufferSizeSamples);
lastError = openDevice (inputChannels, outputChannels, newSampleRate, newBufferSize);
isOpen_ = lastError.isEmpty();
return lastError;

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -143,37 +143,37 @@ private:
public:
MidiHeader() {}
void prepare (HMIDIIN deviceHandle)
void prepare (HMIDIIN device)
{
zerostruct (hdr);
hdr.lpData = data;
hdr.dwBufferLength = (DWORD) numElementsInArray (data);
midiInPrepareHeader (deviceHandle, &hdr, sizeof (hdr));
midiInPrepareHeader (device, &hdr, sizeof (hdr));
}
void unprepare (HMIDIIN deviceHandle)
void unprepare (HMIDIIN device)
{
if ((hdr.dwFlags & WHDR_DONE) != 0)
{
int c = 10;
while (--c >= 0 && midiInUnprepareHeader (deviceHandle, &hdr, sizeof (hdr)) == MIDIERR_STILLPLAYING)
while (--c >= 0 && midiInUnprepareHeader (device, &hdr, sizeof (hdr)) == MIDIERR_STILLPLAYING)
Thread::sleep (20);
jassert (c >= 0);
}
}
void write (HMIDIIN deviceHandle)
void write (HMIDIIN device)
{
hdr.dwBytesRecorded = 0;
midiInAddBuffer (deviceHandle, &hdr, sizeof (hdr));
midiInAddBuffer (device, &hdr, sizeof (hdr));
}
void writeIfFinished (HMIDIIN deviceHandle)
void writeIfFinished (HMIDIIN device)
{
if ((hdr.dwFlags & WHDR_DONE) != 0)
write (deviceHandle);
write (device);
}
private:

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
@ -45,6 +45,7 @@ void logFailure (HRESULT hr)
{
case E_POINTER: m = "E_POINTER"; break;
case E_INVALIDARG: m = "E_INVALIDARG"; break;
case E_NOINTERFACE: m = "E_NOINTERFACE"; break;
#define JUCE_WASAPI_ERR(desc, n) \
case MAKE_HRESULT(1, 0x889, n): m = #desc; break;
@ -126,7 +127,11 @@ enum EDataFlow
eAll = (eCapture + 1)
};
enum { DEVICE_STATE_ACTIVE = 1 };
enum
{
DEVICE_STATE_ACTIVE = 1,
AUDCLNT_BUFFERFLAGS_SILENT = 2
};
JUCE_IUNKNOWNCLASS (IPropertyStore, "886d8eeb-8cf2-4446-8d02-cdba1dbdcf99")
{
@ -328,6 +333,11 @@ int refTimeToSamples (const REFERENCE_TIME& t, const double sampleRate) noexcept
return roundToInt (sampleRate * ((double) t) * 0.0000001);
}
REFERENCE_TIME samplesToRefTime (const int numSamples, const double sampleRate) noexcept
{
return (REFERENCE_TIME) ((numSamples * 10000.0 * 1000.0 / sampleRate) + 0.5);
}
void copyWavFormat (WAVEFORMATEXTENSIBLE& dest, const WAVEFORMATEX* const src) noexcept
{
memcpy (&dest, src, src->wFormatTag == WAVE_FORMAT_EXTENSIBLE ? sizeof (WAVEFORMATEXTENSIBLE)
@ -348,9 +358,12 @@ public:
defaultBufferSize (0),
latencySamples (0),
useExclusiveMode (exclusiveMode),
actualBufferSize (0),
bytesPerSample (0),
bytesPerFrame (0),
sampleRateHasChanged (false)
{
clientEvent = CreateEvent (0, false, false, _T("JuceWASAPI"));
clientEvent = CreateEvent (nullptr, false, false, nullptr);
ComSmartPtr<IAudioClient> tempClient (createClient());
if (tempClient == nullptr)
@ -376,16 +389,24 @@ public:
rates.addUsingDefaultSort (defaultSampleRate);
static const int ratesToTest[] = { 44100, 48000, 88200, 96000, 176400, 192000 };
if (useExclusiveMode
&& findSupportedFormat (tempClient, defaultSampleRate, format.dwChannelMask, format))
{
// Got a format that is supported by the device so we can ask what sample rates are supported (in whatever format)
}
static const int ratesToTest[] = { 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000 };
for (int i = 0; i < numElementsInArray (ratesToTest); ++i)
{
if (ratesToTest[i] == defaultSampleRate)
if (rates.contains (ratesToTest[i]))
continue;
format.Format.nSamplesPerSec = (DWORD) ratesToTest[i];
format.Format.nSamplesPerSec = (DWORD) ratesToTest[i];
format.Format.nAvgBytesPerSec = (DWORD) (format.Format.nSamplesPerSec * format.Format.nChannels * format.Format.wBitsPerSample / 8);
if (SUCCEEDED (tempClient->IsFormatSupported (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED,
if (SUCCEEDED (tempClient->IsFormatSupported (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE
: AUDCLNT_SHAREMODE_SHARED,
(WAVEFORMATEX*) &format, 0)))
if (! rates.contains (ratesToTest[i]))
rates.addUsingDefaultSort (ratesToTest[i]);
@ -400,7 +421,7 @@ public:
bool isOk() const noexcept { return defaultBufferSize > 0 && defaultSampleRate > 0; }
bool openClient (const double newSampleRate, const BigInteger& newChannels)
bool openClient (const double newSampleRate, const BigInteger& newChannels, const int bufferSizeSamples)
{
sampleRate = newSampleRate;
channels = newChannels;
@ -413,8 +434,7 @@ public:
client = createClient();
if (client != nullptr
&& (tryInitialisingWithFormat (true, 4) || tryInitialisingWithFormat (false, 4)
|| tryInitialisingWithFormat (false, 3) || tryInitialisingWithFormat (false, 2)))
&& tryInitialisingWithBufferSize (bufferSizeSamples))
{
sampleRateHasChanged = false;
@ -465,7 +485,7 @@ public:
BigInteger channels;
Array<int> channelMaps;
UINT32 actualBufferSize;
int bytesPerSample;
int bytesPerSample, bytesPerFrame;
bool sampleRateHasChanged;
virtual void updateFormat (bool isFloat) = 0;
@ -527,21 +547,28 @@ private:
//==============================================================================
ComSmartPtr<IAudioClient> createClient()
{
ComSmartPtr<IAudioClient> client;
ComSmartPtr<IAudioClient> newClient;
if (device != nullptr)
logFailure (device->Activate (__uuidof (IAudioClient), CLSCTX_INPROC_SERVER,
nullptr, (void**) client.resetAndGetPointerAddress()));
nullptr, (void**) newClient.resetAndGetPointerAddress()));
return client;
return newClient;
}
bool tryInitialisingWithFormat (const bool useFloat, const int bytesPerSampleToTry)
struct AudioSampleFormat
{
bool useFloat;
int bitsPerSampleToTry;
int bytesPerSampleContainer;
};
bool tryFormat (const AudioSampleFormat sampleFormat, IAudioClient* clientToUse, double newSampleRate,
DWORD newMixFormatChannelMask, WAVEFORMATEXTENSIBLE& format) const
{
WAVEFORMATEXTENSIBLE format;
zerostruct (format);
if (numChannels <= 2 && bytesPerSampleToTry <= 2)
if (numChannels <= 2 && sampleFormat.bitsPerSampleToTry <= 16)
{
format.Format.wFormatTag = WAVE_FORMAT_PCM;
}
@ -551,47 +578,99 @@ private:
format.Format.cbSize = sizeof (WAVEFORMATEXTENSIBLE) - sizeof (WAVEFORMATEX);
}
format.Format.nSamplesPerSec = (DWORD) sampleRate;
format.Format.nSamplesPerSec = (DWORD) newSampleRate;
format.Format.nChannels = (WORD) numChannels;
format.Format.wBitsPerSample = (WORD) (8 * bytesPerSampleToTry);
format.Format.nAvgBytesPerSec = (DWORD) (format.Format.nSamplesPerSec * numChannels * bytesPerSampleToTry);
format.Format.nBlockAlign = (WORD) (numChannels * bytesPerSampleToTry);
format.SubFormat = useFloat ? KSDATAFORMAT_SUBTYPE_IEEE_FLOAT : KSDATAFORMAT_SUBTYPE_PCM;
format.Samples.wValidBitsPerSample = format.Format.wBitsPerSample;
format.dwChannelMask = mixFormatChannelMask;
format.Format.wBitsPerSample = (WORD) (8 * sampleFormat.bytesPerSampleContainer);
format.Samples.wValidBitsPerSample = (WORD) (sampleFormat.bitsPerSampleToTry);
format.Format.nBlockAlign = (WORD) (format.Format.nChannels * format.Format.wBitsPerSample / 8);
format.Format.nAvgBytesPerSec = (DWORD) (format.Format.nSamplesPerSec * format.Format.nBlockAlign);
format.SubFormat = sampleFormat.useFloat ? KSDATAFORMAT_SUBTYPE_IEEE_FLOAT : KSDATAFORMAT_SUBTYPE_PCM;
format.dwChannelMask = newMixFormatChannelMask;
WAVEFORMATEXTENSIBLE* nearestFormat = nullptr;
HRESULT hr = client->IsFormatSupported (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE
: AUDCLNT_SHAREMODE_SHARED,
(WAVEFORMATEX*) &format,
useExclusiveMode ? nullptr : (WAVEFORMATEX**) &nearestFormat);
HRESULT hr = clientToUse->IsFormatSupported (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE
: AUDCLNT_SHAREMODE_SHARED,
(WAVEFORMATEX*) &format,
useExclusiveMode ? nullptr : (WAVEFORMATEX**) &nearestFormat);
logFailure (hr);
if (hr == S_FALSE && format.Format.nSamplesPerSec == nearestFormat->Format.nSamplesPerSec)
{
copyWavFormat (format, (WAVEFORMATEX*) nearestFormat);
copyWavFormat (format, (const WAVEFORMATEX*) nearestFormat);
hr = S_OK;
}
CoTaskMemFree (nearestFormat);
return check (hr);
}
REFERENCE_TIME defaultPeriod = 0, minPeriod = 0;
if (useExclusiveMode)
check (client->GetDevicePeriod (&defaultPeriod, &minPeriod));
bool findSupportedFormat (IAudioClient* clientToUse, double newSampleRate,
DWORD newMixFormatChannelMask, WAVEFORMATEXTENSIBLE& format) const
{
static const AudioSampleFormat formats[] =
{
{ true, 32, 4 },
{ false, 32, 4 },
{ false, 24, 4 },
{ false, 24, 3 },
{ false, 20, 4 },
{ false, 20, 3 },
{ false, 16, 2 }
};
for (int i = 0; i < numElementsInArray (formats); ++i)
if (tryFormat (formats[i], clientToUse, newSampleRate, newMixFormatChannelMask, format))
return true;
return false;
}
GUID session;
if (hr == S_OK
&& check (client->Initialize (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED,
0x40000 /*AUDCLNT_STREAMFLAGS_EVENTCALLBACK*/,
defaultPeriod, defaultPeriod, (WAVEFORMATEX*) &format, &session)))
bool tryInitialisingWithBufferSize (const int bufferSizeSamples)
{
WAVEFORMATEXTENSIBLE format;
if (findSupportedFormat (client, sampleRate, mixFormatChannelMask, format))
{
actualNumChannels = format.Format.nChannels;
const bool isFloat = format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && format.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
bytesPerSample = format.Format.wBitsPerSample / 8;
REFERENCE_TIME defaultPeriod = 0, minPeriod = 0;
updateFormat (isFloat);
return true;
check (client->GetDevicePeriod (&defaultPeriod, &minPeriod));
if (useExclusiveMode && bufferSizeSamples > 0)
defaultPeriod = jmax (minPeriod, samplesToRefTime (bufferSizeSamples, format.Format.nSamplesPerSec));
for (;;)
{
GUID session;
HRESULT hr = client->Initialize (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED,
0x40000 /*AUDCLNT_STREAMFLAGS_EVENTCALLBACK*/,
defaultPeriod, useExclusiveMode ? defaultPeriod : 0, (WAVEFORMATEX*) &format, &session);
if (check (hr))
{
actualNumChannels = format.Format.nChannels;
const bool isFloat = format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && format.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
bytesPerSample = format.Format.wBitsPerSample / 8;
bytesPerFrame = format.Format.nBlockAlign;
updateFormat (isFloat);
return true;
}
// Handle the "alignment dance" : http://msdn.microsoft.com/en-us/library/windows/desktop/dd370875(v=vs.85).aspx (see Remarks)
if (hr != MAKE_HRESULT (1, 0x889, 0x19)) // AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED
break;
UINT32 numFrames = 0;
if (! check (client->GetBufferSize (&numFrames)))
break;
// Recreate client
client = nullptr;
client = createClient();
defaultPeriod = samplesToRefTime (numFrames, format.Format.nSamplesPerSec);
}
}
return false;
@ -615,12 +694,9 @@ public:
close();
}
bool open (const double newSampleRate, const BigInteger& newChannels)
bool open (const double newSampleRate, const BigInteger& newChannels, int bufferSizeSamples)
{
reservoirSize = 0;
reservoirCapacity = 16384;
reservoir.setSize (actualNumChannels * reservoirCapacity * sizeof (float));
return openClient (newSampleRate, newChannels)
return openClient (newSampleRate, newChannels, bufferSizeSamples)
&& (numChannels == 0 || check (client->GetService (__uuidof (IAudioCaptureClient),
(void**) captureClient.resetAndGetPointerAddress())));
}
@ -630,88 +706,129 @@ public:
closeClient();
captureClient = nullptr;
reservoir.reset();
reservoirReadPos = reservoirWritePos = 0;
}
template<class SourceType>
void updateFormatWithType (SourceType*)
void updateFormatWithType (SourceType*) noexcept
{
typedef AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> NativeType;
converter = new AudioData::ConverterInstance<AudioData::Pointer<SourceType, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, NativeType> (actualNumChannels, 1);
}
void updateFormat (bool isFloat)
void updateFormat (bool isFloat) override
{
if (isFloat) updateFormatWithType ((AudioData::Float32*) nullptr);
else if (bytesPerSample == 4) updateFormatWithType ((AudioData::Int32*) nullptr);
else if (bytesPerSample == 3) updateFormatWithType ((AudioData::Int24*) nullptr);
else updateFormatWithType ((AudioData::Int16*) nullptr);
}
bool start (const int userBufferSize)
{
reservoirSize = actualBufferSize + userBufferSize;
reservoirMask = nextPowerOfTwo (reservoirSize) - 1;
reservoir.setSize ((reservoirMask + 1) * bytesPerFrame, true);
reservoirReadPos = reservoirWritePos = 0;
if (! check (client->Start()))
return false;
purgeInputBuffers();
return true;
}
void purgeInputBuffers()
{
if (isFloat) updateFormatWithType ((AudioData::Float32*) 0);
else if (bytesPerSample == 4) updateFormatWithType ((AudioData::Int32*) 0);
else if (bytesPerSample == 3) updateFormatWithType ((AudioData::Int24*) 0);
else updateFormatWithType ((AudioData::Int16*) 0);
uint8* inputData;
UINT32 numSamplesAvailable;
DWORD flags;
while (captureClient->GetBuffer (&inputData, &numSamplesAvailable, &flags, nullptr, nullptr)
!= MAKE_HRESULT (0, 0x889, 0x1) /* AUDCLNT_S_BUFFER_EMPTY */)
captureClient->ReleaseBuffer (numSamplesAvailable);
}
void copyBuffers (float** destBuffers, int numDestBuffers, int bufferSize, Thread& thread)
int getNumSamplesInReservoir() const noexcept { return reservoirWritePos - reservoirReadPos; }
void handleDeviceBuffer()
{
if (numChannels <= 0)
return;
int offset = 0;
uint8* inputData;
UINT32 numSamplesAvailable;
DWORD flags;
while (bufferSize > 0)
while (check (captureClient->GetBuffer (&inputData, &numSamplesAvailable, &flags, nullptr, nullptr)) && numSamplesAvailable > 0)
{
if (reservoirSize > 0) // There's stuff in the reservoir, so use that...
int samplesLeft = (int) numSamplesAvailable;
while (samplesLeft > 0)
{
const int samplesToDo = jmin (bufferSize, (int) reservoirSize);
const int localWrite = reservoirWritePos & reservoirMask;
const int samplesToDo = jmin (samplesLeft, reservoirMask + 1 - localWrite);
const int samplesToDoBytes = samplesToDo * bytesPerFrame;
for (int i = 0; i < numDestBuffers; ++i)
converter->convertSamples (destBuffers[i] + offset, 0, reservoir.getData(), channelMaps.getUnchecked(i), samplesToDo);
void* reservoirPtr = addBytesToPointer (reservoir.getData(), localWrite * bytesPerFrame);
bufferSize -= samplesToDo;
offset += samplesToDo;
reservoirSize = 0;
if ((flags & AUDCLNT_BUFFERFLAGS_SILENT) != 0)
zeromem (reservoirPtr, samplesToDoBytes);
else
memcpy (reservoirPtr, inputData, samplesToDoBytes);
reservoirWritePos += samplesToDo;
inputData += samplesToDoBytes;
samplesLeft -= samplesToDo;
}
else
{
UINT32 packetLength = 0;
if (! check (captureClient->GetNextPacketSize (&packetLength)))
break;
if (packetLength == 0)
{
if (thread.threadShouldExit()
|| WaitForSingleObject (clientEvent, 1000) == WAIT_TIMEOUT)
break;
if (getNumSamplesInReservoir() > reservoirSize)
reservoirReadPos = reservoirWritePos - reservoirSize;
continue;
}
captureClient->ReleaseBuffer (numSamplesAvailable);
}
}
uint8* inputData;
UINT32 numSamplesAvailable;
DWORD flags;
void copyBuffersFromReservoir (float** destBuffers, int numDestBuffers, int bufferSize)
{
if ((numChannels <= 0 && bufferSize == 0) || reservoir.getSize() == 0)
return;
if (check (captureClient->GetBuffer (&inputData, &numSamplesAvailable, &flags, 0, 0)))
{
const int samplesToDo = jmin (bufferSize, (int) numSamplesAvailable);
int offset = jmax (0, bufferSize - getNumSamplesInReservoir());
for (int i = 0; i < numDestBuffers; ++i)
converter->convertSamples (destBuffers[i] + offset, 0, inputData, channelMaps.getUnchecked(i), samplesToDo);
if (offset > 0)
{
for (int i = 0; i < numDestBuffers; ++i)
zeromem (destBuffers[i], offset * sizeof (float));
bufferSize -= samplesToDo;
offset += samplesToDo;
bufferSize -= offset;
reservoirReadPos -= offset / 2;
}
if (samplesToDo < (int) numSamplesAvailable)
{
reservoirSize = jmin ((int) (numSamplesAvailable - samplesToDo), reservoirCapacity);
memcpy ((uint8*) reservoir.getData(), inputData + bytesPerSample * actualNumChannels * samplesToDo,
(size_t) (bytesPerSample * actualNumChannels * reservoirSize));
}
while (bufferSize > 0)
{
const int localRead = reservoirReadPos & reservoirMask;
captureClient->ReleaseBuffer (numSamplesAvailable);
}
}
const int samplesToDo = jmin (bufferSize, getNumSamplesInReservoir(), reservoirMask + 1 - localRead);
if (samplesToDo <= 0)
break;
const int reservoirOffset = localRead * bytesPerFrame;
for (int i = 0; i < numDestBuffers; ++i)
converter->convertSamples (destBuffers[i] + offset, 0, addBytesToPointer (reservoir.getData(), reservoirOffset), channelMaps.getUnchecked(i), samplesToDo);
bufferSize -= samplesToDo;
offset += samplesToDo;
reservoirReadPos += samplesToDo;
}
}
ComSmartPtr<IAudioCaptureClient> captureClient;
MemoryBlock reservoir;
int reservoirSize, reservoirCapacity;
int reservoirSize, reservoirMask;
volatile int reservoirReadPos, reservoirWritePos;
ScopedPointer<AudioData::Converter> converter;
private:
@ -732,10 +849,11 @@ public:
close();
}
bool open (const double newSampleRate, const BigInteger& newChannels)
bool open (const double newSampleRate, const BigInteger& newChannels, int bufferSizeSamples)
{
return openClient (newSampleRate, newChannels)
&& (numChannels == 0 || check (client->GetService (__uuidof (IAudioRenderClient), (void**) renderClient.resetAndGetPointerAddress())));
return openClient (newSampleRate, newChannels, bufferSizeSamples)
&& (numChannels == 0 || check (client->GetService (__uuidof (IAudioRenderClient),
(void**) renderClient.resetAndGetPointerAddress())));
}
void close()
@ -751,15 +869,42 @@ public:
converter = new AudioData::ConverterInstance<NativeType, AudioData::Pointer<DestType, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, actualNumChannels);
}
void updateFormat (bool isFloat)
void updateFormat (bool isFloat) override
{
if (isFloat) updateFormatWithType ((AudioData::Float32*) nullptr);
else if (bytesPerSample == 4) updateFormatWithType ((AudioData::Int32*) nullptr);
else if (bytesPerSample == 3) updateFormatWithType ((AudioData::Int24*) nullptr);
else updateFormatWithType ((AudioData::Int16*) nullptr);
}
bool start()
{
if (isFloat) updateFormatWithType ((AudioData::Float32*) 0);
else if (bytesPerSample == 4) updateFormatWithType ((AudioData::Int32*) 0);
else if (bytesPerSample == 3) updateFormatWithType ((AudioData::Int24*) 0);
else updateFormatWithType ((AudioData::Int16*) 0);
int samplesToDo = getNumSamplesAvailableToCopy();
uint8* outputData;
if (check (renderClient->GetBuffer (samplesToDo, &outputData)))
renderClient->ReleaseBuffer (samplesToDo, AUDCLNT_BUFFERFLAGS_SILENT);
return check (client->Start());
}
int getNumSamplesAvailableToCopy() const
{
if (numChannels <= 0)
return 0;
if (! useExclusiveMode)
{
UINT32 padding = 0;
if (check (client->GetCurrentPadding (&padding)))
return actualBufferSize - (int) padding;
}
return actualBufferSize;
}
void copyBuffers (const float** const srcBuffers, const int numSrcBuffers, int bufferSize, Thread& thread)
void copyBuffers (const float** const srcBuffers, const int numSrcBuffers, int bufferSize,
WASAPIInputDevice* inputDevice, Thread& thread)
{
if (numChannels <= 0)
return;
@ -768,22 +913,25 @@ public:
while (bufferSize > 0)
{
UINT32 padding = 0;
if (! check (client->GetCurrentPadding (&padding)))
return;
// This is needed in order not to drop any input data if the output device endpoint buffer was full
if ((! useExclusiveMode) && inputDevice != nullptr
&& WaitForSingleObject (inputDevice->clientEvent, 0) == WAIT_OBJECT_0)
inputDevice->handleDeviceBuffer();
int samplesToDo = useExclusiveMode ? bufferSize
: jmin ((int) (actualBufferSize - padding), bufferSize);
int samplesToDo = jmin (getNumSamplesAvailableToCopy(), bufferSize);
if (samplesToDo <= 0)
if (samplesToDo == 0)
{
if (thread.threadShouldExit()
|| WaitForSingleObject (clientEvent, 1000) == WAIT_TIMEOUT)
break;
// This can ONLY occur in non-exclusive mode
if (! thread.threadShouldExit() && WaitForSingleObject (clientEvent, 1000) == WAIT_OBJECT_0)
continue;
continue;
break;
}
if (useExclusiveMode && WaitForSingleObject (clientEvent, 1000) == WAIT_TIMEOUT)
break;
uint8* outputData = nullptr;
if (check (renderClient->GetBuffer ((UINT32) samplesToDo, &outputData)))
{
@ -791,10 +939,10 @@ public:
converter->convertSamples (outputData, channelMaps.getUnchecked(i), srcBuffers[i] + offset, 0, samplesToDo);
renderClient->ReleaseBuffer ((UINT32) samplesToDo, 0);
offset += samplesToDo;
bufferSize -= samplesToDo;
}
bufferSize -= samplesToDo;
offset += samplesToDo;
}
}
@ -812,13 +960,14 @@ class WASAPIAudioIODevice : public AudioIODevice,
{
public:
WASAPIAudioIODevice (const String& deviceName,
const String& outputDeviceId_,
const String& inputDeviceId_,
const String& typeName,
const String& outputDeviceID,
const String& inputDeviceID,
const bool exclusiveMode)
: AudioIODevice (deviceName, "Windows Audio"),
: AudioIODevice (deviceName, typeName),
Thread ("Juce WASAPI"),
outputDeviceId (outputDeviceId_),
inputDeviceId (inputDeviceId_),
outputDeviceId (outputDeviceID),
inputDeviceId (inputDeviceID),
useExclusiveMode (exclusiveMode),
isOpen_ (false),
isStarted (false),
@ -932,19 +1081,33 @@ public:
lastKnownInputChannels = inputChannels;
lastKnownOutputChannels = outputChannels;
if (inputDevice != nullptr && ! inputDevice->open (currentSampleRate, inputChannels))
if (inputDevice != nullptr && ! inputDevice->open (currentSampleRate, inputChannels, bufferSizeSamples))
{
lastError = TRANS("Couldn't open the input device!");
return lastError;
}
if (outputDevice != nullptr && ! outputDevice->open (currentSampleRate, outputChannels))
if (outputDevice != nullptr && ! outputDevice->open (currentSampleRate, outputChannels, bufferSizeSamples))
{
close();
lastError = TRANS("Couldn't open the output device!");
return lastError;
}
if (useExclusiveMode)
{
// This is to make sure that the callback uses actualBufferSize in case of exclusive mode
if (inputDevice != nullptr && outputDevice != nullptr && inputDevice->actualBufferSize != outputDevice->actualBufferSize)
{
close();
lastError = TRANS("Couldn't open the output device (buffer size mismatch)");
return lastError;
}
currentBufferSizeSamples = outputDevice != nullptr ? outputDevice->actualBufferSize
: inputDevice->actualBufferSize;
}
if (inputDevice != nullptr) ResetEvent (inputDevice->clientEvent);
if (outputDevice != nullptr) ResetEvent (outputDevice->clientEvent);
@ -955,7 +1118,7 @@ public:
{
latencyIn = (int) (inputDevice->latencySamples + currentBufferSizeSamples);
if (! check (inputDevice->client->Start()))
if (! inputDevice->start (currentBufferSizeSamples))
{
close();
lastError = TRANS("Couldn't start the input device!");
@ -967,7 +1130,7 @@ public:
{
latencyOut = (int) (outputDevice->latencySamples + currentBufferSizeSamples);
if (! check (outputDevice->client->Start()))
if (! outputDevice->start())
{
close();
lastError = TRANS("Couldn't start the output device!");
@ -1056,34 +1219,48 @@ public:
const int bufferSize = currentBufferSizeSamples;
const int numInputBuffers = getActiveInputChannels().countNumberOfSetBits();
const int numOutputBuffers = getActiveOutputChannels().countNumberOfSetBits();
bool sampleRateChanged = false;
bool sampleRateHasChanged = false;
AudioSampleBuffer ins (jmax (1, numInputBuffers), bufferSize + 32);
AudioSampleBuffer outs (jmax (1, numOutputBuffers), bufferSize + 32);
float** const inputBuffers = ins.getArrayOfWritePointers();
float** const outputBuffers = outs.getArrayOfWritePointers();
ins.clear();
outs.clear();
while (! threadShouldExit())
{
if (inputDevice != nullptr)
{
inputDevice->copyBuffers (inputBuffers, numInputBuffers, bufferSize, *this);
if (outputDevice == nullptr)
{
if (WaitForSingleObject (inputDevice->clientEvent, 1000) == WAIT_TIMEOUT)
break;
if (threadShouldExit())
break;
inputDevice->handleDeviceBuffer();
if (inputDevice->getNumSamplesInReservoir() < bufferSize)
continue;
}
else
{
if (useExclusiveMode && WaitForSingleObject (inputDevice->clientEvent, 0) == WAIT_OBJECT_0)
inputDevice->handleDeviceBuffer();
}
inputDevice->copyBuffersFromReservoir (inputBuffers, numInputBuffers, bufferSize);
if (inputDevice->sampleRateHasChanged)
{
sampleRateChanged = true;
sampleRateHasChanged = true;
sampleRateChangedByOutput = false;
}
}
{
const ScopedLock sl (startStopLock);
const ScopedTryLock sl (startStopLock);
if (isStarted)
if (sl.isLocked() && isStarted)
callback->audioDeviceIOCallback (const_cast<const float**> (inputBuffers), numInputBuffers,
outputBuffers, numOutputBuffers, bufferSize);
else
@ -1092,16 +1269,18 @@ public:
if (outputDevice != nullptr)
{
outputDevice->copyBuffers (const_cast<const float**> (outputBuffers), numOutputBuffers, bufferSize, *this);
// 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
outputDevice->copyBuffers (const_cast<const float**> (outputBuffers), numOutputBuffers, bufferSize, inputDevice, *this);
if (outputDevice->sampleRateHasChanged)
{
sampleRateChanged = true;
sampleRateHasChanged = true;
sampleRateChangedByOutput = true;
}
}
if (sampleRateChanged)
if (sampleRateHasChanged)
{
triggerAsyncUpdate();
break; // Quit the thread... will restart it later!
@ -1208,9 +1387,10 @@ class WASAPIAudioIODeviceType : public AudioIODeviceType,
private DeviceChangeDetector
{
public:
WASAPIAudioIODeviceType()
: AudioIODeviceType ("Windows Audio"),
WASAPIAudioIODeviceType (bool exclusive)
: AudioIODeviceType (exclusive ? "Windows Audio (Exclusive Mode)" : "Windows Audio"),
DeviceChangeDetector (L"Windows Audio"),
exclusiveMode (exclusive),
hasScanned (false)
{
}
@ -1267,7 +1447,6 @@ public:
{
jassert (hasScanned); // need to call scanForDevices() before doing this
const bool useExclusiveMode = false;
ScopedPointer<WASAPIAudioIODevice> device;
const int outputIndex = outputDeviceNames.indexOf (outputDeviceName);
@ -1277,9 +1456,10 @@ public:
{
device = new WASAPIAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName
: inputDeviceName,
getTypeName(),
outputDeviceIds [outputIndex],
inputDeviceIds [inputIndex],
useExclusiveMode);
exclusiveMode);
if (! device->initialise())
device = nullptr;
@ -1293,7 +1473,7 @@ public:
StringArray inputDeviceNames, inputDeviceIds;
private:
bool hasScanned;
bool exclusiveMode, hasScanned;
ComSmartPtr<IMMDeviceEnumerator> enumerator;
//==============================================================================
@ -1343,10 +1523,10 @@ private:
}
//==============================================================================
void scan (StringArray& outputDeviceNames,
StringArray& inputDeviceNames,
StringArray& outputDeviceIds,
StringArray& inputDeviceIds)
void scan (StringArray& outDeviceNames,
StringArray& inDeviceNames,
StringArray& outDeviceIds,
StringArray& inDeviceIds)
{
if (enumerator == nullptr)
{
@ -1402,19 +1582,19 @@ private:
if (flow == eRender)
{
const int index = (deviceId == defaultRenderer) ? 0 : -1;
outputDeviceIds.insert (index, deviceId);
outputDeviceNames.insert (index, name);
outDeviceIds.insert (index, deviceId);
outDeviceNames.insert (index, name);
}
else if (flow == eCapture)
{
const int index = (deviceId == defaultCapture) ? 0 : -1;
inputDeviceIds.insert (index, deviceId);
inputDeviceNames.insert (index, name);
inDeviceIds.insert (index, deviceId);
inDeviceNames.insert (index, name);
}
}
inputDeviceNames.appendNumbersToDuplicates (false, false);
outputDeviceNames.appendNumbersToDuplicates (false, false);
inDeviceNames.appendNumbersToDuplicates (false, false);
outDeviceNames.appendNumbersToDuplicates (false, false);
}
//==============================================================================
@ -1493,12 +1673,16 @@ struct MMDeviceMasterVolume
}
//==============================================================================
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_WASAPI()
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_WASAPI (bool exclusiveMode)
{
if (SystemStats::getOperatingSystemType() >= SystemStats::WinVista)
return new WasapiClasses::WASAPIAudioIODeviceType();
#if ! JUCE_WASAPI_EXCLUSIVE
if (exclusiveMode)
return nullptr;
#endif
return nullptr;
return SystemStats::getOperatingSystemType() >= SystemStats::WinVista
? new WasapiClasses::WASAPIAudioIODeviceType (exclusiveMode)
: nullptr;
}
//==============================================================================

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -2,7 +2,7 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)

@ -1,6 +1,6 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000-2009 Josh Coalson
* Copyright (C) 2011-2013 Xiph.Org Foundation
* Copyright (C) 2011-2014 Xiph.Org Foundation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions

@ -1,6 +1,6 @@
/* alloc - Convenience routines for safely allocating memory
* Copyright (C) 2007-2009 Josh Coalson
* Copyright (C) 2011-2013 Xiph.Org Foundation
* Copyright (C) 2011-2014 Xiph.Org Foundation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -33,7 +33,7 @@
#ifndef FLAC__SHARE__ALLOC_H
#define FLAC__SHARE__ALLOC_H
#if HAVE_CONFIG_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

@ -1,6 +1,6 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2001-2009 Josh Coalson
* Copyright (C) 2011-2013 Xiph.Org Foundation
* Copyright (C) 2011-2014 Xiph.Org Foundation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions

@ -1,6 +1,6 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2004-2009 Josh Coalson
* Copyright (C) 2011-2013 Xiph.Org Foundation
* Copyright (C) 2011-2014 Xiph.Org Foundation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions

@ -1,5 +1,5 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2012 Xiph.org Foundation
* Copyright (C) 2012-2014 Xiph.org Foundation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -73,23 +73,25 @@
#endif
#if defined(_MSC_VER)
#if _MSC_VER < 1500
/* Visual Studio 2008 has restrict. */
#define restrict __restrict
#endif
#define inline __inline
#endif
/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
#ifdef _MSC_VER
#define FLAC__U64L(x) x
#if defined __INTEL_COMPILER || (defined _MSC_VER && defined _WIN64)
/* MSVS generates VERY slow 32-bit code with __restrict */
#define flac_restrict __restrict
#elif defined __GNUC__
#define flac_restrict __restrict__
#else
#define FLAC__U64L(x) x##LLU
#define flac_restrict
#endif
#define FLAC__U64L(x) x##ULL
#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
#define FLAC__STRCASECMP stricmp
#define FLAC__STRNCASECMP strnicmp
#else
#define FLAC__STRCASECMP strcasecmp
#define FLAC__STRNCASECMP strncasecmp
#endif
@ -139,6 +141,7 @@
#ifdef _WIN32
/* All char* strings are in UTF-8 format. Added to support Unicode files on Windows */
#include "win_utf8_io.h"
#define flac_printf printf_utf8
#define flac_fprintf fprintf_utf8
@ -160,12 +163,7 @@
#define flac_utime utime
#define flac_unlink unlink
#define flac_rename rename
#ifdef _WIN32
#define flac_stat _stat64
#else
#define flac_stat stat
#endif
#endif
@ -177,8 +175,14 @@
#define flac_fstat fstat
#endif
#ifndef M_LN2
#define M_LN2 0.69314718055994530942
#endif
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
/* FLAC needs to compile and work correctly on systems with a norrmal ISO C99
/* FLAC needs to compile and work correctly on systems with a normal ISO C99
* snprintf as well as Microsoft Visual Studio which has an non-standards
* conformant snprint_s function.
*
@ -188,6 +192,7 @@
extern "C" {
#endif
int flac_snprintf(char *str, size_t size, const char *fmt, ...);
int flac_vsnprintf(char *str, size_t size, const char *fmt, va_list va);
#ifdef __cplusplus
};
#endif

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save