| @@ -0,0 +1,27 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||||
| <plist> | |||||
| <dict> | |||||
| <key>CFBundleExecutable</key> | |||||
| <string>${EXECUTABLE_NAME}</string> | |||||
| <key>CFBundleIconFile</key> | |||||
| <string></string> | |||||
| <key>CFBundleIdentifier</key> | |||||
| <string>com.timurdoumler.PluckedStringsDemo</string> | |||||
| <key>CFBundleName</key> | |||||
| <string>PluckedStringsDemo</string> | |||||
| <key>CFBundlePackageType</key> | |||||
| <string>APPL</string> | |||||
| <key>CFBundleSignature</key> | |||||
| <string>????</string> | |||||
| <key>CFBundleShortVersionString</key> | |||||
| <string>1.0.0</string> | |||||
| <key>CFBundleVersion</key> | |||||
| <string>1.0.0</string> | |||||
| <key>NSHumanReadableCopyright</key> | |||||
| <string></string> | |||||
| <key>NSHighResolutionCapable</key> | |||||
| <true/> | |||||
| </dict> | |||||
| </plist> | |||||
| @@ -0,0 +1,19 @@ | |||||
| Microsoft Visual Studio Solution File, Format Version 11.00 | |||||
| # Visual Studio 2013 | |||||
| Project("{798408B1-275B-0B42-1439-1A3AA75C50F3}") = "PluckedStringsDemo", "PluckedStringsDemo.vcxproj", "{A8C8CD6F-F9CA-737E-DC8B-DA724521F17B}" | |||||
| EndProject | |||||
| Global | |||||
| GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||||
| Debug|Win32 = Debug|Win32 | |||||
| Release|Win32 = Release|Win32 | |||||
| EndGlobalSection | |||||
| GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||||
| {A8C8CD6F-F9CA-737E-DC8B-DA724521F17B}.Debug|Win32.ActiveCfg = Debug|Win32 | |||||
| {A8C8CD6F-F9CA-737E-DC8B-DA724521F17B}.Debug|Win32.Build.0 = Debug|Win32 | |||||
| {A8C8CD6F-F9CA-737E-DC8B-DA724521F17B}.Release|Win32.ActiveCfg = Release|Win32 | |||||
| {A8C8CD6F-F9CA-737E-DC8B-DA724521F17B}.Release|Win32.Build.0 = Release|Win32 | |||||
| EndGlobalSection | |||||
| GlobalSection(SolutionProperties) = preSolution | |||||
| HideSolutionNode = FALSE | |||||
| EndGlobalSection | |||||
| EndGlobal | |||||
| @@ -0,0 +1,29 @@ | |||||
| #ifdef JUCE_USER_DEFINED_RC_FILE | |||||
| #include JUCE_USER_DEFINED_RC_FILE | |||||
| #else | |||||
| #undef WIN32_LEAN_AND_MEAN | |||||
| #define WIN32_LEAN_AND_MEAN | |||||
| #include <windows.h> | |||||
| VS_VERSION_INFO VERSIONINFO | |||||
| FILEVERSION 1,0,0,0 | |||||
| BEGIN | |||||
| BLOCK "StringFileInfo" | |||||
| BEGIN | |||||
| BLOCK "040904E4" | |||||
| BEGIN | |||||
| VALUE "FileDescription", "PluckedStringsDemo\0" | |||||
| VALUE "FileVersion", "1.0.0\0" | |||||
| VALUE "ProductName", "PluckedStringsDemo\0" | |||||
| VALUE "ProductVersion", "1.0.0\0" | |||||
| END | |||||
| END | |||||
| BLOCK "VarFileInfo" | |||||
| BEGIN | |||||
| VALUE "Translation", 0x409, 65001 | |||||
| END | |||||
| END | |||||
| #endif | |||||
| @@ -0,0 +1,179 @@ | |||||
| /* | |||||
| IMPORTANT! This file is auto-generated each time you save your | |||||
| project - if you alter its contents, your changes may be overwritten! | |||||
| There's a section below where you can add your own custom code safely, and the | |||||
| Introjucer will preserve the contents of that block, but the best way to change | |||||
| any of these definitions is by using the Introjucer's project settings. | |||||
| Any commented-out settings will assume their default values. | |||||
| */ | |||||
| #ifndef __JUCE_APPCONFIG_JKHEJM__ | |||||
| #define __JUCE_APPCONFIG_JKHEJM__ | |||||
| //============================================================================== | |||||
| // [BEGIN_USER_CODE_SECTION] | |||||
| // (You can add your own code in this section, and the Introjucer will not overwrite it) | |||||
| // [END_USER_CODE_SECTION] | |||||
| //============================================================================== | |||||
| #define JUCE_MODULE_AVAILABLE_juce_audio_basics 1 | |||||
| #define JUCE_MODULE_AVAILABLE_juce_audio_devices 1 | |||||
| #define JUCE_MODULE_AVAILABLE_juce_audio_formats 1 | |||||
| #define JUCE_MODULE_AVAILABLE_juce_audio_processors 1 | |||||
| #define JUCE_MODULE_AVAILABLE_juce_audio_utils 1 | |||||
| #define JUCE_MODULE_AVAILABLE_juce_core 1 | |||||
| #define JUCE_MODULE_AVAILABLE_juce_data_structures 1 | |||||
| #define JUCE_MODULE_AVAILABLE_juce_events 1 | |||||
| #define JUCE_MODULE_AVAILABLE_juce_graphics 1 | |||||
| #define JUCE_MODULE_AVAILABLE_juce_gui_basics 1 | |||||
| #define JUCE_MODULE_AVAILABLE_juce_gui_extra 1 | |||||
| //============================================================================== | |||||
| // juce_audio_devices flags: | |||||
| #ifndef JUCE_ASIO | |||||
| //#define JUCE_ASIO | |||||
| #endif | |||||
| #ifndef JUCE_WASAPI | |||||
| //#define JUCE_WASAPI | |||||
| #endif | |||||
| #ifndef JUCE_WASAPI_EXCLUSIVE | |||||
| //#define JUCE_WASAPI_EXCLUSIVE | |||||
| #endif | |||||
| #ifndef JUCE_DIRECTSOUND | |||||
| //#define JUCE_DIRECTSOUND | |||||
| #endif | |||||
| #ifndef JUCE_ALSA | |||||
| //#define JUCE_ALSA | |||||
| #endif | |||||
| #ifndef JUCE_JACK | |||||
| //#define JUCE_JACK | |||||
| #endif | |||||
| #ifndef JUCE_USE_ANDROID_OPENSLES | |||||
| //#define JUCE_USE_ANDROID_OPENSLES | |||||
| #endif | |||||
| #ifndef JUCE_USE_CDREADER | |||||
| //#define JUCE_USE_CDREADER | |||||
| #endif | |||||
| #ifndef JUCE_USE_CDBURNER | |||||
| //#define JUCE_USE_CDBURNER | |||||
| #endif | |||||
| //============================================================================== | |||||
| // juce_audio_formats flags: | |||||
| #ifndef JUCE_USE_FLAC | |||||
| //#define JUCE_USE_FLAC | |||||
| #endif | |||||
| #ifndef JUCE_USE_OGGVORBIS | |||||
| //#define JUCE_USE_OGGVORBIS | |||||
| #endif | |||||
| #ifndef JUCE_USE_MP3AUDIOFORMAT | |||||
| //#define JUCE_USE_MP3AUDIOFORMAT | |||||
| #endif | |||||
| #ifndef JUCE_USE_LAME_AUDIO_FORMAT | |||||
| //#define JUCE_USE_LAME_AUDIO_FORMAT | |||||
| #endif | |||||
| #ifndef JUCE_USE_WINDOWS_MEDIA_FORMAT | |||||
| //#define JUCE_USE_WINDOWS_MEDIA_FORMAT | |||||
| #endif | |||||
| //============================================================================== | |||||
| // juce_audio_processors flags: | |||||
| #ifndef JUCE_PLUGINHOST_VST | |||||
| //#define JUCE_PLUGINHOST_VST | |||||
| #endif | |||||
| #ifndef JUCE_PLUGINHOST_VST3 | |||||
| //#define JUCE_PLUGINHOST_VST3 | |||||
| #endif | |||||
| #ifndef JUCE_PLUGINHOST_AU | |||||
| //#define JUCE_PLUGINHOST_AU | |||||
| #endif | |||||
| //============================================================================== | |||||
| // juce_core flags: | |||||
| #ifndef JUCE_FORCE_DEBUG | |||||
| //#define JUCE_FORCE_DEBUG | |||||
| #endif | |||||
| #ifndef JUCE_LOG_ASSERTIONS | |||||
| //#define JUCE_LOG_ASSERTIONS | |||||
| #endif | |||||
| #ifndef JUCE_CHECK_MEMORY_LEAKS | |||||
| //#define JUCE_CHECK_MEMORY_LEAKS | |||||
| #endif | |||||
| #ifndef JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES | |||||
| //#define JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES | |||||
| #endif | |||||
| #ifndef JUCE_INCLUDE_ZLIB_CODE | |||||
| //#define JUCE_INCLUDE_ZLIB_CODE | |||||
| #endif | |||||
| //============================================================================== | |||||
| // juce_graphics flags: | |||||
| #ifndef JUCE_USE_COREIMAGE_LOADER | |||||
| //#define JUCE_USE_COREIMAGE_LOADER | |||||
| #endif | |||||
| #ifndef JUCE_USE_DIRECTWRITE | |||||
| //#define JUCE_USE_DIRECTWRITE | |||||
| #endif | |||||
| //============================================================================== | |||||
| // juce_gui_basics flags: | |||||
| #ifndef JUCE_ENABLE_REPAINT_DEBUGGING | |||||
| //#define JUCE_ENABLE_REPAINT_DEBUGGING | |||||
| #endif | |||||
| #ifndef JUCE_USE_XSHM | |||||
| //#define JUCE_USE_XSHM | |||||
| #endif | |||||
| #ifndef JUCE_USE_XRENDER | |||||
| //#define JUCE_USE_XRENDER | |||||
| #endif | |||||
| #ifndef JUCE_USE_XCURSOR | |||||
| //#define JUCE_USE_XCURSOR | |||||
| #endif | |||||
| //============================================================================== | |||||
| // juce_gui_extra flags: | |||||
| #ifndef JUCE_WEB_BROWSER | |||||
| //#define JUCE_WEB_BROWSER | |||||
| #endif | |||||
| #ifndef JUCE_ENABLE_LIVE_CONSTANT_EDITOR | |||||
| //#define JUCE_ENABLE_LIVE_CONSTANT_EDITOR | |||||
| #endif | |||||
| #endif // __JUCE_APPCONFIG_JKHEJM__ | |||||
| @@ -0,0 +1,44 @@ | |||||
| /* | |||||
| IMPORTANT! This file is auto-generated each time you save your | |||||
| project - if you alter its contents, your changes may be overwritten! | |||||
| This is the header file that your files should include in order to get all the | |||||
| JUCE library headers. You should avoid including the JUCE headers directly in | |||||
| your own source files, because that wouldn't pick up the correct configuration | |||||
| options for your app. | |||||
| */ | |||||
| #ifndef __APPHEADERFILE_JKHEJM__ | |||||
| #define __APPHEADERFILE_JKHEJM__ | |||||
| #include "AppConfig.h" | |||||
| #include "modules/juce_audio_basics/juce_audio_basics.h" | |||||
| #include "modules/juce_audio_devices/juce_audio_devices.h" | |||||
| #include "modules/juce_audio_formats/juce_audio_formats.h" | |||||
| #include "modules/juce_audio_processors/juce_audio_processors.h" | |||||
| #include "modules/juce_audio_utils/juce_audio_utils.h" | |||||
| #include "modules/juce_core/juce_core.h" | |||||
| #include "modules/juce_data_structures/juce_data_structures.h" | |||||
| #include "modules/juce_events/juce_events.h" | |||||
| #include "modules/juce_graphics/juce_graphics.h" | |||||
| #include "modules/juce_gui_basics/juce_gui_basics.h" | |||||
| #include "modules/juce_gui_extra/juce_gui_extra.h" | |||||
| #if ! DONT_SET_USING_JUCE_NAMESPACE | |||||
| // If your code uses a lot of JUCE classes, then this will obviously save you | |||||
| // a lot of typing, but can be disabled by setting DONT_SET_USING_JUCE_NAMESPACE. | |||||
| using namespace juce; | |||||
| #endif | |||||
| #if ! JUCE_DONT_DECLARE_PROJECTINFO | |||||
| namespace ProjectInfo | |||||
| { | |||||
| const char* const projectName = "PluckedStringsDemo"; | |||||
| const char* const versionString = "1.0.0"; | |||||
| const int versionNumber = 0x10000; | |||||
| } | |||||
| #endif | |||||
| #endif // __APPHEADERFILE_JKHEJM__ | |||||
| @@ -0,0 +1,12 @@ | |||||
| Important Note!! | |||||
| ================ | |||||
| The purpose of this folder is to contain files that are auto-generated by the Introjucer, | |||||
| and ALL files in this folder will be mercilessly DELETED and completely re-written whenever | |||||
| the Introjucer saves your project. | |||||
| Therefore, it's a bad idea to make any manual changes to the files in here, or to | |||||
| put any of your own files in here if you don't want to lose them. (Of course you may choose | |||||
| to add the folder's contents to your version-control system so that you can re-merge your own | |||||
| modifications after the Introjucer has saved its changes). | |||||
| @@ -0,0 +1,5 @@ | |||||
| // This is an auto-generated file to redirect any included | |||||
| // module headers to the correct external folder. | |||||
| #include "../../../../../modules/juce_audio_basics/juce_audio_basics.h" | |||||
| @@ -0,0 +1,5 @@ | |||||
| // This is an auto-generated file to redirect any included | |||||
| // module headers to the correct external folder. | |||||
| #include "../../../../../modules/juce_audio_devices/juce_audio_devices.h" | |||||
| @@ -0,0 +1,5 @@ | |||||
| // This is an auto-generated file to redirect any included | |||||
| // module headers to the correct external folder. | |||||
| #include "../../../../../modules/juce_audio_formats/juce_audio_formats.h" | |||||
| @@ -0,0 +1,5 @@ | |||||
| // This is an auto-generated file to redirect any included | |||||
| // module headers to the correct external folder. | |||||
| #include "../../../../../modules/juce_audio_processors/juce_audio_processors.h" | |||||
| @@ -0,0 +1,5 @@ | |||||
| // This is an auto-generated file to redirect any included | |||||
| // module headers to the correct external folder. | |||||
| #include "../../../../../modules/juce_audio_utils/juce_audio_utils.h" | |||||
| @@ -0,0 +1,5 @@ | |||||
| // This is an auto-generated file to redirect any included | |||||
| // module headers to the correct external folder. | |||||
| #include "../../../../../modules/juce_core/juce_core.h" | |||||
| @@ -0,0 +1,5 @@ | |||||
| // This is an auto-generated file to redirect any included | |||||
| // module headers to the correct external folder. | |||||
| #include "../../../../../modules/juce_data_structures/juce_data_structures.h" | |||||
| @@ -0,0 +1,5 @@ | |||||
| // This is an auto-generated file to redirect any included | |||||
| // module headers to the correct external folder. | |||||
| #include "../../../../../modules/juce_events/juce_events.h" | |||||
| @@ -0,0 +1,5 @@ | |||||
| // This is an auto-generated file to redirect any included | |||||
| // module headers to the correct external folder. | |||||
| #include "../../../../../modules/juce_graphics/juce_graphics.h" | |||||
| @@ -0,0 +1,5 @@ | |||||
| // This is an auto-generated file to redirect any included | |||||
| // module headers to the correct external folder. | |||||
| #include "../../../../../modules/juce_gui_basics/juce_gui_basics.h" | |||||
| @@ -0,0 +1,5 @@ | |||||
| // This is an auto-generated file to redirect any included | |||||
| // module headers to the correct external folder. | |||||
| #include "../../../../../modules/juce_gui_extra/juce_gui_extra.h" | |||||
| @@ -0,0 +1,75 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <JUCERPROJECT id="jKHEJM" name="PluckedStringsDemo" projectType="guiapp" version="1.0.0" | |||||
| bundleIdentifier="com.timurdoumler.PluckedStringsDemo" includeBinaryInAppConfig="1" | |||||
| jucerVersion="3.1.1"> | |||||
| <MAINGROUP id="IWdVf7" name="PluckedStringsDemo"> | |||||
| <GROUP id="{8800CD50-6741-8B75-0305-FAF13427EF5D}" name="Source"> | |||||
| <FILE id="Z7hWe1" name="StringSynthesiser.h" compile="0" resource="0" | |||||
| file="Source/StringSynthesiser.h"/> | |||||
| <FILE id="UFFPPQ" name="StringComponent.h" compile="0" resource="0" | |||||
| file="Source/StringComponent.h"/> | |||||
| <FILE id="Sut3oJ" name="StringDemoComponent.h" compile="0" resource="0" | |||||
| file="Source/StringDemoComponent.h"/> | |||||
| <FILE id="Y5HoZY" name="Main.cpp" compile="1" resource="0" file="Source/Main.cpp"/> | |||||
| </GROUP> | |||||
| </MAINGROUP> | |||||
| <EXPORTFORMATS> | |||||
| <XCODE_MAC targetFolder="Builds/MacOSX"> | |||||
| <CONFIGURATIONS> | |||||
| <CONFIGURATION name="Debug" osxSDK="default" osxCompatibility="default" osxArchitecture="default" | |||||
| isDebug="1" optimisation="1" targetName="PluckedStringsDemo"/> | |||||
| <CONFIGURATION name="Release" osxSDK="default" osxCompatibility="default" osxArchitecture="default" | |||||
| isDebug="0" optimisation="2" targetName="PluckedStringsDemo"/> | |||||
| </CONFIGURATIONS> | |||||
| <MODULEPATHS> | |||||
| <MODULEPATH id="juce_core" path="../../modules"/> | |||||
| <MODULEPATH id="juce_events" path="../../modules"/> | |||||
| <MODULEPATH id="juce_graphics" path="../../modules"/> | |||||
| <MODULEPATH id="juce_data_structures" path="../../modules"/> | |||||
| <MODULEPATH id="juce_gui_basics" path="../../modules"/> | |||||
| <MODULEPATH id="juce_gui_extra" path="../../modules"/> | |||||
| <MODULEPATH id="juce_audio_basics" path="../../modules"/> | |||||
| <MODULEPATH id="juce_audio_devices" path="../../modules"/> | |||||
| <MODULEPATH id="juce_audio_formats" path="../../modules"/> | |||||
| <MODULEPATH id="juce_audio_processors" path="../../modules"/> | |||||
| <MODULEPATH id="juce_audio_utils" path="../../modules"/> | |||||
| </MODULEPATHS> | |||||
| </XCODE_MAC> | |||||
| <VS2013 targetFolder="Builds/VisualStudio2013"> | |||||
| <CONFIGURATIONS> | |||||
| <CONFIGURATION name="Debug" winWarningLevel="4" generateManifest="1" winArchitecture="32-bit" | |||||
| isDebug="1" optimisation="1" targetName="PluckedStringsDemo"/> | |||||
| <CONFIGURATION name="Release" winWarningLevel="4" generateManifest="1" winArchitecture="32-bit" | |||||
| isDebug="0" optimisation="2" targetName="PluckedStringsDemo"/> | |||||
| </CONFIGURATIONS> | |||||
| <MODULEPATHS> | |||||
| <MODULEPATH id="juce_gui_extra" path="../../modules"/> | |||||
| <MODULEPATH id="juce_gui_basics" path="../../modules"/> | |||||
| <MODULEPATH id="juce_graphics" path="../../modules"/> | |||||
| <MODULEPATH id="juce_events" path="../../modules"/> | |||||
| <MODULEPATH id="juce_data_structures" path="../../modules"/> | |||||
| <MODULEPATH id="juce_core" path="../../modules"/> | |||||
| <MODULEPATH id="juce_audio_utils" path="../../modules"/> | |||||
| <MODULEPATH id="juce_audio_processors" path="../../modules"/> | |||||
| <MODULEPATH id="juce_audio_formats" path="../../modules"/> | |||||
| <MODULEPATH id="juce_audio_devices" path="../../modules"/> | |||||
| <MODULEPATH id="juce_audio_basics" path="../../modules"/> | |||||
| </MODULEPATHS> | |||||
| </VS2013> | |||||
| </EXPORTFORMATS> | |||||
| <MODULES> | |||||
| <MODULES id="juce_audio_basics" showAllCode="1" useLocalCopy="0"/> | |||||
| <MODULES id="juce_audio_devices" showAllCode="1" useLocalCopy="0"/> | |||||
| <MODULES id="juce_audio_formats" showAllCode="1" useLocalCopy="0"/> | |||||
| <MODULES id="juce_audio_processors" showAllCode="1" useLocalCopy="0"/> | |||||
| <MODULES id="juce_audio_utils" showAllCode="1" useLocalCopy="0"/> | |||||
| <MODULES id="juce_core" showAllCode="1" useLocalCopy="0"/> | |||||
| <MODULES id="juce_data_structures" showAllCode="1" useLocalCopy="0"/> | |||||
| <MODULES id="juce_events" showAllCode="1" useLocalCopy="0"/> | |||||
| <MODULES id="juce_graphics" showAllCode="1" useLocalCopy="0"/> | |||||
| <MODULES id="juce_gui_basics" showAllCode="1" useLocalCopy="0"/> | |||||
| <MODULES id="juce_gui_extra" showAllCode="1" useLocalCopy="0"/> | |||||
| </MODULES> | |||||
| <JUCEOPTIONS/> | |||||
| </JUCERPROJECT> | |||||
| @@ -0,0 +1,92 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| JUCE demo code - use at your own risk! | |||||
| ============================================================================== | |||||
| */ | |||||
| #include "../JuceLibraryCode/JuceHeader.h" | |||||
| #include "StringDemoComponent.h" | |||||
| //============================================================================== | |||||
| class PluckedStringsDemoApplication : public JUCEApplication | |||||
| { | |||||
| public: | |||||
| //============================================================================== | |||||
| PluckedStringsDemoApplication() {} | |||||
| const String getApplicationName() override { return ProjectInfo::projectName; } | |||||
| const String getApplicationVersion() override { return ProjectInfo::versionString; } | |||||
| bool moreThanOneInstanceAllowed() override { return true; } | |||||
| //============================================================================== | |||||
| void initialise (const String& /*commandLine*/) override | |||||
| { | |||||
| mainWindow = new MainWindow(); | |||||
| } | |||||
| void shutdown() override | |||||
| { | |||||
| mainWindow = nullptr; // (deletes our window) | |||||
| } | |||||
| //============================================================================== | |||||
| void systemRequestedQuit() override | |||||
| { | |||||
| // This is called when the app is being asked to quit: you can ignore this | |||||
| // request and let the app carry on running, or call quit() to allow the app to close. | |||||
| quit(); | |||||
| } | |||||
| void anotherInstanceStarted (const String& /*commandLine*/) override | |||||
| { | |||||
| // When another instance of the app is launched while this one is running, | |||||
| // this method is invoked, and the commandLine parameter tells you what | |||||
| // the other instance's command-line arguments were. | |||||
| } | |||||
| //============================================================================== | |||||
| class MainWindow : public DocumentWindow | |||||
| { | |||||
| public: | |||||
| MainWindow() : DocumentWindow (ProjectInfo::projectName, | |||||
| Colours::lightgrey, | |||||
| DocumentWindow::allButtons) | |||||
| { | |||||
| setUsingNativeTitleBar (true); | |||||
| setContentOwned (new StringDemoComponent(), true); | |||||
| setResizable (true, false); | |||||
| centreWithSize (getWidth(), getHeight()); | |||||
| setVisible (true); | |||||
| } | |||||
| void closeButtonPressed() override | |||||
| { | |||||
| // This is called when the user tries to close this window. Here, we'll just | |||||
| // ask the app to quit when this happens, but you can change this to do | |||||
| // whatever you need. | |||||
| JUCEApplication::getInstance()->systemRequestedQuit(); | |||||
| } | |||||
| /* Note: Be careful if you override any DocumentWindow methods - the base | |||||
| class uses a lot of them, so by overriding you might break its functionality. | |||||
| It's best to do all your work in your content component instead, but if | |||||
| you really have to override any DocumentWindow methods, make sure your | |||||
| subclass also calls the superclass's method. | |||||
| */ | |||||
| private: | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow) | |||||
| }; | |||||
| private: | |||||
| ScopedPointer<MainWindow> mainWindow; | |||||
| }; | |||||
| //============================================================================== | |||||
| // This macro generates the main() routine that launches the app. | |||||
| START_JUCE_APPLICATION (PluckedStringsDemoApplication) | |||||
| @@ -0,0 +1,88 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| JUCE demo code - use at your own risk! | |||||
| ============================================================================== | |||||
| */ | |||||
| /* | |||||
| This component represents a horizontal vibrating musical string of fixed height | |||||
| and variable length. The string can be excited by calling stringPlucked(). | |||||
| */ | |||||
| class StringComponent : public Component, | |||||
| private Timer | |||||
| { | |||||
| public: | |||||
| StringComponent (int lengthInPixels, Colour stringColour) | |||||
| : length (lengthInPixels), colour (stringColour) | |||||
| { | |||||
| // ignore mouse-clicks so that our parent can get them instead. | |||||
| setInterceptsMouseClicks (false, false); | |||||
| setSize (length, height); | |||||
| startTimerHz (60); | |||||
| } | |||||
| //======================================================================= | |||||
| void stringPlucked (float pluckPositionRelative) | |||||
| { | |||||
| amplitude = maxAmplitude * std::sin (pluckPositionRelative * float_Pi); | |||||
| phase = float_Pi; | |||||
| } | |||||
| //======================================================================= | |||||
| void paint (Graphics& g) override | |||||
| { | |||||
| g.setColour (colour); | |||||
| g.strokePath (generateStringPath(), PathStrokeType (2.0f)); | |||||
| } | |||||
| Path generateStringPath() const | |||||
| { | |||||
| const float y = height / 2.0f; | |||||
| Path stringPath; | |||||
| stringPath.startNewSubPath (0, y); | |||||
| stringPath.quadraticTo (length / 2.0f, y + (std::sin (phase) * amplitude), (float) length, y); | |||||
| return stringPath; | |||||
| } | |||||
| //============================================================================== | |||||
| void timerCallback() override | |||||
| { | |||||
| updateAmplitude(); | |||||
| updatePhase(); | |||||
| repaint(); | |||||
| } | |||||
| void updateAmplitude() | |||||
| { | |||||
| // this determines the decay of the visible string vibration. | |||||
| amplitude *= 0.99f; | |||||
| } | |||||
| void updatePhase() | |||||
| { | |||||
| // this determines the visible vibration frequency. | |||||
| // just an arbitrary number chosen to look OK: | |||||
| const float phaseStep = 400.0f / length; | |||||
| phase += phaseStep; | |||||
| if (phase > float_Pi) | |||||
| phase -= 2.0f * float_Pi; | |||||
| } | |||||
| private: | |||||
| //======================================================================= | |||||
| int length; | |||||
| Colour colour; | |||||
| int height = 20; | |||||
| float amplitude = 0.0f; | |||||
| const float maxAmplitude = 12.0f; | |||||
| float phase = 0.0f; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StringComponent) | |||||
| }; | |||||
| @@ -0,0 +1,148 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| JUCE demo code - use at your own risk! | |||||
| ============================================================================== | |||||
| */ | |||||
| #include "StringSynthesiser.h" | |||||
| #include "StringComponent.h" | |||||
| //============================================================================== | |||||
| class StringDemoComponent : public AudioAppComponent | |||||
| { | |||||
| public: | |||||
| StringDemoComponent() | |||||
| { | |||||
| createStringComponents(); | |||||
| setSize (800, 560); | |||||
| // specify the number of input and output channels that we want to open | |||||
| setAudioChannels (0, 2); | |||||
| } | |||||
| ~StringDemoComponent() | |||||
| { | |||||
| shutdownAudio(); | |||||
| } | |||||
| //======================================================================= | |||||
| void prepareToPlay (int /*samplesPerBlockExpected*/, double sampleRate) override | |||||
| { | |||||
| generateStringSynths (sampleRate); | |||||
| } | |||||
| void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) override | |||||
| { | |||||
| bufferToFill.clearActiveBufferRegion(); | |||||
| for (int channel = 0; channel < bufferToFill.buffer->getNumChannels(); ++channel) | |||||
| { | |||||
| float* const channelData = bufferToFill.buffer->getWritePointer (channel, bufferToFill.startSample); | |||||
| if (channel == 0) | |||||
| { | |||||
| for (auto synth : stringSynths) | |||||
| synth->generateAndAddData (channelData, bufferToFill.numSamples); | |||||
| } | |||||
| else | |||||
| { | |||||
| memcpy (channelData, | |||||
| bufferToFill.buffer->getReadPointer (0), | |||||
| bufferToFill.numSamples * sizeof (float)); | |||||
| } | |||||
| } | |||||
| } | |||||
| void releaseResources() override | |||||
| { | |||||
| stringSynths.clear(); | |||||
| } | |||||
| //======================================================================= | |||||
| void paint (Graphics& g) override | |||||
| { | |||||
| g.fillAll (Colours::black); | |||||
| } | |||||
| void resized() override | |||||
| { | |||||
| int xPos = 20; | |||||
| int yPos = 20; | |||||
| int yDistance = 50; | |||||
| for (auto stringLine : stringLines) | |||||
| { | |||||
| stringLine->setTopLeftPosition (xPos, yPos); | |||||
| yPos += yDistance; | |||||
| addAndMakeVisible (stringLine); | |||||
| } | |||||
| } | |||||
| private: | |||||
| void mouseDown (const MouseEvent& e) override | |||||
| { | |||||
| mouseDrag (e); | |||||
| } | |||||
| void mouseDrag (const MouseEvent& e) override | |||||
| { | |||||
| for (int i = 0; i < stringLines.size(); ++i) | |||||
| { | |||||
| auto* stringLine = stringLines.getUnchecked(i); | |||||
| if (stringLine->getBounds().contains (e.getPosition())) | |||||
| { | |||||
| float position = (e.position.x - stringLine->getX()) / stringLine->getWidth(); | |||||
| stringLine->stringPlucked (position); | |||||
| stringSynths.getUnchecked(i)->stringPlucked (position); | |||||
| } | |||||
| } | |||||
| } | |||||
| //======================================================================= | |||||
| struct StringParameters | |||||
| { | |||||
| StringParameters (int midiNote) | |||||
| : frequencyInHz (MidiMessage::getMidiNoteInHertz (midiNote)), | |||||
| lengthInPixels ((int) (760 / (frequencyInHz / MidiMessage::getMidiNoteInHertz (42)))) | |||||
| { | |||||
| } | |||||
| double frequencyInHz; | |||||
| int lengthInPixels; | |||||
| }; | |||||
| static std::vector<StringParameters> getDefaultStringParameters() | |||||
| { | |||||
| return { 42, 44, 46, 49, 51, 54, 56, 58, 61, 63, 66, 68, 70 }; | |||||
| } | |||||
| void createStringComponents() | |||||
| { | |||||
| for (auto stringParams : getDefaultStringParameters()) | |||||
| { | |||||
| stringLines.add (new StringComponent (stringParams.lengthInPixels, | |||||
| Colour::fromHSV (Random().nextFloat(), 0.6f, 0.9f, 1.0f))); | |||||
| } | |||||
| } | |||||
| void generateStringSynths (double sampleRate) | |||||
| { | |||||
| stringSynths.clear(); | |||||
| for (auto stringParams : getDefaultStringParameters()) | |||||
| { | |||||
| stringSynths.add (new StringSynthesiser (sampleRate, stringParams.frequencyInHz)); | |||||
| } | |||||
| } | |||||
| //======================================================================= | |||||
| OwnedArray<StringComponent> stringLines; | |||||
| OwnedArray<StringSynthesiser> stringSynths; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StringDemoComponent) | |||||
| }; | |||||
| @@ -0,0 +1,125 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| JUCE demo code - use at your own risk! | |||||
| ============================================================================== | |||||
| */ | |||||
| /** | |||||
| A very basic generator of a simulated plucked string sound, implementing | |||||
| the Karplus-Strong algorithm. | |||||
| Not performance-optimised! | |||||
| */ | |||||
| class StringSynthesiser | |||||
| { | |||||
| public: | |||||
| //======================================================================= | |||||
| /** Constructor. | |||||
| @param sampleRate The audio sample rate to use. | |||||
| @param frequencyInHz The fundamental frequency of the simulated string in | |||||
| Hertz. | |||||
| */ | |||||
| StringSynthesiser (double sampleRate, double frequencyInHz) | |||||
| { | |||||
| doPluckForNextBuffer.set (false); | |||||
| prepareSynthesiserState (sampleRate, frequencyInHz); | |||||
| } | |||||
| //======================================================================= | |||||
| /** Excite the simulated string by plucking it at a given position. | |||||
| @param pluckPosition The position of the plucking, relative to the length | |||||
| of the string. Must be between 0 and 1. | |||||
| */ | |||||
| void stringPlucked (float pluckPosition) | |||||
| { | |||||
| jassert (pluckPosition >= 0.0 && pluckPosition <= 1.0); | |||||
| // we choose a very simple approach to communicate with the audio thread: | |||||
| // simply tell the synth to perform the plucking excitation at the beginning | |||||
| // of the next buffer (= when generateAndAddData is called the next time). | |||||
| if (doPluckForNextBuffer.compareAndSetBool (1, 0)) | |||||
| { | |||||
| // plucking in the middle gives the largest amplitude; | |||||
| // plucking at the very ends will do nothing. | |||||
| amplitude = std::sin (float_Pi * pluckPosition); | |||||
| } | |||||
| } | |||||
| //======================================================================= | |||||
| /** Generate next chunk of mono audio output and add it into a buffer. | |||||
| @param outBuffer Buffer to fill (one channel only). New sound will be | |||||
| added to existing content of the buffer (instead of | |||||
| replacing it). | |||||
| @param numSamples Number of samples to generate (make sure that outBuffer | |||||
| has enough space). | |||||
| */ | |||||
| void generateAndAddData (float* outBuffer, int numSamples) | |||||
| { | |||||
| if (doPluckForNextBuffer.compareAndSetBool (0, 1)) | |||||
| exciteInternalBuffer(); | |||||
| // cycle through the delay line and apply a simple averaging filter | |||||
| for (int i = 0; i < numSamples; ++i) | |||||
| { | |||||
| const int nextPos = (pos + 1) % delayLine.size(); | |||||
| delayLine[nextPos] = (float) (decay * 0.5 * (delayLine[nextPos] + delayLine[pos])); | |||||
| outBuffer[i] += delayLine[pos]; | |||||
| pos = nextPos; | |||||
| } | |||||
| } | |||||
| private: | |||||
| //======================================================================= | |||||
| void prepareSynthesiserState (double sampleRate, double frequencyInHz) | |||||
| { | |||||
| std::size_t delayLineLength = std::lround (sampleRate / frequencyInHz); | |||||
| // we need a minimum delay line length to get a reasonable synthesis. | |||||
| // if you hit this assert, increase sample rate or decrease frequency! | |||||
| jassert (delayLineLength > 50); | |||||
| delayLine.resize (delayLineLength); | |||||
| std::fill (delayLine.begin(), delayLine.end(), 0.0f); | |||||
| excitationSample.resize (delayLineLength); | |||||
| // as the excitation sample we use random noise between -1 and 1 | |||||
| // (as a simple approximation to a plucking excitation) | |||||
| std::generate (excitationSample.begin(), | |||||
| excitationSample.end(), | |||||
| [] { return (Random::getSystemRandom().nextFloat() * 2.0f) - 1.0f; } ); | |||||
| } | |||||
| void exciteInternalBuffer() | |||||
| { | |||||
| // fill the buffer with the precomputed excitation sound (scaled with amplitude) | |||||
| jassert (delayLine.size() >= excitationSample.size()); | |||||
| std::transform (excitationSample.begin(), | |||||
| excitationSample.end(), | |||||
| delayLine.begin(), | |||||
| [this] (double sample) { return amplitude * sample; } ); | |||||
| }; | |||||
| //======================================================================= | |||||
| const double decay = 0.998; | |||||
| double amplitude = 0.0; | |||||
| Atomic<int> doPluckForNextBuffer; | |||||
| std::vector<float> excitationSample, delayLine; | |||||
| int pos = 0; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StringSynthesiser) | |||||
| }; | |||||