From 74395cd014a3106ee8333a8e9a054cd365711987 Mon Sep 17 00:00:00 2001 From: asb2m10 Date: Sun, 26 Jan 2014 14:39:23 -0500 Subject: [PATCH] Code Cleanup --- Builds/MacOSX/Dexed.xcodeproj/project.pbxproj | 46 ++- .../UserInterfaceState.xcuserstate | Bin 87870 -> 87920 bytes Builds/VisualStudio2012/Dexed.vcxproj | 24 +- Builds/VisualStudio2012/Dexed.vcxproj.filters | 36 ++- Dexed.jucer | 35 ++- Source/DXComponents.cpp | 246 +++++++++++++++ Source/DXComponents.h | 58 ++++ Source/DXLookNFeel.cpp | 220 ------------- Source/DXLookNFeel.h | 39 --- Source/GlobalEditor.h | 2 +- Source/OperatorEditor.cpp | 13 +- Source/OperatorEditor.h | 1 + Source/PluginData.cpp | 293 ++++++++++++++++++ Source/PluginData.h | 27 ++ Source/PluginEditor.cpp | 5 +- Source/PluginEditor.h | 2 +- Source/PluginParam.cpp | 245 +-------------- Source/PluginProcessor.h | 4 +- 18 files changed, 722 insertions(+), 574 deletions(-) create mode 100644 Source/DXComponents.cpp create mode 100644 Source/DXComponents.h create mode 100644 Source/PluginData.cpp create mode 100644 Source/PluginData.h diff --git a/Builds/MacOSX/Dexed.xcodeproj/project.pbxproj b/Builds/MacOSX/Dexed.xcodeproj/project.pbxproj index b800a6f..d6d8d51 100644 --- a/Builds/MacOSX/Dexed.xcodeproj/project.pbxproj +++ b/Builds/MacOSX/Dexed.xcodeproj/project.pbxproj @@ -17,8 +17,9 @@ A7D45B047CA84D7EF7018CDC = { isa = PBXBuildFile; fileRef = 2F55D83145737DE69999DB92; }; 7E444608AFB10ED54DB5C9AB = { isa = PBXBuildFile; fileRef = 5E966C95FACF7B8D5A907FE3; }; 813B2285513D65DDA30AA6E3 = { isa = PBXBuildFile; fileRef = 6F9852573AA442CFBAD9695F; }; - C510246D7D5E162C9DE63DDE = { isa = PBXBuildFile; fileRef = 19CEF599CB23958AC63D427E; }; - 082D6FF34EFF195C3A3B0CFB = { isa = PBXBuildFile; fileRef = 838E63F5800CA577B92EF6AE; }; + 1CBFE444B43C89E749602B7F = { isa = PBXBuildFile; fileRef = 45ADFD8885BE76C7F7D999AC; }; + 623AFA9E78826CA0136251DF = { isa = PBXBuildFile; fileRef = 59D15F780D468B587F9C7E78; }; + 8BE2A084394DA3E45DDB5646 = { isa = PBXBuildFile; fileRef = 7936BBAA586387B2FAFB958B; }; 3AB728E101D7B85DD39C5CC8 = { isa = PBXBuildFile; fileRef = 3715DFDD7A1B12083F051F5A; }; FAC9C3E771D11FDA4DFAF17E = { isa = PBXBuildFile; fileRef = 2D26E2304C0F6FC633936014; }; 47C317B0F77A29ECA0400B2B = { isa = PBXBuildFile; fileRef = AE09B4C2A4BDE8FDA01A8A13; }; @@ -28,10 +29,11 @@ 434647C21C803FA8A4D44A70 = { isa = PBXBuildFile; fileRef = 78CA76788217B98287D9E007; }; 95105DC8536836A06FD5C7BB = { isa = PBXBuildFile; fileRef = 51E5757E2D48E638F9A4CB61; }; 0D3132A8B412AE9E63024927 = { isa = PBXBuildFile; fileRef = B0230FCCA099E6430411DFC9; }; - D5A4D43A16EA4C71D53E96CD = { isa = PBXBuildFile; fileRef = A02775EA788AD4BF7DD1B1A1; }; - 1CBFE444B43C89E749602B7F = { isa = PBXBuildFile; fileRef = 45ADFD8885BE76C7F7D999AC; }; 478699B4EF80A1A1C0D34C10 = { isa = PBXBuildFile; fileRef = 018D0FB9E97B68D2EB3E3F72; }; - 623AFA9E78826CA0136251DF = { isa = PBXBuildFile; fileRef = 59D15F780D468B587F9C7E78; }; + C510246D7D5E162C9DE63DDE = { isa = PBXBuildFile; fileRef = 19CEF599CB23958AC63D427E; }; + 082D6FF34EFF195C3A3B0CFB = { isa = PBXBuildFile; fileRef = 838E63F5800CA577B92EF6AE; }; + D5A4D43A16EA4C71D53E96CD = { isa = PBXBuildFile; fileRef = A02775EA788AD4BF7DD1B1A1; }; + 8121E10419E2D99645EA254E = { isa = PBXBuildFile; fileRef = D984CE634945077E682B48F3; }; B18C192606DF6079E7B9AEB9 = { isa = PBXBuildFile; fileRef = 8BADEB7BF1A65E83A7A1736D; }; 1C87DA0B69D67481FC6CF4FD = { isa = PBXBuildFile; fileRef = 54363D0B39B88D43447C0123; }; E3FA856CA4DB2009BB0F13E7 = { isa = PBXBuildFile; fileRef = 505852570B48EB3F18076B03; }; @@ -284,6 +286,7 @@ 448630170E2B48A00FBBA757 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_linux_Threads.cpp"; path = "../../JuceLibraryCode/modules/juce_core/native/juce_linux_Threads.cpp"; sourceTree = "SOURCE_ROOT"; }; 4497D4F58A495EF3F3DB7DD2 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ReadWriteLock.h"; path = "../../JuceLibraryCode/modules/juce_core/threads/juce_ReadWriteLock.h"; sourceTree = "SOURCE_ROOT"; }; 452C1184BD776249B33151E5 = { isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DiscRecording.framework; path = System/Library/Frameworks/DiscRecording.framework; sourceTree = SDKROOT; }; + 4567FB06348FF519FDC6D698 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DXComponents.h; path = ../../Source/DXComponents.h; sourceTree = "SOURCE_ROOT"; }; 4574217C2F5219DEDDDC9656 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_RTAS_DigiCode3.cpp"; path = "../../JuceLibraryCode/modules/juce_audio_plugin_client/RTAS/juce_RTAS_DigiCode3.cpp"; sourceTree = "SOURCE_ROOT"; }; 45ADFD8885BE76C7F7D999AC = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = PluginProcessor.cpp; path = ../../Source/PluginProcessor.cpp; sourceTree = "SOURCE_ROOT"; }; 45CC11D2029BA2CEAE1B0F76 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_CharPointer_UTF16.h"; path = "../../JuceLibraryCode/modules/juce_core/text/juce_CharPointer_UTF16.h"; sourceTree = "SOURCE_ROOT"; }; @@ -436,6 +439,7 @@ 78934C6C88D2B35DEF15BAB8 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_AudioUnitPluginFormat.mm"; path = "../../JuceLibraryCode/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm"; sourceTree = "SOURCE_ROOT"; }; 78A82E89AC0283CC1329E84E = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Timer.h"; path = "../../JuceLibraryCode/modules/juce_events/timers/juce_Timer.h"; sourceTree = "SOURCE_ROOT"; }; 78CA76788217B98287D9E007 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "fm_op_kernel.cc"; path = "../../Source/msfa/fm_op_kernel.cc"; sourceTree = "SOURCE_ROOT"; }; + 7936BBAA586387B2FAFB958B = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = PluginData.cpp; path = ../../Source/PluginData.cpp; sourceTree = "SOURCE_ROOT"; }; 7A0FB6545BA2E344A1F45EA5 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Decibels.h"; path = "../../JuceLibraryCode/modules/juce_audio_basics/effects/juce_Decibels.h"; sourceTree = "SOURCE_ROOT"; }; 7A26D67672786E0663369D49 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_IIRFilterAudioSource.cpp"; path = "../../JuceLibraryCode/modules/juce_audio_basics/sources/juce_IIRFilterAudioSource.cpp"; sourceTree = "SOURCE_ROOT"; }; 7A38190CB0652B0EBA02100C = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_FileFilter.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_FileFilter.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -677,6 +681,7 @@ C48DAE373124C258F3414CDB = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_GIFLoader.cpp"; path = "../../JuceLibraryCode/modules/juce_graphics/image_formats/juce_GIFLoader.cpp"; sourceTree = "SOURCE_ROOT"; }; C49F636E4677A7C8C62A9859 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Synthesiser.h"; path = "../../JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h"; sourceTree = "SOURCE_ROOT"; }; C4A2C1FDE57CCF33BE778B39 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AppleRemote.h"; path = "../../JuceLibraryCode/modules/juce_gui_extra/misc/juce_AppleRemote.h"; sourceTree = "SOURCE_ROOT"; }; + C56E401381FF968837F82364 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PluginData.h; path = ../../Source/PluginData.h; sourceTree = "SOURCE_ROOT"; }; C5E92613992AB74C2E715271 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ApplicationCommandManager.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.cpp"; sourceTree = "SOURCE_ROOT"; }; C6559A509BD759234BFFCA5D = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_TooltipWindow.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/windows/juce_TooltipWindow.cpp"; sourceTree = "SOURCE_ROOT"; }; C6928FE8579AE1980061CA43 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dx7note.h; path = ../../Source/msfa/dx7note.h; sourceTree = "SOURCE_ROOT"; }; @@ -729,6 +734,7 @@ D8498304CBB374B2800442D4 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_LassoComponent.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/mouse/juce_LassoComponent.h"; sourceTree = "SOURCE_ROOT"; }; D90A42D47F3DD9C505D8A925 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_SystemStats.h"; path = "../../JuceLibraryCode/modules/juce_core/system/juce_SystemStats.h"; sourceTree = "SOURCE_ROOT"; }; D921C8001631F2FC4D7EFF9D = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_KeyboardFocusTraverser.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/keyboard/juce_KeyboardFocusTraverser.h"; sourceTree = "SOURCE_ROOT"; }; + D984CE634945077E682B48F3 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DXComponents.cpp; path = ../../Source/DXComponents.cpp; sourceTree = "SOURCE_ROOT"; }; DA27D90A90F1795DCD9DA064 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_Value.cpp"; path = "../../JuceLibraryCode/modules/juce_data_structures/values/juce_Value.cpp"; sourceTree = "SOURCE_ROOT"; }; DA4359972E065615EEF392EB = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ProgressBar.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/widgets/juce_ProgressBar.cpp"; sourceTree = "SOURCE_ROOT"; }; DAEFEE4711393EBF6BC1EB3A = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_DropShadowEffect.h"; path = "../../JuceLibraryCode/modules/juce_graphics/effects/juce_DropShadowEffect.h"; sourceTree = "SOURCE_ROOT"; }; @@ -878,19 +884,23 @@ 3BE8F91A99E8F48CB9F10C1F, 68D35AFE11BAA35EAE497D47 ); name = msfa; sourceTree = ""; }; 29B923E6EB12F97B68585AFC = { isa = PBXGroup; children = ( + 45ADFD8885BE76C7F7D999AC, + 5C0A1B7E2BF8FCAF5A1E8616, + 59D15F780D468B587F9C7E78, + EA6FC4F1F0D6EAE661569905, + 7936BBAA586387B2FAFB958B, + C56E401381FF968837F82364, + BDC5059F1563FD8DD69AD324, + 018D0FB9E97B68D2EB3E3F72, + BD25F7AC4728A7875B6AE9D5, 19CEF599CB23958AC63D427E, 4B70CBF4DB4E571EDF5D3114, 838E63F5800CA577B92EF6AE, C2AA393651CBC37DCD7718BD, - BDC5059F1563FD8DD69AD324, A02775EA788AD4BF7DD1B1A1, 29D6A187B80D22EB609C256D, - 45ADFD8885BE76C7F7D999AC, - 5C0A1B7E2BF8FCAF5A1E8616, - 018D0FB9E97B68D2EB3E3F72, - BD25F7AC4728A7875B6AE9D5, - 59D15F780D468B587F9C7E78, - EA6FC4F1F0D6EAE661569905, + D984CE634945077E682B48F3, + 4567FB06348FF519FDC6D698, 8BADEB7BF1A65E83A7A1736D, DC75DFCDFCDB425927B11EC0 ); name = Source; sourceTree = ""; }; C21CEF3B473FDC99270B7623 = { isa = PBXGroup; children = ( @@ -1930,8 +1940,9 @@ 9D042F9D005532F763A72C26, E293B9570C97E4BAD129D4A2 ); runOnlyForDeploymentPostprocessing = 0; }; 9DB7317ADCFFCEAB747A09AF = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - C510246D7D5E162C9DE63DDE, - 082D6FF34EFF195C3A3B0CFB, + 1CBFE444B43C89E749602B7F, + 623AFA9E78826CA0136251DF, + 8BE2A084394DA3E45DDB5646, 3AB728E101D7B85DD39C5CC8, FAC9C3E771D11FDA4DFAF17E, 47C317B0F77A29ECA0400B2B, @@ -1941,10 +1952,11 @@ 434647C21C803FA8A4D44A70, 95105DC8536836A06FD5C7BB, 0D3132A8B412AE9E63024927, - D5A4D43A16EA4C71D53E96CD, - 1CBFE444B43C89E749602B7F, 478699B4EF80A1A1C0D34C10, - 623AFA9E78826CA0136251DF, + C510246D7D5E162C9DE63DDE, + 082D6FF34EFF195C3A3B0CFB, + D5A4D43A16EA4C71D53E96CD, + 8121E10419E2D99645EA254E, B18C192606DF6079E7B9AEB9, 1C87DA0B69D67481FC6CF4FD, E3FA856CA4DB2009BB0F13E7, diff --git a/Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate b/Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate index 6ef498bde67aec5f284cdb2fba337bdaabc3fcee..49520041b32637a390654db6056f23e39b974b6a 100644 GIT binary patch literal 87920 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%0DQ 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
0A&r9`^t2fkS&9jgHZP^fv_r_ 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 literal 87870 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�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 Giu?}|j%3vU diff --git a/Builds/VisualStudio2012/Dexed.vcxproj b/Builds/VisualStudio2012/Dexed.vcxproj index 744d5bf..9ccec7a 100644 --- a/Builds/VisualStudio2012/Dexed.vcxproj +++ b/Builds/VisualStudio2012/Dexed.vcxproj @@ -133,8 +133,9 @@ - - + + + @@ -144,10 +145,11 @@ - - - + + + + true @@ -1111,8 +1113,9 @@ - - + + + @@ -1126,10 +1129,11 @@ - - - + + + + diff --git a/Builds/VisualStudio2012/Dexed.vcxproj.filters b/Builds/VisualStudio2012/Dexed.vcxproj.filters index 93a09a1..3569e1b 100644 --- a/Builds/VisualStudio2012/Dexed.vcxproj.filters +++ b/Builds/VisualStudio2012/Dexed.vcxproj.filters @@ -268,10 +268,13 @@ - + Dexed\Source - + + Dexed\Source + + Dexed\Source @@ -301,16 +304,19 @@ Dexed\Source\msfa - + Dexed\Source - + Dexed\Source - + Dexed\Source - + + Dexed\Source + + Dexed\Source @@ -1383,10 +1389,13 @@ - + Dexed\Source - + + Dexed\Source + + Dexed\Source @@ -1428,16 +1437,19 @@ Dexed\Source\msfa - + Dexed\Source - + Dexed\Source - + Dexed\Source - + + Dexed\Source + + Dexed\Source diff --git a/Dexed.jucer b/Dexed.jucer index c91259f..9921676 100644 --- a/Dexed.jucer +++ b/Dexed.jucer @@ -14,13 +14,14 @@ - - - - + + + + + + @@ -45,17 +46,21 @@ - - - - - - + + + + + + + + diff --git a/Source/DXComponents.cpp b/Source/DXComponents.cpp new file mode 100644 index 0000000..74d2824 --- /dev/null +++ b/Source/DXComponents.cpp @@ -0,0 +1,246 @@ +/** + * + * Copyright (c) 2014 Pascal Gauthier. + * + * This program is free software; you can redistribute it and/or + * modify it 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. + * + * This program 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 this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include "DXComponents.h" +#include "PluginProcessor.h" +#include "msfa/pitchenv.h" + +/** + * Algorithm arrangements, based on the DX1 display. + */ +static const char algoArr[][13] = { + // 1 2 3 4 5 6 7 8 9 A B C D + { 0, 0, 1, 3, 0, 0, 0, 2, 4, 0, 0, 5, -6 }, // 1 + { 0, 0, 1, 3, 0, 0, 0, -2, 4, 0, 0, 5, 6 }, // 2 + { 0, 0, 1, 4, 0, 0, 0, 2, 5, 0, 3, -6, 0 }, // 3 + { 0, 0, 1, -4, 0, 0, 0, 2, -5, 0, 3, -6, 0 }, // 4 + { 0, 1, 3, 5, 0, 0, 2, 4, -6, 0, 0, 0, 0 }, // 5 + { 0, 1, 3, -5, 0, 0, 2, 4, -6, 0, 0, 0, 0 }, // 6 + { 0, 1, 3, 0, 0, 0, -2, 4, 5, 0, 0, 6, 0 }, // 7 + { 0, 1, 3, 0, 0, 0, 2, -4, 5, 0, 0, 6, 0 }, // 8 + { 0, 1, 3, 0, 0, 0, -2, 4, 5, 0, 0, 6, 0 }, // 9 + { 0, 0, 4, 1, 0, 0, 5, 6, 2, 0, 0, -3, 0 }, // 10 + { 0, 0, 4, 1, 0, 0, 5, -6, 2, 0, 0, 3, 0 }, // 11 + { 0, 0, 3, 0, 1, 0, 4, 5, 6, -2, 0, 0, 0 }, // 12 + { 0, 0, 3, 0, 1, 0, 4, 5, -6, 2, 0, 0, 0 }, // 13 + // 1 2 3 4 5 6 7 8 9 A B C D + { 0, 0, 1, 3, 0, 0, 0, 2, 4, 0, 5, -6, 0 }, // 14 + { 0, 0, 1, 3, 0, 0, 0, -2, 4, 0, 5, 6, 0 }, // 15 + { 0, 0, 1, 0, 0, 0, 2, 3, 5, 0, 4, -6, 0 }, // 16 + { 0, 0, 1, 0, 0, 0, -2, 3, 5, 0, 4, 6, 0 }, // 17 + { 0, 0, 1, 0, 0, 0, 2, -3, 4, 0, 0, 5, 6 }, // 18 + { 0, 0, 1, 4, 5, 0, 0, 2, -6, 0, 3, 0, 0 }, // 19 + { 0, 1, 2, 0, 4, 0, -3, 0, 5, 6, 0, 0, 0 }, // 20 + { 0, 1, 2, 4, 5, 0, -3, 0, 6, 0, 0, 0, 0 }, // 21 + { 0, 1, 3, 4, 5, 0, 2, 0, -6, 0, 0, 0, 0 }, // 22 + { 0, 1, 2, 4, 5, 0, 0, 3, -6, 0, 0, 0, 0 }, // 23 + { 1, 2, 3, 4, 5, 0, 0, 0, -6, 0, 0, 0, 0 }, // 24 + { 1, 2, 3, 4, 5, 0, 0, 0, -6, 0, 0, 0, 0 }, // 25 + { 0, 1, 2, 0, 4, 0, 0, 3, 5, -6, 0, 0, 0 }, // 26 + // 1 2 3 4 5 6 7 8 9 A B C D + { 0, 1, 2, 0, 4, 0, 0, -3, 5, 6, 0, 0, 0 }, // 27 + { 0, 1, 3, 6, 0, 0, 2, 4, 0, 0, -5, 0, 0 }, // 28 + { 0, 1, 2, 3, 5, 0, 0, 0, 4, -6, 0, 0, 0 }, // 29 + { 0, 1, 2, 3, 6, 0, 0, 0, 4, 0, 0, -5, 0 }, // 30 + { 1, 2, 3, 4, 5, 0, 0, 0, 0, -6, 0, 0, 0 }, // 31 + { 1, 2, 3, 4, 5, -6, 0, 0, 0, 0, 0, 0, 0 } // 32 +}; + +static char TMP_LEVEL_PTR[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +AlgoDisplay::AlgoDisplay() { + static char tmpAlgo = 0; + algo = &tmpAlgo; +} + +void AlgoDisplay::paint(Graphics &g) { + int alg; + + if ( *algo <= 31 ) { + alg = *algo; + } else { + alg = 31; + } + const char *arr = algoArr[alg]; + + g.setColour (Colours::black.withAlpha(0.1f)); + g.fillRoundedRectangle (0.0f, 0.0f, (float) getWidth(), (float) getHeight(), 1.0f); + + for(int i=0;i<13;i++) { + int target = arr[i]; + if ( target == 0 ) + continue; + + if ( i < 6 ) { + drawOp(g, i, 3, target); + continue; + } + + if ( i < 10 ){ + drawOp(g, (i-6)+1, 2, target); + continue; + } + + if ( i < 12 ) { + drawOp(g, (i-10)+2, 1, target); + continue; + } + + // last one + drawOp(g, (i-12)+3, 0, target); + } + + String algoTxt; + algoTxt << (alg+1); + g.drawText(algoTxt, 5, 1, 21, 14, Justification::left, true); +} + +void AlgoDisplay::drawOp(Graphics &g, int x, int y, int num) { + String txt; + txt << abs(num); + + int offx = 24; + int offy = 17; + + g.setColour(Colour(0xFF0FC00F)); + g.fillRect(x*offx+4, y*offy+3, offx-2, offy-1); + g.setColour(Colour(0xFFFFFFFF)); + g.drawText(txt, x*offx+3, y*offy+2, offx+2, offy+2, Justification::centred, true); + if ( num < 0 ) { + g.setColour(Colour(0xFFFFFFFF)); + int x1 = (x*offx) + 24; + g.drawLine(x1+1, y*offy+3, x1+1, y*offy+offy+2, 3); + } +} + +EnvDisplay::EnvDisplay() { + pvalues = (char *) &TMP_LEVEL_PTR; +} + +void EnvDisplay::paint(Graphics &g) { + int rate[4]; + int level[4]; + + g.setColour(Colours::black.withAlpha(0.1f)); + g.fillRoundedRectangle (0.0f, 0.0f, (float) getWidth(), (float) getHeight(), 1.0f); + g.setColour(Colours::white); + + for (int i = 0; i < 4; i++) { + rate[i] = pvalues[i]; + level[i] = pvalues[i+4]; + } + + env.init(rate, level, 99 << 5, 0); + env.keydown(true); + for (int i = 0; i < 72; i++) { + int32_t pos = env.getsample(); + for (int j = 0; j < 16; j++) { + env.getsample(); + } + g.setPixel(i, 32 - (sqrt(pos) / 512)); + } + env.keydown(false); + for (int i = 0; i < 24; i++) { + int32_t pos = env.getsample(); + for (int j = 0; j < 16; j++) { + env.getsample(); + } + g.setPixel(i + 72, 32 - (sqrt(pos) / 512)); + } +} + +PitchEnvDisplay::PitchEnvDisplay() { + pvalues = (char *) &TMP_LEVEL_PTR; +} + +void PitchEnvDisplay::paint(Graphics &g) { + g.setColour(Colours::black.withAlpha(0.1f)); + g.fillRoundedRectangle (0.0f, 0.0f, (float) getWidth(), (float) getHeight(), 1.0f); + g.setColour(Colours::white); + + char *levels = pvalues + 4; + char *rates = pvalues; + + float dist[4]; + float total; + + int old = pitchenv_tab[levels[3]] + 128; + // find the scale + + for(int i=0;i<4;i++) { + int nw = pitchenv_tab[levels[i]] + 128; + dist[i] = ((float)abs(nw - old)) / pitchenv_rate[rates[i]]; + total += dist[i]; + old = nw; + } + + if ( total < 0.00001 ) { + dist[0] = dist[1] = dist[2] = dist[3] = 1; + total = 4; + } + + TRACE("total %f", total); + TRACE("level %d %d %d %d", levels[0], levels[1], levels[2], levels[3]); + TRACE("dist %f %f %f %f", dist[0], dist[1], dist[2], dist[3]); + + // TODO : this is WIP + float ratio = 96 / total; + + int oldx = 0; + int oldy = (pitchenv_tab[levels[3]] + 128) / 10; + + for(int i=0;i<4;i++) { + int newx = dist[i] * ratio + oldx; + int newy = (pitchenv_tab[levels[i]] + 128) / 10; + + g.drawLine(oldx, oldy, newx, newy, 2); + + oldx = newx; + oldy = newy; + } +} + + +void VuMeter::paint(Graphics &g) { + + // taken from the drawLevelMeter ; + float width = getWidth(); + float height = getHeight(); + + g.setColour (Colours::black); + g.fillRoundedRectangle (0.0f, 0.0f, (float) width, (float) height, 0); + /*g.setColour (Colours::black.withAlpha (0.2f)); + g.drawRoundedRectangle (1.0f, 1.0f, width - 2.0f, height - 2.0f, 3.0f, 1.0f);*/ + + const int totalBlocks = 16; + const int numBlocks = roundToInt (totalBlocks * v); + const float h = (height - 6.0f) / (float) totalBlocks; + + for (int i = 0; i < totalBlocks; ++i) { + g.setColour (Colours::red); + if (i >= numBlocks) + g.setColour (Colours::red.withAlpha (0.2f)); + else + g.setColour (Colours::red); + //g.fillRoundedRectangle (3.0f + i * w + w * 0.1f, 3.0f, w * 0.8f, height - 6.0f, w * 0.4f); + + g.fillRoundedRectangle (3.0f, (height-3.0f) - (3.0f + i * h + h * 0.1f) , width - 6.0f, h * 0.8f, 0); + } +} \ No newline at end of file diff --git a/Source/DXComponents.h b/Source/DXComponents.h new file mode 100644 index 0000000..4da3d46 --- /dev/null +++ b/Source/DXComponents.h @@ -0,0 +1,58 @@ +/** + * + * Copyright (c) 2014 Pascal Gauthier. + * + * This program is free software; you can redistribute it and/or + * modify it 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. + * + * This program 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 this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef DXCOMPONENTS_H_INCLUDED +#define DXCOMPONENTS_H_INCLUDED + +#include "../JuceLibraryCode/JuceHeader.h" + +#include "msfa/env.h" + +class EnvDisplay : public Component { + Env env; +public: + EnvDisplay(); + char *pvalues; + void paint(Graphics &g); +}; + +class PitchEnvDisplay : public Component { + char rvalues[8]; +public: + PitchEnvDisplay(); + char *pvalues; + void paint(Graphics &g); +}; + +class AlgoDisplay : public Component { + void drawOp(Graphics &g, int x, int y, int num); +public: + AlgoDisplay(); + char *algo; + void paint(Graphics &g); +}; + +class VuMeter: public Component { + void paint(Graphics &g); + public : + float v; +}; + +#endif // DXCOMPONENTS_H_INCLUDED diff --git a/Source/DXLookNFeel.cpp b/Source/DXLookNFeel.cpp index 2bd95c7..272f249 100644 --- a/Source/DXLookNFeel.cpp +++ b/Source/DXLookNFeel.cpp @@ -19,226 +19,6 @@ */ #include "DXLookNFeel.h" -#include "PluginProcessor.h" - -/** - * Algorithm arrangements, based on the DX1 display. - */ -static const char algoArr[][13] = { - // 1 2 3 4 5 6 7 8 9 A B C D - { 0, 0, 1, 3, 0, 0, 0, 2, 4, 0, 0, 5, -6 }, // 1 - { 0, 0, 1, 3, 0, 0, 0, -2, 4, 0, 0, 5, 6 }, // 2 - { 0, 0, 1, 4, 0, 0, 0, 2, 5, 0, 3, -6, 0 }, // 3 - { 0, 0, 1, -4, 0, 0, 0, 2, -5, 0, 3, -6, 0 }, // 4 - { 0, 1, 3, 5, 0, 0, 2, 4, -6, 0, 0, 0, 0 }, // 5 - { 0, 1, 3, -5, 0, 0, 2, 4, -6, 0, 0, 0, 0 }, // 6 - { 0, 1, 3, 0, 0, 0, -2, 4, 5, 0, 0, 6, 0 }, // 7 - { 0, 1, 3, 0, 0, 0, 2, -4, 5, 0, 0, 6, 0 }, // 8 - { 0, 1, 3, 0, 0, 0, -2, 4, 5, 0, 0, 6, 0 }, // 9 - { 0, 0, 4, 1, 0, 0, 5, 6, 2, 0, 0, -3, 0 }, // 10 - { 0, 0, 4, 1, 0, 0, 5, -6, 2, 0, 0, 3, 0 }, // 11 - { 0, 0, 3, 0, 1, 0, 4, 5, 6, -2, 0, 0, 0 }, // 12 - { 0, 0, 3, 0, 1, 0, 4, 5, -6, 2, 0, 0, 0 }, // 13 - // 1 2 3 4 5 6 7 8 9 A B C D - { 0, 0, 1, 3, 0, 0, 0, 2, 4, 0, 5, -6, 0 }, // 14 - { 0, 0, 1, 3, 0, 0, 0, -2, 4, 0, 5, 6, 0 }, // 15 - { 0, 0, 1, 0, 0, 0, 2, 3, 5, 0, 4, -6, 0 }, // 16 - { 0, 0, 1, 0, 0, 0, -2, 3, 5, 0, 4, 6, 0 }, // 17 - { 0, 0, 1, 0, 0, 0, 2, -3, 4, 0, 0, 5, 6 }, // 18 - { 0, 0, 1, 4, 5, 0, 0, 2, -6, 0, 3, 0, 0 }, // 19 - { 0, 1, 2, 0, 4, 0, -3, 0, 5, 6, 0, 0, 0 }, // 20 - { 0, 1, 2, 4, 5, 0, -3, 0, 6, 0, 0, 0, 0 }, // 21 - { 0, 1, 3, 4, 5, 0, 2, 0, -6, 0, 0, 0, 0 }, // 22 - { 0, 1, 2, 4, 5, 0, 0, 3, -6, 0, 0, 0, 0 }, // 23 - { 1, 2, 3, 4, 5, 0, 0, 0, -6, 0, 0, 0, 0 }, // 24 - { 1, 2, 3, 4, 5, 0, 0, 0, -6, 0, 0, 0, 0 }, // 25 - { 0, 1, 2, 0, 4, 0, 0, 3, 5, -6, 0, 0, 0 }, // 26 - // 1 2 3 4 5 6 7 8 9 A B C D - { 0, 1, 2, 0, 4, 0, 0, -3, 5, 6, 0, 0, 0 }, // 27 - { 0, 1, 3, 6, 0, 0, 2, 4, 0, 0, -5, 0, 0 }, // 28 - { 0, 1, 2, 3, 5, 0, 0, 0, 4, -6, 0, 0, 0 }, // 29 - { 0, 1, 2, 3, 6, 0, 0, 0, 4, 0, 0, -5, 0 }, // 30 - { 1, 2, 3, 4, 5, 0, 0, 0, 0, -6, 0, 0, 0 }, // 31 - { 1, 2, 3, 4, 5, -6, 0, 0, 0, 0, 0, 0, 0 } // 32 -}; - -AlgoDisplay::AlgoDisplay() { - static char tmpAlgo = 0; - algo = &tmpAlgo; -} - -/** - * For now, this is hardcoded 126x56 (21x14 each) - */ -void AlgoDisplay::paint(Graphics &g) { - int alg; - - if ( *algo <= 31 ) { - alg = *algo; - } else { - alg = 31; - } - const char *arr = algoArr[alg]; - - g.setColour (Colours::black.withAlpha(0.1f)); - g.fillRoundedRectangle (0.0f, 0.0f, (float) getWidth(), (float) getHeight(), 1.0f); - - for(int i=0;i<13;i++) { - int target = arr[i]; - if ( target == 0 ) - continue; - - if ( i < 6 ) { - drawOp(g, i, 3, target); - continue; - } - - if ( i < 10 ){ - drawOp(g, (i-6)+1, 2, target); - continue; - } - - if ( i < 12 ) { - drawOp(g, (i-10)+2, 1, target); - continue; - } - - // last one - drawOp(g, (i-12)+3, 0, target); - } - - String algoTxt; - algoTxt << (alg+1); - g.drawText(algoTxt, 5, 1, 21, 14, Justification::left, true); -} - -void AlgoDisplay::drawOp(Graphics &g, int x, int y, int num) { - String txt; - txt << abs(num); - - int offx = 24; - int offy = 17; - - g.setColour(Colour(0xFF0FC00F)); - g.fillRect(x*offx+4, y*offy+3, offx-2, offy-1); - g.setColour(Colour(0xFFFFFFFF)); - g.drawText(txt, x*offx+3, y*offy+2, offx+2, offy+2, Justification::centred, true); - if ( num < 0 ) { - g.setColour(Colour(0xFFFFFFFF)); - int x1 = (x*offx) + 24; - g.drawLine(x1+1, y*offy+3, x1+1, y*offy+offy+2, 3); - } -} - -void EnvDisplay::paint(Graphics &g) { - int rate[4]; - int level[4]; - - g.setColour(Colours::black.withAlpha(0.1f)); - g.fillRoundedRectangle (0.0f, 0.0f, (float) getWidth(), (float) getHeight(), 1.0f); - g.setColour(Colours::white); - - for (int i = 0; i < 4; i++) { - rate[i] = s_rate[i]->getValue(); - level[i] = s_level[i]->getValue(); - } - - env.init(rate, level, 99 << 5, 0); - env.keydown(true); - for (int i = 0; i < 72; i++) { - int32_t pos = env.getsample(); - for (int j = 0; j < 16; j++) { - env.getsample(); - } - g.setPixel(i, 32 - (sqrt(pos) / 512)); - } - env.keydown(false); - for (int i = 0; i < 24; i++) { - int32_t pos = env.getsample(); - for (int j = 0; j < 16; j++) { - env.getsample(); - } - g.setPixel(i + 72, 32 - (sqrt(pos) / 512)); - } -} - -PitchEnvDisplay::PitchEnvDisplay() { - static char tmpDisplay[8]; - memset(&tmpDisplay, 0x00, 8); - pvalues = (char *) &tmpDisplay; -} - -void PitchEnvDisplay::paint(Graphics &g) { - g.setColour(Colours::black.withAlpha(0.1f)); - g.fillRoundedRectangle (0.0f, 0.0f, (float) getWidth(), (float) getHeight(), 1.0f); - g.setColour(Colours::white); - - char *levels = pvalues; - char *rates = pvalues + 4; - - float dist[4]; - float total; - - int old = pitchenv_tab[levels[3]] + 128; - // find the scale - - for(int i=0;i<4;i++) { - int nw = pitchenv_tab[levels[i]] + 128; - dist[i] = ((float)abs(nw - old)) / pitchenv_rate[rates[i]]; - total += dist[i]; - old = nw; - } - - if ( total == 0 ) { - dist[0] = 1; - total = 1; - } - //TRACE("DISPLAY %f %f %f %f", dist[0], dist[1], dist[2], dist[3]); - - // TODO : this is WIP - float ratio = 96 / total; - - int oldx = 0; - int oldy = (pitchenv_tab[levels[3]] + 128) / 10; - - for(int i=0;i<4;i++) { - int newx = dist[i] * ratio + oldx; - int newy = (pitchenv_tab[levels[i]] + 128) / 10; - - g.drawLine(oldx, oldy, newx, newy, 2); - - oldx = newx; - oldy = newy; - } -} - - -void VuMeter::paint(Graphics &g) { - - // taken from the drawLevelMeter ; - float width = getWidth(); - float height = getHeight(); - - g.setColour (Colours::black); - g.fillRoundedRectangle (0.0f, 0.0f, (float) width, (float) height, 0); - /*g.setColour (Colours::black.withAlpha (0.2f)); - g.drawRoundedRectangle (1.0f, 1.0f, width - 2.0f, height - 2.0f, 3.0f, 1.0f);*/ - - const int totalBlocks = 16; - const int numBlocks = roundToInt (totalBlocks * v); - const float h = (height - 6.0f) / (float) totalBlocks; - - for (int i = 0; i < totalBlocks; ++i) { - g.setColour (Colours::red); - if (i >= numBlocks) - g.setColour (Colours::red.withAlpha (0.2f)); - else - g.setColour (Colours::red); - //g.fillRoundedRectangle (3.0f + i * w + w * 0.1f, 3.0f, w * 0.8f, height - 6.0f, w * 0.4f); - - g.fillRoundedRectangle (3.0f, (height-3.0f) - (3.0f + i * h + h * 0.1f) , width - 6.0f, h * 0.8f, 0); - } -} DXLookNFeel::DXLookNFeel() { setColour(TextButton::buttonColourId,Colour(0xFF0FC00F)); diff --git a/Source/DXLookNFeel.h b/Source/DXLookNFeel.h index 2312014..fe295fc 100644 --- a/Source/DXLookNFeel.h +++ b/Source/DXLookNFeel.h @@ -22,49 +22,10 @@ #define DXLOOKNFEEL_H_INCLUDED #include "../JuceLibraryCode/JuceHeader.h" -#include "msfa/env.h" -#include "msfa/pitchenv.h" - -class EnvDisplay : public Component { - Env env; -public: - Slider *s_rate[4]; - Slider *s_level[4]; - - void paint(Graphics &g); -}; - -class PitchEnvDisplay : public Component { - char rvalues[8]; - char render[96]; - - void renderDisplay(); -public: - PitchEnvDisplay(); - - char *pvalues; - - void paint(Graphics &g); -}; - -class AlgoDisplay : public Component { - void drawOp(Graphics &g, int x, int y, int num); - -public: - AlgoDisplay(); - char *algo; - - void paint(Graphics &g); -}; class DXLookNFeel : public LookAndFeel_V3 { public: DXLookNFeel(); }; -class VuMeter: public Component { - void paint(Graphics &g); -public : - float v; -}; #endif // DXLOOKNFEEL_H_INCLUDED diff --git a/Source/GlobalEditor.h b/Source/GlobalEditor.h index 5b42147..9689fc5 100644 --- a/Source/GlobalEditor.h +++ b/Source/GlobalEditor.h @@ -23,7 +23,7 @@ //[Headers] -- You can add your own extra header files here -- #include "JuceHeader.h" #include "PluginProcessor.h" -#include "DXLookNFeel.h" +#include "DXComponents.h" //[/Headers] diff --git a/Source/OperatorEditor.cpp b/Source/OperatorEditor.cpp index 7996748..caee165 100644 --- a/Source/OperatorEditor.cpp +++ b/Source/OperatorEditor.cpp @@ -196,14 +196,6 @@ OperatorEditor::OperatorEditor () //[Constructor] You can add your own custom stuff here.. - envDisplay->s_rate[0] = s_egv1; - envDisplay->s_rate[1] = s_egv2; - envDisplay->s_rate[2] = s_egv3; - envDisplay->s_rate[3] = s_egv4; - envDisplay->s_level[0] = s_egl1; - envDisplay->s_level[1] = s_egl2; - envDisplay->s_level[2] = s_egl3; - envDisplay->s_level[3] = s_egl4; //[/Constructor] } @@ -447,15 +439,16 @@ void OperatorEditor::bind(DexedAudioProcessor *parent, int op) { parent->opCtrl[op].sclRate->bind(sclRateScaling); parent->opCtrl[op].ampModSens->bind(ampModSens); parent->opCtrl[op].velModSens->bind(keyVelSens); + + int offset = parent->opCtrl[op].egRate[0]->getOffset(); + envDisplay->pvalues = &(parent->data[offset]); } - void OperatorEditor::updateGain(float v) { vu->v = v; vu->repaint(); } - void OperatorEditor::updateDisplay() { float freq = opCoarse->getValue(); float fine = opFine->getValue(); diff --git a/Source/OperatorEditor.h b/Source/OperatorEditor.h index d5f0171..bd92829 100644 --- a/Source/OperatorEditor.h +++ b/Source/OperatorEditor.h @@ -23,6 +23,7 @@ //[Headers] -- You can add your own extra header files here -- #include "JuceHeader.h" #include "PluginProcessor.h" +#include "DXComponents.h" #include "DXLookNFeel.h" //[/Headers] diff --git a/Source/PluginData.cpp b/Source/PluginData.cpp new file mode 100644 index 0000000..4df1558 --- /dev/null +++ b/Source/PluginData.cpp @@ -0,0 +1,293 @@ +/** + * + * Copyright (c) 2014 Pascal Gauthier. + * + * This program is free software; you can redistribute it and/or + * modify it 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. + * + * This program 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 this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include + +#include "PluginParam.h" +#include "PluginProcessor.h" +#include "PluginData.h" + + +uint8_t sysexChecksum(const char *sysex) { + uint8_t sum = 0; + for (int i=0; i<4096; i++) + sum = (sum + sysex[i]) % (1 << 8); + return ((1 << 8) - sum); +} + + +void extractProgramNames(const char *block, StringArray &dest) { + char programName[11]; + + dest.clear(); + + for (int i = 0; i < 32; i++) { + memcpy(programName, block + ((i * 128) + 118), 11); + + for (int j = 0; j < 10; j++) { + char c = (unsigned char) programName[j]; + switch (c) { + case 92: + c = 'Y'; + break; /* yen */ + case 126: + c = '>'; + break; /* >> */ + case 127: + c = '<'; + break; /* << */ + default: + if (c < 32 || c > 127) + c = 32; + break; + } + programName[j] = c; + } + programName[10] = 0; + + dest.add(String(programName)); + } +} + +int DexedAudioProcessor::importSysex(const char *imported) { + memcpy(sysex, imported + 6, 4096); + + uint8_t checksum = sysexChecksum(sysex); + extractProgramNames(sysex, programNames); + + if ( checksum != imported[4102] ) { + TRACE("sysex import checksum doesnt match"); + return 1; + } + + return 0; +} + +void DexedAudioProcessor::exportSysex(char *dest) { + uint8_t header[] = { 0xF0, 0x43, 0x00, 0x09, 0x20, 0x00 }; + memcpy(dest, header, 6); + + // copy 32 voices + memcpy(dest+6, sysex, 4096); + + // make checksum for dump + uint8_t footer[] = { sysexChecksum(sysex), 0xF7 }; + + memcpy(dest+4102, footer, 2); +} + +/** + * This function normalize data that comes from corrupted sysex data. + * It used to avoid engine crashing upon extrem values + */ +char normparm(char value, char max) { + if ( value <= max ) + return value; + + // if this is beyond the max, we expect a 0-255 range, normalize this + // to the expected return value; and this value as a random data. + + return ((float)value)/255 * max; +} + +void DexedAudioProcessor::unpackProgram(int idx) { + char *bulk = sysex + (idx * 128); + + for (int op = 0; op < 6; op++) { + // eg rate and level, brk pt, depth, scaling + memcpy(data + op * 21, bulk + op * 17, 11); + char leftrightcurves = bulk[op * 17 + 11]; + data[op * 21 + 11] = leftrightcurves & 3; + data[op * 21 + 12] = (leftrightcurves >> 2) & 3; + char detune_rs = bulk[op * 17 + 12]; + data[op * 21 + 13] = detune_rs & 7; + char kvs_ams = bulk[op * 17 + 13]; + data[op * 21 + 14] = kvs_ams & 3; + data[op * 21 + 15] = kvs_ams >> 2; + data[op * 21 + 16] = bulk[op * 17 + 14]; // output level + char fcoarse_mode = bulk[op * 17 + 15]; + data[op * 21 + 17] = fcoarse_mode & 1; + data[op * 21 + 18] = fcoarse_mode >> 1; + data[op * 21 + 19] = bulk[op * 17 + 16]; // fine freq + data[op * 21 + 20] = detune_rs >> 3; + } + memcpy(data + 126, bulk + 102, 9); // pitch env, algo + char oks_fb = bulk[111]; + data[135] = oks_fb & 7; + data[136] = oks_fb >> 3; + memcpy(data + 137, bulk + 112, 4); // lfo + char lpms_lfw_lks = bulk[116]; + data[141] = lpms_lfw_lks & 1; + data[142] = (lpms_lfw_lks >> 1) & 7; + data[143] = lpms_lfw_lks >> 4; + memcpy(data + 144, bulk + 117, 11); // transpose, name + data[155] = 1; // operator on/off + data[156] = 1; + data[157] = 1; + data[158] = 1; + data[159] = 1; + data[160] = 1; +} + +void DexedAudioProcessor::packProgram(int idx, const char *name) { + char *bulk = sysex + (idx * 128); + + for(int op = 0; op < 6; op++) { + // eg rate and level, brk pt, depth, scaling + memcpy(bulk + op * 17, data + op * 21, 11); + int pp = op*17; + int up = op*21; + + // left curves + bulk[pp+11] = (data[up+11]&0x03) | ((data[up+12]&0x03) << 2); + bulk[pp+12] = (data[up+13]&0x07) | ((data[up+20]&0x0f) << 3); + // kvs_ams + bulk[pp+13] = (data[up+14]&0x03) | ((data[up+15]&0x07) << 2); + // output lvl + bulk[pp+14] = data[up+16]; + // fcoarse_mode + bulk[pp+15] = (data[up+17]&0x01) | ((data[up+18]&0x1f) << 1); + // fine freq + bulk[pp+16] = data[up+19]; + } + memcpy(bulk + 102, data + 126, 9); // pitch env, algo + bulk[111] = (data[135]&0x07) | ((data[136]&0x01) << 3); + memcpy(bulk + 112, data + 137, 4); // lfo + bulk[116] = (data[141]&0x01) | (((data[142]&0x07) << 1) | ((data[143]&0x07) << 4)); + bulk[117] = data[144]; + int eos = 0; + for(int i=0; i < 10; i++) { + char c = name[i]; + if ( c == 0 ) + eos = 1; + if ( eos ) { + bulk[117+i] = ' '; + continue; + } + c = c < 32 ? ' ' : c; + c = c > 127 ? ' ' : c; + bulk[117+i] = c; + } + + char programName[11]; + memcpy(programName, bulk+117, 10); + programName[10] = 0; + programNames.set(idx, String(programName)); +} + +void DexedAudioProcessor::updateProgramFromSysex(const uint8 *rawdata) { + memcpy(data, rawdata, 160); + refreshUI = true; +} + +void DexedAudioProcessor::loadBuiltin(int idx) { + InputStream *is = builtin_pgm->createStreamForEntry(idx); + + if ( is == NULL ) { + TRACE("ENTRY IN ZIP NOT FOUND"); + return; + } + + uint8_t syx_data[4104]; + is->read(&syx_data, 4104); + delete is; + + importSysex((char *) &syx_data); +} + +#define CURRENT_PLUGINSTATE_VERSION 2 +struct PluginState { + int version; + uint8_t sysex[4104]; + uint8_t program[161]; + float cutoff; + float reso; + int programNum; +}; + +//============================================================================== +void DexedAudioProcessor::getStateInformation(MemoryBlock& destData) { + // You should use this method to store your parameters in the memory block. + // You could do that either as raw data, or use the XML or ValueTree classes + // as intermediaries to make it easy to save and load complex data. + + // used to SAVE plugin state + + PluginState state; + + state.version = CURRENT_PLUGINSTATE_VERSION; + + exportSysex((char *)(&state.sysex)); + memcpy(state.program, data, 161); + state.cutoff = fx.uiCutoff; + state.reso = fx.uiReso; + state.programNum = currentProgram; + + destData.insert(&state, sizeof(PluginState), 0); +} + +void DexedAudioProcessor::setStateInformation(const void* source, int sizeInBytes) { + // You should use this method to restore your parameters from this memory block, + // whose contents will have been created by the getStateInformation() call. + + // used to LOAD plugin state + + PluginState state; + + if ( sizeInBytes < sizeof(PluginState) ) { + TRACE("too small plugin state size %d", sizeInBytes); + return; + } + + if ( sizeInBytes > sizeof(PluginState) ) { + TRACE("too big plugin state size %d", sizeInBytes); + sizeInBytes = sizeof(PluginState); + } + + memcpy((void *) &state, source, sizeInBytes); + + if ( state.version != CURRENT_PLUGINSTATE_VERSION ) { + TRACE("version of VST chunk is not compatible, bailing out"); + return; + } + + importSysex((char *) state.sysex); + memcpy(data, state.program, 161); + + fx.uiCutoff = state.cutoff; + fx.uiReso = state.reso; + currentProgram = state.programNum; + + lastStateSave = (long) time(NULL); + TRACE("setting VST STATE"); + updateUI(); +} + +//============================================================================== +/*void DexedAudioProcessor::getCurrentProgramStateInformation( + MemoryBlock& destData) { + destData.insert(data, 161, 0); + } + + void DexedAudioProcessor::setCurrentProgramStateInformation(const void* source, + int sizeInBytes) { + memcpy((void *) data, source, sizeInBytes); + updateUI(); + }*/ diff --git a/Source/PluginData.h b/Source/PluginData.h new file mode 100644 index 0000000..cdda13e --- /dev/null +++ b/Source/PluginData.h @@ -0,0 +1,27 @@ +/** + * + * Copyright (c) 2014 Pascal Gauthier. + * + * This program is free software; you can redistribute it and/or + * modify it 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. + * + * This program 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 this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef PLUGINDATA_H_INCLUDED +#define PLUGINDATA_H_INCLUDED + +#include "../JuceLibraryCode/JuceHeader.h" + + +#endif // PLUGINDATA_H_INCLUDED diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp index 323c4bf..1486954 100755 --- a/Source/PluginEditor.cpp +++ b/Source/PluginEditor.cpp @@ -212,10 +212,9 @@ void DexedAudioProcessorEditor::buttonClicked(Button *buttonThatWasClicked) { for(int i=0;ibuiltin_pgm->getNumEntries();i++) { const ZipFile::ZipEntry *e = processor->builtin_pgm->getEntry(i); - cart.add(e->filename.dropLastCharacters(4)); - } + AlertWindow dialog(String("Builtin cartridges"), "", AlertWindow::NoIcon, this); dialog.addComboBox(String("cart"), cart); dialog.addButton("OK", 0, KeyPress(KeyPress::returnKey)); @@ -234,7 +233,7 @@ void DexedAudioProcessorEditor::buttonClicked(Button *buttonThatWasClicked) { if (buttonThatWasClicked == aboutButton) { AlertWindow::showMessageBoxAsync(AlertWindow::NoIcon, "DEXED - DX Emulator 0.3", "https://github.com/asb2m10/dexed\n" - "(c) 2013 Pascal Gauthier\nUnder the GPL v2\n\n" + "(c) 2013-2014 Pascal Gauthier\nUnder the GPL v2\n\n" "Based on Music Synthesizer for Android\nhttps://code.google.com/p/music-synthesizer-for-android"); return; } diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h index 90483eb..ff0d774 100755 --- a/Source/PluginEditor.h +++ b/Source/PluginEditor.h @@ -25,7 +25,7 @@ #include "PluginProcessor.h" #include "OperatorEditor.h" #include "GlobalEditor.h" -#include "DXLookNFeel.h" +#include "DXComponents.h" //============================================================================== /** diff --git a/Source/PluginParam.cpp b/Source/PluginParam.cpp index 2d2a190..01fe8af 100755 --- a/Source/PluginParam.cpp +++ b/Source/PluginParam.cpp @@ -18,8 +18,6 @@ * Boston, MA 02110-1301 USA. */ -#include - #include "PluginParam.h" #include "PluginProcessor.h" #include "PluginEditor.h" @@ -362,155 +360,6 @@ void DexedAudioProcessor::initCtrl() { } } -int DexedAudioProcessor::importSysex(const char *imported) { - memcpy(sysex, imported + 6, 4096); - for (int i = 0; i < 32; i++) { - memcpy(patchNames[i], sysex + ((i * 128) + 118), 11); - - for (int j = 0; j < 10; j++) { - char c = (unsigned char) patchNames[i][j]; - switch (c) { - case 92: - c = 'Y'; - break; /* yen */ - case 126: - c = '>'; - break; /* >> */ - case 127: - c = '<'; - break; /* << */ - default: - if (c < 32 || c > 127) - c = 32; - break; - } - patchNames[i][j] = c; - } - patchNames[i][10] = 0; - } - return 0; -} - -void DexedAudioProcessor::exportSysex(char *dest) { - uint8_t header[] = { 0xF0, 0x43, 0x00, 0x09, 0x20, 0x00 }; - memcpy(dest, header, 6); - - // copy 32 voices - memcpy(dest+6, sysex, 4096); - - // make checksum for dump - uint8_t footer[] = { 0x00, 0xF7 }; - uint8_t sum = 0; - for (int i=0; i<4096; i++) - sum = (sum + sysex[i]) % (1 << 8); - footer[0] = ((1 << 8) - sum); - - memcpy(dest+4102, footer, 2); -} - -/** - * This function normalize data that comes from corrupted sysex data. - * It used to avoid engine crashing upon extrem values - */ -char normparm(char value, char max) { - if ( value <= max ) - return value; - - // if this is beyond the max, we expect a 0-255 range, normalize this - // to the expected return value; and this value as a random data. - - return ((float)value)/255 * max; -} - - -void DexedAudioProcessor::unpackProgram(int idx) { - char *bulk = sysex + (idx * 128); - - for (int op = 0; op < 6; op++) { - // eg rate and level, brk pt, depth, scaling - memcpy(data + op * 21, bulk + op * 17, 11); - char leftrightcurves = bulk[op * 17 + 11]; - data[op * 21 + 11] = leftrightcurves & 3; - data[op * 21 + 12] = (leftrightcurves >> 2) & 3; - char detune_rs = bulk[op * 17 + 12]; - data[op * 21 + 13] = detune_rs & 7; - char kvs_ams = bulk[op * 17 + 13]; - data[op * 21 + 14] = kvs_ams & 3; - data[op * 21 + 15] = kvs_ams >> 2; - data[op * 21 + 16] = bulk[op * 17 + 14]; // output level - char fcoarse_mode = bulk[op * 17 + 15]; - data[op * 21 + 17] = fcoarse_mode & 1; - data[op * 21 + 18] = fcoarse_mode >> 1; - data[op * 21 + 19] = bulk[op * 17 + 16]; // fine freq - data[op * 21 + 20] = detune_rs >> 3; - } - memcpy(data + 126, bulk + 102, 9); // pitch env, algo - char oks_fb = bulk[111]; - data[135] = oks_fb & 7; - data[136] = oks_fb >> 3; - memcpy(data + 137, bulk + 112, 4); // lfo - char lpms_lfw_lks = bulk[116]; - data[141] = lpms_lfw_lks & 1; - data[142] = (lpms_lfw_lks >> 1) & 7; - data[143] = lpms_lfw_lks >> 4; - memcpy(data + 144, bulk + 117, 11); // transpose, name - data[155] = 1; // operator on/off - data[156] = 1; - data[157] = 1; - data[158] = 1; - data[159] = 1; - data[160] = 1; -} - -void DexedAudioProcessor::packProgram(int idx, const char *name) { - char *bulk = sysex + (idx * 128); - - for(int op = 0; op < 6; op++) { - // eg rate and level, brk pt, depth, scaling - memcpy(bulk + op * 17, data + op * 21, 11); - int pp = op*17; - int up = op*21; - - // left curves - bulk[pp+11] = (data[up+11]&0x03) | ((data[up+12]&0x03) << 2); - bulk[pp+12] = (data[up+13]&0x07) | ((data[up+20]&0x0f) << 3); - // kvs_ams - bulk[pp+13] = (data[up+14]&0x03) | ((data[up+15]&0x07) << 2); - // output lvl - bulk[pp+14] = data[up+16]; - // fcoarse_mode - bulk[pp+15] = (data[up+17]&0x01) | ((data[up+18]&0x1f) << 1); - // fine freq - bulk[pp+16] = data[up+19]; - } - memcpy(bulk + 102, data + 126, 9); // pitch env, algo - bulk[111] = (data[135]&0x07) | ((data[136]&0x01) << 3); - memcpy(bulk + 112, data + 137, 4); // lfo - bulk[116] = (data[141]&0x01) | (((data[142]&0x07) << 1) | ((data[143]&0x07) << 4)); - bulk[117] = data[144]; - int eos = 0; - for(int i=0; i < 10; i++) { - char c = name[i]; - if ( c == 0 ) - eos = 1; - if ( eos ) { - bulk[117+i] = ' '; - continue; - } - c = c < 32 ? ' ' : c; - c = c > 127 ? ' ' : c; - bulk[117+i] = c; - } - - memcpy(patchNames[idx], bulk+117, 10); - patchNames[idx][10] = 0; -} - -void DexedAudioProcessor::updateProgramFromSysex(const uint8 *rawdata) { - memcpy(data, rawdata, 160); - refreshUI = true; -} - void DexedAudioProcessor::setDxValue(int offset, int v) { TRACE("setting dx %d %d", offset, v); refreshVoice = true; @@ -524,21 +373,6 @@ void DexedAudioProcessor::setDxValue(int offset, int v) { midiOut.addEvent(msg, 7, 0); } -void DexedAudioProcessor::loadBuiltin(int idx) { - InputStream *is = builtin_pgm->createStreamForEntry(idx); - - if ( is == NULL ) { - TRACE("ENTRY IN ZIP NOT FOUND"); - return; - } - - uint8_t syx_data[4104]; - is->read(&syx_data, 4104); - delete is; - - importSysex((char *) &syx_data); -} - void DexedAudioProcessor::unbindUI() { for (int i = 0; i < ctrl.size(); i++) { ctrl[i]->unbind(); @@ -589,7 +423,7 @@ void DexedAudioProcessor::setCurrentProgram(int index) { const String DexedAudioProcessor::getProgramName(int index) { if (index >= 32) index = 31; - return String(patchNames[index]); + return programNames[index]; } void DexedAudioProcessor::changeProgramName(int index, const String& newName) { @@ -603,82 +437,5 @@ const String DexedAudioProcessor::getParameterText(int index) { return ctrl[index]->getValueDisplay(); } -#define CURRENT_PLUGINSTATE_VERSION 2 -struct PluginState { - int version; - uint8_t sysex[4104]; - uint8_t program[161]; - float cutoff; - float reso; - int programNum; -}; -//============================================================================== -void DexedAudioProcessor::getStateInformation(MemoryBlock& destData) { - // You should use this method to store your parameters in the memory block. - // You could do that either as raw data, or use the XML or ValueTree classes - // as intermediaries to make it easy to save and load complex data. - - // used to SAVE plugin state - - PluginState state; - - state.version = CURRENT_PLUGINSTATE_VERSION; - - exportSysex((char *)(&state.sysex)); - memcpy(state.program, data, 161); - state.cutoff = fx.uiCutoff; - state.reso = fx.uiReso; - state.programNum = currentProgram; - - destData.insert(&state, sizeof(PluginState), 0); -} - -void DexedAudioProcessor::setStateInformation(const void* source, int sizeInBytes) { - // You should use this method to restore your parameters from this memory block, - // whose contents will have been created by the getStateInformation() call. - - // used to LOAD plugin state - - PluginState state; - - if ( sizeInBytes < sizeof(PluginState) ) { - TRACE("too small plugin state size %d", sizeInBytes); - return; - } - - if ( sizeInBytes > sizeof(PluginState) ) { - TRACE("too big plugin state size %d", sizeInBytes); - sizeInBytes = sizeof(PluginState); - } - - memcpy((void *) &state, source, sizeInBytes); - - if ( state.version != CURRENT_PLUGINSTATE_VERSION ) { - TRACE("version of VST chunk is not compatible, bailing out"); - return; - } - importSysex((char *) state.sysex); - memcpy(data, state.program, 161); - - fx.uiCutoff = state.cutoff; - fx.uiReso = state.reso; - currentProgram = state.programNum; - - lastStateSave = (long) time(NULL); - TRACE("setting VST STATE"); - updateUI(); -} - -//============================================================================== -/*void DexedAudioProcessor::getCurrentProgramStateInformation( - MemoryBlock& destData) { - destData.insert(data, 161, 0); -} - -void DexedAudioProcessor::setCurrentProgramStateInformation(const void* source, - int sizeInBytes) { - memcpy((void *) data, source, sizeInBytes); - updateUI(); -}*/ diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index 679f310..38fbd68 100755 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -62,8 +62,8 @@ class DexedAudioProcessor : public AudioProcessor int workBlockSize; int currentProgram; char sysex[4096]; - char patchNames[32][13]; - + StringArray programNames; + /** * The last time the state was save, to be able to bypass a VST host bug. */