From e6f64740d970a1264d6d202015e72e334088e19e Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Mon, 23 May 2011 18:17:03 +0100 Subject: [PATCH] New classes: Reverb and ReverbAudioSource. Fixes for component alpha levels, mac file chooser, MemoryInputStream. --- Builds/Linux/Makefile | 6 + Builds/MacOSX/Juce.xcodeproj/project.pbxproj | 10 +- Builds/VisualStudio2005/Juce.vcproj | 3 + Builds/VisualStudio2008/Juce.vcproj | 3 + Builds/VisualStudio2008_DLL/Juce.vcproj | 3 + Builds/VisualStudio2010/Juce.vcxproj | 3 + Builds/VisualStudio2010/Juce.vcxproj.filters | 9 + Builds/iOS/Juce.xcodeproj/project.pbxproj | 10 +- Juce.jucer | 5 + amalgamation/juce_amalgamated_template.cpp | 1 + .../Source/Application/jucer_Application.h | 2 +- juce_amalgamated.cpp | 239 ++++++----- juce_amalgamated.h | 402 +++++++++++++++++- .../juce_AudioFormatReaderSource.cpp | 65 +-- .../juce_AudioFormatReaderSource.h | 7 +- .../juce_BufferingAudioSource.cpp | 8 +- .../audio_sources/juce_BufferingAudioSource.h | 6 +- .../juce_ChannelRemappingAudioSource.cpp | 13 +- .../juce_ChannelRemappingAudioSource.h | 7 +- .../juce_IIRFilterAudioSource.cpp | 12 +- .../audio_sources/juce_IIRFilterAudioSource.h | 10 +- .../juce_ResamplingAudioSource.cpp | 11 +- .../juce_ResamplingAudioSource.h | 4 +- .../audio_sources/juce_ReverbAudioSource.cpp | 92 ++++ .../audio_sources/juce_ReverbAudioSource.h | 82 ++++ src/audio/dsp/juce_Reverb.h | 325 ++++++++++++++ src/core/juce_StandardHeader.h | 2 +- src/gui/components/juce_Component.cpp | 10 +- src/gui/graphics/contexts/juce_Graphics.h | 4 + .../graphics/imaging/juce_ImageFileFormat.cpp | 25 +- src/io/streams/juce_MemoryInputStream.cpp | 23 +- src/io/streams/juce_MemoryInputStream.h | 4 +- src/juce_app_includes.h | 6 + src/maths/juce_MathsFunctions.h | 11 + src/native/mac/juce_mac_FileChooser.mm | 2 +- src/native/mac/juce_mac_Fonts.mm | 3 + 36 files changed, 1170 insertions(+), 258 deletions(-) create mode 100644 src/audio/audio_sources/juce_ReverbAudioSource.cpp create mode 100644 src/audio/audio_sources/juce_ReverbAudioSource.h create mode 100644 src/audio/dsp/juce_Reverb.h diff --git a/Builds/Linux/Makefile b/Builds/Linux/Makefile index 8e4ff439e6..6650c16363 100644 --- a/Builds/Linux/Makefile +++ b/Builds/Linux/Makefile @@ -65,6 +65,7 @@ OBJECTS := \ $(OBJDIR)/juce_IIRFilterAudioSource_807ee8aa.o \ $(OBJDIR)/juce_MixerAudioSource_bc6f772b.o \ $(OBJDIR)/juce_ResamplingAudioSource_8511875e.o \ + $(OBJDIR)/juce_ReverbAudioSource_3ae42aa6.o \ $(OBJDIR)/juce_ToneGeneratorAudioSource_77f504b3.o \ $(OBJDIR)/juce_AudioDeviceManager_c24db832.o \ $(OBJDIR)/juce_AudioIODevice_f7da876b.o \ @@ -514,6 +515,11 @@ $(OBJDIR)/juce_ResamplingAudioSource_8511875e.o: ../../src/audio/audio_sources/j @echo "Compiling juce_ResamplingAudioSource.cpp" @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" +$(OBJDIR)/juce_ReverbAudioSource_3ae42aa6.o: ../../src/audio/audio_sources/juce_ReverbAudioSource.cpp + -@mkdir -p $(OBJDIR) + @echo "Compiling juce_ReverbAudioSource.cpp" + @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" + $(OBJDIR)/juce_ToneGeneratorAudioSource_77f504b3.o: ../../src/audio/audio_sources/juce_ToneGeneratorAudioSource.cpp -@mkdir -p $(OBJDIR) @echo "Compiling juce_ToneGeneratorAudioSource.cpp" diff --git a/Builds/MacOSX/Juce.xcodeproj/project.pbxproj b/Builds/MacOSX/Juce.xcodeproj/project.pbxproj index c4ae48bbd7..292112c982 100644 --- a/Builds/MacOSX/Juce.xcodeproj/project.pbxproj +++ b/Builds/MacOSX/Juce.xcodeproj/project.pbxproj @@ -32,6 +32,7 @@ 6DC6DEEE8A1A6092830A79C8 = { isa = PBXBuildFile; fileRef = D86718CE7E5DEF2071AC3D17; }; 2862E190ECA33D2CE1458B51 = { isa = PBXBuildFile; fileRef = 9A8053936C35A19B9E98623A; }; 0791EB173E6A9F959E692AA2 = { isa = PBXBuildFile; fileRef = E2A56C23BF2BB466BB273E3E; }; + 3B64EF7F57EAC5C51460059D = { isa = PBXBuildFile; fileRef = 5403C2A4DEE7B9B3B34235F8; }; 16D537EB6D3BFAB3AAB54B11 = { isa = PBXBuildFile; fileRef = 3988438157D4B75177703F8A; }; 0C22446F12486AD139A640CB = { isa = PBXBuildFile; fileRef = 6841D6AC927D02113F3AEBD4; }; 95CF50482DC7139FCB40EB1C = { isa = PBXBuildFile; fileRef = C7DB1BB9AF7FE0A2AA38D767; }; @@ -420,6 +421,8 @@ C63D6EC0555C13C1B79A6AAD = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_PositionableAudioSource.h; path = ../../src/audio/audio_sources/juce_PositionableAudioSource.h; sourceTree = SOURCE_ROOT; }; E2A56C23BF2BB466BB273E3E = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ResamplingAudioSource.cpp; path = ../../src/audio/audio_sources/juce_ResamplingAudioSource.cpp; sourceTree = SOURCE_ROOT; }; BE5DB55285441D501FED3C00 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ResamplingAudioSource.h; path = ../../src/audio/audio_sources/juce_ResamplingAudioSource.h; sourceTree = SOURCE_ROOT; }; + 5403C2A4DEE7B9B3B34235F8 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ReverbAudioSource.cpp; path = ../../src/audio/audio_sources/juce_ReverbAudioSource.cpp; sourceTree = SOURCE_ROOT; }; + 0F70C4D118AC7625B4C42CD4 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ReverbAudioSource.h; path = ../../src/audio/audio_sources/juce_ReverbAudioSource.h; sourceTree = SOURCE_ROOT; }; 3988438157D4B75177703F8A = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ToneGeneratorAudioSource.cpp; path = ../../src/audio/audio_sources/juce_ToneGeneratorAudioSource.cpp; sourceTree = SOURCE_ROOT; }; 6AC857F51FD805D7BD3EF712 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ToneGeneratorAudioSource.h; path = ../../src/audio/audio_sources/juce_ToneGeneratorAudioSource.h; sourceTree = SOURCE_ROOT; }; 6841D6AC927D02113F3AEBD4 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioDeviceManager.cpp; path = ../../src/audio/devices/juce_AudioDeviceManager.cpp; sourceTree = SOURCE_ROOT; }; @@ -435,6 +438,7 @@ 11C1A96A35A2F03F8C34BD43 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Decibels.h; path = ../../src/audio/dsp/juce_Decibels.h; sourceTree = SOURCE_ROOT; }; E68EB4BC75216B5B56E3F937 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_IIRFilter.cpp; path = ../../src/audio/dsp/juce_IIRFilter.cpp; sourceTree = SOURCE_ROOT; }; EE2259D9768027C2C001EEAD = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_IIRFilter.h; path = ../../src/audio/dsp/juce_IIRFilter.h; sourceTree = SOURCE_ROOT; }; + 2C55CE1674244DB199C3033F = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Reverb.h; path = ../../src/audio/dsp/juce_Reverb.h; sourceTree = SOURCE_ROOT; }; B457515938E7141D5E79B671 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_MidiBuffer.cpp; path = ../../src/audio/midi/juce_MidiBuffer.cpp; sourceTree = SOURCE_ROOT; }; 0604C2E17F0E0DFEFDA19F8D = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_MidiBuffer.h; path = ../../src/audio/midi/juce_MidiBuffer.h; sourceTree = SOURCE_ROOT; }; 891E0B1AD09C0EA44297E0F2 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_MidiFile.cpp; path = ../../src/audio/midi/juce_MidiFile.cpp; sourceTree = SOURCE_ROOT; }; @@ -1158,6 +1162,8 @@ C63D6EC0555C13C1B79A6AAD, E2A56C23BF2BB466BB273E3E, BE5DB55285441D501FED3C00, + 5403C2A4DEE7B9B3B34235F8, + 0F70C4D118AC7625B4C42CD4, 3988438157D4B75177703F8A, 6AC857F51FD805D7BD3EF712 ); name = audio_sources; sourceTree = ""; }; BF8F3D00CE4E97468E8BBC55 = { isa = PBXGroup; children = ( @@ -1174,7 +1180,8 @@ 812620B53BE820D26A63B65D, 11C1A96A35A2F03F8C34BD43, E68EB4BC75216B5B56E3F937, - EE2259D9768027C2C001EEAD ); name = dsp; sourceTree = ""; }; + EE2259D9768027C2C001EEAD, + 2C55CE1674244DB199C3033F ); name = dsp; sourceTree = ""; }; 99B60B012D5CCF0BD861011D = { isa = PBXGroup; children = ( B457515938E7141D5E79B671, 0604C2E17F0E0DFEFDA19F8D, @@ -2063,6 +2070,7 @@ 6DC6DEEE8A1A6092830A79C8, 2862E190ECA33D2CE1458B51, 0791EB173E6A9F959E692AA2, + 3B64EF7F57EAC5C51460059D, 16D537EB6D3BFAB3AAB54B11, 0C22446F12486AD139A640CB, 95CF50482DC7139FCB40EB1C, diff --git a/Builds/VisualStudio2005/Juce.vcproj b/Builds/VisualStudio2005/Juce.vcproj index 2bbc5576c3..525fa79117 100644 --- a/Builds/VisualStudio2005/Juce.vcproj +++ b/Builds/VisualStudio2005/Juce.vcproj @@ -162,6 +162,8 @@ + + @@ -181,6 +183,7 @@ + diff --git a/Builds/VisualStudio2008/Juce.vcproj b/Builds/VisualStudio2008/Juce.vcproj index 329ec278e8..259dfa7533 100644 --- a/Builds/VisualStudio2008/Juce.vcproj +++ b/Builds/VisualStudio2008/Juce.vcproj @@ -162,6 +162,8 @@ + + @@ -181,6 +183,7 @@ + diff --git a/Builds/VisualStudio2008_DLL/Juce.vcproj b/Builds/VisualStudio2008_DLL/Juce.vcproj index d5471a33f3..7c6a1638d8 100644 --- a/Builds/VisualStudio2008_DLL/Juce.vcproj +++ b/Builds/VisualStudio2008_DLL/Juce.vcproj @@ -164,6 +164,8 @@ + + @@ -183,6 +185,7 @@ + diff --git a/Builds/VisualStudio2010/Juce.vcxproj b/Builds/VisualStudio2010/Juce.vcxproj index 42fed03f62..d9efa015c6 100644 --- a/Builds/VisualStudio2010/Juce.vcxproj +++ b/Builds/VisualStudio2010/Juce.vcxproj @@ -148,6 +148,7 @@ + @@ -483,6 +484,7 @@ + @@ -491,6 +493,7 @@ + diff --git a/Builds/VisualStudio2010/Juce.vcxproj.filters b/Builds/VisualStudio2010/Juce.vcxproj.filters index ce55c9390f..9b8d58c3b8 100644 --- a/Builds/VisualStudio2010/Juce.vcxproj.filters +++ b/Builds/VisualStudio2010/Juce.vcxproj.filters @@ -265,6 +265,9 @@ Juce\Source\audio\audio_sources + + Juce\Source\audio\audio_sources + Juce\Source\audio\audio_sources @@ -1380,6 +1383,9 @@ Juce\Source\audio\audio_sources + + Juce\Source\audio\audio_sources + Juce\Source\audio\audio_sources @@ -1404,6 +1410,9 @@ Juce\Source\audio\dsp + + Juce\Source\audio\dsp + Juce\Source\audio\midi diff --git a/Builds/iOS/Juce.xcodeproj/project.pbxproj b/Builds/iOS/Juce.xcodeproj/project.pbxproj index 45e07ccc02..7c91b8ee46 100644 --- a/Builds/iOS/Juce.xcodeproj/project.pbxproj +++ b/Builds/iOS/Juce.xcodeproj/project.pbxproj @@ -32,6 +32,7 @@ 6DC6DEEE8A1A6092830A79C8 = { isa = PBXBuildFile; fileRef = D86718CE7E5DEF2071AC3D17; }; 2862E190ECA33D2CE1458B51 = { isa = PBXBuildFile; fileRef = 9A8053936C35A19B9E98623A; }; 0791EB173E6A9F959E692AA2 = { isa = PBXBuildFile; fileRef = E2A56C23BF2BB466BB273E3E; }; + 3B64EF7F57EAC5C51460059D = { isa = PBXBuildFile; fileRef = 5403C2A4DEE7B9B3B34235F8; }; 16D537EB6D3BFAB3AAB54B11 = { isa = PBXBuildFile; fileRef = 3988438157D4B75177703F8A; }; 0C22446F12486AD139A640CB = { isa = PBXBuildFile; fileRef = 6841D6AC927D02113F3AEBD4; }; 95CF50482DC7139FCB40EB1C = { isa = PBXBuildFile; fileRef = C7DB1BB9AF7FE0A2AA38D767; }; @@ -420,6 +421,8 @@ C63D6EC0555C13C1B79A6AAD = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_PositionableAudioSource.h; path = ../../src/audio/audio_sources/juce_PositionableAudioSource.h; sourceTree = SOURCE_ROOT; }; E2A56C23BF2BB466BB273E3E = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ResamplingAudioSource.cpp; path = ../../src/audio/audio_sources/juce_ResamplingAudioSource.cpp; sourceTree = SOURCE_ROOT; }; BE5DB55285441D501FED3C00 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ResamplingAudioSource.h; path = ../../src/audio/audio_sources/juce_ResamplingAudioSource.h; sourceTree = SOURCE_ROOT; }; + 5403C2A4DEE7B9B3B34235F8 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ReverbAudioSource.cpp; path = ../../src/audio/audio_sources/juce_ReverbAudioSource.cpp; sourceTree = SOURCE_ROOT; }; + 0F70C4D118AC7625B4C42CD4 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ReverbAudioSource.h; path = ../../src/audio/audio_sources/juce_ReverbAudioSource.h; sourceTree = SOURCE_ROOT; }; 3988438157D4B75177703F8A = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ToneGeneratorAudioSource.cpp; path = ../../src/audio/audio_sources/juce_ToneGeneratorAudioSource.cpp; sourceTree = SOURCE_ROOT; }; 6AC857F51FD805D7BD3EF712 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ToneGeneratorAudioSource.h; path = ../../src/audio/audio_sources/juce_ToneGeneratorAudioSource.h; sourceTree = SOURCE_ROOT; }; 6841D6AC927D02113F3AEBD4 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioDeviceManager.cpp; path = ../../src/audio/devices/juce_AudioDeviceManager.cpp; sourceTree = SOURCE_ROOT; }; @@ -435,6 +438,7 @@ 11C1A96A35A2F03F8C34BD43 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Decibels.h; path = ../../src/audio/dsp/juce_Decibels.h; sourceTree = SOURCE_ROOT; }; E68EB4BC75216B5B56E3F937 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_IIRFilter.cpp; path = ../../src/audio/dsp/juce_IIRFilter.cpp; sourceTree = SOURCE_ROOT; }; EE2259D9768027C2C001EEAD = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_IIRFilter.h; path = ../../src/audio/dsp/juce_IIRFilter.h; sourceTree = SOURCE_ROOT; }; + 2C55CE1674244DB199C3033F = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Reverb.h; path = ../../src/audio/dsp/juce_Reverb.h; sourceTree = SOURCE_ROOT; }; B457515938E7141D5E79B671 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_MidiBuffer.cpp; path = ../../src/audio/midi/juce_MidiBuffer.cpp; sourceTree = SOURCE_ROOT; }; 0604C2E17F0E0DFEFDA19F8D = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_MidiBuffer.h; path = ../../src/audio/midi/juce_MidiBuffer.h; sourceTree = SOURCE_ROOT; }; 891E0B1AD09C0EA44297E0F2 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_MidiFile.cpp; path = ../../src/audio/midi/juce_MidiFile.cpp; sourceTree = SOURCE_ROOT; }; @@ -1158,6 +1162,8 @@ C63D6EC0555C13C1B79A6AAD, E2A56C23BF2BB466BB273E3E, BE5DB55285441D501FED3C00, + 5403C2A4DEE7B9B3B34235F8, + 0F70C4D118AC7625B4C42CD4, 3988438157D4B75177703F8A, 6AC857F51FD805D7BD3EF712 ); name = audio_sources; sourceTree = ""; }; BF8F3D00CE4E97468E8BBC55 = { isa = PBXGroup; children = ( @@ -1174,7 +1180,8 @@ 812620B53BE820D26A63B65D, 11C1A96A35A2F03F8C34BD43, E68EB4BC75216B5B56E3F937, - EE2259D9768027C2C001EEAD ); name = dsp; sourceTree = ""; }; + EE2259D9768027C2C001EEAD, + 2C55CE1674244DB199C3033F ); name = dsp; sourceTree = ""; }; 99B60B012D5CCF0BD861011D = { isa = PBXGroup; children = ( B457515938E7141D5E79B671, 0604C2E17F0E0DFEFDA19F8D, @@ -2067,6 +2074,7 @@ 6DC6DEEE8A1A6092830A79C8, 2862E190ECA33D2CE1458B51, 0791EB173E6A9F959E692AA2, + 3B64EF7F57EAC5C51460059D, 16D537EB6D3BFAB3AAB54B11, 0C22446F12486AD139A640CB, 95CF50482DC7139FCB40EB1C, diff --git a/Juce.jucer b/Juce.jucer index 26237a2666..c7cc527f79 100644 --- a/Juce.jucer +++ b/Juce.jucer @@ -155,6 +155,10 @@ resource="0" file="src/audio/audio_sources/juce_ResamplingAudioSource.cpp"/> + + + (internalCopy.getData()); - } + createInternalCopy(); } MemoryInputStream::MemoryInputStream (const MemoryBlock& sourceData, @@ -10286,10 +10283,14 @@ MemoryInputStream::MemoryInputStream (const MemoryBlock& sourceData, position (0) { if (keepInternalCopy) - { - internalCopy = sourceData; - data = static_cast (internalCopy.getData()); - } + createInternalCopy(); +} + +void MemoryInputStream::createInternalCopy() +{ + internalCopy.malloc (dataSize); + memcpy (internalCopy, data, dataSize); + data = internalCopy; } MemoryInputStream::~MemoryInputStream() @@ -10305,6 +10306,9 @@ int MemoryInputStream::read (void* const buffer, const int howMany) { jassert (howMany >= 0); const int num = jmin (howMany, (int) (dataSize - position)); + if (num <= 0) + return 0; + memcpy (buffer, data + position, num); position += num; return (int) num; @@ -10312,7 +10316,7 @@ int MemoryInputStream::read (void* const buffer, const int howMany) bool MemoryInputStream::isExhausted() { - return (position >= dataSize); + return position >= dataSize; } bool MemoryInputStream::setPosition (const int64 pos) @@ -24323,29 +24327,18 @@ BEGIN_JUCE_NAMESPACE AudioFormatReaderSource::AudioFormatReaderSource (AudioFormatReader* const reader_, const bool deleteReaderWhenThisIsDeleted) - : reader (reader_), - deleteReader (deleteReaderWhenThisIsDeleted), + : reader (reader_, deleteReaderWhenThisIsDeleted), nextPlayPos (0), looping (false) { jassert (reader != nullptr); } -AudioFormatReaderSource::~AudioFormatReaderSource() -{ - if (deleteReader) - delete reader; -} +AudioFormatReaderSource::~AudioFormatReaderSource() {} -void AudioFormatReaderSource::setNextReadPosition (int64 newPosition) -{ - nextPlayPos = newPosition; -} - -void AudioFormatReaderSource::setLooping (bool shouldLoop) -{ - looping = shouldLoop; -} +int64 AudioFormatReaderSource::getTotalLength() const { return reader->lengthInSamples; } +void AudioFormatReaderSource::setNextReadPosition (int64 newPosition) { nextPlayPos = newPosition; } +void AudioFormatReaderSource::setLooping (bool shouldLoop) { looping = shouldLoop; } int64 AudioFormatReaderSource::getNextReadPosition() const { @@ -24353,19 +24346,8 @@ int64 AudioFormatReaderSource::getNextReadPosition() const : nextPlayPos; } -int64 AudioFormatReaderSource::getTotalLength() const -{ - return reader->lengthInSamples; -} - -void AudioFormatReaderSource::prepareToPlay (int /*samplesPerBlockExpected*/, - double /*sampleRate*/) -{ -} - -void AudioFormatReaderSource::releaseResources() -{ -} +void AudioFormatReaderSource::prepareToPlay (int /*samplesPerBlockExpected*/, double /*sampleRate*/) {} +void AudioFormatReaderSource::releaseResources() {} void AudioFormatReaderSource::getNextAudioBlock (const AudioSourceChannelInfo& info) { @@ -24380,39 +24362,26 @@ void AudioFormatReaderSource::getNextAudioBlock (const AudioSourceChannelInfo& i if (newEnd > newStart) { - info.buffer->readFromAudioReader (reader, - info.startSample, - newEnd - newStart, - newStart, - true, true); + info.buffer->readFromAudioReader (reader, info.startSample, + newEnd - newStart, newStart, true, true); } else { const int endSamps = (int) reader->lengthInSamples - newStart; - info.buffer->readFromAudioReader (reader, - info.startSample, - endSamps, - newStart, - true, true); + info.buffer->readFromAudioReader (reader, info.startSample, + endSamps, newStart, true, true); - info.buffer->readFromAudioReader (reader, - info.startSample + endSamps, - newEnd, - 0, - true, true); + info.buffer->readFromAudioReader (reader, info.startSample + endSamps, + newEnd, 0, true, true); } nextPlayPos = newEnd; } else { - info.buffer->readFromAudioReader (reader, - info.startSample, - info.numSamples, - start, - true, true); - + info.buffer->readFromAudioReader (reader, info.startSample, + info.numSamples, start, true, true); nextPlayPos += info.numSamples; } } @@ -24954,11 +24923,10 @@ private: juce_ImplementSingleton (SharedBufferingAudioSourceThread) BufferingAudioSource::BufferingAudioSource (PositionableAudioSource* source_, - const bool deleteSourceWhenDeleted_, + const bool deleteSourceWhenDeleted, const int numberOfSamplesToBuffer_, const int numberOfChannels_) - : source (source_), - deleteSourceWhenDeleted (deleteSourceWhenDeleted_), + : source (source_, deleteSourceWhenDeleted), numberOfSamplesToBuffer (jmax (1024, numberOfSamplesToBuffer_)), numberOfChannels (numberOfChannels_), buffer (numberOfChannels_, 0), @@ -24979,9 +24947,6 @@ BufferingAudioSource::~BufferingAudioSource() if (thread != nullptr) thread->removeSource (this); - - if (deleteSourceWhenDeleted) - delete source; } void BufferingAudioSource::prepareToPlay (int samplesPerBlockExpected, double sampleRate_) @@ -25203,21 +25168,16 @@ END_JUCE_NAMESPACE BEGIN_JUCE_NAMESPACE ChannelRemappingAudioSource::ChannelRemappingAudioSource (AudioSource* const source_, - const bool deleteSourceWhenDeleted_) - : requiredNumberOfChannels (2), - source (source_), - deleteSourceWhenDeleted (deleteSourceWhenDeleted_), + const bool deleteSourceWhenDeleted) + : source (source_, deleteSourceWhenDeleted), + requiredNumberOfChannels (2), buffer (2, 16) { remappedInfo.buffer = &buffer; remappedInfo.startSample = 0; } -ChannelRemappingAudioSource::~ChannelRemappingAudioSource() -{ - if (deleteSourceWhenDeleted) - delete source; -} +ChannelRemappingAudioSource::~ChannelRemappingAudioSource() {} void ChannelRemappingAudioSource::setNumberOfChannelsToProduce (const int requiredNumberOfChannels_) { @@ -25379,9 +25339,8 @@ END_JUCE_NAMESPACE BEGIN_JUCE_NAMESPACE IIRFilterAudioSource::IIRFilterAudioSource (AudioSource* const inputSource, - const bool deleteInputWhenDeleted_) - : input (inputSource), - deleteInputWhenDeleted (deleteInputWhenDeleted_) + const bool deleteInputWhenDeleted) + : input (inputSource, deleteInputWhenDeleted) { jassert (inputSource != nullptr); @@ -25389,11 +25348,7 @@ IIRFilterAudioSource::IIRFilterAudioSource (AudioSource* const inputSource, iirFilters.add (new IIRFilter()); } -IIRFilterAudioSource::~IIRFilterAudioSource() -{ - if (deleteInputWhenDeleted) - delete input; -} +IIRFilterAudioSource::~IIRFilterAudioSource() {} void IIRFilterAudioSource::setFilterParameters (const IIRFilter& newSettings) { @@ -25434,6 +25389,71 @@ END_JUCE_NAMESPACE /*** End of inlined file: juce_IIRFilterAudioSource.cpp ***/ +/*** Start of inlined file: juce_ReverbAudioSource.cpp ***/ +BEGIN_JUCE_NAMESPACE + +ReverbAudioSource::ReverbAudioSource (AudioSource* const inputSource, const bool deleteInputWhenDeleted) + : input (inputSource, deleteInputWhenDeleted), + bypass (false) +{ + jassert (inputSource != nullptr); +} + +ReverbAudioSource::~ReverbAudioSource() {} + +void ReverbAudioSource::prepareToPlay (int samplesPerBlockExpected, double sampleRate) +{ + const ScopedLock sl (lock); + input->prepareToPlay (samplesPerBlockExpected, sampleRate); + reverb.setSampleRate (sampleRate); +} + +void ReverbAudioSource::releaseResources() {} + +void ReverbAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) +{ + const ScopedLock sl (lock); + + input->getNextAudioBlock (bufferToFill); + + if (! bypass) + { + float* const firstChannel = bufferToFill.buffer->getSampleData (0, bufferToFill.startSample); + + if (bufferToFill.buffer->getNumChannels() > 1) + { + reverb.processStereo (firstChannel, + bufferToFill.buffer->getSampleData (1, bufferToFill.startSample), + bufferToFill.numSamples); + } + else + { + reverb.processMono (firstChannel, bufferToFill.numSamples); + } + } +} + +void ReverbAudioSource::setParameters (const Reverb::Parameters& newParams) +{ + const ScopedLock sl (lock); + reverb.setParameters (newParams); +} + +void ReverbAudioSource::setBypassed (bool isBypassed) noexcept +{ + if (bypass != isBypassed) + { + const ScopedLock sl (lock); + bypass = isBypassed; + reverb.reset(); + } +} + +END_JUCE_NAMESPACE + +/*** End of inlined file: juce_ReverbAudioSource.cpp ***/ + + /*** Start of inlined file: juce_MixerAudioSource.cpp ***/ BEGIN_JUCE_NAMESPACE @@ -25581,10 +25601,9 @@ END_JUCE_NAMESPACE BEGIN_JUCE_NAMESPACE ResamplingAudioSource::ResamplingAudioSource (AudioSource* const inputSource, - const bool deleteInputWhenDeleted_, + const bool deleteInputWhenDeleted, const int numChannels_) - : input (inputSource), - deleteInputWhenDeleted (deleteInputWhenDeleted_), + : input (inputSource, deleteInputWhenDeleted), ratio (1.0), lastRatio (1.0), buffer (numChannels_, 0), @@ -25594,11 +25613,7 @@ ResamplingAudioSource::ResamplingAudioSource (AudioSource* const inputSource, jassert (input != nullptr); } -ResamplingAudioSource::~ResamplingAudioSource() -{ - if (deleteInputWhenDeleted) - delete input; -} +ResamplingAudioSource::~ResamplingAudioSource() {} void ResamplingAudioSource::setResamplingRatio (const double samplesInPerOutputSample) { @@ -42111,7 +42126,7 @@ void Component::paintComponent (Graphics& g) paint (imG); } - g.setColour (Colours::black.withAlpha (getAlpha())); + g.setColour (Colours::black); g.drawImageAt (bufferedImage, 0, 0); } else @@ -42202,9 +42217,9 @@ void Component::paintEntireComponent (Graphics& g, const bool ignoreAlphaLevel) { jassert (! g.isClipEmpty()); - #if JUCE_DEBUG + #if JUCE_DEBUG flags.isInsidePaintCall = true; - #endif + #endif if (effect != nullptr) { @@ -42231,9 +42246,9 @@ void Component::paintEntireComponent (Graphics& g, const bool ignoreAlphaLevel) paintComponentAndChildren (g); } - #if JUCE_DEBUG + #if JUCE_DEBUG flags.isInsidePaintCall = false; - #endif + #endif } void Component::setPaintingIsUnclipped (const bool shouldPaintWithoutClipping) noexcept @@ -97618,22 +97633,24 @@ END_JUCE_NAMESPACE /*** Start of inlined file: juce_ImageFileFormat.cpp ***/ BEGIN_JUCE_NAMESPACE +struct DefaultImageFormats +{ + PNGImageFormat png; + JPEGImageFormat jpg; + GIFImageFormat gif; +}; + +static DefaultImageFormats defaultImageFormats; + ImageFileFormat* ImageFileFormat::findImageFormatForStream (InputStream& input) { - static PNGImageFormat png; - static JPEGImageFormat jpg; - static GIFImageFormat gif; - - ImageFileFormat* formats[4]; - int numFormats = 0; - - formats [numFormats++] = &png; - formats [numFormats++] = &jpg; - formats [numFormats++] = &gif; + ImageFileFormat* formats[] = { &defaultImageFormats.png, + &defaultImageFormats.jpg, + &defaultImageFormats.gif }; const int64 streamPos = input.getPosition(); - for (int i = 0; i < numFormats; ++i) + for (int i = 0; i < numElementsInArray (formats); ++i) { const bool found = formats[i]->canUnderstand (input); input.setPosition (streamPos); @@ -272259,6 +272276,9 @@ public: jassert (path.isEmpty()); // we might need to apply a transform to the path, so this must be empty CGPathRef pathRef = CTFontCreatePathForGlyph (ctFontRef, (CGGlyph) glyphNumber, &renderingTransform); + if (pathRef == 0) + return false; + CGPathApply (pathRef, &path, pathApplier); CFRelease (pathRef); @@ -274948,7 +274968,7 @@ using namespace JUCE_NAMESPACE; if (f.getFileName().matchesWildcard ((*filters)[i], true)) return true; - return f.isDirectory(); + return f.isDirectory() && ! [[NSWorkspace sharedWorkspace] isFilePackageAtPath: filename]; } @end @@ -277296,6 +277316,9 @@ public: jassert (path.isEmpty()); // we might need to apply a transform to the path, so this must be empty CGPathRef pathRef = CTFontCreatePathForGlyph (ctFontRef, (CGGlyph) glyphNumber, &renderingTransform); + if (pathRef == 0) + return false; + CGPathApply (pathRef, &path, pathApplier); CFRelease (pathRef); @@ -282056,7 +282079,7 @@ using namespace JUCE_NAMESPACE; if (f.getFileName().matchesWildcard ((*filters)[i], true)) return true; - return f.isDirectory(); + return f.isDirectory() && ! [[NSWorkspace sharedWorkspace] isFilePackageAtPath: filename]; } @end diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 96f79e9ba4..cd29e8b680 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -73,7 +73,7 @@ namespace JuceDummyNamespace {} */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 53 -#define JUCE_BUILDNUMBER 91 +#define JUCE_BUILDNUMBER 92 /** Current Juce version number. @@ -1350,6 +1350,16 @@ inline int roundFloatToInt (const float value) noexcept return roundToInt (value); } +#if (JUCE_INTEL && JUCE_32BIT) || defined (DOXYGEN) + /** This macro can be applied to a float variable to check whether it contains a denormalised + value, and to normalise it if necessary. + On CPUs that aren't vulnerable to denormalisation problems, this will have no effect. + */ + #define JUCE_UNDENORMALISE(x) x += 1.0f; x -= 1.0f; +#else + #define JUCE_UNDENORMALISE(x) +#endif + /** This namespace contains a few template classes for helping work out class type variations. */ namespace TypeHelpers @@ -20988,7 +20998,9 @@ private: const char* data; size_t dataSize, position; - MemoryBlock internalCopy; + HeapBlock internalCopy; + + void createInternalCopy(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryInputStream); }; @@ -29257,6 +29269,8 @@ public: The x position is an integer, but the top and bottom of the line can be sub-pixel positions, and these will be anti-aliased if necessary. + + The bottom parameter must be greater than or equal to the top parameter. */ void drawVerticalLine (int x, float top, float bottom) const; @@ -29264,6 +29278,8 @@ public: The y position is an integer, but the left and right ends of the line can be sub-pixel positions, and these will be anti-aliased if necessary. + + The right parameter must be greater than or equal to the left parameter. */ void drawHorizontalLine (int y, float left, float right) const; @@ -37982,7 +37998,8 @@ public: /** Creates an AudioFormatReaderSource for a given reader. - @param sourceReader the reader to use as the data source + @param sourceReader the reader to use as the data source - this must + not be null @param deleteReaderWhenThisIsDeleted if true, the reader passed-in will be deleted when this object is deleted; if false it will be left up to the caller to manage its lifetime @@ -38028,8 +38045,7 @@ public: private: - AudioFormatReader* reader; - bool deleteReader; + OptionalScopedPointer reader; int64 volatile nextPlayPos; bool volatile looping; @@ -38506,14 +38522,13 @@ public: private: - PositionableAudioSource* source; - bool deleteSourceWhenDeleted; + OptionalScopedPointer source; int numberOfSamplesToBuffer, numberOfChannels; AudioSampleBuffer buffer; CriticalSection bufferStartPosLock; int64 volatile bufferValidStart, bufferValidEnd, nextPlayPos; - bool wasSourceLooping; double volatile sampleRate; + bool wasSourceLooping; friend class SharedBufferingAudioSourceThread; bool readNextBufferChunk(); @@ -38576,8 +38591,7 @@ public: private: - AudioSource* const input; - const bool deleteInputWhenDeleted; + OptionalScopedPointer input; double ratio, lastRatio; AudioSampleBuffer buffer; int bufferPos, sampsInBuffer; @@ -38862,11 +38876,9 @@ public: private: - int requiredNumberOfChannels; + OptionalScopedPointer source; Array remappedInputs, remappedOutputs; - - AudioSource* const source; - const bool deleteSourceWhenDeleted; + int requiredNumberOfChannels; AudioSampleBuffer buffer; AudioSourceChannelInfo remappedInfo; @@ -39018,7 +39030,7 @@ public: /** Creates a IIRFilterAudioSource for a given input source. - @param inputSource the input source to read from + @param inputSource the input source to read from - this must not be null @param deleteInputWhenDeleted if true, the input source will be deleted when this object is deleted */ @@ -39028,8 +39040,7 @@ public: /** Destructor. */ ~IIRFilterAudioSource(); - /** Changes the filter to use the same parameters as the one being passed in. - */ + /** Changes the filter to use the same parameters as the one being passed in. */ void setFilterParameters (const IIRFilter& newSettings); void prepareToPlay (int samplesPerBlockExpected, double sampleRate); @@ -39038,8 +39049,7 @@ public: private: - AudioSource* const input; - const bool deleteInputWhenDeleted; + OptionalScopedPointer input; OwnedArray iirFilters; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (IIRFilterAudioSource); @@ -39148,6 +39158,357 @@ private: #endif #ifndef __JUCE_RESAMPLINGAUDIOSOURCE_JUCEHEADER__ +#endif +#ifndef __JUCE_REVERBAUDIOSOURCE_JUCEHEADER__ + +/*** Start of inlined file: juce_ReverbAudioSource.h ***/ +#ifndef __JUCE_REVERBAUDIOSOURCE_JUCEHEADER__ +#define __JUCE_REVERBAUDIOSOURCE_JUCEHEADER__ + + +/*** Start of inlined file: juce_Reverb.h ***/ +#ifndef __JUCE_REVERB_JUCEHEADER__ +#define __JUCE_REVERB_JUCEHEADER__ + +/** + Performs a simple reverb effect on a stream of audio data. + + This is a simple stereo reverb, based on the technique and tunings used in FreeVerb. + Use setSampleRate() to prepare it, and then call processStereo() or processMono() to + apply the reverb to your audio data. + + @see ReverbAudioSource +*/ +class Reverb +{ +public: + + Reverb() + { + setParameters (Parameters()); + setSampleRate (44100.0); + } + + /** Holds the parameters being used by a Reverb object. */ + struct Parameters + { + Parameters() noexcept + : roomSize (0.5f), + damping (0.5f), + wetLevel (0.33f), + dryLevel (0.4f), + width (1.0f), + freezeMode (0) + {} + + float roomSize; /**< Room size, 0 to 1.0, where 1.0 is big, 0 is small. */ + float damping; /**< Damping, 0 to 1.0, where 0 is not damped, 1.0 is fully damped. */ + float wetLevel; /**< Wet level, 0 to 1.0 */ + float dryLevel; /**< Dry level, 0 to 1.0 */ + float width; /**< Reverb width, 0 to 1.0, where 1.0 is very wide. */ + float freezeMode; /**< Freeze mode - values < 0.5 are "normal" mode, values > 0.5 + put the reverb into a continuous feedback loop. */ + }; + + /** Returns the reverb's current parameters. */ + const Parameters& getParameters() const noexcept { return parameters; } + + /** Applies a new set of parameters to the reverb. + Note that this doesn't attempt to lock the reverb, so if you call this in parallel with + the process method, you may get artifacts. + */ + void setParameters (const Parameters& newParams) + { + const float wetScaleFactor = 3.0f; + 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; + gain = isFrozen (newParams.freezeMode) ? 0.0f : 0.015f; + parameters = newParams; + shouldUpdateDamping = true; + } + + /** Sets the sample rate that will be used for the reverb. + You must call this before the process methods, in order to tell it the correct sample rate. + */ + void setSampleRate (const double sampleRate) + { + jassert (sampleRate > 0); + + static const short combTunings[] = { 1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617 }; // (at 44100Hz) + static const short allPassTunings[] = { 556, 441, 341, 225 }; + const int stereoSpread = 23; + const int intSampleRate = (int) sampleRate; + + int i; + for (i = 0; i < numCombs; ++i) + { + comb[0][i].setSize ((intSampleRate * combTunings[i]) / 44100); + comb[1][i].setSize ((intSampleRate * (combTunings[i] + stereoSpread)) / 44100); + } + + for (i = 0; i < numAllPasses; ++i) + { + allPass[0][i].setSize ((intSampleRate * allPassTunings[i]) / 44100); + allPass[1][i].setSize ((intSampleRate * (allPassTunings[i] + stereoSpread)) / 44100); + } + + shouldUpdateDamping = true; + } + + /** Clears the reverb's buffers. */ + void reset() + { + for (int j = 0; j < numChannels; ++j) + { + int i; + for (i = 0; i < numCombs; ++i) + comb[j][i].clear(); + + for (i = 0; i < numAllPasses; ++i) + allPass[j][i].clear(); + } + } + + /** Applies the reverb to two stereo channels of audio data. */ + void processStereo (float* const left, float* const right, const int numSamples) noexcept + { + 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; + + int j; + for (j = 0; j < numCombs; ++j) // accumulate the comb filters in parallel + { + outL += comb[0][j].process (input); + outR += comb[1][j].process (input); + } + + for (j = 0; j < numAllPasses; ++j) // run the allpass filters in series + { + outL = allPass[0][j].process (outL); + outR = allPass[1][j].process (outR); + } + + left[i] = outL * wet1 + outR * wet2 + left[i] * dry; + right[i] = outR * wet1 + outL * wet2 + right[i] * dry; + } + } + + /** Applies the reverb to a single mono channel of audio data. */ + void processMono (float* const samples, const int numSamples) noexcept + { + jassert (samples != nullptr); + + if (shouldUpdateDamping) + updateDamping(); + + for (int i = 0; i < numSamples; ++i) + { + const float input = samples[i] * gain; + float output = 0; + + int j; + for (j = 0; j < numCombs; ++j) // accumulate the comb filters in parallel + output += comb[0][j].process (input); + + for (j = 0; j < numAllPasses; ++j) // run the allpass filters in series + output = allPass[0][j].process (output); + + samples[i] = output * wet1 + input * dry; + } + } + +private: + + Parameters parameters; + + volatile bool shouldUpdateDamping; + float gain, wet1, wet2, dry; + + inline static bool isFrozen (const float freezeMode) noexcept { return freezeMode >= 0.5f; } + + void updateDamping() noexcept + { + const float roomScaleFactor = 0.28f; + const float roomOffset = 0.7f; + const float dampScaleFactor = 0.4f; + + shouldUpdateDamping = false; + + if (isFrozen (parameters.freezeMode)) + setDamping (1.0f, 0.0f); + else + setDamping (parameters.damping * dampScaleFactor, + parameters.roomSize * roomScaleFactor + roomOffset); + } + + 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); + } + + class CombFilter + { + public: + CombFilter() noexcept : bufferSize (0), bufferIndex (0) {} + + void setSize (const int size) + { + if (size != bufferSize) + { + bufferIndex = 0; + buffer.malloc (size); + bufferSize = size; + } + + clear(); + } + + void clear() noexcept + { + last = 0; + zeromem (buffer, bufferSize * sizeof (float)); + } + + void setFeedbackAndDamp (const float f, const float d) noexcept + { + damp1 = d; + damp2 = 1.0f - d; + feedback = f; + } + + inline float process (const float input) noexcept + { + const float output = buffer [bufferIndex]; + last = (output * damp2) + (last * damp1); + JUCE_UNDENORMALISE (last); + + float temp = input + (last * feedback); + JUCE_UNDENORMALISE (temp); + buffer [bufferIndex] = temp; + bufferIndex = (bufferIndex + 1) % bufferSize; + return output; + } + + private: + HeapBlock buffer; + int bufferSize, bufferIndex; + float feedback, last, damp1, damp2; + + JUCE_DECLARE_NON_COPYABLE (CombFilter); + }; + + class AllPassFilter + { + public: + AllPassFilter() noexcept : bufferSize (0), bufferIndex (0) {} + + void setSize (const int size) + { + if (size != bufferSize) + { + bufferIndex = 0; + buffer.malloc (size); + bufferSize = size; + } + + clear(); + } + + void clear() noexcept + { + zeromem (buffer, bufferSize * sizeof (float)); + } + + inline float process (const float input) noexcept + { + const float bufferedValue = buffer [bufferIndex]; + float temp = input + (bufferedValue * 0.5f); + JUCE_UNDENORMALISE (temp); + buffer [bufferIndex] = temp; + bufferIndex = (bufferIndex + 1) % bufferSize; + return bufferedValue - input; + } + + private: + HeapBlock buffer; + int bufferSize, bufferIndex; + + JUCE_DECLARE_NON_COPYABLE (AllPassFilter); + }; + + enum { numCombs = 8, numAllPasses = 4, numChannels = 2 }; + + CombFilter comb [numChannels][numCombs]; + AllPassFilter allPass [numChannels][numAllPasses]; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Reverb); +}; + +#endif // __JUCE_REVERB_JUCEHEADER__ + +/*** End of inlined file: juce_Reverb.h ***/ + +/** + An AudioSource that uses the Reverb class to apply a reverb to another AudioSource. + + @see Reverb +*/ +class JUCE_API ReverbAudioSource : public AudioSource +{ +public: + /** Creates a ReverbAudioSource to process a given input source. + + @param inputSource the input source to read from - this must not be null + @param deleteInputWhenDeleted if true, the input source will be deleted when + this object is deleted + */ + ReverbAudioSource (AudioSource* inputSource, + bool deleteInputWhenDeleted); + + /** Destructor. */ + ~ReverbAudioSource(); + + /** Returns the parameters from the reverb. */ + const Reverb::Parameters& getParameters() const noexcept { return reverb.getParameters(); } + + /** Changes the reverb's parameters. */ + void setParameters (const Reverb::Parameters& newParams); + + void setBypassed (bool isBypassed) noexcept; + bool isBypassed() const noexcept { return bypass; } + + void prepareToPlay (int samplesPerBlockExpected, double sampleRate); + void releaseResources(); + void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); + +private: + + CriticalSection lock; + OptionalScopedPointer input; + Reverb reverb; + volatile bool bypass; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ReverbAudioSource); +}; + +#endif // __JUCE_REVERBAUDIOSOURCE_JUCEHEADER__ + +/*** End of inlined file: juce_ReverbAudioSource.h ***/ + + #endif #ifndef __JUCE_TONEGENERATORAUDIOSOURCE_JUCEHEADER__ @@ -44360,6 +44721,9 @@ private: #endif #ifndef __JUCE_IIRFILTER_JUCEHEADER__ +#endif +#ifndef __JUCE_REVERB_JUCEHEADER__ + #endif #ifndef __JUCE_MIDIBUFFER_JUCEHEADER__ diff --git a/src/audio/audio_sources/juce_AudioFormatReaderSource.cpp b/src/audio/audio_sources/juce_AudioFormatReaderSource.cpp index 7169e1c15d..965facbfab 100644 --- a/src/audio/audio_sources/juce_AudioFormatReaderSource.cpp +++ b/src/audio/audio_sources/juce_AudioFormatReaderSource.cpp @@ -33,29 +33,18 @@ BEGIN_JUCE_NAMESPACE //============================================================================== AudioFormatReaderSource::AudioFormatReaderSource (AudioFormatReader* const reader_, const bool deleteReaderWhenThisIsDeleted) - : reader (reader_), - deleteReader (deleteReaderWhenThisIsDeleted), + : reader (reader_, deleteReaderWhenThisIsDeleted), nextPlayPos (0), looping (false) { jassert (reader != nullptr); } -AudioFormatReaderSource::~AudioFormatReaderSource() -{ - if (deleteReader) - delete reader; -} +AudioFormatReaderSource::~AudioFormatReaderSource() {} -void AudioFormatReaderSource::setNextReadPosition (int64 newPosition) -{ - nextPlayPos = newPosition; -} - -void AudioFormatReaderSource::setLooping (bool shouldLoop) -{ - looping = shouldLoop; -} +int64 AudioFormatReaderSource::getTotalLength() const { return reader->lengthInSamples; } +void AudioFormatReaderSource::setNextReadPosition (int64 newPosition) { nextPlayPos = newPosition; } +void AudioFormatReaderSource::setLooping (bool shouldLoop) { looping = shouldLoop; } int64 AudioFormatReaderSource::getNextReadPosition() const { @@ -63,19 +52,8 @@ int64 AudioFormatReaderSource::getNextReadPosition() const : nextPlayPos; } -int64 AudioFormatReaderSource::getTotalLength() const -{ - return reader->lengthInSamples; -} - -void AudioFormatReaderSource::prepareToPlay (int /*samplesPerBlockExpected*/, - double /*sampleRate*/) -{ -} - -void AudioFormatReaderSource::releaseResources() -{ -} +void AudioFormatReaderSource::prepareToPlay (int /*samplesPerBlockExpected*/, double /*sampleRate*/) {} +void AudioFormatReaderSource::releaseResources() {} void AudioFormatReaderSource::getNextAudioBlock (const AudioSourceChannelInfo& info) { @@ -90,39 +68,26 @@ void AudioFormatReaderSource::getNextAudioBlock (const AudioSourceChannelInfo& i if (newEnd > newStart) { - info.buffer->readFromAudioReader (reader, - info.startSample, - newEnd - newStart, - newStart, - true, true); + info.buffer->readFromAudioReader (reader, info.startSample, + newEnd - newStart, newStart, true, true); } else { const int endSamps = (int) reader->lengthInSamples - newStart; - info.buffer->readFromAudioReader (reader, - info.startSample, - endSamps, - newStart, - true, true); + info.buffer->readFromAudioReader (reader, info.startSample, + endSamps, newStart, true, true); - info.buffer->readFromAudioReader (reader, - info.startSample + endSamps, - newEnd, - 0, - true, true); + info.buffer->readFromAudioReader (reader, info.startSample + endSamps, + newEnd, 0, true, true); } nextPlayPos = newEnd; } else { - info.buffer->readFromAudioReader (reader, - info.startSample, - info.numSamples, - start, - true, true); - + info.buffer->readFromAudioReader (reader, info.startSample, + info.numSamples, start, true, true); nextPlayPos += info.numSamples; } } diff --git a/src/audio/audio_sources/juce_AudioFormatReaderSource.h b/src/audio/audio_sources/juce_AudioFormatReaderSource.h index 91f77c1b6e..2b50c881f3 100644 --- a/src/audio/audio_sources/juce_AudioFormatReaderSource.h +++ b/src/audio/audio_sources/juce_AudioFormatReaderSource.h @@ -30,6 +30,7 @@ #include "../../threads/juce_Thread.h" #include "../audio_file_formats/juce_AudioFormatReader.h" #include "../dsp/juce_AudioSampleBuffer.h" +#include "../../memory/juce_OptionalScopedPointer.h" //============================================================================== @@ -44,7 +45,8 @@ public: //============================================================================== /** Creates an AudioFormatReaderSource for a given reader. - @param sourceReader the reader to use as the data source + @param sourceReader the reader to use as the data source - this must + not be null @param deleteReaderWhenThisIsDeleted if true, the reader passed-in will be deleted when this object is deleted; if false it will be left up to the caller to manage its lifetime @@ -93,8 +95,7 @@ public: private: //============================================================================== - AudioFormatReader* reader; - bool deleteReader; + OptionalScopedPointer reader; int64 volatile nextPlayPos; bool volatile looping; diff --git a/src/audio/audio_sources/juce_BufferingAudioSource.cpp b/src/audio/audio_sources/juce_BufferingAudioSource.cpp index 76c1af69ff..f145521c86 100644 --- a/src/audio/audio_sources/juce_BufferingAudioSource.cpp +++ b/src/audio/audio_sources/juce_BufferingAudioSource.cpp @@ -120,11 +120,10 @@ juce_ImplementSingleton (SharedBufferingAudioSourceThread) //============================================================================== BufferingAudioSource::BufferingAudioSource (PositionableAudioSource* source_, - const bool deleteSourceWhenDeleted_, + const bool deleteSourceWhenDeleted, const int numberOfSamplesToBuffer_, const int numberOfChannels_) - : source (source_), - deleteSourceWhenDeleted (deleteSourceWhenDeleted_), + : source (source_, deleteSourceWhenDeleted), numberOfSamplesToBuffer (jmax (1024, numberOfSamplesToBuffer_)), numberOfChannels (numberOfChannels_), buffer (numberOfChannels_, 0), @@ -145,9 +144,6 @@ BufferingAudioSource::~BufferingAudioSource() if (thread != nullptr) thread->removeSource (this); - - if (deleteSourceWhenDeleted) - delete source; } //============================================================================== diff --git a/src/audio/audio_sources/juce_BufferingAudioSource.h b/src/audio/audio_sources/juce_BufferingAudioSource.h index 61412e7d1a..858efba093 100644 --- a/src/audio/audio_sources/juce_BufferingAudioSource.h +++ b/src/audio/audio_sources/juce_BufferingAudioSource.h @@ -29,6 +29,7 @@ #include "juce_PositionableAudioSource.h" #include "../../threads/juce_Thread.h" #include "../dsp/juce_AudioSampleBuffer.h" +#include "../../memory/juce_OptionalScopedPointer.h" //============================================================================== @@ -90,14 +91,13 @@ public: private: //============================================================================== - PositionableAudioSource* source; - bool deleteSourceWhenDeleted; + OptionalScopedPointer source; int numberOfSamplesToBuffer, numberOfChannels; AudioSampleBuffer buffer; CriticalSection bufferStartPosLock; int64 volatile bufferValidStart, bufferValidEnd, nextPlayPos; - bool wasSourceLooping; double volatile sampleRate; + bool wasSourceLooping; friend class SharedBufferingAudioSourceThread; bool readNextBufferChunk(); diff --git a/src/audio/audio_sources/juce_ChannelRemappingAudioSource.cpp b/src/audio/audio_sources/juce_ChannelRemappingAudioSource.cpp index ed6e810ce6..e7a57c8b0c 100644 --- a/src/audio/audio_sources/juce_ChannelRemappingAudioSource.cpp +++ b/src/audio/audio_sources/juce_ChannelRemappingAudioSource.cpp @@ -32,21 +32,16 @@ BEGIN_JUCE_NAMESPACE //============================================================================== ChannelRemappingAudioSource::ChannelRemappingAudioSource (AudioSource* const source_, - const bool deleteSourceWhenDeleted_) - : requiredNumberOfChannels (2), - source (source_), - deleteSourceWhenDeleted (deleteSourceWhenDeleted_), + const bool deleteSourceWhenDeleted) + : source (source_, deleteSourceWhenDeleted), + requiredNumberOfChannels (2), buffer (2, 16) { remappedInfo.buffer = &buffer; remappedInfo.startSample = 0; } -ChannelRemappingAudioSource::~ChannelRemappingAudioSource() -{ - if (deleteSourceWhenDeleted) - delete source; -} +ChannelRemappingAudioSource::~ChannelRemappingAudioSource() {} //============================================================================== void ChannelRemappingAudioSource::setNumberOfChannelsToProduce (const int requiredNumberOfChannels_) diff --git a/src/audio/audio_sources/juce_ChannelRemappingAudioSource.h b/src/audio/audio_sources/juce_ChannelRemappingAudioSource.h index 60d47caaac..40c68496f0 100644 --- a/src/audio/audio_sources/juce_ChannelRemappingAudioSource.h +++ b/src/audio/audio_sources/juce_ChannelRemappingAudioSource.h @@ -29,6 +29,7 @@ #include "juce_AudioSource.h" #include "../../text/juce_XmlElement.h" #include "../../containers/juce_Array.h" +#include "../../memory/juce_OptionalScopedPointer.h" //============================================================================== @@ -135,11 +136,9 @@ public: private: //============================================================================== - int requiredNumberOfChannels; + OptionalScopedPointer source; Array remappedInputs, remappedOutputs; - - AudioSource* const source; - const bool deleteSourceWhenDeleted; + int requiredNumberOfChannels; AudioSampleBuffer buffer; AudioSourceChannelInfo remappedInfo; diff --git a/src/audio/audio_sources/juce_IIRFilterAudioSource.cpp b/src/audio/audio_sources/juce_IIRFilterAudioSource.cpp index 74af221d52..22a4c19677 100644 --- a/src/audio/audio_sources/juce_IIRFilterAudioSource.cpp +++ b/src/audio/audio_sources/juce_IIRFilterAudioSource.cpp @@ -29,11 +29,11 @@ BEGIN_JUCE_NAMESPACE #include "juce_IIRFilterAudioSource.h" + //============================================================================== IIRFilterAudioSource::IIRFilterAudioSource (AudioSource* const inputSource, - const bool deleteInputWhenDeleted_) - : input (inputSource), - deleteInputWhenDeleted (deleteInputWhenDeleted_) + const bool deleteInputWhenDeleted) + : input (inputSource, deleteInputWhenDeleted) { jassert (inputSource != nullptr); @@ -41,11 +41,7 @@ IIRFilterAudioSource::IIRFilterAudioSource (AudioSource* const inputSource, iirFilters.add (new IIRFilter()); } -IIRFilterAudioSource::~IIRFilterAudioSource() -{ - if (deleteInputWhenDeleted) - delete input; -} +IIRFilterAudioSource::~IIRFilterAudioSource() {} //============================================================================== void IIRFilterAudioSource::setFilterParameters (const IIRFilter& newSettings) diff --git a/src/audio/audio_sources/juce_IIRFilterAudioSource.h b/src/audio/audio_sources/juce_IIRFilterAudioSource.h index 6997e97e96..fa413e5d9b 100644 --- a/src/audio/audio_sources/juce_IIRFilterAudioSource.h +++ b/src/audio/audio_sources/juce_IIRFilterAudioSource.h @@ -29,6 +29,7 @@ #include "juce_AudioSource.h" #include "../dsp/juce_IIRFilter.h" #include "../../containers/juce_OwnedArray.h" +#include "../../memory/juce_OptionalScopedPointer.h" //============================================================================== @@ -41,7 +42,7 @@ public: //============================================================================== /** Creates a IIRFilterAudioSource for a given input source. - @param inputSource the input source to read from + @param inputSource the input source to read from - this must not be null @param deleteInputWhenDeleted if true, the input source will be deleted when this object is deleted */ @@ -52,8 +53,7 @@ public: ~IIRFilterAudioSource(); //============================================================================== - /** Changes the filter to use the same parameters as the one being passed in. - */ + /** Changes the filter to use the same parameters as the one being passed in. */ void setFilterParameters (const IIRFilter& newSettings); //============================================================================== @@ -61,11 +61,9 @@ public: void releaseResources(); void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); - private: //============================================================================== - AudioSource* const input; - const bool deleteInputWhenDeleted; + OptionalScopedPointer input; OwnedArray iirFilters; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (IIRFilterAudioSource); diff --git a/src/audio/audio_sources/juce_ResamplingAudioSource.cpp b/src/audio/audio_sources/juce_ResamplingAudioSource.cpp index 713e3ee210..d4bc89e4ba 100644 --- a/src/audio/audio_sources/juce_ResamplingAudioSource.cpp +++ b/src/audio/audio_sources/juce_ResamplingAudioSource.cpp @@ -32,10 +32,9 @@ BEGIN_JUCE_NAMESPACE //============================================================================== ResamplingAudioSource::ResamplingAudioSource (AudioSource* const inputSource, - const bool deleteInputWhenDeleted_, + const bool deleteInputWhenDeleted, const int numChannels_) - : input (inputSource), - deleteInputWhenDeleted (deleteInputWhenDeleted_), + : input (inputSource, deleteInputWhenDeleted), ratio (1.0), lastRatio (1.0), buffer (numChannels_, 0), @@ -45,11 +44,7 @@ ResamplingAudioSource::ResamplingAudioSource (AudioSource* const inputSource, jassert (input != nullptr); } -ResamplingAudioSource::~ResamplingAudioSource() -{ - if (deleteInputWhenDeleted) - delete input; -} +ResamplingAudioSource::~ResamplingAudioSource() {} void ResamplingAudioSource::setResamplingRatio (const double samplesInPerOutputSample) { diff --git a/src/audio/audio_sources/juce_ResamplingAudioSource.h b/src/audio/audio_sources/juce_ResamplingAudioSource.h index 6e521ed4bb..2d8c1a44d6 100644 --- a/src/audio/audio_sources/juce_ResamplingAudioSource.h +++ b/src/audio/audio_sources/juce_ResamplingAudioSource.h @@ -28,6 +28,7 @@ #include "juce_AudioSource.h" #include "../../threads/juce_SpinLock.h" +#include "../../memory/juce_OptionalScopedPointer.h" //============================================================================== @@ -77,8 +78,7 @@ public: private: //============================================================================== - AudioSource* const input; - const bool deleteInputWhenDeleted; + OptionalScopedPointer input; double ratio, lastRatio; AudioSampleBuffer buffer; int bufferPos, sampsInBuffer; diff --git a/src/audio/audio_sources/juce_ReverbAudioSource.cpp b/src/audio/audio_sources/juce_ReverbAudioSource.cpp new file mode 100644 index 0000000000..ae86e453af --- /dev/null +++ b/src/audio/audio_sources/juce_ReverbAudioSource.cpp @@ -0,0 +1,92 @@ +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-11 by Raw Material Software Ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified under the terms of the GNU General + Public License (Version 2), as published by the Free Software Foundation. + A copy of the license is included in the JUCE distribution, or can be found + online 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.rawmaterialsoftware.com/juce for more information. + + ============================================================================== +*/ + +#include "../../core/juce_StandardHeader.h" + +BEGIN_JUCE_NAMESPACE + +#include "juce_ReverbAudioSource.h" + + +//============================================================================== +ReverbAudioSource::ReverbAudioSource (AudioSource* const inputSource, const bool deleteInputWhenDeleted) + : input (inputSource, deleteInputWhenDeleted), + bypass (false) +{ + jassert (inputSource != nullptr); +} + +ReverbAudioSource::~ReverbAudioSource() {} + +void ReverbAudioSource::prepareToPlay (int samplesPerBlockExpected, double sampleRate) +{ + const ScopedLock sl (lock); + input->prepareToPlay (samplesPerBlockExpected, sampleRate); + reverb.setSampleRate (sampleRate); +} + +void ReverbAudioSource::releaseResources() {} + +void ReverbAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) +{ + const ScopedLock sl (lock); + + input->getNextAudioBlock (bufferToFill); + + if (! bypass) + { + float* const firstChannel = bufferToFill.buffer->getSampleData (0, bufferToFill.startSample); + + if (bufferToFill.buffer->getNumChannels() > 1) + { + reverb.processStereo (firstChannel, + bufferToFill.buffer->getSampleData (1, bufferToFill.startSample), + bufferToFill.numSamples); + } + else + { + reverb.processMono (firstChannel, bufferToFill.numSamples); + } + } +} + +void ReverbAudioSource::setParameters (const Reverb::Parameters& newParams) +{ + const ScopedLock sl (lock); + reverb.setParameters (newParams); +} + +void ReverbAudioSource::setBypassed (bool isBypassed) noexcept +{ + if (bypass != isBypassed) + { + const ScopedLock sl (lock); + bypass = isBypassed; + reverb.reset(); + } +} + + +END_JUCE_NAMESPACE diff --git a/src/audio/audio_sources/juce_ReverbAudioSource.h b/src/audio/audio_sources/juce_ReverbAudioSource.h new file mode 100644 index 0000000000..8fb8ee6c84 --- /dev/null +++ b/src/audio/audio_sources/juce_ReverbAudioSource.h @@ -0,0 +1,82 @@ +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-11 by Raw Material Software Ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified under the terms of the GNU General + Public License (Version 2), as published by the Free Software Foundation. + A copy of the license is included in the JUCE distribution, or can be found + online 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.rawmaterialsoftware.com/juce for more information. + + ============================================================================== +*/ + +#ifndef __JUCE_REVERBAUDIOSOURCE_JUCEHEADER__ +#define __JUCE_REVERBAUDIOSOURCE_JUCEHEADER__ + +#include "juce_AudioSource.h" +#include "../dsp/juce_Reverb.h" +#include "../../threads/juce_CriticalSection.h" +#include "../../memory/juce_OptionalScopedPointer.h" + + +//============================================================================== +/** + An AudioSource that uses the Reverb class to apply a reverb to another AudioSource. + + @see Reverb +*/ +class JUCE_API ReverbAudioSource : public AudioSource +{ +public: + /** Creates a ReverbAudioSource to process a given input source. + + @param inputSource the input source to read from - this must not be null + @param deleteInputWhenDeleted if true, the input source will be deleted when + this object is deleted + */ + ReverbAudioSource (AudioSource* inputSource, + bool deleteInputWhenDeleted); + + /** Destructor. */ + ~ReverbAudioSource(); + + //============================================================================== + /** Returns the parameters from the reverb. */ + const Reverb::Parameters& getParameters() const noexcept { return reverb.getParameters(); } + + /** Changes the reverb's parameters. */ + void setParameters (const Reverb::Parameters& newParams); + + void setBypassed (bool isBypassed) noexcept; + bool isBypassed() const noexcept { return bypass; } + + //============================================================================== + void prepareToPlay (int samplesPerBlockExpected, double sampleRate); + void releaseResources(); + void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); + +private: + //============================================================================== + CriticalSection lock; + OptionalScopedPointer input; + Reverb reverb; + volatile bool bypass; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ReverbAudioSource); +}; + + +#endif // __JUCE_REVERBAUDIOSOURCE_JUCEHEADER__ diff --git a/src/audio/dsp/juce_Reverb.h b/src/audio/dsp/juce_Reverb.h new file mode 100644 index 0000000000..21bd531b7b --- /dev/null +++ b/src/audio/dsp/juce_Reverb.h @@ -0,0 +1,325 @@ +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-11 by Raw Material Software Ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified under the terms of the GNU General + Public License (Version 2), as published by the Free Software Foundation. + A copy of the license is included in the JUCE distribution, or can be found + online 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.rawmaterialsoftware.com/juce for more information. + + ============================================================================== +*/ + +#ifndef __JUCE_REVERB_JUCEHEADER__ +#define __JUCE_REVERB_JUCEHEADER__ + + +//============================================================================== +/** + Performs a simple reverb effect on a stream of audio data. + + This is a simple stereo reverb, based on the technique and tunings used in FreeVerb. + Use setSampleRate() to prepare it, and then call processStereo() or processMono() to + apply the reverb to your audio data. + + @see ReverbAudioSource +*/ +class Reverb +{ +public: + //============================================================================== + Reverb() + { + setParameters (Parameters()); + setSampleRate (44100.0); + } + + //============================================================================== + /** Holds the parameters being used by a Reverb object. */ + struct Parameters + { + Parameters() noexcept + : roomSize (0.5f), + damping (0.5f), + wetLevel (0.33f), + dryLevel (0.4f), + width (1.0f), + freezeMode (0) + {} + + float roomSize; /**< Room size, 0 to 1.0, where 1.0 is big, 0 is small. */ + float damping; /**< Damping, 0 to 1.0, where 0 is not damped, 1.0 is fully damped. */ + float wetLevel; /**< Wet level, 0 to 1.0 */ + float dryLevel; /**< Dry level, 0 to 1.0 */ + float width; /**< Reverb width, 0 to 1.0, where 1.0 is very wide. */ + float freezeMode; /**< Freeze mode - values < 0.5 are "normal" mode, values > 0.5 + put the reverb into a continuous feedback loop. */ + }; + + //============================================================================== + /** Returns the reverb's current parameters. */ + const Parameters& getParameters() const noexcept { return parameters; } + + /** Applies a new set of parameters to the reverb. + Note that this doesn't attempt to lock the reverb, so if you call this in parallel with + the process method, you may get artifacts. + */ + void setParameters (const Parameters& newParams) + { + const float wetScaleFactor = 3.0f; + 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; + gain = isFrozen (newParams.freezeMode) ? 0.0f : 0.015f; + parameters = newParams; + shouldUpdateDamping = true; + } + + //============================================================================== + /** Sets the sample rate that will be used for the reverb. + You must call this before the process methods, in order to tell it the correct sample rate. + */ + void setSampleRate (const double sampleRate) + { + jassert (sampleRate > 0); + + static const short combTunings[] = { 1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617 }; // (at 44100Hz) + static const short allPassTunings[] = { 556, 441, 341, 225 }; + const int stereoSpread = 23; + const int intSampleRate = (int) sampleRate; + + int i; + for (i = 0; i < numCombs; ++i) + { + comb[0][i].setSize ((intSampleRate * combTunings[i]) / 44100); + comb[1][i].setSize ((intSampleRate * (combTunings[i] + stereoSpread)) / 44100); + } + + for (i = 0; i < numAllPasses; ++i) + { + allPass[0][i].setSize ((intSampleRate * allPassTunings[i]) / 44100); + allPass[1][i].setSize ((intSampleRate * (allPassTunings[i] + stereoSpread)) / 44100); + } + + shouldUpdateDamping = true; + } + + /** Clears the reverb's buffers. */ + void reset() + { + for (int j = 0; j < numChannels; ++j) + { + int i; + for (i = 0; i < numCombs; ++i) + comb[j][i].clear(); + + for (i = 0; i < numAllPasses; ++i) + allPass[j][i].clear(); + } + } + + //============================================================================== + /** Applies the reverb to two stereo channels of audio data. */ + void processStereo (float* const left, float* const right, const int numSamples) noexcept + { + 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; + + int j; + for (j = 0; j < numCombs; ++j) // accumulate the comb filters in parallel + { + outL += comb[0][j].process (input); + outR += comb[1][j].process (input); + } + + for (j = 0; j < numAllPasses; ++j) // run the allpass filters in series + { + outL = allPass[0][j].process (outL); + outR = allPass[1][j].process (outR); + } + + left[i] = outL * wet1 + outR * wet2 + left[i] * dry; + right[i] = outR * wet1 + outL * wet2 + right[i] * dry; + } + } + + /** Applies the reverb to a single mono channel of audio data. */ + void processMono (float* const samples, const int numSamples) noexcept + { + jassert (samples != nullptr); + + if (shouldUpdateDamping) + updateDamping(); + + for (int i = 0; i < numSamples; ++i) + { + const float input = samples[i] * gain; + float output = 0; + + int j; + for (j = 0; j < numCombs; ++j) // accumulate the comb filters in parallel + output += comb[0][j].process (input); + + for (j = 0; j < numAllPasses; ++j) // run the allpass filters in series + output = allPass[0][j].process (output); + + samples[i] = output * wet1 + input * dry; + } + } + +private: + //============================================================================== + Parameters parameters; + + volatile bool shouldUpdateDamping; + float gain, wet1, wet2, dry; + + inline static bool isFrozen (const float freezeMode) noexcept { return freezeMode >= 0.5f; } + + void updateDamping() noexcept + { + const float roomScaleFactor = 0.28f; + const float roomOffset = 0.7f; + const float dampScaleFactor = 0.4f; + + shouldUpdateDamping = false; + + if (isFrozen (parameters.freezeMode)) + setDamping (1.0f, 0.0f); + else + setDamping (parameters.damping * dampScaleFactor, + parameters.roomSize * roomScaleFactor + roomOffset); + } + + 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); + } + + //============================================================================== + class CombFilter + { + public: + CombFilter() noexcept : bufferSize (0), bufferIndex (0) {} + + void setSize (const int size) + { + if (size != bufferSize) + { + bufferIndex = 0; + buffer.malloc (size); + bufferSize = size; + } + + clear(); + } + + void clear() noexcept + { + last = 0; + zeromem (buffer, bufferSize * sizeof (float)); + } + + void setFeedbackAndDamp (const float f, const float d) noexcept + { + damp1 = d; + damp2 = 1.0f - d; + feedback = f; + } + + inline float process (const float input) noexcept + { + const float output = buffer [bufferIndex]; + last = (output * damp2) + (last * damp1); + JUCE_UNDENORMALISE (last); + + float temp = input + (last * feedback); + JUCE_UNDENORMALISE (temp); + buffer [bufferIndex] = temp; + bufferIndex = (bufferIndex + 1) % bufferSize; + return output; + } + + private: + HeapBlock buffer; + int bufferSize, bufferIndex; + float feedback, last, damp1, damp2; + + JUCE_DECLARE_NON_COPYABLE (CombFilter); + }; + + //============================================================================== + class AllPassFilter + { + public: + AllPassFilter() noexcept : bufferSize (0), bufferIndex (0) {} + + void setSize (const int size) + { + if (size != bufferSize) + { + bufferIndex = 0; + buffer.malloc (size); + bufferSize = size; + } + + clear(); + } + + void clear() noexcept + { + zeromem (buffer, bufferSize * sizeof (float)); + } + + inline float process (const float input) noexcept + { + const float bufferedValue = buffer [bufferIndex]; + float temp = input + (bufferedValue * 0.5f); + JUCE_UNDENORMALISE (temp); + buffer [bufferIndex] = temp; + bufferIndex = (bufferIndex + 1) % bufferSize; + return bufferedValue - input; + } + + private: + HeapBlock buffer; + int bufferSize, bufferIndex; + + JUCE_DECLARE_NON_COPYABLE (AllPassFilter); + }; + + enum { numCombs = 8, numAllPasses = 4, numChannels = 2 }; + + CombFilter comb [numChannels][numCombs]; + AllPassFilter allPass [numChannels][numAllPasses]; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Reverb); +}; + + +#endif // __JUCE_REVERB_JUCEHEADER__ diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h index 172ff38b26..26e295c0cb 100644 --- a/src/core/juce_StandardHeader.h +++ b/src/core/juce_StandardHeader.h @@ -33,7 +33,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 53 -#define JUCE_BUILDNUMBER 91 +#define JUCE_BUILDNUMBER 92 /** Current Juce version number. diff --git a/src/gui/components/juce_Component.cpp b/src/gui/components/juce_Component.cpp index 5f92921e94..fcc32d7ed3 100644 --- a/src/gui/components/juce_Component.cpp +++ b/src/gui/components/juce_Component.cpp @@ -1823,7 +1823,7 @@ void Component::paintComponent (Graphics& g) paint (imG); } - g.setColour (Colours::black.withAlpha (getAlpha())); + g.setColour (Colours::black); g.drawImageAt (bufferedImage, 0, 0); } else @@ -1914,9 +1914,9 @@ void Component::paintEntireComponent (Graphics& g, const bool ignoreAlphaLevel) { jassert (! g.isClipEmpty()); - #if JUCE_DEBUG + #if JUCE_DEBUG flags.isInsidePaintCall = true; - #endif + #endif if (effect != nullptr) { @@ -1943,9 +1943,9 @@ void Component::paintEntireComponent (Graphics& g, const bool ignoreAlphaLevel) paintComponentAndChildren (g); } - #if JUCE_DEBUG + #if JUCE_DEBUG flags.isInsidePaintCall = false; - #endif + #endif } void Component::setPaintingIsUnclipped (const bool shouldPaintWithoutClipping) noexcept diff --git a/src/gui/graphics/contexts/juce_Graphics.h b/src/gui/graphics/contexts/juce_Graphics.h index 23e2a38395..03c8c63fa2 100644 --- a/src/gui/graphics/contexts/juce_Graphics.h +++ b/src/gui/graphics/contexts/juce_Graphics.h @@ -392,6 +392,8 @@ public: The x position is an integer, but the top and bottom of the line can be sub-pixel positions, and these will be anti-aliased if necessary. + + The bottom parameter must be greater than or equal to the top parameter. */ void drawVerticalLine (int x, float top, float bottom) const; @@ -399,6 +401,8 @@ public: The y position is an integer, but the left and right ends of the line can be sub-pixel positions, and these will be anti-aliased if necessary. + + The right parameter must be greater than or equal to the left parameter. */ void drawHorizontalLine (int y, float left, float right) const; diff --git a/src/gui/graphics/imaging/juce_ImageFileFormat.cpp b/src/gui/graphics/imaging/juce_ImageFileFormat.cpp index 792f65429a..602c3d38af 100644 --- a/src/gui/graphics/imaging/juce_ImageFileFormat.cpp +++ b/src/gui/graphics/imaging/juce_ImageFileFormat.cpp @@ -32,24 +32,25 @@ BEGIN_JUCE_NAMESPACE #include "../../../io/files/juce_FileInputStream.h" #include "../../../io/streams/juce_BufferedInputStream.h" - //============================================================================== +struct DefaultImageFormats +{ + PNGImageFormat png; + JPEGImageFormat jpg; + GIFImageFormat gif; +}; + +static DefaultImageFormats defaultImageFormats; + ImageFileFormat* ImageFileFormat::findImageFormatForStream (InputStream& input) { - static PNGImageFormat png; - static JPEGImageFormat jpg; - static GIFImageFormat gif; - - ImageFileFormat* formats[4]; - int numFormats = 0; - - formats [numFormats++] = &png; - formats [numFormats++] = &jpg; - formats [numFormats++] = &gif; + ImageFileFormat* formats[] = { &defaultImageFormats.png, + &defaultImageFormats.jpg, + &defaultImageFormats.gif }; const int64 streamPos = input.getPosition(); - for (int i = 0; i < numFormats; ++i) + for (int i = 0; i < numElementsInArray (formats); ++i) { const bool found = formats[i]->canUnderstand (input); input.setPosition (streamPos); diff --git a/src/io/streams/juce_MemoryInputStream.cpp b/src/io/streams/juce_MemoryInputStream.cpp index f2d088845c..7a50d03c1b 100644 --- a/src/io/streams/juce_MemoryInputStream.cpp +++ b/src/io/streams/juce_MemoryInputStream.cpp @@ -39,10 +39,7 @@ MemoryInputStream::MemoryInputStream (const void* const sourceData, position (0) { if (keepInternalCopy) - { - internalCopy.append (data, sourceDataSize); - data = static_cast (internalCopy.getData()); - } + createInternalCopy(); } MemoryInputStream::MemoryInputStream (const MemoryBlock& sourceData, @@ -52,10 +49,14 @@ MemoryInputStream::MemoryInputStream (const MemoryBlock& sourceData, position (0) { if (keepInternalCopy) - { - internalCopy = sourceData; - data = static_cast (internalCopy.getData()); - } + createInternalCopy(); +} + +void MemoryInputStream::createInternalCopy() +{ + internalCopy.malloc (dataSize); + memcpy (internalCopy, data, dataSize); + data = internalCopy; } MemoryInputStream::~MemoryInputStream() @@ -71,6 +72,9 @@ int MemoryInputStream::read (void* const buffer, const int howMany) { jassert (howMany >= 0); const int num = jmin (howMany, (int) (dataSize - position)); + if (num <= 0) + return 0; + memcpy (buffer, data + position, num); position += num; return (int) num; @@ -78,7 +82,7 @@ int MemoryInputStream::read (void* const buffer, const int howMany) bool MemoryInputStream::isExhausted() { - return (position >= dataSize); + return position >= dataSize; } bool MemoryInputStream::setPosition (const int64 pos) @@ -93,6 +97,7 @@ int64 MemoryInputStream::getPosition() } +//============================================================================== #if JUCE_UNIT_TESTS #include "../../utilities/juce_UnitTest.h" diff --git a/src/io/streams/juce_MemoryInputStream.h b/src/io/streams/juce_MemoryInputStream.h index 45ee4eb084..4fd3fdeb81 100644 --- a/src/io/streams/juce_MemoryInputStream.h +++ b/src/io/streams/juce_MemoryInputStream.h @@ -80,7 +80,9 @@ private: //============================================================================== const char* data; size_t dataSize, position; - MemoryBlock internalCopy; + HeapBlock internalCopy; + + void createInternalCopy(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryInputStream); }; diff --git a/src/juce_app_includes.h b/src/juce_app_includes.h index 2a1a46fed4..3c2a8dc9b0 100644 --- a/src/juce_app_includes.h +++ b/src/juce_app_includes.h @@ -116,6 +116,9 @@ #ifndef __JUCE_RESAMPLINGAUDIOSOURCE_JUCEHEADER__ #include "audio/audio_sources/juce_ResamplingAudioSource.h" #endif +#ifndef __JUCE_REVERBAUDIOSOURCE_JUCEHEADER__ + #include "audio/audio_sources/juce_ReverbAudioSource.h" +#endif #ifndef __JUCE_TONEGENERATORAUDIOSOURCE_JUCEHEADER__ #include "audio/audio_sources/juce_ToneGeneratorAudioSource.h" #endif @@ -140,6 +143,9 @@ #ifndef __JUCE_IIRFILTER_JUCEHEADER__ #include "audio/dsp/juce_IIRFilter.h" #endif +#ifndef __JUCE_REVERB_JUCEHEADER__ + #include "audio/dsp/juce_Reverb.h" +#endif #ifndef __JUCE_MIDIBUFFER_JUCEHEADER__ #include "audio/midi/juce_MidiBuffer.h" #endif diff --git a/src/maths/juce_MathsFunctions.h b/src/maths/juce_MathsFunctions.h index 1abbd9ee81..2c982b26ce 100644 --- a/src/maths/juce_MathsFunctions.h +++ b/src/maths/juce_MathsFunctions.h @@ -416,6 +416,17 @@ inline int roundFloatToInt (const float value) noexcept return roundToInt (value); } +//============================================================================== +#if (JUCE_INTEL && JUCE_32BIT) || defined (DOXYGEN) + /** This macro can be applied to a float variable to check whether it contains a denormalised + value, and to normalise it if necessary. + On CPUs that aren't vulnerable to denormalisation problems, this will have no effect. + */ + #define JUCE_UNDENORMALISE(x) x += 1.0f; x -= 1.0f; +#else + #define JUCE_UNDENORMALISE(x) +#endif + //============================================================================== /** This namespace contains a few template classes for helping work out class type variations. */ diff --git a/src/native/mac/juce_mac_FileChooser.mm b/src/native/mac/juce_mac_FileChooser.mm index 7cb8db8e25..6d5f65709b 100644 --- a/src/native/mac/juce_mac_FileChooser.mm +++ b/src/native/mac/juce_mac_FileChooser.mm @@ -73,7 +73,7 @@ using namespace JUCE_NAMESPACE; if (f.getFileName().matchesWildcard ((*filters)[i], true)) return true; - return f.isDirectory(); + return f.isDirectory() && ! [[NSWorkspace sharedWorkspace] isFilePackageAtPath: filename]; } @end diff --git a/src/native/mac/juce_mac_Fonts.mm b/src/native/mac/juce_mac_Fonts.mm index c2cc00b5e1..d6681bbb9c 100644 --- a/src/native/mac/juce_mac_Fonts.mm +++ b/src/native/mac/juce_mac_Fonts.mm @@ -217,6 +217,9 @@ public: jassert (path.isEmpty()); // we might need to apply a transform to the path, so this must be empty CGPathRef pathRef = CTFontCreatePathForGlyph (ctFontRef, (CGGlyph) glyphNumber, &renderingTransform); + if (pathRef == 0) + return false; + CGPathApply (pathRef, &path, pathApplier); CFRelease (pathRef);