From c6235fd4098e81083207fccbd5f64a664594d76a Mon Sep 17 00:00:00 2001 From: asb2m10 Date: Mon, 30 Dec 2013 21:05:56 -0500 Subject: [PATCH] Parameters names matches the DX7 --- Builds/MacOSX/Dexed.xcodeproj/project.pbxproj | 8 +- .../UserInterfaceState.xcuserstate | Bin 66252 -> 67556 bytes Builds/VisualStudio2012/Dexed.vcxproj | 2 + Builds/VisualStudio2012/Dexed.vcxproj.filters | 6 + Dexed.jucer | 2 + README.md | 17 +- Source/GlobalEditor.cpp | 293 ++++++++++++++++-- Source/GlobalEditor.h | 18 +- Source/OperatorEditor.cpp | 1 + Source/PluginFx.cpp | 86 +++++ Source/PluginFx.h | 34 ++ Source/PluginParam.cpp | 173 ++++++++--- Source/PluginParam.h | 35 ++- Source/PluginProcessor.cpp | 5 +- Source/PluginProcessor.h | 15 +- 15 files changed, 605 insertions(+), 90 deletions(-) create mode 100644 Source/PluginFx.cpp create mode 100644 Source/PluginFx.h diff --git a/Builds/MacOSX/Dexed.xcodeproj/project.pbxproj b/Builds/MacOSX/Dexed.xcodeproj/project.pbxproj index 82b1763..25f654c 100644 --- a/Builds/MacOSX/Dexed.xcodeproj/project.pbxproj +++ b/Builds/MacOSX/Dexed.xcodeproj/project.pbxproj @@ -32,6 +32,7 @@ 1CBFE444B43C89E749602B7F = { isa = PBXBuildFile; fileRef = 45ADFD8885BE76C7F7D999AC; }; 478699B4EF80A1A1C0D34C10 = { isa = PBXBuildFile; fileRef = 018D0FB9E97B68D2EB3E3F72; }; 623AFA9E78826CA0136251DF = { isa = PBXBuildFile; fileRef = 59D15F780D468B587F9C7E78; }; + B18C192606DF6079E7B9AEB9 = { isa = PBXBuildFile; fileRef = 8BADEB7BF1A65E83A7A1736D; }; 1C87DA0B69D67481FC6CF4FD = { isa = PBXBuildFile; fileRef = 54363D0B39B88D43447C0123; }; E3FA856CA4DB2009BB0F13E7 = { isa = PBXBuildFile; fileRef = 505852570B48EB3F18076B03; }; 7E6DF76EEA834AC1E96470CE = { isa = PBXBuildFile; fileRef = 3254CAE4C282C4432214B016; }; @@ -487,6 +488,7 @@ 8B160A62F6A6EF21379A8EA7 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_win32_Direct2DGraphicsContext.cpp"; path = "../../JuceLibraryCode/modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp"; sourceTree = "SOURCE_ROOT"; }; 8B86ECF3351C9D029821C621 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ImageComponent.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/widgets/juce_ImageComponent.h"; sourceTree = "SOURCE_ROOT"; }; 8B87D00DA619D83BA6926E28 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ScopedLock.h"; path = "../../JuceLibraryCode/modules/juce_core/threads/juce_ScopedLock.h"; sourceTree = "SOURCE_ROOT"; }; + 8BADEB7BF1A65E83A7A1736D = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = PluginFx.cpp; path = ../../Source/PluginFx.cpp; sourceTree = "SOURCE_ROOT"; }; 8BBE375590444CD57A311DD2 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Time.h"; path = "../../JuceLibraryCode/modules/juce_core/time/juce_Time.h"; sourceTree = "SOURCE_ROOT"; }; 8C4A3CBB322357AF0CA3C2CD = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_FileListComponent.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_FileListComponent.h"; sourceTree = "SOURCE_ROOT"; }; 8CA96F07FD8390BD5EEC909B = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_DirectoryContentsDisplayComponent.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_DirectoryContentsDisplayComponent.h"; sourceTree = "SOURCE_ROOT"; }; @@ -733,6 +735,7 @@ DB3B5F6FE49267EE53089A05 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_linux_WebBrowserComponent.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_extra/native/juce_linux_WebBrowserComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; DB9F89D1872247982F4D0913 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_TableHeaderComponent.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/widgets/juce_TableHeaderComponent.h"; sourceTree = "SOURCE_ROOT"; }; DBEA78ADC148399D593D22A9 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioProcessorEditor.h"; path = "../../JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h"; sourceTree = "SOURCE_ROOT"; }; + DC75DFCDFCDB425927B11EC0 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PluginFx.h; path = ../../Source/PluginFx.h; sourceTree = "SOURCE_ROOT"; }; DD1BF932ABF0CEC81A8B8A3A = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_DynamicObject.h"; path = "../../JuceLibraryCode/modules/juce_core/containers/juce_DynamicObject.h"; sourceTree = "SOURCE_ROOT"; }; DD683E5793B347EEB07FB199 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ArrayAllocationBase.h"; path = "../../JuceLibraryCode/modules/juce_core/containers/juce_ArrayAllocationBase.h"; sourceTree = "SOURCE_ROOT"; }; DD9B0DAF1119ECB6FDC0A3AE = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_Path.cpp"; path = "../../JuceLibraryCode/modules/juce_graphics/geometry/juce_Path.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -889,7 +892,9 @@ 018D0FB9E97B68D2EB3E3F72, BD25F7AC4728A7875B6AE9D5, 59D15F780D468B587F9C7E78, - EA6FC4F1F0D6EAE661569905 ); name = Source; sourceTree = ""; }; + EA6FC4F1F0D6EAE661569905, + 8BADEB7BF1A65E83A7A1736D, + DC75DFCDFCDB425927B11EC0 ); name = Source; sourceTree = ""; }; C21CEF3B473FDC99270B7623 = { isa = PBXGroup; children = ( F472964B0FFEE5615B72CE3D, 29B923E6EB12F97B68585AFC ); name = Dexed; sourceTree = ""; }; @@ -1942,6 +1947,7 @@ 1CBFE444B43C89E749602B7F, 478699B4EF80A1A1C0D34C10, 623AFA9E78826CA0136251DF, + B18C192606DF6079E7B9AEB9, 1C87DA0B69D67481FC6CF4FD, E3FA856CA4DB2009BB0F13E7, 7E6DF76EEA834AC1E96470CE, 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 6f095f41442a1a92729b5bdcf7fab5f279d5b2d7..7e65e0d95dd78b37073e23737ce8a34286505f4a 100644 GIT binary patch literal 67556 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

|4&(2~%RFp{v8u$Hiu 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 literal 66252 zcmdpf2YeI9v;W=h>F%UcIhjrZm=>yg2a+I5vN5>DvN5I!V+%02#j+^@lH2q~dhe#B z_uhN&y;sr;>An7E_jD)8mI+|q%jf-H-Y=1*-S5uK&d$uv&fYC;Z*B^Arl-Hm@f_kX zCvX-{OzKYBJa63UP)E3_t##hGwxugW4V~e-arGSyE1KZz>T#WI?MWPe^d;B1Eoq#@ z$=m>LAUBAc#7*X=a8tPyE|p8;(zy&Slgr}rxc#{UxN5G3o6FU5^SC;0KDU5d$SvX) zbE~;E+*)oOcL=wh+rVw)4&@HxH125b7;Y1H5_b-FE_WVxK6f#919u~L6L&Lr3wJAb z8+SW*2loi~DEAomIQIniB=;2eH1{0$2KOfS0rxTY3HJrJgZrBMj{BbbiTj!Rh5L*9 zn@7CJOT2@3^8@*z{4jnrKZYO6kK?EEDSRrQ&(Gk?`3imkzmQ+VFXkKhCccet=MU!B z@N4;X{6_vz{xDwSkK~WxPvB4F&*IPHujX&(@8Iv`@8TceALpOqpXQ(AU*uomU*+HA z-{Rlq-{(K#KjwGvU-RGaKk@${j0U06Xbc*Q#-Yh517)K;G!5;K4nT#-i;B@KRE=uT zTvUtZp~WbOLTDLUj#^MF3ZwOC1KNlVMTend(6Q(^v*x*i4%&`BL0_P+(U0gi%wvQxRdO%eR*AEZpCE{#xj#w&|iREI2xJX}y|`XHOw`09#iPXI z#N)-2#FNF-#WTcn#B;?9#f!wv;ui5T@pAEM@fz_4@ka4>@ec7G@e%P!@mcXD@eT1! z@qO_F@l)|L@oVvW@mKM8iIaFqk`&1;4UmROqoncDe$r$qUCNa5r5RG8MNf%3( zNL!_wrCX$1rQ4+2r8}fMrF*3Z`=-cIVO6aItb?t?tovF=S;tt%TPIql zSW~ST)@*B@b((d5>rAWHT4XJ;mRc*URn{8oJnI7MVr#v%(YoBa(%NEew}!2&t?R5C ztcO_-w;p9Z)_Q{VB($oltT$S3vEFXI%X+W%0qeuo z$E;6UpRqn~eaZT&^$qLW*7vO2tsh%Ivwms)+WMXKN9!-v->rYyI2*Q!Hml8UbJ>z? zgKR@>``AX>M%%{OCfFw1Qf%qAEL*Ovz&68npsmp6x6QK6v6b5nvQ^t^ZS!r5Y)fnn zwq>>^TeGdr)?w?it+lPU9cm-CBW=gnj<;>HonkxPc9!j2+Xc3ZZJTY|Y?s@vvR!Mt z!FIFlHrt)Hdu;dH9@h%#Imp(HC~mHm`S%2Xvy$y9Qbd}X?FfZ|bnO0hCqDN`zy zfHGI9Qx+;gWvLQURwymX!ODlqr^;u_SIQ3MJLP-jXXO{=59LogXXot}yJ)xB6}!u> z+6USP*@xMO+eg|**~i+)*(cg3*;DMP_Dp-0J(Q(N1h|!;dA&MMUG;}EJulBwquT?)-lgf=a}zU;8^HbIn$jpoclWua31KK>GU`Yo#oC7XQlHX z=OX7~XVAIC+3aj_wmRFK>zx~%8=Z$bk9VHnJkfcM^IYe7&hwoYI4^WwjT#g*VnFZT;IC>bp7S}TeYc*YF8cVFm<@Pk2*n} zs7_KRtGQ~Pny(h9eziy~Rs(9aTBFWY7pqIv26ef*LTy#s)UdivJw!cBJxV=JJxM)T zJyY#gH>+FJt?HHPRqEC1&FU@ct?F&+?dpT-L+ZooBkI%YtLkg&>*^coo9bKY+v+Fk zr|M_w=jspYkLpkAZ|Yxehui6PxmCB@o#YK; zpu54{=w9J&a<{l!-5u_*dyRXodxLwUo45~mAMHNIeS-T$_bKjE-DkSba-Ziu-+i(B z68Bd3Hun|oE8RD`Z*t%4zQuj3`(F2b?)%*jxSw!8>3+)nwEJcEEACg_ueslIzwiFQ zz1{tV`%Cv%?j7!*+&{a2asQgcCGklp2`4E@_9RD=Gih+rkffnW$w{M=#w3kRnvyg% zDJ3ZA<9!NuH#Vq}fSxl1h`RlWLOYCe8zx)lg>}NAnB5tajjj=%`b6Q&c-R6opW(XwdH}-RiSm^`S9OJ zY&v&bLvwvNyqR-wP7P^zGpBNHO(6W`T47Kfmz$rH?n}=pOv&|n^HQ=i)ALjE^S#+A zMMa*1^h|$#kvA(ds17Xg`D@!cR)yQ^8$!OehOU-SYo{^tU~UvQ@p5hmHz5YRca((ZHies(His6QKNNM;w}gV~X!xR{qcPMGYBULhKHj$0&W^U`W(d%O z>M*lYNox^^D%{W!3bmHCHA4TX^f!YeeaL9vn%1U+yFw+6z+}_1rcg&v9RKQnXV#uwS_XLGsTAalE>zR2Zs1>7`l z`h0!jTR~j&^pBx1=!d7Hqki3HXfR`5d7y&rUu0t@59CU?iC1tlIS*IJc{v~F=Zd&u zZk9Gc8>kJ^25UpKq1rHQxVFy~+-#V`Qm%|E=PF=M58|q{ePI?yXfJ556aIY7P54U* zf0wttqcx-L$;Ev#nzheBp0wf=`}~P<>EM=~GlSolVV6 zo$F|`0Bp@V=Qf4b=zu1e4iPuCankmM!cEIt6ChBMbo{1JnCcpID{5*ERn~W|2&#iU z;V^6k>svc@O2eh~>)N_HgR09nue7agRe4b;)STMT-fqY-$gSiiUdb)t>ba#{1J}rf zxMkdOZUxt*jnqbI$=Yabj5byqr;XS4( z?Idlhc87MS_7GhmDkaqyTH3XIc_<>X!KMhAY6pPO#`=y%ebwp|vmc5>txa8FDsYOS z|1dx1cXd!a&|H0&8&n6t_rB1w`mW|qHnJ|}Cb{;i?lj4R0`E`Z@pr5VF z*+*X!toyds`VLTypgJhNZKxUc{~?fd{P)G7ww6$5$2xs+UO*S;g<6KD8bn>fUCvFs zjO*q$b6dEr+&1n~?lLV?%hIy794%MN)ABFluHdfZuHvqSf3D@O(+ad{npZ1^f2y?_ zt#%>RPG5azef7Hb&;p$%MlIM-56eZ=gVl_m5SR~rrNA#GouQU;W=Mw_<~+e~`xw9Z z*TVeLlt!E3E%3+}736U{3R$+x?O=5Eug8b zxJlFDQcVvP=1y~Em%EjFn|p_QmwQhu(n_>BS{d~h+ky70xsT?@j8&}7 z>TTV05q!#h7F73zp`&UBI1Xl&*Yd1Ly$X+-jqv zF}Is}p7NaNC)Sh4ybx3;_MEY(4C9yTX5K>KcDa2}-Op5sIZd6ZxX621bG3tXnw`9>raS}2OAVm29`eKa z5!}Sh{674?+5&CiW_~0;N?W8Y)@m0q&r#VHZlX4LS3Sd+1OC~z-oPHuPo&uU@e{P5 zwq!FuiJz?1YwNVyI!`lLj8?Gru?~Yzqn%1DL zHU`?C_y3zw=ZpAaeimQC&*rY>OSMKVq%~<_trLuT7j=9t(~PbN)kAP=Kv(iLiHs*d zm#^i<@^#uWZ8;dv6k5tY!nru7Ig43uQC0YOn9; z3`dqee+XUrT8F;KXYctU?@2DipG#r;F_BpUPgi48TV+RELns_>>qws5ZhV}Y+|=5c z+}hPLDG|rf6~-UJR#S(*W{%>IUTm%y7KLx&kD_t7F8E`qJ{_m6)m8`9Aw3sMR&GXW zPIS3!;!o|RqNjn1o}nEADte-!qG!|fcaF9`I*;e`TmDT&xhwc>{H6S5{NjFAI0_wnD zCH0t12*~5yOq_pVfAB9s-(w8VVkp;ZOu3HJm8*2GDHo6vR14y1oHlJI>Q>(Yp|q}R zZS9j{EI0oe)2rij*?d4}dAqjh->vK?{O8mXehOChWNKx<;J?&P(N3kSc~B(S4@W}D zuB9#DEvT<$*#-Vv{(HK9CumE$`5&~?qKfb{|9dZ0`~y_+FYRv%_cDt5=HA{vbLNu-KsUo?Uni$-Z@X=j5fo)b~Uucp3N zw+QynSycNnvI}zi&_y&J?HAF-OSJQ1bP-JfT|`q+3Q9$3+WFcA+J)LhJ#_J3)DBGt zwYzwyYL^>l5&LxK-nJI7i%sFSR=o++2;`%}_G?@IRU=RdD(5C{MYGWyREo;9ZQ7;U zW!mLiQ3a|*2catM3hgTG8tq!}m2+Vj>gvO_kR}PYHHYTwyE8qTLbssNt)aQwi)at3 zLkmEA(0uL6Ztyr2RN;o3fOH>kMC5^nwsvF3fR>=8v{$`$wb{!Z860*$;1cNADy(6q zqG$zzO?NkH(yr@9tF-IsAa01%Ok(JkC#(yoji0_5wWEWz8?;+Z|BX7)8ZK!w>O!lv z8?~D@qqS(AcC&ViR=5aYqQNnZ?B`Zfs>|w^w>EWlHHH?&F*A1Nq3s;~KZ7z29T5k7 zBsxmFO}kwyTo7T0Zm7r3JpBH+UdN*oxQUlsVlFjw5;}!4c(Qg^H#$|jduI%uNf|r~ zovq!Y-5+J}Jal0k9T%aCwR^Suw8A==K3##v&TLu|N5xijSzMpX(G}VQ+JkhP<}xNd zl8G2QbD_?`%jjBk9lD-V&<)(5=q7YC*yfJ5woYAR=-$5^W)9rka+ZlFa3p*$_wzhBhi`5K%Q+Vo2H4L9 z4HUPvlkSs)YO=9g=qvDE&<5N5NCE>!dPaLrdnCp~q5IJT5v%aD_GqkCc$8X&$I#>G z3G}4)nD)5#g!W|2<_h-hv;NI0yb4y~sUB8A-{k1qnK+)&yTJ85aD@LSTBbb2sJ^o#bA_G(nYe@B1CDeK?pAMIuB6|Jyx?99%Y zv3iXKEX6m)R%rSfc!`#!1>6+MC*2+S}SY+wed<2oJ_X z@KEht?PtRCgdaxu;dEst#~E;an+|bts<|f*sw4VpvaV%m8{|s+f+(!-Y*b!(r(|Gv?F)M{y#G?IO(f*e>-9Rpv~w1(?fhZ>EIr*5VpH{frjz5@uR ziGzT*jHar(!o7c{=M4U}?U29>H8OimjfI}1M=@r{Nh~Qa7Hieb$Zl*FHDQ-`x6U$S`@r6v2?J2YW$d zaiR7_H}+{?YPEVQ!}xg?o&!M`_YIy6X^yWp<5KvrL;Fgrtu$I3glo8oTevUrY+McL zk*~C`x4=jE2R_n&YU`>(dTtH&L(KQ#g?O<^UQqj1D>QysiW^O0LfUtxGr=n`^_JW> zT4^_4rF|d$p%u5&AHLLPcjJS#AEG~W;??wrtF_{8MvAc)z=z-s=HMH(pQ3|nn8bN7 zd?Y@RD&0}|XnYJl79WR?$0umNXuoQ|X}@cKXn$&dU4}PNrQ?$EsrWQ5S^JwQokRPF z@SNtL3yYp0#7(AtI1^xt#++`N;hqI2H}#MUT?c7HsvNyrP@e+{ILHW9v^GOCdZ?7B z89hJ?McNFHY12Xv2xtyL&wwQch$I_zT*yXJ>z7~<(>ha9n32O5^3yNTR#)nObaT0v zn9(!dif`a1UX8cmOYvp+a(o585?_U{#@FC$@pbrm!Xv_C!ow+_h43QbCBn;uw-Vk) zc!ltG!aJ_UH{zQx?ABnv_67e1WW+$cY;=amO}i0Ul)BW4|*Ys7>qLpH52e;pha1E7~Im z4b-fdZ2}=W>+GCx4L#ullNkGR+;GwG)$CqI&1;}@T{9RSI#=coX2(DSJz|U|rD*hP zwklcP3bw@yX*J#JnmL|UZ4Jwr(iAmS(B3V*Fid@WIMi6&(bm-t&8U4en^AGm zu;xYlG^gNa@Uw8Brwg6%F2cKCgm0h6FW?vJAio!8IaCZ~8iZ0}|6_)1EW51;2^kqHewKCJ_I@!DA22sAH2u50rHV-o?)neqapU z+Zna^BS`lCj6a6FJ4^1fbP(YO>$H7}KZCPwCdNRhb2EnMCFbuJBb~n_{7}994*WGe z1~C$sM#nAq8~iQhq4!TQaDBUE5SN~5H|*{Y_%Ap~#XsVo@Xz=c{44$q|BnB_e-eHl z!tYD?5riK}_)&yUCj4l^k0JcnE5OhGBX9!GjTNvUz`sR$iaL();|XlM;o~`kKbQXZ zJh}?$QMtdPqpibqV-Y9Y%Q4dhXlfF)rus&|Gp#5)CZXNfqAFac$IA3H&~T`_?$Yg_ z-qnPoP2oFw(ylw`p47n9!*6DLQ;~Z*+noH!QMNEZ7JpK#7EN1FvDBm zo1rWh4Sz7hC=3?{ZWHzq_7z45BL$G?M8bOrA0Yf{!XFDjktq?z2oqqhD~uJ!3FC$R z2tSGNlL>5I%$OnS{@xGIkr=1tZNLUa$=62+ANKSid|}-3iRs zg}atEF#+n-WJ2^UWD!19Q{Uiz6>^0g&;2YMARNg3DI6$x zU`@l(R!1iUNg$-Ime%sFmZh}fASu+^*y~GoL)<}EX$Vr{s@|{^{FvF-fQI!}Ke1ac#d9YiqhMk=ex*4+EA`}V5 zbj|hEAn|cZP~E4dbyaKIn$~10|74nYPM!b>S*TO#oUov>z9Sq;X0fh5A#-4-Ae0Ja zgwH1YbaSsDR0HIDta2k+sewPUKLOq+` z2AJOlAw>8*75r|xI*7`6-=Mme6N)QKT9cQ-nue5gLo=iz8k3iGw6!Gf!Z}xA7i^Tn zX=U{d6@htasj2k;BWGXnNlIGTFfB848e|E*&2YY&Tv|G}EIA`JJ-NKCvkA;M-F6Bq zS+HU(wicnIPw9q*PLM9F&KZP1kV$u@A>DOUx`z;c|HRVWXiE1mknUjuA^ZVUw!^7x zj|r-?s3i96xR2>?b;K?8bxaEG0qJ*H788Wxw;qsWW>C zU69?vX2KT}zAU;Rw+UDF$@W#k)u1xh5`Grp=P;EiHQ2s^vV9}rOA@nvi>Wf^f}9O( z)5GEayDL!_LwJ|U?oHt>2o2sLd^O=~SZFYJtMH!izVLyt zo$$4UpHKKOf%D6Rp+Phfhz%0-srrmc`E$b0ODyHDgdM^T<~6JC((h)4^1u9D8|H zGFB}~Y_j`uUqSVM&4*@9i}**&5X-)O%65chB*+#v1`wbvW3pXt$aXB1?Kr|WCYJ34 zQ?`>pwv#Ln&_V!`t`4QLg)n_Do|Nm7O^rx)#s7r2>=A{mn3kDi$}iKB*QfmQEd?OI z>4a}0d^3|D6fEfU9zf*>F~`cp@+&mu=L7lqEJcK0MdjxN`SD%-@{y1zYFJUWyd$#w zEF}@iE&ZR6Ty(H$8Bv*)S*rS!S-?^)d|;VN_%_0KFe}$-$gGaa3@l%JVwo+nEVeAB zw#%{vWVXZtX5?TM5=`l89!O0FKTGz&cFpc;2$eQ1h5X$*TDFu1r_o)o`%GI2-v{ey zVMfp_#|Wpzd}IycD>n?0hnUD02SP1S$=lSRZxSHKQvvrjJDM7y9wm8oQ%7f4eRJ}% zu2xp`ncNgkUI8`cV3z!A8$vAIlpJmkH9%RoUeuS|wk)|#2Y}sLT*ns310^@tuTAb; zQQw+O3$2o&A+4e`tiUP@C0%dK$Qn8$YYD$L@rM8ecMTOE#L-747T*n~_{x4foy0G7} zyx*sYKd@{E5r0JZ(+PhT6Y<%GW`0Tq_Zfj2wuFNF5|SwmOmI6ua62sD5FV@mh>gaL zQ|=0?9eW_QoqCz&T}?qS+D#4Nv^7nQ%R`+J?*lbAOWO+D*3v9N72FhRX>ShE>rjw- zX@^>C(}%zXfE8_x$rBnP?V;KnYSSAhK&B>nCt}v+`UBHi{qxT;pMNuwqY%Pd{?z|4 zOu|1R4+nIt07gWFzaS!6(ZWyPB8s9ULQsAo;UT%Y#hfis5uLH;;G#=Z34amcFQ!MF z^sLQ1w$O`I+T)JV#X;iGxbDNm;e_udJQRM#-|QJX^VGOwb#at9Ca&jL5#rjdgx_Wi zY~II-8yHIHb|JSFSr0vGxK%MCDshSk;p0`}R53+N71P9YF+byZA?`08ARZ{rq^D>!Gk>#IL4-|2 zIE6qaM!1;>w-C#I>>LfYi~|dy%x6`58{{g(>@FEpxWbY6@W?$HeVNgd@ld#^tpm!g zAz~k*-=KleLcgO{7+L{kw{0B@^~-1hNVn3u+kyI@Rb8!c#R+oB?7l%zO)sqvchVZM z<`4`Oy+@;WD};!ok#&S?Rd9UQ*1@hcMe6DG@qmO8arCicwLsG$A(O#40f$R-+`s-$M9X34a^mZ`ZoF ziM8T9u}+*X!lv~O!hcV&M1*xjIF|0qC&U$1#1oZT+P2&vFsSC~E!n@bV0%oTCslNn9ze5}U;q z!rw{wy9p0&>VCpMNce{d|0v-fCp`Fm)h+(l)>=IXtYs9r8#Cp#Y z{x!nCLHM@_59y2#2>&7BKP5bvS4cv94QKk%B4zPVC?0~qA53WG+LX2QVo6GK+j7XF zW_oinb8-taQ?l~Y3sbWF`ROSIIX?I^11k74{7}G~lM@Scgbs91FQ6=6c5bG(AUmbN z<1a|b_R>3!xmoEc=>_@T{QPu(c1C7)EYPt!(0#ptatqVbeMR|Rpd;I#lI_dROYs!t z6{YxmdFh@)Uw&ReUK~Z6bf5NvhzIIDTUcN-jqBaoK?Yn*xdYr ztXPUp(}5o91(aO`g^zGmHYK+(4`h_(_osLY;QDM~c4m$@BR#vYz*iUxbhZxkNG~8? zVS09fr!YSyGd(jqCA%;uE5(zWmz9!{QM@h-x@q^YmayGr7{+^^z&;{9;rVt?^a@nL#u$I6_lJL+5ET5?l+ zXC0j8ht|@IVT6BGiqP}I~<04EE98a?&YuXGB|CZC+scOu3tR6{) zL(Es$0i5`h_%vMZF}rLQ;cias7kaDb#OL9XEBN{t`)Dw@lyFrtLB*COfvJn2G2u+d< zG)Y#%f1HS>3nU2Mbmf6$|0jLWBn^}X_oOL8t~6YNykxxOjh~XGG4PW#n($wAOJfP# z9oXqyve;FcK*^m*_^%R?dzF-Ckoyebcl1SWmXs467{aq}3|SOV@M(nqHWB#slE(ml zj_}|01@4!MDL7>Me(08F5&ow*=O~rwCgjJUde9#1FXE3_+14tRd00qTtxPinTPe|S zM>|NAznR+=Z(N%JL$cm5#!p9F~nNd${@0#f2)6FtVL z>L7?Ch~F%AN?imYg77X}1b{l@P}~Md+8`a)3y&~73#~Oi z@p`r^+8KNLLOPo2`Y{B_n)7=?at0;rSB0&m4HiE1KTmC0h z7OoeDrXKsy>#GczpC+9JwW`wT(izg31lb945aiqak6_0q&$+L(nj&bF3g}ANUXGO)P;xJX~w+Tt_d=`m+jDr{()65u$dGYvGW&u_FNb8a#*Cg4HdO>+sg5^WW)%6Gt zjk~402^y}gj?@QAu(^N>xcqFGw#+FG(*;uSl;-uSu^YK&!sPZ$rI#>@+5h(JVl-=r^u;tnw&0Y$eD7M zoGs_bxpJPIFBizuY$_;X(9FmvG%jFevle|)1B{$10 za;w}Xx62319dcOil)L2B@)~)qyiPtuUN3KuH_C^~hsl~u%lP@;UOk@_F+4@&)pR@pj?9T2+Aj@fS_pvO($puLHiSQ06_;5G?O3? zL4^c)3Gxx-C#Z;^VuEH7R6@{fg60rZN>CX=7&q1T80M1wl;&tt4m_LCplU5CoR8 zji7dd4kidJeVCw5g1QJ=P0$*G))KUiphE~+PtXQ}HWG9wL5C5f5d^mTaDt8?=tzQ& zBIsy>z$hO}&~XGEPtXYjok-9of=(jnWP(m1=v0DEBj|L3&LHSag3co7Y=X`q2(06I z1f5UN1q5A4&_x7YOwc6+brZCipe+P#C1@K#mlAXtL6;MB1wmI5bQM8Y6Lbwh*AjFc zLDv&>13@O_yPYC*ypw9^UoS-iV`jVip2--o= z*93h-(6?|8%VdaR>?hERg{<31wG#ClDYn%2T+aXu%83au|1myYAP!$s;d3I zU}dSNx~QV6%p?OcKhR^Jo;~JzN=tkU+HCm%YdMV9{gCNHH*5&hmBo?_DI`El(5|9z zc5FM?K0v$i3Gillswk;des4utWgzG)sWSM3tQ7Pa8R-+L&EK%0u%@Kc7o6*9^&sft5HX9dvy}`NussK!z0Sn12XgRSbEEK}m6bDPnslYsRnuGc$quWcY+k~Fo ziv8vODo?c^IH)Kp0S8wc^j7%%Mz2>{ubDl2ne3L7drND4{@^UX2P&Qe!J?{)vLNNK zngaT2yw!0cffO9jKB*^MRZV%&Tk3(a1JyvgH|PN+tpk^9kO4bi=$F~EU%=}r4|+;L zpDSvry#63C;0GEisz45mE>pbkF@WTr08Dct+*4wW@wT((<9T}4o*aN@WI^P;VFMLR zFi=ul9`u)2msFSf%izD}5FfKXqx) zzp9)Hsko}52Chr6TNLt-J8fD~3u(n;JfR*Y6VYdA6?A{Ang zPNgxti!~k?*VqRW9yQliI7fhihs8B9D2&lI>mb%{d|bOSj~A+>gE2y@_EZ)7jRj;K znxId_AV8<0l5*yWz`~aV%s%@hpeHb=q!Jc06Pv->NY-vd96jEO%DQ0XEKdLyDAj7C zEo5ha$8m9OSpx%<*=}a2j4tC?m!S!|1gh&w4a;bqz?#J?b--WgVa7C$hRKnZbKqiJ zs5u$-9#FcoVFOGVEbL&pr_98JL?uwWFQ2$22%*XpR{Bms1JxC#2;lMsfR5|~G~T&b zA)N$`hwyMwVimJ_g*D|qpt7`r+IK@l1+3NhXe(b`X-OfNo-)vzl0tAJ)pb4GmURZ} zGpbjgnyMVKc0L)@y3C7x=V*zY1a$pE(p&(*QUlUl2^78HQLPEe6EJumb*Emw>T+VkdP@ z&({8Vk@yB;k-~~n-If`mg^Far9uOr9u*)lgl_jQ<9K>1-j<%pw2EjB}gSj(cpkfzb z_KP;6G6~j}RL`O=w%q5b^1*JlunMA(s7PvAr$Nz9u*zozD}vQ^l_v0f)@ER|O+^(b z1~bRT*o#<`7#-3bQ>ic3)mWFXRxvtcMj~aN0EjyX5t!dw9f#b&`oypfbH*40R?LZA z#u|-`QaH!&uY_o%WG?k#{(01!nT?xRqn0?1x7Ydw-RAJIp15MfctJVV0Au(nfT+tLV_xfMXJq)S(iw*&raSRZCQ zWIdks939)!WV&)rF-3`Ed{b|#imJe#)K*l@>1n)9VQq)UVn?Z>qA|#asvlUTsfiov zs|NUu#1;_M#_7#jtn=7DI@eTJ*1+Onn*n3Eb9Xje+(1zmZEF4nI~z`)mB=o@817=$ zBW~WKVu%iBG~djc?-$Dt)g`L2(3qL#KyX$O>?b_c9;4GX)@ed)Cu60XTat=WYN28y zn#)TOwUVcMxeBo`p1Z& zs{t9uTRW(?fDy*`=oQubL>BTM)@MwQK05ctNOUet#nRKQV|#Saol{-H9uKi0M)l}X z<)5FhHI#?|6Ek|W_RnJ*M6mW?iC}*Xem{nrV4$WDcJj;+$2iC*5<*4xn!5)D^(sJB z&k12uuoGE57vUVr>^hUHS!okkVBJzw`>AHedW;tnwr1@-MbyPI(`cyEE3EZUJ|3I3 zo&`G`quJ}M*^ords!B}Ve2cXj$44Hcrf;7kp&r;X=Gl9MeDAU@BjdV6ny|D+oH_o0 zH6Gu0W8F1EEaxpXDF2A{N$$IkZpDn|pZ;6(KuuAMEBc~u@~H_6)Im^FW?=7NjYs!Q z3Y(c|!2K<2?}73$xY^3Cn?e<3J6!JUNX|~pOioE=i3)g7Bz@W>oO^B9Kodtr5J=H5 z%F9AwPqmqPv;M&FX6*)^o}QVPp9{{8h9_+QR0Sy$x*Ipxf^%9>>H~HImXb+r9Rzxi z#Ph^%py8|+z)E%#%yi-`9|nG$ik^kp29Z#D0J!__Ca$jzVtO#+EEe|~SpP7rIlGBv z(#RHX?;)l(CUrv<=@QvZ`lQ!M-`*DWXE7NnBGgMld}8Zjxne zjuWeKGQ*s{o0v7_RTYqaE3K%gG^rcQkal7YN})`>3m$Kw+f*;)`-3HcAUypU62XvE zpkEjhuph&k);Cr0SP|X#1j>SQ{B^LC@EJgp{*AqOAa9T+&ugd=F?RO`(o}}D6OD}` z=_cMgZ(iSMX$&oAR~U>zV|fN6?`_N6bqu-=y5s9-EN1Aq8^#J(g11MdzFqtXocZN&^`Cr&dV4EP(cDs(eg zQ9^U{x>5zbkWV+)^6cG{A2skL<$9bSEUGDI!Av}2+3q7&`HNwX2+?(7#7c&^6U!Cl zUSC3Nmf4IzVhT*Zkv*^lc2AD5O#urHEJK(}Gqtc9e34ygFaSm@y0f&+Wyl4)qK7(- z5q)MRQf!7|nR>s1!R@XktMmk5_4EvJRxzxd#9LAQ zr0fM|!C5^-aW!Uo+}6qvigs1rdYBc-NgL**Y2K{Jsg@4NTY=R0n|-A6OJah0OU`!v@+(Xk1(0L64Y|E8F0uF|<~Ll27xs zfHn&bROs%glzjmrF<}p3usaEC`-ZLb`=I)u#9XNx8B}rKqDTl;4F;v!Bn$j>&|g(m zQDqXSG1TgRMGeCa7H(z2<#0XJiWPu&mft%k7=WV-$i>shGVavfb_5%uwqHYd3L%#V zdk?zu0pHhqfgR08*~wlsBAx_{=mwI_rN68a&czBVd}b_k9K)^Y7xhI@`@o`5D6s*r z*5Ucit>KJJlgi?y*Q$e=V*Z}?0 zo80VRbwv;!f<{+Q?;*})LzMTE2Ws~cfS<#_%lZjU!<^oPpU<%ONa16IUs48VBwmmV zD`)9F%0+CHg?qw*sWj}6AF?`7$HS~+QB5fv6v3IJca9%cnW0VHdp;B9Q2Gk4@>kb@ z$&8Khw=(d`e(}L-PH5l>S(S3Au?d(brnbu%{Gxur>$Dq#6qWel{4GXwrZK&ejnzL} z5kD3<$Lb0yEpv=(*cf}XvU|*h!B4rrmZqeP$-bTqP`D=oGmbC4alze9drc~AUjeGB z@9QCpW=iE&HpU)Ve^V-vbp{0zRi-fRV7PmvJuyo;03k0d<%*gBR5?Xfb?*gzHydl^ zo(P`upnH0V&LSlqaByqLiz?7gVu1VDz{~nMu)&xS`m)46t+iprV7&s52ic%=_jFL^ zttnr6@WJ+&)SEyqs=T_$(B((iApNr~HE<#irBKXDLJ4b4b%m*Qk2Cnve(_LKKBpXN z$bfK9F_cvpls~mspjotQOo##fEQ9XfTB#{#(50TjXm0ZbhPy{D)m(!STw0@51|G;v z+r7N^XoiB)8gqTWw)e!$%7vj^!VvSD40@7?39yQ2 zUZ0-ln7Z-KZU}=Ro8m2p1ozyMs_GipR7Qafir?Q|icMUo;Dpjy6WY)?lj08Xt! zlz57DcUV%c7m!yJ6+x9qMG@4Cd8^FRgHIUxPBxx9ku>B|)8|DG<4uY`XPCPd-|DX< zhBpx=d*f%(S3`|Gt!V;fo>k!kvZE(_wy)R_yB5IpH3UoNm_Ef*T|p1PAZUOJgX-w1 zxb2(0HIxxEM23LFe@Oa5yj5Zf?)yCzoT*H(kA`zA-H|~$nAN>kS9mMTLzJJ`5cRvH zO>u%VhbXHltuCnq4;f84u$WY@Ob_@=*#WAtE`Hq$(u>);nsdgs$+~|uhWdjIwQCC{ zj2c;fylb{F;yq^ma5}&ZUDe=K6jF+CggFTGqLKTS(kx>!w&?hacqmTCx@7&qK*>cw z4ca@u*Rc$Hl{^7k*sP=A)GR} z@74h?l>36aiq@bi!(tifk)w+Yu(Q0MvM=kOrPKCr{i)U%_3DNlQbsX^938=U`%H3d z{RO4NyunfCsf0hEfH`(L#xRW3UBD=%7pG`-gt<{u#9>LO z5;bG~C$c^VBkffx6sSa55o%Zk zx}@6-<020bPn;-Pa#< zZxJNH3e9L*naLoF`vnQ7^x!084p!d&o1k=_@JV^ri$LlV27x*{J~oR$k92g zVAv%)k?y}^LkR=aLIBmCO5;FVsbaYE`h^R%N0fX&z(Ump+mZWydaBP5O${3cUiOpN z810g1Vuyi?OqI1z1aBtMm3eH0%Dpy1*&JF9Xx!0J7BKk!&220LRdAeU2xl?F-kAaU z_qmP5hA7QjX$BSb4844>31%*oteX)>BLg29|0D()F4F66rNL^NJuym7mF28)-;Zs8 zw>&9L%1Wr1)*mqePnV#Nxa;}Esx8VYrI|k9Y3I#$`kW`FRcVWR)0@(vz{?!2Q}dLt z(y4SQtCcm%T4kMbh_YVUplnnQRSr`$g(!zBM<_=sM=3`u$0)}t$0^4vCnzT>o0OB3 zla*7HQF(nuON6O!OaA>65LL32f>|GDpx62E7vI3D%UC3D>o=NDmN)NE4L`ODz_=O zD|aY&Dt9S&EB7e(D)%Y(D-S3SDi0|SD~~9TDvv3TD^Dm-Do-g-E6*s;D$gm;D=#Q7 zDlaK7E3YW8Dz7Q8D{m-oDsL%oEAJ@pD(@-pD<2TNn&3kTKAhm=2tJYEGYGzb;EM^q zl;CR#zLDTN3BH%$M+knJ;O7W_iQv}=ev9Du2>yiNF9`mc;O`0knc&}uz!3oxK_P;Z z2yP+_BEm2tj3&Z(B1|O0R3fAiA(IHXM3_c|LLw9qp@hH-c!Yz9P)&q|L|8(E1|lpc z!b&2v5}|_#@J@x8XUQp_u*WW8>;K|oT?5VVM*0r=uA5jwzSId(_V#0WW5@Vb9|PWf zux<~YF}2fY*!Fr-dcxzTSGEl_Ys_la$-a8tYIB>b)u z*ZGl_w>3p)Iupjy5M@{BynmOXhL$Zu;8u44CU z<9V=K^+ARNRd|BWZoC9(c8%8`|8)Jv`p)_wJQ-Slpje|>kCu;{Ao~D)fPMDz+d*P^fLCNt9!9{MpLR=r?4fRHJ6(iS#ZA%6=p-&GKw2zfOm^}MueS^N;W`Vf=)Z`q=+ z-iy`h={o+De&I)+Dqr7G-_pY}+h^+dDM7Vpwy zZqP^Y_iN?E`SuY^##*Xtb?CaF zx?vAQveTJ~?B3b?8-oqaO|Ugin;WRs%{Y7r)^>m|>y@;y-=veYpkLgY4l7OpZr7m~ z1=WN1Hn)B0VQKx+P;<|~^B$d!V7~%eX7r4A{>CfJgF1eFzwmp!ekN9H9@Fs~`ZYz2 z{xB@0xG8#ChYs!TW@&Y}Gu*f;Gc`M{y=y64%SeU4(!yJky@;&YObj(R*9%_8>a!;eg-LiCYy^kJ{VB^~&EZYwKvK z?+ns6pGP8BumfdHjZOa5U>(>K+~WlIzD`?9zov!hSv!4!We>CZv5wx>uh1iIR}e@1 z7drgG{{v2sB{D#gD*!j?7!RpAb1VIYYARQ@F836f7$=$#ya46z3U0y z0B^>^8|g#UhgNnpwLlq;aRyc0)B?|Rsc&hArw;Y_X>L=vX=!r^UYbT3~hhyfUOSI;Ra3y5PTTH8s!9DMG1(_A56Y$#%UBW zryvs$vvP7a&R?IAk(HMhi#p6P5>Oq(9s4-;b&MeR2!f9!_$Y#p-s%|TNY-U^48h0# z_cHQqKWD*+)8|pC6y)cca+%^t?`xJF8IDYygX0N4A;JNZ_U+F;_-q|T%E-;mHlYd} z2T);5b4+*4aO_X;CW22Q_+)}l+3GmZF%zKRob6PCPoq$$|ECHQxNF;8t@R7nXQk(6 zOij+r$jje2Z+%{7ZtUEaIu4@jlsU>B6%IHIJd@zF2tJ$ObGACF906dbhTwAvK990< z{(s8O;?VF1m-+P>$xEla6r^Xx@)C43_Bk~n$1;7EFC_S)=qv~Bdiy|py^fialW)#) zi=%@=wL01y?T&*9zJ%azf;SVqWve6X=+vRM61*(}^&grA&yL~ey|z?mA-f>MWZ^K! zk(33^K^%uWV98!a@Z|)<@$!{h9Y;Bi1{RJb_$q?0rYv0ZpU!M(O5VJ>(F@k+=NHh` zmY=<`Zhb~UHvADaZKpZT26lRzwsRck0xRbed>z5pQ&w)!P1`q<(uT|e)0PV_Xamr^ zf=p`Kax?Se)W6$7-$3iw?AYSi>exo`O$6Ue@GS)2y47)+<8na0lHl72zMUf9@t+FG z)9_Eq?@umVpOIMrTAz`fnN1lg$OI{6W}35pv*V70V!G3D7cg@V!FLgSH)ZCYhzI!P zib=~Ctk0z|89BMRfC(>e0~uvSP2NL}$ElDWc0A&E)bSX>_Yr(Q!4DAp;8w>Ijwb;Z zeB?s}KTL7|TOWB)FlpY1i`inx%qz$;#qx^dP0GTnj@KNoJKiApQG$Vy#|eI7tK%)l z+d2zR68zME&w}@aDTn^{q`sch^9oEBK6QN6=Pc}Se66$a48hMvSO6b(Q1JPU!*!_4 zjI8Kd`pNM-g-Ynd{&4&WP=6ErJi#weD0o*KK-Cn~{gfOrl<7ISV0`n_V}k^z;I#II z>9jc&ZmiQm@XG|hLNQ;BU3I2+L?qHyv_X@5$e|dzoe89}h$bo4zqc~^1 z6W)!LKpmDlR{-8hg1;g7TZ;Fct`6HbzVN^;H2k3+ATukE2Dh0x6g1OZR?c>3S3=O$ z&NToE8-X7P{*i*hOVvOZn!lNRTl%dF)@NmB15A2W9;GuqFHXe{b287HD0pxl<)oe$ z?By>6|4Ly&9RSv|BkkNp!G-I=sza!jm6;nQaFg>iAkcY|^JM2K&Ql5go!~zR{*&Op zwmMIDo}r_`di^JY_8*2KbMD%4)_ZAe2D38qOy#=RxfM7_xW{sCb6(0g5O^Y>s5~0J zQ#@be1?#i(z}ID_XGg)Vao$M9ajo+@=k?ATh#(NbLIjZr(pKk9&YNM*ZY6?D1S^0E zw*S;)mmHdN{4uQy*B8K61h~k_PNyC_BclK`FlvzQcRm6PC5+RYk2)XIrDG?8BPyNH z)XS?o;3&_vJ~JaHGc$v_>)aeO^m9Jze2K~^p*?!p`HBwdB7z!)^tYb)Me0Mkjmye4 z9jEhc=LZ1Q+XQcSeh8xemp3CODfCl~ItN0qY|xFFTIoFP+~~ zjuWnr@0{NQ?vF$mOoSm6cPPUxT>A9ou5%+!F+BrJFhq&5QvBWd4`ule=bz5MoPQHx zI1%+8BsX@sY}YwSf?|ao^5UjT{W)x6e^L~aV>By z1cnzA0eH@)4CgS0OE&)f>)`ivoz2V1qTJ@h?pIxnt|q`t7>2o4x>f;Z3lZ{&kWVoS z7-mgD#TWIP7Qniv@p>-UMY%*vo!!<+(&n4b+Ijjq-QT#r&J z6UF?l$6Sx=99Iz`5ak$>Bi~FJpi`NXA6*O2xn2e+*YmCyTrav_B0>!j<`SWn2=lhO zUU9t&1ins$IwH)c1TOebHOyCh*PX|$hBQESP8MA;*^tQtYnzju7pD%}U7sct_h+up zftxRhu!snYDK|kT?p41IFBF<}!DQyrY(+s1nB45B`ToxJGnIBC7w7uL^{X!JdLk^1 zO53wz#8c0F%|J7A^UU41>mOCp?4GSC#5i2T&3dr9RYw>L8uO6+~!?ArVp#|2(4eog4K8>b@##c`Xs~Wu7;62Y7;Xy3RB5A=LnZc^)+Z;1nXpTb-iPoNYpdRWnq`*{az@Xd^;9 z1wNPo*A&dn81gF(xY8jw$SBCA3G!I?r%qE31ki-*UY)6W{$Fw50o7Ex{Tno~P;&wa zgb)Z2dhfj>Ei_F6NKtwbq@yT`90U{uL=sRG6+!HD2!s+!=n6qV5{hjsWAEeGeJ3z; z?|A?7X4bm%{_DY7oSg9e_TFDFd+%?rWI6?er~W(BVXsB}?^pz87#Z+4r}_r}o)nNS zNDsbSx)sYV7MA)kXx5T5gclL0bhS&;(I`0p%Re)ob+(FuiOgG41Kq{WA8 zC&owpLCcGbT;Z_yztfNXn**dHNlr~m)K1xz{(BY2AY-9m$4JP5V&55L90w`aXD^0G6T5>irxgpdHWaYKl#=m_aZa-&P9Kj z>MwnZkXgv=f9G^R2+#d3{5O&x5*c{_gy;R3n?uM*WIA7H=wEw(6Z+TtW##t27hMSw z+7+G=xRiD143Y-I^PyG&TMrY22_egoC;qfERw7SA4e~SyF96|uJqNt-x6ZiKVp#)? zkVeL)(3q%aY-GY8Ax-puSYIP+k>~jtI0wRu&mb>=@WWZYLHyu&P&8q3D&L-HCDQTl zLewD}`R%tJ*#N?ifbi04WD~L(ghP_j`E?9HP)8`fcUZ*ll?w&4{MUDX41oy+F%I96 z8or!XD=r}{BuGP;|$?PQAioIi$0qEo|jyBZ0ac_wx60zlnr)ivKeUKOyfS?}PAa z5MBeq&q7Vk7P*4oWKQ_8%{)QA_%i}8k*|=iK{(X%&V%p^5CNN4D+Iz|1f^9l!Zh+d z)arjle(?1qYx4~uynt1Kp-=?)lvG{aS%Fon;fOUBmVU$?kl{2`wSL5eP`(Rc%4T9n za#%EEQJPF4rY0n!U;=qnb!*p&A*FFLL?sP9LlY`7J}oY8X1$=0u!yLiC*-QiZ|FY6 zFn$#JKu@w=D)dDt)D%;)R%Hoit=>#d3k!>g2#*M#0Z@YC7%X3+*oa*z{?PL`uGJFg zEO-{8T2d-&P1gD>AsNqcEwA6MpH{rTSpgS?;9PH8UbZ$SqySwNLYluE)2OkOAsQbZ}7W()%xntyOA-J z&@l$;JPG^@DXNY5Uz$Q@&!|5XO881~Rhz5->G#m-g(sO5u`42cxw}KvaNWw9lAMr` znk4{R2LoWx5id*&rVlfLZGe$rn_vO3P$<%Q5-bIl2HOYAgB8OnV3n{_uqs#$tQK}2 zb`jPH>wxvcMq$@sJlI{>eb__TBiI)K0RdqFw1A9&oPer;j(~}Pqkyx3s{l#BTfk2s zKp~*~H2@u1K|TC32#59sCqZ}}2(Lc} ztXZ`YSO=_MwQgq&2-LB5{8o+t0Wjjb<4OSXfC8Wh5CJ7X z8BhUK0X0A!&;T?6EkGO40dxU9Kp!wz11*UeAiM*FcY<(eB7mx`4}=eZa7dV85IzdR zp`rL12%iMu(1<$?!l7|?4unHH7wDRl~((IXD_}y7^moXgoHssK6RFTFSOIcpjfz&o4_`mKdk5g z@(Lg3|CTj3;J3n{>mL~g{;BOI5VS(N=N}nC|A({7kEU=y=n9M8{~um-K-3EJ{{JPL zO(1TCKKmb)--^v9-`Q!!68;CXQy^)D#n3;h{bd$>8|Xh8(*ZkHNRRxZmivRP-hb46 z#tMV6|86_=gKhY~i|240$RkSTOU0$*%+U60KKm5MNXa_p^G&=Y+ep;r{1wf03dm#M& z?=%!`v-^Gn|MuZ`@BlEx2ebL$hs)q$U<8E!48kA%J$M3`;)5so;3v!A>j1PWfzBSE z{XLimEb_tgeDI59@DczO0kq$J_4nX=z(YRxJ|FyM8T>Qw2!y`{;qU$)`~rB*2fyTl z-!FsT01)z55dPus!5@JyeDEhe_|r1@EAS13e+J=S{uYdaqt-%T6oLrm@K z_;(Ni`+Kk$3iYGdC~=eoh*$+8R%hA&UuzhJMal4aN<%ymh-IF5lq`r?10vS`n`c?h zZ_OjGiiX9<_lFbKvI?wVXpIlrxAB2N4qg&f)*11E4%m-h8kpABhHmRr~p2AGaoFy3=TvEfe0LkkokLX7%CD1|Do%lqEOKw0;(H1es1%R{Z=J8qd!#1 zc2wejz>-kOAVMBQDDYvB#~uGi(RTmJk;88t9kmm+n=k4g3Mm7%2SgA-gwmgt?ec~O z1qxVPLS>`&qjI1dg7ygIqYgs13Y8=MK!gg2fZ73Mc4WMK!H*$`&|1C$2-5NFhPFQf z>tI3x>!F>j5NgE*5TW{yCV@XXsQfqypjQ0<5YUd@^}jI7|6vaE{u5Vw)QSfnLh~O@ z@+*_fpL$@UR($&q+W!wH;XgU3K-HkmQu()MMJ%6HU||X{4VV$k9A+bUM)15~t6;a_ zh~T8)jNlDHuHcg3Ey25j_k;w6cuDxK@Dt&u z!XHG0L_|cyL;w+S5wwV;2o^HZ$BXES=!+PN7>k%f>Jux-EZtsYgNU;TStL><6|!?} z7kMc1QFNWCJY=tCD@qmh72PZvAQ~jP6|%4j6O9m!5{(hf6wMON7R?dO6Fn$eAX*41 zUrR(wMd_mFMf*g#q7Ou0iLDcp6|;l%;=y9u#S+DmA$9XkNWXkWtX`~1tVN6=)*;p@ z)+=^RYzEQ^a>eGw?uh*)c364ONCZimE_eMa`maqHd$^qVAy{ zpngWZLVZSkMST|s#HGc}#I41H#3RL{#kYwkiSHKQBc3UqBVHtaSp10iQSl1#bK=e7 z-Qq0qKJftwQ3**2EeU-I7m1A$dn7=KD-t&(ev)`1@m}JC#3zX_XargajYMP6a%dy8 zC3*we1?`4*M~9=6&^yrS=-udjXb`<0or|WSyU=~;3G_627CnbvMBhZ;M&Ct0MZZFS z#lSIZFzYaa7yu)VL1QE_Sd0Qj38R8h!x&>WV4N|o7!t+<%l6Xmd$qka5B&m|VlKzr`l3OHWBEj1)HDm5;3 zO=@21k<=5ZXHqYuUP--?dMEWBi@>hMuEz>tMX+L604t6~V->I(SS_p$Ru5}{wZvLu zZL#)PN30Xp3mb@y!tTLlVzaQ>*c@yg_AvGs_Bgf@dkR~Ht;Sx))?pj4gV+fy2YVg6 zfL+4g!v2hXjD3oIjr}GKlU^kamnKUemaddOC0!+5Eqz(KUb<1bS$bTWE4?IrOZtxV z1L>coA4@;Qt;Qj6C>$CmiGvP>ak4lKoIcJFXN)t&+2HJO4!8|CXPh^VjHBXwapAZW zTpDgCZWk^Cw->h$2jWU_r8qjS9Cr+N99M}ug{#8V;TX6MTqmv@$HI-^#&B106F3g; zI&J~?2=`WIos6K2u#Bh-QU)ahok7be%c#nz%V^4I%b3WR$ymrZ$~eim$ZV7$%TQ&u z$OOxT%0$bg$?TNbC6gi3D$^s=Co>>3D6=HY_{aG7_|N#S`0uiC*)_83WCdlVWHn^XWbI|WWGS*fvVO8bvRh?CWW!_=WYcAH zW%FbY$mYwI%T~yqkUb?^C0i}aknNQnlpU5Gl^vJm$}Y*?lD#AQK=xg2}2p0O2a(7s4lbqP&(oS>8`RQ~r>Av3!X7-;;kN|3vBQ^1sOcssK|E zQIJxQR*+GURUjxRC}=6@DCj8|DwrskD_AOQRoJIct-w&2Q@E$_M&X^pdxZ}QpA^0* ze1kORVv2yGxFT9nQW2|&Q^YIEDQYW{6_XY773&mx6<-h$L=+KClq5>~CM$B7d}4sn_|OPnL#BR(WPB0eQPC%zjR+3VZR>CXE zDak8oE9og2C>bl6Dw!)eE4e7SDv^}@l%kYklwy^(D$tHPx+v7zH+HDO}R|DTDeP^rQEMPs63)Pt~{YU zr97iNr#!E`qj@2b94{iL>9O;}A;O-GHS7Ob{SEk$jI z+Ag(hwOqA4wZm$aYNypMsI{ndsIk?qsd3bJYR}Z(s;^Z?sT--=t5ene)C1JFsE4SB zt4FDCQ{S$hsJ>r4SN)*+A@ySQ5_Ot-x%x5n6Y3|`JJd(i7u8>?f78HdsB1WB1ZX5{ zWN7Ts*r#z&qfDbxqgvy#21A3X(XG*|F`zM|F{*JxQG1m(LVKOIkhZ8cQX8u+qb;W` zukEDms!h`N)b`fiq)pX6s{`n$>FDbi=osnP>yUIjbvEiybbNJ!b;5Kabz*elbmDb( z>g?9ptFuq%tj>9zOFCC{>UElQzUW5i#_J~NCh2DC9?&h&Ez&K~rRi4cp4P3_t<}At zdr7xNm!Zql?b5xYdr$YF?jzkNy3Zji(M@^*dck^OdXak3dTDx@dZ1p8-T}P=J(^y* zUWHzz-f6uvdYAO-^cwY=^|*QqdN=iM>uc+u&_AnRtAAdB6HQs5QWxU@w&p6+>(74$6sPS>*lg6iw2aQLJ$BnNUPa0o0 zku^~@3_Yyeu|ZP%V5d!Y#I2BwD0c?6BBnk!_J{anRzBMX^PR zMTJGB#c7K(7Q+@}7S}8$E%BBGmNZMcWw~XI z`(`g-54T@yFK91fkF*!J$Jk@-b?x=-jqFYA&F!u1ZS5WGo$OuhN%kK0UiOjp`|VHK zU$XDFf9J5qLD|91A;2NoVV^^RLy<#?1I?k_;g~~>!#RhG4p$r+9GV?k9d0>FIode} zIc{?V9djHHI2Je-IhHum9LpUm94j49J61a~9lITS9S0nT97i3mI!-!Xcbs+PIxaXa zIX-rL>iFF8)dr;v`Wp;47;iA!5WgW~!`==1He_#T-!Qmgc*E$1t4=T{5hpPxz)8Z% z)yc=n&&l5@$f?xnw9^@<8mDtki%yT6o;W>odg)Ab)^j#+HgYy~-tN5Hd5?3ZGw954 zW;+i#k2sGze|Hgf5pzMgpk1U~q+N_%Y+USJHn=#u1iB=+>~h)TlIgO~CEF#}rPSq| z3)7{`h2=8hGULK?x$pAab&acttFo)5tE;QKtC#C0SE{S8Yl>@@>wecf*L>GP*J9U8 zuI;X!u05`Ou58yK*SoGSTwlAsbN$uzlj|2ZgxfkdAvX~>1ve!(6*pBk4L5B!3pZ;w zlAEX7MmLI^uiIv~G`DQGT(^U6hun(YO57^kD&0=IopEEhG2Ob{y4`x+2HZGq({8uj zesX)@_Q>t2+jF;1ZeK|-(rVHg(mE2FBt^oJWJ&TQMUoB4g+wBGlDtU~q-fGMQYyXU$ebf>wOyH~hZx}SEhc0cPr>;BzC+at)M$m601 z!-MJ3?a}Ko;4$dI^SJBr(BrYkGmjS@pFLrot3B6v3VDip0-oZY@}7pCMxNGCkScG; zCc(!uz;ladh-a8*oaaH$Bc626qn;I>mpofN+dVrydp!HRB)srm>Rx(YhF&IK=3aJQ zj$Y1QZeH$C6uSVgEU!GTYOl*)^FK5yn_h2vx9QhS zpEi9Z!^o@2Ysl-#!elWrii{>pk#S^MvOJkcRw1jCwaB_;1F|vMjBH7^A=^Vy8eGUE zvL|^XnL_p@`;&vn!Q?PQ3a@Q>RPHGRfLM9ic>LEELDaoM^&IIQB|oLRBfsr)sSjJ zHK$rpZK)1aC#oyeoeG5|p;D=S)Bx%hY6vx)8b#ek-A+xUrcifKcTx9H_ffN{xzvNy zL)2pG5h|T}lzNUo&)FtXW>Q^6_kF<}XkFt-e&n6$LPliv9&jFuW zpL(Arp9!BipLw5Oe7^Y#_^SEp`x^QB_-^$L_096l_bv2o_wDm#`#$%5@B7iu(r<&G zi(jhWUcW5AHb0hMzu$eo=YFp?OKq0lOx*0UdE;iv=KY%sHy_^2*xb8$VDr-E2b&-H zuk}azi~H;QTlic12l_|&NBh(KEB#OVv;D96bNt`1u_Defp-EQ2R;j0 z8-xrJ57G-V53&jh2nr913d##Q98?u7f3n5J*tszq(^C3$iUqjb~t`F4b};Nn7(J{rj2$){_G>sSe08{5xPG`%xLt@2(^e!5djffBJv|jBg!J$B3Kdq5l|GpNi0e%NgPX@PP~zXPLfTMPYOs1 zPl`&aOJXE3lRhP{PF|C2m+Y48k$fWgZ1VZ!=gIGrKc?8ExTKI$@>5Dv%2Mv7JWF|* zs*!4#YLdDwH6?XNYEx=wYEK$0ZGD<>nq!(rns*v4tupO&+U>MQX-{{^?@-^NwPVMQ zeLJ#ujPID)F}KrTr{zwYodr8-JIi<8*m-N`-E@s~!*rAM;`F2G$J5`Xf87P!<-Uu$ z%WqfXF6OT8-K%yB?H1h~wmWWj!tUYSoZZtIiW!<2IvM*i4rUz6c#!cT7P63P1lNNo5Di9yNnk3-2CspfY}ss;Z1wCN+557yv!}Bcvv2KJ z-*2$rcz^Ex;{8YV-`@Xd|I-|k9NQd+oFh5Mb57>G%=wV>IoBcAJ=ZJuTy8^da~_Z< zorllclb4%!FzSXF>1P%h9Z&@Z4A1Qi4qWEUJNC@vT%xLPoI2!2T95b}`A zp^b+qhjI@UA3Ab~d1&C!P~n89`NQ&u)embOPCpDD&N)1L_~zj|C7LBhC8i~` zlFE|PCBKw>J0fs|awOy89ojwGL)v57Gulhq z8`>|l546v;Z*&1VoW7PWNEe|a>Ed(@9ZQ#?%h46+N_17a23?!3M>nLK(9P*qbX&Ru z-HGl>cc**NH_@qdKl&K`8l6L*rr)6R=!^7Q^t<%?^q=WZ=+Eh|=x^!o=^yD|=-ftvc$5zW&6s&vYfJyD~~IWFHb6e zUjC{4OZm5>0!K5C9y(fd^zhNrqqmMeJ^K9U%cF0OSsimb=6=lc*v4bk#~O|`9cwwp zsF1DDsL-m=snD<3S5a6|Tv1X%tN5wnWyR}?w-xV?Z#^D&JpOp%@s#7N<5!PQ9OoRL zK0!R8cf#O=(FxNN`%V;|C_Yhgf_CDU%2k!{$~BeiEBz`XDx)f6D&s0UDu*gZD#t3X zos>GMbW-J{+DXlmX(zK!=A6tsnSYXZ^1;cUPd+~R?3CFlr&BJc+)jC%I(_QOsrplm zr&>-6oEANeJdHYyJ{@{G;dIjJl+!y-f2|U%60Q=h0;>G0qN-x5Vyoh-9##EP^=s9~ zsxN1f&Saj+I+J}S_ssm6hi4w0d2;4?wMDf{wOh4&wO4gz^~LJT)pga4)t_tD)dC2-PgMB^#b*)>k;*$^+3HuJ*FO8kE(^V=yVaBHed;&Y z2i9+`kFJlckFQUxPpMC@AF6*||GxfvgKz`7L8<}QAlo3{px&U>pxdC|VANpJ zVB6r<;M)+~5Y`ac5YrIXkk*jikkPQWA*&&~;bg;L!*s)^#?_6;Mr@;UqfVoKqfw)2 zqeY`*qjRHMqkE%QBa)vDF4mE7vny16y5b!%&MYiw(LYhr6kYg%hbYkTWZ z>+{z4ZLl_xHcT6~O{Pt*O`%PrO}kC6&7jS=&9sf&w!7_MTVorujomiYHs7|?cDwDT zwg+u5+FrN4YkS}JvF$Sh&Jbnb7(|8&L!F_;&}Eo0EEzToJBA~}iQ&cA%m`&9Fwz+r zj7$c|$YB&QN*FXo8RHn^IHQJ9$6zqnjBAWZ#uQ_kG0V8gxWl-|c))nXc*1zw4r>=| zmux4rE4C}QtF>#k8?~FZTeMrX+qT=cliI26TiRpWQ`>j8?{44Qp4Fb;Uf6!P{YX2# zy}Z4to!9=bL$pJ(gV3SXVccQbVcuccVcp@};nv~N;nlIJgVGVy5!I2@k=b#eqoAXx zqojk@QQ2|2qq^g4$N7$n9nBqG9YY<{9g7_|J8pN}?YP(Rtm9?Jn~rxKzjl0Nu40NY zrI{*BU8X+MkZH^`W!fB|gbZfEXh?q}vP^O=Rr!^~sM6Usr@j*Y&QMuBEOQU7x$*-D|rAyG6Q@-PmrKZnh9}icMo+>cJsRLcE9NUwfj@|*B)5U>K@@9u^v>9M2}<-w#Tq1peLs1NYC+} zb3IKxte%mc@t%pEsh*jhrJmb8KlR-2`MKwD&zqj_to1AmOOB<$QevsHG+2f#6P7v4 zl4ZlPW4W;?tPs{VRvasymB>nFWw0_?AZtG>k9ClBgmsE_p4H0gVfC@ttYOv|YnpX~ z#bYh7ZnAE(9$-Sw)J9~HaX7?8Mmi1QmUhb{$ZR&09ZSU>tW%myEj`m*do#>tG{i*k9?}t8t zK6u~SKEXbbK1?6BPo__{PrgsF&$=(7FQxB9-`T$AzMj7EzL~zczWKhTzT16|`kwZ^ z=zG=ow(pm|Z~bfgk^T67<$kq(&3>JJ{eFvn>wdd_hkmDim;R0Yf&DT4$^B{l>HQh~ znf(X)3;K)t5BHb$)B8{MpYLz%@97`zAMGFSzt%t5&+T96zuAAg|EK=@{m=V94y+mw z8;}~n4ag424-f~m26P7u28;$w2h0Z?20RA*2f_v-2Vw@|1`-C+2QmgS2eJnC59AJ1 z4U7!j82HLw!fnyS^ugVOdj@j{4-Ot0EE+5sEFC;Ccww+* zuy1f|@Y*0}aC-2@;H|;CgZBp?4n7`yI{0o#U})VCdPsIieuy}vGNe9aFl0PrHe@km zJ!CuNI^;7HHWW9MFqAx$Hk3XD4&@9T7|I_i94a0G+B9Q{!jHo5nlFyT)1L{o|wKSH~yEuaD1+FOAVPZ zf->Pd5j+t;kv6esB7dTMqGF4MUFB@jibrY;plUWIHsI1P9!IW6URy5By-X@>6{EsCI{r?a1L+^I7OTi4vkaJ zso+#{PIJz1>N$;^W=`AG`YFtm)RgoTerns)&Z%8f8B>{4LsQdJvr}_Z^Ve0c8(lZK zZg$=BdhPY*>#f%r*O}9ZY1FjDG-et*9X*{ky>oik^qy(<^wjk9^z1ZuhB%`)V=!Yh zV>**JLz^j^IXZKE=HAS!nKv`8>|~wZ%o|a+?bw|ozs}pn$wxnpUavnnmasqWR5;}fA00%`?-&E zU$_EXICm{~Jy(p2;mUDUxkg-bt`*moyMgP%C2>8tWNsigf}70U$=%J}%gyHIau0F~ zxFy^QZZ)@o+sbX{c5-{U1Kc6*2zP=z$Gy#c#(m9w$NiQ2h5MbiiU;Qj^2B*EJT;y+ zPmgEFGvitEY3E;^Ya(yo9DacN9QNzr{-todGm|& zx90E6Kc0Ux|9t_zuy#RkL2LoFfL@SXAS|dY7%x~XSTEQuI4!s?xG#7vP!@s~A{SB? z(ibuoG8gtQd&Yp<|(Ip>Kh`FuX9jFuA~8xU=wl;myJ?3m+D~ zF2WX9FCrF27bO>oi)xFSi#m&jizbWai1YEaom2 zFV-xcTfDe + true @@ -1129,6 +1130,7 @@ + diff --git a/Builds/VisualStudio2012/Dexed.vcxproj.filters b/Builds/VisualStudio2012/Dexed.vcxproj.filters index 8a6e036..529789d 100644 --- a/Builds/VisualStudio2012/Dexed.vcxproj.filters +++ b/Builds/VisualStudio2012/Dexed.vcxproj.filters @@ -313,6 +313,9 @@ Dexed\Source + + Dexed\Source + Juce Modules\juce_audio_basics\buffers @@ -1437,6 +1440,9 @@ Dexed\Source + + Dexed\Source + Juce Modules\juce_audio_basics\buffers diff --git a/Dexed.jucer b/Dexed.jucer index d958335..9ae120a 100644 --- a/Dexed.jucer +++ b/Dexed.jucer @@ -57,6 +57,8 @@ + + diff --git a/README.md b/README.md index 0f69ad5..100711b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Dexed DX7 Software Emulator =========================== -Dexed is a multiplatform, multiformat plugin synth that is closely modeled on the Yamaha DX7. +Dexed is a multi platform, multiformat plugin synth that is closely modeled on the Yamaha DX7. Under the hood, it uses [music-synthesizer-for-android](https://code.google.com/p/music-synthesizer-for-android) for the synth engine and [JUCE](http://wwww.juce.com) as a plugin wrapper. @@ -13,10 +13,21 @@ Binary downloads It is far from finish but for those who want to try the "music-synthesizer-for-android" project on a PC/Mac, you can download it [here](http://le-son666.com/software/dexed) +(New) Features +-------------- +* Multi platform (OS X, Windows, Linux) and multi format (VST, AU); by using JUCE. +* The sound engine [music-synthesizer-for-android](https://code.google.com/p/music-synthesizer-for-android) is closely modeled on the original DX7 characteristics +* All of the 144 DX7 parameters are available from one single panel +* Fully supports DX7 input and output Sysex messages; including controller change. This means that you can use this with a native DX7/TX7 as a patch editor +* Each operator have a realtime VU meter to know wich one is active +* Can load any DX7/TX7 sysex programs [see this](http://www.synprez.com/SynprezFM/) for great collection of DX7 patches (SynprezFM-II-builtins.tgz) + TODO - Dexed ------------ -* Make all the knobs actually work -* Implement the DX look and feel +* Implement a better DX look and feel +* Better implementation of the LPF filter +* Better display of the amplitude envelope +* Implement a display of the algo TODO - msfa ----------- diff --git a/Source/GlobalEditor.cpp b/Source/GlobalEditor.cpp index f014ee6..8d8b4c0 100644 --- a/Source/GlobalEditor.cpp +++ b/Source/GlobalEditor.cpp @@ -50,7 +50,7 @@ GlobalEditor::GlobalEditor () addAndMakeVisible (lfoSpeed = new Slider ("lfoSpeed")); lfoSpeed->setRange (0, 99, 1); - lfoSpeed->setSliderStyle (Slider::LinearVertical); + lfoSpeed->setSliderStyle (Slider::LinearHorizontal); lfoSpeed->setTextBoxStyle (Slider::NoTextBox, false, 80, 20); lfoSpeed->addListener (this); @@ -68,18 +68,18 @@ GlobalEditor::GlobalEditor () addAndMakeVisible (lfoDelay = new Slider ("lfoDelay")); lfoDelay->setRange (0, 99, 1); - lfoDelay->setSliderStyle (Slider::LinearVertical); + lfoDelay->setSliderStyle (Slider::Rotary); lfoDelay->setTextBoxStyle (Slider::NoTextBox, false, 80, 20); lfoDelay->addListener (this); addAndMakeVisible (cutoff = new Slider ("cutoff")); - cutoff->setRange (0, 10, 0); + cutoff->setRange (0, 1, 0); cutoff->setSliderStyle (Slider::Rotary); cutoff->setTextBoxStyle (Slider::NoTextBox, false, 80, 20); cutoff->addListener (this); addAndMakeVisible (reso = new Slider ("reso")); - reso->setRange (0, 10, 0); + reso->setRange (0, 1, 0); reso->setSliderStyle (Slider::Rotary); reso->setTextBoxStyle (Slider::NoTextBox, false, 80, 20); reso->addListener (this); @@ -87,6 +87,78 @@ GlobalEditor::GlobalEditor () addAndMakeVisible (algoDisplay = new AlgoDisplay()); algoDisplay->setName ("algoDisplay"); + addAndMakeVisible (pitchRate2 = new Slider ("pitchRate2")); + pitchRate2->setRange (0, 99, 1); + pitchRate2->setSliderStyle (Slider::Rotary); + pitchRate2->setTextBoxStyle (Slider::NoTextBox, false, 80, 20); + pitchRate2->addListener (this); + + addAndMakeVisible (pitchRate3 = new Slider ("pitchRate3")); + pitchRate3->setRange (0, 99, 1); + pitchRate3->setSliderStyle (Slider::Rotary); + pitchRate3->setTextBoxStyle (Slider::NoTextBox, false, 80, 20); + pitchRate3->addListener (this); + + addAndMakeVisible (pitchRate4 = new Slider ("pitchRate4")); + pitchRate4->setRange (0, 99, 1); + pitchRate4->setSliderStyle (Slider::Rotary); + pitchRate4->setTextBoxStyle (Slider::NoTextBox, false, 80, 20); + pitchRate4->addListener (this); + + addAndMakeVisible (pitchRate1 = new Slider ("pitchRate1")); + pitchRate1->setRange (0, 99, 1); + pitchRate1->setSliderStyle (Slider::Rotary); + pitchRate1->setTextBoxStyle (Slider::NoTextBox, false, 80, 20); + pitchRate1->addListener (this); + + addAndMakeVisible (pitchLevel2 = new Slider ("pitchLevel2")); + pitchLevel2->setRange (0, 99, 1); + pitchLevel2->setSliderStyle (Slider::Rotary); + pitchLevel2->setTextBoxStyle (Slider::NoTextBox, false, 80, 20); + pitchLevel2->addListener (this); + + addAndMakeVisible (pitchLevel3 = new Slider ("pitchLevel3")); + pitchLevel3->setRange (0, 99, 1); + pitchLevel3->setSliderStyle (Slider::Rotary); + pitchLevel3->setTextBoxStyle (Slider::NoTextBox, false, 80, 20); + pitchLevel3->addListener (this); + + addAndMakeVisible (pitchLevel4 = new Slider ("pitchLevel4")); + pitchLevel4->setRange (0, 99, 1); + pitchLevel4->setSliderStyle (Slider::Rotary); + pitchLevel4->setTextBoxStyle (Slider::NoTextBox, false, 80, 20); + pitchLevel4->addListener (this); + + addAndMakeVisible (pitchLevel1 = new Slider ("pitchLevel1")); + pitchLevel1->setRange (0, 99, 1); + pitchLevel1->setSliderStyle (Slider::Rotary); + pitchLevel1->setTextBoxStyle (Slider::NoTextBox, false, 80, 20); + pitchLevel1->addListener (this); + + addAndMakeVisible (feedback = new Slider ("feedback")); + feedback->setRange (0, 7, 1); + feedback->setSliderStyle (Slider::Rotary); + feedback->setTextBoxStyle (Slider::NoTextBox, false, 80, 20); + feedback->addListener (this); + + addAndMakeVisible (transpose = new Slider ("transpose")); + transpose->setRange (0, 49, 0); + transpose->setSliderStyle (Slider::LinearVertical); + transpose->setTextBoxStyle (Slider::NoTextBox, false, 80, 20); + transpose->addListener (this); + + addAndMakeVisible (oscSync = new ToggleButton ("oscSync")); + oscSync->setButtonText (String::empty); + + addAndMakeVisible (pitchModSens = new Slider ("pitchModSens")); + pitchModSens->setRange (0, 7, 0); + pitchModSens->setSliderStyle (Slider::Rotary); + pitchModSens->setTextBoxStyle (Slider::NoTextBox, false, 80, 20); + pitchModSens->addListener (this); + + addAndMakeVisible (lfoSync = new ToggleButton ("lfoSync")); + lfoSync->setButtonText (String::empty); + //[UserPreSize] //[/UserPreSize] @@ -95,6 +167,8 @@ GlobalEditor::GlobalEditor () //[Constructor] You can add your own custom stuff here.. + systemMsg << "* DEXED DX synthesizer *"; + //[/Constructor] } @@ -112,6 +186,19 @@ GlobalEditor::~GlobalEditor() cutoff = nullptr; reso = nullptr; algoDisplay = nullptr; + pitchRate2 = nullptr; + pitchRate3 = nullptr; + pitchRate4 = nullptr; + pitchRate1 = nullptr; + pitchLevel2 = nullptr; + pitchLevel3 = nullptr; + pitchLevel4 = nullptr; + pitchLevel1 = nullptr; + feedback = nullptr; + transpose = nullptr; + oscSync = nullptr; + pitchModSens = nullptr; + lfoSync = nullptr; //[Destructor]. You can add your own custom destruction code here.. @@ -125,20 +212,44 @@ void GlobalEditor::paint (Graphics& g) //[/UserPrePaint] //[UserPaint] Add your own custom painting code here.. + g.setColour (Colours::black); + g.setFont (Font (Font::getDefaultMonospacedFontName(), 15.00f, Font::plain)); + g.drawText (systemMsg, + 11, 8, 300, 8, + Justification::centredLeft, true); + + g.setColour (Colours::black); + g.setFont (Font (Font::getDefaultMonospacedFontName(), 15.00f, Font::plain)); + g.drawText (paramMsg, + 11, 24, 300, 8, + Justification::centredLeft, true); //[/UserPaint] } void GlobalEditor::resized() { - algo->setBounds (784, 48, 64, 24); - lfoType->setBounds (768, 8, 80, 16); - lfoSpeed->setBounds (712, 0, 23, 80); - lfoAmDepth->setBounds (816, 24, 32, 24); - lfoPitchDepth->setBounds (792, 24, 32, 24); - lfoDelay->setBounds (736, 0, 23, 80); - cutoff->setBounds (176, 40, 48, 48); - reso->setBounds (232, 40, 48, 48); - algoDisplay->setBounds (8, 8, 150, 72); + algo->setBounds (480, 64, 80, 24); + lfoType->setBounds (624, 40, 96, 16); + lfoSpeed->setBounds (624, 16, 96, 16); + lfoAmDepth->setBounds (696, 64, 24, 24); + lfoPitchDepth->setBounds (648, 64, 24, 24); + lfoDelay->setBounds (672, 64, 24, 24); + cutoff->setBounds (8, 40, 48, 48); + reso->setBounds (64, 40, 48, 48); + algoDisplay->setBounds (480, 8, 126, 56); + pitchRate2->setBounds (776, 64, 32, 24); + pitchRate3->setBounds (800, 64, 32, 24); + pitchRate4->setBounds (824, 64, 32, 24); + pitchRate1->setBounds (752, 64, 32, 24); + pitchLevel2->setBounds (776, 40, 32, 24); + pitchLevel3->setBounds (800, 40, 32, 24); + pitchLevel4->setBounds (824, 40, 32, 24); + pitchLevel1->setBounds (752, 40, 32, 24); + feedback->setBounds (560, 64, 24, 24); + transpose->setBounds (728, 0, 24, 56); + oscSync->setBounds (584, 64, 24, 24); + pitchModSens->setBounds (728, 64, 24, 24); + lfoSync->setBounds (624, 64, 24, 24); //[UserResized] Add your own custom resize handling here.. //[/UserResized] } @@ -183,6 +294,61 @@ void GlobalEditor::sliderValueChanged (Slider* sliderThatWasMoved) //[UserSliderCode_reso] -- add your slider handling code here.. //[/UserSliderCode_reso] } + else if (sliderThatWasMoved == pitchRate2) + { + //[UserSliderCode_pitchRate2] -- add your slider handling code here.. + //[/UserSliderCode_pitchRate2] + } + else if (sliderThatWasMoved == pitchRate3) + { + //[UserSliderCode_pitchRate3] -- add your slider handling code here.. + //[/UserSliderCode_pitchRate3] + } + else if (sliderThatWasMoved == pitchRate4) + { + //[UserSliderCode_pitchRate4] -- add your slider handling code here.. + //[/UserSliderCode_pitchRate4] + } + else if (sliderThatWasMoved == pitchRate1) + { + //[UserSliderCode_pitchRate1] -- add your slider handling code here.. + //[/UserSliderCode_pitchRate1] + } + else if (sliderThatWasMoved == pitchLevel2) + { + //[UserSliderCode_pitchLevel2] -- add your slider handling code here.. + //[/UserSliderCode_pitchLevel2] + } + else if (sliderThatWasMoved == pitchLevel3) + { + //[UserSliderCode_pitchLevel3] -- add your slider handling code here.. + //[/UserSliderCode_pitchLevel3] + } + else if (sliderThatWasMoved == pitchLevel4) + { + //[UserSliderCode_pitchLevel4] -- add your slider handling code here.. + //[/UserSliderCode_pitchLevel4] + } + else if (sliderThatWasMoved == pitchLevel1) + { + //[UserSliderCode_pitchLevel1] -- add your slider handling code here.. + //[/UserSliderCode_pitchLevel1] + } + else if (sliderThatWasMoved == feedback) + { + //[UserSliderCode_feedback] -- add your slider handling code here.. + //[/UserSliderCode_feedback] + } + else if (sliderThatWasMoved == transpose) + { + //[UserSliderCode_transpose] -- add your slider handling code here.. + //[/UserSliderCode_transpose] + } + else if (sliderThatWasMoved == pitchModSens) + { + //[UserSliderCode_pitchModSens] -- add your slider handling code here.. + //[/UserSliderCode_pitchModSens] + } //[UsersliderValueChanged_Post] //[/UsersliderValueChanged_Post] @@ -214,7 +380,32 @@ void GlobalEditor::bind(DexedAudioProcessor *parent) { parent->lfoWaveform->bind(lfoType); parent->lfoAmpDepth->bind(lfoAmDepth); parent->lfoPitchDepth->bind(lfoPitchDepth); - processor = parent; + parent->lfoSync->bind(lfoSync); + parent->oscSync->bind(oscSync); + parent->transpose->bind(transpose); + parent->feedback->bind(feedback); + parent->pitchModSens->bind(pitchModSens); + parent->pitchEgLevel[0]->bind(pitchLevel1); + parent->pitchEgLevel[1]->bind(pitchLevel2); + parent->pitchEgLevel[2]->bind(pitchLevel3); + parent->pitchEgLevel[3]->bind(pitchLevel4); + parent->pitchEgRate[0]->bind(pitchRate1); + parent->pitchEgRate[1]->bind(pitchRate2); + parent->pitchEgRate[2]->bind(pitchRate3); + parent->pitchEgRate[3]->bind(pitchRate4); + parent->fxCutoff->bind(cutoff); + parent->fxReso->bind(reso); + processor = parent; +} + +void GlobalEditor::setSystemMessage(String msg) { + systemMsg = msg; + repaint(); +} + +void GlobalEditor::setParamMessage(String msg) { + paramMsg = msg; + repaint(); } //[/MiscUserCode] @@ -235,40 +426,90 @@ BEGIN_JUCER_METADATA fixedSize="1" initialWidth="855" initialHeight="90"> + explicitFocusOrder="0" pos="672 64 24 24" min="0" max="99" int="1" + style="Rotary" textBoxPos="NoTextBox" textBoxEditable="1" textBoxWidth="80" + textBoxHeight="20" skewFactor="1"/> + + + + + + + + + + + + + END_JUCER_METADATA diff --git a/Source/GlobalEditor.h b/Source/GlobalEditor.h index 2fb0c2f..86215e9 100644 --- a/Source/GlobalEditor.h +++ b/Source/GlobalEditor.h @@ -47,8 +47,9 @@ public: //============================================================================== //[UserMethods] -- You can add your own custom methods in this section. - void bind(DexedAudioProcessor *processor); + void setSystemMessage(String msg); + void setParamMessage(String msg); //[/UserMethods] void paint (Graphics& g); @@ -61,6 +62,8 @@ public: private: //[UserVariables] -- You can add your own custom variables in this section. DexedAudioProcessor *processor; + String systemMsg; + String paramMsg; //[/UserVariables] //============================================================================== @@ -73,6 +76,19 @@ private: ScopedPointer cutoff; ScopedPointer reso; ScopedPointer algoDisplay; + ScopedPointer pitchRate2; + ScopedPointer pitchRate3; + ScopedPointer pitchRate4; + ScopedPointer pitchRate1; + ScopedPointer pitchLevel2; + ScopedPointer pitchLevel3; + ScopedPointer pitchLevel4; + ScopedPointer pitchLevel1; + ScopedPointer feedback; + ScopedPointer transpose; + ScopedPointer oscSync; + ScopedPointer pitchModSens; + ScopedPointer lfoSync; //============================================================================== diff --git a/Source/OperatorEditor.cpp b/Source/OperatorEditor.cpp index 6bd0e20..cd01e05 100644 --- a/Source/OperatorEditor.cpp +++ b/Source/OperatorEditor.cpp @@ -462,6 +462,7 @@ void OperatorEditor::bind(DexedAudioProcessor *parent, int op) { parent->opCtrl[op].sclRightCurve->bind(kbdRightCurve); parent->opCtrl[op].sclLeftDepth->bind(sclLeftLevel); parent->opCtrl[op].sclRightDepth->bind(sclRightLevel); + parent->opCtrl[op].sclRate->bind(sclRateScaling); } diff --git a/Source/PluginFx.cpp b/Source/PluginFx.cpp new file mode 100644 index 0000000..36386ab --- /dev/null +++ b/Source/PluginFx.cpp @@ -0,0 +1,86 @@ +/* + ============================================================================== + + PluginFx.cpp + Created: 26 Dec 2013 7:13:29pm + Author: Pascal Gauthier + + The LPF is taken from the PD moog~ object. (David Lowenfels) + Code is based off of Tim Stilson's moog filter code + + ============================================================================== +*/ + +#include "math.h" +#include "PluginFx.h" + +static float gaintable[199] = { + 0.999969, 0.990082, 0.980347, 0.970764, 0.961304, 0.951996, 0.94281, 0.933777, 0.924866, 0.916077, 0.90741, 0.898865, 0.890442, + 0.882141, 0.873962, 0.865906, 0.857941, 0.850067, 0.842346, 0.834686, 0.827148, 0.819733, 0.812378, 0.805145, 0.798004, 0.790955, + 0.783997, 0.77713, 0.770355, 0.763672, 0.75708 , 0.75058, 0.744141, 0.737793, 0.731537, 0.725342, 0.719238, 0.713196, 0.707245, + 0.701355, 0.695557, 0.689819, 0.684174, 0.678558, 0.673035, 0.667572, 0.66217, 0.65686, 0.651581, 0.646393, 0.641235, 0.636169, + 0.631134, 0.62619, 0.621277, 0.616425, 0.611633, 0.606903, 0.602234, 0.597626, 0.593048, 0.588531, 0.584045, 0.579651, 0.575287, + 0.570953, 0.566681, 0.562469, 0.558289, 0.554169, 0.550079, 0.546051, 0.542053, 0.538116, 0.53421, 0.530334, 0.52652, 0.522736, + 0.518982, 0.515289, 0.511627, 0.507996 , 0.504425, 0.500885, 0.497375, 0.493896, 0.490448, 0.487061, 0.483704, 0.480377, 0.477081, + 0.473816, 0.470581, 0.467377, 0.464203, 0.46109, 0.457977, 0.454926, 0.451874, 0.448883, 0.445892, 0.442932, 0.440033, 0.437134, + 0.434265, 0.431427, 0.428619, 0.425842, 0.423096, 0.42038, 0.417664, 0.415009, 0.412354, 0.409729, 0.407135, 0.404572, 0.402008, + 0.399506, 0.397003, 0.394501, 0.392059, 0.389618, 0.387207, 0.384827, 0.382477, 0.380127, 0.377808, 0.375488, 0.37323, 0.370972, + 0.368713, 0.366516, 0.364319, 0.362122, 0.359985, 0.357849, 0.355713, 0.353607, 0.351532, 0.349457, 0.347412, 0.345398, 0.343384, + 0.34137, 0.339417, 0.337463, 0.33551, 0.333588, 0.331665, 0.329773, 0.327911, 0.32605, 0.324188, 0.322357, 0.320557, 0.318756, + 0.316986, 0.315216, 0.313446, 0.311707, 0.309998, 0.308289, 0.30658, 0.304901, 0.303223, 0.301575, 0.299927, 0.298309, 0.296692, + 0.295074, 0.293488, 0.291931, 0.290375, 0.288818, 0.287262, 0.285736, 0.284241, 0.282715, 0.28125, 0.279755, 0.27829, 0.276825, + 0.275391, 0.273956, 0.272552, 0.271118, 0.269745, 0.268341, 0.266968, 0.265594, 0.264252, 0.262909, 0.261566, 0.260223, 0.258911, + 0.257599, 0.256317, 0.255035, 0.25375 +}; + +static inline float saturate(float input) { //clamp without branching +#define _limit 0.95 + float x1 = fabsf( input + _limit ); + float x2 = fabsf( input - _limit ); + return 0.5 * (x1 - x2); +} + +static inline float crossfade(float amount, float a, float b) { + return (1-amount) * a + amount * b; +} + +void PluginFx::init(int sampleRate) { + srate = sampleRate; + output = 0; + for(int i=0;i<4;i++) + state[i] = 0; +} + +void PluginFx::process(float *work, int sampleSize) { + // the UI values haved changed + if ( uiCutoff != pCutoff || uiReso != pReso) { + // calc cutoff + float freqCutoff = uiCutoff * 22000; + float fc = 2 * freqCutoff / srate; + float x2 = fc*fc; + float x3 = fc*x2; + p = -0.69346 * x3 - 0.59515 * x2 + 3.2937 * fc - 1.0072; //cubic fit + + // calc reso + float ix = p * 99; + int ixint = floor( ix ); + float ixfrac = ix - ixint; + Q = uiReso * crossfade( ixfrac, gaintable[ ixint + 99 ], gaintable[ ixint + 100 ] ); + + pCutoff = uiCutoff; + pReso = uiReso; + } + + for (int i=0; i < sampleSize; i++ ) { + output = 0.25 * ( work[i] - output ); //negative feedback + for(int pole=0; pole < 4; pole++) { + float temp = state[pole]; + output = saturate( output + p * (output - temp)); + state[pole] = output; + output = saturate( output + temp ); + } + work[i] = output; + output *= Q; //scale the feedback + } +} + diff --git a/Source/PluginFx.h b/Source/PluginFx.h new file mode 100644 index 0000000..42976ae --- /dev/null +++ b/Source/PluginFx.h @@ -0,0 +1,34 @@ +/* + ============================================================================== + + PluginFx.h + Created: 26 Dec 2013 7:13:29pm + Author: Pascal Gauthier + + ============================================================================== +*/ + +#ifndef PLUGINFX_H_INCLUDED +#define PLUGINFX_H_INCLUDED + +class PluginFx { + /** + * Used for the 4pole LFP + */ + // process and ui values + float pReso; + float pCutoff; + float p, Q; + int srate; + float state[4]; + float output = 0; +public: + + float uiCutoff = 0; + float uiReso = 0; + + void init(int sampleRate); + void process(float *work, int sampleSize); +}; + +#endif // PLUGINFX_H_INCLUDED diff --git a/Source/PluginParam.cpp b/Source/PluginParam.cpp index 9ab8bad..065b044 100755 --- a/Source/PluginParam.cpp +++ b/Source/PluginParam.cpp @@ -20,6 +20,7 @@ #include "PluginParam.h" #include "PluginProcessor.h" +#include "PluginEditor.h" // ************************************************************************ // @@ -65,21 +66,64 @@ void Ctrl::unbind() { } } +void Ctrl::publishValue(float value) { + parent->beginParameterChangeGesture(idx); + parent->setParameterNotifyingHost(idx, value); + parent->endParameterChangeGesture(idx); +} + +void Ctrl::sliderValueChanged(Slider* moved) { + publishValue(moved->getValue()); +} + +void Ctrl::buttonClicked(Button* clicked) { + publishValue(clicked->getToggleStateValue() == 1 ? 1 : 0); +} + +void Ctrl::comboBoxChanged(ComboBox* combo) { + publishValue((combo->getSelectedId() - 1) / combo->getNumItems()); +} + +// ************************************************************************ +// CtrlDX - control DX mapping +CtrlFloat::CtrlFloat(String name, float *storageValue) : Ctrl(name) { + vPointer = storageValue; +} + +float CtrlFloat::getValueHost() { + return *vPointer; +} + +void CtrlFloat::setValueHost(float v) { + *vPointer = v; +} + +String CtrlFloat::getValueDisplay() { + String display; + display << *vPointer; + return display; +} + +void CtrlFloat::updateComponent() { + if (slider != NULL) { + slider->setValue(*vPointer, NotificationType::dontSendNotification); + } +} + // ************************************************************************ -// CtrlInt ================================================================ -CtrlDX::CtrlDX(String name, int steps, int offset, bool starts1) : - Ctrl(name) { +// CtrlDX - control DX mapping +CtrlDX::CtrlDX(String name, int steps, int offset, bool starts1) : Ctrl(name) { add1 = starts1 == 1; this->steps = steps; - value = 0; + dxValue = 0; dxOffset = offset; } -float CtrlDX::getValuePlugin() { - return value / steps; +float CtrlDX::getValueHost() { + return dxValue / steps; } -void CtrlDX::setValuePlugin(float f) { +void CtrlDX::setValueHost(float f) { setValue((f * steps)); } @@ -88,7 +132,7 @@ void CtrlDX::setValue(int v) { TRACE("WARNING: value too big %s : %d", label.toRawUTF8(), v); v = steps - 1; } - value = v; + dxValue = v; if (dxOffset >= 0) { if (parent != NULL) parent->setDxValue(dxOffset, v); @@ -97,36 +141,36 @@ void CtrlDX::setValue(int v) { int CtrlDX::getValue() { if (dxOffset >= 0) - value = parent->data[dxOffset]; - return value; + dxValue = parent->data[dxOffset]; + return dxValue; } String CtrlDX::getValueDisplay() { String ret; - ret << getValue(); + ret << ( getValue() + add1 ); return ret; } -void CtrlDX::publishValue(int value) { - parent->beginParameterChangeGesture(idx); - parent->setParameterNotifyingHost(idx, (((float) value) / steps)); - parent->endParameterChangeGesture(idx); +void CtrlDX::publishValue(float value) { + Ctrl::publishValue(value / steps); + + DexedAudioProcessorEditor *editor = (DexedAudioProcessorEditor *) parent->getActiveEditor(); + if ( editor == NULL ) + return; + String msg; + msg << label << " = " << getValueDisplay(); + editor->global.setParamMessage(msg); } void CtrlDX::sliderValueChanged(Slider* moved) { publishValue(((int) moved->getValue() - add1)); } -void CtrlDX::buttonClicked(Button* clicked) { - publishValue(clicked->getToggleStateValue() == 1 ? 1 : 0); -} - void CtrlDX::comboBoxChanged(ComboBox* combo) { publishValue(combo->getSelectedId() - 1); } void CtrlDX::updateComponent() { - //TRACE("setting for %s %d", label.toRawUTF8(), getValue()); if (slider != NULL) { slider->setValue(getValue() + add1, NotificationType::dontSendNotification); @@ -151,11 +195,18 @@ void CtrlDX::updateComponent() { } } -// ************************************************************************ -// Patcher ================================================================ +/*************************************************************** + * + */ void DexedAudioProcessor::initCtrl() { importSysex(BinaryData::startup_syx); + fxCutoff = new CtrlFloat("Cutoff", &fx.uiCutoff); + ctrl.add(fxCutoff); + + fxReso = new CtrlFloat("Resonance", &fx.uiReso); + ctrl.add(fxReso); + // fill operator values; for (int i = 0; i < 6; i++) { //// In the Sysex, OP6 comes first, then OP5... @@ -167,107 +218,129 @@ void DexedAudioProcessor::initCtrl() { for (int j = 0; j < 4; j++) { String opRate; - opRate << opName << "-EGR" << (j + 1); + opRate << opName << " EGR" << (j + 1); opCtrl[opVal].egRate[j] = new CtrlDX(opRate, 100, opTarget + j); ctrl.add(opCtrl[opVal].egRate[j]); String opLevel; - opLevel << opName << "-EGL" << (j + 1); - opCtrl[opVal].egLevel[j] = new CtrlDX(opLevel, 100, - opTarget + j + 4); + opLevel << opName << " EGL" << (j + 1); + opCtrl[opVal].egLevel[j] = new CtrlDX(opLevel, 100, opTarget + j + 4); ctrl.add(opCtrl[opVal].egLevel[j]); } String opVol; - opVol << opName << "-LEVEL"; + opVol << opName << " OUTPUT LEVEL"; opCtrl[opVal].level = new CtrlDX(opVol, 100, opTarget + 16); ctrl.add(opCtrl[opVal].level); String opMode; - opMode << opName << "-MODE"; + opMode << opName << " MODE"; opCtrl[opVal].opMode = new CtrlDX(opMode, 1, opTarget + 17); ctrl.add(opCtrl[opVal].opMode); String coarse; - coarse << opName << "-COARSE"; + coarse << opName << " F COARSE"; opCtrl[opVal].coarse = new CtrlDX(coarse, 32, opTarget + 18); ctrl.add(opCtrl[opVal].coarse); String fine; - fine << opName << "-FINE"; + fine << opName << " F FINE"; opCtrl[opVal].fine = new CtrlDX(fine, 100, opTarget + 19); ctrl.add(opCtrl[opVal].fine); String detune; - detune << opName << "-DETUNE"; + detune << opName << " OSC DETUNE"; opCtrl[opVal].detune = new CtrlDX(detune, 15, opTarget + 20); ctrl.add(opCtrl[opVal].detune); String sclBrkPt; - sclBrkPt << opName << "-SCL_BRK_PNT"; + sclBrkPt << opName << " BREAK POINT"; opCtrl[opVal].sclBrkPt = new CtrlDX(sclBrkPt, 100, opTarget + 8); ctrl.add(opCtrl[opVal].sclBrkPt); String sclLeftDepth; - sclLeftDepth << opName << "-SCL_LFT_DEPTH"; + sclLeftDepth << opName << " L SCALE DEPTH"; opCtrl[opVal].sclLeftDepth = new CtrlDX(sclLeftDepth, 100, opTarget + 9); ctrl.add(opCtrl[opVal].sclLeftDepth); String sclRightDepth; - sclRightDepth << opName << "-SCL_RHT_DEPTH"; + sclRightDepth << opName << " R SCALE DEPTH"; opCtrl[opVal].sclRightDepth = new CtrlDX(sclRightDepth, 100, opTarget + 10); ctrl.add(opCtrl[opVal].sclRightDepth); String sclLeftCurve; - sclLeftCurve << opName << "-SCL_LFT_CURVE"; + sclLeftCurve << opName << " L KEY SCALE"; opCtrl[opVal].sclLeftCurve = new CtrlDX(sclLeftCurve, 4, opTarget + 11); ctrl.add(opCtrl[opVal].sclLeftCurve); String sclRightCurve; - sclRightCurve << opName << "-SCL_RHT_CURVE"; + sclRightCurve << opName << " R KEY SCALE"; opCtrl[opVal].sclRightCurve = new CtrlDX(sclRightCurve, 4, opTarget + 12); ctrl.add(opCtrl[opVal].sclRightCurve); String sclRate; - sclRate << opName << "-SCL_RATE"; + sclRate << opName << " RATE SCALING"; opCtrl[opVal].sclRate = new CtrlDX(sclRate, 7, opTarget + 13); ctrl.add(opCtrl[opVal].sclRate); String ampModSens; - ampModSens << opName << "-AMP_MODSENS"; + ampModSens << opName << " A MOD SENS."; opCtrl[opVal].ampModSens = new CtrlDX(ampModSens, 3, opTarget + 14); ctrl.add(opCtrl[opVal].ampModSens); String velModSens; - velModSens << opName << "-VEL_MODSENS"; + velModSens << opName << " KEY VELOCITY"; opCtrl[opVal].velModSens = new CtrlDX(velModSens, 8, opTarget + 15); ctrl.add(opCtrl[opVal].velModSens); } - algo = new CtrlDX("Algorithm", 32, 134, true); + algo = new CtrlDX("ALGORITHM", 32, 134, true); ctrl.add(algo); - lfoRate = new CtrlDX("LFO-Rate", 100, 137); + feedback = new CtrlDX("FEEDBACK", 8, 135); + ctrl.add(feedback); + + oscSync = new CtrlDX("OSC KEY SYNC", 2, 136); + ctrl.add(oscSync); + + lfoRate = new CtrlDX("LFO SPEED", 100, 137); ctrl.add(lfoRate); - lfoDelay = new CtrlDX("LFO-Delay", 100, 138); + lfoDelay = new CtrlDX("LFO DELAY", 100, 138); ctrl.add(lfoDelay); - lfoPitchDepth = new CtrlDX("LFO-PitchDepth", 100, 139); + lfoPitchDepth = new CtrlDX("LFO PM DEPTH", 100, 139); ctrl.add(lfoPitchDepth); - lfoAmpDepth = new CtrlDX("LFO-AmpDepth", 100, 140); + lfoAmpDepth = new CtrlDX("LFO AM DEPTH", 100, 140); ctrl.add(lfoAmpDepth); - lfoSync = new CtrlDX("LFO-Sync", 2, 141); + lfoSync = new CtrlDX("LFO KEY SYNC", 2, 141); ctrl.add(lfoSync); - lfoWaveform = new CtrlDX("LFO-Waveform", 5, 142); + lfoWaveform = new CtrlDX("LFO WAVE", 5, 142); ctrl.add(lfoWaveform); - - for (int i = 0; i < ctrl.size(); i++) { + + transpose = new CtrlDX("MIDDLE C", 49, 144); + ctrl.add(transpose); + + pitchModSens = new CtrlDX("P MODE SENS.", 8, 143); + ctrl.add(pitchModSens); + + for (int i=0;i<4;i++) { + String rate; + rate << "PITCH EGR" << (i+1); + String level; + level << "PITCH EGL" << (i+1); + pitchEgRate[i] = new CtrlDX(rate, 99, 126+i); + ctrl.add(pitchEgRate[i]); + pitchEgLevel[i] = new CtrlDX(level, 99, 130+i); + ctrl.add(pitchEgLevel[i]); + } + + for (int i=0; i < ctrl.size(); i++) { ctrl[i]->idx = i; ctrl[i]->parent = this; } @@ -370,11 +443,11 @@ int DexedAudioProcessor::getNumParameters() { } float DexedAudioProcessor::getParameter(int index) { - return ctrl[index]->getValuePlugin(); + return ctrl[index]->getValueHost(); } void DexedAudioProcessor::setParameter(int index, float newValue) { - ctrl[index]->setValuePlugin(newValue); + ctrl[index]->setValueHost(newValue); } int DexedAudioProcessor::getNumPrograms() { diff --git a/Source/PluginParam.h b/Source/PluginParam.h index 0262017..c8018ac 100755 --- a/Source/PluginParam.h +++ b/Source/PluginParam.h @@ -42,12 +42,22 @@ public: void bind(Button *b); void bind(ComboBox *c); void unbind(); + + // use this to signal a parameter change to the host + void publishValue(float value); - virtual void setValuePlugin(float f) = 0; - virtual float getValuePlugin() = 0; + /** + * Host value is related 0.0 to 1.0 values + */ + virtual void setValueHost(float f) = 0; + virtual float getValueHost() = 0; virtual String getValueDisplay() = 0; virtual void updateComponent() = 0; + void comboBoxChanged (ComboBox* combo); + void sliderValueChanged (Slider* moved); + void buttonClicked (Button* buttonThatWasClicked); + /** * Index of this parameter */ @@ -55,24 +65,35 @@ public: DexedAudioProcessor *parent; }; +class CtrlFloat : public Ctrl { + float *vPointer; +public: + + CtrlFloat(String name, float *storageValue); + void setValueHost(float f); + float getValueHost(); + String getValueDisplay(); + void updateComponent(); +}; + // CtrlDX is a controller that is related to DX parameters class CtrlDX : public Ctrl { - int value; + int dxValue; int steps; int add1; int dxOffset; public: CtrlDX(String name, int steps, int offset = -1, bool starts1 = false); - void setValuePlugin(float f); - float getValuePlugin(); - void publishValue(int value); + void setValueHost(float f); + float getValueHost(); + void publishValue(float value); void setValue(int value); int getValue(); String getValueDisplay(); + void sliderValueChanged (Slider* moved); - void buttonClicked (Button* buttonThatWasClicked); void comboBoxChanged (ComboBox* combo); void updateComponent(); }; diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index fa405ae..cdc5812 100755 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -133,6 +133,8 @@ void DexedAudioProcessor::processBlock(AudioSampleBuffer& buffer, MidiBuffer& mi channelData[i] = (double) f; } + //fx.process(channelData, numSamples); + // DX7 is a mono synth for (int channel = 1; channel < getNumInputChannels(); ++channel) { buffer.copyFrom(channel, 0, channelData, numSamples, 1); @@ -384,13 +386,14 @@ bool DexedAudioProcessor::hasEditor() const { return true; // (change this to false if you choose to not supply an editor) } + void DexedAudioProcessor::updateUI() { AudioProcessorEditor *editor = getActiveEditor(); if ( editor == NULL ) { TRACE("no editor found!?"); return; } - DexedAudioProcessorEditor *dexedEditor = (DexedAudioProcessorEditor *) editor; + DexedAudioProcessorEditor *dexedEditor = (DexedAudioProcessorEditor *) editor; dexedEditor->updateUI(); } diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index 9c1cb33..a40d6e2 100755 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -28,6 +28,7 @@ #include "msfa/lfo.h" #include "msfa/synth.h" #include "PluginParam.h" +#include "PluginFx.h" struct ProcessorVoice { int midi_note; @@ -68,7 +69,12 @@ class DexedAudioProcessor : public AudioProcessor void updateProgramFromSysex(const uint8 *rawdata); /** - * This flag is usd in the audio thread to know if the voice has changed + * PlugFX + */ + PluginFx fx; + + /** + * This flag is used in the audio thread to know if the voice has changed * and needs to be updated. */ bool refreshVoice; @@ -93,13 +99,20 @@ public : OperatorCtrl opCtrl[6]; ScopedPointer pitchEgRate[4]; ScopedPointer pitchEgLevel[4]; + ScopedPointer pitchModSens; ScopedPointer algo; + ScopedPointer oscSync; + ScopedPointer feedback; ScopedPointer lfoRate; ScopedPointer lfoDelay; ScopedPointer lfoAmpDepth; ScopedPointer lfoPitchDepth; ScopedPointer lfoWaveform; ScopedPointer lfoSync; + ScopedPointer transpose; + + ScopedPointer fxCutoff; + ScopedPointer fxReso; int importSysex(const char *imported); void setDxValue(int offset, int v);