| @@ -321,6 +321,7 @@ OBJECTS := \ | |||||
| $(OBJDIR)/juce_FileFilter.o \ | $(OBJDIR)/juce_FileFilter.o \ | ||||
| $(OBJDIR)/juce_FileListComponent.o \ | $(OBJDIR)/juce_FileListComponent.o \ | ||||
| $(OBJDIR)/juce_FilenameComponent.o \ | $(OBJDIR)/juce_FilenameComponent.o \ | ||||
| $(OBJDIR)/juce_FileSearchPathListComponent.o \ | |||||
| $(OBJDIR)/juce_FileTreeComponent.o \ | $(OBJDIR)/juce_FileTreeComponent.o \ | ||||
| $(OBJDIR)/juce_ImagePreviewComponent.o \ | $(OBJDIR)/juce_ImagePreviewComponent.o \ | ||||
| $(OBJDIR)/juce_WildcardFileFilter.o \ | $(OBJDIR)/juce_WildcardFileFilter.o \ | ||||
| @@ -1859,6 +1860,11 @@ $(OBJDIR)/juce_FilenameComponent.o: ../../src/juce_appframework/gui/components/f | |||||
| @echo $(notdir $<) | @echo $(notdir $<) | ||||
| @$(CXX) $(CXXFLAGS) -o $@ -c $< | @$(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 | $(OBJDIR)/juce_FileTreeComponent.o: ../../src/juce_appframework/gui/components/filebrowser/juce_FileTreeComponent.cpp | ||||
| -@$(CMD_MKOBJDIR) | -@$(CMD_MKOBJDIR) | ||||
| @echo $(notdir $<) | @echo $(notdir $<) | ||||
| @@ -40,6 +40,7 @@ | |||||
| #include <X11/Xmd.h> | #include <X11/Xmd.h> | ||||
| #include <X11/keysym.h> | #include <X11/keysym.h> | ||||
| #include <X11/cursorfont.h> | #include <X11/cursorfont.h> | ||||
| #include <X11/extensions/scrnsaver.h> | |||||
| #if JUCE_USE_XINERAMA | #if JUCE_USE_XINERAMA | ||||
| /* If you're trying to use Xinerama, you'll need to install the "libxinerama-dev" package.. | /* 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() | 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() | bool Desktop::isScreenSaverEnabled() throw() | ||||
| { | { | ||||
| return true; | |||||
| return screenSaverAllowed; | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -2897,6 +2904,14 @@ bool juce_makeOpenGLContextCurrent (void* context) | |||||
| return glXMakeCurrent (display, None, 0); | 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) | void juce_swapOpenGLBuffers (void* context) | ||||
| { | { | ||||
| OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; | OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; | ||||
| @@ -646,6 +646,8 @@ | |||||
| 84FC31BB09B74A5C00B75141 /* juce_WildcardFileFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 84FC31A909B74A5C00B75141 /* juce_WildcardFileFilter.h */; }; | 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 */; }; | 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 */; }; | 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 */ | /* End PBXBuildFile section */ | ||||
| /* Begin PBXFileReference 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>"; }; | 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>"; }; | 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>"; }; | 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; }; | D2AAC046055464E500DB518D /* libjucedebug.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjucedebug.a; sourceTree = BUILT_PRODUCTS_DIR; }; | ||||
| /* End PBXFileReference section */ | /* End PBXFileReference section */ | ||||
| @@ -2416,6 +2420,8 @@ | |||||
| 84FC31A209B74A5C00B75141 /* juce_FileFilter.h */, | 84FC31A209B74A5C00B75141 /* juce_FileFilter.h */, | ||||
| 84FC31A309B74A5C00B75141 /* juce_FileListComponent.cpp */, | 84FC31A309B74A5C00B75141 /* juce_FileListComponent.cpp */, | ||||
| 84FC31A409B74A5C00B75141 /* juce_FileListComponent.h */, | 84FC31A409B74A5C00B75141 /* juce_FileListComponent.h */, | ||||
| 84FFAF290C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.cpp */, | |||||
| 84FFAF2A0C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.h */, | |||||
| 847F72D90C2702A000CBECEC /* juce_FileTreeComponent.cpp */, | 847F72D90C2702A000CBECEC /* juce_FileTreeComponent.cpp */, | ||||
| 847F72DA0C2702A000CBECEC /* juce_FileTreeComponent.h */, | 847F72DA0C2702A000CBECEC /* juce_FileTreeComponent.h */, | ||||
| 84F1F05B0A36CE96008CCC5E /* juce_FilenameComponent.cpp */, | 84F1F05B0A36CE96008CCC5E /* juce_FilenameComponent.cpp */, | ||||
| @@ -2722,6 +2728,7 @@ | |||||
| 84F6B7550C06E29D00BB8791 /* juce_ChannelRemappingAudioSource.h in Headers */, | 84F6B7550C06E29D00BB8791 /* juce_ChannelRemappingAudioSource.h in Headers */, | ||||
| 847F72DC0C2702A000CBECEC /* juce_DirectoryContentsDisplayComponent.h in Headers */, | 847F72DC0C2702A000CBECEC /* juce_DirectoryContentsDisplayComponent.h in Headers */, | ||||
| 847F72DE0C2702A000CBECEC /* juce_FileTreeComponent.h in Headers */, | 847F72DE0C2702A000CBECEC /* juce_FileTreeComponent.h in Headers */, | ||||
| 84FFAF2C0C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.h in Headers */, | |||||
| ); | ); | ||||
| runOnlyForDeploymentPostprocessing = 0; | runOnlyForDeploymentPostprocessing = 0; | ||||
| }; | }; | ||||
| @@ -3118,6 +3125,7 @@ | |||||
| 847F72DB0C2702A000CBECEC /* juce_DirectoryContentsDisplayComponent.cpp in Sources */, | 847F72DB0C2702A000CBECEC /* juce_DirectoryContentsDisplayComponent.cpp in Sources */, | ||||
| 847F72DD0C2702A000CBECEC /* juce_FileTreeComponent.cpp in Sources */, | 847F72DD0C2702A000CBECEC /* juce_FileTreeComponent.cpp in Sources */, | ||||
| 8406AA5A0C4BDF90003A0D6A /* juce_MidiOutput.cpp in Sources */, | 8406AA5A0C4BDF90003A0D6A /* juce_MidiOutput.cpp in Sources */, | ||||
| 84FFAF2B0C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.cpp in Sources */, | |||||
| ); | ); | ||||
| runOnlyForDeploymentPostprocessing = 0; | runOnlyForDeploymentPostprocessing = 0; | ||||
| }; | }; | ||||
| @@ -1937,6 +1937,15 @@ bool juce_isHIViewCreatedByJuce (HIViewRef view) | |||||
| && HIObjectIsOfClass ((HIObjectRef) view, juceHiViewClassNameCFString); | && 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() | static void trackNextMouseEvent() | ||||
| { | { | ||||
| UInt32 mods; | UInt32 mods; | ||||
| @@ -3350,6 +3359,14 @@ bool juce_makeOpenGLContextCurrent (void* context) | |||||
| return aglSetCurrentContext ((oc != 0) ? oc->renderContext : 0); | 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) | void juce_swapOpenGLBuffers (void* context) | ||||
| { | { | ||||
| OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; | OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; | ||||
| @@ -3141,6 +3141,14 @@ bool juce_makeOpenGLContextCurrent (void* context) | |||||
| return wglMakeCurrent (0, 0) != 0; | 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) | void juce_swapOpenGLBuffers (void* context) | ||||
| { | { | ||||
| OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; | OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; | ||||
| @@ -4145,6 +4145,14 @@ | |||||
| RelativePath="..\..\..\src\juce_appframework\gui\components\filebrowser\juce_FilePreviewComponent.h" | RelativePath="..\..\..\src\juce_appframework\gui\components\filebrowser\juce_FilePreviewComponent.h" | ||||
| > | > | ||||
| </File> | </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 | <File | ||||
| RelativePath="..\..\..\src\juce_appframework\gui\components\filebrowser\juce_FileTreeComponent.cpp" | RelativePath="..\..\..\src\juce_appframework\gui\components\filebrowser\juce_FileTreeComponent.cpp" | ||||
| > | > | ||||
| @@ -6,7 +6,10 @@ | |||||
| ============================================================================== | ============================================================================== | ||||
| Changelist for version 1.45 | 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 | 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) | void JUCE_CALLTYPE informHostOfParameterChange (int index, float newValue) | ||||
| { | { | ||||
| if (juceFilter != 0) | |||||
| juceFilter->setParameter (index, newValue); | |||||
| SetControlValue (index + 2, floatToLong (newValue)); | SetControlValue (index + 2, floatToLong (newValue)); | ||||
| } | } | ||||
| @@ -34,14 +34,14 @@ | |||||
| //============================================================================== | //============================================================================== | ||||
| AudioFilterBase::AudioFilterBase() | AudioFilterBase::AudioFilterBase() | ||||
| : suspended (false), | |||||
| : sampleRate (0), | |||||
| blockSize (0), | |||||
| numInputChannels (0), | numInputChannels (0), | ||||
| numOutputChannels (0), | numOutputChannels (0), | ||||
| suspended (false), | |||||
| callbacks (0), | callbacks (0), | ||||
| activeEditor (0) | activeEditor (0) | ||||
| { | { | ||||
| sampleRate = 0.0; | |||||
| blockSize = 0; | |||||
| } | } | ||||
| AudioFilterBase::~AudioFilterBase() | AudioFilterBase::~AudioFilterBase() | ||||
| @@ -67,6 +67,11 @@ void AudioFilterBase::setParameterNotifyingHost (const int parameterIndex, | |||||
| setParameter (parameterIndex, newValue); | setParameter (parameterIndex, newValue); | ||||
| } | } | ||||
| bool AudioFilterBase::isParameterAutomatable (int /*index*/) const | |||||
| { | |||||
| return true; | |||||
| } | |||||
| void AudioFilterBase::suspendProcessing (const bool shouldBeSuspended) | void AudioFilterBase::suspendProcessing (const bool shouldBeSuspended) | ||||
| { | { | ||||
| const ScopedLock sl (callbackLock); | const ScopedLock sl (callbackLock); | ||||
| @@ -80,18 +85,6 @@ bool AudioFilterBase::getCurrentPositionInfo (CurrentPositionInfo& info) | |||||
| && callbacks->getCurrentPositionInfo (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) | void AudioFilterBase::editorBeingDeleted (AudioFilterEditor* const editor) | ||||
| { | { | ||||
| @@ -112,8 +105,10 @@ AudioFilterEditor* AudioFilterBase::createEditorIfNeeded() | |||||
| if (ed != 0) | if (ed != 0) | ||||
| { | { | ||||
| #if ! JUCE_PLUGIN_HOST | |||||
| // you must give your editor comp a size before returning it.. | // you must give your editor comp a size before returning it.. | ||||
| jassert (ed->getWidth() > 0 && ed->getHeight() > 0); | jassert (ed->getWidth() > 0 && ed->getHeight() > 0); | ||||
| #endif | |||||
| const ScopedLock sl (callbackLock); | const ScopedLock sl (callbackLock); | ||||
| activeEditor = ed; | activeEditor = ed; | ||||
| @@ -207,6 +207,7 @@ public: | |||||
| */ | */ | ||||
| bool JUCE_CALLTYPE getCurrentPositionInfo (CurrentPositionInfo& info); | bool JUCE_CALLTYPE getCurrentPositionInfo (CurrentPositionInfo& info); | ||||
| //============================================================================== | |||||
| /** Returns the current sample rate. | /** Returns the current sample rate. | ||||
| This can be called from your processBlock() method - it's not guaranteed | 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; } | int JUCE_CALLTYPE getBlockSize() const throw() { return blockSize; } | ||||
| //============================================================================== | |||||
| /** Returns the number of input channels that the host will be sending the filter. | /** 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 | 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 | The host might not supply very useful names for channels, and this might be | ||||
| something like "1", "2", "left", "right", etc. | 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. | /** 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 | The host might not supply very useful names for channels, and this might be | ||||
| something like "1", "2", "left", "right", etc. | 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 | /** This returns a critical section that will automatically be locked while the host | ||||
| @@ -384,6 +392,12 @@ public: | |||||
| void JUCE_CALLTYPE setParameterNotifyingHost (int parameterIndex, | void JUCE_CALLTYPE setParameterNotifyingHost (int parameterIndex, | ||||
| float newValue); | 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. | /** Returns the number of preset programs the plugin supports. | ||||
| @@ -507,6 +521,11 @@ protected: | |||||
| static XmlElement* JUCE_CALLTYPE getXmlFromBinary (const void* data, | static XmlElement* JUCE_CALLTYPE getXmlFromBinary (const void* data, | ||||
| const int sizeInBytes); | const int sizeInBytes); | ||||
| /** @internal */ | |||||
| double sampleRate; | |||||
| /** @internal */ | |||||
| int numInputChannels, numOutputChannels, blockSize; | |||||
| private: | private: | ||||
| friend class JuceVSTWrapper; | friend class JuceVSTWrapper; | ||||
| friend class JuceAU; | friend class JuceAU; | ||||
| @@ -517,9 +536,6 @@ private: | |||||
| CriticalSection callbackLock; | CriticalSection callbackLock; | ||||
| bool suspended; | bool suspended; | ||||
| double sampleRate; | |||||
| int blockSize, numInputChannels, numOutputChannels; | |||||
| StringArray outputNames, inputNames; | |||||
| FilterNativeCallbacks* callbacks; | FilterNativeCallbacks* callbacks; | ||||
| @@ -54,7 +54,7 @@ namespace BinaryData | |||||
| const int treeviewdemo_cppSize = 7534; | const int treeviewdemo_cppSize = 7534; | ||||
| extern const char* widgetsdemo_cpp; | extern const char* widgetsdemo_cpp; | ||||
| const int widgetsdemo_cppSize = 52997; | |||||
| const int widgetsdemo_cppSize = 53000; | |||||
| }; | }; | ||||
| @@ -175,8 +175,8 @@ class CustomMenuComponent : public PopupMenuCustomComponent, | |||||
| public: | public: | ||||
| CustomMenuComponent() | CustomMenuComponent() | ||||
| blobX (0), | |||||
| blobY (0) | |||||
| : blobX (0), | |||||
| blobY (0) | |||||
| { | { | ||||
| // set off a timer to move a blob around on this component every | // set off a timer to move a blob around on this component every | ||||
| // 300 milliseconds - see the timerCallback() method. | // 300 milliseconds - see the timerCallback() method. | ||||
| @@ -175,7 +175,7 @@ class CustomMenuComponent : public PopupMenuCustomComponent, | |||||
| public: | public: | ||||
| CustomMenuComponent() | CustomMenuComponent() | ||||
| : blobX (0), | |||||
| : blobX (0), | |||||
| blobY (0) | blobY (0) | ||||
| { | { | ||||
| // set off a timer to move a blob around on this component every | // set off a timer to move a blob around on this component every | ||||
| @@ -113,6 +113,7 @@ MainWindow::MainWindow() | |||||
| } | } | ||||
| addKeyListener (commandManager->getKeyMappings()); | addKeyListener (commandManager->getKeyMappings()); | ||||
| commandManager->addListener (this); | |||||
| // don't want the window to take focus when the title-bar is clicked.. | // don't want the window to take focus when the title-bar is clicked.. | ||||
| setWantsKeyboardFocus (false); | setWantsKeyboardFocus (false); | ||||
| @@ -569,6 +569,9 @@ | |||||
| #ifndef __JUCE_FILEPREVIEWCOMPONENT_JUCEHEADER__ | #ifndef __JUCE_FILEPREVIEWCOMPONENT_JUCEHEADER__ | ||||
| #include "juce_appframework/gui/components/filebrowser/juce_FilePreviewComponent.h" | #include "juce_appframework/gui/components/filebrowser/juce_FilePreviewComponent.h" | ||||
| #endif | #endif | ||||
| #ifndef __JUCE_FILESEARCHPATHLISTCOMPONENT_JUCEHEADER__ | |||||
| #include "juce_appframework/gui/components/filebrowser/juce_FileSearchPathListComponent.h" | |||||
| #endif | |||||
| #ifndef __JUCE_FILETREECOMPONENT_JUCEHEADER__ | #ifndef __JUCE_FILETREECOMPONENT_JUCEHEADER__ | ||||
| #include "juce_appframework/gui/components/filebrowser/juce_FileTreeComponent.h" | #include "juce_appframework/gui/components/filebrowser/juce_FileTreeComponent.h" | ||||
| #endif | #endif | ||||
| @@ -256,7 +256,7 @@ FileBasedDocument::SaveResult FileBasedDocument::saveAsInteractive (const bool w | |||||
| if (f.existsAsFile() || f.getParentDirectory().isDirectory()) | if (f.existsAsFile() || f.getParentDirectory().isDirectory()) | ||||
| f = f.getSiblingFile (legalFilename); | f = f.getSiblingFile (legalFilename); | ||||
| else | else | ||||
| f = File::getCurrentWorkingDirectory().getChildFile (legalFilename); | |||||
| f = File::getSpecialLocation (File::userDocumentsDirectory).getChildFile (legalFilename); | |||||
| f = f.withFileExtension (fileExtension) | f = f.withFileExtension (fileExtension) | ||||
| .getNonexistentSibling (true); | .getNonexistentSibling (true); | ||||
| @@ -267,8 +267,11 @@ FileBasedDocument::SaveResult FileBasedDocument::saveAsInteractive (const bool w | |||||
| { | { | ||||
| setLastDocumentOpened (fc.getResult()); | 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; | return userCancelledSave; | ||||
| @@ -49,7 +49,7 @@ | |||||
| void loadMooseFile() | void loadMooseFile() | ||||
| { | { | ||||
| FileChooser myChooser ("Please select the moose you want to load...", | FileChooser myChooser ("Please select the moose you want to load...", | ||||
| File (SystemStats::getUserHomeDirectory()), | |||||
| File::getSpecialLocation (File::userHomeDirectory), | |||||
| "*.moose"); | "*.moose"); | ||||
| if (myChooser.browseForFileToOpen()) | 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 "../controls/juce_TreeView.h" | ||||
| #include "../filebrowser/juce_FilenameComponent.h" | #include "../filebrowser/juce_FilenameComponent.h" | ||||
| #include "../filebrowser/juce_DirectoryContentsDisplayComponent.h" | #include "../filebrowser/juce_DirectoryContentsDisplayComponent.h" | ||||
| #include "../filebrowser/juce_FileSearchPathListComponent.h" | |||||
| #include "../layout/juce_GroupComponent.h" | #include "../layout/juce_GroupComponent.h" | ||||
| #include "../properties/juce_PropertyComponent.h" | #include "../properties/juce_PropertyComponent.h" | ||||
| #include "../juce_Desktop.h" | #include "../juce_Desktop.h" | ||||
| @@ -193,7 +194,9 @@ LookAndFeel::LookAndFeel() | |||||
| MidiKeyboardComponent::upDownButtonArrowColourId, 0xff000000, | MidiKeyboardComponent::upDownButtonArrowColourId, 0xff000000, | ||||
| ColourSelector::backgroundColourId, 0xffe5e5e5, | ColourSelector::backgroundColourId, 0xffe5e5e5, | ||||
| ColourSelector::labelTextColourId, 0xff000000 | |||||
| ColourSelector::labelTextColourId, 0xff000000, | |||||
| FileSearchPathListComponent::backgroundColourId, 0xffffffff, | |||||
| }; | }; | ||||
| for (int i = 0; i < numElementsInArray (standardColours); i += 2) | 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_swapOpenGLBuffers (void* context); | ||||
| extern void juce_updateOpenGLWindowPos (void* context, Component* owner, Component* topComp); | extern void juce_updateOpenGLWindowPos (void* context, Component* owner, Component* topComp); | ||||
| extern void juce_repaintOpenGLWindow (void* context); | extern void juce_repaintOpenGLWindow (void* context); | ||||
| extern bool juce_isActiveOpenGLContext (void* context) throw(); | |||||
| static VoidArray activeGLWindows (2); | static VoidArray activeGLWindows (2); | ||||
| @@ -139,6 +140,11 @@ public: | |||||
| return context != 0 && juce_makeOpenGLContextCurrent (context); | return context != 0 && juce_makeOpenGLContextCurrent (context); | ||||
| } | } | ||||
| bool isActive() const throw() | |||||
| { | |||||
| return context != 0 && juce_isActiveOpenGLContext (context); | |||||
| } | |||||
| void swapBuffers() const | void swapBuffers() const | ||||
| { | { | ||||
| if (context != 0) | if (context != 0) | ||||
| @@ -222,6 +228,26 @@ void OpenGLComponent::makeCurrentContextInactive() | |||||
| juce_makeOpenGLContextCurrent (0); | 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() | void OpenGLComponent::swapBuffers() | ||||
| { | { | ||||
| InternalGLContextHolder* const context = (InternalGLContextHolder*) internalData; | InternalGLContextHolder* const context = (InternalGLContextHolder*) internalData; | ||||
| @@ -78,6 +78,17 @@ public: | |||||
| */ | */ | ||||
| void makeCurrentContextInactive(); | 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. */ | /** Flips the openGL buffers over. */ | ||||
| void swapBuffers(); | void swapBuffers(); | ||||