From 346c3de2064140a7b526d4a14f46e13e5f873e62 Mon Sep 17 00:00:00 2001 From: jules Date: Fri, 4 Jan 2008 15:31:47 +0000 Subject: [PATCH] --- build/linux/JUCE.make | 60 +- build/macosx/Juce.xcodeproj/project.pbxproj | 234 +- .../platform_specific_code/juce_mac_Files.cpp | 3 +- .../build/linux/JuceAudioPluginHost.make | 42 - .../mac/PluginHost.xcodeproj/project.pbxproj | 94 +- extras/audio plugin host/src/HostStartup.cpp | 2 +- .../formats/juce_AudioUnitPluginFormat.cpp | 2576 +++---- .../plugins/formats/juce_VSTPluginFormat.cpp | 6034 ++++++++--------- .../audio/plugins/juce_AudioPluginFormat.cpp | 2 +- 9 files changed, 4539 insertions(+), 4508 deletions(-) diff --git a/build/linux/JUCE.make b/build/linux/JUCE.make index 072bb72a63..e478299d94 100644 --- a/build/linux/JUCE.make +++ b/build/linux/JUCE.make @@ -112,6 +112,15 @@ OBJECTS := \ $(OBJDIR)/juce_AudioProcessorGraph.o \ $(OBJDIR)/juce_AudioProcessorPlayer.o \ $(OBJDIR)/juce_GenericAudioProcessorEditor.o \ + $(OBJDIR)/juce_AudioPluginFormat.o \ + $(OBJDIR)/juce_AudioPluginFormatManager.o \ + $(OBJDIR)/juce_AudioPluginInstance.o \ + $(OBJDIR)/juce_KnownPluginList.o \ + $(OBJDIR)/juce_PluginDescription.o \ + $(OBJDIR)/juce_PluginDirectoryScanner.o \ + $(OBJDIR)/juce_PluginListComponent.o \ + $(OBJDIR)/juce_AudioUnitPluginFormat.o \ + $(OBJDIR)/juce_VSTPluginFormat.o \ $(OBJDIR)/juce_AiffAudioFormat.o \ $(OBJDIR)/juce_AudioCDReader.o \ $(OBJDIR)/juce_AudioFormat.o \ @@ -120,7 +129,6 @@ OBJECTS := \ $(OBJDIR)/juce_FlacAudioFormat.o \ $(OBJDIR)/juce_OggVorbisAudioFormat.o \ $(OBJDIR)/juce_WavAudioFormat.o \ - $(OBJDIR)/bitbuffer.o \ $(OBJDIR)/bitmath.o \ $(OBJDIR)/bitreader.o \ $(OBJDIR)/bitwriter.o \ @@ -820,6 +828,51 @@ $(OBJDIR)/juce_GenericAudioProcessorEditor.o: ../../src/juce_appframework/audio/ @echo $(notdir $<) @$(CXX) $(CXXFLAGS) -o $@ -c $< +$(OBJDIR)/juce_AudioPluginFormat.o: ../../src/juce_appframework/audio/plugins/juce_AudioPluginFormat.cpp + -@$(CMD_MKOBJDIR) + @echo $(notdir $<) + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +$(OBJDIR)/juce_AudioPluginFormatManager.o: ../../src/juce_appframework/audio/plugins/juce_AudioPluginFormatManager.cpp + -@$(CMD_MKOBJDIR) + @echo $(notdir $<) + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +$(OBJDIR)/juce_AudioPluginInstance.o: ../../src/juce_appframework/audio/plugins/juce_AudioPluginInstance.cpp + -@$(CMD_MKOBJDIR) + @echo $(notdir $<) + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +$(OBJDIR)/juce_KnownPluginList.o: ../../src/juce_appframework/audio/plugins/juce_KnownPluginList.cpp + -@$(CMD_MKOBJDIR) + @echo $(notdir $<) + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +$(OBJDIR)/juce_PluginDescription.o: ../../src/juce_appframework/audio/plugins/juce_PluginDescription.cpp + -@$(CMD_MKOBJDIR) + @echo $(notdir $<) + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +$(OBJDIR)/juce_PluginDirectoryScanner.o: ../../src/juce_appframework/audio/plugins/juce_PluginDirectoryScanner.cpp + -@$(CMD_MKOBJDIR) + @echo $(notdir $<) + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +$(OBJDIR)/juce_PluginListComponent.o: ../../src/juce_appframework/audio/plugins/juce_PluginListComponent.cpp + -@$(CMD_MKOBJDIR) + @echo $(notdir $<) + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +$(OBJDIR)/juce_AudioUnitPluginFormat.o: ../../src/juce_appframework/audio/plugins/formats/juce_AudioUnitPluginFormat.cpp + -@$(CMD_MKOBJDIR) + @echo $(notdir $<) + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +$(OBJDIR)/juce_VSTPluginFormat.o: ../../src/juce_appframework/audio/plugins/formats/juce_VSTPluginFormat.cpp + -@$(CMD_MKOBJDIR) + @echo $(notdir $<) + @$(CXX) $(CXXFLAGS) -o $@ -c $< + $(OBJDIR)/juce_AiffAudioFormat.o: ../../src/juce_appframework/audio/audio_file_formats/juce_AiffAudioFormat.cpp -@$(CMD_MKOBJDIR) @echo $(notdir $<) @@ -860,11 +913,6 @@ $(OBJDIR)/juce_WavAudioFormat.o: ../../src/juce_appframework/audio/audio_file_fo @echo $(notdir $<) @$(CXX) $(CXXFLAGS) -o $@ -c $< -$(OBJDIR)/bitbuffer.o: ../../src/juce_appframework/audio/audio_file_formats/flac/libFLAC/bitbuffer.c - -@$(CMD_MKOBJDIR) - @echo $(notdir $<) - @$(CC) $(CFLAGS) -o $@ -c $< - $(OBJDIR)/bitmath.o: ../../src/juce_appframework/audio/audio_file_formats/flac/libFLAC/bitmath.c -@$(CMD_MKOBJDIR) @echo $(notdir $<) diff --git a/build/macosx/Juce.xcodeproj/project.pbxproj b/build/macosx/Juce.xcodeproj/project.pbxproj index 9c0613314c..af61264a43 100644 --- a/build/macosx/Juce.xcodeproj/project.pbxproj +++ b/build/macosx/Juce.xcodeproj/project.pbxproj @@ -20,22 +20,6 @@ 84099CA10AE52BD000B2A05D /* juce_Synthesiser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84099C9D0AE52BD000B2A05D /* juce_Synthesiser.cpp */; }; 84099CA20AE52BD000B2A05D /* juce_Synthesiser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84099C9E0AE52BD000B2A05D /* juce_Synthesiser.h */; }; 840F80BC092B399D005E7B4E /* juce.h in Headers */ = {isa = PBXBuildFile; fileRef = 840F80BB092B399D005E7B4E /* juce.h */; }; - 8416EB750D1999620094A433 /* bitbuffer.c in Sources */ = {isa = PBXBuildFile; fileRef = 8416EB650D1999610094A433 /* bitbuffer.c */; }; - 8416EB760D1999620094A433 /* bitmath.c in Sources */ = {isa = PBXBuildFile; fileRef = 8416EB660D1999610094A433 /* bitmath.c */; }; - 8416EB770D1999620094A433 /* bitreader.c in Sources */ = {isa = PBXBuildFile; fileRef = 8416EB670D1999610094A433 /* bitreader.c */; }; - 8416EB780D1999620094A433 /* bitwriter.c in Sources */ = {isa = PBXBuildFile; fileRef = 8416EB680D1999610094A433 /* bitwriter.c */; }; - 8416EB790D1999620094A433 /* cpu.c in Sources */ = {isa = PBXBuildFile; fileRef = 8416EB690D1999610094A433 /* cpu.c */; }; - 8416EB7A0D1999620094A433 /* crc.c in Sources */ = {isa = PBXBuildFile; fileRef = 8416EB6A0D1999610094A433 /* crc.c */; }; - 8416EB7B0D1999620094A433 /* fixed.c in Sources */ = {isa = PBXBuildFile; fileRef = 8416EB6B0D1999610094A433 /* fixed.c */; }; - 8416EB7C0D1999620094A433 /* float.c in Sources */ = {isa = PBXBuildFile; fileRef = 8416EB6C0D1999610094A433 /* float.c */; }; - 8416EB7D0D1999620094A433 /* format.c in Sources */ = {isa = PBXBuildFile; fileRef = 8416EB6D0D1999610094A433 /* format.c */; }; - 8416EB7E0D1999620094A433 /* lpc_flac.c in Sources */ = {isa = PBXBuildFile; fileRef = 8416EB6E0D1999610094A433 /* lpc_flac.c */; }; - 8416EB7F0D1999620094A433 /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 8416EB6F0D1999620094A433 /* md5.c */; }; - 8416EB800D1999620094A433 /* memory.c in Sources */ = {isa = PBXBuildFile; fileRef = 8416EB700D1999620094A433 /* memory.c */; }; - 8416EB810D1999620094A433 /* stream_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 8416EB710D1999620094A433 /* stream_decoder.c */; }; - 8416EB820D1999620094A433 /* stream_encoder_framing.c in Sources */ = {isa = PBXBuildFile; fileRef = 8416EB720D1999620094A433 /* stream_encoder_framing.c */; }; - 8416EB830D1999620094A433 /* stream_encoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 8416EB730D1999620094A433 /* stream_encoder.c */; }; - 8416EB840D1999620094A433 /* window_flac.c in Sources */ = {isa = PBXBuildFile; fileRef = 8416EB740D1999620094A433 /* window_flac.c */; }; 8417EE530A6E7A280058E04E /* juce_TableHeaderComponent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8417EE4F0A6E7A270058E04E /* juce_TableHeaderComponent.cpp */; }; 8417EE540A6E7A280058E04E /* juce_TableHeaderComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 8417EE500A6E7A270058E04E /* juce_TableHeaderComponent.h */; }; 8417EE550A6E7A280058E04E /* juce_TableListBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8417EE510A6E7A280058E04E /* juce_TableListBox.cpp */; }; @@ -49,6 +33,42 @@ 84198B14096D8E2B0022A439 /* juce_MidiOutput.h in Headers */ = {isa = PBXBuildFile; fileRef = 84198B0E096D8E2B0022A439 /* juce_MidiOutput.h */; }; 84198BB5096EB9E40022A439 /* juce_AudioDeviceSelectorComponent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84198BB3096EB9E40022A439 /* juce_AudioDeviceSelectorComponent.cpp */; }; 84198BB6096EB9E40022A439 /* juce_AudioDeviceSelectorComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 84198BB4096EB9E40022A439 /* juce_AudioDeviceSelectorComponent.h */; }; + 841B22B60D2E7F04009D01AA /* bitmath.c in Sources */ = {isa = PBXBuildFile; fileRef = 841B22A60D2E7F04009D01AA /* bitmath.c */; }; + 841B22B70D2E7F04009D01AA /* bitreader.c in Sources */ = {isa = PBXBuildFile; fileRef = 841B22A70D2E7F04009D01AA /* bitreader.c */; }; + 841B22B80D2E7F04009D01AA /* bitwriter.c in Sources */ = {isa = PBXBuildFile; fileRef = 841B22A80D2E7F04009D01AA /* bitwriter.c */; }; + 841B22B90D2E7F04009D01AA /* cpu.c in Sources */ = {isa = PBXBuildFile; fileRef = 841B22A90D2E7F04009D01AA /* cpu.c */; }; + 841B22BA0D2E7F04009D01AA /* crc.c in Sources */ = {isa = PBXBuildFile; fileRef = 841B22AA0D2E7F04009D01AA /* crc.c */; }; + 841B22BB0D2E7F04009D01AA /* fixed.c in Sources */ = {isa = PBXBuildFile; fileRef = 841B22AB0D2E7F04009D01AA /* fixed.c */; }; + 841B22BC0D2E7F04009D01AA /* float.c in Sources */ = {isa = PBXBuildFile; fileRef = 841B22AC0D2E7F04009D01AA /* float.c */; }; + 841B22BD0D2E7F04009D01AA /* format.c in Sources */ = {isa = PBXBuildFile; fileRef = 841B22AD0D2E7F04009D01AA /* format.c */; }; + 841B22BE0D2E7F04009D01AA /* juce_FlacHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 841B22AE0D2E7F04009D01AA /* juce_FlacHeader.h */; }; + 841B22BF0D2E7F04009D01AA /* lpc_flac.c in Sources */ = {isa = PBXBuildFile; fileRef = 841B22AF0D2E7F04009D01AA /* lpc_flac.c */; }; + 841B22C00D2E7F04009D01AA /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 841B22B00D2E7F04009D01AA /* md5.c */; }; + 841B22C10D2E7F04009D01AA /* memory.c in Sources */ = {isa = PBXBuildFile; fileRef = 841B22B10D2E7F04009D01AA /* memory.c */; }; + 841B22C20D2E7F04009D01AA /* stream_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 841B22B20D2E7F04009D01AA /* stream_decoder.c */; }; + 841B22C30D2E7F04009D01AA /* stream_encoder_framing.c in Sources */ = {isa = PBXBuildFile; fileRef = 841B22B30D2E7F04009D01AA /* stream_encoder_framing.c */; }; + 841B22C40D2E7F04009D01AA /* stream_encoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 841B22B40D2E7F04009D01AA /* stream_encoder.c */; }; + 841B22C50D2E7F04009D01AA /* window_flac.c in Sources */ = {isa = PBXBuildFile; fileRef = 841B22B50D2E7F04009D01AA /* window_flac.c */; }; + 841B22E20D2E7FE3009D01AA /* juce_AudioUnitPluginFormat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 841B22CE0D2E7FE3009D01AA /* juce_AudioUnitPluginFormat.cpp */; }; + 841B22E30D2E7FE3009D01AA /* juce_AudioUnitPluginFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 841B22CF0D2E7FE3009D01AA /* juce_AudioUnitPluginFormat.h */; }; + 841B22E40D2E7FE3009D01AA /* juce_DirectXPluginFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 841B22D00D2E7FE3009D01AA /* juce_DirectXPluginFormat.h */; }; + 841B22E50D2E7FE3009D01AA /* juce_LADSPAPluginFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 841B22D10D2E7FE3009D01AA /* juce_LADSPAPluginFormat.h */; }; + 841B22E60D2E7FE3009D01AA /* juce_VSTPluginFormat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 841B22D20D2E7FE3009D01AA /* juce_VSTPluginFormat.cpp */; }; + 841B22E70D2E7FE3009D01AA /* juce_VSTPluginFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 841B22D30D2E7FE3009D01AA /* juce_VSTPluginFormat.h */; }; + 841B22E80D2E7FE3009D01AA /* juce_AudioPluginFormat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 841B22D40D2E7FE3009D01AA /* juce_AudioPluginFormat.cpp */; }; + 841B22E90D2E7FE3009D01AA /* juce_AudioPluginFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 841B22D50D2E7FE3009D01AA /* juce_AudioPluginFormat.h */; }; + 841B22EA0D2E7FE3009D01AA /* juce_AudioPluginFormatManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 841B22D60D2E7FE3009D01AA /* juce_AudioPluginFormatManager.cpp */; }; + 841B22EB0D2E7FE3009D01AA /* juce_AudioPluginFormatManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 841B22D70D2E7FE3009D01AA /* juce_AudioPluginFormatManager.h */; }; + 841B22EC0D2E7FE3009D01AA /* juce_AudioPluginInstance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 841B22D80D2E7FE3009D01AA /* juce_AudioPluginInstance.cpp */; }; + 841B22ED0D2E7FE3009D01AA /* juce_AudioPluginInstance.h in Headers */ = {isa = PBXBuildFile; fileRef = 841B22D90D2E7FE3009D01AA /* juce_AudioPluginInstance.h */; }; + 841B22EE0D2E7FE3009D01AA /* juce_KnownPluginList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 841B22DA0D2E7FE3009D01AA /* juce_KnownPluginList.cpp */; }; + 841B22EF0D2E7FE3009D01AA /* juce_KnownPluginList.h in Headers */ = {isa = PBXBuildFile; fileRef = 841B22DB0D2E7FE3009D01AA /* juce_KnownPluginList.h */; }; + 841B22F00D2E7FE3009D01AA /* juce_PluginDescription.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 841B22DC0D2E7FE3009D01AA /* juce_PluginDescription.cpp */; }; + 841B22F10D2E7FE3009D01AA /* juce_PluginDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = 841B22DD0D2E7FE3009D01AA /* juce_PluginDescription.h */; }; + 841B22F20D2E7FE3009D01AA /* juce_PluginDirectoryScanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 841B22DE0D2E7FE3009D01AA /* juce_PluginDirectoryScanner.cpp */; }; + 841B22F30D2E7FE3009D01AA /* juce_PluginDirectoryScanner.h in Headers */ = {isa = PBXBuildFile; fileRef = 841B22DF0D2E7FE3009D01AA /* juce_PluginDirectoryScanner.h */; }; + 841B22F40D2E7FE3009D01AA /* juce_PluginListComponent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 841B22E00D2E7FE3009D01AA /* juce_PluginListComponent.cpp */; }; + 841B22F50D2E7FE3009D01AA /* juce_PluginListComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 841B22E10D2E7FE3009D01AA /* juce_PluginListComponent.h */; }; 841E06350AF8CE74005E6FCC /* juce_AudioDataConverters.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 841E062F0AF8CE74005E6FCC /* juce_AudioDataConverters.cpp */; }; 841E06360AF8CE75005E6FCC /* juce_AudioDataConverters.h in Headers */ = {isa = PBXBuildFile; fileRef = 841E06300AF8CE74005E6FCC /* juce_AudioDataConverters.h */; }; 841E06370AF8CE75005E6FCC /* juce_AudioSampleBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 841E06310AF8CE74005E6FCC /* juce_AudioSampleBuffer.cpp */; }; @@ -674,22 +694,6 @@ 84099C9D0AE52BD000B2A05D /* juce_Synthesiser.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = juce_Synthesiser.cpp; sourceTree = ""; }; 84099C9E0AE52BD000B2A05D /* juce_Synthesiser.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_Synthesiser.h; sourceTree = ""; }; 840F80BB092B399D005E7B4E /* juce.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = juce.h; path = ../../juce.h; sourceTree = SOURCE_ROOT; }; - 8416EB650D1999610094A433 /* bitbuffer.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = bitbuffer.c; path = flac/libFLAC/bitbuffer.c; sourceTree = ""; }; - 8416EB660D1999610094A433 /* bitmath.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = bitmath.c; path = flac/libFLAC/bitmath.c; sourceTree = ""; }; - 8416EB670D1999610094A433 /* bitreader.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = bitreader.c; path = flac/libFLAC/bitreader.c; sourceTree = ""; }; - 8416EB680D1999610094A433 /* bitwriter.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = bitwriter.c; path = flac/libFLAC/bitwriter.c; sourceTree = ""; }; - 8416EB690D1999610094A433 /* cpu.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = cpu.c; path = flac/libFLAC/cpu.c; sourceTree = ""; }; - 8416EB6A0D1999610094A433 /* crc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = crc.c; path = flac/libFLAC/crc.c; sourceTree = ""; }; - 8416EB6B0D1999610094A433 /* fixed.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = fixed.c; path = flac/libFLAC/fixed.c; sourceTree = ""; }; - 8416EB6C0D1999610094A433 /* float.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = float.c; path = flac/libFLAC/float.c; sourceTree = ""; }; - 8416EB6D0D1999610094A433 /* format.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = format.c; path = flac/libFLAC/format.c; sourceTree = ""; }; - 8416EB6E0D1999610094A433 /* lpc_flac.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = lpc_flac.c; path = flac/libFLAC/lpc_flac.c; sourceTree = ""; }; - 8416EB6F0D1999620094A433 /* md5.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = md5.c; path = flac/libFLAC/md5.c; sourceTree = ""; }; - 8416EB700D1999620094A433 /* memory.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = memory.c; path = flac/libFLAC/memory.c; sourceTree = ""; }; - 8416EB710D1999620094A433 /* stream_decoder.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = stream_decoder.c; path = flac/libFLAC/stream_decoder.c; sourceTree = ""; }; - 8416EB720D1999620094A433 /* stream_encoder_framing.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = stream_encoder_framing.c; path = flac/libFLAC/stream_encoder_framing.c; sourceTree = ""; }; - 8416EB730D1999620094A433 /* stream_encoder.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = stream_encoder.c; path = flac/libFLAC/stream_encoder.c; sourceTree = ""; }; - 8416EB740D1999620094A433 /* window_flac.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = window_flac.c; path = flac/libFLAC/window_flac.c; sourceTree = ""; }; 8417EE4F0A6E7A270058E04E /* juce_TableHeaderComponent.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = juce_TableHeaderComponent.cpp; sourceTree = ""; }; 8417EE500A6E7A270058E04E /* juce_TableHeaderComponent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_TableHeaderComponent.h; sourceTree = ""; }; 8417EE510A6E7A280058E04E /* juce_TableListBox.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = juce_TableListBox.cpp; sourceTree = ""; }; @@ -703,6 +707,42 @@ 84198B0E096D8E2B0022A439 /* juce_MidiOutput.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_MidiOutput.h; sourceTree = ""; }; 84198BB3096EB9E40022A439 /* juce_AudioDeviceSelectorComponent.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = juce_AudioDeviceSelectorComponent.cpp; sourceTree = ""; }; 84198BB4096EB9E40022A439 /* juce_AudioDeviceSelectorComponent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_AudioDeviceSelectorComponent.h; sourceTree = ""; }; + 841B22A60D2E7F04009D01AA /* bitmath.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = bitmath.c; path = flac/libFLAC/bitmath.c; sourceTree = ""; }; + 841B22A70D2E7F04009D01AA /* bitreader.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = bitreader.c; path = flac/libFLAC/bitreader.c; sourceTree = ""; }; + 841B22A80D2E7F04009D01AA /* bitwriter.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = bitwriter.c; path = flac/libFLAC/bitwriter.c; sourceTree = ""; }; + 841B22A90D2E7F04009D01AA /* cpu.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = cpu.c; path = flac/libFLAC/cpu.c; sourceTree = ""; }; + 841B22AA0D2E7F04009D01AA /* crc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = crc.c; path = flac/libFLAC/crc.c; sourceTree = ""; }; + 841B22AB0D2E7F04009D01AA /* fixed.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = fixed.c; path = flac/libFLAC/fixed.c; sourceTree = ""; }; + 841B22AC0D2E7F04009D01AA /* float.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = float.c; path = flac/libFLAC/float.c; sourceTree = ""; }; + 841B22AD0D2E7F04009D01AA /* format.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = format.c; path = flac/libFLAC/format.c; sourceTree = ""; }; + 841B22AE0D2E7F04009D01AA /* juce_FlacHeader.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = juce_FlacHeader.h; path = flac/libFLAC/juce_FlacHeader.h; sourceTree = ""; }; + 841B22AF0D2E7F04009D01AA /* lpc_flac.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = lpc_flac.c; path = flac/libFLAC/lpc_flac.c; sourceTree = ""; }; + 841B22B00D2E7F04009D01AA /* md5.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = md5.c; path = flac/libFLAC/md5.c; sourceTree = ""; }; + 841B22B10D2E7F04009D01AA /* memory.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = memory.c; path = flac/libFLAC/memory.c; sourceTree = ""; }; + 841B22B20D2E7F04009D01AA /* stream_decoder.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = stream_decoder.c; path = flac/libFLAC/stream_decoder.c; sourceTree = ""; }; + 841B22B30D2E7F04009D01AA /* stream_encoder_framing.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = stream_encoder_framing.c; path = flac/libFLAC/stream_encoder_framing.c; sourceTree = ""; }; + 841B22B40D2E7F04009D01AA /* stream_encoder.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = stream_encoder.c; path = flac/libFLAC/stream_encoder.c; sourceTree = ""; }; + 841B22B50D2E7F04009D01AA /* window_flac.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = window_flac.c; path = flac/libFLAC/window_flac.c; sourceTree = ""; }; + 841B22CE0D2E7FE3009D01AA /* juce_AudioUnitPluginFormat.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = juce_AudioUnitPluginFormat.cpp; sourceTree = ""; }; + 841B22CF0D2E7FE3009D01AA /* juce_AudioUnitPluginFormat.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_AudioUnitPluginFormat.h; sourceTree = ""; }; + 841B22D00D2E7FE3009D01AA /* juce_DirectXPluginFormat.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_DirectXPluginFormat.h; sourceTree = ""; }; + 841B22D10D2E7FE3009D01AA /* juce_LADSPAPluginFormat.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_LADSPAPluginFormat.h; sourceTree = ""; }; + 841B22D20D2E7FE3009D01AA /* juce_VSTPluginFormat.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = juce_VSTPluginFormat.cpp; sourceTree = ""; }; + 841B22D30D2E7FE3009D01AA /* juce_VSTPluginFormat.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_VSTPluginFormat.h; sourceTree = ""; }; + 841B22D40D2E7FE3009D01AA /* juce_AudioPluginFormat.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = juce_AudioPluginFormat.cpp; sourceTree = ""; }; + 841B22D50D2E7FE3009D01AA /* juce_AudioPluginFormat.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_AudioPluginFormat.h; sourceTree = ""; }; + 841B22D60D2E7FE3009D01AA /* juce_AudioPluginFormatManager.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = juce_AudioPluginFormatManager.cpp; sourceTree = ""; }; + 841B22D70D2E7FE3009D01AA /* juce_AudioPluginFormatManager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_AudioPluginFormatManager.h; sourceTree = ""; }; + 841B22D80D2E7FE3009D01AA /* juce_AudioPluginInstance.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = juce_AudioPluginInstance.cpp; sourceTree = ""; }; + 841B22D90D2E7FE3009D01AA /* juce_AudioPluginInstance.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_AudioPluginInstance.h; sourceTree = ""; }; + 841B22DA0D2E7FE3009D01AA /* juce_KnownPluginList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = juce_KnownPluginList.cpp; sourceTree = ""; }; + 841B22DB0D2E7FE3009D01AA /* juce_KnownPluginList.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_KnownPluginList.h; sourceTree = ""; }; + 841B22DC0D2E7FE3009D01AA /* juce_PluginDescription.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = juce_PluginDescription.cpp; sourceTree = ""; }; + 841B22DD0D2E7FE3009D01AA /* juce_PluginDescription.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_PluginDescription.h; sourceTree = ""; }; + 841B22DE0D2E7FE3009D01AA /* juce_PluginDirectoryScanner.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = juce_PluginDirectoryScanner.cpp; sourceTree = ""; }; + 841B22DF0D2E7FE3009D01AA /* juce_PluginDirectoryScanner.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_PluginDirectoryScanner.h; sourceTree = ""; }; + 841B22E00D2E7FE3009D01AA /* juce_PluginListComponent.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = juce_PluginListComponent.cpp; sourceTree = ""; }; + 841B22E10D2E7FE3009D01AA /* juce_PluginListComponent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_PluginListComponent.h; sourceTree = ""; }; 841E062F0AF8CE74005E6FCC /* juce_AudioDataConverters.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = juce_AudioDataConverters.cpp; sourceTree = ""; }; 841E06300AF8CE74005E6FCC /* juce_AudioDataConverters.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_AudioDataConverters.h; sourceTree = ""; }; 841E06310AF8CE74005E6FCC /* juce_AudioSampleBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = juce_AudioSampleBuffer.cpp; sourceTree = ""; }; @@ -1315,7 +1355,7 @@ 84FED3C80CAA96DA00003997 /* juce_FileDragAndDropTarget.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_FileDragAndDropTarget.h; sourceTree = ""; }; 84FFAF290C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = juce_FileSearchPathListComponent.cpp; path = filebrowser/juce_FileSearchPathListComponent.cpp; sourceTree = ""; }; 84FFAF2A0C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = juce_FileSearchPathListComponent.h; path = filebrowser/juce_FileSearchPathListComponent.h; sourceTree = ""; }; - D2AAC046055464E500DB518D /* libjuce.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjuce.a; sourceTree = BUILT_PRODUCTS_DIR; }; + D2AAC046055464E500DB518D /* libjucedebug.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjucedebug.a; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1355,7 +1395,7 @@ 1AB674ADFE9D54B511CA2CBB /* Products */ = { isa = PBXGroup; children = ( - D2AAC046055464E500DB518D /* libjuce.a */, + D2AAC046055464E500DB518D /* libjucedebug.a */, ); name = Products; sourceTree = ""; @@ -1387,6 +1427,41 @@ path = devices; sourceTree = ""; }; + 841B22CC0D2E7FE3009D01AA /* plugins */ = { + isa = PBXGroup; + children = ( + 841B22CD0D2E7FE3009D01AA /* formats */, + 841B22D40D2E7FE3009D01AA /* juce_AudioPluginFormat.cpp */, + 841B22D50D2E7FE3009D01AA /* juce_AudioPluginFormat.h */, + 841B22D60D2E7FE3009D01AA /* juce_AudioPluginFormatManager.cpp */, + 841B22D70D2E7FE3009D01AA /* juce_AudioPluginFormatManager.h */, + 841B22D80D2E7FE3009D01AA /* juce_AudioPluginInstance.cpp */, + 841B22D90D2E7FE3009D01AA /* juce_AudioPluginInstance.h */, + 841B22DA0D2E7FE3009D01AA /* juce_KnownPluginList.cpp */, + 841B22DB0D2E7FE3009D01AA /* juce_KnownPluginList.h */, + 841B22DC0D2E7FE3009D01AA /* juce_PluginDescription.cpp */, + 841B22DD0D2E7FE3009D01AA /* juce_PluginDescription.h */, + 841B22DE0D2E7FE3009D01AA /* juce_PluginDirectoryScanner.cpp */, + 841B22DF0D2E7FE3009D01AA /* juce_PluginDirectoryScanner.h */, + 841B22E00D2E7FE3009D01AA /* juce_PluginListComponent.cpp */, + 841B22E10D2E7FE3009D01AA /* juce_PluginListComponent.h */, + ); + path = plugins; + sourceTree = ""; + }; + 841B22CD0D2E7FE3009D01AA /* formats */ = { + isa = PBXGroup; + children = ( + 841B22CE0D2E7FE3009D01AA /* juce_AudioUnitPluginFormat.cpp */, + 841B22CF0D2E7FE3009D01AA /* juce_AudioUnitPluginFormat.h */, + 841B22D00D2E7FE3009D01AA /* juce_DirectXPluginFormat.h */, + 841B22D10D2E7FE3009D01AA /* juce_LADSPAPluginFormat.h */, + 841B22D20D2E7FE3009D01AA /* juce_VSTPluginFormat.cpp */, + 841B22D30D2E7FE3009D01AA /* juce_VSTPluginFormat.h */, + ); + path = formats; + sourceTree = ""; + }; 841E062E0AF8CE74005E6FCC /* dsp */ = { isa = PBXGroup; children = ( @@ -1499,11 +1574,12 @@ 84A4883B08A22E4900752A2B /* audio */ = { isa = PBXGroup; children = ( - 84BC4E200C8DD38C00FA249B /* processors */, 84A4883C08A22E4900752A2B /* audio_file_formats */, 84A4884908A22E4900752A2B /* audio_sources */, 84198B08096D8E2B0022A439 /* devices */, 841E062E0AF8CE74005E6FCC /* dsp */, + 841B22CC0D2E7FE3009D01AA /* plugins */, + 84BC4E200C8DD38C00FA249B /* processors */, 8463D5B4098BD2CD00F9AEC2 /* midi */, 84099C9A0AE52BD000B2A05D /* synthesisers */, ); @@ -2368,22 +2444,22 @@ 84F690DC0B3444A500ABAE1C /* flac */ = { isa = PBXGroup; children = ( - 8416EB650D1999610094A433 /* bitbuffer.c */, - 8416EB660D1999610094A433 /* bitmath.c */, - 8416EB670D1999610094A433 /* bitreader.c */, - 8416EB680D1999610094A433 /* bitwriter.c */, - 8416EB690D1999610094A433 /* cpu.c */, - 8416EB6A0D1999610094A433 /* crc.c */, - 8416EB6B0D1999610094A433 /* fixed.c */, - 8416EB6C0D1999610094A433 /* float.c */, - 8416EB6D0D1999610094A433 /* format.c */, - 8416EB6E0D1999610094A433 /* lpc_flac.c */, - 8416EB6F0D1999620094A433 /* md5.c */, - 8416EB700D1999620094A433 /* memory.c */, - 8416EB710D1999620094A433 /* stream_decoder.c */, - 8416EB720D1999620094A433 /* stream_encoder_framing.c */, - 8416EB730D1999620094A433 /* stream_encoder.c */, - 8416EB740D1999620094A433 /* window_flac.c */, + 841B22A60D2E7F04009D01AA /* bitmath.c */, + 841B22A70D2E7F04009D01AA /* bitreader.c */, + 841B22A80D2E7F04009D01AA /* bitwriter.c */, + 841B22A90D2E7F04009D01AA /* cpu.c */, + 841B22AA0D2E7F04009D01AA /* crc.c */, + 841B22AB0D2E7F04009D01AA /* fixed.c */, + 841B22AC0D2E7F04009D01AA /* float.c */, + 841B22AD0D2E7F04009D01AA /* format.c */, + 841B22AE0D2E7F04009D01AA /* juce_FlacHeader.h */, + 841B22AF0D2E7F04009D01AA /* lpc_flac.c */, + 841B22B00D2E7F04009D01AA /* md5.c */, + 841B22B10D2E7F04009D01AA /* memory.c */, + 841B22B20D2E7F04009D01AA /* stream_decoder.c */, + 841B22B30D2E7F04009D01AA /* stream_encoder_framing.c */, + 841B22B40D2E7F04009D01AA /* stream_encoder.c */, + 841B22B50D2E7F04009D01AA /* window_flac.c */, ); name = flac; sourceTree = ""; @@ -2773,6 +2849,18 @@ 84BC4E2E0C8DD38C00FA249B /* juce_AudioProcessorListener.h in Headers */, 84BC4E300C8DD38C00FA249B /* juce_GenericAudioProcessorEditor.h in Headers */, 84FED3C90CAA96DA00003997 /* juce_FileDragAndDropTarget.h in Headers */, + 841B22BE0D2E7F04009D01AA /* juce_FlacHeader.h in Headers */, + 841B22E30D2E7FE3009D01AA /* juce_AudioUnitPluginFormat.h in Headers */, + 841B22E40D2E7FE3009D01AA /* juce_DirectXPluginFormat.h in Headers */, + 841B22E50D2E7FE3009D01AA /* juce_LADSPAPluginFormat.h in Headers */, + 841B22E70D2E7FE3009D01AA /* juce_VSTPluginFormat.h in Headers */, + 841B22E90D2E7FE3009D01AA /* juce_AudioPluginFormat.h in Headers */, + 841B22EB0D2E7FE3009D01AA /* juce_AudioPluginFormatManager.h in Headers */, + 841B22ED0D2E7FE3009D01AA /* juce_AudioPluginInstance.h in Headers */, + 841B22EF0D2E7FE3009D01AA /* juce_KnownPluginList.h in Headers */, + 841B22F10D2E7FE3009D01AA /* juce_PluginDescription.h in Headers */, + 841B22F30D2E7FE3009D01AA /* juce_PluginDirectoryScanner.h in Headers */, + 841B22F50D2E7FE3009D01AA /* juce_PluginListComponent.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2793,7 +2881,7 @@ ); name = Juce; productName = Juce; - productReference = D2AAC046055464E500DB518D /* libjuce.a */; + productReference = D2AAC046055464E500DB518D /* libjucedebug.a */; productType = "com.apple.product-type.library.static"; }; /* End PBXNativeTarget section */ @@ -3158,22 +3246,30 @@ 84BC4E2A0C8DD38C00FA249B /* juce_AudioProcessor.cpp in Sources */, 84BC4E2C0C8DD38C00FA249B /* juce_AudioProcessorEditor.cpp in Sources */, 84BC4E2F0C8DD38C00FA249B /* juce_GenericAudioProcessorEditor.cpp in Sources */, - 8416EB750D1999620094A433 /* bitbuffer.c in Sources */, - 8416EB760D1999620094A433 /* bitmath.c in Sources */, - 8416EB770D1999620094A433 /* bitreader.c in Sources */, - 8416EB780D1999620094A433 /* bitwriter.c in Sources */, - 8416EB790D1999620094A433 /* cpu.c in Sources */, - 8416EB7A0D1999620094A433 /* crc.c in Sources */, - 8416EB7B0D1999620094A433 /* fixed.c in Sources */, - 8416EB7C0D1999620094A433 /* float.c in Sources */, - 8416EB7D0D1999620094A433 /* format.c in Sources */, - 8416EB7E0D1999620094A433 /* lpc_flac.c in Sources */, - 8416EB7F0D1999620094A433 /* md5.c in Sources */, - 8416EB800D1999620094A433 /* memory.c in Sources */, - 8416EB810D1999620094A433 /* stream_decoder.c in Sources */, - 8416EB820D1999620094A433 /* stream_encoder_framing.c in Sources */, - 8416EB830D1999620094A433 /* stream_encoder.c in Sources */, - 8416EB840D1999620094A433 /* window_flac.c in Sources */, + 841B22B60D2E7F04009D01AA /* bitmath.c in Sources */, + 841B22B70D2E7F04009D01AA /* bitreader.c in Sources */, + 841B22B80D2E7F04009D01AA /* bitwriter.c in Sources */, + 841B22B90D2E7F04009D01AA /* cpu.c in Sources */, + 841B22BA0D2E7F04009D01AA /* crc.c in Sources */, + 841B22BB0D2E7F04009D01AA /* fixed.c in Sources */, + 841B22BC0D2E7F04009D01AA /* float.c in Sources */, + 841B22BD0D2E7F04009D01AA /* format.c in Sources */, + 841B22BF0D2E7F04009D01AA /* lpc_flac.c in Sources */, + 841B22C00D2E7F04009D01AA /* md5.c in Sources */, + 841B22C10D2E7F04009D01AA /* memory.c in Sources */, + 841B22C20D2E7F04009D01AA /* stream_decoder.c in Sources */, + 841B22C30D2E7F04009D01AA /* stream_encoder_framing.c in Sources */, + 841B22C40D2E7F04009D01AA /* stream_encoder.c in Sources */, + 841B22C50D2E7F04009D01AA /* window_flac.c in Sources */, + 841B22E20D2E7FE3009D01AA /* juce_AudioUnitPluginFormat.cpp in Sources */, + 841B22E60D2E7FE3009D01AA /* juce_VSTPluginFormat.cpp in Sources */, + 841B22E80D2E7FE3009D01AA /* juce_AudioPluginFormat.cpp in Sources */, + 841B22EA0D2E7FE3009D01AA /* juce_AudioPluginFormatManager.cpp in Sources */, + 841B22EC0D2E7FE3009D01AA /* juce_AudioPluginInstance.cpp in Sources */, + 841B22EE0D2E7FE3009D01AA /* juce_KnownPluginList.cpp in Sources */, + 841B22F00D2E7FE3009D01AA /* juce_PluginDescription.cpp in Sources */, + 841B22F20D2E7FE3009D01AA /* juce_PluginDirectoryScanner.cpp in Sources */, + 841B22F40D2E7FE3009D01AA /* juce_PluginListComponent.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3212,6 +3308,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; PRODUCT_NAME = jucedebug; SYMROOT = ../../bin; + USER_HEADER_SEARCH_PATHS = "~/stuff/vstsdk2.4 $(inherited)"; }; name = Debug; }; @@ -3233,6 +3330,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; PRODUCT_NAME = juce; SYMROOT = ../../bin; + USER_HEADER_SEARCH_PATHS = "~/stuff/vstsdk2.4 $(inherited)"; }; name = Release; }; diff --git a/build/macosx/platform_specific_code/juce_mac_Files.cpp b/build/macosx/platform_specific_code/juce_mac_Files.cpp index f82085223d..f85737b7b4 100644 --- a/build/macosx/platform_specific_code/juce_mac_Files.cpp +++ b/build/macosx/platform_specific_code/juce_mac_Files.cpp @@ -877,7 +877,8 @@ bool juce_launchFile (const String& fileName, if (fileName.startsWithIgnoreCase (T("http:")) || fileName.startsWithIgnoreCase (T("https:")) - || fileName.startsWithIgnoreCase (T("ftp:"))) + || fileName.startsWithIgnoreCase (T("ftp:")) + || fileName.startsWithIgnoreCase (T("file:"))) { CFStringRef urlString = PlatformUtilities::juceStringToCFString (fileName); diff --git a/extras/audio plugin host/build/linux/JuceAudioPluginHost.make b/extras/audio plugin host/build/linux/JuceAudioPluginHost.make index c329d65916..25431d5c27 100644 --- a/extras/audio plugin host/build/linux/JuceAudioPluginHost.make +++ b/extras/audio plugin host/build/linux/JuceAudioPluginHost.make @@ -41,13 +41,6 @@ OBJECTS := \ $(OBJDIR)/GraphEditorPanel.o \ $(OBJDIR)/InternalFilters.o \ $(OBJDIR)/MainHostWindow.o \ - $(OBJDIR)/juce_AudioPluginFormat.o \ - $(OBJDIR)/juce_AudioPluginInstance.o \ - $(OBJDIR)/juce_KnownPluginList.o \ - $(OBJDIR)/juce_PluginDescription.o \ - $(OBJDIR)/juce_PluginDirectoryScanner.o \ - $(OBJDIR)/juce_PluginListComponent.o \ - $(OBJDIR)/juce_VSTPluginInstance.o \ MKDIR_TYPE := msdos CMD := $(subst \,\\,$(ComSpec)$(COMSPEC)) @@ -113,40 +106,5 @@ $(OBJDIR)/MainHostWindow.o: ../../src/host/MainHostWindow.cpp @echo $(notdir $<) @$(CXX) $(CXXFLAGS) -o $@ -c $< -$(OBJDIR)/juce_AudioPluginFormat.o: ../../src/plugins/juce_AudioPluginFormat.cpp - -@$(CMD_MKOBJDIR) - @echo $(notdir $<) - @$(CXX) $(CXXFLAGS) -o $@ -c $< - -$(OBJDIR)/juce_AudioPluginInstance.o: ../../src/plugins/juce_AudioPluginInstance.cpp - -@$(CMD_MKOBJDIR) - @echo $(notdir $<) - @$(CXX) $(CXXFLAGS) -o $@ -c $< - -$(OBJDIR)/juce_KnownPluginList.o: ../../src/plugins/juce_KnownPluginList.cpp - -@$(CMD_MKOBJDIR) - @echo $(notdir $<) - @$(CXX) $(CXXFLAGS) -o $@ -c $< - -$(OBJDIR)/juce_PluginDescription.o: ../../src/plugins/juce_PluginDescription.cpp - -@$(CMD_MKOBJDIR) - @echo $(notdir $<) - @$(CXX) $(CXXFLAGS) -o $@ -c $< - -$(OBJDIR)/juce_PluginDirectoryScanner.o: ../../src/plugins/juce_PluginDirectoryScanner.cpp - -@$(CMD_MKOBJDIR) - @echo $(notdir $<) - @$(CXX) $(CXXFLAGS) -o $@ -c $< - -$(OBJDIR)/juce_PluginListComponent.o: ../../src/plugins/juce_PluginListComponent.cpp - -@$(CMD_MKOBJDIR) - @echo $(notdir $<) - @$(CXX) $(CXXFLAGS) -o $@ -c $< - -$(OBJDIR)/juce_VSTPluginInstance.o: ../../src/plugins/vst/juce_VSTPluginInstance.cpp - -@$(CMD_MKOBJDIR) - @echo $(notdir $<) - @$(CXX) $(CXXFLAGS) -o $@ -c $< - -include $(OBJECTS:%.o=%.d) diff --git a/extras/audio plugin host/build/mac/PluginHost.xcodeproj/project.pbxproj b/extras/audio plugin host/build/mac/PluginHost.xcodeproj/project.pbxproj index b8de43b74e..b0f390f380 100644 --- a/extras/audio plugin host/build/mac/PluginHost.xcodeproj/project.pbxproj +++ b/extras/audio plugin host/build/mac/PluginHost.xcodeproj/project.pbxproj @@ -7,8 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 840A4D4A0CD774A000445927 /* juce_AudioUnitPluginFormat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 840A4D460CD774A000445927 /* juce_AudioUnitPluginFormat.cpp */; }; - 840A4D4B0CD774A000445927 /* juce_VSTPluginFormat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 840A4D480CD774A000445927 /* juce_VSTPluginFormat.cpp */; }; 8411682E0CBBEE0500232E45 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8411682D0CBBEE0500232E45 /* OpenGL.framework */; }; 84CF14390CD6367800A8D756 /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84CF14380CD6367800A8D756 /* AudioUnit.framework */; }; 84FC4CD90CD8894600850651 /* juce.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 84FC4CD80CD8894600850651 /* juce.xcconfig */; }; @@ -17,12 +15,6 @@ 84FFAEAE0C6C8A6F009F6E72 /* InternalFilters.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84FFAE960C6C8A6F009F6E72 /* InternalFilters.cpp */; }; 84FFAEAF0C6C8A6F009F6E72 /* MainHostWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84FFAE980C6C8A6F009F6E72 /* MainHostWindow.cpp */; }; 84FFAEB00C6C8A6F009F6E72 /* HostStartup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84FFAE9A0C6C8A6F009F6E72 /* HostStartup.cpp */; }; - 84FFAEB10C6C8A6F009F6E72 /* juce_AudioPluginFormat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84FFAE9C0C6C8A6F009F6E72 /* juce_AudioPluginFormat.cpp */; }; - 84FFAEB20C6C8A6F009F6E72 /* juce_AudioPluginInstance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84FFAE9E0C6C8A6F009F6E72 /* juce_AudioPluginInstance.cpp */; }; - 84FFAEB30C6C8A6F009F6E72 /* juce_KnownPluginList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84FFAEA00C6C8A6F009F6E72 /* juce_KnownPluginList.cpp */; }; - 84FFAEB40C6C8A6F009F6E72 /* juce_PluginDescription.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84FFAEA20C6C8A6F009F6E72 /* juce_PluginDescription.cpp */; }; - 84FFAEB50C6C8A6F009F6E72 /* juce_PluginDirectoryScanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84FFAEA40C6C8A6F009F6E72 /* juce_PluginDirectoryScanner.cpp */; }; - 84FFAEB60C6C8A6F009F6E72 /* juce_PluginListComponent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84FFAEA60C6C8A6F009F6E72 /* juce_PluginListComponent.cpp */; }; 84FFAEFE0C6C8E80009F6E72 /* libjucedebug.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 84FFAEFC0C6C8E76009F6E72 /* libjucedebug.a */; }; 84FFAF040C6C8ED5009F6E72 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84FFAEFF0C6C8ED5009F6E72 /* CoreAudio.framework */; }; 84FFAF050C6C8ED5009F6E72 /* CoreMIDI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84FFAF000C6C8ED5009F6E72 /* CoreMIDI.framework */; }; @@ -46,11 +38,7 @@ 20286C33FDCF999611CA2CEA /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = ""; }; 4A9504C8FFE6A3BC11CA0CBA /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = /System/Library/Frameworks/ApplicationServices.framework; sourceTree = ""; }; 4A9504CAFFE6A41611CA0CBA /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = /System/Library/Frameworks/CoreServices.framework; sourceTree = ""; }; - 508344B209E5C41E0093A071 /* Juce Plugin Host.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Juce Plugin Host.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 840A4D460CD774A000445927 /* juce_AudioUnitPluginFormat.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioUnitPluginFormat.cpp; path = formats/juce_AudioUnitPluginFormat.cpp; sourceTree = ""; }; - 840A4D470CD774A000445927 /* juce_AudioUnitPluginFormat.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = juce_AudioUnitPluginFormat.h; path = formats/juce_AudioUnitPluginFormat.h; sourceTree = ""; }; - 840A4D480CD774A000445927 /* juce_VSTPluginFormat.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = juce_VSTPluginFormat.cpp; path = formats/juce_VSTPluginFormat.cpp; sourceTree = ""; }; - 840A4D490CD774A000445927 /* juce_VSTPluginFormat.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = juce_VSTPluginFormat.h; path = formats/juce_VSTPluginFormat.h; sourceTree = ""; }; + 508344B209E5C41E0093A071 /* Juce Plugin Host.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = "Juce Plugin Host.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 8411682D0CBBEE0500232E45 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = ""; }; 84CF14380CD6367800A8D756 /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = /System/Library/Frameworks/AudioUnit.framework; sourceTree = ""; }; 84FC4CD80CD8894600850651 /* juce.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; name = juce.xcconfig; path = ../../../../build/macosx/juce.xcconfig; sourceTree = SOURCE_ROOT; }; @@ -63,18 +51,6 @@ 84FFAE980C6C8A6F009F6E72 /* MainHostWindow.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = MainHostWindow.cpp; path = ../../src/host/MainHostWindow.cpp; sourceTree = SOURCE_ROOT; }; 84FFAE990C6C8A6F009F6E72 /* MainHostWindow.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = MainHostWindow.h; path = ../../src/host/MainHostWindow.h; sourceTree = SOURCE_ROOT; }; 84FFAE9A0C6C8A6F009F6E72 /* HostStartup.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = HostStartup.cpp; path = ../../src/HostStartup.cpp; sourceTree = SOURCE_ROOT; }; - 84FFAE9C0C6C8A6F009F6E72 /* juce_AudioPluginFormat.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioPluginFormat.cpp; path = ../../src/plugins/juce_AudioPluginFormat.cpp; sourceTree = SOURCE_ROOT; }; - 84FFAE9D0C6C8A6F009F6E72 /* juce_AudioPluginFormat.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = juce_AudioPluginFormat.h; path = ../../src/plugins/juce_AudioPluginFormat.h; sourceTree = SOURCE_ROOT; }; - 84FFAE9E0C6C8A6F009F6E72 /* juce_AudioPluginInstance.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioPluginInstance.cpp; path = ../../src/plugins/juce_AudioPluginInstance.cpp; sourceTree = SOURCE_ROOT; }; - 84FFAE9F0C6C8A6F009F6E72 /* juce_AudioPluginInstance.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = juce_AudioPluginInstance.h; path = ../../src/plugins/juce_AudioPluginInstance.h; sourceTree = SOURCE_ROOT; }; - 84FFAEA00C6C8A6F009F6E72 /* juce_KnownPluginList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = juce_KnownPluginList.cpp; path = ../../src/plugins/juce_KnownPluginList.cpp; sourceTree = SOURCE_ROOT; }; - 84FFAEA10C6C8A6F009F6E72 /* juce_KnownPluginList.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = juce_KnownPluginList.h; path = ../../src/plugins/juce_KnownPluginList.h; sourceTree = SOURCE_ROOT; }; - 84FFAEA20C6C8A6F009F6E72 /* juce_PluginDescription.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = juce_PluginDescription.cpp; path = ../../src/plugins/juce_PluginDescription.cpp; sourceTree = SOURCE_ROOT; }; - 84FFAEA30C6C8A6F009F6E72 /* juce_PluginDescription.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = juce_PluginDescription.h; path = ../../src/plugins/juce_PluginDescription.h; sourceTree = SOURCE_ROOT; }; - 84FFAEA40C6C8A6F009F6E72 /* juce_PluginDirectoryScanner.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = juce_PluginDirectoryScanner.cpp; path = ../../src/plugins/juce_PluginDirectoryScanner.cpp; sourceTree = SOURCE_ROOT; }; - 84FFAEA50C6C8A6F009F6E72 /* juce_PluginDirectoryScanner.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = juce_PluginDirectoryScanner.h; path = ../../src/plugins/juce_PluginDirectoryScanner.h; sourceTree = SOURCE_ROOT; }; - 84FFAEA60C6C8A6F009F6E72 /* juce_PluginListComponent.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = juce_PluginListComponent.cpp; path = ../../src/plugins/juce_PluginListComponent.cpp; sourceTree = SOURCE_ROOT; }; - 84FFAEA70C6C8A6F009F6E72 /* juce_PluginListComponent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = juce_PluginListComponent.h; path = ../../src/plugins/juce_PluginListComponent.h; sourceTree = SOURCE_ROOT; }; 84FFAEF70C6C8E76009F6E72 /* Juce.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Juce.xcodeproj; path = ../../../../build/macosx/Juce.xcodeproj; sourceTree = SOURCE_ROOT; }; 84FFAEFF0C6C8ED5009F6E72 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = /System/Library/Frameworks/CoreAudio.framework; sourceTree = ""; }; 84FFAF000C6C8ED5009F6E72 /* CoreMIDI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMIDI.framework; path = /System/Library/Frameworks/CoreMIDI.framework; sourceTree = ""; }; @@ -126,10 +102,16 @@ 20286C2AFDCF999611CA2CEA /* Sources */ = { isa = PBXGroup; children = ( - 84FC4CD80CD8894600850651 /* juce.xcconfig */, - 84FFAE910C6C8A6F009F6E72 /* host */, - 84FFAE9B0C6C8A6F009F6E72 /* plugins */, + 84FFAE920C6C8A6F009F6E72 /* FilterGraph.cpp */, + 84FFAE930C6C8A6F009F6E72 /* FilterGraph.h */, + 84FFAE940C6C8A6F009F6E72 /* GraphEditorPanel.cpp */, + 84FFAE950C6C8A6F009F6E72 /* GraphEditorPanel.h */, + 84FFAE960C6C8A6F009F6E72 /* InternalFilters.cpp */, + 84FFAE970C6C8A6F009F6E72 /* InternalFilters.h */, + 84FFAE980C6C8A6F009F6E72 /* MainHostWindow.cpp */, + 84FFAE990C6C8A6F009F6E72 /* MainHostWindow.h */, 84FFAE9A0C6C8A6F009F6E72 /* HostStartup.cpp */, + 84FC4CD80CD8894600850651 /* juce.xcconfig */, ); name = Sources; sourceTree = ""; @@ -160,54 +142,6 @@ name = "External Frameworks and Libraries"; sourceTree = ""; }; - 840A4D420CD7747400445927 /* formats */ = { - isa = PBXGroup; - children = ( - 840A4D460CD774A000445927 /* juce_AudioUnitPluginFormat.cpp */, - 840A4D470CD774A000445927 /* juce_AudioUnitPluginFormat.h */, - 840A4D480CD774A000445927 /* juce_VSTPluginFormat.cpp */, - 840A4D490CD774A000445927 /* juce_VSTPluginFormat.h */, - ); - name = formats; - sourceTree = ""; - }; - 84FFAE910C6C8A6F009F6E72 /* host */ = { - isa = PBXGroup; - children = ( - 84FFAE920C6C8A6F009F6E72 /* FilterGraph.cpp */, - 84FFAE930C6C8A6F009F6E72 /* FilterGraph.h */, - 84FFAE940C6C8A6F009F6E72 /* GraphEditorPanel.cpp */, - 84FFAE950C6C8A6F009F6E72 /* GraphEditorPanel.h */, - 84FFAE960C6C8A6F009F6E72 /* InternalFilters.cpp */, - 84FFAE970C6C8A6F009F6E72 /* InternalFilters.h */, - 84FFAE980C6C8A6F009F6E72 /* MainHostWindow.cpp */, - 84FFAE990C6C8A6F009F6E72 /* MainHostWindow.h */, - ); - name = host; - path = ../../src/host; - sourceTree = SOURCE_ROOT; - }; - 84FFAE9B0C6C8A6F009F6E72 /* plugins */ = { - isa = PBXGroup; - children = ( - 840A4D420CD7747400445927 /* formats */, - 84FFAE9C0C6C8A6F009F6E72 /* juce_AudioPluginFormat.cpp */, - 84FFAE9D0C6C8A6F009F6E72 /* juce_AudioPluginFormat.h */, - 84FFAE9E0C6C8A6F009F6E72 /* juce_AudioPluginInstance.cpp */, - 84FFAE9F0C6C8A6F009F6E72 /* juce_AudioPluginInstance.h */, - 84FFAEA00C6C8A6F009F6E72 /* juce_KnownPluginList.cpp */, - 84FFAEA10C6C8A6F009F6E72 /* juce_KnownPluginList.h */, - 84FFAEA20C6C8A6F009F6E72 /* juce_PluginDescription.cpp */, - 84FFAEA30C6C8A6F009F6E72 /* juce_PluginDescription.h */, - 84FFAEA40C6C8A6F009F6E72 /* juce_PluginDirectoryScanner.cpp */, - 84FFAEA50C6C8A6F009F6E72 /* juce_PluginDirectoryScanner.h */, - 84FFAEA60C6C8A6F009F6E72 /* juce_PluginListComponent.cpp */, - 84FFAEA70C6C8A6F009F6E72 /* juce_PluginListComponent.h */, - ); - name = plugins; - path = ../../src/plugins; - sourceTree = SOURCE_ROOT; - }; 84FFAEF80C6C8E76009F6E72 /* Products */ = { isa = PBXGroup; children = ( @@ -289,14 +223,6 @@ 84FFAEAE0C6C8A6F009F6E72 /* InternalFilters.cpp in Sources */, 84FFAEAF0C6C8A6F009F6E72 /* MainHostWindow.cpp in Sources */, 84FFAEB00C6C8A6F009F6E72 /* HostStartup.cpp in Sources */, - 84FFAEB10C6C8A6F009F6E72 /* juce_AudioPluginFormat.cpp in Sources */, - 84FFAEB20C6C8A6F009F6E72 /* juce_AudioPluginInstance.cpp in Sources */, - 84FFAEB30C6C8A6F009F6E72 /* juce_KnownPluginList.cpp in Sources */, - 84FFAEB40C6C8A6F009F6E72 /* juce_PluginDescription.cpp in Sources */, - 84FFAEB50C6C8A6F009F6E72 /* juce_PluginDirectoryScanner.cpp in Sources */, - 84FFAEB60C6C8A6F009F6E72 /* juce_PluginListComponent.cpp in Sources */, - 840A4D4A0CD774A000445927 /* juce_AudioUnitPluginFormat.cpp in Sources */, - 840A4D4B0CD774A000445927 /* juce_VSTPluginFormat.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/extras/audio plugin host/src/HostStartup.cpp b/extras/audio plugin host/src/HostStartup.cpp index 0ff04c0924..22074515f7 100644 --- a/extras/audio plugin host/src/HostStartup.cpp +++ b/extras/audio plugin host/src/HostStartup.cpp @@ -34,7 +34,7 @@ #include "host/InternalFilters.h" #if ! JUCE_PLUGINHOST_VST - #error If you're building the audio plugin host, you probably want to enable VST support in juce_Config.h + #error "If you're building the audio plugin host, you probably want to enable VST support in juce_Config.h" #endif diff --git a/src/juce_appframework/audio/plugins/formats/juce_AudioUnitPluginFormat.cpp b/src/juce_appframework/audio/plugins/formats/juce_AudioUnitPluginFormat.cpp index d2ac6a0d9d..44d360e1f2 100644 --- a/src/juce_appframework/audio/plugins/formats/juce_AudioUnitPluginFormat.cpp +++ b/src/juce_appframework/audio/plugins/formats/juce_AudioUnitPluginFormat.cpp @@ -1,1286 +1,1290 @@ -/* - ============================================================================== - - This file is part of the JUCE library - "Jules' Utility Class Extensions" - Copyright 2004-7 by Raw Material Software ltd. - - ------------------------------------------------------------------------------ - - JUCE can be redistributed and/or modified under the terms of the - GNU General Public License, as published by the Free Software Foundation; - either version 2 of the License, or (at your option) any later version. - - 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. - - You should have received a copy of the GNU General Public License - along with JUCE; if not, visit www.gnu.org/licenses or write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA - - ------------------------------------------------------------------------------ - - If you'd like to release a closed-source product which uses JUCE, commercial - licenses are also available: visit www.rawmaterialsoftware.com/juce for - more information. - - ============================================================================== -*/ - -#include "../../../../../juce_Config.h" - -#if JUCE_PLUGINHOST_AU && (! (defined (LINUX) || defined (_WIN32))) - -#include -#include -#include - -#include "../../../../juce_core/basics/juce_StandardHeader.h" - -BEGIN_JUCE_NAMESPACE - -#include "juce_AudioUnitPluginFormat.h" -#include "../juce_PluginDescription.h" - -#if JUCE_MAC - -extern void juce_callAnyTimersSynchronously(); -extern bool juce_isHIViewCreatedByJuce (HIViewRef view); -extern bool juce_isWindowCreatedByJuce (WindowRef window); - -#if MACOS_10_3_OR_EARLIER - #define kAudioUnitType_Generator 'augn' -#endif - -// Change this to disable logging of various activities -#ifndef AU_LOGGING - #define AU_LOGGING 1 -#endif - -#if AU_LOGGING - #define log(a) Logger::writeToLog(a); -#else - #define log(a) -#endif - -static int insideCallback = 0; - -//============================================================================== -class AudioUnitPluginWindow; - -//============================================================================== -class AudioUnitPluginInstance : public AudioPluginInstance -{ -public: - //============================================================================== - ~AudioUnitPluginInstance(); - - //============================================================================== - // AudioPluginInstance methods: - - void fillInPluginDescription (PluginDescription& desc) const - { - desc.name = pluginName; - desc.file = file; - desc.uid = ((int) componentDesc.componentType) - ^ ((int) componentDesc.componentSubType) - ^ ((int) componentDesc.componentManufacturer); - desc.lastFileModTime = file.getLastModificationTime(); - desc.pluginFormatName = "AudioUnit"; - desc.category = getCategory(); - desc.manufacturerName = manufacturer; - desc.version = version; - desc.numInputChannels = instance.getNumInputChannels(); - desc.numOutputChannels = instance.getNumOutputChannels(); - desc.isInstrument = (componentDesc.componentType == kAudioUnitType_MusicDevice); - } - - bool acceptsMidi() const { return wantsMidiMessages; } - bool producesMidi() const { return false; } - - //============================================================================== - // AudioProcessor methods: - - void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock); - void releaseResources(); - void processBlock (AudioSampleBuffer& buffer, - MidiBuffer& midiMessages); - - AudioProcessorEditor* createEditor(); - - const String getInputChannelName (const int index) const; - bool isInputChannelStereoPair (int index) const; - - const String getOutputChannelName (const int index) const; - bool isOutputChannelStereoPair (int index) const; - - //============================================================================== - int getNumParameters(); - float getParameter (int index); - void setParameter (int index, float newValue); - const String getParameterName (int index); - const String getParameterText (int index); - bool isParameterAutomatable (int index) const; - - //============================================================================== - int getNumPrograms(); - int getCurrentProgram(); - void setCurrentProgram (int index); - const String getProgramName (int index); - void changeProgramName (int index, const String& newName); - - //============================================================================== - void getStateInformation (MemoryBlock& destData); - void getCurrentProgramStateInformation (MemoryBlock& destData); - void setStateInformation (const void* data, int sizeInBytes); - void setCurrentProgramStateInformation (const void* data, int sizeInBytes); - - //============================================================================== - juce_UseDebuggingNewOperator - -private: - friend class AudioUnitPluginWindow; - friend class AudioUnitPluginFormat; - - ComponentDescription componentDesc; - String pluginName, manufacturer, version; - File file; - CriticalSection lock; - bool initialised, wantsMidiMessages, wasPlaying; - - AudioBufferList* outputBufferList; - AudioTimeStamp timeStamp; - AudioSampleBuffer* currentBuffer; - - AudioUnit audioUnit; - Array parameterIds; - - //============================================================================== - bool getComponentDescFromFile (const File& file); - void initialise(); - - //============================================================================== - OSStatus renderGetInput (AudioUnitRenderActionFlags* ioActionFlags, - const AudioTimeStamp* inTimeStamp, - UInt32 inBusNumber, - UInt32 inNumberFrames, - AudioBufferList* ioData) const; - - static OSStatus renderGetInputCallback (void* inRefCon, - AudioUnitRenderActionFlags* ioActionFlags, - const AudioTimeStamp* inTimeStamp, - UInt32 inBusNumber, - UInt32 inNumberFrames, - AudioBufferList* ioData) - { - return ((AudioUnitPluginInstance*) inRefCon) - ->renderGetInput (ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); - } - - OSStatus getBeatAndTempo (Float64* outCurrentBeat, Float64* outCurrentTempo) const; - OSStatus getMusicalTimeLocation (UInt32* outDeltaSampleOffsetToNextBeat, Float32* outTimeSig_Numerator, - UInt32* outTimeSig_Denominator, Float64* outCurrentMeasureDownBeat) const; - OSStatus getTransportState (Boolean* outIsPlaying, Boolean* outTransportStateChanged, - Float64* outCurrentSampleInTimeLine, Boolean* outIsCycling, - Float64* outCycleStartBeat, Float64* outCycleEndBeat); - - static OSStatus getBeatAndTempoCallback (void* inHostUserData, Float64* outCurrentBeat, Float64* outCurrentTempo) - { - return ((AudioUnitPluginInstance*) inHostUserData)->getBeatAndTempo (outCurrentBeat, outCurrentTempo); - } - - static OSStatus getMusicalTimeLocationCallback (void* inHostUserData, UInt32* outDeltaSampleOffsetToNextBeat, - Float32* outTimeSig_Numerator, UInt32* outTimeSig_Denominator, - Float64* outCurrentMeasureDownBeat) - { - return ((AudioUnitPluginInstance*) inHostUserData) - ->getMusicalTimeLocation (outDeltaSampleOffsetToNextBeat, outTimeSig_Numerator, - outTimeSig_Denominator, outCurrentMeasureDownBeat); - } - - static OSStatus getTransportStateCallback (void* inHostUserData, Boolean* outIsPlaying, Boolean* outTransportStateChanged, - Float64* outCurrentSampleInTimeLine, Boolean* outIsCycling, - Float64* outCycleStartBeat, Float64* outCycleEndBeat) - { - return ((AudioUnitPluginInstance*) inHostUserData) - ->getTransportState (outIsPlaying, outTransportStateChanged, - outCurrentSampleInTimeLine, outIsCycling, - outCycleStartBeat, outCycleEndBeat); - } - - //============================================================================== - void getNumChannels (int& numIns, int& numOuts) - { - numIns = 0; - numOuts = 0; - - AUChannelInfo supportedChannels [128]; - UInt32 supportedChannelsSize = sizeof (supportedChannels); - - if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_SupportedNumChannels, kAudioUnitScope_Global, - 0, supportedChannels, &supportedChannelsSize) == noErr - && supportedChannelsSize > 0) - { - for (int i = 0; i < supportedChannelsSize / sizeof (AUChannelInfo); ++i) - { - numIns = jmax (numIns, supportedChannels[i].inChannels); - numOuts = jmax (numOuts, supportedChannels[i].outChannels); - } - } - else - { - // (this really means the plugin will take any number of ins/outs as long - // as they are the same) - numIns = numOuts = 2; - } - } - - const String getCategory() const; - - //============================================================================== - AudioUnitPluginInstance (const File& file); -}; - -//============================================================================== -AudioUnitPluginInstance::AudioUnitPluginInstance (const File& file_) - : file (file_), - initialised (false), - wantsMidiMessages (false), - audioUnit (0), - outputBufferList (0), - currentBuffer (0) -{ - try - { - ++insideCallback; - - log (T("Opening AU: ") + file.getFullPathName()); - - if (getComponentDescFromFile (file)) - { - ComponentRecord* const comp = FindNextComponent (0, &componentDesc); - - if (comp != 0) - { - audioUnit = (AudioUnit) OpenComponent (comp); - - wantsMidiMessages = componentDesc.componentType == kAudioUnitType_MusicDevice - || componentDesc.componentType == kAudioUnitType_MusicEffect; - } - } - - --insideCallback; - } - catch (...) - { - --insideCallback; - } -} - -AudioUnitPluginInstance::~AudioUnitPluginInstance() -{ - { - const ScopedLock sl (lock); - - jassert (insideCallback == 0); - - if (audioUnit != 0) - { - AudioUnitUninitialize (audioUnit); - CloseComponent (audioUnit); - audioUnit = 0; - } - } - - juce_free (outputBufferList); -} - -bool AudioUnitPluginInstance::getComponentDescFromFile (const File& file) -{ - zerostruct (componentDesc); - - if (! file.hasFileExtension (T(".component"))) - return false; - - const String filename (file.getFullPathName()); - const char* const utf8 = filename.toUTF8(); - CFURLRef url = CFURLCreateFromFileSystemRepresentation (0, (const UInt8*) utf8, - strlen (utf8), file.isDirectory()); - if (url != 0) - { - CFBundleRef bundleRef = CFBundleCreate (kCFAllocatorDefault, url); - CFRelease (url); - - if (bundleRef != 0) - { - CFTypeRef name = CFBundleGetValueForInfoDictionaryKey (bundleRef, CFSTR("CFBundleName")); - - if (name != 0 && CFGetTypeID (name) == CFStringGetTypeID()) - pluginName = PlatformUtilities::cfStringToJuceString ((CFStringRef) name); - - if (pluginName.isEmpty()) - pluginName = file.getFileNameWithoutExtension(); - - CFTypeRef versionString = CFBundleGetValueForInfoDictionaryKey (bundleRef, CFSTR("CFBundleVersion")); - - if (versionString != 0 && CFGetTypeID (versionString) == CFStringGetTypeID()) - version = PlatformUtilities::cfStringToJuceString ((CFStringRef) versionString); - - CFTypeRef manuString = CFBundleGetValueForInfoDictionaryKey (bundleRef, CFSTR("CFBundleGetInfoString")); - - if (manuString != 0 && CFGetTypeID (manuString) == CFStringGetTypeID()) - manufacturer = PlatformUtilities::cfStringToJuceString ((CFStringRef) manuString); - - short resFileId = CFBundleOpenBundleResourceMap (bundleRef); - UseResFile (resFileId); - - for (int i = 1; i <= Count1Resources ('thng'); ++i) - { - Handle h = Get1IndResource ('thng', i); - - if (h != 0) - { - HLock (h); - const uint32* const types = (const uint32*) *h; - - if (types[0] == kAudioUnitType_MusicDevice - || types[0] == kAudioUnitType_MusicEffect - || types[0] == kAudioUnitType_Effect - || types[0] == kAudioUnitType_Generator - || types[0] == kAudioUnitType_Panner) - { - componentDesc.componentType = types[0]; - componentDesc.componentSubType = types[1]; - componentDesc.componentManufacturer = types[2]; - break; - } - - HUnlock (h); - ReleaseResource (h); - } - } - - CFBundleCloseBundleResourceMap (bundleRef, resFileId); - CFRelease (bundleRef); - } - } - - return componentDesc.componentType != 0 && componentDesc.componentSubType != 0; -} - -//============================================================================== -void AudioUnitPluginInstance::initialise() -{ - if (initialised || audioUnit == 0) - return; - - log (T("Initialising AU: ") + pluginName); - - parameterIds.clear(); - - { - UInt32 paramListSize = 0; - AudioUnitGetProperty (audioUnit, kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, - 0, 0, ¶mListSize); - - if (paramListSize > 0) - { - parameterIds.insertMultiple (0, 0, paramListSize / sizeof (int)); - - AudioUnitGetProperty (audioUnit, kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, - 0, ¶meterIds.getReference(0), ¶mListSize); - } - } - - { - AURenderCallbackStruct info; - zerostruct (info); - info.inputProcRefCon = this; - info.inputProc = renderGetInputCallback; - - AudioUnitSetProperty (audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, - 0, &info, sizeof (info)); - } - - { - HostCallbackInfo info; - zerostruct (info); - info.hostUserData = this; - info.beatAndTempoProc = getBeatAndTempoCallback; - info.musicalTimeLocationProc = getMusicalTimeLocationCallback; - info.transportStateProc = getTransportStateCallback; - - AudioUnitSetProperty (audioUnit, kAudioUnitProperty_HostCallbacks, kAudioUnitScope_Global, - 0, &info, sizeof (info)); - } - - int numIns, numOuts; - getNumChannels (numIns, numOuts); - setPlayConfigDetails (numIns, numOuts, 0, 0); - - initialised = AudioUnitInitialize (audioUnit) == noErr; - - setLatencySamples (0); -} - - -//============================================================================== -void AudioUnitPluginInstance::prepareToPlay (double sampleRate_, - int samplesPerBlockExpected) -{ - initialise(); - - if (initialised) - { - int numIns, numOuts; - getNumChannels (numIns, numOuts); - - setPlayConfigDetails (numIns, numOuts, sampleRate_, samplesPerBlockExpected); - - Float64 latencySecs = 0.0; - UInt32 latencySize = sizeof (latencySecs); - AudioUnitGetProperty (audioUnit, kAudioUnitProperty_Latency, kAudioUnitScope_Global, - 0, &latencySecs, &latencySize); - - setLatencySamples (roundDoubleToInt (latencySecs * sampleRate_)); - - AudioUnitReset (audioUnit, kAudioUnitScope_Input, 0); - AudioUnitReset (audioUnit, kAudioUnitScope_Output, 0); - AudioUnitReset (audioUnit, kAudioUnitScope_Global, 0); - - AudioStreamBasicDescription stream; - zerostruct (stream); - stream.mSampleRate = sampleRate_; - stream.mFormatID = kAudioFormatLinearPCM; - stream.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved; - stream.mFramesPerPacket = 1; - stream.mBytesPerPacket = 4; - stream.mBytesPerFrame = 4; - stream.mBitsPerChannel = 32; - stream.mChannelsPerFrame = numIns; - - OSStatus err = AudioUnitSetProperty (audioUnit, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, - 0, &stream, sizeof (stream)); - - stream.mChannelsPerFrame = numOuts; - - err = AudioUnitSetProperty (audioUnit, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Output, - 0, &stream, sizeof (stream)); - - juce_free (outputBufferList); - outputBufferList = (AudioBufferList*) juce_calloc (sizeof (AudioBufferList) + sizeof (AudioBuffer) * (numOuts + 1)); - outputBufferList->mNumberBuffers = numOuts; - - for (int i = numOuts; --i >= 0;) - outputBufferList->mBuffers[i].mNumberChannels = 1; - - zerostruct (timeStamp); - timeStamp.mSampleTime = 0; - timeStamp.mHostTime = AudioGetCurrentHostTime(); - timeStamp.mFlags = kAudioTimeStampSampleTimeValid | kAudioTimeStampHostTimeValid; - - currentBuffer = 0; - wasPlaying = false; - } -} - -void AudioUnitPluginInstance::releaseResources() -{ - if (initialised) - { - AudioUnitReset (audioUnit, kAudioUnitScope_Input, 0); - AudioUnitReset (audioUnit, kAudioUnitScope_Output, 0); - AudioUnitReset (audioUnit, kAudioUnitScope_Global, 0); - - juce_free (outputBufferList); - outputBufferList = 0; - currentBuffer = 0; - } -} - -OSStatus AudioUnitPluginInstance::renderGetInput (AudioUnitRenderActionFlags* ioActionFlags, - const AudioTimeStamp* inTimeStamp, - UInt32 inBusNumber, - UInt32 inNumberFrames, - AudioBufferList* ioData) const -{ - if (inBusNumber == 0 - && currentBuffer != 0) - { - jassert (inNumberFrames == currentBuffer->getNumSamples()); // if this ever happens, might need to add extra handling - - for (int i = 0; i < ioData->mNumberBuffers; ++i) - { - if (i < currentBuffer->getNumChannels()) - { - memcpy (ioData->mBuffers[i].mData, - currentBuffer->getSampleData (i, 0), - sizeof (float) * inNumberFrames); - } - else - { - zeromem (ioData->mBuffers[i].mData, sizeof (float) * inNumberFrames); - } - } - } - - return noErr; -} - -void AudioUnitPluginInstance::processBlock (AudioSampleBuffer& buffer, - MidiBuffer& midiMessages) -{ - const int numSamples = buffer.getNumSamples(); - - if (initialised) - { - AudioUnitRenderActionFlags flags = 0; - - timeStamp.mHostTime = AudioGetCurrentHostTime(); - - for (int i = getNumOutputChannels(); --i >= 0;) - { - outputBufferList->mBuffers[i].mDataByteSize = sizeof (float) * numSamples; - outputBufferList->mBuffers[i].mData = buffer.getSampleData (i, 0); - } - - currentBuffer = &buffer; - - if (wantsMidiMessages) - { - const uint8* midiEventData; - int midiEventSize, midiEventPosition; - MidiBuffer::Iterator i (midiMessages); - - while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition)) - { - if (midiEventSize <= 3) - MusicDeviceMIDIEvent (audioUnit, - midiEventData[0], midiEventData[1], midiEventData[2], - midiEventPosition); - else - MusicDeviceSysEx (audioUnit, midiEventData, midiEventSize); - } - - midiMessages.clear(); - } - - AudioUnitRender (audioUnit, &flags, &timeStamp, - 0, numSamples, outputBufferList); - - timeStamp.mSampleTime += numSamples; - } - else - { - // Not initialised, so just bypass.. - for (int i = getNumInputChannels(); i < getNumOutputChannels(); ++i) - buffer.clear (i, 0, buffer.getNumSamples()); - } -} - -//============================================================================== -OSStatus AudioUnitPluginInstance::getBeatAndTempo (Float64* outCurrentBeat, Float64* outCurrentTempo) const -{ - AudioPlayHead* const ph = getPlayHead(); - AudioPlayHead::CurrentPositionInfo result; - - if (ph != 0 && ph->getCurrentPosition (result)) - { - *outCurrentBeat = result.ppqPosition; - *outCurrentTempo = result.bpm; - } - else - { - *outCurrentBeat = 0; - *outCurrentTempo = 120.0; - } - - return noErr; -} - -OSStatus AudioUnitPluginInstance::getMusicalTimeLocation (UInt32* outDeltaSampleOffsetToNextBeat, - Float32* outTimeSig_Numerator, - UInt32* outTimeSig_Denominator, - Float64* outCurrentMeasureDownBeat) const -{ - AudioPlayHead* const ph = getPlayHead(); - AudioPlayHead::CurrentPositionInfo result; - - if (ph != 0 && ph->getCurrentPosition (result)) - { - *outTimeSig_Numerator = result.timeSigNumerator; - *outTimeSig_Denominator = result.timeSigDenominator; - - *outDeltaSampleOffsetToNextBeat = 0; //xxx - *outCurrentMeasureDownBeat = result.ppqPositionOfLastBarStart; //xxx wrong - } - else - { - *outDeltaSampleOffsetToNextBeat = 0; - *outTimeSig_Numerator = 4; - *outTimeSig_Denominator = 4; - *outCurrentMeasureDownBeat = 0; - } - - return noErr; -} - -OSStatus AudioUnitPluginInstance::getTransportState (Boolean* outIsPlaying, - Boolean* outTransportStateChanged, - Float64* outCurrentSampleInTimeLine, - Boolean* outIsCycling, - Float64* outCycleStartBeat, - Float64* outCycleEndBeat) -{ - AudioPlayHead* const ph = getPlayHead(); - AudioPlayHead::CurrentPositionInfo result; - - if (ph != 0 && ph->getCurrentPosition (result)) - { - *outIsPlaying = result.isPlaying; - *outTransportStateChanged = result.isPlaying != wasPlaying; - wasPlaying = result.isPlaying; - *outCurrentSampleInTimeLine = roundDoubleToInt (result.timeInSeconds * getSampleRate()); - *outIsCycling = false; - *outCycleStartBeat = 0; - *outCycleEndBeat = 0; - } - else - { - *outIsPlaying = false; - *outTransportStateChanged = false; - *outCurrentSampleInTimeLine = 0; - *outIsCycling = false; - *outCycleStartBeat = 0; - *outCycleEndBeat = 0; - } - - return noErr; -} - - -//============================================================================== -static VoidArray activeWindows; - -//============================================================================== -class AudioUnitPluginWindow : public AudioProcessorEditor, - public Timer -{ -public: - //============================================================================== - AudioUnitPluginWindow (AudioUnitPluginInstance& plugin_) - : AudioProcessorEditor (&plugin_), - plugin (plugin_), - isOpen (false), - pluginWantsKeys (false), - wasShowing (false), - recursiveResize (false), - viewComponent (0), - pluginViewRef (0) - { - movementWatcher = new CompMovementWatcher (this); - - activeWindows.add (this); - - setOpaque (true); - setVisible (true); - setSize (1, 1); - - ComponentDescription viewList [16]; - UInt32 viewListSize = sizeof (viewList); - AudioUnitGetProperty (plugin.audioUnit, kAudioUnitProperty_GetUIComponentList, kAudioUnitScope_Global, - 0, &viewList, &viewListSize); - - componentRecord = FindNextComponent (0, &viewList[0]); - } - - ~AudioUnitPluginWindow() - { - deleteAndZero (movementWatcher); - - closePluginWindow(); - - activeWindows.removeValue (this); - plugin.editorBeingDeleted (this); - } - - bool isValid() const throw() { return componentRecord != 0; } - - //============================================================================== - void componentMovedOrResized() - { - if (recursiveResize) - return; - - Component* const topComp = getTopLevelComponent(); - - if (topComp->getPeer() != 0) - { - int x = 0, y = 0; - relativePositionToOtherComponent (topComp, x, y); - - recursiveResize = true; - - if (pluginViewRef != 0) - { - HIRect r; - r.origin.x = (float) x; - r.origin.y = (float) y; - r.size.width = (float) getWidth(); - r.size.height = (float) getHeight(); - HIViewSetFrame (pluginViewRef, &r); - } - - recursiveResize = false; - } - } - - void componentVisibilityChanged() - { - const bool isShowingNow = isShowing(); - - if (wasShowing != isShowingNow) - { - wasShowing = isShowingNow; - - if (isShowingNow) - openPluginWindow(); - else - closePluginWindow(); - } - - componentMovedOrResized(); - } - - void componentPeerChanged() - { - closePluginWindow(); - openPluginWindow(); - } - - void timerCallback() - { - if (pluginViewRef != 0) - { - HIRect bounds; - HIViewGetBounds (pluginViewRef, &bounds); - const int w = jmax (32, (int) bounds.size.width); - const int h = jmax (32, (int) bounds.size.height); - - if (w != getWidth() || h != getHeight()) - { - setSize (w, h); - startTimer (50); - } - else - { - startTimer (jlimit (50, 500, getTimerInterval() + 20)); - } - } - } - - //============================================================================== - bool keyStateChanged() - { - return pluginWantsKeys; - } - - bool keyPressed (const KeyPress&) - { - return pluginWantsKeys; - } - - //============================================================================== - void paint (Graphics& g) - { - if (isOpen) - { - ComponentPeer* const peer = getPeer(); - - if (peer != 0) - { - peer->addMaskedRegion (getScreenX() - peer->getScreenX(), - getScreenY() - peer->getScreenY(), - getWidth(), getHeight()); - } - } - else - { - g.fillAll (Colours::black); - } - } - - //============================================================================== - void broughtToFront() - { - activeWindows.removeValue (this); - activeWindows.add (this); - } - - //============================================================================== - juce_UseDebuggingNewOperator - -private: - AudioUnitPluginInstance& plugin; - bool isOpen, wasShowing, recursiveResize; - bool pluginWantsKeys; - - ComponentRecord* componentRecord; - AudioUnitCarbonView viewComponent; - HIViewRef pluginViewRef; - - //============================================================================== - void openPluginWindow() - { - if (isOpen || getWindowHandle() == 0 || componentRecord == 0) - return; - - log (T("Opening AU GUI: ") + plugin.getName()); - isOpen = true; - - pluginWantsKeys = true; //xxx any way to find this out? Does it matter? - - viewComponent = (AudioUnitCarbonView) OpenComponent (componentRecord); - - if (viewComponent != 0) - { - Float32Point pos = { getScreenX() - getTopLevelComponent()->getScreenX(), - getScreenY() - getTopLevelComponent()->getScreenY() }; - Float32Point size = { 250, 200 }; - - AudioUnitCarbonViewCreate (viewComponent, - plugin.audioUnit, - (WindowRef) getWindowHandle(), - HIViewGetRoot ((WindowRef) getWindowHandle()), - &pos, &size, - (ControlRef*) &pluginViewRef); - } - - timerCallback(); // to set our comp to the right size - repaint(); - } - - //============================================================================== - void closePluginWindow() - { - stopTimer(); - - if (isOpen) - { - log (T("Closing AU GUI: ") + plugin.getName()); - isOpen = false; - - if (viewComponent != 0) - CloseComponent (viewComponent); - - pluginViewRef = 0; - } - } - - //============================================================================== - class CompMovementWatcher : public ComponentMovementWatcher - { - public: - CompMovementWatcher (AudioUnitPluginWindow* const owner_) - : ComponentMovementWatcher (owner_), - owner (owner_) - { - } - - //============================================================================== - void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) - { - owner->componentMovedOrResized(); - } - - void componentPeerChanged() - { - owner->componentPeerChanged(); - } - - void componentVisibilityChanged (Component&) - { - owner->componentVisibilityChanged(); - } - - private: - AudioUnitPluginWindow* const owner; - }; - - CompMovementWatcher* movementWatcher; -}; - -//============================================================================== -AudioProcessorEditor* AudioUnitPluginInstance::createEditor() -{ - AudioUnitPluginWindow* w = new AudioUnitPluginWindow (*this); - - if (! w->isValid()) - deleteAndZero (w); - - return w; -} - - -//============================================================================== -const String AudioUnitPluginInstance::getCategory() const -{ - const char* result = 0; - - switch (componentDesc.componentType) - { - case kAudioUnitType_Effect: - case kAudioUnitType_MusicEffect: - result = "Effect"; - break; - case kAudioUnitType_MusicDevice: - result = "Synth"; - break; - case kAudioUnitType_Generator: - result = "Generator"; - break; - case kAudioUnitType_Panner: - result = "Panner"; - break; - default: - break; - } - - return result; -} - -//============================================================================== -int AudioUnitPluginInstance::getNumParameters() -{ - return parameterIds.size(); -} - -float AudioUnitPluginInstance::getParameter (int index) -{ - const ScopedLock sl (lock); - - Float32 value = 0.0f; - - if (audioUnit != 0 && ((unsigned int) index) < (unsigned int) parameterIds.size()) - { - AudioUnitGetParameter (audioUnit, - (UInt32) parameterIds.getUnchecked (index), - kAudioUnitScope_Global, 0, - &value); - } - - return value; -} - -void AudioUnitPluginInstance::setParameter (int index, float newValue) -{ - const ScopedLock sl (lock); - - if (audioUnit != 0 && ((unsigned int) index) < (unsigned int) parameterIds.size()) - { - AudioUnitSetParameter (audioUnit, - (UInt32) parameterIds.getUnchecked (index), - kAudioUnitScope_Global, 0, - newValue, 0); - } -} - -const String AudioUnitPluginInstance::getParameterName (int index) -{ - AudioUnitParameterInfo info; - zerostruct (info); - UInt32 sz = sizeof (info); - - String name; - - if (AudioUnitGetProperty (audioUnit, - kAudioUnitProperty_ParameterInfo, - kAudioUnitScope_Global, - parameterIds [index], &info, &sz) == noErr) - { - if ((info.flags & kAudioUnitParameterFlag_HasCFNameString) != 0) - name = PlatformUtilities::cfStringToJuceString (info.cfNameString); - else - name = String (info.name, sizeof (info.name)); - } - - return name; -} - -const String AudioUnitPluginInstance::getParameterText (int index) -{ - return String (getParameter (index)); -} - -bool AudioUnitPluginInstance::isParameterAutomatable (int index) const -{ - AudioUnitParameterInfo info; - UInt32 sz = sizeof (info); - - if (AudioUnitGetProperty (audioUnit, - kAudioUnitProperty_ParameterInfo, - kAudioUnitScope_Global, - parameterIds [index], &info, &sz) == noErr) - { - return (info.flags & kAudioUnitParameterFlag_NonRealTime) == 0; - } - - return true; -} - -//============================================================================== -int AudioUnitPluginInstance::getNumPrograms() -{ - CFArrayRef presets; - UInt32 sz = sizeof (CFArrayRef); - int num = 0; - - if (AudioUnitGetProperty (audioUnit, - kAudioUnitProperty_FactoryPresets, - kAudioUnitScope_Global, - 0, &presets, &sz) == noErr) - { - num = (int) CFArrayGetCount (presets); - CFRelease (presets); - } - - return num; -} - -int AudioUnitPluginInstance::getCurrentProgram() -{ - AUPreset current; - current.presetNumber = 0; - UInt32 sz = sizeof (AUPreset); - - AudioUnitGetProperty (audioUnit, - kAudioUnitProperty_FactoryPresets, - kAudioUnitScope_Global, - 0, ¤t, &sz); - - return current.presetNumber; -} - -void AudioUnitPluginInstance::setCurrentProgram (int newIndex) -{ - AUPreset current; - current.presetNumber = newIndex; - current.presetName = 0; - - AudioUnitSetProperty (audioUnit, - kAudioUnitProperty_FactoryPresets, - kAudioUnitScope_Global, - 0, ¤t, sizeof (AUPreset)); -} - -const String AudioUnitPluginInstance::getProgramName (int index) -{ - String s; - CFArrayRef presets; - UInt32 sz = sizeof (CFArrayRef); - - if (AudioUnitGetProperty (audioUnit, - kAudioUnitProperty_FactoryPresets, - kAudioUnitScope_Global, - 0, &presets, &sz) == noErr) - { - for (CFIndex i = 0; i < CFArrayGetCount (presets); ++i) - { - const AUPreset* p = (const AUPreset*) CFArrayGetValueAtIndex (presets, i); - - if (p != 0 && p->presetNumber == index) - { - s = PlatformUtilities::cfStringToJuceString (p->presetName); - break; - } - } - - CFRelease (presets); - } - - return s; -} - -void AudioUnitPluginInstance::changeProgramName (int index, const String& newName) -{ - jassertfalse // xxx not implemented! -} - -//============================================================================== -const String AudioUnitPluginInstance::getInputChannelName (const int index) const -{ - if (((unsigned int) index) < (unsigned int) getNumInputChannels()) - return T("Input ") + String (index + 1); - - return String::empty; -} - -bool AudioUnitPluginInstance::isInputChannelStereoPair (int index) const -{ - if (((unsigned int) index) >= (unsigned int) getNumInputChannels()) - return false; - - - return true; -} - -const String AudioUnitPluginInstance::getOutputChannelName (const int index) const -{ - if (((unsigned int) index) < (unsigned int) getNumOutputChannels()) - return T("Output ") + String (index + 1); - - return String::empty; -} - -bool AudioUnitPluginInstance::isOutputChannelStereoPair (int index) const -{ - if (((unsigned int) index) >= (unsigned int) getNumOutputChannels()) - return false; - - return true; -} - -//============================================================================== -void AudioUnitPluginInstance::getStateInformation (MemoryBlock& destData) -{ - getCurrentProgramStateInformation (destData); -} - -void AudioUnitPluginInstance::getCurrentProgramStateInformation (MemoryBlock& destData) -{ - CFPropertyListRef propertyList = 0; - UInt32 sz = sizeof (CFPropertyListRef); - - if (AudioUnitGetProperty (audioUnit, - kAudioUnitProperty_ClassInfo, - kAudioUnitScope_Global, - 0, &propertyList, &sz) == noErr) - { - CFWriteStreamRef stream = CFWriteStreamCreateWithAllocatedBuffers (kCFAllocatorDefault, kCFAllocatorDefault); - CFWriteStreamOpen (stream); - - CFIndex bytesWritten = CFPropertyListWriteToStream (propertyList, stream, kCFPropertyListBinaryFormat_v1_0, 0); - CFWriteStreamClose (stream); - - CFDataRef data = (CFDataRef) CFWriteStreamCopyProperty (stream, kCFStreamPropertyDataWritten); - - destData.setSize (bytesWritten); - destData.copyFrom (CFDataGetBytePtr (data), 0, destData.getSize()); - CFRelease (data); - - CFRelease (stream); - CFRelease (propertyList); - } -} - -void AudioUnitPluginInstance::setStateInformation (const void* data, int sizeInBytes) -{ - setCurrentProgramStateInformation (data, sizeInBytes); -} - -void AudioUnitPluginInstance::setCurrentProgramStateInformation (const void* data, int sizeInBytes) -{ - CFReadStreamRef stream = CFReadStreamCreateWithBytesNoCopy (kCFAllocatorDefault, - (const UInt8*) data, - sizeInBytes, - kCFAllocatorNull); - CFReadStreamOpen (stream); - - CFPropertyListFormat format = kCFPropertyListBinaryFormat_v1_0; - CFPropertyListRef propertyList = CFPropertyListCreateFromStream (kCFAllocatorDefault, - stream, - 0, - kCFPropertyListImmutable, - &format, - 0); - CFRelease (stream); - - if (propertyList != 0) - AudioUnitSetProperty (audioUnit, - kAudioUnitProperty_ClassInfo, - kAudioUnitScope_Global, - 0, &propertyList, sizeof (propertyList)); -} - -//============================================================================== -//============================================================================== -AudioUnitPluginFormat::AudioUnitPluginFormat() -{ -} - -AudioUnitPluginFormat::~AudioUnitPluginFormat() -{ -} - -void AudioUnitPluginFormat::findAllTypesForFile (OwnedArray & results, - const File& file) -{ - if (! fileMightContainThisPluginType (file)) - return; - - PluginDescription desc; - desc.file = file; - desc.uid = 0; - - AudioUnitPluginInstance* instance = dynamic_cast (createInstanceFromDescription (desc)); - - if (instance == 0) - return; - - try - { - desc.fillInFromInstance (*instance); - - results.add (new PluginDescription (desc)); - } - catch (...) - { - // crashed while loading... - } - - deleteAndZero (instance); -} - -AudioPluginInstance* AudioUnitPluginFormat::createInstanceFromDescription (const PluginDescription& desc) -{ - AudioUnitPluginInstance* result = 0; - - if (fileMightContainThisPluginType (desc.file)) - { - result = new AudioUnitPluginInstance (desc.file); - - if (result->audioUnit != 0) - { - result->initialise(); - } - else - { - deleteAndZero (result); - } - } - - return result; -} - -bool AudioUnitPluginFormat::fileMightContainThisPluginType (const File& f) -{ - return f.hasFileExtension (T(".component")) - && f.isDirectory(); -} - -const FileSearchPath AudioUnitPluginFormat::getDefaultLocationsToSearch() -{ - return FileSearchPath ("~/Library/Audio/Plug-Ins/Components;/Library/Audio/Plug-Ins/Components"); -} - -#endif - -END_JUCE_NAMESPACE - -#endif +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-7 by Raw Material Software ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified under the terms of the + GNU General Public License, as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + 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. + + You should have received a copy of the GNU General Public License + along with JUCE; if not, visit www.gnu.org/licenses or write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------------ + + If you'd like to release a closed-source product which uses JUCE, commercial + licenses are also available: visit www.rawmaterialsoftware.com/juce for + more information. + + ============================================================================== +*/ + +#include "../../../../../juce_Config.h" + +#if JUCE_PLUGINHOST_AU && (! (defined (LINUX) || defined (_WIN32))) + +#include +#include +#include + +#include "../../../../juce_core/basics/juce_StandardHeader.h" + +BEGIN_JUCE_NAMESPACE + +#include "juce_AudioUnitPluginFormat.h" +#include "../juce_PluginDescription.h" +#include "../../../../juce_core/threads/juce_ScopedLock.h" +#include "../../../../juce_appframework/events/juce_Timer.h" +#include "../../../../juce_core/misc/juce_PlatformUtilities.h" +#include "../../../../juce_appframework/gui/components/layout/juce_ComponentMovementWatcher.h" + +#if JUCE_MAC + +extern void juce_callAnyTimersSynchronously(); +extern bool juce_isHIViewCreatedByJuce (HIViewRef view); +extern bool juce_isWindowCreatedByJuce (WindowRef window); + +#if MACOS_10_3_OR_EARLIER + #define kAudioUnitType_Generator 'augn' +#endif + +// Change this to disable logging of various activities +#ifndef AU_LOGGING + #define AU_LOGGING 1 +#endif + +#if AU_LOGGING + #define log(a) Logger::writeToLog(a); +#else + #define log(a) +#endif + +static int insideCallback = 0; + +//============================================================================== +class AudioUnitPluginWindow; + +//============================================================================== +class AudioUnitPluginInstance : public AudioPluginInstance +{ +public: + //============================================================================== + ~AudioUnitPluginInstance(); + + //============================================================================== + // AudioPluginInstance methods: + + void fillInPluginDescription (PluginDescription& desc) const + { + desc.name = pluginName; + desc.file = file; + desc.uid = ((int) componentDesc.componentType) + ^ ((int) componentDesc.componentSubType) + ^ ((int) componentDesc.componentManufacturer); + desc.lastFileModTime = file.getLastModificationTime(); + desc.pluginFormatName = "AudioUnit"; + desc.category = getCategory(); + desc.manufacturerName = manufacturer; + desc.version = version; + desc.numInputChannels = getNumInputChannels(); + desc.numOutputChannels = getNumOutputChannels(); + desc.isInstrument = (componentDesc.componentType == kAudioUnitType_MusicDevice); + } + + const String getName() const { return pluginName; } + bool acceptsMidi() const { return wantsMidiMessages; } + bool producesMidi() const { return false; } + + //============================================================================== + // AudioProcessor methods: + + void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock); + void releaseResources(); + void processBlock (AudioSampleBuffer& buffer, + MidiBuffer& midiMessages); + + AudioProcessorEditor* createEditor(); + + const String getInputChannelName (const int index) const; + bool isInputChannelStereoPair (int index) const; + + const String getOutputChannelName (const int index) const; + bool isOutputChannelStereoPair (int index) const; + + //============================================================================== + int getNumParameters(); + float getParameter (int index); + void setParameter (int index, float newValue); + const String getParameterName (int index); + const String getParameterText (int index); + bool isParameterAutomatable (int index) const; + + //============================================================================== + int getNumPrograms(); + int getCurrentProgram(); + void setCurrentProgram (int index); + const String getProgramName (int index); + void changeProgramName (int index, const String& newName); + + //============================================================================== + void getStateInformation (MemoryBlock& destData); + void getCurrentProgramStateInformation (MemoryBlock& destData); + void setStateInformation (const void* data, int sizeInBytes); + void setCurrentProgramStateInformation (const void* data, int sizeInBytes); + + //============================================================================== + juce_UseDebuggingNewOperator + +private: + friend class AudioUnitPluginWindow; + friend class AudioUnitPluginFormat; + + ComponentDescription componentDesc; + String pluginName, manufacturer, version; + File file; + CriticalSection lock; + bool initialised, wantsMidiMessages, wasPlaying; + + AudioBufferList* outputBufferList; + AudioTimeStamp timeStamp; + AudioSampleBuffer* currentBuffer; + + AudioUnit audioUnit; + Array parameterIds; + + //============================================================================== + bool getComponentDescFromFile (const File& file); + void initialise(); + + //============================================================================== + OSStatus renderGetInput (AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList* ioData) const; + + static OSStatus renderGetInputCallback (void* inRefCon, + AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList* ioData) + { + return ((AudioUnitPluginInstance*) inRefCon) + ->renderGetInput (ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); + } + + OSStatus getBeatAndTempo (Float64* outCurrentBeat, Float64* outCurrentTempo) const; + OSStatus getMusicalTimeLocation (UInt32* outDeltaSampleOffsetToNextBeat, Float32* outTimeSig_Numerator, + UInt32* outTimeSig_Denominator, Float64* outCurrentMeasureDownBeat) const; + OSStatus getTransportState (Boolean* outIsPlaying, Boolean* outTransportStateChanged, + Float64* outCurrentSampleInTimeLine, Boolean* outIsCycling, + Float64* outCycleStartBeat, Float64* outCycleEndBeat); + + static OSStatus getBeatAndTempoCallback (void* inHostUserData, Float64* outCurrentBeat, Float64* outCurrentTempo) + { + return ((AudioUnitPluginInstance*) inHostUserData)->getBeatAndTempo (outCurrentBeat, outCurrentTempo); + } + + static OSStatus getMusicalTimeLocationCallback (void* inHostUserData, UInt32* outDeltaSampleOffsetToNextBeat, + Float32* outTimeSig_Numerator, UInt32* outTimeSig_Denominator, + Float64* outCurrentMeasureDownBeat) + { + return ((AudioUnitPluginInstance*) inHostUserData) + ->getMusicalTimeLocation (outDeltaSampleOffsetToNextBeat, outTimeSig_Numerator, + outTimeSig_Denominator, outCurrentMeasureDownBeat); + } + + static OSStatus getTransportStateCallback (void* inHostUserData, Boolean* outIsPlaying, Boolean* outTransportStateChanged, + Float64* outCurrentSampleInTimeLine, Boolean* outIsCycling, + Float64* outCycleStartBeat, Float64* outCycleEndBeat) + { + return ((AudioUnitPluginInstance*) inHostUserData) + ->getTransportState (outIsPlaying, outTransportStateChanged, + outCurrentSampleInTimeLine, outIsCycling, + outCycleStartBeat, outCycleEndBeat); + } + + //============================================================================== + void getNumChannels (int& numIns, int& numOuts) + { + numIns = 0; + numOuts = 0; + + AUChannelInfo supportedChannels [128]; + UInt32 supportedChannelsSize = sizeof (supportedChannels); + + if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_SupportedNumChannels, kAudioUnitScope_Global, + 0, supportedChannels, &supportedChannelsSize) == noErr + && supportedChannelsSize > 0) + { + for (int i = 0; i < supportedChannelsSize / sizeof (AUChannelInfo); ++i) + { + numIns = jmax (numIns, supportedChannels[i].inChannels); + numOuts = jmax (numOuts, supportedChannels[i].outChannels); + } + } + else + { + // (this really means the plugin will take any number of ins/outs as long + // as they are the same) + numIns = numOuts = 2; + } + } + + const String getCategory() const; + + //============================================================================== + AudioUnitPluginInstance (const File& file); +}; + +//============================================================================== +AudioUnitPluginInstance::AudioUnitPluginInstance (const File& file_) + : file (file_), + initialised (false), + wantsMidiMessages (false), + audioUnit (0), + outputBufferList (0), + currentBuffer (0) +{ + try + { + ++insideCallback; + + log (T("Opening AU: ") + file.getFullPathName()); + + if (getComponentDescFromFile (file)) + { + ComponentRecord* const comp = FindNextComponent (0, &componentDesc); + + if (comp != 0) + { + audioUnit = (AudioUnit) OpenComponent (comp); + + wantsMidiMessages = componentDesc.componentType == kAudioUnitType_MusicDevice + || componentDesc.componentType == kAudioUnitType_MusicEffect; + } + } + + --insideCallback; + } + catch (...) + { + --insideCallback; + } +} + +AudioUnitPluginInstance::~AudioUnitPluginInstance() +{ + { + const ScopedLock sl (lock); + + jassert (insideCallback == 0); + + if (audioUnit != 0) + { + AudioUnitUninitialize (audioUnit); + CloseComponent (audioUnit); + audioUnit = 0; + } + } + + juce_free (outputBufferList); +} + +bool AudioUnitPluginInstance::getComponentDescFromFile (const File& file) +{ + zerostruct (componentDesc); + + if (! file.hasFileExtension (T(".component"))) + return false; + + const String filename (file.getFullPathName()); + const char* const utf8 = filename.toUTF8(); + CFURLRef url = CFURLCreateFromFileSystemRepresentation (0, (const UInt8*) utf8, + strlen (utf8), file.isDirectory()); + if (url != 0) + { + CFBundleRef bundleRef = CFBundleCreate (kCFAllocatorDefault, url); + CFRelease (url); + + if (bundleRef != 0) + { + CFTypeRef name = CFBundleGetValueForInfoDictionaryKey (bundleRef, CFSTR("CFBundleName")); + + if (name != 0 && CFGetTypeID (name) == CFStringGetTypeID()) + pluginName = PlatformUtilities::cfStringToJuceString ((CFStringRef) name); + + if (pluginName.isEmpty()) + pluginName = file.getFileNameWithoutExtension(); + + CFTypeRef versionString = CFBundleGetValueForInfoDictionaryKey (bundleRef, CFSTR("CFBundleVersion")); + + if (versionString != 0 && CFGetTypeID (versionString) == CFStringGetTypeID()) + version = PlatformUtilities::cfStringToJuceString ((CFStringRef) versionString); + + CFTypeRef manuString = CFBundleGetValueForInfoDictionaryKey (bundleRef, CFSTR("CFBundleGetInfoString")); + + if (manuString != 0 && CFGetTypeID (manuString) == CFStringGetTypeID()) + manufacturer = PlatformUtilities::cfStringToJuceString ((CFStringRef) manuString); + + short resFileId = CFBundleOpenBundleResourceMap (bundleRef); + UseResFile (resFileId); + + for (int i = 1; i <= Count1Resources ('thng'); ++i) + { + Handle h = Get1IndResource ('thng', i); + + if (h != 0) + { + HLock (h); + const uint32* const types = (const uint32*) *h; + + if (types[0] == kAudioUnitType_MusicDevice + || types[0] == kAudioUnitType_MusicEffect + || types[0] == kAudioUnitType_Effect + || types[0] == kAudioUnitType_Generator + || types[0] == kAudioUnitType_Panner) + { + componentDesc.componentType = types[0]; + componentDesc.componentSubType = types[1]; + componentDesc.componentManufacturer = types[2]; + break; + } + + HUnlock (h); + ReleaseResource (h); + } + } + + CFBundleCloseBundleResourceMap (bundleRef, resFileId); + CFRelease (bundleRef); + } + } + + return componentDesc.componentType != 0 && componentDesc.componentSubType != 0; +} + +//============================================================================== +void AudioUnitPluginInstance::initialise() +{ + if (initialised || audioUnit == 0) + return; + + log (T("Initialising AU: ") + pluginName); + + parameterIds.clear(); + + { + UInt32 paramListSize = 0; + AudioUnitGetProperty (audioUnit, kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, + 0, 0, ¶mListSize); + + if (paramListSize > 0) + { + parameterIds.insertMultiple (0, 0, paramListSize / sizeof (int)); + + AudioUnitGetProperty (audioUnit, kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, + 0, ¶meterIds.getReference(0), ¶mListSize); + } + } + + { + AURenderCallbackStruct info; + zerostruct (info); + info.inputProcRefCon = this; + info.inputProc = renderGetInputCallback; + + AudioUnitSetProperty (audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, + 0, &info, sizeof (info)); + } + + { + HostCallbackInfo info; + zerostruct (info); + info.hostUserData = this; + info.beatAndTempoProc = getBeatAndTempoCallback; + info.musicalTimeLocationProc = getMusicalTimeLocationCallback; + info.transportStateProc = getTransportStateCallback; + + AudioUnitSetProperty (audioUnit, kAudioUnitProperty_HostCallbacks, kAudioUnitScope_Global, + 0, &info, sizeof (info)); + } + + int numIns, numOuts; + getNumChannels (numIns, numOuts); + setPlayConfigDetails (numIns, numOuts, 0, 0); + + initialised = AudioUnitInitialize (audioUnit) == noErr; + + setLatencySamples (0); +} + + +//============================================================================== +void AudioUnitPluginInstance::prepareToPlay (double sampleRate_, + int samplesPerBlockExpected) +{ + initialise(); + + if (initialised) + { + int numIns, numOuts; + getNumChannels (numIns, numOuts); + + setPlayConfigDetails (numIns, numOuts, sampleRate_, samplesPerBlockExpected); + + Float64 latencySecs = 0.0; + UInt32 latencySize = sizeof (latencySecs); + AudioUnitGetProperty (audioUnit, kAudioUnitProperty_Latency, kAudioUnitScope_Global, + 0, &latencySecs, &latencySize); + + setLatencySamples (roundDoubleToInt (latencySecs * sampleRate_)); + + AudioUnitReset (audioUnit, kAudioUnitScope_Input, 0); + AudioUnitReset (audioUnit, kAudioUnitScope_Output, 0); + AudioUnitReset (audioUnit, kAudioUnitScope_Global, 0); + + AudioStreamBasicDescription stream; + zerostruct (stream); + stream.mSampleRate = sampleRate_; + stream.mFormatID = kAudioFormatLinearPCM; + stream.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved; + stream.mFramesPerPacket = 1; + stream.mBytesPerPacket = 4; + stream.mBytesPerFrame = 4; + stream.mBitsPerChannel = 32; + stream.mChannelsPerFrame = numIns; + + OSStatus err = AudioUnitSetProperty (audioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 0, &stream, sizeof (stream)); + + stream.mChannelsPerFrame = numOuts; + + err = AudioUnitSetProperty (audioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + 0, &stream, sizeof (stream)); + + juce_free (outputBufferList); + outputBufferList = (AudioBufferList*) juce_calloc (sizeof (AudioBufferList) + sizeof (AudioBuffer) * (numOuts + 1)); + outputBufferList->mNumberBuffers = numOuts; + + for (int i = numOuts; --i >= 0;) + outputBufferList->mBuffers[i].mNumberChannels = 1; + + zerostruct (timeStamp); + timeStamp.mSampleTime = 0; + timeStamp.mHostTime = AudioGetCurrentHostTime(); + timeStamp.mFlags = kAudioTimeStampSampleTimeValid | kAudioTimeStampHostTimeValid; + + currentBuffer = 0; + wasPlaying = false; + } +} + +void AudioUnitPluginInstance::releaseResources() +{ + if (initialised) + { + AudioUnitReset (audioUnit, kAudioUnitScope_Input, 0); + AudioUnitReset (audioUnit, kAudioUnitScope_Output, 0); + AudioUnitReset (audioUnit, kAudioUnitScope_Global, 0); + + juce_free (outputBufferList); + outputBufferList = 0; + currentBuffer = 0; + } +} + +OSStatus AudioUnitPluginInstance::renderGetInput (AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList* ioData) const +{ + if (inBusNumber == 0 + && currentBuffer != 0) + { + jassert (inNumberFrames == currentBuffer->getNumSamples()); // if this ever happens, might need to add extra handling + + for (int i = 0; i < ioData->mNumberBuffers; ++i) + { + if (i < currentBuffer->getNumChannels()) + { + memcpy (ioData->mBuffers[i].mData, + currentBuffer->getSampleData (i, 0), + sizeof (float) * inNumberFrames); + } + else + { + zeromem (ioData->mBuffers[i].mData, sizeof (float) * inNumberFrames); + } + } + } + + return noErr; +} + +void AudioUnitPluginInstance::processBlock (AudioSampleBuffer& buffer, + MidiBuffer& midiMessages) +{ + const int numSamples = buffer.getNumSamples(); + + if (initialised) + { + AudioUnitRenderActionFlags flags = 0; + + timeStamp.mHostTime = AudioGetCurrentHostTime(); + + for (int i = getNumOutputChannels(); --i >= 0;) + { + outputBufferList->mBuffers[i].mDataByteSize = sizeof (float) * numSamples; + outputBufferList->mBuffers[i].mData = buffer.getSampleData (i, 0); + } + + currentBuffer = &buffer; + + if (wantsMidiMessages) + { + const uint8* midiEventData; + int midiEventSize, midiEventPosition; + MidiBuffer::Iterator i (midiMessages); + + while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition)) + { + if (midiEventSize <= 3) + MusicDeviceMIDIEvent (audioUnit, + midiEventData[0], midiEventData[1], midiEventData[2], + midiEventPosition); + else + MusicDeviceSysEx (audioUnit, midiEventData, midiEventSize); + } + + midiMessages.clear(); + } + + AudioUnitRender (audioUnit, &flags, &timeStamp, + 0, numSamples, outputBufferList); + + timeStamp.mSampleTime += numSamples; + } + else + { + // Not initialised, so just bypass.. + for (int i = getNumInputChannels(); i < getNumOutputChannels(); ++i) + buffer.clear (i, 0, buffer.getNumSamples()); + } +} + +//============================================================================== +OSStatus AudioUnitPluginInstance::getBeatAndTempo (Float64* outCurrentBeat, Float64* outCurrentTempo) const +{ + AudioPlayHead* const ph = getPlayHead(); + AudioPlayHead::CurrentPositionInfo result; + + if (ph != 0 && ph->getCurrentPosition (result)) + { + *outCurrentBeat = result.ppqPosition; + *outCurrentTempo = result.bpm; + } + else + { + *outCurrentBeat = 0; + *outCurrentTempo = 120.0; + } + + return noErr; +} + +OSStatus AudioUnitPluginInstance::getMusicalTimeLocation (UInt32* outDeltaSampleOffsetToNextBeat, + Float32* outTimeSig_Numerator, + UInt32* outTimeSig_Denominator, + Float64* outCurrentMeasureDownBeat) const +{ + AudioPlayHead* const ph = getPlayHead(); + AudioPlayHead::CurrentPositionInfo result; + + if (ph != 0 && ph->getCurrentPosition (result)) + { + *outTimeSig_Numerator = result.timeSigNumerator; + *outTimeSig_Denominator = result.timeSigDenominator; + + *outDeltaSampleOffsetToNextBeat = 0; //xxx + *outCurrentMeasureDownBeat = result.ppqPositionOfLastBarStart; //xxx wrong + } + else + { + *outDeltaSampleOffsetToNextBeat = 0; + *outTimeSig_Numerator = 4; + *outTimeSig_Denominator = 4; + *outCurrentMeasureDownBeat = 0; + } + + return noErr; +} + +OSStatus AudioUnitPluginInstance::getTransportState (Boolean* outIsPlaying, + Boolean* outTransportStateChanged, + Float64* outCurrentSampleInTimeLine, + Boolean* outIsCycling, + Float64* outCycleStartBeat, + Float64* outCycleEndBeat) +{ + AudioPlayHead* const ph = getPlayHead(); + AudioPlayHead::CurrentPositionInfo result; + + if (ph != 0 && ph->getCurrentPosition (result)) + { + *outIsPlaying = result.isPlaying; + *outTransportStateChanged = result.isPlaying != wasPlaying; + wasPlaying = result.isPlaying; + *outCurrentSampleInTimeLine = roundDoubleToInt (result.timeInSeconds * getSampleRate()); + *outIsCycling = false; + *outCycleStartBeat = 0; + *outCycleEndBeat = 0; + } + else + { + *outIsPlaying = false; + *outTransportStateChanged = false; + *outCurrentSampleInTimeLine = 0; + *outIsCycling = false; + *outCycleStartBeat = 0; + *outCycleEndBeat = 0; + } + + return noErr; +} + + +//============================================================================== +static VoidArray activeWindows; + +//============================================================================== +class AudioUnitPluginWindow : public AudioProcessorEditor, + public Timer +{ +public: + //============================================================================== + AudioUnitPluginWindow (AudioUnitPluginInstance& plugin_) + : AudioProcessorEditor (&plugin_), + plugin (plugin_), + isOpen (false), + pluginWantsKeys (false), + wasShowing (false), + recursiveResize (false), + viewComponent (0), + pluginViewRef (0) + { + movementWatcher = new CompMovementWatcher (this); + + activeWindows.add (this); + + setOpaque (true); + setVisible (true); + setSize (1, 1); + + ComponentDescription viewList [16]; + UInt32 viewListSize = sizeof (viewList); + AudioUnitGetProperty (plugin.audioUnit, kAudioUnitProperty_GetUIComponentList, kAudioUnitScope_Global, + 0, &viewList, &viewListSize); + + componentRecord = FindNextComponent (0, &viewList[0]); + } + + ~AudioUnitPluginWindow() + { + deleteAndZero (movementWatcher); + + closePluginWindow(); + + activeWindows.removeValue (this); + plugin.editorBeingDeleted (this); + } + + bool isValid() const throw() { return componentRecord != 0; } + + //============================================================================== + void componentMovedOrResized() + { + if (recursiveResize) + return; + + Component* const topComp = getTopLevelComponent(); + + if (topComp->getPeer() != 0) + { + int x = 0, y = 0; + relativePositionToOtherComponent (topComp, x, y); + + recursiveResize = true; + + if (pluginViewRef != 0) + { + HIRect r; + r.origin.x = (float) x; + r.origin.y = (float) y; + r.size.width = (float) getWidth(); + r.size.height = (float) getHeight(); + HIViewSetFrame (pluginViewRef, &r); + } + + recursiveResize = false; + } + } + + void componentVisibilityChanged() + { + const bool isShowingNow = isShowing(); + + if (wasShowing != isShowingNow) + { + wasShowing = isShowingNow; + + if (isShowingNow) + openPluginWindow(); + else + closePluginWindow(); + } + + componentMovedOrResized(); + } + + void componentPeerChanged() + { + closePluginWindow(); + openPluginWindow(); + } + + void timerCallback() + { + if (pluginViewRef != 0) + { + HIRect bounds; + HIViewGetBounds (pluginViewRef, &bounds); + const int w = jmax (32, (int) bounds.size.width); + const int h = jmax (32, (int) bounds.size.height); + + if (w != getWidth() || h != getHeight()) + { + setSize (w, h); + startTimer (50); + } + else + { + startTimer (jlimit (50, 500, getTimerInterval() + 20)); + } + } + } + + //============================================================================== + bool keyStateChanged() + { + return pluginWantsKeys; + } + + bool keyPressed (const KeyPress&) + { + return pluginWantsKeys; + } + + //============================================================================== + void paint (Graphics& g) + { + if (isOpen) + { + ComponentPeer* const peer = getPeer(); + + if (peer != 0) + { + peer->addMaskedRegion (getScreenX() - peer->getScreenX(), + getScreenY() - peer->getScreenY(), + getWidth(), getHeight()); + } + } + else + { + g.fillAll (Colours::black); + } + } + + //============================================================================== + void broughtToFront() + { + activeWindows.removeValue (this); + activeWindows.add (this); + } + + //============================================================================== + juce_UseDebuggingNewOperator + +private: + AudioUnitPluginInstance& plugin; + bool isOpen, wasShowing, recursiveResize; + bool pluginWantsKeys; + + ComponentRecord* componentRecord; + AudioUnitCarbonView viewComponent; + HIViewRef pluginViewRef; + + //============================================================================== + void openPluginWindow() + { + if (isOpen || getWindowHandle() == 0 || componentRecord == 0) + return; + + log (T("Opening AU GUI: ") + plugin.getName()); + isOpen = true; + + pluginWantsKeys = true; //xxx any way to find this out? Does it matter? + + viewComponent = (AudioUnitCarbonView) OpenComponent (componentRecord); + + if (viewComponent != 0) + { + Float32Point pos = { getScreenX() - getTopLevelComponent()->getScreenX(), + getScreenY() - getTopLevelComponent()->getScreenY() }; + Float32Point size = { 250, 200 }; + + AudioUnitCarbonViewCreate (viewComponent, + plugin.audioUnit, + (WindowRef) getWindowHandle(), + HIViewGetRoot ((WindowRef) getWindowHandle()), + &pos, &size, + (ControlRef*) &pluginViewRef); + } + + timerCallback(); // to set our comp to the right size + repaint(); + } + + //============================================================================== + void closePluginWindow() + { + stopTimer(); + + if (isOpen) + { + log (T("Closing AU GUI: ") + plugin.getName()); + isOpen = false; + + if (viewComponent != 0) + CloseComponent (viewComponent); + + pluginViewRef = 0; + } + } + + //============================================================================== + class CompMovementWatcher : public ComponentMovementWatcher + { + public: + CompMovementWatcher (AudioUnitPluginWindow* const owner_) + : ComponentMovementWatcher (owner_), + owner (owner_) + { + } + + //============================================================================== + void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) + { + owner->componentMovedOrResized(); + } + + void componentPeerChanged() + { + owner->componentPeerChanged(); + } + + void componentVisibilityChanged (Component&) + { + owner->componentVisibilityChanged(); + } + + private: + AudioUnitPluginWindow* const owner; + }; + + CompMovementWatcher* movementWatcher; +}; + +//============================================================================== +AudioProcessorEditor* AudioUnitPluginInstance::createEditor() +{ + AudioUnitPluginWindow* w = new AudioUnitPluginWindow (*this); + + if (! w->isValid()) + deleteAndZero (w); + + return w; +} + + +//============================================================================== +const String AudioUnitPluginInstance::getCategory() const +{ + const char* result = 0; + + switch (componentDesc.componentType) + { + case kAudioUnitType_Effect: + case kAudioUnitType_MusicEffect: + result = "Effect"; + break; + case kAudioUnitType_MusicDevice: + result = "Synth"; + break; + case kAudioUnitType_Generator: + result = "Generator"; + break; + case kAudioUnitType_Panner: + result = "Panner"; + break; + default: + break; + } + + return result; +} + +//============================================================================== +int AudioUnitPluginInstance::getNumParameters() +{ + return parameterIds.size(); +} + +float AudioUnitPluginInstance::getParameter (int index) +{ + const ScopedLock sl (lock); + + Float32 value = 0.0f; + + if (audioUnit != 0 && ((unsigned int) index) < (unsigned int) parameterIds.size()) + { + AudioUnitGetParameter (audioUnit, + (UInt32) parameterIds.getUnchecked (index), + kAudioUnitScope_Global, 0, + &value); + } + + return value; +} + +void AudioUnitPluginInstance::setParameter (int index, float newValue) +{ + const ScopedLock sl (lock); + + if (audioUnit != 0 && ((unsigned int) index) < (unsigned int) parameterIds.size()) + { + AudioUnitSetParameter (audioUnit, + (UInt32) parameterIds.getUnchecked (index), + kAudioUnitScope_Global, 0, + newValue, 0); + } +} + +const String AudioUnitPluginInstance::getParameterName (int index) +{ + AudioUnitParameterInfo info; + zerostruct (info); + UInt32 sz = sizeof (info); + + String name; + + if (AudioUnitGetProperty (audioUnit, + kAudioUnitProperty_ParameterInfo, + kAudioUnitScope_Global, + parameterIds [index], &info, &sz) == noErr) + { + if ((info.flags & kAudioUnitParameterFlag_HasCFNameString) != 0) + name = PlatformUtilities::cfStringToJuceString (info.cfNameString); + else + name = String (info.name, sizeof (info.name)); + } + + return name; +} + +const String AudioUnitPluginInstance::getParameterText (int index) +{ + return String (getParameter (index)); +} + +bool AudioUnitPluginInstance::isParameterAutomatable (int index) const +{ + AudioUnitParameterInfo info; + UInt32 sz = sizeof (info); + + if (AudioUnitGetProperty (audioUnit, + kAudioUnitProperty_ParameterInfo, + kAudioUnitScope_Global, + parameterIds [index], &info, &sz) == noErr) + { + return (info.flags & kAudioUnitParameterFlag_NonRealTime) == 0; + } + + return true; +} + +//============================================================================== +int AudioUnitPluginInstance::getNumPrograms() +{ + CFArrayRef presets; + UInt32 sz = sizeof (CFArrayRef); + int num = 0; + + if (AudioUnitGetProperty (audioUnit, + kAudioUnitProperty_FactoryPresets, + kAudioUnitScope_Global, + 0, &presets, &sz) == noErr) + { + num = (int) CFArrayGetCount (presets); + CFRelease (presets); + } + + return num; +} + +int AudioUnitPluginInstance::getCurrentProgram() +{ + AUPreset current; + current.presetNumber = 0; + UInt32 sz = sizeof (AUPreset); + + AudioUnitGetProperty (audioUnit, + kAudioUnitProperty_FactoryPresets, + kAudioUnitScope_Global, + 0, ¤t, &sz); + + return current.presetNumber; +} + +void AudioUnitPluginInstance::setCurrentProgram (int newIndex) +{ + AUPreset current; + current.presetNumber = newIndex; + current.presetName = 0; + + AudioUnitSetProperty (audioUnit, + kAudioUnitProperty_FactoryPresets, + kAudioUnitScope_Global, + 0, ¤t, sizeof (AUPreset)); +} + +const String AudioUnitPluginInstance::getProgramName (int index) +{ + String s; + CFArrayRef presets; + UInt32 sz = sizeof (CFArrayRef); + + if (AudioUnitGetProperty (audioUnit, + kAudioUnitProperty_FactoryPresets, + kAudioUnitScope_Global, + 0, &presets, &sz) == noErr) + { + for (CFIndex i = 0; i < CFArrayGetCount (presets); ++i) + { + const AUPreset* p = (const AUPreset*) CFArrayGetValueAtIndex (presets, i); + + if (p != 0 && p->presetNumber == index) + { + s = PlatformUtilities::cfStringToJuceString (p->presetName); + break; + } + } + + CFRelease (presets); + } + + return s; +} + +void AudioUnitPluginInstance::changeProgramName (int index, const String& newName) +{ + jassertfalse // xxx not implemented! +} + +//============================================================================== +const String AudioUnitPluginInstance::getInputChannelName (const int index) const +{ + if (((unsigned int) index) < (unsigned int) getNumInputChannels()) + return T("Input ") + String (index + 1); + + return String::empty; +} + +bool AudioUnitPluginInstance::isInputChannelStereoPair (int index) const +{ + if (((unsigned int) index) >= (unsigned int) getNumInputChannels()) + return false; + + + return true; +} + +const String AudioUnitPluginInstance::getOutputChannelName (const int index) const +{ + if (((unsigned int) index) < (unsigned int) getNumOutputChannels()) + return T("Output ") + String (index + 1); + + return String::empty; +} + +bool AudioUnitPluginInstance::isOutputChannelStereoPair (int index) const +{ + if (((unsigned int) index) >= (unsigned int) getNumOutputChannels()) + return false; + + return true; +} + +//============================================================================== +void AudioUnitPluginInstance::getStateInformation (MemoryBlock& destData) +{ + getCurrentProgramStateInformation (destData); +} + +void AudioUnitPluginInstance::getCurrentProgramStateInformation (MemoryBlock& destData) +{ + CFPropertyListRef propertyList = 0; + UInt32 sz = sizeof (CFPropertyListRef); + + if (AudioUnitGetProperty (audioUnit, + kAudioUnitProperty_ClassInfo, + kAudioUnitScope_Global, + 0, &propertyList, &sz) == noErr) + { + CFWriteStreamRef stream = CFWriteStreamCreateWithAllocatedBuffers (kCFAllocatorDefault, kCFAllocatorDefault); + CFWriteStreamOpen (stream); + + CFIndex bytesWritten = CFPropertyListWriteToStream (propertyList, stream, kCFPropertyListBinaryFormat_v1_0, 0); + CFWriteStreamClose (stream); + + CFDataRef data = (CFDataRef) CFWriteStreamCopyProperty (stream, kCFStreamPropertyDataWritten); + + destData.setSize (bytesWritten); + destData.copyFrom (CFDataGetBytePtr (data), 0, destData.getSize()); + CFRelease (data); + + CFRelease (stream); + CFRelease (propertyList); + } +} + +void AudioUnitPluginInstance::setStateInformation (const void* data, int sizeInBytes) +{ + setCurrentProgramStateInformation (data, sizeInBytes); +} + +void AudioUnitPluginInstance::setCurrentProgramStateInformation (const void* data, int sizeInBytes) +{ + CFReadStreamRef stream = CFReadStreamCreateWithBytesNoCopy (kCFAllocatorDefault, + (const UInt8*) data, + sizeInBytes, + kCFAllocatorNull); + CFReadStreamOpen (stream); + + CFPropertyListFormat format = kCFPropertyListBinaryFormat_v1_0; + CFPropertyListRef propertyList = CFPropertyListCreateFromStream (kCFAllocatorDefault, + stream, + 0, + kCFPropertyListImmutable, + &format, + 0); + CFRelease (stream); + + if (propertyList != 0) + AudioUnitSetProperty (audioUnit, + kAudioUnitProperty_ClassInfo, + kAudioUnitScope_Global, + 0, &propertyList, sizeof (propertyList)); +} + +//============================================================================== +//============================================================================== +AudioUnitPluginFormat::AudioUnitPluginFormat() +{ +} + +AudioUnitPluginFormat::~AudioUnitPluginFormat() +{ +} + +void AudioUnitPluginFormat::findAllTypesForFile (OwnedArray & results, + const File& file) +{ + if (! fileMightContainThisPluginType (file)) + return; + + PluginDescription desc; + desc.file = file; + desc.uid = 0; + + AudioUnitPluginInstance* instance = dynamic_cast (createInstanceFromDescription (desc)); + + if (instance == 0) + return; + + try + { + instance->fillInPluginDescription (desc); + results.add (new PluginDescription (desc)); + } + catch (...) + { + // crashed while loading... + } + + deleteAndZero (instance); +} + +AudioPluginInstance* AudioUnitPluginFormat::createInstanceFromDescription (const PluginDescription& desc) +{ + AudioUnitPluginInstance* result = 0; + + if (fileMightContainThisPluginType (desc.file)) + { + result = new AudioUnitPluginInstance (desc.file); + + if (result->audioUnit != 0) + { + result->initialise(); + } + else + { + deleteAndZero (result); + } + } + + return result; +} + +bool AudioUnitPluginFormat::fileMightContainThisPluginType (const File& f) +{ + return f.hasFileExtension (T(".component")) + && f.isDirectory(); +} + +const FileSearchPath AudioUnitPluginFormat::getDefaultLocationsToSearch() +{ + return FileSearchPath ("~/Library/Audio/Plug-Ins/Components;/Library/Audio/Plug-Ins/Components"); +} + +#endif + +END_JUCE_NAMESPACE + +#endif diff --git a/src/juce_appframework/audio/plugins/formats/juce_VSTPluginFormat.cpp b/src/juce_appframework/audio/plugins/formats/juce_VSTPluginFormat.cpp index ef4e4a55a8..a035b15035 100644 --- a/src/juce_appframework/audio/plugins/formats/juce_VSTPluginFormat.cpp +++ b/src/juce_appframework/audio/plugins/formats/juce_VSTPluginFormat.cpp @@ -1,3019 +1,3015 @@ -/* - ============================================================================== - - This file is part of the JUCE library - "Jules' Utility Class Extensions" - Copyright 2004-7 by Raw Material Software ltd. - - ------------------------------------------------------------------------------ - - JUCE can be redistributed and/or modified under the terms of the - GNU General Public License, as published by the Free Software Foundation; - either version 2 of the License, or (at your option) any later version. - - 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. - - You should have received a copy of the GNU General Public License - along with JUCE; if not, visit www.gnu.org/licenses or write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA - - ------------------------------------------------------------------------------ - - If you'd like to release a closed-source product which uses JUCE, commercial - licenses are also available: visit www.rawmaterialsoftware.com/juce for - more information. - - ============================================================================== -*/ - -#include "../../../../../juce_Config.h" - -#if JUCE_PLUGINHOST_VST - -#ifdef _WIN32 - #define _WIN32_WINNT 0x500 - #define STRICT - #include - #include - #pragma warning (disable : 4312) -#elif defined (LINUX) - #include - #include - #include - #include - #include - #undef Font - #undef KeyPress - #undef Drawable - #undef Time -#else - #include -#endif - -//============================================================================== -#include "../../../../juce_core/basics/juce_StandardHeader.h" - -BEGIN_JUCE_NAMESPACE - -#include "juce_VSTPluginFormat.h" -#include "../../../../juce_core/threads/juce_Process.h" -#include "../../../../juce_core/threads/juce_ScopedLock.h" -#include "../../../../juce_core/basics/juce_Random.h" -#include "../../../events/juce_Timer.h" -#include "../../../events/juce_AsyncUpdater.h" -#include "../../../events/juce_MessageManager.h" -#include "../../../gui/components/layout/juce_ComponentMovementWatcher.h" -#include "../../../application/juce_Application.h" - - -//============================================================================== -#undef PRAGMA_ALIGN_SUPPORTED -#define VST_FORCE_DEPRECATED 0 - -#ifdef _MSC_VER - #pragma warning (push) - #pragma warning (disable: 4996) -#endif - -/* Obviously you're going to need the Steinberg vstsdk2.4 folder in - your include path if you want to add VST support. - - If you're not interested in VSTs, you can disable them by changing the - JUCE_PLUGINHOST_VST flag in juce_Config.h -*/ -#include "pluginterfaces/vst2.x/aeffectx.h" - -#ifdef _MSC_VER - #pragma warning (pop) -#endif - -//============================================================================== -#if JUCE_LINUX - #define Font JUCE_NAMESPACE::Font - #define KeyPress JUCE_NAMESPACE::KeyPress - #define Drawable JUCE_NAMESPACE::Drawable - #define Time JUCE_NAMESPACE::Time -#endif - -#include "../juce_PluginDescription.h" - -#if ! JUCE_WIN32 - #define _fpreset() - #define _clearfp() -#endif - -extern void juce_callAnyTimersSynchronously(); - - -//============================================================================== -const int fxbVersionNum = 1; - -struct fxProgram -{ - long chunkMagic; // 'CcnK' - long byteSize; // of this chunk, excl. magic + byteSize - long fxMagic; // 'FxCk' - long version; - long fxID; // fx unique id - long fxVersion; - long numParams; - char prgName[28]; - float params[1]; // variable no. of parameters -}; - -struct fxSet -{ - long chunkMagic; // 'CcnK' - long byteSize; // of this chunk, excl. magic + byteSize - long fxMagic; // 'FxBk' - long version; - long fxID; // fx unique id - long fxVersion; - long numPrograms; - char future[128]; - fxProgram programs[1]; // variable no. of programs -}; - -struct fxChunkSet -{ - long chunkMagic; // 'CcnK' - long byteSize; // of this chunk, excl. magic + byteSize - long fxMagic; // 'FxCh', 'FPCh', or 'FBCh' - long version; - long fxID; // fx unique id - long fxVersion; - long numPrograms; - char future[128]; - long chunkSize; - char chunk[8]; // variable -}; - -struct fxProgramSet -{ - long chunkMagic; // 'CcnK' - long byteSize; // of this chunk, excl. magic + byteSize - long fxMagic; // 'FxCh', 'FPCh', or 'FBCh' - long version; - long fxID; // fx unique id - long fxVersion; - long numPrograms; - char name[28]; - long chunkSize; - char chunk[8]; // variable -}; - - -#ifdef JUCE_LITTLE_ENDIAN - static long swap (const long x) throw() { return (long) swapByteOrder ((uint32) x); } - - static float swapFloat (const float x) throw() - { - union { uint32 asInt; float asFloat; } n; - n.asFloat = x; - n.asInt = swapByteOrder (n.asInt); - return n.asFloat; - } -#else - #define swap(x) (x) - #define swapFloat(x) (x) -#endif - -//============================================================================== -typedef AEffect* (*MainCall) (audioMasterCallback); - -static VstIntPtr VSTCALLBACK audioMaster (AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt); - -#if JUCE_PPC - static void* audioMasterCoerced = 0; -#endif - -static int shellUIDToCreate = 0; -static int insideVSTCallback = 0; - -class VSTPluginWindow; - -//============================================================================== -// Change this to disable logging of various VST activities -#ifndef VST_LOGGING - #define VST_LOGGING 1 -#endif - -#if VST_LOGGING - #define log(a) Logger::writeToLog(a); -#else - #define log(a) -#endif - -//============================================================================== -#if JUCE_MAC -extern bool juce_isHIViewCreatedByJuce (HIViewRef view); -extern bool juce_isWindowCreatedByJuce (WindowRef window); - -#if JUCE_PPC -static void* NewCFMFromMachO (void* const machofp) throw() -{ - void* result = juce_malloc (8); - - ((void**) result)[0] = machofp; - ((void**) result)[1] = result; - - return result; -} -#endif -#endif - -//============================================================================== -#if JUCE_LINUX - -extern Display* display; -extern XContext improbableNumber; - -typedef void (*EventProcPtr) (XEvent* ev); - -static bool xErrorTriggered; - -static int temporaryErrorHandler (Display*, XErrorEvent*) -{ - xErrorTriggered = true; - return 0; -} - -static int getPropertyFromXWindow (Window handle, Atom atom) -{ - XErrorHandler oldErrorHandler = XSetErrorHandler (temporaryErrorHandler); - xErrorTriggered = false; - - int userSize; - unsigned long bytes, userCount; - unsigned char* data; - Atom userType; - - XGetWindowProperty (display, handle, atom, 0, 1, false, AnyPropertyType, - &userType, &userSize, &userCount, &bytes, &data); - - XSetErrorHandler (oldErrorHandler); - - return (userCount == 1 && ! xErrorTriggered) ? *(int*) data - : 0; -} - -static Window getChildWindow (Window windowToCheck) -{ - Window rootWindow, parentWindow; - Window* childWindows; - unsigned int numChildren; - - XQueryTree (display, - windowToCheck, - &rootWindow, - &parentWindow, - &childWindows, - &numChildren); - - if (numChildren > 0) - return childWindows [0]; - - return 0; -} - -static void translateJuceToXButtonModifiers (const MouseEvent& e, XEvent& ev) throw() -{ - if (e.mods.isLeftButtonDown()) - { - ev.xbutton.button = Button1; - ev.xbutton.state |= Button1Mask; - } - else if (e.mods.isRightButtonDown()) - { - ev.xbutton.button = Button3; - ev.xbutton.state |= Button3Mask; - } - else if (e.mods.isMiddleButtonDown()) - { - ev.xbutton.button = Button2; - ev.xbutton.state |= Button2Mask; - } -} - -static void translateJuceToXMotionModifiers (const MouseEvent& e, XEvent& ev) throw() -{ - if (e.mods.isLeftButtonDown()) - ev.xmotion.state |= Button1Mask; - else if (e.mods.isRightButtonDown()) - ev.xmotion.state |= Button3Mask; - else if (e.mods.isMiddleButtonDown()) - ev.xmotion.state |= Button2Mask; -} - -static void translateJuceToXCrossingModifiers (const MouseEvent& e, XEvent& ev) throw() -{ - if (e.mods.isLeftButtonDown()) - ev.xcrossing.state |= Button1Mask; - else if (e.mods.isRightButtonDown()) - ev.xcrossing.state |= Button3Mask; - else if (e.mods.isMiddleButtonDown()) - ev.xcrossing.state |= Button2Mask; -} - -static void translateJuceToXMouseWheelModifiers (const MouseEvent& e, const float increment, XEvent& ev) throw() -{ - if (increment < 0) - { - ev.xbutton.button = Button5; - ev.xbutton.state |= Button5Mask; - } - else if (increment > 0) - { - ev.xbutton.button = Button4; - ev.xbutton.state |= Button4Mask; - } -} - -#endif - -//============================================================================== -static VoidArray activeModules; - -//============================================================================== -class ModuleHandle : public ReferenceCountedObject -{ -public: - //============================================================================== - File file; - MainCall moduleMain; - String pluginName; - - //============================================================================== - static ModuleHandle* findOrCreateModule (const File& file) - { - for (int i = activeModules.size(); --i >= 0;) - { - ModuleHandle* const module = (ModuleHandle*) activeModules.getUnchecked(i); - - if (module->file == file) - return module; - } - - _fpreset(); // (doesn't do any harm) - ++insideVSTCallback; - shellUIDToCreate = 0; - - log ("Attempting to load VST: " + file.getFullPathName()); - - ModuleHandle* m = new ModuleHandle (file); - - if (! m->open()) - deleteAndZero (m); - - --insideVSTCallback; - _fpreset(); // (doesn't do any harm) - - return m; - } - - //============================================================================== - ModuleHandle (const File& file_) - : file (file_), - moduleMain (0), -#if JUCE_WIN32 || JUCE_LINUX - hModule (0) -#elif JUCE_MAC - fragId (0), - resHandle (0), - bundleRef (0), - resFileId (0) -#endif - { - activeModules.add (this); - -#if JUCE_WIN32 || JUCE_LINUX - fullParentDirectoryPathName = file_.getParentDirectory().getFullPathName(); -#elif JUCE_MAC - PlatformUtilities::makeFSSpecFromPath (&parentDirFSSpec, file_.getParentDirectory().getFullPathName()); -#endif - } - - ~ModuleHandle() - { - activeModules.removeValue (this); - - close(); - } - - //============================================================================== - juce_UseDebuggingNewOperator - - //============================================================================== -#if JUCE_WIN32 || JUCE_LINUX - void* hModule; - String fullParentDirectoryPathName; - - bool open() - { -#if JUCE_WIN32 - static bool timePeriodSet = false; - - if (! timePeriodSet) - { - timePeriodSet = true; - timeBeginPeriod (2); - } -#endif - - pluginName = file.getFileNameWithoutExtension(); - - hModule = Process::loadDynamicLibrary (file.getFullPathName()); - - moduleMain = (MainCall) Process::getProcedureEntryPoint (hModule, "VSTPluginMain"); - - if (moduleMain == 0) - moduleMain = (MainCall) Process::getProcedureEntryPoint (hModule, "main"); - - return moduleMain != 0; - } - - void close() - { - _fpreset(); // (doesn't do any harm) - - Process::freeDynamicLibrary (hModule); - } - - void closeEffect (AEffect* eff) - { - eff->dispatcher (eff, effClose, 0, 0, 0, 0); - } - -#else - CFragConnectionID fragId; - Handle resHandle; - CFBundleRef bundleRef; - FSSpec parentDirFSSpec; - short resFileId; - - bool open() - { - bool ok = false; - const String filename (file.getFullPathName()); - - if (file.hasFileExtension (T(".vst"))) - { - const char* const utf8 = filename.toUTF8(); - CFURLRef url = CFURLCreateFromFileSystemRepresentation (0, (const UInt8*) utf8, - strlen (utf8), file.isDirectory()); - - if (url != 0) - { - bundleRef = CFBundleCreate (kCFAllocatorDefault, url); - CFRelease (url); - - if (bundleRef != 0) - { - if (CFBundleLoadExecutable (bundleRef)) - { - moduleMain = (MainCall) CFBundleGetFunctionPointerForName (bundleRef, CFSTR("main_macho")); - - if (moduleMain == 0) - moduleMain = (MainCall) CFBundleGetFunctionPointerForName (bundleRef, CFSTR("VSTPluginMain")); - - if (moduleMain != 0) - { - CFTypeRef name = CFBundleGetValueForInfoDictionaryKey (bundleRef, CFSTR("CFBundleName")); - - if (name != 0) - { - if (CFGetTypeID (name) == CFStringGetTypeID()) - { - char buffer[1024]; - - if (CFStringGetCString ((CFStringRef) name, buffer, sizeof (buffer), CFStringGetSystemEncoding())) - pluginName = buffer; - } - } - - if (pluginName.isEmpty()) - pluginName = file.getFileNameWithoutExtension(); - - resFileId = CFBundleOpenBundleResourceMap (bundleRef); - - ok = true; - } - } - - if (! ok) - { - CFBundleUnloadExecutable (bundleRef); - CFRelease (bundleRef); - bundleRef = 0; - } - } - } - } -#if JUCE_PPC - else - { - FSRef fn; - - if (FSPathMakeRef ((UInt8*) (const char*) filename, &fn, 0) == noErr) - { - resFileId = FSOpenResFile (&fn, fsRdPerm); - - if (resFileId != -1) - { - const int numEffs = Count1Resources ('aEff'); - - for (int i = 0; i < numEffs; ++i) - { - resHandle = Get1IndResource ('aEff', i + 1); - - if (resHandle != 0) - { - OSType type; - Str255 name; - SInt16 id; - GetResInfo (resHandle, &id, &type, name); - pluginName = String ((const char*) name + 1, name[0]); - DetachResource (resHandle); - HLock (resHandle); - - Ptr ptr; - Str255 errorText; - - OSErr err = GetMemFragment (*resHandle, GetHandleSize (resHandle), - name, kPrivateCFragCopy, - &fragId, &ptr, errorText); - - if (err == noErr) - { - moduleMain = (MainCall) newMachOFromCFM (ptr); - ok = true; - } - else - { - HUnlock (resHandle); - } - - break; - } - } - - if (! ok) - CloseResFile (resFileId); - } - } - } -#endif - - return ok; - } - - void close() - { -#if JUCE_PPC - if (fragId != 0) - { - if (moduleMain != 0) - disposeMachOFromCFM ((void*) moduleMain); - - CloseConnection (&fragId); - HUnlock (resHandle); - - if (resFileId != 0) - CloseResFile (resFileId); - } - else -#endif - if (bundleRef != 0) - { - CFBundleCloseBundleResourceMap (bundleRef, resFileId); - - if (CFGetRetainCount (bundleRef) == 1) - CFBundleUnloadExecutable (bundleRef); - - if (CFGetRetainCount (bundleRef) > 0) - CFRelease (bundleRef); - } - } - - void closeEffect (AEffect* eff) - { -#if JUCE_PPC - if (fragId != 0) - { - VoidArray thingsToDelete; - thingsToDelete.add ((void*) eff->dispatcher); - thingsToDelete.add ((void*) eff->process); - thingsToDelete.add ((void*) eff->setParameter); - thingsToDelete.add ((void*) eff->getParameter); - thingsToDelete.add ((void*) eff->processReplacing); - - eff->dispatcher (eff, effClose, 0, 0, 0, 0); - - for (int i = thingsToDelete.size(); --i >= 0;) - disposeMachOFromCFM (thingsToDelete[i]); - } - else -#endif - { - eff->dispatcher (eff, effClose, 0, 0, 0, 0); - } - } - -#if JUCE_PPC - static void* newMachOFromCFM (void* cfmfp) - { - if (cfmfp == 0) - return 0; - - UInt32* const mfp = (UInt32*) juce_malloc (sizeof (UInt32) * 6); - - mfp[0] = 0x3d800000 | ((UInt32) cfmfp >> 16); - mfp[1] = 0x618c0000 | ((UInt32) cfmfp & 0xffff); - mfp[2] = 0x800c0000; - mfp[3] = 0x804c0004; - mfp[4] = 0x7c0903a6; - mfp[5] = 0x4e800420; - - MakeDataExecutable (mfp, sizeof (UInt32) * 6); - return mfp; - } - - static void disposeMachOFromCFM (void* ptr) - { - juce_free (ptr); - } - - void coerceAEffectFunctionCalls (AEffect* eff) - { - if (fragId != 0) - { - eff->dispatcher = (AEffectDispatcherProc) newMachOFromCFM ((void*) eff->dispatcher); - eff->process = (AEffectProcessProc) newMachOFromCFM ((void*) eff->process); - eff->setParameter = (AEffectSetParameterProc) newMachOFromCFM ((void*) eff->setParameter); - eff->getParameter = (AEffectGetParameterProc) newMachOFromCFM ((void*) eff->getParameter); - eff->processReplacing = (AEffectProcessProc) newMachOFromCFM ((void*) eff->processReplacing); - } - } -#endif - -#endif -}; - - -//============================================================================== -/** - An instance of a plugin, created by a VSTPluginFormat. - -*/ -class VSTPluginInstance : public AudioPluginInstance, - private Timer, - private AsyncUpdater -{ -public: - //============================================================================== - ~VSTPluginInstance(); - - //============================================================================== - // AudioPluginInstance methods: - - void fillInPluginDescription (PluginDescription& desc) const - { - desc.name = name; - desc.file = module->file; - desc.uid = getUID(); - desc.lastFileModTime = desc.file.getLastModificationTime(); - desc.pluginFormatName = "VST"; - desc.category = getCategory(); - - { - char buffer [kVstMaxVendorStrLen + 8]; - zerostruct (buffer); - dispatch (effGetVendorString, 0, 0, buffer, 0); - desc.manufacturerName = buffer; - } - - desc.version = getVersion(); - desc.numInputChannels = getNumInputChannels(); - desc.numOutputChannels = getNumOutputChannels(); - desc.isInstrument = (effect != 0 && (effect->flags & effFlagsIsSynth) != 0); - } - - const String getName() const { return name; } - int getUID() const throw(); - bool acceptsMidi() const { return wantsMidiMessages; } - bool producesMidi() const { return dispatch (effCanDo, 0, 0, (void*) "sendVstMidiEvent", 0) > 0; } - - //============================================================================== - // AudioProcessor methods: - - void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock); - void releaseResources(); - void processBlock (AudioSampleBuffer& buffer, - MidiBuffer& midiMessages); - - AudioProcessorEditor* createEditor(); - - const String getInputChannelName (const int index) const; - bool isInputChannelStereoPair (int index) const; - - const String getOutputChannelName (const int index) const; - bool isOutputChannelStereoPair (int index) const; - - //============================================================================== - int getNumParameters() { return effect != 0 ? effect->numParams : 0; } - float getParameter (int index); - void setParameter (int index, float newValue); - const String getParameterName (int index); - const String getParameterText (int index); - bool isParameterAutomatable (int index) const; - - //============================================================================== - int getNumPrograms() { return effect != 0 ? effect->numPrograms : 0; } - int getCurrentProgram() { return dispatch (effGetProgram, 0, 0, 0, 0); } - void setCurrentProgram (int index); - const String getProgramName (int index); - void changeProgramName (int index, const String& newName); - - //============================================================================== - void getStateInformation (MemoryBlock& destData); - void getCurrentProgramStateInformation (MemoryBlock& destData); - void setStateInformation (const void* data, int sizeInBytes); - void setCurrentProgramStateInformation (const void* data, int sizeInBytes); - - //============================================================================== - void timerCallback(); - void handleAsyncUpdate(); - VstIntPtr handleCallback (VstInt32 opcode, VstInt32 index, VstInt32 value, void *ptr, float opt); - - //============================================================================== - juce_UseDebuggingNewOperator - -private: - friend class VSTPluginWindow; - friend class VSTPluginFormat; - - AEffect* effect; - String name; - CriticalSection lock; - bool wantsMidiMessages, initialised, isPowerOn; - mutable StringArray programNames; - AudioSampleBuffer tempBuffer; - CriticalSection midiInLock; - MidiBuffer incomingMidi; - void* midiEventsToSend; - int numAllocatedMidiEvents; - VstTimeInfo vstHostTime; - float** channels; - - ReferenceCountedObjectPtr module; - - //============================================================================== - int dispatch (const int opcode, const int index, const int value, void* const ptr, float opt) const; - bool restoreProgramSettings (const fxProgram* const prog); - const String getCurrentProgramName(); - void setParamsInProgramBlock (fxProgram* const prog) throw(); - void updateStoredProgramNames(); - void initialise(); - void ensureMidiEventSize (int numEventsNeeded); - void freeMidiEvents(); - void handleMidiFromPlugin (const VstEvents* const events); - void createTempParameterStore (MemoryBlock& dest); - void restoreFromTempParameterStore (const MemoryBlock& mb); - const String getParameterLabel (int index) const; - - bool usesChunks() const throw() { return effect != 0 && (effect->flags & effFlagsProgramChunks) != 0; } - void getChunkData (MemoryBlock& mb, bool isPreset, int maxSizeMB) const; - void setChunkData (const char* data, int size, bool isPreset); - bool loadFromFXBFile (const void* data, int numBytes); - bool saveToFXBFile (MemoryBlock& dest, bool isFXB, int maxSizeMB); - - int getVersionNumber() const throw() { return effect != 0 ? effect->version : 0; } - const String getVersion() const throw(); - const String getCategory() const throw(); - - bool hasEditor() const throw() { return effect != 0 && (effect->flags & effFlagsHasEditor) != 0; } - void setPower (const bool on); - - VSTPluginInstance (const ReferenceCountedObjectPtr & module); -}; - -//============================================================================== -VSTPluginInstance::VSTPluginInstance (const ReferenceCountedObjectPtr & module_) - : effect (0), - wantsMidiMessages (false), - initialised (false), - isPowerOn (false), - numAllocatedMidiEvents (0), - midiEventsToSend (0), - tempBuffer (1, 1), - channels (0), - module (module_) -{ - try - { - _fpreset(); - - ++insideVSTCallback; - - name = module->pluginName; - log (T("Creating VST instance: ") + name); - -#if JUCE_MAC - if (module->resFileId != 0) - UseResFile (module->resFileId); - -#if JUCE_PPC - if (module->fragId != 0) - { - static void* audioMasterCoerced = 0; - if (audioMasterCoerced == 0) - audioMasterCoerced = NewCFMFromMachO ((void*) &audioMaster); - - effect = module->moduleMain ((audioMasterCallback) audioMasterCoerced); - } - else -#endif -#endif - { - effect = module->moduleMain (&audioMaster); - } - - --insideVSTCallback; - - if (effect != 0 && effect->magic == kEffectMagic) - { -#if JUCE_PPC - module->coerceAEffectFunctionCalls (effect); -#endif - - jassert (effect->resvd2 == 0); - jassert (effect->object != 0); - - _fpreset(); // some dodgy plugs fuck around with this - } - else - { - effect = 0; - } - } - catch (...) - { - --insideVSTCallback; - } -} - -VSTPluginInstance::~VSTPluginInstance() -{ - { - const ScopedLock sl (lock); - - jassert (insideVSTCallback == 0); - - if (effect != 0 && effect->magic == kEffectMagic) - { - try - { -#if JUCE_MAC - if (module->resFileId != 0) - UseResFile (module->resFileId); -#endif - - // Must delete any editors before deleting the plugin instance! - jassert (getActiveEditor() == 0); - - _fpreset(); // some dodgy plugs fuck around with this - - module->closeEffect (effect); - } - catch (...) - {} - } - - module = 0; - effect = 0; - } - - freeMidiEvents(); - - juce_free (channels); - channels = 0; -} - -//============================================================================== -void VSTPluginInstance::initialise() -{ - if (initialised || effect == 0) - return; - - log (T("Initialising VST: ") + module->pluginName); - initialised = true; - - dispatch (effIdentify, 0, 0, 0, 0); - - // this code would ask the plugin for its name, but so few plugins - // actually bother implementing this correctly, that it's better to - // just ignore it and use the file name instead. -/* { - char buffer [256]; - zerostruct (buffer); - dispatch (effGetEffectName, 0, 0, buffer, 0); - - name = String (buffer).trim(); - if (name.isEmpty()) - name = module->pluginName; - } -*/ - - if (getSampleRate() > 0) - dispatch (effSetSampleRate, 0, 0, 0, (float) getSampleRate()); - - if (getBlockSize() > 0) - dispatch (effSetBlockSize, 0, jmax (32, getBlockSize()), 0, 0); - - dispatch (effOpen, 0, 0, 0, 0); - - setPlayConfigDetails (effect->numInputs, effect->numOutputs, - getSampleRate(), getBlockSize()); - - if (getNumPrograms() > 1) - setCurrentProgram (0); - else - dispatch (effSetProgram, 0, 0, 0, 0); - - int i; - for (i = effect->numInputs; --i >= 0;) - dispatch (effConnectInput, i, 1, 0, 0); - - for (i = effect->numOutputs; --i >= 0;) - dispatch (effConnectOutput, i, 1, 0, 0); - - updateStoredProgramNames(); - - wantsMidiMessages = dispatch (effCanDo, 0, 0, (void*) "receiveVstMidiEvent", 0) > 0; - - setLatencySamples (effect->initialDelay); -} - - -//============================================================================== -void VSTPluginInstance::prepareToPlay (double sampleRate_, - int samplesPerBlockExpected) -{ - setPlayConfigDetails (effect->numInputs, effect->numOutputs, - sampleRate_, samplesPerBlockExpected); - - setLatencySamples (effect->initialDelay); - - juce_free (channels); - channels = (float**) juce_calloc (sizeof (float*) * jmax (16, getNumOutputChannels() + 2, getNumInputChannels() + 2)); - - vstHostTime.tempo = 120.0; - vstHostTime.timeSigNumerator = 4; - vstHostTime.timeSigDenominator = 4; - vstHostTime.sampleRate = sampleRate_; - vstHostTime.samplePos = 0; - vstHostTime.flags = kVstNanosValid; /*| kVstTransportPlaying | kVstTempoValid | kVstTimeSigValid*/; - - initialise(); - - if (initialised) - { - wantsMidiMessages = wantsMidiMessages - || (dispatch (effCanDo, 0, 0, (void*) "receiveVstMidiEvent", 0) > 0); - - if (wantsMidiMessages) - ensureMidiEventSize (256); - else - freeMidiEvents(); - - incomingMidi.clear(); - - dispatch (effSetSampleRate, 0, 0, 0, (float) sampleRate_); - dispatch (effSetBlockSize, 0, jmax (16, samplesPerBlockExpected), 0, 0); - - tempBuffer.setSize (jmax (1, effect->numOutputs), samplesPerBlockExpected); - - if (! isPowerOn) - setPower (true); - - // dodgy hack to force some plugins to initialise the sample rate.. - if ((! hasEditor()) && getNumParameters() > 0) - { - const float old = getParameter (0); - setParameter (0, (old < 0.5f) ? 1.0f : 0.0f); - setParameter (0, old); - } - - dispatch (effStartProcess, 0, 0, 0, 0); - } -} - -void VSTPluginInstance::releaseResources() -{ - if (initialised) - { - dispatch (effStopProcess, 0, 0, 0, 0); - setPower (false); - } - - tempBuffer.setSize (1, 1); - incomingMidi.clear(); - - freeMidiEvents(); - juce_free (channels); - channels = 0; -} - -void VSTPluginInstance::processBlock (AudioSampleBuffer& buffer, - MidiBuffer& midiMessages) -{ - const int numSamples = buffer.getNumSamples(); - - if (initialised) - { -#if JUCE_WIN32 - vstHostTime.nanoSeconds = timeGetTime() * 1000000.0; -#elif JUCE_LINUX - timeval micro; - gettimeofday (µ, 0); - vstHostTime.nanoSeconds = micro.tv_usec * 1000.0; -#elif JUCE_MAC - UnsignedWide micro; - Microseconds (µ); - vstHostTime.nanoSeconds = micro.lo * 1000.0; -#endif - - if (wantsMidiMessages) - { - MidiBuffer::Iterator iter (midiMessages); - - int eventIndex = 0; - const uint8* midiData; - int numBytesOfMidiData, samplePosition; - - while (iter.getNextEvent (midiData, numBytesOfMidiData, samplePosition)) - { - if (numBytesOfMidiData < 4) - { - ensureMidiEventSize (eventIndex); - VstMidiEvent* const e - = (VstMidiEvent*) ((VstEvents*) midiEventsToSend)->events [eventIndex++]; - - // check that some plugin hasn't messed up our objects - jassert (e->type == kVstMidiType); - jassert (e->byteSize == 24); - - e->deltaFrames = jlimit (0, numSamples - 1, samplePosition); - e->noteLength = 0; - e->noteOffset = 0; - e->midiData[0] = midiData[0]; - e->midiData[1] = midiData[1]; - e->midiData[2] = midiData[2]; - e->detune = 0; - e->noteOffVelocity = 0; - } - } - - if (midiEventsToSend == 0) - ensureMidiEventSize (1); - - ((VstEvents*) midiEventsToSend)->numEvents = eventIndex; - - try - { - effect->dispatcher (effect, effProcessEvents, 0, 0, midiEventsToSend, 0); - } - catch (...) - {} - } - - int i; - const int maxChans = jmax (effect->numInputs, effect->numOutputs); - - for (i = 0; i < maxChans; ++i) - channels[i] = buffer.getSampleData (i); - - channels [maxChans] = 0; - - _clearfp(); - - if ((effect->flags & effFlagsCanReplacing) != 0) - { - try - { - effect->processReplacing (effect, channels, channels, numSamples); - } - catch (...) - {} - } - else - { - tempBuffer.setSize (effect->numOutputs, numSamples); - tempBuffer.clear(); - - float* outs [64]; - - for (i = effect->numOutputs; --i >= 0;) - outs[i] = tempBuffer.getSampleData (i); - - outs [effect->numOutputs] = 0; - - try - { - effect->process (effect, channels, outs, numSamples); - } - catch (...) - {} - - for (i = effect->numOutputs; --i >= 0;) - buffer.copyFrom (i, 0, outs[i], numSamples); - } - } - else - { - // Not initialised, so just bypass.. - for (int i = getNumInputChannels(); i < getNumOutputChannels(); ++i) - buffer.clear (i, 0, buffer.getNumSamples()); - } - - { - // copy any incoming midi.. - const ScopedLock sl (midiInLock); - - midiMessages = incomingMidi; - incomingMidi.clear(); - } -} - -//============================================================================== -void VSTPluginInstance::ensureMidiEventSize (int numEventsNeeded) -{ - if (numEventsNeeded > numAllocatedMidiEvents) - { - numEventsNeeded = (numEventsNeeded + 32) & ~31; - - const int size = 20 + sizeof (VstEvent*) * numEventsNeeded; - - if (midiEventsToSend == 0) - midiEventsToSend = juce_calloc (size); - else - midiEventsToSend = juce_realloc (midiEventsToSend, size); - - for (int i = numAllocatedMidiEvents; i < numEventsNeeded; ++i) - { - VstMidiEvent* const e = (VstMidiEvent*) juce_calloc (sizeof (VstMidiEvent)); - e->type = kVstMidiType; - e->byteSize = 24; - - ((VstEvents*) midiEventsToSend)->events[i] = (VstEvent*) e; - } - - numAllocatedMidiEvents = numEventsNeeded; - } -} - -void VSTPluginInstance::freeMidiEvents() -{ - if (midiEventsToSend != 0) - { - for (int i = numAllocatedMidiEvents; --i >= 0;) - juce_free (((VstEvents*) midiEventsToSend)->events[i]); - - juce_free (midiEventsToSend); - midiEventsToSend = 0; - numAllocatedMidiEvents = 0; - } -} - -void VSTPluginInstance::handleMidiFromPlugin (const VstEvents* const events) -{ - if (events != 0) - { - const ScopedLock sl (midiInLock); - - for (int i = 0; i < events->numEvents; ++i) - { - const VstEvent* const e = events->events[i]; - - if (e->type == kVstMidiType) - { - incomingMidi.addEvent ((const uint8*) ((const VstMidiEvent*) e)->midiData, - 3, e->deltaFrames); - } - } - } -} - -//============================================================================== -static Array activeWindows; - -//============================================================================== -class VSTPluginWindow : public AudioProcessorEditor, - public Timer -{ -public: - //============================================================================== - VSTPluginWindow (VSTPluginInstance& plugin_) - : AudioProcessorEditor (&plugin_), - plugin (plugin_), - isOpen (false), - wasShowing (false), - pluginRefusesToResize (false), - pluginWantsKeys (false), - alreadyInside (false), - recursiveResize (false) - { -#if JUCE_WIN32 - sizeCheckCount = 0; - pluginHWND = 0; -#elif JUCE_LINUX - pluginWindow = None; - pluginProc = None; -#else - pluginViewRef = 0; -#endif - - movementWatcher = new CompMovementWatcher (this); - - activeWindows.add (this); - - setSize (1, 1); - setOpaque (true); - setVisible (true); - } - - ~VSTPluginWindow() - { - deleteAndZero (movementWatcher); - - closePluginWindow(); - - activeWindows.removeValue (this); - plugin.editorBeingDeleted (this); - } - - //============================================================================== - void componentMovedOrResized() - { - if (recursiveResize) - return; - - Component* const topComp = getTopLevelComponent(); - - if (topComp->getPeer() != 0) - { - int x = 0, y = 0; - relativePositionToOtherComponent (topComp, x, y); - - recursiveResize = true; - -#if JUCE_MAC - if (pluginViewRef != 0) - { - HIRect r; - r.origin.x = (float) x; - r.origin.y = (float) y; - r.size.width = (float) getWidth(); - r.size.height = (float) getHeight(); - HIViewSetFrame (pluginViewRef, &r); - } - else if (pluginWindowRef != 0) - { - Rect r; - r.left = getScreenX(); - r.top = getScreenY(); - r.right = r.left + getWidth(); - r.bottom = r.top + getHeight(); - - WindowGroupRef group = GetWindowGroup (pluginWindowRef); - WindowGroupAttributes atts; - GetWindowGroupAttributes (group, &atts); - ChangeWindowGroupAttributes (group, 0, kWindowGroupAttrMoveTogether); - - SetWindowBounds (pluginWindowRef, kWindowContentRgn, &r); - - if ((atts & kWindowGroupAttrMoveTogether) != 0) - ChangeWindowGroupAttributes (group, kWindowGroupAttrMoveTogether, 0); - } - else - { - repaint(); - } -#elif JUCE_WIN32 - if (pluginHWND != 0) - MoveWindow (pluginHWND, x, y, getWidth(), getHeight(), TRUE); -#elif JUCE_LINUX - if (pluginWindow != 0) - { - XResizeWindow (display, pluginWindow, getWidth(), getHeight()); - XMoveWindow (display, pluginWindow, x, y); - XMapRaised (display, pluginWindow); - } -#endif - - recursiveResize = false; - } - } - - void componentVisibilityChanged() - { - const bool isShowingNow = isShowing(); - - if (wasShowing != isShowingNow) - { - wasShowing = isShowingNow; - - if (isShowingNow) - openPluginWindow(); - else - closePluginWindow(); - } - - componentMovedOrResized(); - } - - void componentPeerChanged() - { - closePluginWindow(); - openPluginWindow(); - } - - //============================================================================== - bool keyStateChanged() - { - return pluginWantsKeys; - } - - bool keyPressed (const KeyPress&) - { - return pluginWantsKeys; - } - - //============================================================================== - void paint (Graphics& g) - { - if (isOpen) - { - ComponentPeer* const peer = getPeer(); - - if (peer != 0) - { - peer->addMaskedRegion (getScreenX() - peer->getScreenX(), - getScreenY() - peer->getScreenY(), - getWidth(), getHeight()); - -#if JUCE_MAC - if (pluginViewRef == 0) - { - ERect r; - r.left = getScreenX() - peer->getScreenX(); - r.right = r.left + getWidth(); - r.top = getScreenY() - peer->getScreenY(); - r.bottom = r.top + getHeight(); - - dispatch (effEditDraw, 0, 0, &r, 0); - } -#elif JUCE_LINUX - if (pluginWindow != 0) - { - const Rectangle clip (g.getClipBounds()); - - XEvent ev; - zerostruct (ev); - ev.xexpose.type = Expose; - ev.xexpose.display = display; - ev.xexpose.window = pluginWindow; - ev.xexpose.x = clip.getX(); - ev.xexpose.y = clip.getY(); - ev.xexpose.width = clip.getWidth(); - ev.xexpose.height = clip.getHeight(); - - sendEventToChild (&ev); - } -#endif - } - } - else - { - g.fillAll (Colours::black); - } - } - - //============================================================================== - void timerCallback() - { -#if JUCE_WIN32 - if (--sizeCheckCount <= 0) - { - sizeCheckCount = 10; - - checkPluginWindowSize(); - } -#endif - - try - { - static bool reentrant = false; - - if (! reentrant) - { - reentrant = true; - plugin.dispatch (effEditIdle, 0, 0, 0, 0); - reentrant = false; - } - } - catch (...) - {} - } - - //============================================================================== - void mouseDown (const MouseEvent& e) - { -#if JUCE_MAC - if (! alreadyInside) - { - alreadyInside = true; - toFront (true); - dispatch (effEditMouse, e.x, e.y, 0, 0); - alreadyInside = false; - } - else - { - PostEvent (::mouseDown, 0); - } -#elif JUCE_LINUX - - if (pluginWindow == 0) - return; - - toFront (true); - - XEvent ev; - zerostruct (ev); - ev.xbutton.display = display; - ev.xbutton.type = ButtonPress; - ev.xbutton.window = pluginWindow; - ev.xbutton.root = RootWindow (display, DefaultScreen (display)); - ev.xbutton.time = CurrentTime; - ev.xbutton.x = e.x; - ev.xbutton.y = e.y; - ev.xbutton.x_root = e.getScreenX(); - ev.xbutton.y_root = e.getScreenY(); - - translateJuceToXButtonModifiers (e, ev); - - sendEventToChild (&ev); - -#else - (void) e; - - toFront (true); -#endif - } - - void broughtToFront() - { - activeWindows.removeValue (this); - activeWindows.add (this); - -#if JUCE_MAC - dispatch (effEditTop, 0, 0, 0, 0); -#endif - } - - //============================================================================== - juce_UseDebuggingNewOperator - -private: - VSTPluginInstance& plugin; - bool isOpen, wasShowing, recursiveResize; - bool pluginWantsKeys, pluginRefusesToResize, alreadyInside; - -#if JUCE_WIN32 - HWND pluginHWND; - void* originalWndProc; - int sizeCheckCount; -#elif JUCE_MAC - HIViewRef pluginViewRef; - WindowRef pluginWindowRef; -#elif JUCE_LINUX - Window pluginWindow; - EventProcPtr pluginProc; -#endif - - //============================================================================== - void openPluginWindow() - { - if (isOpen || getWindowHandle() == 0) - return; - - log (T("Opening VST UI: ") + plugin.name); - isOpen = true; - - ERect* rect = 0; - dispatch (effEditGetRect, 0, 0, &rect, 0); - dispatch (effEditOpen, 0, 0, getWindowHandle(), 0); - - // do this before and after like in the steinberg example - dispatch (effEditGetRect, 0, 0, &rect, 0); - dispatch (effGetProgram, 0, 0, 0, 0); // also in steinberg code - - // Install keyboard hooks - pluginWantsKeys = (dispatch (effKeysRequired, 0, 0, 0, 0) == 0); - -#if JUCE_WIN32 - originalWndProc = 0; - pluginHWND = GetWindow ((HWND) getWindowHandle(), GW_CHILD); - - if (pluginHWND == 0) - { - isOpen = false; - setSize (300, 150); - return; - } - - #pragma warning (push) - #pragma warning (disable: 4244) - - originalWndProc = (void*) GetWindowLongPtr (pluginHWND, GWL_WNDPROC); - - if (! pluginWantsKeys) - SetWindowLongPtr (pluginHWND, GWL_WNDPROC, (LONG_PTR) vstHookWndProc); - - #pragma warning (pop) - - int w, h; - RECT r; - GetWindowRect (pluginHWND, &r); - w = r.right - r.left; - h = r.bottom - r.top; - - if (rect != 0) - { - const int rw = rect->right - rect->left; - const int rh = rect->bottom - rect->top; - - if ((rw > 50 && rh > 50 && rw < 2000 && rh < 2000 && rw != w && rh != h) - || ((w == 0 && rw > 0) || (h == 0 && rh > 0))) - { - // very dodgy logic to decide which size is right. - if (abs (rw - w) > 350 || abs (rh - h) > 350) - { - SetWindowPos (pluginHWND, 0, - 0, 0, rw, rh, - SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER); - - GetWindowRect (pluginHWND, &r); - - w = r.right - r.left; - h = r.bottom - r.top; - - pluginRefusesToResize = (w != rw) || (h != rh); - - w = rw; - h = rh; - } - } - } -#elif JUCE_MAC - HIViewRef root = HIViewGetRoot ((WindowRef) getWindowHandle()); - HIViewFindByID (root, kHIViewWindowContentID, &root); - pluginViewRef = HIViewGetFirstSubview (root); - - while (pluginViewRef != 0 && juce_isHIViewCreatedByJuce (pluginViewRef)) - pluginViewRef = HIViewGetNextView (pluginViewRef); - - pluginWindowRef = 0; - - if (pluginViewRef == 0) - { - WindowGroupRef ourGroup = GetWindowGroup ((WindowRef) getWindowHandle()); - //DebugPrintWindowGroup (ourGroup); - //DebugPrintAllWindowGroups(); - - GetIndexedWindow (ourGroup, 1, - kWindowGroupContentsVisible, - &pluginWindowRef); - - if (pluginWindowRef == (WindowRef) getWindowHandle() - || juce_isWindowCreatedByJuce (pluginWindowRef)) - pluginWindowRef = 0; - } - - int w = 250, h = 150; - - if (rect != 0) - { - w = rect->right - rect->left; - h = rect->bottom - rect->top; - - if (w == 0 || h == 0) - { - w = 250; - h = 150; - } - } - -#elif JUCE_LINUX - pluginWindow = getChildWindow ((Window) getWindowHandle()); - - if (pluginWindow != 0) - pluginProc = (EventProcPtr) getPropertyFromXWindow (pluginWindow, - XInternAtom (display, "_XEventProc", False)); - - int w = 250, h = 150; - - if (rect != 0) - { - w = rect->right - rect->left; - h = rect->bottom - rect->top; - - if (w == 0 || h == 0) - { - w = 250; - h = 150; - } - } - - if (pluginWindow != 0) - XMapRaised (display, pluginWindow); -#endif - - // double-check it's not too tiny - w = jmax (w, 32); - h = jmax (h, 32); - - setSize (w, h); - -#if JUCE_WIN32 - checkPluginWindowSize(); -#endif - - startTimer (18 + JUCE_NAMESPACE::Random::getSystemRandom().nextInt (5)); - repaint(); - } - - //============================================================================== - void closePluginWindow() - { - if (isOpen) - { - log (T("Closing VST UI: ") + plugin.getName()); - isOpen = false; - - dispatch (effEditClose, 0, 0, 0, 0); - -#if JUCE_WIN32 - #pragma warning (push) - #pragma warning (disable: 4244) - - if (pluginHWND != 0 && IsWindow (pluginHWND)) - SetWindowLongPtr (pluginHWND, GWL_WNDPROC, (LONG_PTR) originalWndProc); - - #pragma warning (pop) - - stopTimer(); - - if (pluginHWND != 0 && IsWindow (pluginHWND)) - DestroyWindow (pluginHWND); - - pluginHWND = 0; -#elif JUCE_MAC - dispatch (effEditSleep, 0, 0, 0, 0); - pluginViewRef = 0; - stopTimer(); -#elif JUCE_LINUX - stopTimer(); - pluginWindow = 0; - pluginProc = 0; -#endif - } - } - - //============================================================================== -#if JUCE_WIN32 - void checkPluginWindowSize() throw() - { - RECT r; - GetWindowRect (pluginHWND, &r); - const int w = r.right - r.left; - const int h = r.bottom - r.top; - - if (isShowing() && w > 0 && h > 0 - && (w != getWidth() || h != getHeight()) - && ! pluginRefusesToResize) - { - setSize (w, h); - sizeCheckCount = 0; - } - } -#endif - - //============================================================================== - class CompMovementWatcher : public ComponentMovementWatcher - { - public: - CompMovementWatcher (VSTPluginWindow* const owner_) - : ComponentMovementWatcher (owner_), - owner (owner_) - { - } - - //============================================================================== - void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) - { - owner->componentMovedOrResized(); - } - - void componentPeerChanged() - { - owner->componentPeerChanged(); - } - - void componentVisibilityChanged (Component&) - { - owner->componentVisibilityChanged(); - } - - private: - VSTPluginWindow* const owner; - }; - - CompMovementWatcher* movementWatcher; - - //============================================================================== - int dispatch (const int opcode, const int index, const int value, void* const ptr, float opt) - { - return plugin.dispatch (opcode, index, value, ptr, opt); - } - - //============================================================================== - // hooks to get keyboard events from VST windows.. -#if JUCE_WIN32 - static LRESULT CALLBACK vstHookWndProc (HWND hW, UINT message, WPARAM wParam, LPARAM lParam) - { - for (int i = activeWindows.size(); --i >= 0;) - { - const VSTPluginWindow* const w = (const VSTPluginWindow*) activeWindows.getUnchecked (i); - - if (w->pluginHWND == hW) - { - if (message == WM_CHAR - || message == WM_KEYDOWN - || message == WM_SYSKEYDOWN - || message == WM_KEYUP - || message == WM_SYSKEYUP - || message == WM_APPCOMMAND) - { - SendMessage ((HWND) w->getTopLevelComponent()->getWindowHandle(), - message, wParam, lParam); - } - - return CallWindowProc ((WNDPROC) (w->originalWndProc), - (HWND) w->pluginHWND, - message, - wParam, - lParam); - } - } - - return DefWindowProc (hW, message, wParam, lParam); - } -#endif - -#if JUCE_LINUX - //============================================================================== - // overload mouse/keyboard events to forward them to the plugin's inner window.. - void sendEventToChild (XEvent* event) - { - if (pluginProc != 0) - { - // if the plugin publishes an event procedure, pass the event directly.. - pluginProc (event); - } - else if (pluginWindow != 0) - { - // if the plugin has a window, then send the event to the window so that - // its message thread will pick it up.. - XSendEvent (display, pluginWindow, False, 0L, event); - XFlush (display); - } - } - - void mouseEnter (const MouseEvent& e) - { - if (pluginWindow != 0) - { - XEvent ev; - zerostruct (ev); - ev.xcrossing.display = display; - ev.xcrossing.type = EnterNotify; - ev.xcrossing.window = pluginWindow; - ev.xcrossing.root = RootWindow (display, DefaultScreen (display)); - ev.xcrossing.time = CurrentTime; - ev.xcrossing.x = e.x; - ev.xcrossing.y = e.y; - ev.xcrossing.x_root = e.getScreenX(); - ev.xcrossing.y_root = e.getScreenY(); - ev.xcrossing.mode = NotifyNormal; // NotifyGrab, NotifyUngrab - ev.xcrossing.detail = NotifyAncestor; // NotifyVirtual, NotifyInferior, NotifyNonlinear,NotifyNonlinearVirtual - - translateJuceToXCrossingModifiers (e, ev); - - sendEventToChild (&ev); - } - } - - void mouseExit (const MouseEvent& e) - { - if (pluginWindow != 0) - { - XEvent ev; - zerostruct (ev); - ev.xcrossing.display = display; - ev.xcrossing.type = LeaveNotify; - ev.xcrossing.window = pluginWindow; - ev.xcrossing.root = RootWindow (display, DefaultScreen (display)); - ev.xcrossing.time = CurrentTime; - ev.xcrossing.x = e.x; - ev.xcrossing.y = e.y; - ev.xcrossing.x_root = e.getScreenX(); - ev.xcrossing.y_root = e.getScreenY(); - ev.xcrossing.mode = NotifyNormal; // NotifyGrab, NotifyUngrab - ev.xcrossing.detail = NotifyAncestor; // NotifyVirtual, NotifyInferior, NotifyNonlinear,NotifyNonlinearVirtual - ev.xcrossing.focus = hasKeyboardFocus (true); // TODO - yes ? - - translateJuceToXCrossingModifiers (e, ev); - - sendEventToChild (&ev); - } - } - - void mouseMove (const MouseEvent& e) - { - if (pluginWindow != 0) - { - XEvent ev; - zerostruct (ev); - ev.xmotion.display = display; - ev.xmotion.type = MotionNotify; - ev.xmotion.window = pluginWindow; - ev.xmotion.root = RootWindow (display, DefaultScreen (display)); - ev.xmotion.time = CurrentTime; - ev.xmotion.is_hint = NotifyNormal; - ev.xmotion.x = e.x; - ev.xmotion.y = e.y; - ev.xmotion.x_root = e.getScreenX(); - ev.xmotion.y_root = e.getScreenY(); - - sendEventToChild (&ev); - } - } - - void mouseDrag (const MouseEvent& e) - { - if (pluginWindow != 0) - { - XEvent ev; - zerostruct (ev); - ev.xmotion.display = display; - ev.xmotion.type = MotionNotify; - ev.xmotion.window = pluginWindow; - ev.xmotion.root = RootWindow (display, DefaultScreen (display)); - ev.xmotion.time = CurrentTime; - ev.xmotion.x = e.x ; - ev.xmotion.y = e.y; - ev.xmotion.x_root = e.getScreenX(); - ev.xmotion.y_root = e.getScreenY(); - ev.xmotion.is_hint = NotifyNormal; - - translateJuceToXMotionModifiers (e, ev); - sendEventToChild (&ev); - } - } - - void mouseUp (const MouseEvent& e) - { - if (pluginWindow != 0) - { - XEvent ev; - zerostruct (ev); - ev.xbutton.display = display; - ev.xbutton.type = ButtonRelease; - ev.xbutton.window = pluginWindow; - ev.xbutton.root = RootWindow (display, DefaultScreen (display)); - ev.xbutton.time = CurrentTime; - ev.xbutton.x = e.x; - ev.xbutton.y = e.y; - ev.xbutton.x_root = e.getScreenX(); - ev.xbutton.y_root = e.getScreenY(); - - translateJuceToXButtonModifiers (e, ev); - sendEventToChild (&ev); - } - } - - void mouseWheelMove (const MouseEvent& e, - float incrementX, - float incrementY) - { - if (pluginWindow != 0) - { - XEvent ev; - zerostruct (ev); - ev.xbutton.display = display; - ev.xbutton.type = ButtonPress; - ev.xbutton.window = pluginWindow; - ev.xbutton.root = RootWindow (display, DefaultScreen (display)); - ev.xbutton.time = CurrentTime; - ev.xbutton.x = e.x; - ev.xbutton.y = e.y; - ev.xbutton.x_root = e.getScreenX(); - ev.xbutton.y_root = e.getScreenY(); - - translateJuceToXMouseWheelModifiers (e, incrementY, ev); - sendEventToChild (&ev); - - // TODO - put a usleep here ? - - ev.xbutton.type = ButtonRelease; - sendEventToChild (&ev); - } - } -#endif - -}; - -//============================================================================== -AudioProcessorEditor* VSTPluginInstance::createEditor() -{ - if (hasEditor()) - return new VSTPluginWindow (*this); - - return 0; -} - - -//============================================================================== -void VSTPluginInstance::handleAsyncUpdate() -{ - // indicates that something about the plugin has changed.. - updateHostDisplay(); -} - -//============================================================================== -bool VSTPluginInstance::restoreProgramSettings (const fxProgram* const prog) -{ - if (swap (prog->chunkMagic) == 'CcnK' && swap (prog->fxMagic) == 'FxCk') - { - changeProgramName (getCurrentProgram(), prog->prgName); - - for (int i = 0; i < swap (prog->numParams); ++i) - setParameter (i, swapFloat (prog->params[i])); - - return true; - } - - return false; -} - -bool VSTPluginInstance::loadFromFXBFile (const void* const data, - const int dataSize) -{ - if (dataSize < 28) - return false; - - const fxSet* const set = (const fxSet*) data; - - if ((swap (set->chunkMagic) != 'CcnK' && swap (set->chunkMagic) != 'KncC') - || swap (set->version) > fxbVersionNum) - return false; - - if (swap (set->fxMagic) == 'FxBk') - { - // bank of programs - if (swap (set->numPrograms) >= 0) - { - const int oldProg = getCurrentProgram(); - const int numParams = swap (((const fxProgram*) (set->programs))->numParams); - const int progLen = sizeof (fxProgram) + (numParams - 1) * sizeof (float); - - for (int i = 0; i < swap (set->numPrograms); ++i) - { - if (i != oldProg) - { - const fxProgram* const prog = (const fxProgram*) (((const char*) (set->programs)) + i * progLen); - if (((const char*) prog) - ((const char*) set) >= dataSize) - return false; - - if (swap (set->numPrograms) > 0) - setCurrentProgram (i); - - if (! restoreProgramSettings (prog)) - return false; - } - } - - if (swap (set->numPrograms) > 0) - setCurrentProgram (oldProg); - - const fxProgram* const prog = (const fxProgram*) (((const char*) (set->programs)) + oldProg * progLen); - if (((const char*) prog) - ((const char*) set) >= dataSize) - return false; - - if (! restoreProgramSettings (prog)) - return false; - } - } - else if (swap (set->fxMagic) == 'FxCk') - { - // single program - const fxProgram* const prog = (const fxProgram*) data; - - if (swap (prog->chunkMagic) != 'CcnK') - return false; - - changeProgramName (getCurrentProgram(), prog->prgName); - - for (int i = 0; i < swap (prog->numParams); ++i) - setParameter (i, swapFloat (prog->params[i])); - } - else if (swap (set->fxMagic) == 'FBCh' || swap (set->fxMagic) == 'hCBF') - { - // non-preset chunk - const fxChunkSet* const cset = (const fxChunkSet*) data; - - if (swap (cset->chunkSize) + sizeof (fxChunkSet) - 8 > (unsigned int) dataSize) - return false; - - setChunkData (cset->chunk, swap (cset->chunkSize), false); - } - else if (swap (set->fxMagic) == 'FPCh' || swap (set->fxMagic) == 'hCPF') - { - // preset chunk - const fxProgramSet* const cset = (const fxProgramSet*) data; - - if (swap (cset->chunkSize) + sizeof (fxProgramSet) - 8 > (unsigned int) dataSize) - return false; - - setChunkData (cset->chunk, swap (cset->chunkSize), true); - - changeProgramName (getCurrentProgram(), cset->name); - } - else - { - return false; - } - - return true; -} - -//============================================================================== -void VSTPluginInstance::setParamsInProgramBlock (fxProgram* const prog) throw() -{ - const int numParams = getNumParameters(); - - prog->chunkMagic = swap ('CcnK'); - prog->byteSize = 0; - prog->fxMagic = swap ('FxCk'); - prog->version = swap (fxbVersionNum); - prog->fxID = swap (getUID()); - prog->fxVersion = swap (getVersionNumber()); - prog->numParams = swap (numParams); - - getCurrentProgramName().copyToBuffer (prog->prgName, sizeof (prog->prgName) - 1); - - for (int i = 0; i < numParams; ++i) - prog->params[i] = swapFloat (getParameter (i)); -} - -bool VSTPluginInstance::saveToFXBFile (MemoryBlock& dest, bool isFXB, int maxSizeMB) -{ - const int numPrograms = getNumPrograms(); - const int numParams = getNumParameters(); - - if (usesChunks()) - { - if (isFXB) - { - MemoryBlock chunk; - getChunkData (chunk, false, maxSizeMB); - - const int totalLen = sizeof (fxChunkSet) + chunk.getSize() - 8; - dest.setSize (totalLen, true); - - fxChunkSet* const set = (fxChunkSet*) dest.getData(); - set->chunkMagic = swap ('CcnK'); - set->byteSize = 0; - set->fxMagic = swap ('FBCh'); - set->version = swap (fxbVersionNum); - set->fxID = swap (getUID()); - set->fxVersion = swap (getVersionNumber()); - set->numPrograms = swap (numPrograms); - set->chunkSize = swap (chunk.getSize()); - - chunk.copyTo (set->chunk, 0, chunk.getSize()); - } - else - { - MemoryBlock chunk; - getChunkData (chunk, true, maxSizeMB); - - const int totalLen = sizeof (fxProgramSet) + chunk.getSize() - 8; - dest.setSize (totalLen, true); - - fxProgramSet* const set = (fxProgramSet*) dest.getData(); - set->chunkMagic = swap ('CcnK'); - set->byteSize = 0; - set->fxMagic = swap ('FPCh'); - set->version = swap (fxbVersionNum); - set->fxID = swap (getUID()); - set->fxVersion = swap (getVersionNumber()); - set->numPrograms = swap (numPrograms); - set->chunkSize = swap (chunk.getSize()); - - getCurrentProgramName().copyToBuffer (set->name, sizeof (set->name) - 1); - chunk.copyTo (set->chunk, 0, chunk.getSize()); - } - } - else - { - if (isFXB) - { - const int progLen = sizeof (fxProgram) + (numParams - 1) * sizeof (float); - const int len = (sizeof (fxSet) - sizeof (fxProgram)) + progLen * jmax (1, numPrograms); - dest.setSize (len, true); - - fxSet* const set = (fxSet*) dest.getData(); - set->chunkMagic = swap ('CcnK'); - set->byteSize = 0; - set->fxMagic = swap ('FxBk'); - set->version = swap (fxbVersionNum); - set->fxID = swap (getUID()); - set->fxVersion = swap (getVersionNumber()); - set->numPrograms = swap (numPrograms); - - const int oldProgram = getCurrentProgram(); - MemoryBlock oldSettings; - createTempParameterStore (oldSettings); - - setParamsInProgramBlock ((fxProgram*) (((char*) (set->programs)) + oldProgram * progLen)); - - for (int i = 0; i < numPrograms; ++i) - { - if (i != oldProgram) - { - setCurrentProgram (i); - setParamsInProgramBlock ((fxProgram*) (((char*) (set->programs)) + i * progLen)); - } - } - - setCurrentProgram (oldProgram); - restoreFromTempParameterStore (oldSettings); - } - else - { - const int totalLen = sizeof (fxProgram) + (numParams - 1) * sizeof (float); - dest.setSize (totalLen, true); - - setParamsInProgramBlock ((fxProgram*) dest.getData()); - } - } - - return true; -} - -void VSTPluginInstance::getChunkData (MemoryBlock& mb, bool isPreset, int maxSizeMB) const -{ - if (usesChunks()) - { - void* data = 0; - const int bytes = dispatch (effGetChunk, isPreset ? 1 : 0, 0, &data, 0.0f); - - if (data != 0 && bytes <= maxSizeMB * 1024 * 1024) - { - mb.setSize (bytes); - mb.copyFrom (data, 0, bytes); - } - } -} - -void VSTPluginInstance::setChunkData (const char* data, int size, bool isPreset) -{ - if (size > 0 && usesChunks()) - { - dispatch (effSetChunk, isPreset ? 1 : 0, size, (void*) data, 0.0f); - - if (! isPreset) - updateStoredProgramNames(); - } -} - -//============================================================================== -void VSTPluginInstance::timerCallback() -{ - if (dispatch (effIdle, 0, 0, 0, 0) == 0) - stopTimer(); -} - -int VSTPluginInstance::dispatch (const int opcode, const int index, const int value, void* const ptr, float opt) const -{ - const ScopedLock sl (lock); - - ++insideVSTCallback; - int result = 0; - - try - { - if (effect != 0) - { -#if JUCE_MAC - if (module->resFileId != 0) - UseResFile (module->resFileId); - - CGrafPtr oldPort; - - if (getActiveEditor() != 0) - { - int x = 0, y = 0; - getActiveEditor()->relativePositionToOtherComponent (getActiveEditor()->getTopLevelComponent(), x, y); - - GetPort (&oldPort); - SetPortWindowPort ((WindowRef) getActiveEditor()->getWindowHandle()); - SetOrigin (-x, -y); - } -#endif - - result = effect->dispatcher (effect, opcode, index, value, ptr, opt); - -#if JUCE_MAC - if (getActiveEditor() != 0) - SetPort (oldPort); - - module->resFileId = CurResFile(); -#endif - - --insideVSTCallback; - return result; - } - } - catch (...) - { - //char s[512]; - //sprintf (s, "dispatcher (%d, %d, %d, %x, %f)", opcode, index, value, (int)ptr, opt); - } - - --insideVSTCallback; - return result; -} - -//============================================================================== -// handles non plugin-specific callbacks.. -static VstIntPtr handleGeneralCallback (VstInt32 opcode, VstInt32 index, VstInt32 value, void *ptr, float opt) -{ - (void) index; - (void) value; - (void) opt; - - switch (opcode) - { - case audioMasterCanDo: - { - static const char* canDos[] = { "supplyIdle", - "sendVstEvents", - "sendVstMidiEvent", - "sendVstTimeInfo", - "receiveVstEvents", - "receiveVstMidiEvent", - "supportShell", - "shellCategory" }; - - for (int i = 0; i < numElementsInArray (canDos); ++i) - if (strcmp (canDos[i], (const char*) ptr) == 0) - return 1; - - return 0; - } - - case audioMasterVersion: - return 0x2400; - case audioMasterCurrentId: - return shellUIDToCreate; - case audioMasterGetNumAutomatableParameters: - return 0; - case audioMasterGetAutomationState: - return 1; - - case audioMasterGetVendorVersion: - return 0x0101; - case audioMasterGetVendorString: - case audioMasterGetProductString: - JUCEApplication::getInstance() - ->getApplicationName().copyToBuffer ((char*) ptr, jmin (kVstMaxVendorStrLen, kVstMaxProductStrLen) - 1); - break; - - case audioMasterGetSampleRate: - return 44100; - - case audioMasterGetBlockSize: - return 512; - - case audioMasterSetOutputSampleRate: - return 0; - - default: - DBG ("*** Unhandled VST Callback: " + String ((int) opcode)); - break; - } - - return 0; -} - -// handles callbacks for a specific plugin -VstIntPtr VSTPluginInstance::handleCallback (VstInt32 opcode, VstInt32 index, VstInt32 value, void *ptr, float opt) -{ - switch (opcode) - { - case audioMasterAutomate: - sendParamChangeMessageToListeners (index, opt); - break; - - case audioMasterProcessEvents: - handleMidiFromPlugin ((const VstEvents*) ptr); - break; - - case audioMasterGetTime: - #ifdef _MSC_VER - #pragma warning (push) - #pragma warning (disable: 4311) - #endif - - return (VstIntPtr) &vstHostTime; - - #ifdef _MSC_VER - #pragma warning (pop) - #endif - break; - - case audioMasterIdle: - if (insideVSTCallback == 0 && MessageManager::getInstance()->isThisTheMessageThread()) - { - ++insideVSTCallback; -#if JUCE_MAC - if (getActiveEditor() != 0) - dispatch (effEditIdle, 0, 0, 0, 0); -#endif - const MessageManagerLock mml; - - juce_callAnyTimersSynchronously(); - - handleUpdateNowIfNeeded(); - - for (int i = ComponentPeer::getNumPeers(); --i >= 0;) - ComponentPeer::getPeer (i)->performAnyPendingRepaintsNow(); - - --insideVSTCallback; - } - break; - - case audioMasterUpdateDisplay: - triggerAsyncUpdate(); - break; - - case audioMasterTempoAt: - // returns (10000 * bpm) - break; - - case audioMasterNeedIdle: - startTimer (50); - break; - - case audioMasterSizeWindow: - if (getActiveEditor() != 0) - getActiveEditor()->setSize (index, value); - - return 1; - - case audioMasterGetSampleRate: - return (VstIntPtr) getSampleRate(); - - case audioMasterGetBlockSize: - return (VstIntPtr) getBlockSize(); - - case audioMasterWantMidi: - wantsMidiMessages = true; - break; - - case audioMasterGetDirectory: - #if JUCE_MAC - return (VstIntPtr) (void*) &module->parentDirFSSpec; - #else - return (VstIntPtr) (pointer_sized_uint) (const char*) module->fullParentDirectoryPathName; - #endif - - case audioMasterGetAutomationState: - // returns 0: not supported, 1: off, 2:read, 3:write, 4:read/write - break; - - // none of these are handled (yet).. - case audioMasterBeginEdit: - case audioMasterEndEdit: - case audioMasterSetTime: - case audioMasterPinConnected: - case audioMasterGetParameterQuantization: - case audioMasterIOChanged: - case audioMasterGetInputLatency: - case audioMasterGetOutputLatency: - case audioMasterGetPreviousPlug: - case audioMasterGetNextPlug: - case audioMasterWillReplaceOrAccumulate: - case audioMasterGetCurrentProcessLevel: - case audioMasterOfflineStart: - case audioMasterOfflineRead: - case audioMasterOfflineWrite: - case audioMasterOfflineGetCurrentPass: - case audioMasterOfflineGetCurrentMetaPass: - case audioMasterVendorSpecific: - case audioMasterSetIcon: - case audioMasterGetLanguage: - case audioMasterOpenWindow: - case audioMasterCloseWindow: - break; - - default: - return handleGeneralCallback (opcode, index, value, ptr, opt); - } - - return 0; -} - -// entry point for all callbacks from the plugin -static VstIntPtr VSTCALLBACK audioMaster (AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt) -{ - try - { - if (effect != 0 && effect->resvd2 != 0) - { - return ((VSTPluginInstance*)(effect->resvd2)) - ->handleCallback (opcode, index, value, ptr, opt); - } - - return handleGeneralCallback (opcode, index, value, ptr, opt); - } - catch (...) - { - return 0; - } -} - -//============================================================================== -const String VSTPluginInstance::getVersion() const throw() -{ - int v = dispatch (effGetVendorVersion, 0, 0, 0, 0); - - String s; - - if (v != 0) - { - int versionBits[4]; - int n = 0; - - while (v != 0) - { - versionBits [n++] = (v & 0xff); - v >>= 8; - } - - s << 'V'; - - while (n > 0) - { - s << versionBits [--n]; - - if (n > 0) - s << '.'; - } - } - - return s; -} - -int VSTPluginInstance::getUID() const throw() -{ - int uid = effect != 0 ? effect->uniqueID : 0; - - if (uid == 0) - uid = module->file.hashCode(); - - return uid; -} - -const String VSTPluginInstance::getCategory() const throw() -{ - const char* result = 0; - - switch (dispatch (effGetPlugCategory, 0, 0, 0, 0)) - { - case kPlugCategEffect: - result = "Effect"; - break; - - case kPlugCategSynth: - result = "Synth"; - break; - - case kPlugCategAnalysis: - result = "Anaylsis"; - break; - - case kPlugCategMastering: - result = "Mastering"; - break; - - case kPlugCategSpacializer: - result = "Spacial"; - break; - - case kPlugCategRoomFx: - result = "Reverb"; - break; - - case kPlugSurroundFx: - result = "Surround"; - break; - - case kPlugCategRestoration: - result = "Restoration"; - break; - - case kPlugCategGenerator: - result = "Tone generation"; - break; - - default: - break; - } - - return result; -} - -//============================================================================== -float VSTPluginInstance::getParameter (int index) -{ - if (effect != 0 && ((unsigned int) index) < (unsigned int) effect->numParams) - { - try - { - const ScopedLock sl (lock); - return effect->getParameter (effect, index); - } - catch (...) - { - } - } - - return 0.0f; -} - -void VSTPluginInstance::setParameter (int index, float newValue) -{ - if (effect != 0 && ((unsigned int) index) < (unsigned int) effect->numParams) - { - try - { - const ScopedLock sl (lock); - - if (effect->getParameter (effect, index) != newValue) - effect->setParameter (effect, index, newValue); - } - catch (...) - { - } - } -} - -const String VSTPluginInstance::getParameterName (int index) -{ - if (effect != 0) - { - jassert (index >= 0 && index < effect->numParams); - - char nm [256]; - zerostruct (nm); - dispatch (effGetParamName, index, 0, nm, 0); - return String (nm).trim(); - } - - return String::empty; -} - -const String VSTPluginInstance::getParameterLabel (int index) const -{ - if (effect != 0) - { - jassert (index >= 0 && index < effect->numParams); - - char nm [256]; - zerostruct (nm); - dispatch (effGetParamLabel, index, 0, nm, 0); - return String (nm).trim(); - } - - return String::empty; -} - -const String VSTPluginInstance::getParameterText (int index) -{ - if (effect != 0) - { - jassert (index >= 0 && index < effect->numParams); - - char nm [256]; - zerostruct (nm); - dispatch (effGetParamDisplay, index, 0, nm, 0); - return String (nm).trim(); - } - - return String::empty; -} - -bool VSTPluginInstance::isParameterAutomatable (int index) const -{ - if (effect != 0) - { - jassert (index >= 0 && index < effect->numParams); - return dispatch (effCanBeAutomated, index, 0, 0, 0) != 0; - } - - return false; -} - -void VSTPluginInstance::createTempParameterStore (MemoryBlock& dest) -{ - dest.setSize (64 + 4 * getNumParameters()); - dest.fillWith (0); - - getCurrentProgramName().copyToBuffer ((char*) dest.getData(), 63); - - float* const p = (float*) (((char*) dest.getData()) + 64); - for (int i = 0; i < getNumParameters(); ++i) - p[i] = getParameter(i); -} - -void VSTPluginInstance::restoreFromTempParameterStore (const MemoryBlock& m) -{ - changeProgramName (getCurrentProgram(), (const char*) m); - - float* p = (float*) (((char*) m.getData()) + 64); - for (int i = 0; i < getNumParameters(); ++i) - setParameter (i, p[i]); -} - -//============================================================================== -void VSTPluginInstance::setCurrentProgram (int newIndex) -{ - if (getNumPrograms() > 0 && newIndex != getCurrentProgram()) - dispatch (effSetProgram, 0, jlimit (0, getNumPrograms() - 1, newIndex), 0, 0); -} - -const String VSTPluginInstance::getProgramName (int index) -{ - if (index == getCurrentProgram()) - { - return getCurrentProgramName(); - } - else if (effect != 0) - { - char nm [256]; - zerostruct (nm); - - if (dispatch (effGetProgramNameIndexed, - jlimit (0, getNumPrograms(), index), - -1, nm, 0) != 0) - { - return String (nm).trim(); - } - } - - return programNames [index]; -} - -void VSTPluginInstance::changeProgramName (int index, const String& newName) -{ - if (index == getCurrentProgram()) - { - if (getNumPrograms() > 0 && newName != getCurrentProgramName()) - dispatch (effSetProgramName, 0, 0, (void*) (const char*) newName.substring (0, 24), 0.0f); - } - else - { - jassertfalse // xxx not implemented! - } -} - -void VSTPluginInstance::updateStoredProgramNames() -{ - if (effect != 0 && getNumPrograms() > 0) - { - char nm [256]; - zerostruct (nm); - - // only do this if the plugin can't use indexed names.. - if (dispatch (effGetProgramNameIndexed, 0, -1, nm, 0) == 0) - { - const int oldProgram = getCurrentProgram(); - MemoryBlock oldSettings; - createTempParameterStore (oldSettings); - - for (int i = 0; i < getNumPrograms(); ++i) - { - setCurrentProgram (i); - getCurrentProgramName(); // (this updates the list) - } - - setCurrentProgram (oldProgram); - restoreFromTempParameterStore (oldSettings); - } - } -} - -const String VSTPluginInstance::getCurrentProgramName() -{ - if (effect != 0) - { - char nm [256]; - zerostruct (nm); - dispatch (effGetProgramName, 0, 0, nm, 0); - - const int index = getCurrentProgram(); - if (programNames[index].isEmpty()) - { - while (programNames.size() < index) - programNames.add (String::empty); - - programNames.set (index, String (nm).trim()); - } - - return String (nm).trim(); - } - - return String::empty; -} - -//============================================================================== -const String VSTPluginInstance::getInputChannelName (const int index) const -{ - if (index >= 0 && index < getNumInputChannels()) - { - VstPinProperties pinProps; - if (dispatch (effGetInputProperties, index, 0, &pinProps, 0.0f) != 0) - return String (pinProps.label, sizeof (pinProps.label)); - } - - return String::empty; -} - -bool VSTPluginInstance::isInputChannelStereoPair (int index) const -{ - if (index < 0 || index >= getNumInputChannels()) - return false; - - VstPinProperties pinProps; - if (dispatch (effGetInputProperties, index, 0, &pinProps, 0.0f) != 0) - return (pinProps.flags & kVstPinIsStereo) != 0; - - return true; -} - -const String VSTPluginInstance::getOutputChannelName (const int index) const -{ - if (index >= 0 && index < getNumOutputChannels()) - { - VstPinProperties pinProps; - if (dispatch (effGetOutputProperties, index, 0, &pinProps, 0.0f) != 0) - return String (pinProps.label, sizeof (pinProps.label)); - } - - return String::empty; -} - -bool VSTPluginInstance::isOutputChannelStereoPair (int index) const -{ - if (index < 0 || index >= getNumOutputChannels()) - return false; - - VstPinProperties pinProps; - if (dispatch (effGetOutputProperties, index, 0, &pinProps, 0.0f) != 0) - return (pinProps.flags & kVstPinIsStereo) != 0; - - return true; -} - -//============================================================================== -void VSTPluginInstance::setPower (const bool on) -{ - dispatch (effMainsChanged, 0, on ? 1 : 0, 0, 0); - isPowerOn = on; -} - -//============================================================================== -const int defaultMaxSizeMB = 64; - -void VSTPluginInstance::getStateInformation (MemoryBlock& destData) -{ - saveToFXBFile (destData, true, defaultMaxSizeMB); -} - -void VSTPluginInstance::getCurrentProgramStateInformation (MemoryBlock& destData) -{ - saveToFXBFile (destData, false, defaultMaxSizeMB); -} - -void VSTPluginInstance::setStateInformation (const void* data, int sizeInBytes) -{ - loadFromFXBFile (data, sizeInBytes); -} - -void VSTPluginInstance::setCurrentProgramStateInformation (const void* data, int sizeInBytes) -{ - loadFromFXBFile (data, sizeInBytes); -} - -//============================================================================== -//============================================================================== -VSTPluginFormat::VSTPluginFormat() -{ -} - -VSTPluginFormat::~VSTPluginFormat() -{ -} - -void VSTPluginFormat::findAllTypesForFile (OwnedArray & results, - const File& file) -{ - if (! fileMightContainThisPluginType (file)) - return; - - PluginDescription desc; - desc.file = file; - desc.uid = 0; - - VSTPluginInstance* instance = dynamic_cast (createInstanceFromDescription (desc)); - - if (instance == 0) - return; - - try - { -#if JUCE_MAC - if (instance->module->resFileId != 0) - UseResFile (instance->module->resFileId); -#endif - - instance->fillInPluginDescription (desc); - - VstPlugCategory category = (VstPlugCategory) instance->dispatch (effGetPlugCategory, 0, 0, 0, 0); - - if (category != kPlugCategShell) - { - // Normal plugin... - results.add (new PluginDescription (desc)); - - ++insideVSTCallback; - instance->dispatch (effOpen, 0, 0, 0, 0); - --insideVSTCallback; - } - else - { - // It's a shell plugin, so iterate all the subtypes... - char shellEffectName [64]; - - for (;;) - { - zerostruct (shellEffectName); - const int uid = instance->dispatch (effShellGetNextPlugin, 0, 0, shellEffectName, 0); - - if (uid == 0) - { - break; - } - else - { - desc.uid = uid; - desc.name = shellEffectName; - - bool alreadyThere = false; - - for (int i = results.size(); --i >= 0;) - { - PluginDescription* const d = results.getUnchecked(i); - - if (d->isDuplicateOf (desc)) - { - alreadyThere = true; - break; - } - } - - if (! alreadyThere) - results.add (new PluginDescription (desc)); - } - } - } - } - catch (...) - { - // crashed while loading... - } - - deleteAndZero (instance); -} - -AudioPluginInstance* VSTPluginFormat::createInstanceFromDescription (const PluginDescription& desc) -{ - VSTPluginInstance* result = 0; - - if (fileMightContainThisPluginType (desc.file)) - { - const File previousWorkingDirectory (File::getCurrentWorkingDirectory()); - desc.file.getParentDirectory().setAsCurrentWorkingDirectory(); - - const ReferenceCountedObjectPtr module (ModuleHandle::findOrCreateModule (desc.file)); - - if (module != 0) - { - shellUIDToCreate = desc.uid; - - result = new VSTPluginInstance (module); - - if (result->effect != 0) - { - result->effect->resvd2 = (VstIntPtr) (pointer_sized_int) result; - result->initialise(); - } - else - { - deleteAndZero (result); - } - } - - previousWorkingDirectory.setAsCurrentWorkingDirectory(); - } - - return result; -} - -bool VSTPluginFormat::fileMightContainThisPluginType (const File& f) -{ -#if JUCE_MAC - if (f.isDirectory() && f.hasFileExtension (T(".vst"))) - return true; - -#if JUCE_PPC - FSRef fileRef; - if (PlatformUtilities::makeFSRefFromPath (&fileRef, f.getFullPathName())) - { - const short resFileId = FSOpenResFile (&fileRef, fsRdPerm); - - if (resFileId != -1) - { - const int numEffects = Count1Resources ('aEff'); - CloseResFile (resFileId); - - if (numEffects > 0) - return true; - } - } -#endif - - return false; -#elif JUCE_WIN32 - return f.existsAsFile() - && f.hasFileExtension (T(".dll")); -#elif JUCE_LINUX - return f.existsAsFile() - && f.hasFileExtension (T(".so")); -#endif -} - -const FileSearchPath VSTPluginFormat::getDefaultLocationsToSearch() -{ -#if JUCE_MAC - return FileSearchPath ("~/Library/Audio/Plug-Ins/VST;/Library/Audio/Plug-Ins/VST"); -#elif JUCE_WIN32 - const String programFiles (File::getSpecialLocation (File::globalApplicationsDirectory).getFullPathName()); - - return FileSearchPath (programFiles + "\\Steinberg\\VstPlugins"); -#elif JUCE_LINUX - return FileSearchPath ("/usr/lib/vst"); -#endif -} - -END_JUCE_NAMESPACE - -#endif - +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-7 by Raw Material Software ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified under the terms of the + GNU General Public License, as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + 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. + + You should have received a copy of the GNU General Public License + along with JUCE; if not, visit www.gnu.org/licenses or write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------------ + + If you'd like to release a closed-source product which uses JUCE, commercial + licenses are also available: visit www.rawmaterialsoftware.com/juce for + more information. + + ============================================================================== +*/ + +#include "../../../../../juce_Config.h" + +#if JUCE_PLUGINHOST_VST + +#ifdef _WIN32 + #define _WIN32_WINNT 0x500 + #define STRICT + #include + #include + #pragma warning (disable : 4312) +#elif defined (LINUX) + #include + #include + #include + #include + #include + #undef Font + #undef KeyPress + #undef Drawable + #undef Time +#else + #include +#endif + +//============================================================================== +#include "../../../../juce_core/basics/juce_StandardHeader.h" + +BEGIN_JUCE_NAMESPACE + +#include "juce_VSTPluginFormat.h" +#include "../../../../juce_core/threads/juce_Process.h" +#include "../../../../juce_core/threads/juce_ScopedLock.h" +#include "../../../../juce_core/basics/juce_Random.h" +#include "../../../events/juce_Timer.h" +#include "../../../events/juce_AsyncUpdater.h" +#include "../../../events/juce_MessageManager.h" +#include "../../../gui/components/layout/juce_ComponentMovementWatcher.h" +#include "../../../application/juce_Application.h" +#include "../../../../juce_core/misc/juce_PlatformUtilities.h" + +//============================================================================== +#undef PRAGMA_ALIGN_SUPPORTED +#define VST_FORCE_DEPRECATED 0 + +#ifdef _MSC_VER + #pragma warning (push) + #pragma warning (disable: 4996) +#endif + +/* Obviously you're going to need the Steinberg vstsdk2.4 folder in + your include path if you want to add VST support. + + If you're not interested in VSTs, you can disable them by changing the + JUCE_PLUGINHOST_VST flag in juce_Config.h +*/ +#include "pluginterfaces/vst2.x/aeffectx.h" + +#ifdef _MSC_VER + #pragma warning (pop) +#endif + +//============================================================================== +#if JUCE_LINUX + #define Font JUCE_NAMESPACE::Font + #define KeyPress JUCE_NAMESPACE::KeyPress + #define Drawable JUCE_NAMESPACE::Drawable + #define Time JUCE_NAMESPACE::Time +#endif + +#include "../juce_PluginDescription.h" + +#if ! JUCE_WIN32 + #define _fpreset() + #define _clearfp() +#endif + +extern void juce_callAnyTimersSynchronously(); + + +//============================================================================== +const int fxbVersionNum = 1; + +struct fxProgram +{ + long chunkMagic; // 'CcnK' + long byteSize; // of this chunk, excl. magic + byteSize + long fxMagic; // 'FxCk' + long version; + long fxID; // fx unique id + long fxVersion; + long numParams; + char prgName[28]; + float params[1]; // variable no. of parameters +}; + +struct fxSet +{ + long chunkMagic; // 'CcnK' + long byteSize; // of this chunk, excl. magic + byteSize + long fxMagic; // 'FxBk' + long version; + long fxID; // fx unique id + long fxVersion; + long numPrograms; + char future[128]; + fxProgram programs[1]; // variable no. of programs +}; + +struct fxChunkSet +{ + long chunkMagic; // 'CcnK' + long byteSize; // of this chunk, excl. magic + byteSize + long fxMagic; // 'FxCh', 'FPCh', or 'FBCh' + long version; + long fxID; // fx unique id + long fxVersion; + long numPrograms; + char future[128]; + long chunkSize; + char chunk[8]; // variable +}; + +struct fxProgramSet +{ + long chunkMagic; // 'CcnK' + long byteSize; // of this chunk, excl. magic + byteSize + long fxMagic; // 'FxCh', 'FPCh', or 'FBCh' + long version; + long fxID; // fx unique id + long fxVersion; + long numPrograms; + char name[28]; + long chunkSize; + char chunk[8]; // variable +}; + + +#ifdef JUCE_LITTLE_ENDIAN + static long swap (const long x) throw() { return (long) swapByteOrder ((uint32) x); } + + static float swapFloat (const float x) throw() + { + union { uint32 asInt; float asFloat; } n; + n.asFloat = x; + n.asInt = swapByteOrder (n.asInt); + return n.asFloat; + } +#else + #define swap(x) (x) + #define swapFloat(x) (x) +#endif + +//============================================================================== +typedef AEffect* (*MainCall) (audioMasterCallback); + +static VstIntPtr VSTCALLBACK audioMaster (AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt); + +static int shellUIDToCreate = 0; +static int insideVSTCallback = 0; + +class VSTPluginWindow; + +//============================================================================== +// Change this to disable logging of various VST activities +#ifndef VST_LOGGING + #define VST_LOGGING 1 +#endif + +#if VST_LOGGING + #define log(a) Logger::writeToLog(a); +#else + #define log(a) +#endif + +//============================================================================== +#if JUCE_MAC +extern bool juce_isHIViewCreatedByJuce (HIViewRef view); +extern bool juce_isWindowCreatedByJuce (WindowRef window); + +#if JUCE_PPC +static void* NewCFMFromMachO (void* const machofp) throw() +{ + void* result = juce_malloc (8); + + ((void**) result)[0] = machofp; + ((void**) result)[1] = result; + + return result; +} +#endif +#endif + +//============================================================================== +#if JUCE_LINUX + +extern Display* display; +extern XContext improbableNumber; + +typedef void (*EventProcPtr) (XEvent* ev); + +static bool xErrorTriggered; + +static int temporaryErrorHandler (Display*, XErrorEvent*) +{ + xErrorTriggered = true; + return 0; +} + +static int getPropertyFromXWindow (Window handle, Atom atom) +{ + XErrorHandler oldErrorHandler = XSetErrorHandler (temporaryErrorHandler); + xErrorTriggered = false; + + int userSize; + unsigned long bytes, userCount; + unsigned char* data; + Atom userType; + + XGetWindowProperty (display, handle, atom, 0, 1, false, AnyPropertyType, + &userType, &userSize, &userCount, &bytes, &data); + + XSetErrorHandler (oldErrorHandler); + + return (userCount == 1 && ! xErrorTriggered) ? *(int*) data + : 0; +} + +static Window getChildWindow (Window windowToCheck) +{ + Window rootWindow, parentWindow; + Window* childWindows; + unsigned int numChildren; + + XQueryTree (display, + windowToCheck, + &rootWindow, + &parentWindow, + &childWindows, + &numChildren); + + if (numChildren > 0) + return childWindows [0]; + + return 0; +} + +static void translateJuceToXButtonModifiers (const MouseEvent& e, XEvent& ev) throw() +{ + if (e.mods.isLeftButtonDown()) + { + ev.xbutton.button = Button1; + ev.xbutton.state |= Button1Mask; + } + else if (e.mods.isRightButtonDown()) + { + ev.xbutton.button = Button3; + ev.xbutton.state |= Button3Mask; + } + else if (e.mods.isMiddleButtonDown()) + { + ev.xbutton.button = Button2; + ev.xbutton.state |= Button2Mask; + } +} + +static void translateJuceToXMotionModifiers (const MouseEvent& e, XEvent& ev) throw() +{ + if (e.mods.isLeftButtonDown()) + ev.xmotion.state |= Button1Mask; + else if (e.mods.isRightButtonDown()) + ev.xmotion.state |= Button3Mask; + else if (e.mods.isMiddleButtonDown()) + ev.xmotion.state |= Button2Mask; +} + +static void translateJuceToXCrossingModifiers (const MouseEvent& e, XEvent& ev) throw() +{ + if (e.mods.isLeftButtonDown()) + ev.xcrossing.state |= Button1Mask; + else if (e.mods.isRightButtonDown()) + ev.xcrossing.state |= Button3Mask; + else if (e.mods.isMiddleButtonDown()) + ev.xcrossing.state |= Button2Mask; +} + +static void translateJuceToXMouseWheelModifiers (const MouseEvent& e, const float increment, XEvent& ev) throw() +{ + if (increment < 0) + { + ev.xbutton.button = Button5; + ev.xbutton.state |= Button5Mask; + } + else if (increment > 0) + { + ev.xbutton.button = Button4; + ev.xbutton.state |= Button4Mask; + } +} + +#endif + +//============================================================================== +static VoidArray activeModules; + +//============================================================================== +class ModuleHandle : public ReferenceCountedObject +{ +public: + //============================================================================== + File file; + MainCall moduleMain; + String pluginName; + + //============================================================================== + static ModuleHandle* findOrCreateModule (const File& file) + { + for (int i = activeModules.size(); --i >= 0;) + { + ModuleHandle* const module = (ModuleHandle*) activeModules.getUnchecked(i); + + if (module->file == file) + return module; + } + + _fpreset(); // (doesn't do any harm) + ++insideVSTCallback; + shellUIDToCreate = 0; + + log ("Attempting to load VST: " + file.getFullPathName()); + + ModuleHandle* m = new ModuleHandle (file); + + if (! m->open()) + deleteAndZero (m); + + --insideVSTCallback; + _fpreset(); // (doesn't do any harm) + + return m; + } + + //============================================================================== + ModuleHandle (const File& file_) + : file (file_), + moduleMain (0), +#if JUCE_WIN32 || JUCE_LINUX + hModule (0) +#elif JUCE_MAC + fragId (0), + resHandle (0), + bundleRef (0), + resFileId (0) +#endif + { + activeModules.add (this); + +#if JUCE_WIN32 || JUCE_LINUX + fullParentDirectoryPathName = file_.getParentDirectory().getFullPathName(); +#elif JUCE_MAC + PlatformUtilities::makeFSSpecFromPath (&parentDirFSSpec, file_.getParentDirectory().getFullPathName()); +#endif + } + + ~ModuleHandle() + { + activeModules.removeValue (this); + + close(); + } + + //============================================================================== + juce_UseDebuggingNewOperator + + //============================================================================== +#if JUCE_WIN32 || JUCE_LINUX + void* hModule; + String fullParentDirectoryPathName; + + bool open() + { +#if JUCE_WIN32 + static bool timePeriodSet = false; + + if (! timePeriodSet) + { + timePeriodSet = true; + timeBeginPeriod (2); + } +#endif + + pluginName = file.getFileNameWithoutExtension(); + + hModule = Process::loadDynamicLibrary (file.getFullPathName()); + + moduleMain = (MainCall) Process::getProcedureEntryPoint (hModule, "VSTPluginMain"); + + if (moduleMain == 0) + moduleMain = (MainCall) Process::getProcedureEntryPoint (hModule, "main"); + + return moduleMain != 0; + } + + void close() + { + _fpreset(); // (doesn't do any harm) + + Process::freeDynamicLibrary (hModule); + } + + void closeEffect (AEffect* eff) + { + eff->dispatcher (eff, effClose, 0, 0, 0, 0); + } + +#else + CFragConnectionID fragId; + Handle resHandle; + CFBundleRef bundleRef; + FSSpec parentDirFSSpec; + short resFileId; + + bool open() + { + bool ok = false; + const String filename (file.getFullPathName()); + + if (file.hasFileExtension (T(".vst"))) + { + const char* const utf8 = filename.toUTF8(); + CFURLRef url = CFURLCreateFromFileSystemRepresentation (0, (const UInt8*) utf8, + strlen (utf8), file.isDirectory()); + + if (url != 0) + { + bundleRef = CFBundleCreate (kCFAllocatorDefault, url); + CFRelease (url); + + if (bundleRef != 0) + { + if (CFBundleLoadExecutable (bundleRef)) + { + moduleMain = (MainCall) CFBundleGetFunctionPointerForName (bundleRef, CFSTR("main_macho")); + + if (moduleMain == 0) + moduleMain = (MainCall) CFBundleGetFunctionPointerForName (bundleRef, CFSTR("VSTPluginMain")); + + if (moduleMain != 0) + { + CFTypeRef name = CFBundleGetValueForInfoDictionaryKey (bundleRef, CFSTR("CFBundleName")); + + if (name != 0) + { + if (CFGetTypeID (name) == CFStringGetTypeID()) + { + char buffer[1024]; + + if (CFStringGetCString ((CFStringRef) name, buffer, sizeof (buffer), CFStringGetSystemEncoding())) + pluginName = buffer; + } + } + + if (pluginName.isEmpty()) + pluginName = file.getFileNameWithoutExtension(); + + resFileId = CFBundleOpenBundleResourceMap (bundleRef); + + ok = true; + } + } + + if (! ok) + { + CFBundleUnloadExecutable (bundleRef); + CFRelease (bundleRef); + bundleRef = 0; + } + } + } + } +#if JUCE_PPC + else + { + FSRef fn; + + if (FSPathMakeRef ((UInt8*) (const char*) filename, &fn, 0) == noErr) + { + resFileId = FSOpenResFile (&fn, fsRdPerm); + + if (resFileId != -1) + { + const int numEffs = Count1Resources ('aEff'); + + for (int i = 0; i < numEffs; ++i) + { + resHandle = Get1IndResource ('aEff', i + 1); + + if (resHandle != 0) + { + OSType type; + Str255 name; + SInt16 id; + GetResInfo (resHandle, &id, &type, name); + pluginName = String ((const char*) name + 1, name[0]); + DetachResource (resHandle); + HLock (resHandle); + + Ptr ptr; + Str255 errorText; + + OSErr err = GetMemFragment (*resHandle, GetHandleSize (resHandle), + name, kPrivateCFragCopy, + &fragId, &ptr, errorText); + + if (err == noErr) + { + moduleMain = (MainCall) newMachOFromCFM (ptr); + ok = true; + } + else + { + HUnlock (resHandle); + } + + break; + } + } + + if (! ok) + CloseResFile (resFileId); + } + } + } +#endif + + return ok; + } + + void close() + { +#if JUCE_PPC + if (fragId != 0) + { + if (moduleMain != 0) + disposeMachOFromCFM ((void*) moduleMain); + + CloseConnection (&fragId); + HUnlock (resHandle); + + if (resFileId != 0) + CloseResFile (resFileId); + } + else +#endif + if (bundleRef != 0) + { + CFBundleCloseBundleResourceMap (bundleRef, resFileId); + + if (CFGetRetainCount (bundleRef) == 1) + CFBundleUnloadExecutable (bundleRef); + + if (CFGetRetainCount (bundleRef) > 0) + CFRelease (bundleRef); + } + } + + void closeEffect (AEffect* eff) + { +#if JUCE_PPC + if (fragId != 0) + { + VoidArray thingsToDelete; + thingsToDelete.add ((void*) eff->dispatcher); + thingsToDelete.add ((void*) eff->process); + thingsToDelete.add ((void*) eff->setParameter); + thingsToDelete.add ((void*) eff->getParameter); + thingsToDelete.add ((void*) eff->processReplacing); + + eff->dispatcher (eff, effClose, 0, 0, 0, 0); + + for (int i = thingsToDelete.size(); --i >= 0;) + disposeMachOFromCFM (thingsToDelete[i]); + } + else +#endif + { + eff->dispatcher (eff, effClose, 0, 0, 0, 0); + } + } + +#if JUCE_PPC + static void* newMachOFromCFM (void* cfmfp) + { + if (cfmfp == 0) + return 0; + + UInt32* const mfp = (UInt32*) juce_malloc (sizeof (UInt32) * 6); + + mfp[0] = 0x3d800000 | ((UInt32) cfmfp >> 16); + mfp[1] = 0x618c0000 | ((UInt32) cfmfp & 0xffff); + mfp[2] = 0x800c0000; + mfp[3] = 0x804c0004; + mfp[4] = 0x7c0903a6; + mfp[5] = 0x4e800420; + + MakeDataExecutable (mfp, sizeof (UInt32) * 6); + return mfp; + } + + static void disposeMachOFromCFM (void* ptr) + { + juce_free (ptr); + } + + void coerceAEffectFunctionCalls (AEffect* eff) + { + if (fragId != 0) + { + eff->dispatcher = (AEffectDispatcherProc) newMachOFromCFM ((void*) eff->dispatcher); + eff->process = (AEffectProcessProc) newMachOFromCFM ((void*) eff->process); + eff->setParameter = (AEffectSetParameterProc) newMachOFromCFM ((void*) eff->setParameter); + eff->getParameter = (AEffectGetParameterProc) newMachOFromCFM ((void*) eff->getParameter); + eff->processReplacing = (AEffectProcessProc) newMachOFromCFM ((void*) eff->processReplacing); + } + } +#endif + +#endif +}; + + +//============================================================================== +/** + An instance of a plugin, created by a VSTPluginFormat. + +*/ +class VSTPluginInstance : public AudioPluginInstance, + private Timer, + private AsyncUpdater +{ +public: + //============================================================================== + ~VSTPluginInstance(); + + //============================================================================== + // AudioPluginInstance methods: + + void fillInPluginDescription (PluginDescription& desc) const + { + desc.name = name; + desc.file = module->file; + desc.uid = getUID(); + desc.lastFileModTime = desc.file.getLastModificationTime(); + desc.pluginFormatName = "VST"; + desc.category = getCategory(); + + { + char buffer [kVstMaxVendorStrLen + 8]; + zerostruct (buffer); + dispatch (effGetVendorString, 0, 0, buffer, 0); + desc.manufacturerName = buffer; + } + + desc.version = getVersion(); + desc.numInputChannels = getNumInputChannels(); + desc.numOutputChannels = getNumOutputChannels(); + desc.isInstrument = (effect != 0 && (effect->flags & effFlagsIsSynth) != 0); + } + + const String getName() const { return name; } + int getUID() const throw(); + bool acceptsMidi() const { return wantsMidiMessages; } + bool producesMidi() const { return dispatch (effCanDo, 0, 0, (void*) "sendVstMidiEvent", 0) > 0; } + + //============================================================================== + // AudioProcessor methods: + + void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock); + void releaseResources(); + void processBlock (AudioSampleBuffer& buffer, + MidiBuffer& midiMessages); + + AudioProcessorEditor* createEditor(); + + const String getInputChannelName (const int index) const; + bool isInputChannelStereoPair (int index) const; + + const String getOutputChannelName (const int index) const; + bool isOutputChannelStereoPair (int index) const; + + //============================================================================== + int getNumParameters() { return effect != 0 ? effect->numParams : 0; } + float getParameter (int index); + void setParameter (int index, float newValue); + const String getParameterName (int index); + const String getParameterText (int index); + bool isParameterAutomatable (int index) const; + + //============================================================================== + int getNumPrograms() { return effect != 0 ? effect->numPrograms : 0; } + int getCurrentProgram() { return dispatch (effGetProgram, 0, 0, 0, 0); } + void setCurrentProgram (int index); + const String getProgramName (int index); + void changeProgramName (int index, const String& newName); + + //============================================================================== + void getStateInformation (MemoryBlock& destData); + void getCurrentProgramStateInformation (MemoryBlock& destData); + void setStateInformation (const void* data, int sizeInBytes); + void setCurrentProgramStateInformation (const void* data, int sizeInBytes); + + //============================================================================== + void timerCallback(); + void handleAsyncUpdate(); + VstIntPtr handleCallback (VstInt32 opcode, VstInt32 index, VstInt32 value, void *ptr, float opt); + + //============================================================================== + juce_UseDebuggingNewOperator + +private: + friend class VSTPluginWindow; + friend class VSTPluginFormat; + + AEffect* effect; + String name; + CriticalSection lock; + bool wantsMidiMessages, initialised, isPowerOn; + mutable StringArray programNames; + AudioSampleBuffer tempBuffer; + CriticalSection midiInLock; + MidiBuffer incomingMidi; + void* midiEventsToSend; + int numAllocatedMidiEvents; + VstTimeInfo vstHostTime; + float** channels; + + ReferenceCountedObjectPtr module; + + //============================================================================== + int dispatch (const int opcode, const int index, const int value, void* const ptr, float opt) const; + bool restoreProgramSettings (const fxProgram* const prog); + const String getCurrentProgramName(); + void setParamsInProgramBlock (fxProgram* const prog) throw(); + void updateStoredProgramNames(); + void initialise(); + void ensureMidiEventSize (int numEventsNeeded); + void freeMidiEvents(); + void handleMidiFromPlugin (const VstEvents* const events); + void createTempParameterStore (MemoryBlock& dest); + void restoreFromTempParameterStore (const MemoryBlock& mb); + const String getParameterLabel (int index) const; + + bool usesChunks() const throw() { return effect != 0 && (effect->flags & effFlagsProgramChunks) != 0; } + void getChunkData (MemoryBlock& mb, bool isPreset, int maxSizeMB) const; + void setChunkData (const char* data, int size, bool isPreset); + bool loadFromFXBFile (const void* data, int numBytes); + bool saveToFXBFile (MemoryBlock& dest, bool isFXB, int maxSizeMB); + + int getVersionNumber() const throw() { return effect != 0 ? effect->version : 0; } + const String getVersion() const throw(); + const String getCategory() const throw(); + + bool hasEditor() const throw() { return effect != 0 && (effect->flags & effFlagsHasEditor) != 0; } + void setPower (const bool on); + + VSTPluginInstance (const ReferenceCountedObjectPtr & module); +}; + +//============================================================================== +VSTPluginInstance::VSTPluginInstance (const ReferenceCountedObjectPtr & module_) + : effect (0), + wantsMidiMessages (false), + initialised (false), + isPowerOn (false), + numAllocatedMidiEvents (0), + midiEventsToSend (0), + tempBuffer (1, 1), + channels (0), + module (module_) +{ + try + { + _fpreset(); + + ++insideVSTCallback; + + name = module->pluginName; + log (T("Creating VST instance: ") + name); + +#if JUCE_MAC + if (module->resFileId != 0) + UseResFile (module->resFileId); + +#if JUCE_PPC + if (module->fragId != 0) + { + static void* audioMasterCoerced = 0; + if (audioMasterCoerced == 0) + audioMasterCoerced = NewCFMFromMachO ((void*) &audioMaster); + + effect = module->moduleMain ((audioMasterCallback) audioMasterCoerced); + } + else +#endif +#endif + { + effect = module->moduleMain (&audioMaster); + } + + --insideVSTCallback; + + if (effect != 0 && effect->magic == kEffectMagic) + { +#if JUCE_PPC + module->coerceAEffectFunctionCalls (effect); +#endif + + jassert (effect->resvd2 == 0); + jassert (effect->object != 0); + + _fpreset(); // some dodgy plugs fuck around with this + } + else + { + effect = 0; + } + } + catch (...) + { + --insideVSTCallback; + } +} + +VSTPluginInstance::~VSTPluginInstance() +{ + { + const ScopedLock sl (lock); + + jassert (insideVSTCallback == 0); + + if (effect != 0 && effect->magic == kEffectMagic) + { + try + { +#if JUCE_MAC + if (module->resFileId != 0) + UseResFile (module->resFileId); +#endif + + // Must delete any editors before deleting the plugin instance! + jassert (getActiveEditor() == 0); + + _fpreset(); // some dodgy plugs fuck around with this + + module->closeEffect (effect); + } + catch (...) + {} + } + + module = 0; + effect = 0; + } + + freeMidiEvents(); + + juce_free (channels); + channels = 0; +} + +//============================================================================== +void VSTPluginInstance::initialise() +{ + if (initialised || effect == 0) + return; + + log (T("Initialising VST: ") + module->pluginName); + initialised = true; + + dispatch (effIdentify, 0, 0, 0, 0); + + // this code would ask the plugin for its name, but so few plugins + // actually bother implementing this correctly, that it's better to + // just ignore it and use the file name instead. +/* { + char buffer [256]; + zerostruct (buffer); + dispatch (effGetEffectName, 0, 0, buffer, 0); + + name = String (buffer).trim(); + if (name.isEmpty()) + name = module->pluginName; + } +*/ + + if (getSampleRate() > 0) + dispatch (effSetSampleRate, 0, 0, 0, (float) getSampleRate()); + + if (getBlockSize() > 0) + dispatch (effSetBlockSize, 0, jmax (32, getBlockSize()), 0, 0); + + dispatch (effOpen, 0, 0, 0, 0); + + setPlayConfigDetails (effect->numInputs, effect->numOutputs, + getSampleRate(), getBlockSize()); + + if (getNumPrograms() > 1) + setCurrentProgram (0); + else + dispatch (effSetProgram, 0, 0, 0, 0); + + int i; + for (i = effect->numInputs; --i >= 0;) + dispatch (effConnectInput, i, 1, 0, 0); + + for (i = effect->numOutputs; --i >= 0;) + dispatch (effConnectOutput, i, 1, 0, 0); + + updateStoredProgramNames(); + + wantsMidiMessages = dispatch (effCanDo, 0, 0, (void*) "receiveVstMidiEvent", 0) > 0; + + setLatencySamples (effect->initialDelay); +} + + +//============================================================================== +void VSTPluginInstance::prepareToPlay (double sampleRate_, + int samplesPerBlockExpected) +{ + setPlayConfigDetails (effect->numInputs, effect->numOutputs, + sampleRate_, samplesPerBlockExpected); + + setLatencySamples (effect->initialDelay); + + juce_free (channels); + channels = (float**) juce_calloc (sizeof (float*) * jmax (16, getNumOutputChannels() + 2, getNumInputChannels() + 2)); + + vstHostTime.tempo = 120.0; + vstHostTime.timeSigNumerator = 4; + vstHostTime.timeSigDenominator = 4; + vstHostTime.sampleRate = sampleRate_; + vstHostTime.samplePos = 0; + vstHostTime.flags = kVstNanosValid; /*| kVstTransportPlaying | kVstTempoValid | kVstTimeSigValid*/; + + initialise(); + + if (initialised) + { + wantsMidiMessages = wantsMidiMessages + || (dispatch (effCanDo, 0, 0, (void*) "receiveVstMidiEvent", 0) > 0); + + if (wantsMidiMessages) + ensureMidiEventSize (256); + else + freeMidiEvents(); + + incomingMidi.clear(); + + dispatch (effSetSampleRate, 0, 0, 0, (float) sampleRate_); + dispatch (effSetBlockSize, 0, jmax (16, samplesPerBlockExpected), 0, 0); + + tempBuffer.setSize (jmax (1, effect->numOutputs), samplesPerBlockExpected); + + if (! isPowerOn) + setPower (true); + + // dodgy hack to force some plugins to initialise the sample rate.. + if ((! hasEditor()) && getNumParameters() > 0) + { + const float old = getParameter (0); + setParameter (0, (old < 0.5f) ? 1.0f : 0.0f); + setParameter (0, old); + } + + dispatch (effStartProcess, 0, 0, 0, 0); + } +} + +void VSTPluginInstance::releaseResources() +{ + if (initialised) + { + dispatch (effStopProcess, 0, 0, 0, 0); + setPower (false); + } + + tempBuffer.setSize (1, 1); + incomingMidi.clear(); + + freeMidiEvents(); + juce_free (channels); + channels = 0; +} + +void VSTPluginInstance::processBlock (AudioSampleBuffer& buffer, + MidiBuffer& midiMessages) +{ + const int numSamples = buffer.getNumSamples(); + + if (initialised) + { +#if JUCE_WIN32 + vstHostTime.nanoSeconds = timeGetTime() * 1000000.0; +#elif JUCE_LINUX + timeval micro; + gettimeofday (µ, 0); + vstHostTime.nanoSeconds = micro.tv_usec * 1000.0; +#elif JUCE_MAC + UnsignedWide micro; + Microseconds (µ); + vstHostTime.nanoSeconds = micro.lo * 1000.0; +#endif + + if (wantsMidiMessages) + { + MidiBuffer::Iterator iter (midiMessages); + + int eventIndex = 0; + const uint8* midiData; + int numBytesOfMidiData, samplePosition; + + while (iter.getNextEvent (midiData, numBytesOfMidiData, samplePosition)) + { + if (numBytesOfMidiData < 4) + { + ensureMidiEventSize (eventIndex); + VstMidiEvent* const e + = (VstMidiEvent*) ((VstEvents*) midiEventsToSend)->events [eventIndex++]; + + // check that some plugin hasn't messed up our objects + jassert (e->type == kVstMidiType); + jassert (e->byteSize == 24); + + e->deltaFrames = jlimit (0, numSamples - 1, samplePosition); + e->noteLength = 0; + e->noteOffset = 0; + e->midiData[0] = midiData[0]; + e->midiData[1] = midiData[1]; + e->midiData[2] = midiData[2]; + e->detune = 0; + e->noteOffVelocity = 0; + } + } + + if (midiEventsToSend == 0) + ensureMidiEventSize (1); + + ((VstEvents*) midiEventsToSend)->numEvents = eventIndex; + + try + { + effect->dispatcher (effect, effProcessEvents, 0, 0, midiEventsToSend, 0); + } + catch (...) + {} + } + + int i; + const int maxChans = jmax (effect->numInputs, effect->numOutputs); + + for (i = 0; i < maxChans; ++i) + channels[i] = buffer.getSampleData (i); + + channels [maxChans] = 0; + + _clearfp(); + + if ((effect->flags & effFlagsCanReplacing) != 0) + { + try + { + effect->processReplacing (effect, channels, channels, numSamples); + } + catch (...) + {} + } + else + { + tempBuffer.setSize (effect->numOutputs, numSamples); + tempBuffer.clear(); + + float* outs [64]; + + for (i = effect->numOutputs; --i >= 0;) + outs[i] = tempBuffer.getSampleData (i); + + outs [effect->numOutputs] = 0; + + try + { + effect->process (effect, channels, outs, numSamples); + } + catch (...) + {} + + for (i = effect->numOutputs; --i >= 0;) + buffer.copyFrom (i, 0, outs[i], numSamples); + } + } + else + { + // Not initialised, so just bypass.. + for (int i = getNumInputChannels(); i < getNumOutputChannels(); ++i) + buffer.clear (i, 0, buffer.getNumSamples()); + } + + { + // copy any incoming midi.. + const ScopedLock sl (midiInLock); + + midiMessages = incomingMidi; + incomingMidi.clear(); + } +} + +//============================================================================== +void VSTPluginInstance::ensureMidiEventSize (int numEventsNeeded) +{ + if (numEventsNeeded > numAllocatedMidiEvents) + { + numEventsNeeded = (numEventsNeeded + 32) & ~31; + + const int size = 20 + sizeof (VstEvent*) * numEventsNeeded; + + if (midiEventsToSend == 0) + midiEventsToSend = juce_calloc (size); + else + midiEventsToSend = juce_realloc (midiEventsToSend, size); + + for (int i = numAllocatedMidiEvents; i < numEventsNeeded; ++i) + { + VstMidiEvent* const e = (VstMidiEvent*) juce_calloc (sizeof (VstMidiEvent)); + e->type = kVstMidiType; + e->byteSize = 24; + + ((VstEvents*) midiEventsToSend)->events[i] = (VstEvent*) e; + } + + numAllocatedMidiEvents = numEventsNeeded; + } +} + +void VSTPluginInstance::freeMidiEvents() +{ + if (midiEventsToSend != 0) + { + for (int i = numAllocatedMidiEvents; --i >= 0;) + juce_free (((VstEvents*) midiEventsToSend)->events[i]); + + juce_free (midiEventsToSend); + midiEventsToSend = 0; + numAllocatedMidiEvents = 0; + } +} + +void VSTPluginInstance::handleMidiFromPlugin (const VstEvents* const events) +{ + if (events != 0) + { + const ScopedLock sl (midiInLock); + + for (int i = 0; i < events->numEvents; ++i) + { + const VstEvent* const e = events->events[i]; + + if (e->type == kVstMidiType) + { + incomingMidi.addEvent ((const uint8*) ((const VstMidiEvent*) e)->midiData, + 3, e->deltaFrames); + } + } + } +} + +//============================================================================== +static Array activeWindows; + +//============================================================================== +class VSTPluginWindow : public AudioProcessorEditor, + public Timer +{ +public: + //============================================================================== + VSTPluginWindow (VSTPluginInstance& plugin_) + : AudioProcessorEditor (&plugin_), + plugin (plugin_), + isOpen (false), + wasShowing (false), + pluginRefusesToResize (false), + pluginWantsKeys (false), + alreadyInside (false), + recursiveResize (false) + { +#if JUCE_WIN32 + sizeCheckCount = 0; + pluginHWND = 0; +#elif JUCE_LINUX + pluginWindow = None; + pluginProc = None; +#else + pluginViewRef = 0; +#endif + + movementWatcher = new CompMovementWatcher (this); + + activeWindows.add (this); + + setSize (1, 1); + setOpaque (true); + setVisible (true); + } + + ~VSTPluginWindow() + { + deleteAndZero (movementWatcher); + + closePluginWindow(); + + activeWindows.removeValue (this); + plugin.editorBeingDeleted (this); + } + + //============================================================================== + void componentMovedOrResized() + { + if (recursiveResize) + return; + + Component* const topComp = getTopLevelComponent(); + + if (topComp->getPeer() != 0) + { + int x = 0, y = 0; + relativePositionToOtherComponent (topComp, x, y); + + recursiveResize = true; + +#if JUCE_MAC + if (pluginViewRef != 0) + { + HIRect r; + r.origin.x = (float) x; + r.origin.y = (float) y; + r.size.width = (float) getWidth(); + r.size.height = (float) getHeight(); + HIViewSetFrame (pluginViewRef, &r); + } + else if (pluginWindowRef != 0) + { + Rect r; + r.left = getScreenX(); + r.top = getScreenY(); + r.right = r.left + getWidth(); + r.bottom = r.top + getHeight(); + + WindowGroupRef group = GetWindowGroup (pluginWindowRef); + WindowGroupAttributes atts; + GetWindowGroupAttributes (group, &atts); + ChangeWindowGroupAttributes (group, 0, kWindowGroupAttrMoveTogether); + + SetWindowBounds (pluginWindowRef, kWindowContentRgn, &r); + + if ((atts & kWindowGroupAttrMoveTogether) != 0) + ChangeWindowGroupAttributes (group, kWindowGroupAttrMoveTogether, 0); + } + else + { + repaint(); + } +#elif JUCE_WIN32 + if (pluginHWND != 0) + MoveWindow (pluginHWND, x, y, getWidth(), getHeight(), TRUE); +#elif JUCE_LINUX + if (pluginWindow != 0) + { + XResizeWindow (display, pluginWindow, getWidth(), getHeight()); + XMoveWindow (display, pluginWindow, x, y); + XMapRaised (display, pluginWindow); + } +#endif + + recursiveResize = false; + } + } + + void componentVisibilityChanged() + { + const bool isShowingNow = isShowing(); + + if (wasShowing != isShowingNow) + { + wasShowing = isShowingNow; + + if (isShowingNow) + openPluginWindow(); + else + closePluginWindow(); + } + + componentMovedOrResized(); + } + + void componentPeerChanged() + { + closePluginWindow(); + openPluginWindow(); + } + + //============================================================================== + bool keyStateChanged() + { + return pluginWantsKeys; + } + + bool keyPressed (const KeyPress&) + { + return pluginWantsKeys; + } + + //============================================================================== + void paint (Graphics& g) + { + if (isOpen) + { + ComponentPeer* const peer = getPeer(); + + if (peer != 0) + { + peer->addMaskedRegion (getScreenX() - peer->getScreenX(), + getScreenY() - peer->getScreenY(), + getWidth(), getHeight()); + +#if JUCE_MAC + if (pluginViewRef == 0) + { + ERect r; + r.left = getScreenX() - peer->getScreenX(); + r.right = r.left + getWidth(); + r.top = getScreenY() - peer->getScreenY(); + r.bottom = r.top + getHeight(); + + dispatch (effEditDraw, 0, 0, &r, 0); + } +#elif JUCE_LINUX + if (pluginWindow != 0) + { + const Rectangle clip (g.getClipBounds()); + + XEvent ev; + zerostruct (ev); + ev.xexpose.type = Expose; + ev.xexpose.display = display; + ev.xexpose.window = pluginWindow; + ev.xexpose.x = clip.getX(); + ev.xexpose.y = clip.getY(); + ev.xexpose.width = clip.getWidth(); + ev.xexpose.height = clip.getHeight(); + + sendEventToChild (&ev); + } +#endif + } + } + else + { + g.fillAll (Colours::black); + } + } + + //============================================================================== + void timerCallback() + { +#if JUCE_WIN32 + if (--sizeCheckCount <= 0) + { + sizeCheckCount = 10; + + checkPluginWindowSize(); + } +#endif + + try + { + static bool reentrant = false; + + if (! reentrant) + { + reentrant = true; + plugin.dispatch (effEditIdle, 0, 0, 0, 0); + reentrant = false; + } + } + catch (...) + {} + } + + //============================================================================== + void mouseDown (const MouseEvent& e) + { +#if JUCE_MAC + if (! alreadyInside) + { + alreadyInside = true; + toFront (true); + dispatch (effEditMouse, e.x, e.y, 0, 0); + alreadyInside = false; + } + else + { + PostEvent (::mouseDown, 0); + } +#elif JUCE_LINUX + + if (pluginWindow == 0) + return; + + toFront (true); + + XEvent ev; + zerostruct (ev); + ev.xbutton.display = display; + ev.xbutton.type = ButtonPress; + ev.xbutton.window = pluginWindow; + ev.xbutton.root = RootWindow (display, DefaultScreen (display)); + ev.xbutton.time = CurrentTime; + ev.xbutton.x = e.x; + ev.xbutton.y = e.y; + ev.xbutton.x_root = e.getScreenX(); + ev.xbutton.y_root = e.getScreenY(); + + translateJuceToXButtonModifiers (e, ev); + + sendEventToChild (&ev); + +#else + (void) e; + + toFront (true); +#endif + } + + void broughtToFront() + { + activeWindows.removeValue (this); + activeWindows.add (this); + +#if JUCE_MAC + dispatch (effEditTop, 0, 0, 0, 0); +#endif + } + + //============================================================================== + juce_UseDebuggingNewOperator + +private: + VSTPluginInstance& plugin; + bool isOpen, wasShowing, recursiveResize; + bool pluginWantsKeys, pluginRefusesToResize, alreadyInside; + +#if JUCE_WIN32 + HWND pluginHWND; + void* originalWndProc; + int sizeCheckCount; +#elif JUCE_MAC + HIViewRef pluginViewRef; + WindowRef pluginWindowRef; +#elif JUCE_LINUX + Window pluginWindow; + EventProcPtr pluginProc; +#endif + + //============================================================================== + void openPluginWindow() + { + if (isOpen || getWindowHandle() == 0) + return; + + log (T("Opening VST UI: ") + plugin.name); + isOpen = true; + + ERect* rect = 0; + dispatch (effEditGetRect, 0, 0, &rect, 0); + dispatch (effEditOpen, 0, 0, getWindowHandle(), 0); + + // do this before and after like in the steinberg example + dispatch (effEditGetRect, 0, 0, &rect, 0); + dispatch (effGetProgram, 0, 0, 0, 0); // also in steinberg code + + // Install keyboard hooks + pluginWantsKeys = (dispatch (effKeysRequired, 0, 0, 0, 0) == 0); + +#if JUCE_WIN32 + originalWndProc = 0; + pluginHWND = GetWindow ((HWND) getWindowHandle(), GW_CHILD); + + if (pluginHWND == 0) + { + isOpen = false; + setSize (300, 150); + return; + } + + #pragma warning (push) + #pragma warning (disable: 4244) + + originalWndProc = (void*) GetWindowLongPtr (pluginHWND, GWL_WNDPROC); + + if (! pluginWantsKeys) + SetWindowLongPtr (pluginHWND, GWL_WNDPROC, (LONG_PTR) vstHookWndProc); + + #pragma warning (pop) + + int w, h; + RECT r; + GetWindowRect (pluginHWND, &r); + w = r.right - r.left; + h = r.bottom - r.top; + + if (rect != 0) + { + const int rw = rect->right - rect->left; + const int rh = rect->bottom - rect->top; + + if ((rw > 50 && rh > 50 && rw < 2000 && rh < 2000 && rw != w && rh != h) + || ((w == 0 && rw > 0) || (h == 0 && rh > 0))) + { + // very dodgy logic to decide which size is right. + if (abs (rw - w) > 350 || abs (rh - h) > 350) + { + SetWindowPos (pluginHWND, 0, + 0, 0, rw, rh, + SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER); + + GetWindowRect (pluginHWND, &r); + + w = r.right - r.left; + h = r.bottom - r.top; + + pluginRefusesToResize = (w != rw) || (h != rh); + + w = rw; + h = rh; + } + } + } +#elif JUCE_MAC + HIViewRef root = HIViewGetRoot ((WindowRef) getWindowHandle()); + HIViewFindByID (root, kHIViewWindowContentID, &root); + pluginViewRef = HIViewGetFirstSubview (root); + + while (pluginViewRef != 0 && juce_isHIViewCreatedByJuce (pluginViewRef)) + pluginViewRef = HIViewGetNextView (pluginViewRef); + + pluginWindowRef = 0; + + if (pluginViewRef == 0) + { + WindowGroupRef ourGroup = GetWindowGroup ((WindowRef) getWindowHandle()); + //DebugPrintWindowGroup (ourGroup); + //DebugPrintAllWindowGroups(); + + GetIndexedWindow (ourGroup, 1, + kWindowGroupContentsVisible, + &pluginWindowRef); + + if (pluginWindowRef == (WindowRef) getWindowHandle() + || juce_isWindowCreatedByJuce (pluginWindowRef)) + pluginWindowRef = 0; + } + + int w = 250, h = 150; + + if (rect != 0) + { + w = rect->right - rect->left; + h = rect->bottom - rect->top; + + if (w == 0 || h == 0) + { + w = 250; + h = 150; + } + } + +#elif JUCE_LINUX + pluginWindow = getChildWindow ((Window) getWindowHandle()); + + if (pluginWindow != 0) + pluginProc = (EventProcPtr) getPropertyFromXWindow (pluginWindow, + XInternAtom (display, "_XEventProc", False)); + + int w = 250, h = 150; + + if (rect != 0) + { + w = rect->right - rect->left; + h = rect->bottom - rect->top; + + if (w == 0 || h == 0) + { + w = 250; + h = 150; + } + } + + if (pluginWindow != 0) + XMapRaised (display, pluginWindow); +#endif + + // double-check it's not too tiny + w = jmax (w, 32); + h = jmax (h, 32); + + setSize (w, h); + +#if JUCE_WIN32 + checkPluginWindowSize(); +#endif + + startTimer (18 + JUCE_NAMESPACE::Random::getSystemRandom().nextInt (5)); + repaint(); + } + + //============================================================================== + void closePluginWindow() + { + if (isOpen) + { + log (T("Closing VST UI: ") + plugin.getName()); + isOpen = false; + + dispatch (effEditClose, 0, 0, 0, 0); + +#if JUCE_WIN32 + #pragma warning (push) + #pragma warning (disable: 4244) + + if (pluginHWND != 0 && IsWindow (pluginHWND)) + SetWindowLongPtr (pluginHWND, GWL_WNDPROC, (LONG_PTR) originalWndProc); + + #pragma warning (pop) + + stopTimer(); + + if (pluginHWND != 0 && IsWindow (pluginHWND)) + DestroyWindow (pluginHWND); + + pluginHWND = 0; +#elif JUCE_MAC + dispatch (effEditSleep, 0, 0, 0, 0); + pluginViewRef = 0; + stopTimer(); +#elif JUCE_LINUX + stopTimer(); + pluginWindow = 0; + pluginProc = 0; +#endif + } + } + + //============================================================================== +#if JUCE_WIN32 + void checkPluginWindowSize() throw() + { + RECT r; + GetWindowRect (pluginHWND, &r); + const int w = r.right - r.left; + const int h = r.bottom - r.top; + + if (isShowing() && w > 0 && h > 0 + && (w != getWidth() || h != getHeight()) + && ! pluginRefusesToResize) + { + setSize (w, h); + sizeCheckCount = 0; + } + } +#endif + + //============================================================================== + class CompMovementWatcher : public ComponentMovementWatcher + { + public: + CompMovementWatcher (VSTPluginWindow* const owner_) + : ComponentMovementWatcher (owner_), + owner (owner_) + { + } + + //============================================================================== + void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) + { + owner->componentMovedOrResized(); + } + + void componentPeerChanged() + { + owner->componentPeerChanged(); + } + + void componentVisibilityChanged (Component&) + { + owner->componentVisibilityChanged(); + } + + private: + VSTPluginWindow* const owner; + }; + + CompMovementWatcher* movementWatcher; + + //============================================================================== + int dispatch (const int opcode, const int index, const int value, void* const ptr, float opt) + { + return plugin.dispatch (opcode, index, value, ptr, opt); + } + + //============================================================================== + // hooks to get keyboard events from VST windows.. +#if JUCE_WIN32 + static LRESULT CALLBACK vstHookWndProc (HWND hW, UINT message, WPARAM wParam, LPARAM lParam) + { + for (int i = activeWindows.size(); --i >= 0;) + { + const VSTPluginWindow* const w = (const VSTPluginWindow*) activeWindows.getUnchecked (i); + + if (w->pluginHWND == hW) + { + if (message == WM_CHAR + || message == WM_KEYDOWN + || message == WM_SYSKEYDOWN + || message == WM_KEYUP + || message == WM_SYSKEYUP + || message == WM_APPCOMMAND) + { + SendMessage ((HWND) w->getTopLevelComponent()->getWindowHandle(), + message, wParam, lParam); + } + + return CallWindowProc ((WNDPROC) (w->originalWndProc), + (HWND) w->pluginHWND, + message, + wParam, + lParam); + } + } + + return DefWindowProc (hW, message, wParam, lParam); + } +#endif + +#if JUCE_LINUX + //============================================================================== + // overload mouse/keyboard events to forward them to the plugin's inner window.. + void sendEventToChild (XEvent* event) + { + if (pluginProc != 0) + { + // if the plugin publishes an event procedure, pass the event directly.. + pluginProc (event); + } + else if (pluginWindow != 0) + { + // if the plugin has a window, then send the event to the window so that + // its message thread will pick it up.. + XSendEvent (display, pluginWindow, False, 0L, event); + XFlush (display); + } + } + + void mouseEnter (const MouseEvent& e) + { + if (pluginWindow != 0) + { + XEvent ev; + zerostruct (ev); + ev.xcrossing.display = display; + ev.xcrossing.type = EnterNotify; + ev.xcrossing.window = pluginWindow; + ev.xcrossing.root = RootWindow (display, DefaultScreen (display)); + ev.xcrossing.time = CurrentTime; + ev.xcrossing.x = e.x; + ev.xcrossing.y = e.y; + ev.xcrossing.x_root = e.getScreenX(); + ev.xcrossing.y_root = e.getScreenY(); + ev.xcrossing.mode = NotifyNormal; // NotifyGrab, NotifyUngrab + ev.xcrossing.detail = NotifyAncestor; // NotifyVirtual, NotifyInferior, NotifyNonlinear,NotifyNonlinearVirtual + + translateJuceToXCrossingModifiers (e, ev); + + sendEventToChild (&ev); + } + } + + void mouseExit (const MouseEvent& e) + { + if (pluginWindow != 0) + { + XEvent ev; + zerostruct (ev); + ev.xcrossing.display = display; + ev.xcrossing.type = LeaveNotify; + ev.xcrossing.window = pluginWindow; + ev.xcrossing.root = RootWindow (display, DefaultScreen (display)); + ev.xcrossing.time = CurrentTime; + ev.xcrossing.x = e.x; + ev.xcrossing.y = e.y; + ev.xcrossing.x_root = e.getScreenX(); + ev.xcrossing.y_root = e.getScreenY(); + ev.xcrossing.mode = NotifyNormal; // NotifyGrab, NotifyUngrab + ev.xcrossing.detail = NotifyAncestor; // NotifyVirtual, NotifyInferior, NotifyNonlinear,NotifyNonlinearVirtual + ev.xcrossing.focus = hasKeyboardFocus (true); // TODO - yes ? + + translateJuceToXCrossingModifiers (e, ev); + + sendEventToChild (&ev); + } + } + + void mouseMove (const MouseEvent& e) + { + if (pluginWindow != 0) + { + XEvent ev; + zerostruct (ev); + ev.xmotion.display = display; + ev.xmotion.type = MotionNotify; + ev.xmotion.window = pluginWindow; + ev.xmotion.root = RootWindow (display, DefaultScreen (display)); + ev.xmotion.time = CurrentTime; + ev.xmotion.is_hint = NotifyNormal; + ev.xmotion.x = e.x; + ev.xmotion.y = e.y; + ev.xmotion.x_root = e.getScreenX(); + ev.xmotion.y_root = e.getScreenY(); + + sendEventToChild (&ev); + } + } + + void mouseDrag (const MouseEvent& e) + { + if (pluginWindow != 0) + { + XEvent ev; + zerostruct (ev); + ev.xmotion.display = display; + ev.xmotion.type = MotionNotify; + ev.xmotion.window = pluginWindow; + ev.xmotion.root = RootWindow (display, DefaultScreen (display)); + ev.xmotion.time = CurrentTime; + ev.xmotion.x = e.x ; + ev.xmotion.y = e.y; + ev.xmotion.x_root = e.getScreenX(); + ev.xmotion.y_root = e.getScreenY(); + ev.xmotion.is_hint = NotifyNormal; + + translateJuceToXMotionModifiers (e, ev); + sendEventToChild (&ev); + } + } + + void mouseUp (const MouseEvent& e) + { + if (pluginWindow != 0) + { + XEvent ev; + zerostruct (ev); + ev.xbutton.display = display; + ev.xbutton.type = ButtonRelease; + ev.xbutton.window = pluginWindow; + ev.xbutton.root = RootWindow (display, DefaultScreen (display)); + ev.xbutton.time = CurrentTime; + ev.xbutton.x = e.x; + ev.xbutton.y = e.y; + ev.xbutton.x_root = e.getScreenX(); + ev.xbutton.y_root = e.getScreenY(); + + translateJuceToXButtonModifiers (e, ev); + sendEventToChild (&ev); + } + } + + void mouseWheelMove (const MouseEvent& e, + float incrementX, + float incrementY) + { + if (pluginWindow != 0) + { + XEvent ev; + zerostruct (ev); + ev.xbutton.display = display; + ev.xbutton.type = ButtonPress; + ev.xbutton.window = pluginWindow; + ev.xbutton.root = RootWindow (display, DefaultScreen (display)); + ev.xbutton.time = CurrentTime; + ev.xbutton.x = e.x; + ev.xbutton.y = e.y; + ev.xbutton.x_root = e.getScreenX(); + ev.xbutton.y_root = e.getScreenY(); + + translateJuceToXMouseWheelModifiers (e, incrementY, ev); + sendEventToChild (&ev); + + // TODO - put a usleep here ? + + ev.xbutton.type = ButtonRelease; + sendEventToChild (&ev); + } + } +#endif + +}; + +//============================================================================== +AudioProcessorEditor* VSTPluginInstance::createEditor() +{ + if (hasEditor()) + return new VSTPluginWindow (*this); + + return 0; +} + + +//============================================================================== +void VSTPluginInstance::handleAsyncUpdate() +{ + // indicates that something about the plugin has changed.. + updateHostDisplay(); +} + +//============================================================================== +bool VSTPluginInstance::restoreProgramSettings (const fxProgram* const prog) +{ + if (swap (prog->chunkMagic) == 'CcnK' && swap (prog->fxMagic) == 'FxCk') + { + changeProgramName (getCurrentProgram(), prog->prgName); + + for (int i = 0; i < swap (prog->numParams); ++i) + setParameter (i, swapFloat (prog->params[i])); + + return true; + } + + return false; +} + +bool VSTPluginInstance::loadFromFXBFile (const void* const data, + const int dataSize) +{ + if (dataSize < 28) + return false; + + const fxSet* const set = (const fxSet*) data; + + if ((swap (set->chunkMagic) != 'CcnK' && swap (set->chunkMagic) != 'KncC') + || swap (set->version) > fxbVersionNum) + return false; + + if (swap (set->fxMagic) == 'FxBk') + { + // bank of programs + if (swap (set->numPrograms) >= 0) + { + const int oldProg = getCurrentProgram(); + const int numParams = swap (((const fxProgram*) (set->programs))->numParams); + const int progLen = sizeof (fxProgram) + (numParams - 1) * sizeof (float); + + for (int i = 0; i < swap (set->numPrograms); ++i) + { + if (i != oldProg) + { + const fxProgram* const prog = (const fxProgram*) (((const char*) (set->programs)) + i * progLen); + if (((const char*) prog) - ((const char*) set) >= dataSize) + return false; + + if (swap (set->numPrograms) > 0) + setCurrentProgram (i); + + if (! restoreProgramSettings (prog)) + return false; + } + } + + if (swap (set->numPrograms) > 0) + setCurrentProgram (oldProg); + + const fxProgram* const prog = (const fxProgram*) (((const char*) (set->programs)) + oldProg * progLen); + if (((const char*) prog) - ((const char*) set) >= dataSize) + return false; + + if (! restoreProgramSettings (prog)) + return false; + } + } + else if (swap (set->fxMagic) == 'FxCk') + { + // single program + const fxProgram* const prog = (const fxProgram*) data; + + if (swap (prog->chunkMagic) != 'CcnK') + return false; + + changeProgramName (getCurrentProgram(), prog->prgName); + + for (int i = 0; i < swap (prog->numParams); ++i) + setParameter (i, swapFloat (prog->params[i])); + } + else if (swap (set->fxMagic) == 'FBCh' || swap (set->fxMagic) == 'hCBF') + { + // non-preset chunk + const fxChunkSet* const cset = (const fxChunkSet*) data; + + if (swap (cset->chunkSize) + sizeof (fxChunkSet) - 8 > (unsigned int) dataSize) + return false; + + setChunkData (cset->chunk, swap (cset->chunkSize), false); + } + else if (swap (set->fxMagic) == 'FPCh' || swap (set->fxMagic) == 'hCPF') + { + // preset chunk + const fxProgramSet* const cset = (const fxProgramSet*) data; + + if (swap (cset->chunkSize) + sizeof (fxProgramSet) - 8 > (unsigned int) dataSize) + return false; + + setChunkData (cset->chunk, swap (cset->chunkSize), true); + + changeProgramName (getCurrentProgram(), cset->name); + } + else + { + return false; + } + + return true; +} + +//============================================================================== +void VSTPluginInstance::setParamsInProgramBlock (fxProgram* const prog) throw() +{ + const int numParams = getNumParameters(); + + prog->chunkMagic = swap ('CcnK'); + prog->byteSize = 0; + prog->fxMagic = swap ('FxCk'); + prog->version = swap (fxbVersionNum); + prog->fxID = swap (getUID()); + prog->fxVersion = swap (getVersionNumber()); + prog->numParams = swap (numParams); + + getCurrentProgramName().copyToBuffer (prog->prgName, sizeof (prog->prgName) - 1); + + for (int i = 0; i < numParams; ++i) + prog->params[i] = swapFloat (getParameter (i)); +} + +bool VSTPluginInstance::saveToFXBFile (MemoryBlock& dest, bool isFXB, int maxSizeMB) +{ + const int numPrograms = getNumPrograms(); + const int numParams = getNumParameters(); + + if (usesChunks()) + { + if (isFXB) + { + MemoryBlock chunk; + getChunkData (chunk, false, maxSizeMB); + + const int totalLen = sizeof (fxChunkSet) + chunk.getSize() - 8; + dest.setSize (totalLen, true); + + fxChunkSet* const set = (fxChunkSet*) dest.getData(); + set->chunkMagic = swap ('CcnK'); + set->byteSize = 0; + set->fxMagic = swap ('FBCh'); + set->version = swap (fxbVersionNum); + set->fxID = swap (getUID()); + set->fxVersion = swap (getVersionNumber()); + set->numPrograms = swap (numPrograms); + set->chunkSize = swap (chunk.getSize()); + + chunk.copyTo (set->chunk, 0, chunk.getSize()); + } + else + { + MemoryBlock chunk; + getChunkData (chunk, true, maxSizeMB); + + const int totalLen = sizeof (fxProgramSet) + chunk.getSize() - 8; + dest.setSize (totalLen, true); + + fxProgramSet* const set = (fxProgramSet*) dest.getData(); + set->chunkMagic = swap ('CcnK'); + set->byteSize = 0; + set->fxMagic = swap ('FPCh'); + set->version = swap (fxbVersionNum); + set->fxID = swap (getUID()); + set->fxVersion = swap (getVersionNumber()); + set->numPrograms = swap (numPrograms); + set->chunkSize = swap (chunk.getSize()); + + getCurrentProgramName().copyToBuffer (set->name, sizeof (set->name) - 1); + chunk.copyTo (set->chunk, 0, chunk.getSize()); + } + } + else + { + if (isFXB) + { + const int progLen = sizeof (fxProgram) + (numParams - 1) * sizeof (float); + const int len = (sizeof (fxSet) - sizeof (fxProgram)) + progLen * jmax (1, numPrograms); + dest.setSize (len, true); + + fxSet* const set = (fxSet*) dest.getData(); + set->chunkMagic = swap ('CcnK'); + set->byteSize = 0; + set->fxMagic = swap ('FxBk'); + set->version = swap (fxbVersionNum); + set->fxID = swap (getUID()); + set->fxVersion = swap (getVersionNumber()); + set->numPrograms = swap (numPrograms); + + const int oldProgram = getCurrentProgram(); + MemoryBlock oldSettings; + createTempParameterStore (oldSettings); + + setParamsInProgramBlock ((fxProgram*) (((char*) (set->programs)) + oldProgram * progLen)); + + for (int i = 0; i < numPrograms; ++i) + { + if (i != oldProgram) + { + setCurrentProgram (i); + setParamsInProgramBlock ((fxProgram*) (((char*) (set->programs)) + i * progLen)); + } + } + + setCurrentProgram (oldProgram); + restoreFromTempParameterStore (oldSettings); + } + else + { + const int totalLen = sizeof (fxProgram) + (numParams - 1) * sizeof (float); + dest.setSize (totalLen, true); + + setParamsInProgramBlock ((fxProgram*) dest.getData()); + } + } + + return true; +} + +void VSTPluginInstance::getChunkData (MemoryBlock& mb, bool isPreset, int maxSizeMB) const +{ + if (usesChunks()) + { + void* data = 0; + const int bytes = dispatch (effGetChunk, isPreset ? 1 : 0, 0, &data, 0.0f); + + if (data != 0 && bytes <= maxSizeMB * 1024 * 1024) + { + mb.setSize (bytes); + mb.copyFrom (data, 0, bytes); + } + } +} + +void VSTPluginInstance::setChunkData (const char* data, int size, bool isPreset) +{ + if (size > 0 && usesChunks()) + { + dispatch (effSetChunk, isPreset ? 1 : 0, size, (void*) data, 0.0f); + + if (! isPreset) + updateStoredProgramNames(); + } +} + +//============================================================================== +void VSTPluginInstance::timerCallback() +{ + if (dispatch (effIdle, 0, 0, 0, 0) == 0) + stopTimer(); +} + +int VSTPluginInstance::dispatch (const int opcode, const int index, const int value, void* const ptr, float opt) const +{ + const ScopedLock sl (lock); + + ++insideVSTCallback; + int result = 0; + + try + { + if (effect != 0) + { +#if JUCE_MAC + if (module->resFileId != 0) + UseResFile (module->resFileId); + + CGrafPtr oldPort; + + if (getActiveEditor() != 0) + { + int x = 0, y = 0; + getActiveEditor()->relativePositionToOtherComponent (getActiveEditor()->getTopLevelComponent(), x, y); + + GetPort (&oldPort); + SetPortWindowPort ((WindowRef) getActiveEditor()->getWindowHandle()); + SetOrigin (-x, -y); + } +#endif + + result = effect->dispatcher (effect, opcode, index, value, ptr, opt); + +#if JUCE_MAC + if (getActiveEditor() != 0) + SetPort (oldPort); + + module->resFileId = CurResFile(); +#endif + + --insideVSTCallback; + return result; + } + } + catch (...) + { + //char s[512]; + //sprintf (s, "dispatcher (%d, %d, %d, %x, %f)", opcode, index, value, (int)ptr, opt); + } + + --insideVSTCallback; + return result; +} + +//============================================================================== +// handles non plugin-specific callbacks.. +static VstIntPtr handleGeneralCallback (VstInt32 opcode, VstInt32 index, VstInt32 value, void *ptr, float opt) +{ + (void) index; + (void) value; + (void) opt; + + switch (opcode) + { + case audioMasterCanDo: + { + static const char* canDos[] = { "supplyIdle", + "sendVstEvents", + "sendVstMidiEvent", + "sendVstTimeInfo", + "receiveVstEvents", + "receiveVstMidiEvent", + "supportShell", + "shellCategory" }; + + for (int i = 0; i < numElementsInArray (canDos); ++i) + if (strcmp (canDos[i], (const char*) ptr) == 0) + return 1; + + return 0; + } + + case audioMasterVersion: + return 0x2400; + case audioMasterCurrentId: + return shellUIDToCreate; + case audioMasterGetNumAutomatableParameters: + return 0; + case audioMasterGetAutomationState: + return 1; + + case audioMasterGetVendorVersion: + return 0x0101; + case audioMasterGetVendorString: + case audioMasterGetProductString: + JUCEApplication::getInstance() + ->getApplicationName().copyToBuffer ((char*) ptr, jmin (kVstMaxVendorStrLen, kVstMaxProductStrLen) - 1); + break; + + case audioMasterGetSampleRate: + return 44100; + + case audioMasterGetBlockSize: + return 512; + + case audioMasterSetOutputSampleRate: + return 0; + + default: + DBG ("*** Unhandled VST Callback: " + String ((int) opcode)); + break; + } + + return 0; +} + +// handles callbacks for a specific plugin +VstIntPtr VSTPluginInstance::handleCallback (VstInt32 opcode, VstInt32 index, VstInt32 value, void *ptr, float opt) +{ + switch (opcode) + { + case audioMasterAutomate: + sendParamChangeMessageToListeners (index, opt); + break; + + case audioMasterProcessEvents: + handleMidiFromPlugin ((const VstEvents*) ptr); + break; + + case audioMasterGetTime: + #ifdef _MSC_VER + #pragma warning (push) + #pragma warning (disable: 4311) + #endif + + return (VstIntPtr) &vstHostTime; + + #ifdef _MSC_VER + #pragma warning (pop) + #endif + break; + + case audioMasterIdle: + if (insideVSTCallback == 0 && MessageManager::getInstance()->isThisTheMessageThread()) + { + ++insideVSTCallback; +#if JUCE_MAC + if (getActiveEditor() != 0) + dispatch (effEditIdle, 0, 0, 0, 0); +#endif + const MessageManagerLock mml; + + juce_callAnyTimersSynchronously(); + + handleUpdateNowIfNeeded(); + + for (int i = ComponentPeer::getNumPeers(); --i >= 0;) + ComponentPeer::getPeer (i)->performAnyPendingRepaintsNow(); + + --insideVSTCallback; + } + break; + + case audioMasterUpdateDisplay: + triggerAsyncUpdate(); + break; + + case audioMasterTempoAt: + // returns (10000 * bpm) + break; + + case audioMasterNeedIdle: + startTimer (50); + break; + + case audioMasterSizeWindow: + if (getActiveEditor() != 0) + getActiveEditor()->setSize (index, value); + + return 1; + + case audioMasterGetSampleRate: + return (VstIntPtr) getSampleRate(); + + case audioMasterGetBlockSize: + return (VstIntPtr) getBlockSize(); + + case audioMasterWantMidi: + wantsMidiMessages = true; + break; + + case audioMasterGetDirectory: + #if JUCE_MAC + return (VstIntPtr) (void*) &module->parentDirFSSpec; + #else + return (VstIntPtr) (pointer_sized_uint) (const char*) module->fullParentDirectoryPathName; + #endif + + case audioMasterGetAutomationState: + // returns 0: not supported, 1: off, 2:read, 3:write, 4:read/write + break; + + // none of these are handled (yet).. + case audioMasterBeginEdit: + case audioMasterEndEdit: + case audioMasterSetTime: + case audioMasterPinConnected: + case audioMasterGetParameterQuantization: + case audioMasterIOChanged: + case audioMasterGetInputLatency: + case audioMasterGetOutputLatency: + case audioMasterGetPreviousPlug: + case audioMasterGetNextPlug: + case audioMasterWillReplaceOrAccumulate: + case audioMasterGetCurrentProcessLevel: + case audioMasterOfflineStart: + case audioMasterOfflineRead: + case audioMasterOfflineWrite: + case audioMasterOfflineGetCurrentPass: + case audioMasterOfflineGetCurrentMetaPass: + case audioMasterVendorSpecific: + case audioMasterSetIcon: + case audioMasterGetLanguage: + case audioMasterOpenWindow: + case audioMasterCloseWindow: + break; + + default: + return handleGeneralCallback (opcode, index, value, ptr, opt); + } + + return 0; +} + +// entry point for all callbacks from the plugin +static VstIntPtr VSTCALLBACK audioMaster (AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt) +{ + try + { + if (effect != 0 && effect->resvd2 != 0) + { + return ((VSTPluginInstance*)(effect->resvd2)) + ->handleCallback (opcode, index, value, ptr, opt); + } + + return handleGeneralCallback (opcode, index, value, ptr, opt); + } + catch (...) + { + return 0; + } +} + +//============================================================================== +const String VSTPluginInstance::getVersion() const throw() +{ + int v = dispatch (effGetVendorVersion, 0, 0, 0, 0); + + String s; + + if (v != 0) + { + int versionBits[4]; + int n = 0; + + while (v != 0) + { + versionBits [n++] = (v & 0xff); + v >>= 8; + } + + s << 'V'; + + while (n > 0) + { + s << versionBits [--n]; + + if (n > 0) + s << '.'; + } + } + + return s; +} + +int VSTPluginInstance::getUID() const throw() +{ + int uid = effect != 0 ? effect->uniqueID : 0; + + if (uid == 0) + uid = module->file.hashCode(); + + return uid; +} + +const String VSTPluginInstance::getCategory() const throw() +{ + const char* result = 0; + + switch (dispatch (effGetPlugCategory, 0, 0, 0, 0)) + { + case kPlugCategEffect: + result = "Effect"; + break; + + case kPlugCategSynth: + result = "Synth"; + break; + + case kPlugCategAnalysis: + result = "Anaylsis"; + break; + + case kPlugCategMastering: + result = "Mastering"; + break; + + case kPlugCategSpacializer: + result = "Spacial"; + break; + + case kPlugCategRoomFx: + result = "Reverb"; + break; + + case kPlugSurroundFx: + result = "Surround"; + break; + + case kPlugCategRestoration: + result = "Restoration"; + break; + + case kPlugCategGenerator: + result = "Tone generation"; + break; + + default: + break; + } + + return result; +} + +//============================================================================== +float VSTPluginInstance::getParameter (int index) +{ + if (effect != 0 && ((unsigned int) index) < (unsigned int) effect->numParams) + { + try + { + const ScopedLock sl (lock); + return effect->getParameter (effect, index); + } + catch (...) + { + } + } + + return 0.0f; +} + +void VSTPluginInstance::setParameter (int index, float newValue) +{ + if (effect != 0 && ((unsigned int) index) < (unsigned int) effect->numParams) + { + try + { + const ScopedLock sl (lock); + + if (effect->getParameter (effect, index) != newValue) + effect->setParameter (effect, index, newValue); + } + catch (...) + { + } + } +} + +const String VSTPluginInstance::getParameterName (int index) +{ + if (effect != 0) + { + jassert (index >= 0 && index < effect->numParams); + + char nm [256]; + zerostruct (nm); + dispatch (effGetParamName, index, 0, nm, 0); + return String (nm).trim(); + } + + return String::empty; +} + +const String VSTPluginInstance::getParameterLabel (int index) const +{ + if (effect != 0) + { + jassert (index >= 0 && index < effect->numParams); + + char nm [256]; + zerostruct (nm); + dispatch (effGetParamLabel, index, 0, nm, 0); + return String (nm).trim(); + } + + return String::empty; +} + +const String VSTPluginInstance::getParameterText (int index) +{ + if (effect != 0) + { + jassert (index >= 0 && index < effect->numParams); + + char nm [256]; + zerostruct (nm); + dispatch (effGetParamDisplay, index, 0, nm, 0); + return String (nm).trim(); + } + + return String::empty; +} + +bool VSTPluginInstance::isParameterAutomatable (int index) const +{ + if (effect != 0) + { + jassert (index >= 0 && index < effect->numParams); + return dispatch (effCanBeAutomated, index, 0, 0, 0) != 0; + } + + return false; +} + +void VSTPluginInstance::createTempParameterStore (MemoryBlock& dest) +{ + dest.setSize (64 + 4 * getNumParameters()); + dest.fillWith (0); + + getCurrentProgramName().copyToBuffer ((char*) dest.getData(), 63); + + float* const p = (float*) (((char*) dest.getData()) + 64); + for (int i = 0; i < getNumParameters(); ++i) + p[i] = getParameter(i); +} + +void VSTPluginInstance::restoreFromTempParameterStore (const MemoryBlock& m) +{ + changeProgramName (getCurrentProgram(), (const char*) m); + + float* p = (float*) (((char*) m.getData()) + 64); + for (int i = 0; i < getNumParameters(); ++i) + setParameter (i, p[i]); +} + +//============================================================================== +void VSTPluginInstance::setCurrentProgram (int newIndex) +{ + if (getNumPrograms() > 0 && newIndex != getCurrentProgram()) + dispatch (effSetProgram, 0, jlimit (0, getNumPrograms() - 1, newIndex), 0, 0); +} + +const String VSTPluginInstance::getProgramName (int index) +{ + if (index == getCurrentProgram()) + { + return getCurrentProgramName(); + } + else if (effect != 0) + { + char nm [256]; + zerostruct (nm); + + if (dispatch (effGetProgramNameIndexed, + jlimit (0, getNumPrograms(), index), + -1, nm, 0) != 0) + { + return String (nm).trim(); + } + } + + return programNames [index]; +} + +void VSTPluginInstance::changeProgramName (int index, const String& newName) +{ + if (index == getCurrentProgram()) + { + if (getNumPrograms() > 0 && newName != getCurrentProgramName()) + dispatch (effSetProgramName, 0, 0, (void*) (const char*) newName.substring (0, 24), 0.0f); + } + else + { + jassertfalse // xxx not implemented! + } +} + +void VSTPluginInstance::updateStoredProgramNames() +{ + if (effect != 0 && getNumPrograms() > 0) + { + char nm [256]; + zerostruct (nm); + + // only do this if the plugin can't use indexed names.. + if (dispatch (effGetProgramNameIndexed, 0, -1, nm, 0) == 0) + { + const int oldProgram = getCurrentProgram(); + MemoryBlock oldSettings; + createTempParameterStore (oldSettings); + + for (int i = 0; i < getNumPrograms(); ++i) + { + setCurrentProgram (i); + getCurrentProgramName(); // (this updates the list) + } + + setCurrentProgram (oldProgram); + restoreFromTempParameterStore (oldSettings); + } + } +} + +const String VSTPluginInstance::getCurrentProgramName() +{ + if (effect != 0) + { + char nm [256]; + zerostruct (nm); + dispatch (effGetProgramName, 0, 0, nm, 0); + + const int index = getCurrentProgram(); + if (programNames[index].isEmpty()) + { + while (programNames.size() < index) + programNames.add (String::empty); + + programNames.set (index, String (nm).trim()); + } + + return String (nm).trim(); + } + + return String::empty; +} + +//============================================================================== +const String VSTPluginInstance::getInputChannelName (const int index) const +{ + if (index >= 0 && index < getNumInputChannels()) + { + VstPinProperties pinProps; + if (dispatch (effGetInputProperties, index, 0, &pinProps, 0.0f) != 0) + return String (pinProps.label, sizeof (pinProps.label)); + } + + return String::empty; +} + +bool VSTPluginInstance::isInputChannelStereoPair (int index) const +{ + if (index < 0 || index >= getNumInputChannels()) + return false; + + VstPinProperties pinProps; + if (dispatch (effGetInputProperties, index, 0, &pinProps, 0.0f) != 0) + return (pinProps.flags & kVstPinIsStereo) != 0; + + return true; +} + +const String VSTPluginInstance::getOutputChannelName (const int index) const +{ + if (index >= 0 && index < getNumOutputChannels()) + { + VstPinProperties pinProps; + if (dispatch (effGetOutputProperties, index, 0, &pinProps, 0.0f) != 0) + return String (pinProps.label, sizeof (pinProps.label)); + } + + return String::empty; +} + +bool VSTPluginInstance::isOutputChannelStereoPair (int index) const +{ + if (index < 0 || index >= getNumOutputChannels()) + return false; + + VstPinProperties pinProps; + if (dispatch (effGetOutputProperties, index, 0, &pinProps, 0.0f) != 0) + return (pinProps.flags & kVstPinIsStereo) != 0; + + return true; +} + +//============================================================================== +void VSTPluginInstance::setPower (const bool on) +{ + dispatch (effMainsChanged, 0, on ? 1 : 0, 0, 0); + isPowerOn = on; +} + +//============================================================================== +const int defaultMaxSizeMB = 64; + +void VSTPluginInstance::getStateInformation (MemoryBlock& destData) +{ + saveToFXBFile (destData, true, defaultMaxSizeMB); +} + +void VSTPluginInstance::getCurrentProgramStateInformation (MemoryBlock& destData) +{ + saveToFXBFile (destData, false, defaultMaxSizeMB); +} + +void VSTPluginInstance::setStateInformation (const void* data, int sizeInBytes) +{ + loadFromFXBFile (data, sizeInBytes); +} + +void VSTPluginInstance::setCurrentProgramStateInformation (const void* data, int sizeInBytes) +{ + loadFromFXBFile (data, sizeInBytes); +} + +//============================================================================== +//============================================================================== +VSTPluginFormat::VSTPluginFormat() +{ +} + +VSTPluginFormat::~VSTPluginFormat() +{ +} + +void VSTPluginFormat::findAllTypesForFile (OwnedArray & results, + const File& file) +{ + if (! fileMightContainThisPluginType (file)) + return; + + PluginDescription desc; + desc.file = file; + desc.uid = 0; + + VSTPluginInstance* instance = dynamic_cast (createInstanceFromDescription (desc)); + + if (instance == 0) + return; + + try + { +#if JUCE_MAC + if (instance->module->resFileId != 0) + UseResFile (instance->module->resFileId); +#endif + + instance->fillInPluginDescription (desc); + + VstPlugCategory category = (VstPlugCategory) instance->dispatch (effGetPlugCategory, 0, 0, 0, 0); + + if (category != kPlugCategShell) + { + // Normal plugin... + results.add (new PluginDescription (desc)); + + ++insideVSTCallback; + instance->dispatch (effOpen, 0, 0, 0, 0); + --insideVSTCallback; + } + else + { + // It's a shell plugin, so iterate all the subtypes... + char shellEffectName [64]; + + for (;;) + { + zerostruct (shellEffectName); + const int uid = instance->dispatch (effShellGetNextPlugin, 0, 0, shellEffectName, 0); + + if (uid == 0) + { + break; + } + else + { + desc.uid = uid; + desc.name = shellEffectName; + + bool alreadyThere = false; + + for (int i = results.size(); --i >= 0;) + { + PluginDescription* const d = results.getUnchecked(i); + + if (d->isDuplicateOf (desc)) + { + alreadyThere = true; + break; + } + } + + if (! alreadyThere) + results.add (new PluginDescription (desc)); + } + } + } + } + catch (...) + { + // crashed while loading... + } + + deleteAndZero (instance); +} + +AudioPluginInstance* VSTPluginFormat::createInstanceFromDescription (const PluginDescription& desc) +{ + VSTPluginInstance* result = 0; + + if (fileMightContainThisPluginType (desc.file)) + { + const File previousWorkingDirectory (File::getCurrentWorkingDirectory()); + desc.file.getParentDirectory().setAsCurrentWorkingDirectory(); + + const ReferenceCountedObjectPtr module (ModuleHandle::findOrCreateModule (desc.file)); + + if (module != 0) + { + shellUIDToCreate = desc.uid; + + result = new VSTPluginInstance (module); + + if (result->effect != 0) + { + result->effect->resvd2 = (VstIntPtr) (pointer_sized_int) result; + result->initialise(); + } + else + { + deleteAndZero (result); + } + } + + previousWorkingDirectory.setAsCurrentWorkingDirectory(); + } + + return result; +} + +bool VSTPluginFormat::fileMightContainThisPluginType (const File& f) +{ +#if JUCE_MAC + if (f.isDirectory() && f.hasFileExtension (T(".vst"))) + return true; + +#if JUCE_PPC + FSRef fileRef; + if (PlatformUtilities::makeFSRefFromPath (&fileRef, f.getFullPathName())) + { + const short resFileId = FSOpenResFile (&fileRef, fsRdPerm); + + if (resFileId != -1) + { + const int numEffects = Count1Resources ('aEff'); + CloseResFile (resFileId); + + if (numEffects > 0) + return true; + } + } +#endif + + return false; +#elif JUCE_WIN32 + return f.existsAsFile() + && f.hasFileExtension (T(".dll")); +#elif JUCE_LINUX + return f.existsAsFile() + && f.hasFileExtension (T(".so")); +#endif +} + +const FileSearchPath VSTPluginFormat::getDefaultLocationsToSearch() +{ +#if JUCE_MAC + return FileSearchPath ("~/Library/Audio/Plug-Ins/VST;/Library/Audio/Plug-Ins/VST"); +#elif JUCE_WIN32 + const String programFiles (File::getSpecialLocation (File::globalApplicationsDirectory).getFullPathName()); + + return FileSearchPath (programFiles + "\\Steinberg\\VstPlugins"); +#elif JUCE_LINUX + return FileSearchPath ("/usr/lib/vst"); +#endif +} + +END_JUCE_NAMESPACE + +#endif + diff --git a/src/juce_appframework/audio/plugins/juce_AudioPluginFormat.cpp b/src/juce_appframework/audio/plugins/juce_AudioPluginFormat.cpp index 04c382ef4c..78b893cfa4 100644 --- a/src/juce_appframework/audio/plugins/juce_AudioPluginFormat.cpp +++ b/src/juce_appframework/audio/plugins/juce_AudioPluginFormat.cpp @@ -41,7 +41,7 @@ AudioPluginFormat::AudioPluginFormat() throw() { } -AudioPluginFormat::~AudioPluginFormat() throw() +AudioPluginFormat::~AudioPluginFormat() { }