| @@ -321,6 +321,7 @@ OBJECTS := \ | |||
| $(OBJDIR)/juce_FileFilter.o \ | |||
| $(OBJDIR)/juce_FileListComponent.o \ | |||
| $(OBJDIR)/juce_FilenameComponent.o \ | |||
| $(OBJDIR)/juce_FileSearchPathListComponent.o \ | |||
| $(OBJDIR)/juce_FileTreeComponent.o \ | |||
| $(OBJDIR)/juce_ImagePreviewComponent.o \ | |||
| $(OBJDIR)/juce_WildcardFileFilter.o \ | |||
| @@ -1859,6 +1860,11 @@ $(OBJDIR)/juce_FilenameComponent.o: ../../src/juce_appframework/gui/components/f | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o $@ -c $< | |||
| $(OBJDIR)/juce_FileSearchPathListComponent.o: ../../src/juce_appframework/gui/components/filebrowser/juce_FileSearchPathListComponent.cpp | |||
| -@$(CMD_MKOBJDIR) | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o $@ -c $< | |||
| $(OBJDIR)/juce_FileTreeComponent.o: ../../src/juce_appframework/gui/components/filebrowser/juce_FileTreeComponent.cpp | |||
| -@$(CMD_MKOBJDIR) | |||
| @echo $(notdir $<) | |||
| @@ -40,6 +40,7 @@ | |||
| #include <X11/Xmd.h> | |||
| #include <X11/keysym.h> | |||
| #include <X11/cursorfont.h> | |||
| #include <X11/extensions/scrnsaver.h> | |||
| #if JUCE_USE_XINERAMA | |||
| /* If you're trying to use Xinerama, you'll need to install the "libxinerama-dev" package.. | |||
| @@ -2564,14 +2565,20 @@ void Desktop::setMousePosition (int x, int y) throw() | |||
| //============================================================================== | |||
| static bool screenSaverAllowed = false; | |||
| void Desktop::setScreenSaverEnabled (const bool isEnabled) throw() | |||
| { | |||
| jassertfalse // anyone know how to do this?? | |||
| if (screenSaverAllowed != isEnabled) | |||
| { | |||
| screenSaverAllowed = isEnabled; | |||
| XScreenSaverSuspend (display, ! isEnabled); | |||
| } | |||
| } | |||
| bool Desktop::isScreenSaverEnabled() throw() | |||
| { | |||
| return true; | |||
| return screenSaverAllowed; | |||
| } | |||
| //============================================================================== | |||
| @@ -2897,6 +2904,14 @@ bool juce_makeOpenGLContextCurrent (void* context) | |||
| return glXMakeCurrent (display, None, 0); | |||
| } | |||
| bool juce_isActiveOpenGLContext (void* context) throw() | |||
| { | |||
| OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; | |||
| jassert (oc != 0); | |||
| return glXGetCurrentContext() == oc->renderContext; | |||
| } | |||
| void juce_swapOpenGLBuffers (void* context) | |||
| { | |||
| OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; | |||
| @@ -646,6 +646,8 @@ | |||
| 84FC31BB09B74A5C00B75141 /* juce_WildcardFileFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 84FC31A909B74A5C00B75141 /* juce_WildcardFileFilter.h */; }; | |||
| 84FC31BE09B74A7700B75141 /* juce_BorderSize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84FC31BC09B74A7700B75141 /* juce_BorderSize.cpp */; }; | |||
| 84FC31BF09B74A7700B75141 /* juce_BorderSize.h in Headers */ = {isa = PBXBuildFile; fileRef = 84FC31BD09B74A7700B75141 /* juce_BorderSize.h */; }; | |||
| 84FFAF2B0C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84FFAF290C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.cpp */; }; | |||
| 84FFAF2C0C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 84FFAF2A0C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.h */; }; | |||
| /* End PBXBuildFile section */ | |||
| /* Begin PBXFileReference section */ | |||
| @@ -1291,6 +1293,8 @@ | |||
| 84FC31A909B74A5C00B75141 /* juce_WildcardFileFilter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = juce_WildcardFileFilter.h; path = filebrowser/juce_WildcardFileFilter.h; sourceTree = "<group>"; }; | |||
| 84FC31BC09B74A7700B75141 /* juce_BorderSize.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = juce_BorderSize.cpp; sourceTree = "<group>"; }; | |||
| 84FC31BD09B74A7700B75141 /* juce_BorderSize.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_BorderSize.h; sourceTree = "<group>"; }; | |||
| 84FFAF290C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = juce_FileSearchPathListComponent.cpp; path = filebrowser/juce_FileSearchPathListComponent.cpp; sourceTree = "<group>"; }; | |||
| 84FFAF2A0C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = juce_FileSearchPathListComponent.h; path = filebrowser/juce_FileSearchPathListComponent.h; sourceTree = "<group>"; }; | |||
| D2AAC046055464E500DB518D /* libjucedebug.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjucedebug.a; sourceTree = BUILT_PRODUCTS_DIR; }; | |||
| /* End PBXFileReference section */ | |||
| @@ -2416,6 +2420,8 @@ | |||
| 84FC31A209B74A5C00B75141 /* juce_FileFilter.h */, | |||
| 84FC31A309B74A5C00B75141 /* juce_FileListComponent.cpp */, | |||
| 84FC31A409B74A5C00B75141 /* juce_FileListComponent.h */, | |||
| 84FFAF290C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.cpp */, | |||
| 84FFAF2A0C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.h */, | |||
| 847F72D90C2702A000CBECEC /* juce_FileTreeComponent.cpp */, | |||
| 847F72DA0C2702A000CBECEC /* juce_FileTreeComponent.h */, | |||
| 84F1F05B0A36CE96008CCC5E /* juce_FilenameComponent.cpp */, | |||
| @@ -2722,6 +2728,7 @@ | |||
| 84F6B7550C06E29D00BB8791 /* juce_ChannelRemappingAudioSource.h in Headers */, | |||
| 847F72DC0C2702A000CBECEC /* juce_DirectoryContentsDisplayComponent.h in Headers */, | |||
| 847F72DE0C2702A000CBECEC /* juce_FileTreeComponent.h in Headers */, | |||
| 84FFAF2C0C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.h in Headers */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| @@ -3118,6 +3125,7 @@ | |||
| 847F72DB0C2702A000CBECEC /* juce_DirectoryContentsDisplayComponent.cpp in Sources */, | |||
| 847F72DD0C2702A000CBECEC /* juce_FileTreeComponent.cpp in Sources */, | |||
| 8406AA5A0C4BDF90003A0D6A /* juce_MidiOutput.cpp in Sources */, | |||
| 84FFAF2B0C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.cpp in Sources */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| @@ -1937,6 +1937,15 @@ bool juce_isHIViewCreatedByJuce (HIViewRef view) | |||
| && HIObjectIsOfClass ((HIObjectRef) view, juceHiViewClassNameCFString); | |||
| } | |||
| bool juce_isWindowCreatedByJuce (WindowRef window) | |||
| { | |||
| for (int i = ComponentPeer::getNumPeers(); --i >= 0;) | |||
| if (ComponentPeer::getPeer(i)->getNativeHandle() == window) | |||
| return true; | |||
| return false; | |||
| } | |||
| static void trackNextMouseEvent() | |||
| { | |||
| UInt32 mods; | |||
| @@ -3350,6 +3359,14 @@ bool juce_makeOpenGLContextCurrent (void* context) | |||
| return aglSetCurrentContext ((oc != 0) ? oc->renderContext : 0); | |||
| } | |||
| bool juce_isActiveOpenGLContext (void* context) throw() | |||
| { | |||
| OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; | |||
| jassert (oc != 0); | |||
| return aglGetCurrentContext() == oc->renderContext; | |||
| } | |||
| void juce_swapOpenGLBuffers (void* context) | |||
| { | |||
| OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; | |||
| @@ -3141,6 +3141,14 @@ bool juce_makeOpenGLContextCurrent (void* context) | |||
| return wglMakeCurrent (0, 0) != 0; | |||
| } | |||
| bool juce_isActiveOpenGLContext (void* context) throw() | |||
| { | |||
| OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; | |||
| jassert (oc != 0); | |||
| return wglGetCurrentContext() == oc->renderContext; | |||
| } | |||
| void juce_swapOpenGLBuffers (void* context) | |||
| { | |||
| OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; | |||
| @@ -4145,6 +4145,14 @@ | |||
| RelativePath="..\..\..\src\juce_appframework\gui\components\filebrowser\juce_FilePreviewComponent.h" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\src\juce_appframework\gui\components\filebrowser\juce_FileSearchPathListComponent.cpp" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\src\juce_appframework\gui\components\filebrowser\juce_FileSearchPathListComponent.h" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\src\juce_appframework\gui\components\filebrowser\juce_FileTreeComponent.cpp" | |||
| > | |||
| @@ -6,7 +6,10 @@ | |||
| ============================================================================== | |||
| Changelist for version 1.45 | |||
| - | |||
| - big new project in the "extras" folder - a basic audio plugin host! Currently it loads VSTs on PC/Mac, and lets you put them together in a filter graph, which it plays. Hosting functionality is very basic at the moment, but I'm laying down a good architecture to hopefully build out into cross-platform plugin loading. | |||
| - audio plugins: AudioFilterBase now requires a few extra methods to be implemented by your plugin: getInputChannelName, getOutputChannelName, isInputChannelStereoPair, isOutputChannelStereoPair. | |||
| - new class: FileSearchPathListComponent, for letting the user edit a FileSearchPath. | |||
| ============================================================================== | |||
| Changelist for version 1.44 | |||
| @@ -0,0 +1,26 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||
| <plist version="1.0"> | |||
| <dict> | |||
| <key>CFBundleDevelopmentRegion</key> | |||
| <string>English</string> | |||
| <key>CFBundleExecutable</key> | |||
| <string>$(EXECUTABLE_NAME)</string> | |||
| <key>CFBundleIconFile</key> | |||
| <string></string> | |||
| <key>CFBundleIdentifier</key> | |||
| <string>com.yourcompany.PluginHost</string> | |||
| <key>CFBundleInfoDictionaryVersion</key> | |||
| <string>6.0</string> | |||
| <key>CFBundleName</key> | |||
| <string>$(PRODUCT_NAME)</string> | |||
| <key>CFBundlePackageType</key> | |||
| <string>APPL</string> | |||
| <key>CFBundleSignature</key> | |||
| <string>????</string> | |||
| <key>CFBundleVersion</key> | |||
| <string>1.0</string> | |||
| <key>CSResourcesFileMapped</key> | |||
| <true/> | |||
| </dict> | |||
| </plist> | |||
| @@ -0,0 +1,371 @@ | |||
| // !$*UTF8*$! | |||
| { | |||
| archiveVersion = 1; | |||
| classes = { | |||
| }; | |||
| objectVersion = 42; | |||
| objects = { | |||
| /* Begin PBXBuildFile section */ | |||
| 84FFAEAC0C6C8A6F009F6E72 /* FilterGraph.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84FFAE920C6C8A6F009F6E72 /* FilterGraph.cpp */; }; | |||
| 84FFAEAD0C6C8A6F009F6E72 /* GraphEditorPanel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84FFAE940C6C8A6F009F6E72 /* GraphEditorPanel.cpp */; }; | |||
| 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 */; }; | |||
| 84FFAEB70C6C8A6F009F6E72 /* juce_VSTPluginInstance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84FFAEAA0C6C8A6F009F6E72 /* juce_VSTPluginInstance.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 */; }; | |||
| 84FFAF060C6C8ED5009F6E72 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84FFAF010C6C8ED5009F6E72 /* IOKit.framework */; }; | |||
| 84FFAF080C6C8ED5009F6E72 /* QuickTime.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84FFAF030C6C8ED5009F6E72 /* QuickTime.framework */; }; | |||
| 84FFAF150C6C8EE8009F6E72 /* AGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84FFAF140C6C8EE8009F6E72 /* AGL.framework */; }; | |||
| 8D0C4E920486CD37000505A6 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 20286C33FDCF999611CA2CEA /* Carbon.framework */; }; | |||
| /* End PBXBuildFile section */ | |||
| /* Begin PBXContainerItemProxy section */ | |||
| 84FFAEFB0C6C8E76009F6E72 /* PBXContainerItemProxy */ = { | |||
| isa = PBXContainerItemProxy; | |||
| containerPortal = 84FFAEF70C6C8E76009F6E72 /* Juce.xcodeproj */; | |||
| proxyType = 2; | |||
| remoteGlobalIDString = D2AAC046055464E500DB518D; | |||
| remoteInfo = Juce; | |||
| }; | |||
| /* End PBXContainerItemProxy section */ | |||
| /* Begin PBXFileReference section */ | |||
| 20286C33FDCF999611CA2CEA /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; }; | |||
| 4A9504C8FFE6A3BC11CA0CBA /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = /System/Library/Frameworks/ApplicationServices.framework; sourceTree = "<absolute>"; }; | |||
| 4A9504CAFFE6A41611CA0CBA /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = /System/Library/Frameworks/CoreServices.framework; sourceTree = "<absolute>"; }; | |||
| 508344B209E5C41E0093A071 /* Juce Plugin Host.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Juce Plugin Host.app"; sourceTree = BUILT_PRODUCTS_DIR; }; | |||
| 84FFAE920C6C8A6F009F6E72 /* FilterGraph.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = FilterGraph.cpp; path = ../../src/host/FilterGraph.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 84FFAE930C6C8A6F009F6E72 /* FilterGraph.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = FilterGraph.h; path = ../../src/host/FilterGraph.h; sourceTree = SOURCE_ROOT; }; | |||
| 84FFAE940C6C8A6F009F6E72 /* GraphEditorPanel.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = GraphEditorPanel.cpp; path = ../../src/host/GraphEditorPanel.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 84FFAE950C6C8A6F009F6E72 /* GraphEditorPanel.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = GraphEditorPanel.h; path = ../../src/host/GraphEditorPanel.h; sourceTree = SOURCE_ROOT; }; | |||
| 84FFAE960C6C8A6F009F6E72 /* InternalFilters.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = InternalFilters.cpp; path = ../../src/host/InternalFilters.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 84FFAE970C6C8A6F009F6E72 /* InternalFilters.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = InternalFilters.h; path = ../../src/host/InternalFilters.h; sourceTree = SOURCE_ROOT; }; | |||
| 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; }; | |||
| 84FFAEA90C6C8A6F009F6E72 /* juce_VSTPluginFormat.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = juce_VSTPluginFormat.h; path = ../../src/plugins/vst/juce_VSTPluginFormat.h; sourceTree = SOURCE_ROOT; }; | |||
| 84FFAEAA0C6C8A6F009F6E72 /* juce_VSTPluginInstance.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = juce_VSTPluginInstance.cpp; path = ../../src/plugins/vst/juce_VSTPluginInstance.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 84FFAEAB0C6C8A6F009F6E72 /* juce_VSTPluginInstance.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = juce_VSTPluginInstance.h; path = ../../src/plugins/vst/juce_VSTPluginInstance.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 = "<absolute>"; }; | |||
| 84FFAF000C6C8ED5009F6E72 /* CoreMIDI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMIDI.framework; path = /System/Library/Frameworks/CoreMIDI.framework; sourceTree = "<absolute>"; }; | |||
| 84FFAF010C6C8ED5009F6E72 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; }; | |||
| 84FFAF030C6C8ED5009F6E72 /* QuickTime.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuickTime.framework; path = /System/Library/Frameworks/QuickTime.framework; sourceTree = "<absolute>"; }; | |||
| 84FFAF140C6C8EE8009F6E72 /* AGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AGL.framework; path = /System/Library/Frameworks/AGL.framework; sourceTree = "<absolute>"; }; | |||
| 8D0C4E960486CD37000505A6 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = Info.plist; sourceTree = "<group>"; }; | |||
| /* End PBXFileReference section */ | |||
| /* Begin PBXFrameworksBuildPhase section */ | |||
| 8D0C4E910486CD37000505A6 /* Frameworks */ = { | |||
| isa = PBXFrameworksBuildPhase; | |||
| buildActionMask = 2147483647; | |||
| files = ( | |||
| 84FFAEFE0C6C8E80009F6E72 /* libjucedebug.a in Frameworks */, | |||
| 8D0C4E920486CD37000505A6 /* Carbon.framework in Frameworks */, | |||
| 84FFAF040C6C8ED5009F6E72 /* CoreAudio.framework in Frameworks */, | |||
| 84FFAF050C6C8ED5009F6E72 /* CoreMIDI.framework in Frameworks */, | |||
| 84FFAF060C6C8ED5009F6E72 /* IOKit.framework in Frameworks */, | |||
| 84FFAF080C6C8ED5009F6E72 /* QuickTime.framework in Frameworks */, | |||
| 84FFAF150C6C8EE8009F6E72 /* AGL.framework in Frameworks */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| /* End PBXFrameworksBuildPhase section */ | |||
| /* Begin PBXGroup section */ | |||
| 195DF8CFFE9D517E11CA2CBB /* Products */ = { | |||
| isa = PBXGroup; | |||
| children = ( | |||
| 508344B209E5C41E0093A071 /* Juce Plugin Host.app */, | |||
| ); | |||
| name = Products; | |||
| sourceTree = "<group>"; | |||
| }; | |||
| 20286C29FDCF999611CA2CEA /* PluginHost */ = { | |||
| isa = PBXGroup; | |||
| children = ( | |||
| 20286C2AFDCF999611CA2CEA /* Sources */, | |||
| 20286C2CFDCF999611CA2CEA /* Resources */, | |||
| 20286C32FDCF999611CA2CEA /* External Frameworks and Libraries */, | |||
| 195DF8CFFE9D517E11CA2CBB /* Products */, | |||
| ); | |||
| name = PluginHost; | |||
| sourceTree = "<group>"; | |||
| }; | |||
| 20286C2AFDCF999611CA2CEA /* Sources */ = { | |||
| isa = PBXGroup; | |||
| children = ( | |||
| 84FFAE900C6C8A6F009F6E72 /* src */, | |||
| ); | |||
| name = Sources; | |||
| sourceTree = "<group>"; | |||
| }; | |||
| 20286C2CFDCF999611CA2CEA /* Resources */ = { | |||
| isa = PBXGroup; | |||
| children = ( | |||
| 8D0C4E960486CD37000505A6 /* Info.plist */, | |||
| ); | |||
| name = Resources; | |||
| sourceTree = "<group>"; | |||
| }; | |||
| 20286C32FDCF999611CA2CEA /* External Frameworks and Libraries */ = { | |||
| isa = PBXGroup; | |||
| children = ( | |||
| 84FFAF140C6C8EE8009F6E72 /* AGL.framework */, | |||
| 84FFAEFF0C6C8ED5009F6E72 /* CoreAudio.framework */, | |||
| 84FFAF000C6C8ED5009F6E72 /* CoreMIDI.framework */, | |||
| 84FFAF010C6C8ED5009F6E72 /* IOKit.framework */, | |||
| 84FFAF030C6C8ED5009F6E72 /* QuickTime.framework */, | |||
| 84FFAEF70C6C8E76009F6E72 /* Juce.xcodeproj */, | |||
| 20286C33FDCF999611CA2CEA /* Carbon.framework */, | |||
| 4A9504CAFFE6A41611CA0CBA /* CoreServices.framework */, | |||
| 4A9504C8FFE6A3BC11CA0CBA /* ApplicationServices.framework */, | |||
| ); | |||
| name = "External Frameworks and Libraries"; | |||
| sourceTree = "<group>"; | |||
| }; | |||
| 84FFAE900C6C8A6F009F6E72 /* src */ = { | |||
| isa = PBXGroup; | |||
| children = ( | |||
| 84FFAE910C6C8A6F009F6E72 /* host */, | |||
| 84FFAE9A0C6C8A6F009F6E72 /* HostStartup.cpp */, | |||
| 84FFAE9B0C6C8A6F009F6E72 /* plugins */, | |||
| ); | |||
| name = src; | |||
| path = ../../src; | |||
| sourceTree = SOURCE_ROOT; | |||
| }; | |||
| 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 = ( | |||
| 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 */, | |||
| 84FFAEA80C6C8A6F009F6E72 /* vst */, | |||
| ); | |||
| name = plugins; | |||
| path = ../../src/plugins; | |||
| sourceTree = SOURCE_ROOT; | |||
| }; | |||
| 84FFAEA80C6C8A6F009F6E72 /* vst */ = { | |||
| isa = PBXGroup; | |||
| children = ( | |||
| 84FFAEA90C6C8A6F009F6E72 /* juce_VSTPluginFormat.h */, | |||
| 84FFAEAA0C6C8A6F009F6E72 /* juce_VSTPluginInstance.cpp */, | |||
| 84FFAEAB0C6C8A6F009F6E72 /* juce_VSTPluginInstance.h */, | |||
| ); | |||
| name = vst; | |||
| path = ../../src/plugins/vst; | |||
| sourceTree = SOURCE_ROOT; | |||
| }; | |||
| 84FFAEF80C6C8E76009F6E72 /* Products */ = { | |||
| isa = PBXGroup; | |||
| children = ( | |||
| 84FFAEFC0C6C8E76009F6E72 /* libjucedebug.a */, | |||
| ); | |||
| name = Products; | |||
| sourceTree = "<group>"; | |||
| }; | |||
| /* End PBXGroup section */ | |||
| /* Begin PBXNativeTarget section */ | |||
| 8D0C4E890486CD37000505A6 /* PluginHost */ = { | |||
| isa = PBXNativeTarget; | |||
| buildConfigurationList = C0E91AC508A95435008D54AB /* Build configuration list for PBXNativeTarget "PluginHost" */; | |||
| buildPhases = ( | |||
| 8D0C4E8C0486CD37000505A6 /* Resources */, | |||
| 8D0C4E8F0486CD37000505A6 /* Sources */, | |||
| 8D0C4E910486CD37000505A6 /* Frameworks */, | |||
| ); | |||
| buildRules = ( | |||
| ); | |||
| dependencies = ( | |||
| ); | |||
| name = PluginHost; | |||
| productInstallPath = "$(HOME)/Applications"; | |||
| productName = PluginHost; | |||
| productReference = 508344B209E5C41E0093A071 /* Juce Plugin Host.app */; | |||
| productType = "com.apple.product-type.application"; | |||
| }; | |||
| /* End PBXNativeTarget section */ | |||
| /* Begin PBXProject section */ | |||
| 20286C28FDCF999611CA2CEA /* Project object */ = { | |||
| isa = PBXProject; | |||
| buildConfigurationList = C0E91AC908A95435008D54AB /* Build configuration list for PBXProject "PluginHost" */; | |||
| hasScannedForEncodings = 1; | |||
| mainGroup = 20286C29FDCF999611CA2CEA /* PluginHost */; | |||
| projectDirPath = ""; | |||
| projectReferences = ( | |||
| { | |||
| ProductGroup = 84FFAEF80C6C8E76009F6E72 /* Products */; | |||
| ProjectRef = 84FFAEF70C6C8E76009F6E72 /* Juce.xcodeproj */; | |||
| }, | |||
| ); | |||
| targets = ( | |||
| 8D0C4E890486CD37000505A6 /* PluginHost */, | |||
| ); | |||
| }; | |||
| /* End PBXProject section */ | |||
| /* Begin PBXReferenceProxy section */ | |||
| 84FFAEFC0C6C8E76009F6E72 /* libjucedebug.a */ = { | |||
| isa = PBXReferenceProxy; | |||
| fileType = archive.ar; | |||
| path = libjucedebug.a; | |||
| remoteRef = 84FFAEFB0C6C8E76009F6E72 /* PBXContainerItemProxy */; | |||
| sourceTree = BUILT_PRODUCTS_DIR; | |||
| }; | |||
| /* End PBXReferenceProxy section */ | |||
| /* Begin PBXResourcesBuildPhase section */ | |||
| 8D0C4E8C0486CD37000505A6 /* Resources */ = { | |||
| isa = PBXResourcesBuildPhase; | |||
| buildActionMask = 2147483647; | |||
| files = ( | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| /* End PBXResourcesBuildPhase section */ | |||
| /* Begin PBXSourcesBuildPhase section */ | |||
| 8D0C4E8F0486CD37000505A6 /* Sources */ = { | |||
| isa = PBXSourcesBuildPhase; | |||
| buildActionMask = 2147483647; | |||
| files = ( | |||
| 84FFAEAC0C6C8A6F009F6E72 /* FilterGraph.cpp in Sources */, | |||
| 84FFAEAD0C6C8A6F009F6E72 /* GraphEditorPanel.cpp in Sources */, | |||
| 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 */, | |||
| 84FFAEB70C6C8A6F009F6E72 /* juce_VSTPluginInstance.cpp in Sources */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| /* End PBXSourcesBuildPhase section */ | |||
| /* Begin XCBuildConfiguration section */ | |||
| C0E91AC608A95435008D54AB /* Debug */ = { | |||
| isa = XCBuildConfiguration; | |||
| buildSettings = { | |||
| ARCHS = ppc; | |||
| COPY_PHASE_STRIP = NO; | |||
| }; | |||
| name = Debug; | |||
| }; | |||
| C0E91AC708A95435008D54AB /* Release */ = { | |||
| isa = XCBuildConfiguration; | |||
| buildSettings = { | |||
| ARCHS = ppc; | |||
| DEAD_CODE_STRIPPING = YES; | |||
| INSTALL_PATH = "$(HOME)/Applications"; | |||
| PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES; | |||
| }; | |||
| name = Release; | |||
| }; | |||
| C0E91ACA08A95435008D54AB /* Debug */ = { | |||
| isa = XCBuildConfiguration; | |||
| buildSettings = { | |||
| ARCHS = ( | |||
| ppc, | |||
| i386, | |||
| ); | |||
| GCC_ENABLE_FIX_AND_CONTINUE = YES; | |||
| GCC_OPTIMIZATION_LEVEL = 0; | |||
| PRODUCT_NAME = "Juce Plugin Host"; | |||
| USER_HEADER_SEARCH_PATHS = "~/stuff/vstsdk2.4 $(inherited)"; | |||
| ZERO_LINK = NO; | |||
| }; | |||
| name = Debug; | |||
| }; | |||
| C0E91ACB08A95435008D54AB /* Release */ = { | |||
| isa = XCBuildConfiguration; | |||
| buildSettings = { | |||
| ARCHS = ( | |||
| ppc, | |||
| i386, | |||
| ); | |||
| PRODUCT_NAME = "Juce Plugin Host"; | |||
| SEPARATE_STRIP = YES; | |||
| USER_HEADER_SEARCH_PATHS = "~/stuff/vstsdk2.4 $(inherited)"; | |||
| ZERO_LINK = NO; | |||
| }; | |||
| name = Release; | |||
| }; | |||
| /* End XCBuildConfiguration section */ | |||
| /* Begin XCConfigurationList section */ | |||
| C0E91AC508A95435008D54AB /* Build configuration list for PBXNativeTarget "PluginHost" */ = { | |||
| isa = XCConfigurationList; | |||
| buildConfigurations = ( | |||
| C0E91AC608A95435008D54AB /* Debug */, | |||
| C0E91AC708A95435008D54AB /* Release */, | |||
| ); | |||
| defaultConfigurationIsVisible = 0; | |||
| defaultConfigurationName = Release; | |||
| }; | |||
| C0E91AC908A95435008D54AB /* Build configuration list for PBXProject "PluginHost" */ = { | |||
| isa = XCConfigurationList; | |||
| buildConfigurations = ( | |||
| C0E91ACA08A95435008D54AB /* Debug */, | |||
| C0E91ACB08A95435008D54AB /* Release */, | |||
| ); | |||
| defaultConfigurationIsVisible = 0; | |||
| defaultConfigurationName = Release; | |||
| }; | |||
| /* End XCConfigurationList section */ | |||
| }; | |||
| rootObject = 20286C28FDCF999611CA2CEA /* Project object */; | |||
| } | |||
| @@ -0,0 +1,39 @@ | |||
|  | |||
| Microsoft Visual Studio Solution File, Format Version 9.00 | |||
| # Visual Studio 2005 | |||
| Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PluginHost", "PluginHost.vcproj", "{A20203D2-E1C3-48E3-89DD-401D5731DCC0}" | |||
| ProjectSection(ProjectDependencies) = postProject | |||
| {AE232C11-D91C-4CA1-B24E-8B11A52EFF26} = {AE232C11-D91C-4CA1-B24E-8B11A52EFF26} | |||
| EndProjectSection | |||
| EndProject | |||
| Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JUCE", "..\..\..\..\build\win32\vc8\JUCE.vcproj", "{AE232C11-D91C-4CA1-B24E-8B11A52EFF26}" | |||
| EndProject | |||
| Global | |||
| GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||
| Debug|Win32 = Debug|Win32 | |||
| DLL Debug|Win32 = DLL Debug|Win32 | |||
| DLL Release|Win32 = DLL Release|Win32 | |||
| Release|Win32 = Release|Win32 | |||
| EndGlobalSection | |||
| GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||
| {A20203D2-E1C3-48E3-89DD-401D5731DCC0}.Debug|Win32.ActiveCfg = Debug|Win32 | |||
| {A20203D2-E1C3-48E3-89DD-401D5731DCC0}.Debug|Win32.Build.0 = Debug|Win32 | |||
| {A20203D2-E1C3-48E3-89DD-401D5731DCC0}.DLL Debug|Win32.ActiveCfg = Debug|Win32 | |||
| {A20203D2-E1C3-48E3-89DD-401D5731DCC0}.DLL Debug|Win32.Build.0 = Debug|Win32 | |||
| {A20203D2-E1C3-48E3-89DD-401D5731DCC0}.DLL Release|Win32.ActiveCfg = Release|Win32 | |||
| {A20203D2-E1C3-48E3-89DD-401D5731DCC0}.DLL Release|Win32.Build.0 = Release|Win32 | |||
| {A20203D2-E1C3-48E3-89DD-401D5731DCC0}.Release|Win32.ActiveCfg = Release|Win32 | |||
| {A20203D2-E1C3-48E3-89DD-401D5731DCC0}.Release|Win32.Build.0 = Release|Win32 | |||
| {AE232C11-D91C-4CA1-B24E-8B11A52EFF26}.Debug|Win32.ActiveCfg = Debug|Win32 | |||
| {AE232C11-D91C-4CA1-B24E-8B11A52EFF26}.Debug|Win32.Build.0 = Debug|Win32 | |||
| {AE232C11-D91C-4CA1-B24E-8B11A52EFF26}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32 | |||
| {AE232C11-D91C-4CA1-B24E-8B11A52EFF26}.DLL Debug|Win32.Build.0 = DLL Debug|Win32 | |||
| {AE232C11-D91C-4CA1-B24E-8B11A52EFF26}.DLL Release|Win32.ActiveCfg = DLL Release|Win32 | |||
| {AE232C11-D91C-4CA1-B24E-8B11A52EFF26}.DLL Release|Win32.Build.0 = DLL Release|Win32 | |||
| {AE232C11-D91C-4CA1-B24E-8B11A52EFF26}.Release|Win32.ActiveCfg = Release|Win32 | |||
| {AE232C11-D91C-4CA1-B24E-8B11A52EFF26}.Release|Win32.Build.0 = Release|Win32 | |||
| EndGlobalSection | |||
| GlobalSection(SolutionProperties) = preSolution | |||
| HideSolutionNode = FALSE | |||
| EndGlobalSection | |||
| EndGlobal | |||
| @@ -0,0 +1,295 @@ | |||
| <?xml version="1.0" encoding="Windows-1252"?> | |||
| <VisualStudioProject | |||
| ProjectType="Visual C++" | |||
| Version="8.00" | |||
| Name="PluginHost" | |||
| ProjectGUID="{A20203D2-E1C3-48E3-89DD-401D5731DCC0}" | |||
| RootNamespace="PluginHost" | |||
| Keyword="Win32Proj" | |||
| > | |||
| <Platforms> | |||
| <Platform | |||
| Name="Win32" | |||
| /> | |||
| </Platforms> | |||
| <ToolFiles> | |||
| </ToolFiles> | |||
| <Configurations> | |||
| <Configuration | |||
| Name="Debug|Win32" | |||
| OutputDirectory="$(SolutionDir)$(ConfigurationName)" | |||
| IntermediateDirectory="$(ConfigurationName)" | |||
| ConfigurationType="1" | |||
| CharacterSet="1" | |||
| > | |||
| <Tool | |||
| Name="VCPreBuildEventTool" | |||
| /> | |||
| <Tool | |||
| Name="VCCustomBuildTool" | |||
| /> | |||
| <Tool | |||
| Name="VCXMLDataGeneratorTool" | |||
| /> | |||
| <Tool | |||
| Name="VCWebServiceProxyGeneratorTool" | |||
| /> | |||
| <Tool | |||
| Name="VCMIDLTool" | |||
| /> | |||
| <Tool | |||
| Name="VCCLCompilerTool" | |||
| Optimization="0" | |||
| PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS" | |||
| MinimalRebuild="true" | |||
| BasicRuntimeChecks="3" | |||
| RuntimeLibrary="1" | |||
| UsePrecompiledHeader="0" | |||
| WarningLevel="4" | |||
| Detect64BitPortabilityProblems="true" | |||
| DebugInformationFormat="4" | |||
| /> | |||
| <Tool | |||
| Name="VCManagedResourceCompilerTool" | |||
| /> | |||
| <Tool | |||
| Name="VCResourceCompilerTool" | |||
| /> | |||
| <Tool | |||
| Name="VCPreLinkEventTool" | |||
| /> | |||
| <Tool | |||
| Name="VCLinkerTool" | |||
| LinkIncremental="2" | |||
| GenerateDebugInformation="true" | |||
| SubSystem="2" | |||
| TargetMachine="1" | |||
| /> | |||
| <Tool | |||
| Name="VCALinkTool" | |||
| /> | |||
| <Tool | |||
| Name="VCManifestTool" | |||
| /> | |||
| <Tool | |||
| Name="VCXDCMakeTool" | |||
| /> | |||
| <Tool | |||
| Name="VCBscMakeTool" | |||
| /> | |||
| <Tool | |||
| Name="VCFxCopTool" | |||
| /> | |||
| <Tool | |||
| Name="VCAppVerifierTool" | |||
| /> | |||
| <Tool | |||
| Name="VCWebDeploymentTool" | |||
| /> | |||
| <Tool | |||
| Name="VCPostBuildEventTool" | |||
| /> | |||
| </Configuration> | |||
| <Configuration | |||
| Name="Release|Win32" | |||
| OutputDirectory="$(SolutionDir)$(ConfigurationName)" | |||
| IntermediateDirectory="$(ConfigurationName)" | |||
| ConfigurationType="1" | |||
| CharacterSet="1" | |||
| WholeProgramOptimization="1" | |||
| > | |||
| <Tool | |||
| Name="VCPreBuildEventTool" | |||
| /> | |||
| <Tool | |||
| Name="VCCustomBuildTool" | |||
| /> | |||
| <Tool | |||
| Name="VCXMLDataGeneratorTool" | |||
| /> | |||
| <Tool | |||
| Name="VCWebServiceProxyGeneratorTool" | |||
| /> | |||
| <Tool | |||
| Name="VCMIDLTool" | |||
| /> | |||
| <Tool | |||
| Name="VCCLCompilerTool" | |||
| PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS" | |||
| RuntimeLibrary="0" | |||
| UsePrecompiledHeader="0" | |||
| WarningLevel="4" | |||
| Detect64BitPortabilityProblems="true" | |||
| DebugInformationFormat="3" | |||
| /> | |||
| <Tool | |||
| Name="VCManagedResourceCompilerTool" | |||
| /> | |||
| <Tool | |||
| Name="VCResourceCompilerTool" | |||
| /> | |||
| <Tool | |||
| Name="VCPreLinkEventTool" | |||
| /> | |||
| <Tool | |||
| Name="VCLinkerTool" | |||
| LinkIncremental="1" | |||
| GenerateDebugInformation="true" | |||
| SubSystem="2" | |||
| OptimizeReferences="2" | |||
| EnableCOMDATFolding="2" | |||
| TargetMachine="1" | |||
| /> | |||
| <Tool | |||
| Name="VCALinkTool" | |||
| /> | |||
| <Tool | |||
| Name="VCManifestTool" | |||
| /> | |||
| <Tool | |||
| Name="VCXDCMakeTool" | |||
| /> | |||
| <Tool | |||
| Name="VCBscMakeTool" | |||
| /> | |||
| <Tool | |||
| Name="VCFxCopTool" | |||
| /> | |||
| <Tool | |||
| Name="VCAppVerifierTool" | |||
| /> | |||
| <Tool | |||
| Name="VCWebDeploymentTool" | |||
| /> | |||
| <Tool | |||
| Name="VCPostBuildEventTool" | |||
| /> | |||
| </Configuration> | |||
| </Configurations> | |||
| <References> | |||
| </References> | |||
| <Files> | |||
| <Filter | |||
| Name="Source Files" | |||
| Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" | |||
| UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" | |||
| > | |||
| <File | |||
| RelativePath="..\..\src\HostStartup.cpp" | |||
| > | |||
| </File> | |||
| <Filter | |||
| Name="host" | |||
| > | |||
| <File | |||
| RelativePath="..\..\src\host\FilterGraph.cpp" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\src\host\FilterGraph.h" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\src\host\GraphEditorPanel.cpp" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\src\host\GraphEditorPanel.h" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\src\host\InternalFilters.cpp" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\src\host\InternalFilters.h" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\src\host\MainHostWindow.cpp" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\src\host\MainHostWindow.h" | |||
| > | |||
| </File> | |||
| </Filter> | |||
| <Filter | |||
| Name="plugins" | |||
| > | |||
| <File | |||
| RelativePath="..\..\src\plugins\juce_AudioPluginFormat.cpp" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\src\plugins\juce_AudioPluginFormat.h" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\src\plugins\juce_AudioPluginInstance.cpp" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\src\plugins\juce_AudioPluginInstance.h" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\src\plugins\juce_KnownPluginList.cpp" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\src\plugins\juce_KnownPluginList.h" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\src\plugins\juce_PluginDescription.cpp" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\src\plugins\juce_PluginDescription.h" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\src\plugins\juce_PluginDirectoryScanner.cpp" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\src\plugins\juce_PluginDirectoryScanner.h" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\src\plugins\juce_PluginListComponent.cpp" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\src\plugins\juce_PluginListComponent.h" | |||
| > | |||
| </File> | |||
| <Filter | |||
| Name="vst" | |||
| > | |||
| <File | |||
| RelativePath="..\..\src\plugins\vst\juce_VSTPluginFormat.h" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\src\plugins\vst\juce_VSTPluginInstance.cpp" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\src\plugins\vst\juce_VSTPluginInstance.h" | |||
| > | |||
| </File> | |||
| </Filter> | |||
| </Filter> | |||
| </Filter> | |||
| <Filter | |||
| Name="Resource Files" | |||
| Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" | |||
| UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" | |||
| > | |||
| </Filter> | |||
| </Files> | |||
| <Globals> | |||
| </Globals> | |||
| </VisualStudioProject> | |||
| @@ -0,0 +1,110 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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.h" | |||
| #include "host/MainHostWindow.h" | |||
| #include "host/InternalFilters.h" | |||
| ApplicationCommandManager* commandManager = 0; | |||
| //============================================================================== | |||
| class PluginHostApp : public JUCEApplication | |||
| { | |||
| MainHostWindow* mainWindow; | |||
| public: | |||
| //============================================================================== | |||
| PluginHostApp() | |||
| : mainWindow (0) | |||
| { | |||
| } | |||
| ~PluginHostApp() | |||
| { | |||
| } | |||
| void initialise (const String& /*commandLine*/) | |||
| { | |||
| // initialise our settings file.. | |||
| ApplicationProperties::getInstance() | |||
| ->setStorageParameters (T("Juce Audio Plugin Host"), | |||
| T("settings"), String::empty, 1000, | |||
| PropertiesFile::storeAsXML); | |||
| commandManager = new ApplicationCommandManager(); | |||
| AudioPluginFormatManager::getInstance()->addDefaultFormats(); | |||
| AudioPluginFormatManager::getInstance()->addFormat (new InternalPluginFormat()); | |||
| mainWindow = new MainHostWindow(); | |||
| commandManager->registerAllCommandsForTarget (this); | |||
| commandManager->registerAllCommandsForTarget (mainWindow); | |||
| } | |||
| void shutdown() | |||
| { | |||
| deleteAndZero (mainWindow); | |||
| ApplicationProperties::getInstance()->closeFiles(); | |||
| deleteAndZero (commandManager); | |||
| } | |||
| const String getApplicationName() | |||
| { | |||
| return T("Juce Plug-In Host"); | |||
| } | |||
| const String getApplicationVersion() | |||
| { | |||
| return T("0.9"); | |||
| } | |||
| void systemRequestedQuit() | |||
| { | |||
| if (mainWindow->isValidComponent()) | |||
| mainWindow->tryToQuitApplication(); | |||
| else | |||
| JUCEApplication::quit(); | |||
| } | |||
| bool moreThanOneInstanceAllowed() | |||
| { | |||
| return true; | |||
| } | |||
| }; | |||
| // This kicks the whole thing off.. | |||
| START_JUCE_APPLICATION (PluginHostApp) | |||
| @@ -0,0 +1,744 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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 "FilterGraph.h" | |||
| #include "InternalFilters.h" | |||
| //============================================================================== | |||
| FilterConnection::FilterConnection (FilterGraph& owner_) | |||
| : owner (owner_) | |||
| { | |||
| } | |||
| FilterConnection::FilterConnection (const FilterConnection& other) | |||
| : sourceFilterID (other.sourceFilterID), | |||
| sourceChannel (other.sourceChannel), | |||
| destFilterID (other.destFilterID), | |||
| destChannel (other.destChannel), | |||
| owner (other.owner) | |||
| { | |||
| } | |||
| FilterConnection::~FilterConnection() | |||
| { | |||
| } | |||
| //============================================================================== | |||
| class PluginWindow : public DocumentWindow | |||
| { | |||
| public: | |||
| PluginWindow (Component* const uiComp, | |||
| FilterInGraph& owner_) | |||
| : DocumentWindow (uiComp->getName(), Colours::lightblue, | |||
| DocumentWindow::minimiseButton | DocumentWindow::closeButton), | |||
| owner (owner_) | |||
| { | |||
| setSize (400, 300); | |||
| setContentComponent (uiComp, true, true); | |||
| setTopLeftPosition (owner.lastX, owner.lastY); | |||
| setVisible (true); | |||
| } | |||
| ~PluginWindow() | |||
| { | |||
| setContentComponent (0); | |||
| } | |||
| void moved() | |||
| { | |||
| owner.lastX = getX(); | |||
| owner.lastY = getY(); | |||
| } | |||
| void closeButtonPressed() | |||
| { | |||
| owner.activeUI = 0; | |||
| delete this; | |||
| } | |||
| private: | |||
| FilterInGraph& owner; | |||
| }; | |||
| //============================================================================== | |||
| FilterInGraph::FilterInGraph (FilterGraph& owner_, AudioPluginInstance* const filter_) | |||
| : owner (owner_), | |||
| filter (filter_), | |||
| uid (0), | |||
| processedAudio (1, 1), | |||
| inputAudio (1, 1), | |||
| activeUI (0) | |||
| { | |||
| lastX = 100 + Random::getSystemRandom().nextInt (400); | |||
| lastY = 100 + Random::getSystemRandom().nextInt (400); | |||
| } | |||
| FilterInGraph::~FilterInGraph() | |||
| { | |||
| delete activeUI; | |||
| delete filter; | |||
| } | |||
| void FilterInGraph::setPosition (double newX, double newY) throw() | |||
| { | |||
| x = jlimit (0.0, 1.0, newX); | |||
| y = jlimit (0.0, 1.0, newY); | |||
| } | |||
| void FilterInGraph::showUI() | |||
| { | |||
| if (activeUI == 0) | |||
| { | |||
| Component* ui = filter->createEditorIfNeeded(); | |||
| if (ui != 0) | |||
| { | |||
| ui->setName (filter->getName()); | |||
| activeUI = new PluginWindow (ui, *this); | |||
| } | |||
| } | |||
| if (activeUI != 0) | |||
| activeUI->toFront (true); | |||
| } | |||
| void FilterInGraph::prepareBuffers (int blockSize) | |||
| { | |||
| processedAudio.setSize (jmax (1, filter->getNumOutputChannels()), blockSize); | |||
| inputAudio.setSize (jmax (1, filter->getNumInputChannels()), blockSize); | |||
| processedAudio.clear(); | |||
| processedMidi.clear(); | |||
| } | |||
| void FilterInGraph::renderBlock (int numSamples, | |||
| const ReferenceCountedArray <FilterInGraph>& filters, | |||
| const OwnedArray <FilterConnection>& connections) | |||
| { | |||
| processedAudio.setSize (jmax (1, filter->getNumOutputChannels()), numSamples); | |||
| inputAudio.setSize (jmax (1, filter->getNumInputChannels()), numSamples); | |||
| // this isn't particularly efficient - could do with some optimising here | |||
| inputAudio.clear(); | |||
| processedAudio.clear(); | |||
| processedMidi.clear(); | |||
| for (int i = connections.size(); --i >= 0;) | |||
| { | |||
| const FilterConnection* const fc = connections.getUnchecked(i); | |||
| if (fc->destFilterID == uid) | |||
| { | |||
| for (int j = filters.size(); --j >= 0;) | |||
| { | |||
| const FilterInGraph* const input = filters.getUnchecked(j); | |||
| if (filters.getUnchecked(j)->uid == fc->sourceFilterID) | |||
| { | |||
| if (fc->sourceChannel == FilterGraph::midiChannelNumber) | |||
| { | |||
| processedMidi.addEvents (input->processedMidi, 0, numSamples, 0); | |||
| } | |||
| else | |||
| { | |||
| inputAudio.addFrom (fc->destChannel, 0, input->processedAudio, | |||
| fc->sourceChannel, 0, numSamples); | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| filter->processBlock (inputAudio, processedAudio, true, processedMidi); | |||
| } | |||
| XmlElement* FilterInGraph::createXml() const | |||
| { | |||
| XmlElement* e = new XmlElement ("FILTER"); | |||
| e->setAttribute (T("uid"), (int) uid); | |||
| e->setAttribute (T("x"), x); | |||
| e->setAttribute (T("y"), y); | |||
| e->setAttribute (T("uiLastX"), lastX); | |||
| e->setAttribute (T("uiLastY"), lastY); | |||
| PluginDescription pd; | |||
| pd.fillInFromInstance (*filter); | |||
| e->addChildElement (pd.createXml()); | |||
| XmlElement* state = new XmlElement ("STATE"); | |||
| juce::MemoryBlock m; | |||
| filter->getStateInformation (m); | |||
| state->addTextElement (m.toBase64Encoding()); | |||
| e->addChildElement (state); | |||
| return e; | |||
| } | |||
| FilterInGraph* FilterInGraph::createForDescription (FilterGraph& owner, const PluginDescription& desc) | |||
| { | |||
| AudioPluginInstance* instance = desc.createInstance(); | |||
| if (instance != 0) | |||
| return new FilterInGraph (owner, instance); | |||
| return 0; | |||
| } | |||
| FilterInGraph* FilterInGraph::createFromXml (FilterGraph& owner, const XmlElement& xml) | |||
| { | |||
| PluginDescription pd; | |||
| forEachXmlChildElement (xml, e) | |||
| { | |||
| if (pd.loadFromXml (*e)) | |||
| break; | |||
| } | |||
| FilterInGraph* const c = createForDescription (owner, pd); | |||
| if (c == 0) | |||
| return 0; | |||
| const XmlElement* const state = xml.getChildByName (T("STATE")); | |||
| if (state != 0) | |||
| { | |||
| juce::MemoryBlock m; | |||
| m.fromBase64Encoding (state->getAllSubText()); | |||
| c->filter->setStateInformation (m.getData(), m.getSize()); | |||
| } | |||
| c->uid = xml.getIntAttribute (T("uid")); | |||
| c->x = xml.getDoubleAttribute (T("x")); | |||
| c->y = xml.getDoubleAttribute (T("y")); | |||
| c->lastX = xml.getIntAttribute (T("uiLastX"), c->lastX); | |||
| c->lastY = xml.getIntAttribute (T("uiLastY"), c->lastY); | |||
| return c; | |||
| } | |||
| //============================================================================== | |||
| const int FilterGraph::midiChannelNumber = 0x1000; | |||
| FilterGraph::FilterGraph() | |||
| : FileBasedDocument (filenameSuffix, | |||
| filenameWildcard, | |||
| "Load a filter graph", | |||
| "Save a filter graph"), | |||
| lastUID (0) | |||
| { | |||
| InternalPluginFormat internalFormat; | |||
| addFilter (internalFormat.getDescriptionFor (InternalPluginFormat::audioInputFilter), | |||
| 0.5f, 0.1f); | |||
| addFilter (internalFormat.getDescriptionFor (InternalPluginFormat::midiInputFilter), | |||
| 0.25f, 0.1f); | |||
| addFilter (internalFormat.getDescriptionFor (InternalPluginFormat::audioOutputFilter), | |||
| 0.5f, 0.9f); | |||
| setChangedFlag (false); | |||
| } | |||
| FilterGraph::~FilterGraph() | |||
| { | |||
| clear(); | |||
| } | |||
| uint32 FilterGraph::getNextUID() throw() | |||
| { | |||
| return ++lastUID; | |||
| } | |||
| //============================================================================== | |||
| const String FilterGraph::getDocumentTitle() | |||
| { | |||
| if (! getFile().exists()) | |||
| return "Unnamed"; | |||
| return getFile().getFileNameWithoutExtension(); | |||
| } | |||
| const String FilterGraph::loadDocument (const File& file) | |||
| { | |||
| XmlDocument doc (file); | |||
| XmlElement* xml = doc.getDocumentElement(); | |||
| if (xml == 0 || ! xml->hasTagName (T("FILTERGRAPH"))) | |||
| { | |||
| delete xml; | |||
| return "Not a valid filter graph file"; | |||
| } | |||
| restoreFromXml (*xml); | |||
| delete xml; | |||
| return String::empty; | |||
| } | |||
| const String FilterGraph::saveDocument (const File& file) | |||
| { | |||
| XmlElement* xml = createXml(); | |||
| String error; | |||
| if (! xml->writeToFile (file, String::empty)) | |||
| error = "Couldn't write to the file"; | |||
| delete xml; | |||
| return error; | |||
| } | |||
| const File FilterGraph::getLastDocumentOpened() | |||
| { | |||
| RecentlyOpenedFilesList recentFiles; | |||
| recentFiles.restoreFromString (ApplicationProperties::getInstance()->getUserSettings() | |||
| ->getValue ("recentFilterGraphFiles")); | |||
| return recentFiles.getFile (0); | |||
| } | |||
| void FilterGraph::setLastDocumentOpened (const File& file) | |||
| { | |||
| RecentlyOpenedFilesList recentFiles; | |||
| recentFiles.restoreFromString (ApplicationProperties::getInstance()->getUserSettings() | |||
| ->getValue ("recentFilterGraphFiles")); | |||
| recentFiles.addFile (file); | |||
| ApplicationProperties::getInstance()->getUserSettings() | |||
| ->setValue ("recentFilterGraphFiles", recentFiles.toString()); | |||
| } | |||
| //============================================================================== | |||
| FilterInGraph* FilterGraph::getFilterForUID (const uint32 uid) const throw() | |||
| { | |||
| for (int i = filters.size(); --i >= 0;) | |||
| if (filters.getUnchecked(i)->uid == uid) | |||
| return filters.getUnchecked(i); | |||
| return 0; | |||
| } | |||
| void FilterGraph::addFilter (const FilterInGraph::Ptr& newFilter) | |||
| { | |||
| if (newFilter->uid == 0) | |||
| newFilter->uid = getNextUID(); | |||
| else if (newFilter->uid > lastUID) | |||
| lastUID = newFilter->uid; | |||
| filters.add (newFilter); | |||
| changed(); | |||
| } | |||
| void FilterGraph::addFilter (const PluginDescription* desc, double x, double y) | |||
| { | |||
| if (desc != 0) | |||
| { | |||
| FilterInGraph* cf = FilterInGraph::createForDescription (*this, *desc); | |||
| if (cf != 0) | |||
| { | |||
| cf->setPosition (x, y); | |||
| addFilter (cf); | |||
| } | |||
| } | |||
| } | |||
| void FilterGraph::removeFilter (const uint32 uid) | |||
| { | |||
| FilterInGraph* const filter = getFilterForUID (uid); | |||
| if (filter != 0) | |||
| { | |||
| disconnectFilter (uid); | |||
| filters.removeObject (filter); | |||
| changed(); | |||
| } | |||
| } | |||
| void FilterGraph::disconnectFilter (const uint32 uid) | |||
| { | |||
| for (int i = connections.size(); --i >= 0;) | |||
| { | |||
| const FilterConnection* const fc = connections.getUnchecked(i); | |||
| if (fc->sourceFilterID == uid | |||
| || fc->destFilterID == uid) | |||
| { | |||
| removeConnection (i); | |||
| } | |||
| } | |||
| } | |||
| bool FilterGraph::isAnInputTo (const uint32 possibleInput, const uint32 possibleDestination, int recursionCheck) const throw() | |||
| { | |||
| if (recursionCheck > 0) | |||
| { | |||
| for (int i = 0; i < connections.size(); ++i) | |||
| { | |||
| if (connections.getUnchecked(i)->destFilterID == possibleDestination | |||
| && (connections.getUnchecked(i)->sourceFilterID == possibleInput | |||
| || isAnInputTo (possibleInput, connections.getUnchecked(i)->sourceFilterID, recursionCheck - 1))) | |||
| return true; | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| bool FilterGraph::isAnInputTo (const uint32 possibleInput, const uint32 possibleDestination) const throw() | |||
| { | |||
| return isAnInputTo (possibleInput, possibleDestination, filters.size() + 1); | |||
| } | |||
| FilterConnection* FilterGraph::getConnectionBetween (uint32 sourceFilterUID, int sourceFilterChannel, | |||
| uint32 destFilterUID, int destFilterChannel) const throw() | |||
| { | |||
| for (int i = connections.size(); --i >= 0;) | |||
| { | |||
| FilterConnection* const fc = connections.getUnchecked(i); | |||
| if (fc->sourceFilterID == sourceFilterUID | |||
| && fc->sourceChannel == sourceFilterChannel | |||
| && fc->destFilterID == destFilterUID | |||
| && fc->destChannel == destFilterChannel) | |||
| { | |||
| return fc; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| bool FilterGraph::canConnect (uint32 sourceFilterUID, int sourceFilterChannel, | |||
| uint32 destFilterUID, int destFilterChannel) const throw() | |||
| { | |||
| if (sourceFilterChannel < 0 | |||
| || destFilterChannel < 0 | |||
| || sourceFilterUID == destFilterUID | |||
| || (destFilterChannel == midiChannelNumber) != (sourceFilterChannel == midiChannelNumber)) | |||
| return false; | |||
| const FilterInGraph* const source = getFilterForUID (sourceFilterUID); | |||
| if (source == 0 | |||
| || (sourceFilterChannel != midiChannelNumber && (sourceFilterChannel < 0 || sourceFilterChannel >= source->filter->getNumOutputChannels())) | |||
| || (sourceFilterChannel == midiChannelNumber && ! source->filter->producesMidi())) | |||
| return false; | |||
| const FilterInGraph* const dest = getFilterForUID (destFilterUID); | |||
| if (dest == 0 | |||
| || (destFilterChannel != midiChannelNumber && (destFilterChannel < 0 || destFilterChannel >= dest->filter->getNumInputChannels())) | |||
| || (destFilterChannel == midiChannelNumber && ! dest->filter->acceptsMidi())) | |||
| return false; | |||
| if (getConnectionBetween (sourceFilterUID, sourceFilterChannel, destFilterUID, destFilterChannel) != 0) | |||
| return false; | |||
| return true; | |||
| } | |||
| void FilterGraph::addConnection (uint32 sourceFilterUID, int sourceChannel, | |||
| uint32 destFilterUID, int destChannel) | |||
| { | |||
| if (canConnect (sourceFilterUID, sourceChannel, destFilterUID, destChannel)) | |||
| { | |||
| FilterConnection* const conn = new FilterConnection (*this); | |||
| conn->sourceFilterID = sourceFilterUID; | |||
| conn->sourceChannel = sourceChannel; | |||
| conn->destFilterID = destFilterUID; | |||
| conn->destChannel = destChannel; | |||
| connections.add (conn); | |||
| changed(); | |||
| } | |||
| } | |||
| void FilterGraph::removeConnection (const int index) | |||
| { | |||
| if (connections [index] != 0) | |||
| { | |||
| connections.remove (index); | |||
| changed(); | |||
| } | |||
| } | |||
| void FilterGraph::removeConnection (uint32 sourceFilterUID, int sourceFilterChannel, | |||
| uint32 destFilterUID, int destFilterChannel) | |||
| { | |||
| for (int i = connections.size(); --i >= 0;) | |||
| { | |||
| const FilterConnection* const fc = connections.getUnchecked(i); | |||
| if (fc->sourceFilterID == sourceFilterUID | |||
| && fc->sourceChannel == sourceFilterChannel | |||
| && fc->destFilterID == destFilterUID | |||
| && fc->destChannel == destFilterChannel) | |||
| { | |||
| removeConnection (i); | |||
| } | |||
| } | |||
| } | |||
| void FilterGraph::clear() | |||
| { | |||
| connections.clear(); | |||
| filters.clear(); | |||
| changed(); | |||
| } | |||
| XmlElement* FilterGraph::createXml() const | |||
| { | |||
| XmlElement* xml = new XmlElement ("FILTERGRAPH"); | |||
| int i; | |||
| for (i = 0; i < filters.size(); ++i) | |||
| xml->addChildElement (filters.getUnchecked(i)->createXml()); | |||
| for (i = 0; i < connections.size(); ++i) | |||
| { | |||
| const FilterConnection* const fc = connections.getUnchecked(i); | |||
| XmlElement* e = new XmlElement ("CONNECTION"); | |||
| e->setAttribute (T("srcFilter"), (int) fc->sourceFilterID); | |||
| e->setAttribute (T("srcChannel"), fc->sourceChannel); | |||
| e->setAttribute (T("dstFilter"), (int) fc->destFilterID); | |||
| e->setAttribute (T("dstChannel"), fc->destChannel); | |||
| xml->addChildElement (e); | |||
| } | |||
| return xml; | |||
| } | |||
| void FilterGraph::restoreFromXml (const XmlElement& xml) | |||
| { | |||
| clear(); | |||
| forEachXmlChildElementWithTagName (xml, e, T("FILTER")) | |||
| { | |||
| FilterInGraph* f = FilterInGraph::createFromXml (*this, *e); | |||
| if (f != 0) | |||
| addFilter (f); | |||
| } | |||
| forEachXmlChildElementWithTagName (xml, e, T("CONNECTION")) | |||
| { | |||
| addConnection ((uint32) e->getIntAttribute (T("srcFilter")), | |||
| e->getIntAttribute (T("srcChannel")), | |||
| (uint32) e->getIntAttribute (T("dstFilter")), | |||
| e->getIntAttribute (T("dstChannel"))); | |||
| } | |||
| } | |||
| //============================================================================== | |||
| FilterGraphPlayer::FilterGraphPlayer() | |||
| : sampleRate (44100.0), | |||
| blockSize (512), | |||
| deviceManager (0), | |||
| inputChannelData (0), | |||
| totalNumInputChannels (0), | |||
| outputChannelData (0), | |||
| totalNumOutputChannels (0) | |||
| { | |||
| setAudioDeviceManager (0); | |||
| keyState.addListener (&messageCollector); | |||
| } | |||
| FilterGraphPlayer::~FilterGraphPlayer() | |||
| { | |||
| keyState.removeListener (&messageCollector); | |||
| } | |||
| void FilterGraphPlayer::setAudioDeviceManager (AudioDeviceManager* dm) | |||
| { | |||
| if (deviceManager != 0) | |||
| { | |||
| deviceManager->removeMidiInputCallback (this); | |||
| deviceManager->setAudioCallback (0); | |||
| } | |||
| deviceManager = dm; | |||
| if (dm != 0) | |||
| { | |||
| dm->addMidiInputCallback (String::empty, this); | |||
| dm->setAudioCallback (this); | |||
| } | |||
| } | |||
| int FilterGraphPlayer::compareElements (FilterInGraph* const first, FilterInGraph* const second) throw() | |||
| { | |||
| const bool firstIsInputToSecond = first->owner.isAnInputTo (first->uid, second->uid); | |||
| const bool secondInInputToFirst = first->owner.isAnInputTo (second->uid, first->uid); | |||
| if (firstIsInputToSecond == secondInInputToFirst) | |||
| return 0; | |||
| return firstIsInputToSecond ? -1 : 1; | |||
| } | |||
| void FilterGraphPlayer::updateFrom (FilterGraph* graphToUse) | |||
| { | |||
| ReferenceCountedArray <FilterInGraph> filtersBeingRemoved (filters); | |||
| if (graphToUse != 0) | |||
| { | |||
| ReferenceCountedArray <FilterInGraph> newFilters (graphToUse->filters); | |||
| int i; | |||
| for (i = newFilters.size(); --i >= 0;) | |||
| if (filters.contains (newFilters.getUnchecked(i))) | |||
| newFilters.remove (i); | |||
| for (i = filtersBeingRemoved.size(); --i >= 0;) | |||
| if (graphToUse->filters.contains (filtersBeingRemoved.getUnchecked(i))) | |||
| filtersBeingRemoved.remove (i); | |||
| // prepare any new filters for use.. | |||
| for (i = 0; i < newFilters.size(); ++i) | |||
| newFilters.getUnchecked(i)->filter->prepareToPlay (sampleRate, blockSize); | |||
| ReferenceCountedArray <FilterInGraph> sortedFilters (graphToUse->filters); | |||
| sortedFilters.sort (*this, true); | |||
| for (i = sortedFilters.size(); --i >= 0;) | |||
| { | |||
| PlayerAwareFilter* const specialFilter = dynamic_cast <PlayerAwareFilter*> (sortedFilters.getUnchecked(i)->filter); | |||
| if (specialFilter != 0) | |||
| specialFilter->setPlayer (this); | |||
| } | |||
| { | |||
| const ScopedLock sl (processLock); | |||
| filters = sortedFilters; | |||
| connections.clear(); | |||
| for (int i = 0; i < graphToUse->connections.size(); ++i) | |||
| connections.add (new FilterConnection (*graphToUse->connections.getUnchecked(i))); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| const ScopedLock sl (processLock); | |||
| filters.clear(); | |||
| connections.clear(); | |||
| } | |||
| // release any old ones.. | |||
| for (int i = 0; i < filtersBeingRemoved.size(); ++i) | |||
| { | |||
| filtersBeingRemoved.getUnchecked(i)->filter->releaseResources(); | |||
| PlayerAwareFilter* const specialFilter = dynamic_cast <PlayerAwareFilter*> (filtersBeingRemoved.getUnchecked(i)->filter); | |||
| if (specialFilter != 0) | |||
| specialFilter->setPlayer (0); | |||
| } | |||
| } | |||
| void FilterGraphPlayer::audioDeviceIOCallback (const float** inputChannelData_, | |||
| int totalNumInputChannels_, | |||
| float** outputChannelData_, | |||
| int totalNumOutputChannels_, | |||
| int numSamples) | |||
| { | |||
| incomingMidi.clear(); | |||
| messageCollector.removeNextBlockOfMessages (incomingMidi, numSamples); | |||
| for (int i = 0; i < totalNumOutputChannels_; ++i) | |||
| if (outputChannelData_[i] != 0) | |||
| zeromem (outputChannelData_[i], sizeof (float) * numSamples); | |||
| const ScopedLock sl (processLock); | |||
| inputChannelData = inputChannelData_; | |||
| totalNumInputChannels = totalNumInputChannels_; | |||
| outputChannelData = outputChannelData_; | |||
| totalNumOutputChannels = totalNumOutputChannels_; | |||
| for (int i = 0; i < filters.size(); ++i) | |||
| { | |||
| FilterInGraph* const cf = filters.getUnchecked(i); | |||
| cf->renderBlock (numSamples, filters, connections); | |||
| } | |||
| } | |||
| void FilterGraphPlayer::audioDeviceAboutToStart (double sampleRate_, int numSamplesPerBlock) | |||
| { | |||
| const ScopedLock sl (processLock); | |||
| sampleRate = sampleRate_; | |||
| blockSize = numSamplesPerBlock; | |||
| messageCollector.reset (sampleRate_); | |||
| for (int i = 0; i < filters.size(); ++i) | |||
| { | |||
| filters.getUnchecked(i)->prepareBuffers (blockSize); | |||
| filters.getUnchecked(i)->filter->prepareToPlay (sampleRate, blockSize); | |||
| } | |||
| } | |||
| void FilterGraphPlayer::audioDeviceStopped() | |||
| { | |||
| const ScopedLock sl (processLock); | |||
| for (int i = 0; i < filters.size(); ++i) | |||
| filters.getUnchecked(i)->filter->releaseResources(); | |||
| } | |||
| void FilterGraphPlayer::handleIncomingMidiMessage (MidiInput*, const MidiMessage& message) | |||
| { | |||
| // keyState.processNextMidiEvent (message); | |||
| messageCollector.addMessageToQueue (message); | |||
| } | |||
| @@ -0,0 +1,269 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_FILTERGRAPH_JUCEHEADER__ | |||
| #define __JUCE_FILTERGRAPH_JUCEHEADER__ | |||
| #include "../plugins/juce_AudioPluginInstance.h" | |||
| #include "../plugins/juce_PluginDescription.h" | |||
| class FilterInGraph; | |||
| class FilterGraph; | |||
| class FilterGraphPlayer; | |||
| const char* const filenameSuffix = ".filtergraph"; | |||
| const char* const filenameWildcard = "*.filtergraph"; | |||
| //============================================================================== | |||
| /** | |||
| Represents a connection between two pins in a FilterGraph. | |||
| */ | |||
| class FilterConnection | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| FilterConnection (FilterGraph& owner); | |||
| FilterConnection (const FilterConnection& other); | |||
| ~FilterConnection(); | |||
| //============================================================================== | |||
| uint32 sourceFilterID; | |||
| int sourceChannel; | |||
| uint32 destFilterID; | |||
| int destChannel; | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| FilterGraph& owner; | |||
| const FilterConnection& operator= (const FilterConnection&); | |||
| }; | |||
| //============================================================================== | |||
| /** | |||
| Represents one of the filters in a FilterGraph. | |||
| */ | |||
| class FilterInGraph : public ReferenceCountedObject | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| FilterInGraph (FilterGraph& owner, AudioPluginInstance* const plugin); | |||
| ~FilterInGraph(); | |||
| //============================================================================== | |||
| AudioPluginInstance* const filter; | |||
| uint32 uid; | |||
| //============================================================================== | |||
| void showUI(); | |||
| double getX() const throw() { return x; } | |||
| double getY() const throw() { return y; } | |||
| void setPosition (double x, double y) throw(); | |||
| XmlElement* createXml() const; | |||
| static FilterInGraph* createForDescription (FilterGraph& owner, const PluginDescription& desc); | |||
| static FilterInGraph* createFromXml (FilterGraph& owner, const XmlElement& xml); | |||
| //============================================================================== | |||
| typedef ReferenceCountedObjectPtr <FilterInGraph> Ptr; | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| friend class FilterGraphPlayer; | |||
| FilterGraph& owner; | |||
| double x, y; | |||
| friend class PluginWindow; | |||
| Component* activeUI; | |||
| int lastX, lastY; | |||
| MidiBuffer outputMidi; | |||
| AudioSampleBuffer inputAudio, processedAudio; | |||
| MidiBuffer processedMidi; | |||
| void prepareBuffers (int blockSize); | |||
| void renderBlock (int numSamples, | |||
| const ReferenceCountedArray <FilterInGraph>& filters, | |||
| const OwnedArray <FilterConnection>& connections); | |||
| FilterInGraph (const FilterInGraph&); | |||
| const FilterInGraph& operator= (const FilterInGraph&); | |||
| }; | |||
| //============================================================================== | |||
| /** | |||
| A collection of filters and some connections between them. | |||
| */ | |||
| class FilterGraph : public FileBasedDocument | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| FilterGraph(); | |||
| ~FilterGraph(); | |||
| //============================================================================== | |||
| int getNumFilters() const throw() { return filters.size(); } | |||
| FilterInGraph* getFilter (const int index) const throw() { return filters [index]; } | |||
| FilterInGraph* getFilterForUID (const uint32 uid) const throw(); | |||
| void addFilter (const FilterInGraph::Ptr& newFilter); | |||
| void addFilter (const PluginDescription* desc, double x, double y); | |||
| void removeFilter (const uint32 filterUID); | |||
| void disconnectFilter (const uint32 filterUID); | |||
| //============================================================================== | |||
| int getNumConnections() const throw() { return connections.size(); } | |||
| FilterConnection* getConnection (const int index) const throw() { return connections [index]; } | |||
| FilterConnection* getConnectionBetween (uint32 sourceFilterUID, int sourceFilterChannel, | |||
| uint32 destFilterUID, int destFilterChannel) const throw(); | |||
| bool isAnInputTo (const uint32 possibleInput, const uint32 possibleDestination) const throw(); | |||
| bool canConnect (uint32 sourceFilterUID, int sourceFilterChannel, | |||
| uint32 destFilterUID, int destFilterChannel) const throw(); | |||
| void addConnection (uint32 sourceFilterUID, int sourceFilterChannel, | |||
| uint32 destFilterUID, int destFilterChannel); | |||
| void removeConnection (const int index); | |||
| void removeConnection (uint32 sourceFilterUID, int sourceFilterChannel, | |||
| uint32 destFilterUID, int destFilterChannel); | |||
| void clear(); | |||
| XmlElement* createXml() const; | |||
| void restoreFromXml (const XmlElement& xml); | |||
| //============================================================================== | |||
| const String getDocumentTitle(); | |||
| const String loadDocument (const File& file); | |||
| const String saveDocument (const File& file); | |||
| const File getLastDocumentOpened(); | |||
| void setLastDocumentOpened (const File& file); | |||
| /** The special channel index used to refer to a filter's midi channel. | |||
| */ | |||
| static const int midiChannelNumber; | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| friend class FilterGraphPlayer; | |||
| ReferenceCountedArray <FilterInGraph> filters; | |||
| OwnedArray <FilterConnection> connections; | |||
| uint32 lastUID; | |||
| uint32 getNextUID() throw(); | |||
| bool isAnInputTo (const uint32 possibleInput, const uint32 possibleDestination, int recursionCheck) const throw(); | |||
| FilterGraph (const FilterGraph&); | |||
| const FilterGraph& operator= (const FilterGraph&); | |||
| }; | |||
| //============================================================================== | |||
| /** | |||
| An object the | |||
| */ | |||
| class FilterGraphPlayer : public AudioIODeviceCallback, | |||
| public MidiInputCallback | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| FilterGraphPlayer(); | |||
| ~FilterGraphPlayer(); | |||
| //============================================================================== | |||
| void updateFrom (FilterGraph* graphToUse); | |||
| void setAudioDeviceManager (AudioDeviceManager* dm); | |||
| AudioDeviceManager* getAudioDeviceManager() const throw() { return deviceManager; } | |||
| //============================================================================== | |||
| void audioDeviceIOCallback (const float** inputChannelData, | |||
| int totalNumInputChannels, | |||
| float** outputChannelData, | |||
| int totalNumOutputChannels, | |||
| int numSamples); | |||
| void audioDeviceAboutToStart (double sampleRate, int numSamplesPerBlock); | |||
| void audioDeviceStopped(); | |||
| void handleIncomingMidiMessage (MidiInput* source, const MidiMessage& message); | |||
| //============================================================================== | |||
| static int compareElements (FilterInGraph* const first, FilterInGraph* const second) throw(); | |||
| const float** inputChannelData; | |||
| int totalNumInputChannels; | |||
| float** outputChannelData; | |||
| int totalNumOutputChannels; | |||
| MidiBuffer incomingMidi; | |||
| MidiKeyboardState keyState; | |||
| MidiMessageCollector messageCollector; | |||
| //============================================================================== | |||
| class PlayerAwareFilter | |||
| { | |||
| public: | |||
| virtual void setPlayer (FilterGraphPlayer* newPlayer) = 0; | |||
| }; | |||
| private: | |||
| CriticalSection processLock; | |||
| double sampleRate; | |||
| int blockSize; | |||
| AudioDeviceManager* deviceManager; | |||
| ReferenceCountedArray <FilterInGraph> filters; | |||
| OwnedArray <FilterConnection> connections; | |||
| FilterGraphPlayer (const FilterGraphPlayer&); | |||
| const FilterGraphPlayer& operator= (const FilterGraphPlayer&); | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,901 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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.h" | |||
| #include "GraphEditorPanel.h" | |||
| #include "InternalFilters.h" | |||
| #include "MainHostWindow.h" | |||
| //============================================================================== | |||
| class PinComponent : public Component | |||
| { | |||
| public: | |||
| PinComponent (FilterGraph& graph_, | |||
| const uint32 filterID_, const int index_, const bool isInput_) | |||
| : graph (graph_), | |||
| filterID (filterID_), | |||
| index (index_), | |||
| isInput (isInput_) | |||
| { | |||
| setSize (16, 16); | |||
| } | |||
| ~PinComponent() | |||
| { | |||
| } | |||
| void paint (Graphics& g) | |||
| { | |||
| const float w = (float) getWidth(); | |||
| const float h = (float) getHeight(); | |||
| Path p; | |||
| p.addEllipse (w * 0.25f, h * 0.25f, w * 0.5f, h * 0.5f); | |||
| p.addRectangle (w * 0.4f, isInput ? (0.5f * h) : 0.0f, w * 0.2f, h * 0.5f); | |||
| g.setColour (index == FilterGraph::midiChannelNumber ? Colours::red : Colours::green); | |||
| g.fillPath (p); | |||
| } | |||
| void mouseDown (const MouseEvent& e) | |||
| { | |||
| getGraphPanel()->beginConnectorDrag (isInput ? 0 : filterID, | |||
| index, | |||
| isInput ? filterID : 0, | |||
| index, | |||
| e); | |||
| } | |||
| void mouseDrag (const MouseEvent& e) | |||
| { | |||
| getGraphPanel()->dragConnector (e); | |||
| } | |||
| void mouseUp (const MouseEvent& e) | |||
| { | |||
| getGraphPanel()->endDraggingConnector (e); | |||
| } | |||
| juce_UseDebuggingNewOperator | |||
| const uint32 filterID; | |||
| const int index; | |||
| const bool isInput; | |||
| private: | |||
| FilterGraph& graph; | |||
| PinComponent (const PinComponent&); | |||
| const PinComponent& operator= (const PinComponent&); | |||
| GraphEditorPanel* getGraphPanel() const throw() | |||
| { | |||
| return findParentComponentOfClass ((GraphEditorPanel*) 0); | |||
| } | |||
| }; | |||
| //============================================================================== | |||
| class FilterComponent : public Component | |||
| { | |||
| public: | |||
| FilterComponent (FilterGraph& graph_, | |||
| const uint32 filterID_) | |||
| : graph (graph_), | |||
| filterID (filterID_), | |||
| numInputs (0), | |||
| numOutputs (0), | |||
| pinSize (16), | |||
| originalX (0), | |||
| originalY (0), | |||
| font (13.0f, Font::bold), | |||
| numIns (0), | |||
| numOuts (0) | |||
| { | |||
| shadow.setShadowProperties (2.5f, 0.5f, -1, 0); | |||
| setComponentEffect (&shadow); | |||
| setSize (150, 60); | |||
| } | |||
| ~FilterComponent() | |||
| { | |||
| deleteAllChildren(); | |||
| } | |||
| void mouseDown (const MouseEvent& e) | |||
| { | |||
| originalX = 0; | |||
| originalY = 0; | |||
| relativePositionToGlobal (originalX, originalY); | |||
| toFront (true); | |||
| if (e.mods.isPopupMenu()) | |||
| { | |||
| PopupMenu m; | |||
| m.addItem (1, "Delete this filter"); | |||
| m.addItem (2, "Disconnect all pins"); | |||
| const int r = m.show(); | |||
| if (r == 1) | |||
| { | |||
| graph.removeFilter (filterID); | |||
| return; | |||
| } | |||
| else if (r == 2) | |||
| { | |||
| graph.disconnectFilter (filterID); | |||
| } | |||
| } | |||
| } | |||
| void mouseDrag (const MouseEvent& e) | |||
| { | |||
| if (! e.mods.isPopupMenu()) | |||
| { | |||
| int x = originalX + e.getDistanceFromDragStartX(); | |||
| int y = originalY + e.getDistanceFromDragStartY(); | |||
| if (getParentComponent() != 0) | |||
| getParentComponent()->globalPositionToRelative (x, y); | |||
| const FilterInGraph::Ptr f (graph.getFilterForUID (filterID)); | |||
| if (f != 0) | |||
| { | |||
| f->setPosition ((x + getWidth() / 2) / (double) getParentWidth(), | |||
| (y + getHeight() / 2) / (double) getParentHeight()); | |||
| getGraphPanel()->updateComponents(); | |||
| } | |||
| } | |||
| } | |||
| void mouseUp (const MouseEvent& e) | |||
| { | |||
| if (e.mouseWasClicked() && e.getNumberOfClicks() == 2) | |||
| { | |||
| const FilterInGraph::Ptr f (graph.getFilterForUID (filterID)); | |||
| if (f != 0) | |||
| f->showUI(); | |||
| } | |||
| else if (! e.mouseWasClicked()) | |||
| { | |||
| graph.setChangedFlag (true); | |||
| } | |||
| } | |||
| bool hitTest (int x, int y) | |||
| { | |||
| for (int i = getNumChildComponents(); --i >= 0;) | |||
| if (getChildComponent(i)->getBounds().contains (x, y)) | |||
| return true; | |||
| return x >= 3 && x < getWidth() - 6 && y >= pinSize && y < getHeight() - pinSize; | |||
| } | |||
| void paint (Graphics& g) | |||
| { | |||
| g.setColour (Colours::lightgrey); | |||
| const int x = 4; | |||
| const int y = pinSize; | |||
| const int w = getWidth() - x * 2; | |||
| const int h = getHeight() - pinSize * 2; | |||
| g.fillRect (x, y, w, h); | |||
| g.setColour (Colours::black); | |||
| g.setFont (font); | |||
| g.drawFittedText (getName(), | |||
| x + 4, y + 2, w - 8, h - 4, | |||
| Justification::centred, 2); | |||
| g.setColour (Colours::grey); | |||
| g.drawRect (x, y, w, h); | |||
| } | |||
| void resized() | |||
| { | |||
| for (int i = 0; i < getNumChildComponents(); ++i) | |||
| { | |||
| PinComponent* const pc = dynamic_cast <PinComponent*> (getChildComponent(i)); | |||
| if (pc != 0) | |||
| { | |||
| const int total = pc->isInput ? numIns : numOuts; | |||
| const int index = pc->index == FilterGraph::midiChannelNumber ? (total - 1) : pc->index; | |||
| pc->setBounds (proportionOfWidth ((1 + index) / (total + 1.0f)) - pinSize / 2, | |||
| pc->isInput ? 0 : (getHeight() - pinSize), | |||
| pinSize, pinSize); | |||
| } | |||
| } | |||
| } | |||
| void getPinPos (const int index, const bool isInput, float& x, float& y) | |||
| { | |||
| for (int i = 0; i < getNumChildComponents(); ++i) | |||
| { | |||
| PinComponent* const pc = dynamic_cast <PinComponent*> (getChildComponent(i)); | |||
| if (pc != 0 && pc->index == index && isInput == pc->isInput) | |||
| { | |||
| x = getX() + pc->getX() + pc->getWidth() * 0.5f; | |||
| y = getY() + pc->getY() + pc->getHeight() * 0.5f; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| void update() | |||
| { | |||
| const FilterInGraph* const f = graph.getFilterForUID (filterID); | |||
| if (f == 0) | |||
| { | |||
| delete this; | |||
| return; | |||
| } | |||
| numIns = f->filter->getNumInputChannels(); | |||
| if (f->filter->acceptsMidi()) | |||
| ++numIns; | |||
| numOuts = f->filter->getNumOutputChannels(); | |||
| if (f->filter->producesMidi()) | |||
| ++numOuts; | |||
| int w = 100; | |||
| int h = 60; | |||
| w = jmax (w, (jmax (numIns, numOuts) + 1) * 20); | |||
| const int textWidth = font.getStringWidth (f->filter->getName()); | |||
| w = jmax (w, 16 + jmin (textWidth, 300)); | |||
| if (textWidth > 300) | |||
| h = 100; | |||
| setSize (w, h); | |||
| setCentreRelative ((float) f->getX(), (float) f->getY()); | |||
| if (numIns != numInputs || numOuts != numOutputs) | |||
| { | |||
| numInputs = numIns; | |||
| numOutputs = numOuts; | |||
| deleteAllChildren(); | |||
| int i; | |||
| for (i = 0; i < f->filter->getNumInputChannels(); ++i) | |||
| addAndMakeVisible (new PinComponent (graph, filterID, i, true)); | |||
| if (f->filter->acceptsMidi()) | |||
| addAndMakeVisible (new PinComponent (graph, filterID, FilterGraph::midiChannelNumber, true)); | |||
| for (i = 0; i < f->filter->getNumOutputChannels(); ++i) | |||
| addAndMakeVisible (new PinComponent (graph, filterID, i, false)); | |||
| if (f->filter->producesMidi()) | |||
| addAndMakeVisible (new PinComponent (graph, filterID, FilterGraph::midiChannelNumber, false)); | |||
| setName (f->filter->getName()); | |||
| resized(); | |||
| } | |||
| } | |||
| FilterGraph& graph; | |||
| const uint32 filterID; | |||
| int numInputs, numOutputs; | |||
| private: | |||
| int pinSize; | |||
| int originalX, originalY; | |||
| int numIns, numOuts; | |||
| DropShadowEffect shadow; | |||
| Font font; | |||
| GraphEditorPanel* getGraphPanel() const throw() | |||
| { | |||
| return findParentComponentOfClass ((GraphEditorPanel*) 0); | |||
| } | |||
| FilterComponent (const FilterComponent&); | |||
| const FilterComponent& operator= (const FilterComponent&); | |||
| }; | |||
| //============================================================================== | |||
| class ConnectorComponent : public Component | |||
| { | |||
| public: | |||
| ConnectorComponent (FilterGraph& graph_) | |||
| : graph (graph_), | |||
| sourceFilterID (0), | |||
| destFilterID (0), | |||
| sourceFilterChannel (0), | |||
| destFilterChannel (0), | |||
| lastInputX (0), | |||
| lastInputY (0), | |||
| lastOutputX (0), | |||
| lastOutputY (0) | |||
| { | |||
| setAlwaysOnTop (true); | |||
| } | |||
| ~ConnectorComponent() | |||
| { | |||
| } | |||
| void setInput (const uint32 sourceFilterID_, const int sourceFilterChannel_) | |||
| { | |||
| if (sourceFilterID != sourceFilterID_ || sourceFilterChannel != sourceFilterChannel_) | |||
| { | |||
| sourceFilterID = sourceFilterID_; | |||
| sourceFilterChannel = sourceFilterChannel_; | |||
| update(); | |||
| } | |||
| } | |||
| void setOutput (const uint32 destFilterID_, const int destFilterChannel_) | |||
| { | |||
| if (destFilterID != destFilterID_ || destFilterChannel != destFilterChannel_) | |||
| { | |||
| destFilterID = destFilterID_; | |||
| destFilterChannel = destFilterChannel_; | |||
| update(); | |||
| } | |||
| } | |||
| void dragStart (int x, int y) | |||
| { | |||
| lastInputX = (float) x; | |||
| lastInputY = (float) y; | |||
| resizeToFit(); | |||
| } | |||
| void dragEnd (int x, int y) | |||
| { | |||
| lastOutputX = (float) x; | |||
| lastOutputY = (float) y; | |||
| resizeToFit(); | |||
| } | |||
| void update() | |||
| { | |||
| float x1, y1, x2, y2; | |||
| getPoints (x1, y1, x2, y2); | |||
| if (lastInputX != x1 | |||
| || lastInputY != y1 | |||
| || lastOutputX != x2 | |||
| || lastOutputY != y2) | |||
| { | |||
| resizeToFit(); | |||
| } | |||
| } | |||
| void resizeToFit() | |||
| { | |||
| float x1, y1, x2, y2; | |||
| getPoints (x1, y1, x2, y2); | |||
| const Rectangle newBounds ((int) jmin (x1, x2) - 4, | |||
| (int) jmin (y1, y2) - 4, | |||
| (int) abs (x1 - x2) + 8, | |||
| (int) abs (y1 - y2) + 8); | |||
| if (newBounds != getBounds()) | |||
| setBounds (newBounds); | |||
| else | |||
| resized(); | |||
| repaint(); | |||
| } | |||
| void getPoints (float& x1, float& y1, float& x2, float& y2) const | |||
| { | |||
| x1 = lastInputX; | |||
| y1 = lastInputY; | |||
| x2 = lastOutputX; | |||
| y2 = lastOutputY; | |||
| GraphEditorPanel* const hostPanel = getGraphPanel(); | |||
| if (hostPanel != 0) | |||
| { | |||
| FilterComponent* srcFilterComp = hostPanel->getComponentForFilter (sourceFilterID); | |||
| if (srcFilterComp != 0) | |||
| srcFilterComp->getPinPos (sourceFilterChannel, false, x1, y1); | |||
| FilterComponent* dstFilterComp = hostPanel->getComponentForFilter (destFilterID); | |||
| if (dstFilterComp != 0) | |||
| dstFilterComp->getPinPos (destFilterChannel, true, x2, y2); | |||
| } | |||
| } | |||
| void paint (Graphics& g) | |||
| { | |||
| if (sourceFilterChannel == FilterGraph::midiChannelNumber | |||
| || destFilterChannel == FilterGraph::midiChannelNumber) | |||
| { | |||
| g.setColour (Colours::red); | |||
| } | |||
| else | |||
| { | |||
| g.setColour (Colours::green); | |||
| } | |||
| g.fillPath (linePath); | |||
| } | |||
| bool hitTest (int x, int y) | |||
| { | |||
| if (hitPath.contains ((float) x, (float) y)) | |||
| { | |||
| double distanceFromStart, distanceFromEnd; | |||
| getDistancesFromEnds (x, y, distanceFromStart, distanceFromEnd); | |||
| // avoid clicking the connector when over a pin | |||
| return distanceFromStart > 7.0 && distanceFromEnd > 7.0; | |||
| } | |||
| return false; | |||
| } | |||
| void mouseDown (const MouseEvent&) | |||
| { | |||
| dragging = false; | |||
| } | |||
| void mouseDrag (const MouseEvent& e) | |||
| { | |||
| if ((! dragging) && ! e.mouseWasClicked()) | |||
| { | |||
| dragging = true; | |||
| graph.removeConnection (sourceFilterID, sourceFilterChannel, destFilterID, destFilterChannel); | |||
| double distanceFromStart, distanceFromEnd; | |||
| getDistancesFromEnds (e.x, e.y, distanceFromStart, distanceFromEnd); | |||
| const bool isNearerSource = (distanceFromStart < distanceFromEnd); | |||
| getGraphPanel()->beginConnectorDrag (isNearerSource ? 0 : sourceFilterID, | |||
| sourceFilterChannel, | |||
| isNearerSource ? destFilterID : 0, | |||
| destFilterChannel, | |||
| e); | |||
| } | |||
| else if (dragging) | |||
| { | |||
| getGraphPanel()->dragConnector (e); | |||
| } | |||
| } | |||
| void mouseUp (const MouseEvent& e) | |||
| { | |||
| if (dragging) | |||
| getGraphPanel()->endDraggingConnector (e); | |||
| } | |||
| void resized() | |||
| { | |||
| float x1, y1, x2, y2; | |||
| getPoints (x1, y1, x2, y2); | |||
| lastInputX = x1; | |||
| lastInputY = y1; | |||
| lastOutputX = x2; | |||
| lastOutputY = y2; | |||
| x1 -= getX(); | |||
| y1 -= getY(); | |||
| x2 -= getX(); | |||
| y2 -= getY(); | |||
| linePath.clear(); | |||
| linePath.startNewSubPath (x1, y1); | |||
| linePath.cubicTo (x1, y1 + (y2 - y1) * 0.33f, | |||
| x2, y1 + (y2 - y1) * 0.66f, | |||
| x2, y2); | |||
| PathStrokeType wideStroke (8.0f); | |||
| wideStroke.createStrokedPath (hitPath, linePath); | |||
| PathStrokeType stroke (2.5f); | |||
| stroke.createStrokedPath (linePath, linePath); | |||
| const float arrowW = 5.0f; | |||
| const float arrowL = 4.0f; | |||
| Path arrow; | |||
| arrow.addTriangle (-arrowL, arrowW, | |||
| -arrowL, -arrowW, | |||
| arrowL, 0.0f); | |||
| arrow.applyTransform (AffineTransform::identity | |||
| .rotated (float_Pi * 0.5f - (float) atan2 (x2 - x1, y2 - y1)) | |||
| .translated ((x1 + x2) * 0.5f, | |||
| (y1 + y2) * 0.5f)); | |||
| linePath.addPath (arrow); | |||
| linePath.setUsingNonZeroWinding (true); | |||
| } | |||
| juce_UseDebuggingNewOperator | |||
| uint32 sourceFilterID, destFilterID; | |||
| int sourceFilterChannel, destFilterChannel; | |||
| private: | |||
| FilterGraph& graph; | |||
| float lastInputX, lastInputY, lastOutputX, lastOutputY; | |||
| Path linePath, hitPath; | |||
| bool dragging; | |||
| GraphEditorPanel* getGraphPanel() const throw() | |||
| { | |||
| return findParentComponentOfClass ((GraphEditorPanel*) 0); | |||
| } | |||
| void getDistancesFromEnds (int x, int y, double& distanceFromStart, double& distanceFromEnd) const | |||
| { | |||
| float x1, y1, x2, y2; | |||
| getPoints (x1, y1, x2, y2); | |||
| distanceFromStart = juce_hypot (x - (x1 - getX()), y - (y1 - getY())); | |||
| distanceFromEnd = juce_hypot (x - (x2 - getX()), y - (y2 - getY())); | |||
| } | |||
| ConnectorComponent (const ConnectorComponent&); | |||
| const ConnectorComponent& operator= (const ConnectorComponent&); | |||
| }; | |||
| //============================================================================== | |||
| GraphEditorPanel::GraphEditorPanel (FilterGraph& graph_) | |||
| : graph (graph_), | |||
| draggingConnector (0) | |||
| { | |||
| graph.addChangeListener (this); | |||
| setOpaque (true); | |||
| } | |||
| GraphEditorPanel::~GraphEditorPanel() | |||
| { | |||
| graph.removeChangeListener (this); | |||
| deleteAndZero (draggingConnector); | |||
| deleteAllChildren(); | |||
| } | |||
| void GraphEditorPanel::paint (Graphics& g) | |||
| { | |||
| g.fillAll (Colours::white); | |||
| } | |||
| void GraphEditorPanel::mouseDown (const MouseEvent& e) | |||
| { | |||
| if (e.mods.isPopupMenu()) | |||
| { | |||
| PopupMenu m; | |||
| MainHostWindow* const mainWindow = findParentComponentOfClass ((MainHostWindow*) 0); | |||
| if (mainWindow != 0) | |||
| { | |||
| mainWindow->addPluginsToMenu (m); | |||
| const int r = m.show(); | |||
| createNewPlugin (mainWindow->getChosenType (r), e.x, e.y); | |||
| } | |||
| } | |||
| } | |||
| void GraphEditorPanel::createNewPlugin (const PluginDescription* desc, int x, int y) | |||
| { | |||
| graph.addFilter (desc, x / (double) getWidth(), y / (double) getHeight()); | |||
| } | |||
| FilterComponent* GraphEditorPanel::getComponentForFilter (const uint32 filterID) const | |||
| { | |||
| for (int i = getNumChildComponents(); --i >= 0;) | |||
| { | |||
| FilterComponent* const fc = dynamic_cast <FilterComponent*> (getChildComponent (i)); | |||
| if (fc != 0 && fc->filterID == filterID) | |||
| return fc; | |||
| } | |||
| return 0; | |||
| } | |||
| ConnectorComponent* GraphEditorPanel::getComponentForConnection (const FilterConnection& conn) const | |||
| { | |||
| for (int i = getNumChildComponents(); --i >= 0;) | |||
| { | |||
| ConnectorComponent* const c = dynamic_cast <ConnectorComponent*> (getChildComponent (i)); | |||
| if (c != 0 | |||
| && c->sourceFilterID == conn.sourceFilterID | |||
| && c->destFilterID == conn.destFilterID | |||
| && c->sourceFilterChannel == conn.sourceChannel | |||
| && c->destFilterChannel == conn.destChannel) | |||
| { | |||
| return c; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| PinComponent* GraphEditorPanel::findPinAt (const int x, const int y) const | |||
| { | |||
| for (int i = getNumChildComponents(); --i >= 0;) | |||
| { | |||
| FilterComponent* const fc = dynamic_cast <FilterComponent*> (getChildComponent (i)); | |||
| if (fc != 0) | |||
| { | |||
| PinComponent* const pin | |||
| = dynamic_cast <PinComponent*> (fc->getComponentAt (x - fc->getX(), | |||
| y - fc->getY())); | |||
| if (pin != 0) | |||
| return pin; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| void GraphEditorPanel::resized() | |||
| { | |||
| updateComponents(); | |||
| } | |||
| void GraphEditorPanel::changeListenerCallback (void*) | |||
| { | |||
| updateComponents(); | |||
| } | |||
| void GraphEditorPanel::updateComponents() | |||
| { | |||
| int i; | |||
| for (i = getNumChildComponents(); --i >= 0;) | |||
| { | |||
| FilterComponent* const fc = dynamic_cast <FilterComponent*> (getChildComponent (i)); | |||
| if (fc != 0) | |||
| fc->update(); | |||
| } | |||
| for (i = getNumChildComponents(); --i >= 0;) | |||
| { | |||
| ConnectorComponent* const cc = dynamic_cast <ConnectorComponent*> (getChildComponent (i)); | |||
| if (cc != 0 && cc != draggingConnector) | |||
| { | |||
| if (graph.getConnectionBetween (cc->sourceFilterID, cc->sourceFilterChannel, | |||
| cc->destFilterID, cc->destFilterChannel) == 0) | |||
| { | |||
| delete cc; | |||
| } | |||
| else | |||
| { | |||
| cc->update(); | |||
| } | |||
| } | |||
| } | |||
| for (i = graph.getNumFilters(); --i >= 0;) | |||
| { | |||
| const FilterInGraph* const f = graph.getFilter (i); | |||
| if (getComponentForFilter (f->uid) == 0) | |||
| { | |||
| FilterComponent* const comp = new FilterComponent (graph, f->uid); | |||
| addAndMakeVisible (comp); | |||
| comp->update(); | |||
| } | |||
| } | |||
| for (i = graph.getNumConnections(); --i >= 0;) | |||
| { | |||
| FilterConnection* const c = graph.getConnection (i); | |||
| if (getComponentForConnection (*c) == 0) | |||
| { | |||
| ConnectorComponent* const comp = new ConnectorComponent (graph); | |||
| addAndMakeVisible (comp); | |||
| comp->setInput (c->sourceFilterID, c->sourceChannel); | |||
| comp->setOutput (c->destFilterID, c->destChannel); | |||
| } | |||
| } | |||
| } | |||
| void GraphEditorPanel::beginConnectorDrag (const uint32 sourceFilterID, const int sourceFilterChannel, | |||
| const uint32 destFilterID, const int destFilterChannel, | |||
| const MouseEvent& e) | |||
| { | |||
| delete draggingConnector; | |||
| draggingConnector = dynamic_cast <ConnectorComponent*> (e.originalComponent); | |||
| if (draggingConnector == 0) | |||
| draggingConnector = new ConnectorComponent (graph); | |||
| draggingConnector->setInput (sourceFilterID, sourceFilterChannel); | |||
| draggingConnector->setOutput (destFilterID, destFilterChannel); | |||
| addAndMakeVisible (draggingConnector); | |||
| draggingConnector->toFront (false); | |||
| dragConnector (e); | |||
| } | |||
| void GraphEditorPanel::dragConnector (const MouseEvent& e) | |||
| { | |||
| const MouseEvent e2 (e.getEventRelativeTo (this)); | |||
| if (draggingConnector != 0) | |||
| { | |||
| int x = e2.x; | |||
| int y = e2.y; | |||
| PinComponent* const pin = findPinAt (x, y); | |||
| if (pin != 0) | |||
| { | |||
| uint32 srcFilter = draggingConnector->sourceFilterID; | |||
| int srcChannel = draggingConnector->sourceFilterChannel; | |||
| uint32 dstFilter = draggingConnector->destFilterID; | |||
| int dstChannel = draggingConnector->destFilterChannel; | |||
| if (srcFilter == 0 && ! pin->isInput) | |||
| { | |||
| srcFilter = pin->filterID; | |||
| srcChannel = pin->index; | |||
| } | |||
| else if (dstFilter == 0 && pin->isInput) | |||
| { | |||
| dstFilter = pin->filterID; | |||
| dstChannel = pin->index; | |||
| } | |||
| if (graph.canConnect (srcFilter, srcChannel, dstFilter, dstChannel)) | |||
| { | |||
| x = pin->getParentComponent()->getX() + pin->getX() + pin->getWidth() / 2; | |||
| y = pin->getParentComponent()->getY() + pin->getY() + pin->getHeight() / 2; | |||
| } | |||
| } | |||
| if (draggingConnector->sourceFilterID == 0) | |||
| draggingConnector->dragStart (x, y); | |||
| else | |||
| draggingConnector->dragEnd (x, y); | |||
| } | |||
| } | |||
| void GraphEditorPanel::endDraggingConnector (const MouseEvent& e) | |||
| { | |||
| if (draggingConnector == 0) | |||
| return; | |||
| const MouseEvent e2 (e.getEventRelativeTo (this)); | |||
| uint32 srcFilter = draggingConnector->sourceFilterID; | |||
| int srcChannel = draggingConnector->sourceFilterChannel; | |||
| uint32 dstFilter = draggingConnector->destFilterID; | |||
| int dstChannel = draggingConnector->destFilterChannel; | |||
| deleteAndZero (draggingConnector); | |||
| PinComponent* const pin = findPinAt (e2.x, e2.y); | |||
| if (pin != 0) | |||
| { | |||
| if (srcFilter == 0) | |||
| { | |||
| if (pin->isInput) | |||
| return; | |||
| srcFilter = pin->filterID; | |||
| srcChannel = pin->index; | |||
| } | |||
| else | |||
| { | |||
| if (! pin->isInput) | |||
| return; | |||
| dstFilter = pin->filterID; | |||
| dstChannel = pin->index; | |||
| } | |||
| graph.addConnection (srcFilter, srcChannel, dstFilter, dstChannel); | |||
| } | |||
| } | |||
| //============================================================================== | |||
| GraphDocumentComponent::GraphDocumentComponent (AudioDeviceManager* deviceManager_) | |||
| : deviceManager (deviceManager_) | |||
| { | |||
| addAndMakeVisible (graphPanel = new GraphEditorPanel (graph)); | |||
| addAndMakeVisible (keyboardComp = new MidiKeyboardComponent (graphRenderer.keyState, | |||
| MidiKeyboardComponent::horizontalKeyboard)); | |||
| graphRenderer.setAudioDeviceManager (deviceManager); | |||
| graphRenderer.updateFrom (&graph); | |||
| graph.addChangeListener (this); | |||
| deviceManager->addChangeListener (this); | |||
| graphPanel->updateComponents(); | |||
| } | |||
| GraphDocumentComponent::~GraphDocumentComponent() | |||
| { | |||
| graph.removeChangeListener (this); | |||
| deviceManager->removeChangeListener (this); | |||
| deleteAllChildren(); | |||
| graphRenderer.updateFrom (0); | |||
| graphRenderer.setAudioDeviceManager (0); | |||
| graph.clear(); | |||
| } | |||
| void GraphDocumentComponent::resized() | |||
| { | |||
| const int keysHeight = 60; | |||
| graphPanel->setBounds (0, 0, getWidth(), getHeight() - keysHeight); | |||
| keyboardComp->setBounds (0, getHeight() - keysHeight, getWidth(), keysHeight); | |||
| } | |||
| void GraphDocumentComponent::createNewPlugin (const PluginDescription* desc, int x, int y) | |||
| { | |||
| graphPanel->createNewPlugin (desc, x, y); | |||
| } | |||
| void GraphDocumentComponent::changeListenerCallback (void*) | |||
| { | |||
| graphRenderer.updateFrom (&graph); | |||
| } | |||
| @@ -0,0 +1,122 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_FILTERGRAPHEDITOR_JUCEHEADER__ | |||
| #define __JUCE_FILTERGRAPHEDITOR_JUCEHEADER__ | |||
| #include "../plugins/juce_KnownPluginList.h" | |||
| #include "FilterGraph.h" | |||
| class FilterComponent; | |||
| class ConnectorComponent; | |||
| class PinComponent; | |||
| //============================================================================== | |||
| /** | |||
| A panel that displays and edits a FilterGraph. | |||
| */ | |||
| class GraphEditorPanel : public Component, | |||
| public ChangeListener | |||
| { | |||
| public: | |||
| GraphEditorPanel (FilterGraph& graph); | |||
| ~GraphEditorPanel(); | |||
| void paint (Graphics& g); | |||
| void mouseDown (const MouseEvent& e); | |||
| void createNewPlugin (const PluginDescription* desc, int x, int y); | |||
| FilterComponent* getComponentForFilter (const uint32 filterID) const; | |||
| ConnectorComponent* getComponentForConnection (const FilterConnection& conn) const; | |||
| PinComponent* findPinAt (const int x, const int y) const; | |||
| void resized(); | |||
| void changeListenerCallback (void*); | |||
| void updateComponents(); | |||
| //============================================================================== | |||
| void beginConnectorDrag (const uint32 sourceFilterID, const int sourceFilterChannel, | |||
| const uint32 destFilterID, const int destFilterChannel, | |||
| const MouseEvent& e); | |||
| void dragConnector (const MouseEvent& e); | |||
| void endDraggingConnector (const MouseEvent& e); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| FilterGraph& graph; | |||
| ConnectorComponent* draggingConnector; | |||
| GraphEditorPanel (const GraphEditorPanel&); | |||
| const GraphEditorPanel& operator= (const GraphEditorPanel&); | |||
| }; | |||
| //============================================================================== | |||
| /** | |||
| A panel that embeds a GraphEditorPanel with a midi keyboard at the bottom. | |||
| It also manages the graph itself, and plays it. | |||
| */ | |||
| class GraphDocumentComponent : public Component, | |||
| public ChangeListener | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| GraphDocumentComponent (AudioDeviceManager* deviceManager); | |||
| ~GraphDocumentComponent(); | |||
| //============================================================================== | |||
| void createNewPlugin (const PluginDescription* desc, int x, int y); | |||
| //============================================================================== | |||
| FilterGraph graph; | |||
| //============================================================================== | |||
| void resized(); | |||
| void changeListenerCallback (void*); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| AudioDeviceManager* deviceManager; | |||
| FilterGraphPlayer graphRenderer; | |||
| GraphEditorPanel* graphPanel; | |||
| Component* keyboardComp; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,406 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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 "InternalFilters.h" | |||
| #include "FilterGraph.h" | |||
| //============================================================================== | |||
| class InternalFilterBase : public AudioPluginInstance, | |||
| public FilterGraphPlayer::PlayerAwareFilter | |||
| { | |||
| public: | |||
| InternalFilterBase() | |||
| : player (0) | |||
| { | |||
| } | |||
| ~InternalFilterBase() | |||
| { | |||
| } | |||
| void setPlayer (FilterGraphPlayer* p) | |||
| { | |||
| player = p; | |||
| rendererChanged(); | |||
| } | |||
| virtual void rendererChanged() {} | |||
| const String getManufacturer() const { return "Raw Material Software"; } | |||
| const String getFormatName() const { return "Internal"; } | |||
| const File getFile() const { return File::nonexistent; } | |||
| int getUID() const { return getName().hashCode(); } | |||
| int getSamplesLatency() const { return 0; } | |||
| AudioFilterEditor* JUCE_CALLTYPE createEditor() { return 0; } | |||
| int JUCE_CALLTYPE getNumParameters() { return 0; } | |||
| const String JUCE_CALLTYPE getParameterName (int) { return String::empty; } | |||
| float JUCE_CALLTYPE getParameter (int) { return 0; } | |||
| const String JUCE_CALLTYPE getParameterText (int) { return String::empty; } | |||
| void JUCE_CALLTYPE setParameter (int, float) {} | |||
| int JUCE_CALLTYPE getNumPrograms() { return 0; } | |||
| int JUCE_CALLTYPE getCurrentProgram() { return 0; } | |||
| void JUCE_CALLTYPE setCurrentProgram (int) {} | |||
| const String JUCE_CALLTYPE getProgramName (int) { return String::empty; } | |||
| void JUCE_CALLTYPE changeProgramName (int, const String&) {} | |||
| void JUCE_CALLTYPE getStateInformation (JUCE_NAMESPACE::MemoryBlock&) {} | |||
| void JUCE_CALLTYPE setStateInformation (const void*, int) {} | |||
| protected: | |||
| FilterGraphPlayer* player; | |||
| AudioIODevice* getAudioDevice() const | |||
| { | |||
| if (player != 0) | |||
| { | |||
| AudioDeviceManager* const dm = player->getAudioDeviceManager(); | |||
| jassert (dm != 0); | |||
| if (dm != 0) | |||
| return dm->getCurrentAudioDevice(); | |||
| } | |||
| return 0; | |||
| } | |||
| }; | |||
| //============================================================================== | |||
| class AudioInputDeviceFilter : public InternalFilterBase | |||
| { | |||
| public: | |||
| AudioInputDeviceFilter (const int numChannels) | |||
| { | |||
| numOutputChannels = numChannels; | |||
| } | |||
| ~AudioInputDeviceFilter() {} | |||
| const String getName() const { return "Audio Input"; } | |||
| const String getVersion() const { return "1.0"; } | |||
| bool isInstrument() const { return true; } | |||
| const String getCategory() const { return "I/O devices"; } | |||
| bool acceptsMidi() const { return false; } | |||
| bool producesMidi() const { return false; } | |||
| void rendererChanged() | |||
| { | |||
| AudioIODevice* const dev = getAudioDevice(); | |||
| if (dev != 0) | |||
| numOutputChannels = dev->getInputChannelNames().size(); | |||
| } | |||
| void JUCE_CALLTYPE prepareToPlay (double /*sampleRate*/, int /*estimatedSamplesPerBlock*/) | |||
| { | |||
| rendererChanged(); | |||
| } | |||
| void JUCE_CALLTYPE releaseResources() | |||
| { | |||
| } | |||
| void JUCE_CALLTYPE processBlock (const AudioSampleBuffer& /*input*/, | |||
| AudioSampleBuffer& output, | |||
| const bool accumulateOutput, | |||
| MidiBuffer&) | |||
| { | |||
| int n = 0; | |||
| for (int i = 0; i < player->totalNumInputChannels; ++i) | |||
| { | |||
| if (n >= output.getNumChannels()) | |||
| break; | |||
| if (player->inputChannelData [i] != 0) | |||
| { | |||
| if (accumulateOutput) | |||
| output.addFrom (n, 0, player->inputChannelData [i], output.getNumSamples()); | |||
| else | |||
| output.copyFrom (n, 0, player->inputChannelData [i], output.getNumSamples()); | |||
| ++n; | |||
| } | |||
| } | |||
| } | |||
| const String JUCE_CALLTYPE getInputChannelName (const int channelIndex) const | |||
| { | |||
| return String (channelIndex + 1); | |||
| } | |||
| const String JUCE_CALLTYPE getOutputChannelName (const int channelIndex) const | |||
| { | |||
| AudioIODevice* const dev = getAudioDevice(); | |||
| if (dev != 0) | |||
| return dev->getInputChannelNames() [channelIndex]; | |||
| return String (channelIndex + 1); | |||
| } | |||
| bool JUCE_CALLTYPE isInputChannelStereoPair (int) const | |||
| { | |||
| return true; | |||
| } | |||
| bool JUCE_CALLTYPE isOutputChannelStereoPair (int) const | |||
| { | |||
| return true; | |||
| } | |||
| }; | |||
| //============================================================================== | |||
| class AudioOutputDeviceFilter : public InternalFilterBase | |||
| { | |||
| public: | |||
| AudioOutputDeviceFilter (const int numChannels) | |||
| { | |||
| numInputChannels = numChannels; | |||
| } | |||
| ~AudioOutputDeviceFilter() {} | |||
| const String getName() const { return "Audio Output"; } | |||
| const String getVersion() const { return "1.0"; } | |||
| bool isInstrument() const { return false; } | |||
| const String getCategory() const { return "I/O devices"; } | |||
| bool acceptsMidi() const { return false; } | |||
| bool producesMidi() const { return false; } | |||
| void rendererChanged() | |||
| { | |||
| AudioIODevice* const dev = getAudioDevice(); | |||
| if (dev != 0) | |||
| numInputChannels = dev->getOutputChannelNames().size(); | |||
| } | |||
| void JUCE_CALLTYPE prepareToPlay (double /*sampleRate*/, int /*estimatedSamplesPerBlock*/) | |||
| { | |||
| rendererChanged(); | |||
| } | |||
| void JUCE_CALLTYPE releaseResources() | |||
| { | |||
| } | |||
| void JUCE_CALLTYPE processBlock (const AudioSampleBuffer& input, | |||
| AudioSampleBuffer&, | |||
| const bool accumulateOutput, | |||
| MidiBuffer&) | |||
| { | |||
| int n = 0; | |||
| for (int i = 0; i < player->totalNumOutputChannels; ++i) | |||
| { | |||
| if (n >= input.getNumChannels()) | |||
| break; | |||
| float* dst = player->outputChannelData [i]; | |||
| if (dst != 0) | |||
| { | |||
| const float* src = input.getSampleData (n); | |||
| if (accumulateOutput) | |||
| { | |||
| for (int i = input.getNumSamples(); --i >= 0;) | |||
| *dst++ += *src++; | |||
| } | |||
| else | |||
| { | |||
| memcpy (dst, src, sizeof (float) * input.getNumSamples()); | |||
| } | |||
| ++n; | |||
| } | |||
| } | |||
| } | |||
| const String JUCE_CALLTYPE getInputChannelName (const int channelIndex) const | |||
| { | |||
| AudioIODevice* const dev = getAudioDevice(); | |||
| if (dev != 0) | |||
| return dev->getOutputChannelNames() [channelIndex]; | |||
| return String (channelIndex + 1); | |||
| } | |||
| const String JUCE_CALLTYPE getOutputChannelName (const int channelIndex) const | |||
| { | |||
| return String (channelIndex + 1); | |||
| } | |||
| bool JUCE_CALLTYPE isInputChannelStereoPair (int) const | |||
| { | |||
| return true; | |||
| } | |||
| bool JUCE_CALLTYPE isOutputChannelStereoPair (int) const | |||
| { | |||
| return true; | |||
| } | |||
| }; | |||
| //============================================================================== | |||
| class MidiInputDeviceFilter : public InternalFilterBase | |||
| { | |||
| public: | |||
| MidiInputDeviceFilter() | |||
| { | |||
| } | |||
| ~MidiInputDeviceFilter() {} | |||
| const String getName() const { return "Midi Input"; } | |||
| const String getVersion() const { return "1.0"; } | |||
| bool isInstrument() const { return true; } | |||
| const String getCategory() const { return "I/O devices"; } | |||
| bool acceptsMidi() const { return false; } | |||
| bool producesMidi() const { return true; } | |||
| void rendererChanged() | |||
| { | |||
| if (player != 0) | |||
| { | |||
| AudioDeviceManager* const dm = player->getAudioDeviceManager(); | |||
| jassert (dm != 0); | |||
| } | |||
| } | |||
| void JUCE_CALLTYPE prepareToPlay (double /*sampleRate*/, int /*estimatedSamplesPerBlock*/) | |||
| { | |||
| rendererChanged(); | |||
| } | |||
| void JUCE_CALLTYPE releaseResources() | |||
| { | |||
| } | |||
| void JUCE_CALLTYPE processBlock (const AudioSampleBuffer& input, | |||
| AudioSampleBuffer&, | |||
| const bool accumulateOutput, | |||
| MidiBuffer& midiBuffer) | |||
| { | |||
| if (! accumulateOutput) | |||
| midiBuffer.clear(); | |||
| midiBuffer.addEvents (player->incomingMidi, 0, input.getNumSamples(), 0); | |||
| } | |||
| const String JUCE_CALLTYPE getInputChannelName (const int channelIndex) const | |||
| { | |||
| return String (channelIndex + 1); | |||
| } | |||
| const String JUCE_CALLTYPE getOutputChannelName (const int channelIndex) const | |||
| { | |||
| AudioIODevice* const dev = getAudioDevice(); | |||
| if (dev != 0) | |||
| return dev->getInputChannelNames() [channelIndex]; | |||
| return String (channelIndex + 1); | |||
| } | |||
| bool JUCE_CALLTYPE isInputChannelStereoPair (int) const | |||
| { | |||
| return true; | |||
| } | |||
| bool JUCE_CALLTYPE isOutputChannelStereoPair (int) const | |||
| { | |||
| return true; | |||
| } | |||
| }; | |||
| //============================================================================== | |||
| InternalPluginFormat::InternalPluginFormat() | |||
| { | |||
| { | |||
| AudioInputDeviceFilter f (2); | |||
| audioInDesc.fillInFromInstance (f); | |||
| } | |||
| { | |||
| AudioOutputDeviceFilter f (2); | |||
| audioOutDesc.fillInFromInstance (f); | |||
| } | |||
| { | |||
| MidiInputDeviceFilter f; | |||
| midiInDesc.fillInFromInstance (f); | |||
| } | |||
| } | |||
| AudioPluginInstance* InternalPluginFormat::createInstanceFromDescription (const PluginDescription& desc) | |||
| { | |||
| if (desc.name == audioOutDesc.name) | |||
| { | |||
| return new AudioOutputDeviceFilter (desc.numInputChannels); | |||
| } | |||
| else if (desc.name == audioInDesc.name) | |||
| { | |||
| return new AudioInputDeviceFilter (desc.numOutputChannels); | |||
| } | |||
| else if (desc.name == midiInDesc.name) | |||
| { | |||
| return new MidiInputDeviceFilter(); | |||
| } | |||
| return 0; | |||
| } | |||
| const PluginDescription* InternalPluginFormat::getDescriptionFor (const InternalFilterType type) | |||
| { | |||
| switch (type) | |||
| { | |||
| case audioInputFilter: | |||
| return &audioInDesc; | |||
| case audioOutputFilter: | |||
| return &audioOutDesc; | |||
| case midiInputFilter: | |||
| return &midiInDesc; | |||
| } | |||
| return 0; | |||
| } | |||
| void InternalPluginFormat::getAllTypes (OwnedArray <PluginDescription>& results) | |||
| { | |||
| for (int i = 0; i < (int) endOfFilterTypes; ++i) | |||
| results.add (new PluginDescription (*getDescriptionFor ((InternalFilterType) i))); | |||
| } | |||
| @@ -0,0 +1,80 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_MAINHOSTWINDOW_JUCEHEADER__xxxxx | |||
| #define __JUCE_MAINHOSTWINDOW_JUCEHEADER__xxxxx | |||
| #include "FilterGraph.h" | |||
| #include "../plugins/juce_AudioPluginFormat.h" | |||
| //============================================================================== | |||
| /** | |||
| Manages the internal plugin types. | |||
| */ | |||
| class InternalPluginFormat : public AudioPluginFormat | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| InternalPluginFormat(); | |||
| ~InternalPluginFormat() {} | |||
| //============================================================================== | |||
| enum InternalFilterType | |||
| { | |||
| audioInputFilter = 0, | |||
| audioOutputFilter, | |||
| midiInputFilter, | |||
| endOfFilterTypes | |||
| }; | |||
| const PluginDescription* getDescriptionFor (const InternalFilterType type); | |||
| void getAllTypes (OwnedArray <PluginDescription>& results); | |||
| //============================================================================== | |||
| const String getName() const { return "Internal"; } | |||
| bool fileMightContainThisPluginType (const File&) { return false; } | |||
| const FileSearchPath getDefaultLocationsToSearch() { return FileSearchPath(); } | |||
| void findAllTypesForFile (OwnedArray <PluginDescription>&, const File&) {} | |||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| PluginDescription audioInDesc; | |||
| PluginDescription audioOutDesc; | |||
| PluginDescription midiInDesc; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,484 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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.h" | |||
| #include "MainHostWindow.h" | |||
| #include "InternalFilters.h" | |||
| #include "../plugins/juce_PluginListComponent.h" | |||
| //============================================================================== | |||
| class PluginListWindow : public DocumentWindow | |||
| { | |||
| public: | |||
| PluginListWindow (KnownPluginList& knownPluginList) | |||
| : DocumentWindow ("Available Plugins", Colours::white, | |||
| DocumentWindow::minimiseButton | DocumentWindow::closeButton) | |||
| { | |||
| currentPluginListWindow = this; | |||
| const File deadMansPedalFile (ApplicationProperties::getInstance()->getUserSettings() | |||
| ->getFile().getSiblingFile ("RecentlyCrashedPluginsList")); | |||
| setContentComponent (new PluginListComponent (knownPluginList, | |||
| deadMansPedalFile, | |||
| ApplicationProperties::getInstance()->getUserSettings()), true, true); | |||
| setResizable (true, false); | |||
| setVisible (true); | |||
| setResizeLimits (300, 400, 800, 1500); | |||
| setTopLeftPosition (60, 60); | |||
| restoreWindowStateFromString (ApplicationProperties::getInstance()->getUserSettings()->getValue ("listWindowPos")); | |||
| } | |||
| ~PluginListWindow() | |||
| { | |||
| ApplicationProperties::getInstance()->getUserSettings()->setValue ("listWindowPos", getWindowStateAsString()); | |||
| setContentComponent (0); | |||
| jassert (currentPluginListWindow == this); | |||
| currentPluginListWindow = 0; | |||
| } | |||
| void closeButtonPressed() | |||
| { | |||
| delete this; | |||
| } | |||
| static PluginListWindow* currentPluginListWindow; | |||
| }; | |||
| PluginListWindow* PluginListWindow::currentPluginListWindow = 0; | |||
| //============================================================================== | |||
| MainHostWindow::MainHostWindow() | |||
| : DocumentWindow (JUCEApplication::getInstance()->getApplicationName(), Colours::lightgrey, | |||
| DocumentWindow::allButtons) | |||
| { | |||
| setResizable (true, false); | |||
| setResizeLimits (500, 400, 10000, 10000); | |||
| centreWithSize (800, 600); | |||
| setContentComponent (new GraphDocumentComponent (&deviceManager)); | |||
| restoreWindowStateFromString (ApplicationProperties::getInstance()->getUserSettings()->getValue ("mainWindowPos")); | |||
| #if JUCE_MAC | |||
| setMacMainMenu (this); | |||
| #else | |||
| setMenuBar (this); | |||
| #endif | |||
| setVisible (true); | |||
| InternalPluginFormat internalFormat; | |||
| internalFormat.getAllTypes (internalTypes); | |||
| XmlElement* const savedAudioState = ApplicationProperties::getInstance()->getUserSettings() | |||
| ->getXmlValue (T("audioDeviceState")); | |||
| deviceManager.initialise (256, 256, savedAudioState, true); | |||
| delete savedAudioState; | |||
| XmlElement* const savedPluginList = ApplicationProperties::getInstance() | |||
| ->getUserSettings() | |||
| ->getXmlValue (T("pluginList")); | |||
| if (savedPluginList != 0) | |||
| { | |||
| knownPluginList.recreateFromXml (*savedPluginList); | |||
| delete savedPluginList; | |||
| } | |||
| pluginSortMethod = (KnownPluginList::SortMethod) ApplicationProperties::getInstance()->getUserSettings() | |||
| ->getIntValue (T("pluginSortMethod"), KnownPluginList::sortByManufacturer); | |||
| knownPluginList.addChangeListener (this); | |||
| addKeyListener (commandManager->getKeyMappings()); | |||
| } | |||
| MainHostWindow::~MainHostWindow() | |||
| { | |||
| delete PluginListWindow::currentPluginListWindow; | |||
| #if JUCE_MAC | |||
| setMacMainMenu (0); | |||
| #else | |||
| setMenuBar (0); | |||
| #endif | |||
| knownPluginList.removeChangeListener (this); | |||
| ApplicationProperties::getInstance()->getUserSettings()->setValue ("mainWindowPos", getWindowStateAsString()); | |||
| setContentComponent (0); | |||
| } | |||
| void MainHostWindow::closeButtonPressed() | |||
| { | |||
| tryToQuitApplication(); | |||
| } | |||
| bool MainHostWindow::tryToQuitApplication() | |||
| { | |||
| if (getGraphEditor() != 0 | |||
| && getGraphEditor()->graph.saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk) | |||
| { | |||
| JUCEApplication::quit(); | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| void MainHostWindow::changeListenerCallback (void*) | |||
| { | |||
| menuItemsChanged(); | |||
| // save the plugin list every time it gets chnaged, so that if we're scanning | |||
| // and it crashes, we've still saved the previous ones | |||
| XmlElement* const savedPluginList = knownPluginList.createXml(); | |||
| if (savedPluginList != 0) | |||
| { | |||
| ApplicationProperties::getInstance()->getUserSettings() | |||
| ->setValue (T("pluginList"), savedPluginList); | |||
| delete savedPluginList; | |||
| ApplicationProperties::getInstance()->saveIfNeeded(); | |||
| } | |||
| } | |||
| const StringArray MainHostWindow::getMenuBarNames() | |||
| { | |||
| const tchar* const names[] = { T("File"), T("Plugins"), T("Options"), 0 }; | |||
| return StringArray ((const tchar**) names); | |||
| } | |||
| const PopupMenu MainHostWindow::getMenuForIndex (int topLevelMenuIndex, const String& /*menuName*/) | |||
| { | |||
| PopupMenu menu; | |||
| if (topLevelMenuIndex == 0) | |||
| { | |||
| // "File" menu | |||
| menu.addCommandItem (commandManager, CommandIDs::open); | |||
| RecentlyOpenedFilesList recentFiles; | |||
| recentFiles.restoreFromString (ApplicationProperties::getInstance()->getUserSettings() | |||
| ->getValue ("recentFilterGraphFiles")); | |||
| PopupMenu recentFilesMenu; | |||
| recentFiles.createPopupMenuItems (recentFilesMenu, 100, true, true); | |||
| menu.addSubMenu (T("Open recent file"), recentFilesMenu); | |||
| menu.addCommandItem (commandManager, CommandIDs::save); | |||
| menu.addCommandItem (commandManager, CommandIDs::saveAs); | |||
| menu.addSeparator(); | |||
| menu.addCommandItem (commandManager, StandardApplicationCommandIDs::quit); | |||
| } | |||
| else if (topLevelMenuIndex == 1) | |||
| { | |||
| // "Plugins" menu | |||
| PopupMenu pluginsMenu; | |||
| addPluginsToMenu (pluginsMenu); | |||
| menu.addSubMenu (T("Create plugin"), pluginsMenu); | |||
| menu.addSeparator(); | |||
| menu.addItem (250, T("Delete all plugins")); | |||
| } | |||
| else if (topLevelMenuIndex == 2) | |||
| { | |||
| // "Options" menu | |||
| menu.addCommandItem (commandManager, CommandIDs::showPluginListEditor); | |||
| PopupMenu sortTypeMenu; | |||
| sortTypeMenu.addItem (200, "List plugins in default order", true, pluginSortMethod == KnownPluginList::defaultOrder); | |||
| sortTypeMenu.addItem (201, "List plugins in alphabetical order", true, pluginSortMethod == KnownPluginList::sortAlphabetically); | |||
| sortTypeMenu.addItem (202, "List plugins by category", true, pluginSortMethod == KnownPluginList::sortByCategory); | |||
| sortTypeMenu.addItem (203, "List plugins by manufacturer", true, pluginSortMethod == KnownPluginList::sortByManufacturer); | |||
| menu.addSubMenu ("Plugin menu type", sortTypeMenu); | |||
| menu.addSeparator(); | |||
| menu.addCommandItem (commandManager, CommandIDs::showAudioSettings); | |||
| menu.addSeparator(); | |||
| menu.addCommandItem (commandManager, CommandIDs::aboutBox); | |||
| } | |||
| return menu; | |||
| } | |||
| void MainHostWindow::menuItemSelected (int menuItemID, int /*topLevelMenuIndex*/) | |||
| { | |||
| GraphDocumentComponent* const graphEditor = getGraphEditor(); | |||
| if (menuItemID == 250) | |||
| { | |||
| if (graphEditor != 0) | |||
| graphEditor->graph.clear(); | |||
| } | |||
| else if (menuItemID >= 100 && menuItemID < 200) | |||
| { | |||
| RecentlyOpenedFilesList recentFiles; | |||
| recentFiles.restoreFromString (ApplicationProperties::getInstance()->getUserSettings() | |||
| ->getValue ("recentFilterGraphFiles")); | |||
| if (graphEditor != 0 && graphEditor->graph.saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk) | |||
| graphEditor->graph.loadFrom (recentFiles.getFile (menuItemID - 100), true); | |||
| } | |||
| else if (menuItemID >= 200 && menuItemID < 210) | |||
| { | |||
| if (menuItemID == 200) | |||
| pluginSortMethod = KnownPluginList::defaultOrder; | |||
| else if (menuItemID == 201) | |||
| pluginSortMethod = KnownPluginList::sortAlphabetically; | |||
| else if (menuItemID == 202) | |||
| pluginSortMethod = KnownPluginList::sortByCategory; | |||
| else if (menuItemID == 203) | |||
| pluginSortMethod = KnownPluginList::sortByManufacturer; | |||
| ApplicationProperties::getInstance()->getUserSettings() | |||
| ->setValue (T("pluginSortMethod"), (int) pluginSortMethod); | |||
| } | |||
| else | |||
| { | |||
| createPlugin (getChosenType (menuItemID), | |||
| proportionOfWidth (0.3f + Random::getSystemRandom().nextFloat() * 0.6f), | |||
| proportionOfHeight (0.3f + Random::getSystemRandom().nextFloat() * 0.6f)); | |||
| } | |||
| } | |||
| void MainHostWindow::createPlugin (const PluginDescription* desc, int x, int y) | |||
| { | |||
| GraphDocumentComponent* const graphEditor = getGraphEditor(); | |||
| if (graphEditor != 0) | |||
| graphEditor->createNewPlugin (desc, x, y); | |||
| } | |||
| void MainHostWindow::addPluginsToMenu (PopupMenu& m) const | |||
| { | |||
| for (int i = 0; i < internalTypes.size(); ++i) | |||
| m.addItem (i + 1, internalTypes.getUnchecked(i)->name); | |||
| m.addSeparator(); | |||
| knownPluginList.addToMenu (m, pluginSortMethod); | |||
| } | |||
| const PluginDescription* MainHostWindow::getChosenType (const int menuID) const | |||
| { | |||
| if (menuID >= 1 && menuID < 1 + internalTypes.size()) | |||
| { | |||
| return internalTypes [menuID - 1]; | |||
| } | |||
| else | |||
| { | |||
| return knownPluginList.getType (knownPluginList.getIndexChosenByMenu (menuID)); | |||
| } | |||
| } | |||
| //============================================================================== | |||
| ApplicationCommandTarget* MainHostWindow::getNextCommandTarget() | |||
| { | |||
| return findFirstTargetParentComponent(); | |||
| } | |||
| void MainHostWindow::getAllCommands (Array <CommandID>& commands) | |||
| { | |||
| // this returns the set of all commands that this target can perform.. | |||
| const CommandID ids[] = { CommandIDs::open, | |||
| CommandIDs::save, | |||
| CommandIDs::saveAs, | |||
| CommandIDs::showPluginListEditor, | |||
| CommandIDs::showAudioSettings, | |||
| CommandIDs::aboutBox | |||
| }; | |||
| commands.addArray (ids, numElementsInArray (ids)); | |||
| } | |||
| void MainHostWindow::getCommandInfo (const CommandID commandID, ApplicationCommandInfo& result) | |||
| { | |||
| const String category ("General"); | |||
| switch (commandID) | |||
| { | |||
| case CommandIDs::open: | |||
| result.setInfo (T("Open..."), | |||
| T("Opens a filter graph file"), | |||
| category, 0); | |||
| result.defaultKeypresses.add (KeyPress (T('o'), ModifierKeys::commandModifier, 0)); | |||
| break; | |||
| case CommandIDs::save: | |||
| result.setInfo (T("Save"), | |||
| T("Saves the current graph to a file"), | |||
| category, 0); | |||
| result.defaultKeypresses.add (KeyPress (T('s'), ModifierKeys::commandModifier, 0)); | |||
| break; | |||
| case CommandIDs::saveAs: | |||
| result.setInfo (T("Save As..."), | |||
| T("Saves a copy of the current graph to a file"), | |||
| category, 0); | |||
| result.defaultKeypresses.add (KeyPress (T('s'), ModifierKeys::shiftModifier | ModifierKeys::commandModifier, 0)); | |||
| break; | |||
| case CommandIDs::showPluginListEditor: | |||
| result.setInfo ("Edit the list of available plug-Ins...", String::empty, category, 0); | |||
| result.addDefaultKeypress (T('p'), ModifierKeys::commandModifier); | |||
| break; | |||
| case CommandIDs::showAudioSettings: | |||
| result.setInfo ("Change the audio device settings", String::empty, category, 0); | |||
| result.addDefaultKeypress (T('a'), ModifierKeys::commandModifier); | |||
| break; | |||
| case CommandIDs::aboutBox: | |||
| result.setInfo ("About...", String::empty, category, 0); | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| } | |||
| bool MainHostWindow::perform (const InvocationInfo& info) | |||
| { | |||
| GraphDocumentComponent* const graphEditor = getGraphEditor(); | |||
| switch (info.commandID) | |||
| { | |||
| case CommandIDs::open: | |||
| if (graphEditor != 0 && graphEditor->graph.saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk) | |||
| graphEditor->graph.loadFromUserSpecifiedFile (true); | |||
| break; | |||
| case CommandIDs::save: | |||
| if (graphEditor != 0) | |||
| graphEditor->graph.save (true, true); | |||
| break; | |||
| case CommandIDs::saveAs: | |||
| if (graphEditor != 0) | |||
| graphEditor->graph.saveAs (File::nonexistent, true, true, true); | |||
| break; | |||
| case CommandIDs::showPluginListEditor: | |||
| if (PluginListWindow::currentPluginListWindow == 0) | |||
| PluginListWindow::currentPluginListWindow = new PluginListWindow (knownPluginList); | |||
| PluginListWindow::currentPluginListWindow->toFront (true); | |||
| break; | |||
| case CommandIDs::showAudioSettings: | |||
| showAudioSettings(); | |||
| break; | |||
| case CommandIDs::aboutBox: | |||
| { | |||
| /* AboutBoxComponent aboutComp; | |||
| DialogWindow::showModalDialog (T("About"), | |||
| &aboutComp, | |||
| this, Colours::white, | |||
| true, false, false); | |||
| */ } | |||
| break; | |||
| default: | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| void MainHostWindow::showAudioSettings() | |||
| { | |||
| AudioDeviceSelectorComponent audioSettingsComp (deviceManager, | |||
| 0, 2, | |||
| 0, 2, | |||
| false); | |||
| audioSettingsComp.setSize (500, 300); | |||
| DialogWindow::showModalDialog (T("Audio Settings"), | |||
| &audioSettingsComp, | |||
| this, | |||
| Colours::azure, | |||
| true); | |||
| XmlElement* const audioState = deviceManager.createStateXml(); | |||
| ApplicationProperties::getInstance()->getUserSettings() | |||
| ->setValue (T("audioSettings"), audioState); | |||
| ApplicationProperties::getInstance()->getUserSettings()->saveIfNeeded(); | |||
| delete audioState; | |||
| } | |||
| bool MainHostWindow::filesDropped (const StringArray& files, int x, int y) | |||
| { | |||
| if (files.size() == 1 && File (files[0]).hasFileExtension (filenameSuffix)) | |||
| { | |||
| GraphDocumentComponent* const graphEditor = getGraphEditor(); | |||
| if (graphEditor == 0) | |||
| return false; | |||
| return graphEditor->graph.saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk | |||
| && graphEditor->graph.loadFrom (File (files[0]), true); | |||
| } | |||
| OwnedArray <PluginDescription> typesFound; | |||
| knownPluginList.scanAndAddDragAndDroppedFiles (files, typesFound); | |||
| for (int i = 0; i < jmin (5, typesFound.size()); ++i) | |||
| createPlugin (typesFound.getUnchecked(i), x, y); | |||
| return typesFound.size() > 0; | |||
| } | |||
| GraphDocumentComponent* MainHostWindow::getGraphEditor() const | |||
| { | |||
| return dynamic_cast <GraphDocumentComponent*> (getContentComponent()); | |||
| } | |||
| @@ -0,0 +1,103 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_MAINHOSTWINDOW_JUCEHEADER__ | |||
| #define __JUCE_MAINHOSTWINDOW_JUCEHEADER__ | |||
| #include "FilterGraph.h" | |||
| #include "GraphEditorPanel.h" | |||
| #include "../plugins/juce_KnownPluginList.h" | |||
| //============================================================================== | |||
| namespace CommandIDs | |||
| { | |||
| static const int open = 0x30000; | |||
| static const int save = 0x30001; | |||
| static const int saveAs = 0x30002; | |||
| static const int showPluginListEditor = 0x30100; | |||
| static const int showAudioSettings = 0x30200; | |||
| static const int aboutBox = 0x30300; | |||
| } | |||
| extern ApplicationCommandManager* commandManager; | |||
| //============================================================================== | |||
| /** | |||
| */ | |||
| class MainHostWindow : public DocumentWindow, | |||
| public MenuBarModel, | |||
| public ApplicationCommandTarget, | |||
| public ChangeListener | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| MainHostWindow(); | |||
| ~MainHostWindow(); | |||
| //============================================================================== | |||
| void closeButtonPressed(); | |||
| void changeListenerCallback (void*); | |||
| bool filesDropped (const StringArray& filenames, int x, int y); | |||
| const StringArray getMenuBarNames(); | |||
| const PopupMenu getMenuForIndex (int topLevelMenuIndex, const String& menuName); | |||
| void menuItemSelected (int menuItemID, int topLevelMenuIndex); | |||
| ApplicationCommandTarget* getNextCommandTarget(); | |||
| void getAllCommands (Array <CommandID>& commands); | |||
| void getCommandInfo (const CommandID commandID, ApplicationCommandInfo& result); | |||
| bool perform (const InvocationInfo& info); | |||
| bool tryToQuitApplication(); | |||
| void createPlugin (const PluginDescription* desc, int x, int y); | |||
| void addPluginsToMenu (PopupMenu& m) const; | |||
| const PluginDescription* getChosenType (const int menuID) const; | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| AudioDeviceManager deviceManager; | |||
| OwnedArray <PluginDescription> internalTypes; | |||
| KnownPluginList knownPluginList; | |||
| KnownPluginList::SortMethod pluginSortMethod; | |||
| void showAudioSettings(); | |||
| GraphDocumentComponent* getGraphEditor() const; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,73 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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.h" | |||
| #include "juce_AudioPluginFormat.h" | |||
| #include "vst/juce_VSTPluginFormat.h" | |||
| //============================================================================== | |||
| AudioPluginFormatManager::AudioPluginFormatManager() throw() | |||
| { | |||
| } | |||
| AudioPluginFormatManager::~AudioPluginFormatManager() throw() | |||
| { | |||
| } | |||
| juce_ImplementSingleton_SingleThreaded (AudioPluginFormatManager); | |||
| //============================================================================== | |||
| void AudioPluginFormatManager::addDefaultFormats() | |||
| { | |||
| #ifdef JUCE_DEBUG | |||
| // you should only call this method once! | |||
| for (int i = formats.size(); --i >= 0;) | |||
| jassert (dynamic_cast <VSTPluginFormat*> (formats[i]) == 0); | |||
| #endif | |||
| formats.add (new VSTPluginFormat()); | |||
| } | |||
| int AudioPluginFormatManager::getNumFormats() throw() | |||
| { | |||
| return formats.size(); | |||
| } | |||
| AudioPluginFormat* AudioPluginFormatManager::getFormat (const int index) throw() | |||
| { | |||
| return formats [index]; | |||
| } | |||
| void AudioPluginFormatManager::addFormat (AudioPluginFormat* const format) throw() | |||
| { | |||
| formats.add (format); | |||
| } | |||
| @@ -0,0 +1,154 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_AUDIOPLUGINFORMAT_JUCEHEADER__ | |||
| #define __JUCE_AUDIOPLUGINFORMAT_JUCEHEADER__ | |||
| #include "juce_AudioPluginInstance.h" | |||
| class PluginDescription; | |||
| //============================================================================== | |||
| /** | |||
| The base class for a type of plugin format, such as VST, AudioUnit, LADSPA, etc. | |||
| Use the static getNumFormats() and getFormat() calls to find the types | |||
| of format that are available. | |||
| */ | |||
| class AudioPluginFormat | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** Destructor. */ | |||
| virtual ~AudioPluginFormat() {} | |||
| //============================================================================== | |||
| /** Returns the format name. | |||
| E.g. "VST", "AudioUnit", etc. | |||
| */ | |||
| virtual const String getName() const = 0; | |||
| /** This tries to create descriptions for all the plugin types available in | |||
| a binary module file. | |||
| The file will be some kind of DLL or bundle. | |||
| Normally there will only be one type returned, but some plugins | |||
| (e.g. VST shells) can use a single DLL to create a set of different plugin | |||
| subtypes, so in that case, each subtype is returned as a separate object. | |||
| */ | |||
| virtual void findAllTypesForFile (OwnedArray <PluginDescription>& results, | |||
| const File& file) = 0; | |||
| /** Tries to recreate a type from a previously generated PluginDescription. | |||
| @see PluginDescription::createInstance | |||
| */ | |||
| virtual AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc) = 0; | |||
| /** Should do a quick check to see if this file or directory might be a plugin of | |||
| this format. | |||
| This is for searching for potential files, so it shouldn't actually try to | |||
| load the plugin or do anything time-consuming. | |||
| */ | |||
| virtual bool fileMightContainThisPluginType (const File& file) = 0; | |||
| /** Returns the typical places to look for this kind of plugin. | |||
| Note that if this returns no paths, it means that the format can't be scanned-for | |||
| (i.e. it's an internal format that doesn't live in files) | |||
| */ | |||
| virtual const FileSearchPath getDefaultLocationsToSearch() = 0; | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| protected: | |||
| AudioPluginFormat() throw() {} | |||
| }; | |||
| //============================================================================== | |||
| /** | |||
| This simply maintains a list of known AudioPluginFormats. | |||
| @see AudioPluginFormat | |||
| */ | |||
| class AudioPluginFormatManager : public DeletedAtShutdown | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| AudioPluginFormatManager() throw(); | |||
| /** Destructor. */ | |||
| ~AudioPluginFormatManager() throw(); | |||
| juce_DeclareSingleton_SingleThreaded (AudioPluginFormatManager, false); | |||
| //============================================================================== | |||
| /** Adds any formats that it knows about, e.g. VST. | |||
| */ | |||
| void addDefaultFormats(); | |||
| //============================================================================== | |||
| /** Returns the number of types of format that are available. | |||
| Use getFormat() to get one of them. | |||
| */ | |||
| int getNumFormats() throw(); | |||
| /** Returns one of the available formats. | |||
| @see getNumFormats | |||
| */ | |||
| AudioPluginFormat* getFormat (const int index) throw(); | |||
| //============================================================================== | |||
| /** Adds a format to the list. | |||
| The object passed in will be owned and deleted by the manager. | |||
| */ | |||
| void addFormat (AudioPluginFormat* const format) throw(); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| OwnedArray <AudioPluginFormat> formats; | |||
| }; | |||
| #endif // __JUCE_AUDIOPLUGINFORMAT_JUCEHEADER__ | |||
| @@ -0,0 +1,82 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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. | |||
| ============================================================================== | |||
| */ | |||
| #define JUCE_PLUGIN_HOST 1 | |||
| //============================================================================== | |||
| // (Just a quick way of getting these files into the project) | |||
| #include "../../../audio plugins/wrapper/juce_AudioFilterBase.cpp" | |||
| #include "../../../audio plugins/wrapper/juce_AudioFilterEditor.cpp" | |||
| //============================================================================== | |||
| #include "juce_AudioPluginInstance.h" | |||
| //============================================================================== | |||
| bool JUCE_CALLTYPE AudioPluginInstance::getCurrentPositionInfo (AudioFilterBase::CurrentPositionInfo& info) | |||
| { | |||
| info.bpm = 120.0; | |||
| info.timeSigNumerator = 4; | |||
| info.timeSigDenominator = 4; | |||
| info.timeInSeconds = 0; | |||
| /** For timecode, the position of the start of the edit, in seconds from 00:00:00:00. */ | |||
| info.editOriginTime = 0; | |||
| /** The current play position in pulses-per-quarter-note. | |||
| This is the number of quarter notes since the edit start. | |||
| */ | |||
| info.ppqPosition = 0; | |||
| /** The position of the start of the last bar, in pulses-per-quarter-note. | |||
| This is the number of quarter notes from the start of the edit to the | |||
| start of the current bar. | |||
| Note - this value may be unavailable on some hosts, e.g. Pro-Tools. If | |||
| it's not available, the value will be 0. | |||
| */ | |||
| info.ppqPositionOfLastBarStart = 0; | |||
| info.frameRate = AudioFilterBase::CurrentPositionInfo::fpsUnknown; | |||
| info.isPlaying = false; | |||
| info.isRecording = false; | |||
| return true; | |||
| } | |||
| void JUCE_CALLTYPE AudioPluginInstance::informHostOfParameterChange (int /*index*/, float /*newValue*/) | |||
| { | |||
| } | |||
| @@ -0,0 +1,123 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_AUDIOPLUGININSTANCE_JUCEHEADER__ | |||
| #define __JUCE_AUDIOPLUGININSTANCE_JUCEHEADER__ | |||
| #include "../../../audio plugins/wrapper/juce_AudioFilterBase.h" | |||
| //============================================================================== | |||
| /** | |||
| Base class for an active instance of a plugin. | |||
| This derives from the same AudioFilterBase object that is used in the | |||
| plugin wrapper code, and most of its functionality is exposed by that interface, | |||
| with just a few extra methods here for using it from the host side. | |||
| @see AudioFilterBase, AudioPluginFormat | |||
| */ | |||
| class AudioPluginInstance : public AudioFilterBase, | |||
| private AudioFilterBase::FilterNativeCallbacks | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** Destructor. | |||
| Make sure that you delete any UI components that belong to this plugin before | |||
| deleting the plugin. | |||
| */ | |||
| virtual ~AudioPluginInstance() {} | |||
| //============================================================================== | |||
| /** Returns the plugin's name. */ | |||
| virtual const String getName() const = 0; | |||
| /** Asks the plugin to supply a manufacturer name. */ | |||
| virtual const String getManufacturer() const = 0; | |||
| /** Asks the plugin for its version number. */ | |||
| virtual const String getVersion() const = 0; | |||
| /** Returns true if the plugin is an instrument rather than an effect. */ | |||
| virtual bool isInstrument() const = 0; | |||
| /** Returns a category description for the plugin. | |||
| E.g. "Dynamics", "Reverbs", etc. | |||
| */ | |||
| virtual const String getCategory() const = 0; | |||
| /** Returns the class of plugin to which this belongs. | |||
| E.g. "VST", "AU", etc | |||
| */ | |||
| virtual const String getFormatName() const = 0; | |||
| /** Returns the binary file containing the plugin. | |||
| This is normally the DLL or bundle file. | |||
| */ | |||
| virtual const File getFile() const = 0; | |||
| /** Returns a unique identifier for the plugin. | |||
| (Note that this may not be unique across different plugin formats). | |||
| */ | |||
| virtual int getUID() const = 0; | |||
| //============================================================================== | |||
| /** Returns true if the plugin wants midi messages. */ | |||
| virtual bool acceptsMidi() const = 0; | |||
| /** Returns true if the plugin produces midi messages. */ | |||
| virtual bool producesMidi() const = 0; | |||
| /** Returns the plugin's latency. | |||
| This may not always be fixed, but should be correct just after the filter | |||
| has been prepared for playback. | |||
| */ | |||
| virtual int getSamplesLatency() const = 0; | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| protected: | |||
| AudioPluginInstance() {} | |||
| bool JUCE_CALLTYPE getCurrentPositionInfo (AudioFilterBase::CurrentPositionInfo& info); | |||
| void JUCE_CALLTYPE informHostOfParameterChange (int index, float newValue); | |||
| }; | |||
| #endif // __JUCE_AUDIOPLUGININSTANCE_JUCEHEADER__ | |||
| @@ -0,0 +1,314 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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.h" | |||
| #include "juce_KnownPluginList.h" | |||
| //============================================================================== | |||
| KnownPluginList::KnownPluginList() | |||
| { | |||
| } | |||
| KnownPluginList::~KnownPluginList() | |||
| { | |||
| } | |||
| void KnownPluginList::clear() | |||
| { | |||
| if (types.size() > 0) | |||
| { | |||
| types.clear(); | |||
| sendChangeMessage (this); | |||
| } | |||
| } | |||
| PluginDescription* KnownPluginList::getTypeForFile (const File& file) const throw() | |||
| { | |||
| for (int i = 0; i < types.size(); ++i) | |||
| if (types.getUnchecked(i)->file == file) | |||
| return types.getUnchecked(i); | |||
| return 0; | |||
| } | |||
| bool KnownPluginList::addType (const PluginDescription& type) | |||
| { | |||
| for (int i = types.size(); --i >= 0;) | |||
| { | |||
| if (types.getUnchecked(i)->isDuplicateOf (type)) | |||
| { | |||
| // strange - found a duplicate plugin with different info.. | |||
| jassert (types.getUnchecked(i)->name == type.name); | |||
| jassert (types.getUnchecked(i)->isInstrument == type.isInstrument); | |||
| *types.getUnchecked(i) = type; | |||
| return false; | |||
| } | |||
| } | |||
| types.add (new PluginDescription (type)); | |||
| sendChangeMessage (this); | |||
| return true; | |||
| } | |||
| void KnownPluginList::removeType (const int index) throw() | |||
| { | |||
| types.remove (index); | |||
| sendChangeMessage (this); | |||
| } | |||
| bool KnownPluginList::isListingUpToDate (const File& possiblePluginFile) const throw() | |||
| { | |||
| if (getTypeForFile (possiblePluginFile) == 0) | |||
| return false; | |||
| for (int i = types.size(); --i >= 0;) | |||
| { | |||
| const PluginDescription* const d = types.getUnchecked(i); | |||
| if (d->file == possiblePluginFile | |||
| && d->lastFileModTime != possiblePluginFile.getLastModificationTime()) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| bool KnownPluginList::scanAndAddFile (const File& possiblePluginFile, | |||
| const bool dontRescanIfAlreadyInList, | |||
| OwnedArray <PluginDescription>& typesFound) | |||
| { | |||
| bool addedOne = false; | |||
| if (dontRescanIfAlreadyInList | |||
| && getTypeForFile (possiblePluginFile) != 0) | |||
| { | |||
| bool needsRescanning = false; | |||
| for (int i = types.size(); --i >= 0;) | |||
| { | |||
| const PluginDescription* const d = types.getUnchecked(i); | |||
| if (d->file == possiblePluginFile | |||
| && d->lastFileModTime != possiblePluginFile.getLastModificationTime()) | |||
| { | |||
| needsRescanning = true; | |||
| } | |||
| else | |||
| { | |||
| typesFound.add (new PluginDescription (*d)); | |||
| } | |||
| } | |||
| if (! needsRescanning) | |||
| return false; | |||
| } | |||
| OwnedArray <PluginDescription> found; | |||
| for (int i = 0; i < AudioPluginFormatManager::getInstance()->getNumFormats(); ++i) | |||
| { | |||
| AudioPluginFormat* const format = AudioPluginFormatManager::getInstance()->getFormat (i); | |||
| format->findAllTypesForFile (found, possiblePluginFile); | |||
| for (int i = 0; i < found.size(); ++i) | |||
| { | |||
| PluginDescription* const desc = found.getUnchecked(i); | |||
| jassert (desc != 0); | |||
| if (addType (*desc)) | |||
| addedOne = true; | |||
| typesFound.add (new PluginDescription (*desc)); | |||
| } | |||
| } | |||
| return addedOne; | |||
| } | |||
| void KnownPluginList::scanAndAddDragAndDroppedFiles (const StringArray& files, | |||
| OwnedArray <PluginDescription>& typesFound) | |||
| { | |||
| for (int i = 0; i < files.size(); ++i) | |||
| { | |||
| const File f (files [i]); | |||
| if (! scanAndAddFile (f, false, typesFound)) | |||
| { | |||
| if (f.isDirectory()) | |||
| { | |||
| StringArray s; | |||
| { | |||
| OwnedArray <File> subFiles; | |||
| f.findChildFiles (subFiles, File::findFilesAndDirectories, false); | |||
| for (int j = 0; j < subFiles.size(); ++j) | |||
| s.add (subFiles.getUnchecked (j)->getFullPathName()); | |||
| } | |||
| scanAndAddDragAndDroppedFiles (s, typesFound); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| //============================================================================== | |||
| class PluginSorter | |||
| { | |||
| public: | |||
| KnownPluginList::SortMethod method; | |||
| PluginSorter() throw() {} | |||
| int compareElements (const PluginDescription* const first, | |||
| const PluginDescription* const second) const throw() | |||
| { | |||
| int diff = 0; | |||
| if (method == KnownPluginList::sortByCategory) | |||
| diff = first->category.compareLexicographically (second->category); | |||
| else if (method == KnownPluginList::sortByManufacturer) | |||
| diff = first->manufacturerName.compareLexicographically (second->manufacturerName); | |||
| if (diff == 0) | |||
| diff = first->name.compareLexicographically (second->name); | |||
| return diff; | |||
| } | |||
| }; | |||
| void KnownPluginList::sort (const SortMethod method) | |||
| { | |||
| if (method != defaultOrder) | |||
| { | |||
| PluginSorter sorter; | |||
| sorter.method = method; | |||
| types.sort (sorter, true); | |||
| sendChangeMessage (this); | |||
| } | |||
| } | |||
| //============================================================================== | |||
| XmlElement* KnownPluginList::createXml() const | |||
| { | |||
| XmlElement* const e = new XmlElement (T("KNOWNPLUGINS")); | |||
| for (int i = 0; i < types.size(); ++i) | |||
| e->addChildElement (types.getUnchecked(i)->createXml()); | |||
| return e; | |||
| } | |||
| void KnownPluginList::recreateFromXml (const XmlElement& xml) | |||
| { | |||
| clear(); | |||
| if (xml.hasTagName (T("KNOWNPLUGINS"))) | |||
| { | |||
| forEachXmlChildElement (xml, e) | |||
| { | |||
| PluginDescription info; | |||
| if (info.loadFromXml (*e)) | |||
| addType (info); | |||
| } | |||
| } | |||
| } | |||
| //============================================================================== | |||
| const int menuIdBase = 0x324503f4; | |||
| void KnownPluginList::addToMenu (PopupMenu& menu, const SortMethod sortMethod) const | |||
| { | |||
| Array <PluginDescription*> sorted; | |||
| { | |||
| PluginSorter sorter; | |||
| sorter.method = sortMethod; | |||
| for (int i = 0; i < types.size(); ++i) | |||
| sorted.addSorted (sorter, types.getUnchecked(i)); | |||
| } | |||
| if (sortMethod == sortByCategory | |||
| || sortMethod == KnownPluginList::sortByManufacturer) | |||
| { | |||
| String lastSubMenuName; | |||
| PopupMenu sub; | |||
| for (int i = 0; i < sorted.size(); ++i) | |||
| { | |||
| const PluginDescription* const pd = sorted.getUnchecked(i); | |||
| String thisSubMenuName (sortMethod == sortByCategory ? pd->category | |||
| : pd->manufacturerName); | |||
| if (thisSubMenuName.trim().isEmpty()) | |||
| thisSubMenuName = T("Other"); | |||
| if (thisSubMenuName != lastSubMenuName) | |||
| { | |||
| if (sub.getNumItems() > 0) | |||
| { | |||
| menu.addSubMenu (lastSubMenuName, sub); | |||
| sub.clear(); | |||
| } | |||
| lastSubMenuName = thisSubMenuName; | |||
| } | |||
| sub.addItem (types.indexOf (pd) + menuIdBase, pd->name, true, false); | |||
| } | |||
| if (sub.getNumItems() > 0) | |||
| menu.addSubMenu (lastSubMenuName, sub); | |||
| } | |||
| else | |||
| { | |||
| for (int i = 0; i < sorted.size(); ++i) | |||
| { | |||
| const PluginDescription* const pd = sorted.getUnchecked(i); | |||
| menu.addItem (types.indexOf (pd) + menuIdBase, pd->name, true, false); | |||
| } | |||
| } | |||
| } | |||
| int KnownPluginList::getIndexChosenByMenu (const int menuResultCode) const | |||
| { | |||
| const int i = menuResultCode - menuIdBase; | |||
| return (i >= 0 && i < types.size()) ? i : -1; | |||
| } | |||
| @@ -0,0 +1,163 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_KNOWNPLUGINLIST_JUCEHEADER__ | |||
| #define __JUCE_KNOWNPLUGINLIST_JUCEHEADER__ | |||
| #include "juce_PluginDescription.h" | |||
| #include "juce_AudioPluginFormat.h" | |||
| //============================================================================== | |||
| /** | |||
| Manages a list of plugin types. | |||
| This can be easily edited, saved and loaded, and used to create instances of | |||
| the plugin types in it. | |||
| @see PluginListComponent | |||
| */ | |||
| class KnownPluginList : public ChangeBroadcaster | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** Creates an empty list. | |||
| */ | |||
| KnownPluginList(); | |||
| /** Destructor. */ | |||
| ~KnownPluginList(); | |||
| //============================================================================== | |||
| /** Clears the list. */ | |||
| void clear(); | |||
| /** Returns the number of types currently in the list. | |||
| @see getType | |||
| */ | |||
| int getNumTypes() const throw() { return types.size(); } | |||
| /** Returns one of the types. | |||
| @see getNumTypes | |||
| */ | |||
| PluginDescription* getType (const int index) const throw() { return types [index]; } | |||
| /** Looks for a type in the list which comes from this file. | |||
| */ | |||
| PluginDescription* getTypeForFile (const File& file) const throw(); | |||
| /** Adds a type manually from its description. */ | |||
| bool addType (const PluginDescription& type); | |||
| /** Removes a type. */ | |||
| void removeType (const int index) throw(); | |||
| /** Looks for all types that can be loaded from a given file, and adds them | |||
| to the list. | |||
| If dontRescanIfAlreadyInList is true, then the file will only be loaded and | |||
| re-tested if it's not already in the list, or if the file's modification | |||
| time has changed since the list was created. If dontRescanIfAlreadyInList is | |||
| false, the file will always be reloaded and tested. | |||
| Returns true if any new types were added, and all the types found in this | |||
| file (even if it was already known and hasn't been re-scanned) get returned | |||
| in the array. | |||
| */ | |||
| bool scanAndAddFile (const File& possiblePluginFile, | |||
| const bool dontRescanIfAlreadyInList, | |||
| OwnedArray <PluginDescription>& typesFound); | |||
| /** Returns true if the specified file is already known about and if it | |||
| hasn't been modified since our entry was created. | |||
| */ | |||
| bool isListingUpToDate (const File& possiblePluginFile) const throw(); | |||
| /** Scans and adds a bunch of files that might have been dragged-and-dropped. | |||
| If any types are found in the files, their descriptions are returned in the array. | |||
| */ | |||
| void scanAndAddDragAndDroppedFiles (const StringArray& filenames, | |||
| OwnedArray <PluginDescription>& typesFound); | |||
| //============================================================================== | |||
| /** Sort methods used to change the order of the plugins in the list. | |||
| */ | |||
| enum SortMethod | |||
| { | |||
| defaultOrder = 0, | |||
| sortAlphabetically, | |||
| sortByCategory, | |||
| sortByManufacturer | |||
| }; | |||
| //============================================================================== | |||
| /** Adds all the plugin types to a popup menu so that the user can select one. | |||
| Depending on the sort method, it may add sub-menus for categories, | |||
| manufacturers, etc. | |||
| Use getIndexChosenByMenu() to find out the type that was chosen. | |||
| */ | |||
| void addToMenu (PopupMenu& menu, | |||
| const SortMethod sortMethod) const; | |||
| /** Converts a menu item index that has been chosen into its index in this list. | |||
| Returns -1 if it's not an ID that was used. | |||
| @see addToMenu | |||
| */ | |||
| int getIndexChosenByMenu (const int menuResultCode) const; | |||
| //============================================================================== | |||
| /** Sorts the list. */ | |||
| void sort (const SortMethod method); | |||
| //============================================================================== | |||
| /** Creates some XML that can be used to store the state of this list. | |||
| */ | |||
| XmlElement* createXml() const; | |||
| /** Recreates the state of this list from its stored XML format. | |||
| */ | |||
| void recreateFromXml (const XmlElement& xml); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| OwnedArray <PluginDescription> types; | |||
| }; | |||
| #endif // __JUCE_KNOWNPLUGINLIST_JUCEHEADER__ | |||
| @@ -0,0 +1,158 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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.h" | |||
| #include "juce_PluginDescription.h" | |||
| #include "juce_AudioPluginFormat.h" | |||
| //============================================================================== | |||
| PluginDescription::PluginDescription() throw() | |||
| : uid (0), | |||
| isInstrument (false), | |||
| numInputChannels (0), | |||
| numOutputChannels (0) | |||
| { | |||
| } | |||
| PluginDescription::~PluginDescription() throw() | |||
| { | |||
| } | |||
| PluginDescription::PluginDescription (const PluginDescription& other) throw() | |||
| : name (other.name), | |||
| pluginFormatName (other.pluginFormatName), | |||
| category (other.category), | |||
| manufacturerName (other.manufacturerName), | |||
| version (other.version), | |||
| file (other.file), | |||
| uid (other.uid), | |||
| isInstrument (other.isInstrument), | |||
| lastFileModTime (other.lastFileModTime), | |||
| numInputChannels (other.numInputChannels), | |||
| numOutputChannels (other.numOutputChannels) | |||
| { | |||
| } | |||
| const PluginDescription& PluginDescription::operator= (const PluginDescription& other) throw() | |||
| { | |||
| name = other.name; | |||
| pluginFormatName = other.pluginFormatName; | |||
| category = other.category; | |||
| manufacturerName = other.manufacturerName; | |||
| version = other.version; | |||
| file = other.file; | |||
| uid = other.uid; | |||
| isInstrument = other.isInstrument; | |||
| lastFileModTime = other.lastFileModTime; | |||
| numInputChannels = other.numInputChannels; | |||
| numOutputChannels = other.numOutputChannels; | |||
| return *this; | |||
| } | |||
| bool PluginDescription::isDuplicateOf (const PluginDescription& other) const | |||
| { | |||
| return file == other.file | |||
| && uid == other.uid; | |||
| } | |||
| void PluginDescription::fillInFromInstance (AudioPluginInstance& instance) throw() | |||
| { | |||
| name = instance.getName(); | |||
| file = instance.getFile(); | |||
| uid = instance.getUID(); | |||
| lastFileModTime = file.getLastModificationTime(); | |||
| pluginFormatName = instance.getFormatName(); | |||
| category = instance.getCategory(); | |||
| manufacturerName = instance.getManufacturer(); | |||
| version = instance.getVersion(); | |||
| numInputChannels = instance.getNumInputChannels(); | |||
| numOutputChannels = instance.getNumOutputChannels(); | |||
| isInstrument = instance.isInstrument(); | |||
| } | |||
| AudioPluginInstance* PluginDescription::createInstance() const | |||
| { | |||
| AudioPluginInstance* result = 0; | |||
| for (int i = 0; i < AudioPluginFormatManager::getInstance()->getNumFormats(); ++i) | |||
| { | |||
| AudioPluginFormat* const format = AudioPluginFormatManager::getInstance()->getFormat (i); | |||
| result = format->createInstanceFromDescription (*this); | |||
| if (result != 0) | |||
| break; | |||
| } | |||
| return result; | |||
| } | |||
| XmlElement* PluginDescription::createXml() const | |||
| { | |||
| XmlElement* const e = new XmlElement (T("PLUGIN")); | |||
| e->setAttribute (T("name"), name); | |||
| e->setAttribute (T("format"), pluginFormatName); | |||
| e->setAttribute (T("category"), category); | |||
| e->setAttribute (T("manufacturer"), manufacturerName); | |||
| e->setAttribute (T("version"), version); | |||
| e->setAttribute (T("file"), file.getFullPathName()); | |||
| e->setAttribute (T("uid"), String::toHexString (uid)); | |||
| e->setAttribute (T("isInstrument"), isInstrument); | |||
| e->setAttribute (T("fileTime"), String::toHexString (lastFileModTime.toMilliseconds())); | |||
| e->setAttribute (T("numInputs"), numInputChannels); | |||
| e->setAttribute (T("numOutputs"), numOutputChannels); | |||
| return e; | |||
| } | |||
| bool PluginDescription::loadFromXml (const XmlElement& xml) | |||
| { | |||
| if (xml.hasTagName (T("PLUGIN"))) | |||
| { | |||
| name = xml.getStringAttribute (T("name")); | |||
| pluginFormatName = xml.getStringAttribute (T("format")); | |||
| category = xml.getStringAttribute (T("category")); | |||
| manufacturerName = xml.getStringAttribute (T("manufacturer")); | |||
| version = xml.getStringAttribute (T("version")); | |||
| file = File (xml.getStringAttribute (T("file"))); | |||
| uid = xml.getStringAttribute (T("uid")).getHexValue32(); | |||
| isInstrument = xml.getBoolAttribute (T("isInstrument"), false); | |||
| lastFileModTime = Time (xml.getStringAttribute (T("fileTime")).getHexValue64()); | |||
| numInputChannels = xml.getIntAttribute (T("numInputs")); | |||
| numOutputChannels = xml.getIntAttribute (T("numOutputs")); | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| @@ -0,0 +1,144 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_PLUGINDESCRIPTION_JUCEHEADER__ | |||
| #define __JUCE_PLUGINDESCRIPTION_JUCEHEADER__ | |||
| #include "juce_AudioPluginInstance.h" | |||
| //============================================================================== | |||
| /** | |||
| A small class to represent some facts about a particular type of plugin. | |||
| This class is for storing and managing the details about a plugin without | |||
| actually having to load an instance of it. | |||
| A KnownPluginList contains a list of PluginDescription objects. | |||
| @see KnownPluginList | |||
| */ | |||
| class PluginDescription | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| PluginDescription() throw(); | |||
| PluginDescription (const PluginDescription& other) throw(); | |||
| const PluginDescription& operator= (const PluginDescription& other) throw(); | |||
| ~PluginDescription() throw(); | |||
| //============================================================================== | |||
| /** The name of the plugin. */ | |||
| String name; | |||
| /** The plugin format, e.g. "VST", "AudioUnit", etc. | |||
| */ | |||
| String pluginFormatName; | |||
| /** A category, such as "Dynamics", "Reverbs", etc. | |||
| */ | |||
| String category; | |||
| /** The manufacturer. */ | |||
| String manufacturerName; | |||
| /** The version. This string doesn't have any particular format. */ | |||
| String version; | |||
| /** The binary module file containing the plugin. */ | |||
| File file; | |||
| /** The last time the plugin file was changed. | |||
| This is handy when scanning for new or changed plugins. | |||
| */ | |||
| Time lastFileModTime; | |||
| /** A unique ID for the plugin. | |||
| Note that this might not be unique between formats, e.g. a VST and some | |||
| other format might actually have the same id. | |||
| */ | |||
| int uid; | |||
| /** True if the plugin identifies itself as a synthesiser. */ | |||
| bool isInstrument; | |||
| /** The number of inputs. */ | |||
| int numInputChannels; | |||
| /** The number of outputs. */ | |||
| int numOutputChannels; | |||
| /** Returns true if the two descriptions refer the the same plugin. | |||
| This isn't quite as simple as them just having the same file (because of | |||
| shell plugins). | |||
| */ | |||
| bool isDuplicateOf (const PluginDescription& other) const; | |||
| //============================================================================== | |||
| /** Fills in this description based on the given plugin. | |||
| Returns true if it worked, false if it couldn't get the info. | |||
| */ | |||
| void fillInFromInstance (AudioPluginInstance& instance) throw(); | |||
| //============================================================================== | |||
| /** Tries to load the type for this description, by trying all the formats | |||
| available in the AudioPluginFormat. | |||
| The caller is responsible for deleting the object that is returned. | |||
| Returns 0 if it can't load the plugin for some reason. | |||
| */ | |||
| AudioPluginInstance* createInstance() const; | |||
| //============================================================================== | |||
| /** Creates an XML object containing these details. | |||
| @see loadFromXml | |||
| */ | |||
| XmlElement* createXml() const; | |||
| /** Reloads the info in this structure from an XML record that was previously | |||
| saved with createXML(). | |||
| Returns true if the XML was a valid plugin description. | |||
| */ | |||
| bool loadFromXml (const XmlElement& xml); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| }; | |||
| #endif // __JUCE_PLUGINDESCRIPTION_JUCEHEADER__ | |||
| @@ -0,0 +1,148 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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.h" | |||
| #include "juce_PluginDirectoryScanner.h" | |||
| #include "juce_AudioPluginFormat.h" | |||
| //============================================================================== | |||
| PluginDirectoryScanner::PluginDirectoryScanner (KnownPluginList& listToAddTo, | |||
| FileSearchPath directoriesToSearch, | |||
| const bool recursive, | |||
| const File& deadMansPedalFile_) | |||
| : list (listToAddTo), | |||
| deadMansPedalFile (deadMansPedalFile_), | |||
| nextIndex (0), | |||
| progress (0) | |||
| { | |||
| directoriesToSearch.removeRedundantPaths(); | |||
| for (int j = 0; j < directoriesToSearch.getNumPaths(); ++j) | |||
| { | |||
| DirectoryIterator iter (directoriesToSearch[j], recursive, "*", File::findFilesAndDirectories); | |||
| while (iter.next()) | |||
| { | |||
| const File f (iter.getFile()); | |||
| for (int i = 0; i < AudioPluginFormatManager::getInstance()->getNumFormats(); ++i) | |||
| { | |||
| AudioPluginFormat* const format = AudioPluginFormatManager::getInstance()->getFormat (i); | |||
| if (format->fileMightContainThisPluginType (f)) | |||
| { | |||
| filesToScan.add (new File (f)); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // If any plugins have crashed recently when being loaded, move them to the | |||
| // end of the list to give the others a chance to load correctly.. | |||
| const StringArray crashedPlugins (getDeadMansPedalFile()); | |||
| for (int i = 0; i < crashedPlugins.size(); ++i) | |||
| { | |||
| const File f (crashedPlugins[i]); | |||
| for (int j = filesToScan.size(); --j >= 0;) | |||
| if (f == *filesToScan.getUnchecked (j)) | |||
| filesToScan.move (j, -1); | |||
| } | |||
| } | |||
| PluginDirectoryScanner::~PluginDirectoryScanner() | |||
| { | |||
| } | |||
| //============================================================================== | |||
| const File PluginDirectoryScanner::getNextPluginFileThatWillBeScanned() const throw() | |||
| { | |||
| File* const file = filesToScan [nextIndex]; | |||
| if (file != 0) | |||
| return *file; | |||
| return File::nonexistent; | |||
| } | |||
| bool PluginDirectoryScanner::scanNextFile (const bool dontRescanIfAlreadyInList) | |||
| { | |||
| File* const file = filesToScan [nextIndex]; | |||
| if (file != 0) | |||
| { | |||
| if (! list.isListingUpToDate (*file)) | |||
| { | |||
| OwnedArray <PluginDescription> typesFound; | |||
| // Add this plugin to the end of the dead-man's pedal list in case it crashes... | |||
| StringArray crashedPlugins (getDeadMansPedalFile()); | |||
| crashedPlugins.removeString (file->getFullPathName()); | |||
| crashedPlugins.add (file->getFullPathName()); | |||
| setDeadMansPedalFile (crashedPlugins); | |||
| list.scanAndAddFile (*file, | |||
| dontRescanIfAlreadyInList, | |||
| typesFound); | |||
| // Managed to load without crashing, so remove it from the dead-man's-pedal.. | |||
| crashedPlugins.removeString (file->getFullPathName()); | |||
| setDeadMansPedalFile (crashedPlugins); | |||
| } | |||
| ++nextIndex; | |||
| progress = nextIndex / (float) filesToScan.size(); | |||
| } | |||
| return nextIndex < filesToScan.size(); | |||
| } | |||
| const StringArray PluginDirectoryScanner::getDeadMansPedalFile() throw() | |||
| { | |||
| StringArray lines; | |||
| if (deadMansPedalFile != File::nonexistent) | |||
| { | |||
| lines.addLines (deadMansPedalFile.loadFileAsString()); | |||
| lines.removeEmptyStrings(); | |||
| } | |||
| return lines; | |||
| } | |||
| void PluginDirectoryScanner::setDeadMansPedalFile (const StringArray& newContents) throw() | |||
| { | |||
| if (deadMansPedalFile != File::nonexistent) | |||
| deadMansPedalFile.replaceWithText (newContents.joinIntoString ("\n"), true, true); | |||
| } | |||
| @@ -0,0 +1,116 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_PLUGINDIRECTORYSCANNER_JUCEHEADER__ | |||
| #define __JUCE_PLUGINDIRECTORYSCANNER_JUCEHEADER__ | |||
| #include "juce_KnownPluginList.h" | |||
| //============================================================================== | |||
| /** | |||
| Scans a directory for plugins, and adds them to a KnownPluginList. | |||
| To use one of these, create it and call scanNextFile() repeatedly, until | |||
| it returns false. | |||
| */ | |||
| class PluginDirectoryScanner | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** | |||
| Creates a scanner. | |||
| @param listToAddResultsTo this will get the new types added to it. | |||
| @param directoriesToSearch the path to search | |||
| @param searchRecursively true to search recursively | |||
| @param deadMansPedalFile if this isn't File::nonexistent, then it will | |||
| be used as a file to store the names of any plugins | |||
| that crash during initialisation. If there are | |||
| any plugins listed in it, then these will always | |||
| be scanned after all other possible files have | |||
| been tried - in this way, even if there's a few | |||
| dodgy plugins in your path, then a couple of rescans | |||
| will still manage to find all the proper plugins. | |||
| It's probably best to choose a file in the user's | |||
| application data directory (alongside your app's | |||
| settings file) for this. The file format it uses | |||
| is just a list of filenames of the modules that | |||
| failed. | |||
| */ | |||
| PluginDirectoryScanner (KnownPluginList& listToAddResultsTo, | |||
| FileSearchPath directoriesToSearch, | |||
| const bool searchRecursively, | |||
| const File& deadMansPedalFile); | |||
| /** Destructor. */ | |||
| ~PluginDirectoryScanner(); | |||
| //============================================================================== | |||
| /** Tries the next likely-looking file. | |||
| If dontRescanIfAlreadyInList is true, then the file will only be loaded and | |||
| re-tested if it's not already in the list, or if the file's modification | |||
| time has changed since the list was created. If dontRescanIfAlreadyInList is | |||
| false, the file will always be reloaded and tested. | |||
| Returns false when there are no more files to try. | |||
| */ | |||
| bool scanNextFile (const bool dontRescanIfAlreadyInList); | |||
| /** Returns the file that will be scanned during the next call to scanNextFile(). | |||
| This is handy if you want to show the user which file is currently getting | |||
| scanned. | |||
| */ | |||
| const File getNextPluginFileThatWillBeScanned() const throw(); | |||
| /** Returns the estimated progress, between 0 and 1. | |||
| */ | |||
| float getProgress() const { return progress; } | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| KnownPluginList& list; | |||
| OwnedArray <File> filesToScan; | |||
| File deadMansPedalFile; | |||
| int nextIndex; | |||
| float progress; | |||
| const StringArray getDeadMansPedalFile() throw(); | |||
| void setDeadMansPedalFile (const StringArray& newContents) throw(); | |||
| }; | |||
| #endif // __JUCE_PLUGINDIRECTORYSCANNER_JUCEHEADER__ | |||
| @@ -0,0 +1,261 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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.h" | |||
| #include "juce_PluginListComponent.h" | |||
| #include "juce_PluginDirectoryScanner.h" | |||
| //============================================================================== | |||
| PluginListComponent::PluginListComponent (KnownPluginList& listToEdit, | |||
| const File& deadMansPedalFile_, | |||
| PropertiesFile* const propertiesToUse_) | |||
| : list (listToEdit), | |||
| deadMansPedalFile (deadMansPedalFile_), | |||
| propertiesToUse (propertiesToUse_) | |||
| { | |||
| addAndMakeVisible (listBox = new ListBox (String::empty, this)); | |||
| addAndMakeVisible (optionsButton = new TextButton ("Options...")); | |||
| optionsButton->addButtonListener (this); | |||
| optionsButton->setTriggeredOnMouseDown (true); | |||
| setSize (400, 600); | |||
| list.addChangeListener (this); | |||
| } | |||
| PluginListComponent::~PluginListComponent() | |||
| { | |||
| list.removeChangeListener (this); | |||
| deleteAllChildren(); | |||
| } | |||
| void PluginListComponent::resized() | |||
| { | |||
| listBox->setBounds (0, 0, getWidth(), getHeight() - 30); | |||
| optionsButton->changeWidthToFitText (24); | |||
| optionsButton->setTopLeftPosition (8, getHeight() - 28); | |||
| } | |||
| void PluginListComponent::changeListenerCallback (void*) | |||
| { | |||
| listBox->updateContent(); | |||
| listBox->repaint(); | |||
| } | |||
| int PluginListComponent::getNumRows() | |||
| { | |||
| return list.getNumTypes(); | |||
| } | |||
| void PluginListComponent::paintListBoxItem (int row, | |||
| Graphics& g, | |||
| int width, int height, | |||
| bool rowIsSelected) | |||
| { | |||
| if (rowIsSelected) | |||
| g.fillAll (findColour (TextEditor::highlightColourId)); | |||
| const PluginDescription* const pd = list.getType (row); | |||
| if (pd != 0) | |||
| { | |||
| GlyphArrangement ga; | |||
| ga.addCurtailedLineOfText (Font (height * 0.7f, Font::bold), pd->name, 8.0f, height * 0.8f, width - 10.0f, true); | |||
| g.setColour (Colours::black); | |||
| ga.draw (g); | |||
| float x, y, r, b; | |||
| ga.getBoundingBox (0, -1, x, y, r, b, false); | |||
| String desc; | |||
| desc << pd->pluginFormatName | |||
| << (pd->isInstrument ? " instrument" : " effect") | |||
| << " - " | |||
| << pd->numInputChannels << (pd->numInputChannels == 1 ? " in" : " ins") | |||
| << " / " | |||
| << pd->numOutputChannels << (pd->numOutputChannels == 1 ? " out" : " outs"); | |||
| if (pd->manufacturerName.isNotEmpty()) | |||
| desc << " - " << pd->manufacturerName; | |||
| if (pd->version.isNotEmpty()) | |||
| desc << " - " << pd->version; | |||
| if (pd->category.isNotEmpty()) | |||
| desc << " - category: '" << pd->category << '\''; | |||
| g.setColour (Colours::grey); | |||
| ga.clear(); | |||
| ga.addCurtailedLineOfText (Font (height * 0.6f), desc, r + 10.0f, height * 0.8f, width - r - 12.0f, true); | |||
| ga.draw (g); | |||
| } | |||
| } | |||
| void PluginListComponent::deleteKeyPressed (int lastRowSelected) | |||
| { | |||
| list.removeType (lastRowSelected); | |||
| } | |||
| void PluginListComponent::buttonClicked (Button* b) | |||
| { | |||
| if (optionsButton == b) | |||
| { | |||
| PopupMenu menu; | |||
| menu.addItem (1, TRANS("Clear list")); | |||
| menu.addItem (5, TRANS("Remove selected plugin from list"), listBox->getNumSelectedRows() > 0); | |||
| menu.addItem (6, TRANS("Show folder containing selected plugin"), listBox->getNumSelectedRows() > 0); | |||
| menu.addSeparator(); | |||
| menu.addItem (2, TRANS("Sort alphabetically")); | |||
| menu.addItem (3, TRANS("Sort by category")); | |||
| menu.addItem (4, TRANS("Sort by manufacturer")); | |||
| menu.addSeparator(); | |||
| for (int i = 0; i < AudioPluginFormatManager::getInstance()->getNumFormats(); ++i) | |||
| { | |||
| AudioPluginFormat* const format = AudioPluginFormatManager::getInstance()->getFormat (i); | |||
| if (format->getDefaultLocationsToSearch().getNumPaths() > 0) | |||
| menu.addItem (10 + i, "Scan for new or updated " + format->getName() + " plugins..."); | |||
| } | |||
| const int r = menu.showAt (optionsButton); | |||
| if (r == 1) | |||
| { | |||
| list.clear(); | |||
| } | |||
| else if (r == 2) | |||
| { | |||
| list.sort (KnownPluginList::sortAlphabetically); | |||
| } | |||
| else if (r == 3) | |||
| { | |||
| list.sort (KnownPluginList::sortByCategory); | |||
| } | |||
| else if (r == 4) | |||
| { | |||
| list.sort (KnownPluginList::sortByManufacturer); | |||
| } | |||
| else if (r == 5) | |||
| { | |||
| const SparseSet <int> selected (listBox->getSelectedRows()); | |||
| for (int i = list.getNumTypes(); --i >= 0;) | |||
| if (selected.contains (i)) | |||
| list.removeType (i); | |||
| } | |||
| else if (r == 6) | |||
| { | |||
| const PluginDescription* const desc = list.getType (listBox->getSelectedRow()); | |||
| if (desc != 0) | |||
| desc->file.getParentDirectory().startAsProcess(); | |||
| } | |||
| else if (r != 0) | |||
| { | |||
| scanFor (AudioPluginFormatManager::getInstance()->getFormat (r - 10)); | |||
| } | |||
| } | |||
| } | |||
| bool PluginListComponent::filesDropped (const StringArray& files, int, int) | |||
| { | |||
| OwnedArray <PluginDescription> typesFound; | |||
| list.scanAndAddDragAndDroppedFiles (files, typesFound); | |||
| return typesFound.size() > 0; | |||
| } | |||
| void PluginListComponent::scanFor (AudioPluginFormat* format) | |||
| { | |||
| if (format == 0) | |||
| return; | |||
| FileSearchPath path (format->getDefaultLocationsToSearch()); | |||
| if (propertiesToUse != 0) | |||
| path = propertiesToUse->getValue ("lastPluginScanPath_" + format->getName(), path.toString()); | |||
| { | |||
| AlertWindow aw (TRANS("Select folders to scan..."), String::empty, AlertWindow::NoIcon); | |||
| FileSearchPathListComponent pathList; | |||
| pathList.setSize (500, 300); | |||
| pathList.setPath (path); | |||
| aw.addCustomComponent (&pathList); | |||
| aw.addButton (TRANS("Scan"), 1, KeyPress::returnKey); | |||
| aw.addButton (TRANS("Cancel"), 0, KeyPress (KeyPress::escapeKey)); | |||
| if (aw.runModalLoop() == 0) | |||
| return; | |||
| path = pathList.getPath(); | |||
| } | |||
| if (propertiesToUse != 0) | |||
| { | |||
| propertiesToUse->setValue ("lastPluginScanPath_" + format->getName(), path.toString()); | |||
| propertiesToUse->saveIfNeeded(); | |||
| } | |||
| double progress = 0.0; | |||
| AlertWindow aw (TRANS("Scanning for plugins..."), | |||
| TRANS("Searching for all possible plugin files..."), AlertWindow::NoIcon); | |||
| aw.addButton (TRANS("Cancel"), 0, KeyPress (KeyPress::escapeKey)); | |||
| aw.addProgressBarComponent (progress); | |||
| aw.enterModalState(); | |||
| MessageManager::getInstance()->dispatchPendingMessages(); | |||
| PluginDirectoryScanner scanner (list, path, true, deadMansPedalFile); | |||
| for (;;) | |||
| { | |||
| aw.setMessage (TRANS("Testing:\n\n") | |||
| + scanner.getNextPluginFileThatWillBeScanned().getFileName()); | |||
| MessageManager::getInstance()->dispatchPendingMessages (500); | |||
| if (! scanner.scanNextFile (true)) | |||
| break; | |||
| if (! aw.isCurrentlyModal()) | |||
| break; | |||
| progress = scanner.getProgress(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,95 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_PLUGINLISTCOMPONENT_JUCEHEADER__ | |||
| #define __JUCE_PLUGINLISTCOMPONENT_JUCEHEADER__ | |||
| #include "juce_KnownPluginList.h" | |||
| #include "juce_AudioPluginFormat.h" | |||
| //============================================================================== | |||
| /** | |||
| A component displaying a list of plugins, with options to scan for them, | |||
| add, remove and sort them. | |||
| */ | |||
| class PluginListComponent : public Component, | |||
| public ListBoxModel, | |||
| public ChangeListener, | |||
| public ButtonListener | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** | |||
| Creates the list component. | |||
| For info about the deadMansPedalFile, see the PluginDirectoryScanner constructor. | |||
| The properties file, if supplied is used to store the user's last search paths. | |||
| */ | |||
| PluginListComponent (KnownPluginList& listToRepresent, | |||
| const File& deadMansPedalFile, | |||
| PropertiesFile* const propertiesToUse); | |||
| /** Destructor. */ | |||
| ~PluginListComponent(); | |||
| //============================================================================== | |||
| /** @internal */ | |||
| void resized(); | |||
| /** @internal */ | |||
| bool filesDropped (const StringArray& files, int x, int y); | |||
| /** @internal */ | |||
| int getNumRows(); | |||
| /** @internal */ | |||
| void paintListBoxItem (int row, Graphics& g, int width, int height, bool rowIsSelected); | |||
| /** @internal */ | |||
| void deleteKeyPressed (int lastRowSelected); | |||
| /** @internal */ | |||
| void buttonClicked (Button* b); | |||
| /** @internal */ | |||
| void changeListenerCallback (void*); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| KnownPluginList& list; | |||
| File deadMansPedalFile; | |||
| ListBox* listBox; | |||
| TextButton* optionsButton; | |||
| PropertiesFile* propertiesToUse; | |||
| void scanFor (AudioPluginFormat* format); | |||
| }; | |||
| #endif // __JUCE_PLUGINLISTCOMPONENT_JUCEHEADER__ | |||
| @@ -0,0 +1,61 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_VSTPLUGINFORMAT_JUCEHEADER__ | |||
| #define __JUCE_VSTPLUGINFORMAT_JUCEHEADER__ | |||
| #include "../juce_AudioPluginFormat.h" | |||
| //============================================================================== | |||
| /** | |||
| Implements a plugin format manager for VSTs. | |||
| */ | |||
| class VSTPluginFormat : public AudioPluginFormat | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| VSTPluginFormat(); | |||
| ~VSTPluginFormat(); | |||
| //============================================================================== | |||
| const String getName() const { return "VST"; } | |||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const File& file); | |||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | |||
| bool fileMightContainThisPluginType (const File& file); | |||
| const FileSearchPath getDefaultLocationsToSearch(); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| }; | |||
| #endif // __JUCE_VSTPLUGINFORMAT_JUCEHEADER__ | |||
| @@ -0,0 +1,187 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_VSTFORMAT_JUCEHEADER__ | |||
| #define __JUCE_VSTFORMAT_JUCEHEADER__ | |||
| #include "juce_VSTPluginFormat.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. | |||
| */ | |||
| #include "pluginterfaces/vst2.x/aeffectx.h" | |||
| #ifdef _MSC_VER | |||
| #pragma warning (pop) | |||
| #endif | |||
| class ModuleHandle; | |||
| struct fxProgram; | |||
| //============================================================================== | |||
| /** | |||
| An instance of a plugin, created by a VSTPluginType. | |||
| */ | |||
| class VSTPluginInstance : public AudioPluginInstance, | |||
| private Timer, | |||
| private AsyncUpdater | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| ~VSTPluginInstance(); | |||
| //============================================================================== | |||
| // AudioPluginInstance methods: | |||
| const String getName() const; | |||
| const String getManufacturer() const; | |||
| const String getVersion() const; | |||
| bool isInstrument() const; | |||
| const String getCategory() const; | |||
| const String getFormatName() const; | |||
| const File getFile() const; | |||
| int getUID() const; | |||
| bool acceptsMidi() const; | |||
| bool producesMidi() const; | |||
| int getSamplesLatency() const; | |||
| //============================================================================== | |||
| // AudioFilterBase methods: | |||
| void JUCE_CALLTYPE prepareToPlay (double sampleRate, int estimatedSamplesPerBlock); | |||
| void JUCE_CALLTYPE releaseResources(); | |||
| void JUCE_CALLTYPE processBlock (const AudioSampleBuffer& input, | |||
| AudioSampleBuffer& output, | |||
| const bool accumulateOutput, | |||
| MidiBuffer& midiMessages); | |||
| AudioFilterEditor* JUCE_CALLTYPE createEditor(); | |||
| const String JUCE_CALLTYPE getInputChannelName (const int index) const; | |||
| bool JUCE_CALLTYPE isInputChannelStereoPair (int index) const; | |||
| const String JUCE_CALLTYPE getOutputChannelName (const int index) const; | |||
| bool JUCE_CALLTYPE isOutputChannelStereoPair (int index) const; | |||
| //============================================================================== | |||
| int JUCE_CALLTYPE getNumParameters(); | |||
| float JUCE_CALLTYPE getParameter (int index); | |||
| void JUCE_CALLTYPE setParameter (int index, float newValue); | |||
| const String JUCE_CALLTYPE getParameterName (int index); | |||
| const String JUCE_CALLTYPE getParameterText (int index); | |||
| bool isParameterAutomatable (int index) const; | |||
| //============================================================================== | |||
| int JUCE_CALLTYPE getNumPrograms(); | |||
| int JUCE_CALLTYPE getCurrentProgram(); | |||
| void JUCE_CALLTYPE setCurrentProgram (int index); | |||
| const String JUCE_CALLTYPE getProgramName (int index); | |||
| void JUCE_CALLTYPE changeProgramName (int index, const String& newName); | |||
| //============================================================================== | |||
| void JUCE_CALLTYPE getStateInformation (JUCE_NAMESPACE::MemoryBlock& destData); | |||
| void JUCE_CALLTYPE getCurrentProgramStateInformation (JUCE_NAMESPACE::MemoryBlock& destData); | |||
| void JUCE_CALLTYPE setStateInformation (const void* data, int sizeInBytes); | |||
| void JUCE_CALLTYPE 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 VSTPluginType; | |||
| friend class VSTPluginWindow; | |||
| friend class VSTPluginFormat; | |||
| AEffect* effect; | |||
| String name; | |||
| CriticalSection lock; | |||
| bool wantsMidiMessages, initialised, isPowerOn; | |||
| mutable StringArray programNames; | |||
| MidiMessageCollector midiCollector; | |||
| AudioSampleBuffer tempBuffer; | |||
| CriticalSection midiInLock; | |||
| MidiBuffer incomingMidi; | |||
| void* midiEventsToSend; | |||
| int numAllocatedMidiEvents; | |||
| VstTimeInfo vstHostTime; | |||
| float** channelsIn; | |||
| float** channelsOut; | |||
| ReferenceCountedObjectPtr <ModuleHandle> 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 (juce::MemoryBlock& dest); | |||
| void restoreFromTempParameterStore (const juce::MemoryBlock& mb); | |||
| const String getParameterLabel (int index) const; | |||
| bool usesChunks() const throw(); | |||
| void getChunkData (juce::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 (juce::MemoryBlock& dest, bool isFXB, int maxSizeMB); | |||
| int getVersionNumber() const throw(); | |||
| bool hasEditor() const throw(); | |||
| bool canMono() const throw(); | |||
| bool canReplace() const throw(); | |||
| bool isOffline() const throw(); | |||
| void setPower (const bool on); | |||
| VSTPluginInstance (const ReferenceCountedObjectPtr <ModuleHandle>& module); | |||
| }; | |||
| #endif // __JUCE_VSTFORMAT_JUCEHEADER__ | |||
| @@ -0,0 +1,55 @@ | |||
| project.name = "JucePluginDemo" | |||
| project.bindir = "build" | |||
| project.libdir = "build" | |||
| project.configs = { "Debug", "Release" } | |||
| package = newpackage() | |||
| package.name = "JucePluginDemo" | |||
| package.kind = "dll" | |||
| package.language = "c++" | |||
| package.objdir = "build/intermediate" | |||
| package.config["Debug"].objdir = "build/intermediate/Debug" | |||
| package.config["Release"].objdir = "build/intermediate/Release" | |||
| package.config["Debug"].defines = { "LINUX=1", "DEBUG=1", "_DEBUG=1" } | |||
| package.config["Debug"].buildoptions = { "-O0 -ggdb -g3 -Wall" } | |||
| package.config["Release"].defines = { "LINUX=1", "NDEBUG=1" } | |||
| package.config["Release"].buildoptions = { "-O2 -s" } | |||
| package.includepaths = { | |||
| "/usr/include", | |||
| "../../../../../", | |||
| "/usr/include/vst/source/common", | |||
| "/usr/include/vst", | |||
| "../../src" | |||
| } | |||
| package.libpaths = { | |||
| "../../../../../bin", | |||
| "/usr/X11R6/lib/", | |||
| "/usr/lib" | |||
| } | |||
| package.config["Debug"].links = { | |||
| "freetype", "pthread", "rt", "X11", "GL", "GLU", "Xinerama", "asound", "juce_debug" | |||
| } | |||
| package.config["Release"].links = { | |||
| "freetype", "pthread", "rt", "X11", "GL", "GLU", "Xinerama", "asound", "juce" | |||
| } | |||
| package.files = { | |||
| matchfiles ( | |||
| "../../../wrapper/*.h", | |||
| "../../../wrapper/*.cpp", | |||
| "../../../wrapper/formats/VST/*.cpp" | |||
| ), | |||
| matchrecursive ( | |||
| "../../src/*.h", | |||
| "../../src/*.cpp" | |||
| ) | |||
| } | |||
| @@ -811,6 +811,9 @@ protected: | |||
| void JUCE_CALLTYPE informHostOfParameterChange (int index, float newValue) | |||
| { | |||
| if (juceFilter != 0) | |||
| juceFilter->setParameter (index, newValue); | |||
| SetControlValue (index + 2, floatToLong (newValue)); | |||
| } | |||
| @@ -34,14 +34,14 @@ | |||
| //============================================================================== | |||
| AudioFilterBase::AudioFilterBase() | |||
| : suspended (false), | |||
| : sampleRate (0), | |||
| blockSize (0), | |||
| numInputChannels (0), | |||
| numOutputChannels (0), | |||
| suspended (false), | |||
| callbacks (0), | |||
| activeEditor (0) | |||
| { | |||
| sampleRate = 0.0; | |||
| blockSize = 0; | |||
| } | |||
| AudioFilterBase::~AudioFilterBase() | |||
| @@ -67,6 +67,11 @@ void AudioFilterBase::setParameterNotifyingHost (const int parameterIndex, | |||
| setParameter (parameterIndex, newValue); | |||
| } | |||
| bool AudioFilterBase::isParameterAutomatable (int /*index*/) const | |||
| { | |||
| return true; | |||
| } | |||
| void AudioFilterBase::suspendProcessing (const bool shouldBeSuspended) | |||
| { | |||
| const ScopedLock sl (callbackLock); | |||
| @@ -80,18 +85,6 @@ bool AudioFilterBase::getCurrentPositionInfo (CurrentPositionInfo& info) | |||
| && callbacks->getCurrentPositionInfo (info); | |||
| } | |||
| const String AudioFilterBase::getInputChannelName (const int channelIndex) const | |||
| { | |||
| String s (inputNames [channelIndex]); | |||
| return s.isNotEmpty() ? s : String (channelIndex + 1); | |||
| } | |||
| const String AudioFilterBase::getOutputChannelName (const int channelIndex) const | |||
| { | |||
| String s (outputNames [channelIndex]); | |||
| return s.isNotEmpty() ? s : String (channelIndex + 1); | |||
| } | |||
| //============================================================================== | |||
| void AudioFilterBase::editorBeingDeleted (AudioFilterEditor* const editor) | |||
| { | |||
| @@ -112,8 +105,10 @@ AudioFilterEditor* AudioFilterBase::createEditorIfNeeded() | |||
| if (ed != 0) | |||
| { | |||
| #if ! JUCE_PLUGIN_HOST | |||
| // you must give your editor comp a size before returning it.. | |||
| jassert (ed->getWidth() > 0 && ed->getHeight() > 0); | |||
| #endif | |||
| const ScopedLock sl (callbackLock); | |||
| activeEditor = ed; | |||
| @@ -207,6 +207,7 @@ public: | |||
| */ | |||
| bool JUCE_CALLTYPE getCurrentPositionInfo (CurrentPositionInfo& info); | |||
| //============================================================================== | |||
| /** Returns the current sample rate. | |||
| This can be called from your processBlock() method - it's not guaranteed | |||
| @@ -225,6 +226,7 @@ public: | |||
| */ | |||
| int JUCE_CALLTYPE getBlockSize() const throw() { return blockSize; } | |||
| //============================================================================== | |||
| /** Returns the number of input channels that the host will be sending the filter. | |||
| In your JucePluginCharacteristics.h file, you specify the number of channels | |||
| @@ -252,14 +254,20 @@ public: | |||
| The host might not supply very useful names for channels, and this might be | |||
| something like "1", "2", "left", "right", etc. | |||
| */ | |||
| const String getInputChannelName (const int channelIndex) const; | |||
| virtual const String JUCE_CALLTYPE getInputChannelName (const int channelIndex) const = 0; | |||
| /** Returns the name of one of the output channels, as returned by the host. | |||
| The host might not supply very useful names for channels, and this might be | |||
| something like "1", "2", "left", "right", etc. | |||
| */ | |||
| const String getOutputChannelName (const int channelIndex) const; | |||
| virtual const String JUCE_CALLTYPE getOutputChannelName (const int channelIndex) const = 0; | |||
| /** Returns true if the specified channel is part of a stereo pair with its neighbour. */ | |||
| virtual bool JUCE_CALLTYPE isInputChannelStereoPair (int index) const = 0; | |||
| /** Returns true if the specified channel is part of a stereo pair with its neighbour. */ | |||
| virtual bool JUCE_CALLTYPE isOutputChannelStereoPair (int index) const = 0; | |||
| //============================================================================== | |||
| /** This returns a critical section that will automatically be locked while the host | |||
| @@ -384,6 +392,12 @@ public: | |||
| void JUCE_CALLTYPE setParameterNotifyingHost (int parameterIndex, | |||
| float newValue); | |||
| /** Returns true if the host can automate this parameter. | |||
| By default, this returns true for all parameters. | |||
| */ | |||
| virtual bool isParameterAutomatable (int index) const; | |||
| //============================================================================== | |||
| /** Returns the number of preset programs the plugin supports. | |||
| @@ -507,6 +521,11 @@ protected: | |||
| static XmlElement* JUCE_CALLTYPE getXmlFromBinary (const void* data, | |||
| const int sizeInBytes); | |||
| /** @internal */ | |||
| double sampleRate; | |||
| /** @internal */ | |||
| int numInputChannels, numOutputChannels, blockSize; | |||
| private: | |||
| friend class JuceVSTWrapper; | |||
| friend class JuceAU; | |||
| @@ -517,9 +536,6 @@ private: | |||
| CriticalSection callbackLock; | |||
| bool suspended; | |||
| double sampleRate; | |||
| int blockSize, numInputChannels, numOutputChannels; | |||
| StringArray outputNames, inputNames; | |||
| FilterNativeCallbacks* callbacks; | |||
| @@ -54,7 +54,7 @@ namespace BinaryData | |||
| const int treeviewdemo_cppSize = 7534; | |||
| extern const char* widgetsdemo_cpp; | |||
| const int widgetsdemo_cppSize = 52997; | |||
| const int widgetsdemo_cppSize = 53000; | |||
| }; | |||
| @@ -175,8 +175,8 @@ class CustomMenuComponent : public PopupMenuCustomComponent, | |||
| public: | |||
| CustomMenuComponent() | |||
| blobX (0), | |||
| blobY (0) | |||
| : blobX (0), | |||
| blobY (0) | |||
| { | |||
| // set off a timer to move a blob around on this component every | |||
| // 300 milliseconds - see the timerCallback() method. | |||
| @@ -175,7 +175,7 @@ class CustomMenuComponent : public PopupMenuCustomComponent, | |||
| public: | |||
| CustomMenuComponent() | |||
| : blobX (0), | |||
| : blobX (0), | |||
| blobY (0) | |||
| { | |||
| // set off a timer to move a blob around on this component every | |||
| @@ -113,6 +113,7 @@ MainWindow::MainWindow() | |||
| } | |||
| addKeyListener (commandManager->getKeyMappings()); | |||
| commandManager->addListener (this); | |||
| // don't want the window to take focus when the title-bar is clicked.. | |||
| setWantsKeyboardFocus (false); | |||
| @@ -569,6 +569,9 @@ | |||
| #ifndef __JUCE_FILEPREVIEWCOMPONENT_JUCEHEADER__ | |||
| #include "juce_appframework/gui/components/filebrowser/juce_FilePreviewComponent.h" | |||
| #endif | |||
| #ifndef __JUCE_FILESEARCHPATHLISTCOMPONENT_JUCEHEADER__ | |||
| #include "juce_appframework/gui/components/filebrowser/juce_FileSearchPathListComponent.h" | |||
| #endif | |||
| #ifndef __JUCE_FILETREECOMPONENT_JUCEHEADER__ | |||
| #include "juce_appframework/gui/components/filebrowser/juce_FileTreeComponent.h" | |||
| #endif | |||
| @@ -256,7 +256,7 @@ FileBasedDocument::SaveResult FileBasedDocument::saveAsInteractive (const bool w | |||
| if (f.existsAsFile() || f.getParentDirectory().isDirectory()) | |||
| f = f.getSiblingFile (legalFilename); | |||
| else | |||
| f = File::getCurrentWorkingDirectory().getChildFile (legalFilename); | |||
| f = File::getSpecialLocation (File::userDocumentsDirectory).getChildFile (legalFilename); | |||
| f = f.withFileExtension (fileExtension) | |||
| .getNonexistentSibling (true); | |||
| @@ -267,8 +267,11 @@ FileBasedDocument::SaveResult FileBasedDocument::saveAsInteractive (const bool w | |||
| { | |||
| setLastDocumentOpened (fc.getResult()); | |||
| return saveAs (fc.getResult(), | |||
| false, false, true); | |||
| File chosen (fc.getResult()); | |||
| if (chosen.getFileExtension().isEmpty()) | |||
| chosen = chosen.withFileExtension (fileExtension); | |||
| return saveAs (f, false, false, true); | |||
| } | |||
| return userCancelledSave; | |||
| @@ -49,7 +49,7 @@ | |||
| void loadMooseFile() | |||
| { | |||
| FileChooser myChooser ("Please select the moose you want to load...", | |||
| File (SystemStats::getUserHomeDirectory()), | |||
| File::getSpecialLocation (File::userHomeDirectory), | |||
| "*.moose"); | |||
| if (myChooser.browseForFileToOpen()) | |||
| @@ -0,0 +1,279 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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_core/basics/juce_StandardHeader.h" | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "juce_FileSearchPathListComponent.h" | |||
| #include "../lookandfeel/juce_LookAndFeel.h" | |||
| #include "../filebrowser/juce_FileChooser.h" | |||
| #include "../../../../juce_core/text/juce_LocalisedStrings.h" | |||
| #include "../buttons/juce_TextButton.h" | |||
| #include "../buttons/juce_DrawableButton.h" | |||
| #include "../../graphics/drawables/juce_DrawablePath.h" | |||
| //============================================================================== | |||
| FileSearchPathListComponent::FileSearchPathListComponent() | |||
| { | |||
| addAndMakeVisible (listBox = new ListBox (String::empty, this)); | |||
| listBox->setColour (ListBox::backgroundColourId, Colours::black.withAlpha (0.02f)); | |||
| listBox->setColour (ListBox::outlineColourId, Colours::black.withAlpha (0.1f)); | |||
| listBox->setOutlineThickness (1); | |||
| addAndMakeVisible (addButton = new TextButton ("+")); | |||
| addButton->addButtonListener (this); | |||
| addButton->setConnectedEdges (Button::ConnectedOnLeft | Button::ConnectedOnRight | Button::ConnectedOnBottom | Button::ConnectedOnTop); | |||
| addAndMakeVisible (removeButton = new TextButton ("-")); | |||
| removeButton->addButtonListener (this); | |||
| removeButton->setConnectedEdges (Button::ConnectedOnLeft | Button::ConnectedOnRight | Button::ConnectedOnBottom | Button::ConnectedOnTop); | |||
| addAndMakeVisible (changeButton = new TextButton (TRANS("change..."))); | |||
| changeButton->addButtonListener (this); | |||
| addAndMakeVisible (upButton = new DrawableButton (String::empty, DrawableButton::ImageOnButtonBackground)); | |||
| upButton->addButtonListener (this); | |||
| { | |||
| Path arrowPath; | |||
| arrowPath.addArrow (50.0f, 100.0f, 50.0f, 0.0, 40.0f, 100.0f, 50.0f); | |||
| DrawablePath arrowImage; | |||
| arrowImage.setSolidFill (Colours::black.withAlpha (0.4f)); | |||
| arrowImage.setPath (arrowPath); | |||
| ((DrawableButton*) upButton)->setImages (&arrowImage); | |||
| } | |||
| addAndMakeVisible (downButton = new DrawableButton (String::empty, DrawableButton::ImageOnButtonBackground)); | |||
| downButton->addButtonListener (this); | |||
| { | |||
| Path arrowPath; | |||
| arrowPath.addArrow (50.0f, 0.0f, 50.0f, 100.0f, 40.0f, 100.0f, 50.0f); | |||
| DrawablePath arrowImage; | |||
| arrowImage.setSolidFill (Colours::black.withAlpha (0.4f)); | |||
| arrowImage.setPath (arrowPath); | |||
| ((DrawableButton*) downButton)->setImages (&arrowImage); | |||
| } | |||
| updateButtons(); | |||
| } | |||
| FileSearchPathListComponent::~FileSearchPathListComponent() | |||
| { | |||
| deleteAllChildren(); | |||
| } | |||
| void FileSearchPathListComponent::updateButtons() throw() | |||
| { | |||
| const bool anythingSelected = listBox->getNumSelectedRows() > 0; | |||
| removeButton->setEnabled (anythingSelected); | |||
| changeButton->setEnabled (anythingSelected); | |||
| upButton->setEnabled (anythingSelected); | |||
| downButton->setEnabled (anythingSelected); | |||
| } | |||
| void FileSearchPathListComponent::changed() throw() | |||
| { | |||
| listBox->updateContent(); | |||
| listBox->repaint(); | |||
| updateButtons(); | |||
| } | |||
| //============================================================================== | |||
| void FileSearchPathListComponent::setPath (const FileSearchPath& newPath) | |||
| { | |||
| if (newPath.toString() != path.toString()) | |||
| { | |||
| path = newPath; | |||
| changed(); | |||
| } | |||
| } | |||
| void FileSearchPathListComponent::setDefaultBrowseTarget (const File& newDefaultDirectory) throw() | |||
| { | |||
| defaultBrowseTarget = newDefaultDirectory; | |||
| } | |||
| //============================================================================== | |||
| int FileSearchPathListComponent::getNumRows() | |||
| { | |||
| return path.getNumPaths(); | |||
| } | |||
| void FileSearchPathListComponent::paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected) | |||
| { | |||
| if (rowIsSelected) | |||
| g.fillAll (findColour (TextEditor::highlightColourId)); | |||
| g.setColour (findColour (ListBox::textColourId)); | |||
| Font f (height * 0.7f); | |||
| f.setHorizontalScale (0.9f); | |||
| g.setFont (f); | |||
| g.drawText (path [rowNumber].getFullPathName(), | |||
| 4, 0, width - 6, height, | |||
| Justification::centredLeft, true); | |||
| } | |||
| void FileSearchPathListComponent::deleteKeyPressed (int row) | |||
| { | |||
| if (row >= 0 && row < path.getNumPaths()) | |||
| { | |||
| path.remove (row); | |||
| changed(); | |||
| } | |||
| } | |||
| void FileSearchPathListComponent::returnKeyPressed (int row) | |||
| { | |||
| FileChooser chooser (TRANS("Change folder..."), path [row], T("*")); | |||
| if (chooser.browseForDirectory()) | |||
| { | |||
| path.remove (row); | |||
| path.add (chooser.getResult(), row); | |||
| changed(); | |||
| } | |||
| } | |||
| void FileSearchPathListComponent::listBoxItemDoubleClicked (int row, const MouseEvent&) | |||
| { | |||
| returnKeyPressed (row); | |||
| } | |||
| void FileSearchPathListComponent::selectedRowsChanged (int) | |||
| { | |||
| updateButtons(); | |||
| } | |||
| void FileSearchPathListComponent::paint (Graphics& g) | |||
| { | |||
| g.fillAll (findColour (backgroundColourId)); | |||
| } | |||
| void FileSearchPathListComponent::resized() | |||
| { | |||
| const int buttonH = 22; | |||
| const int buttonY = getHeight() - buttonH - 4; | |||
| listBox->setBounds (2, 2, getWidth() - 4, buttonY - 5); | |||
| addButton->setBounds (2, buttonY, buttonH, buttonH); | |||
| removeButton->setBounds (addButton->getRight(), buttonY, buttonH, buttonH); | |||
| ((TextButton*) changeButton)->changeWidthToFitText (buttonH); | |||
| downButton->setSize (buttonH * 2, buttonH); | |||
| upButton->setSize (buttonH * 2, buttonH); | |||
| downButton->setTopRightPosition (getWidth() - 2, buttonY); | |||
| upButton->setTopRightPosition (downButton->getX() - 4, buttonY); | |||
| changeButton->setTopRightPosition (upButton->getX() - 8, buttonY); | |||
| } | |||
| bool FileSearchPathListComponent::filesDropped (const StringArray& filenames, int /*mouseX*/, int mouseY) | |||
| { | |||
| bool usedAny = false; | |||
| for (int i = filenames.size(); --i >= 0;) | |||
| { | |||
| const File f (filenames[i]); | |||
| if (f.isDirectory()) | |||
| { | |||
| const int row = listBox->getRowContainingPosition (0, mouseY - listBox->getY()); | |||
| path.add (f, row); | |||
| changed(); | |||
| usedAny = true; | |||
| } | |||
| } | |||
| return usedAny; | |||
| } | |||
| void FileSearchPathListComponent::buttonClicked (Button* button) | |||
| { | |||
| const int currentRow = listBox->getSelectedRow(); | |||
| if (button == removeButton) | |||
| { | |||
| deleteKeyPressed (currentRow); | |||
| } | |||
| else if (button == addButton) | |||
| { | |||
| File start (defaultBrowseTarget); | |||
| if (start == File::nonexistent) | |||
| start = path [0]; | |||
| if (start == File::nonexistent) | |||
| start = File::getCurrentWorkingDirectory(); | |||
| FileChooser chooser (TRANS("Add a folder..."), start, T("*")); | |||
| if (chooser.browseForDirectory()) | |||
| { | |||
| path.add (chooser.getResult(), currentRow); | |||
| } | |||
| } | |||
| else if (button == changeButton) | |||
| { | |||
| returnKeyPressed (currentRow); | |||
| } | |||
| else if (button == upButton) | |||
| { | |||
| if (currentRow > 0 && currentRow < path.getNumPaths()) | |||
| { | |||
| const File f (path[currentRow]); | |||
| path.remove (currentRow); | |||
| path.add (f, currentRow - 1); | |||
| listBox->selectRow (currentRow - 1); | |||
| } | |||
| } | |||
| else if (button == downButton) | |||
| { | |||
| if (currentRow >= 0 && currentRow < path.getNumPaths()-1) | |||
| { | |||
| const File f (path[currentRow]); | |||
| path.remove (currentRow); | |||
| path.add (f, currentRow + 1); | |||
| listBox->selectRow (currentRow + 1); | |||
| } | |||
| } | |||
| changed(); | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -0,0 +1,134 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_FILESEARCHPATHLISTCOMPONENT_JUCEHEADER__ | |||
| #define __JUCE_FILESEARCHPATHLISTCOMPONENT_JUCEHEADER__ | |||
| #include "../controls/juce_ListBox.h" | |||
| #include "../buttons/juce_Button.h" | |||
| #include "../../../../juce_core/io/files/juce_FileSearchPath.h" | |||
| //============================================================================== | |||
| /** | |||
| Shows a set of file paths in a list, allowing them to be added, removed or | |||
| re-ordered. | |||
| @see FileSearchPath | |||
| */ | |||
| class JUCE_API FileSearchPathListComponent : public Component, | |||
| public SettableTooltipClient, | |||
| private ButtonListener, | |||
| private ListBoxModel | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** Creates an empty FileSearchPathListComponent. | |||
| */ | |||
| FileSearchPathListComponent(); | |||
| /** Destructor. */ | |||
| ~FileSearchPathListComponent(); | |||
| //============================================================================== | |||
| /** Returns the path as it is currently shown. */ | |||
| const FileSearchPath& getPath() const throw() { return path; } | |||
| /** Changes the current path. */ | |||
| void setPath (const FileSearchPath& newPath); | |||
| /** Sets a file or directory to be the default starting point for the browser to show. | |||
| This is only used if the current file hasn't been set. | |||
| */ | |||
| void setDefaultBrowseTarget (const File& newDefaultDirectory) throw(); | |||
| /** A set of colour IDs to use to change the colour of various aspects of the label. | |||
| These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() | |||
| methods. | |||
| @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour | |||
| */ | |||
| enum ColourIds | |||
| { | |||
| backgroundColourId = 0x1004100, /**< The background colour to fill the component with. | |||
| Make this transparent if you don't want the background to be filled. */ | |||
| }; | |||
| //============================================================================== | |||
| /** @internal */ | |||
| int getNumRows(); | |||
| /** @internal */ | |||
| void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected); | |||
| /** @internal */ | |||
| void deleteKeyPressed (int lastRowSelected); | |||
| /** @internal */ | |||
| void returnKeyPressed (int lastRowSelected); | |||
| /** @internal */ | |||
| void listBoxItemDoubleClicked (int row, const MouseEvent&); | |||
| /** @internal */ | |||
| void selectedRowsChanged (int lastRowSelected); | |||
| /** @internal */ | |||
| void resized(); | |||
| /** @internal */ | |||
| void paint (Graphics& g); | |||
| /** @internal */ | |||
| bool filesDropped (const StringArray& filenames, int mouseX, int mouseY); | |||
| /** @internal */ | |||
| void buttonClicked (Button* button); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| //============================================================================== | |||
| FileSearchPath path; | |||
| File defaultBrowseTarget; | |||
| ListBox* listBox; | |||
| Button* addButton; | |||
| Button* removeButton; | |||
| Button* changeButton; | |||
| Button* upButton; | |||
| Button* downButton; | |||
| void changed() throw(); | |||
| void updateButtons() throw(); | |||
| FileSearchPathListComponent (const FileSearchPathListComponent&); | |||
| const FileSearchPathListComponent& operator= (const FileSearchPathListComponent&); | |||
| }; | |||
| #endif // __JUCE_FILESEARCHPATHLISTCOMPONENT_JUCEHEADER__ | |||
| @@ -56,6 +56,7 @@ BEGIN_JUCE_NAMESPACE | |||
| #include "../controls/juce_TreeView.h" | |||
| #include "../filebrowser/juce_FilenameComponent.h" | |||
| #include "../filebrowser/juce_DirectoryContentsDisplayComponent.h" | |||
| #include "../filebrowser/juce_FileSearchPathListComponent.h" | |||
| #include "../layout/juce_GroupComponent.h" | |||
| #include "../properties/juce_PropertyComponent.h" | |||
| #include "../juce_Desktop.h" | |||
| @@ -193,7 +194,9 @@ LookAndFeel::LookAndFeel() | |||
| MidiKeyboardComponent::upDownButtonArrowColourId, 0xff000000, | |||
| ColourSelector::backgroundColourId, 0xffe5e5e5, | |||
| ColourSelector::labelTextColourId, 0xff000000 | |||
| ColourSelector::labelTextColourId, 0xff000000, | |||
| FileSearchPathListComponent::backgroundColourId, 0xffffffff, | |||
| }; | |||
| for (int i = 0; i < numElementsInArray (standardColours); i += 2) | |||
| @@ -70,6 +70,7 @@ extern bool juce_makeOpenGLContextCurrent (void* context); | |||
| extern void juce_swapOpenGLBuffers (void* context); | |||
| extern void juce_updateOpenGLWindowPos (void* context, Component* owner, Component* topComp); | |||
| extern void juce_repaintOpenGLWindow (void* context); | |||
| extern bool juce_isActiveOpenGLContext (void* context) throw(); | |||
| static VoidArray activeGLWindows (2); | |||
| @@ -139,6 +140,11 @@ public: | |||
| return context != 0 && juce_makeOpenGLContextCurrent (context); | |||
| } | |||
| bool isActive() const throw() | |||
| { | |||
| return context != 0 && juce_isActiveOpenGLContext (context); | |||
| } | |||
| void swapBuffers() const | |||
| { | |||
| if (context != 0) | |||
| @@ -222,6 +228,26 @@ void OpenGLComponent::makeCurrentContextInactive() | |||
| juce_makeOpenGLContextCurrent (0); | |||
| } | |||
| bool OpenGLComponent::isActiveContext() const throw() | |||
| { | |||
| const InternalGLContextHolder* const context = (InternalGLContextHolder*) internalData; | |||
| return context != 0 && context->isActive(); | |||
| } | |||
| OpenGLComponent* OpenGLComponent::getCurrentlyActiveContextComponent() throw() | |||
| { | |||
| for (int i = activeGLWindows.size(); --i >= 0;) | |||
| { | |||
| OpenGLComponent* const component = (OpenGLComponent*) activeGLWindows.getUnchecked(i); | |||
| if (component->isActiveContext()) | |||
| return component; | |||
| } | |||
| return 0; | |||
| } | |||
| void OpenGLComponent::swapBuffers() | |||
| { | |||
| InternalGLContextHolder* const context = (InternalGLContextHolder*) internalData; | |||
| @@ -78,6 +78,17 @@ public: | |||
| */ | |||
| void makeCurrentContextInactive(); | |||
| /** Returns true if this component is the active openGL context for the | |||
| current thread. | |||
| */ | |||
| bool isActiveContext() const throw(); | |||
| /** Returns the OpenGLComponent that is currently the active context for | |||
| the current thread. | |||
| */ | |||
| static OpenGLComponent* getCurrentlyActiveContextComponent() throw(); | |||
| //============================================================================== | |||
| /** Flips the openGL buffers over. */ | |||
| void swapBuffers(); | |||