From 61cca2b513b189d45eb55b777f113c7086c765b6 Mon Sep 17 00:00:00 2001 From: Vesa Date: Tue, 24 Jun 2014 20:27:25 +0300 Subject: [PATCH 01/11] Monstro waveform icons updated --- plugins/monstro/exp.png | Bin 367 -> 522 bytes plugins/monstro/moog.png | Bin 402 -> 599 bytes plugins/monstro/noise.png | Bin 478 -> 563 bytes plugins/monstro/ramp.png | Bin 333 -> 520 bytes plugins/monstro/rand.png | Bin 407 -> 500 bytes plugins/monstro/saw.png | Bin 365 -> 529 bytes plugins/monstro/sin.png | Bin 398 -> 578 bytes plugins/monstro/sinabs.png | Bin 399 -> 468 bytes plugins/monstro/sqr.png | Bin 342 -> 427 bytes plugins/monstro/sqrsoft.png | Bin 393 -> 539 bytes plugins/monstro/tri.png | Bin 380 -> 602 bytes 11 files changed, 0 insertions(+), 0 deletions(-) diff --git a/plugins/monstro/exp.png b/plugins/monstro/exp.png index 3f9cc47a0e7136382b3e7e4f6609153459e4c1bc..9fe634881a8d4c47b380b1963604c840b40a623f 100644 GIT binary patch delta 468 zcmV;_0W1FR0*VAPiBL{Q4GJ0x0000DNk~Le0000D0000F2nGNE06!x|cK`qY24YJ` zL;wH)0002_L%V;GAs-0_6$u|Li!%F6kMFX)98LL@QQjBDLoyo6BtB(#GKG|dP&KD z*6@Z%W^s%g2xJzAH$-erv^OXaerDN(L4hVJb%92oDAC3=F#}9fqTT2dyOT&~M<^Bq zLqy}tLWUR%!r9TI+QW<0JSdPbZD0=3!^{C~1yVIXL8&T{BgwFUn8jQnW(^CDq^jgu z5M66}ij-@XBuc|2qB2}cl(}YUdWuAU_b$PJtz}~p8*=&ZIna=uM z^y%Yon!}Qo%x7Q=xR5xGk*_%ufMvlJ=5H=J==|X-<;)iX?=h>0CT2gGlMMY-b21Vu zh;7WLk@%1Y{0OcwkP+v=4h?o&1-);F{BITXXs`?HAkHPS!MAbXg)^EsU|j$U0000< KMNUMnLSTX^ti-ec delta 339 zcmV-Z0j&Ot1n&Y#iBL{Q4GJ0x0000DNk~Le0000E0000G2nGNE049`9IsgCw32;bR za{vGf6951U69E94oEQKA00(qQO+^RZ10576D{N(AdN(MZIfpTZE4{nq!n z$z+l{bM8Io&Y5IPpp8MAL;+p+jFYN+(-ryIvM-=r7r2^aF^MFt|8#s!vQ!Gy?l_<1 zWzsCFI<}I$e>DZJ6spg)HI@mk6`BuCG;Sr?Ofpr#b4hAF$9j^PBv(mBCAa&RWA<^0 zM;sOh-D8L|Z2tx(~2S3ogbJaMnegFUf07*qoM6N<$0fL-yiI)HX diff --git a/plugins/monstro/moog.png b/plugins/monstro/moog.png index 1a657b161324cabb6a67bade9c17f35d366bc4b2..6d9005966f448c6da2cd4003fc4f06d6c4e2af7e 100644 GIT binary patch delta 544 zcmV+*0^j|T1J?vIiBL{Q4GJ0x0000DNk~Le0000D0000F2nGNE06!x|cK`qY24YJ` zL;wH)0002_L%V;GAs-0_6$u|C^6ykKkx3|jzez+vR4C7N&_8dDaTEve&v~BbUe%V6 z5Q8%K6aR9jN<<<;!XQXQ^c7f460ZR7fKB2ZxJwhkU?2ulO*EFK2E<@Mv{k+L`5i-r z3clk>J}2LE!kSFZWW9dOrZ!v;F6Zj_Ze6+A?DgeoM1ks;$c*kbRjG_f2c*$pDblNd zEQVXxEdPb3`XavTW;z{VPlj)q7Ey*>ss9f&KP8fN!2xUuRw68CC>H&Z2HePK<}}gT zjUFQTj$x$aA87KNs*^@rE=D?vxd>zY4OZ)A#>lv)v~~r(3^KgOApeJ^`l8e72)$%y z@IH8l_Giu7i0b3i8uW3iY9)*&$7A(>o|!CeB@cq_5iZsP`8#3?<)KYSFKc8*)#)0SPN0{}C?3VQ#dQllDegpgfD0vEEnjUsGpDXf zIwwrxW$>(onYq3uElZP30;8G*q!$5efW8uY3<@a+VAMMHZ i$ee|y=$CX5$9@3U;J0Ax>%CV10000m39-=1Tepn?7qRhDSQx9%!ha>0 zU0n}Ma}HZ6|F$H#j2VfGp)h5P6U=uix^$w&l$sAfUOW6eqU>vn)U@Inhtee;a zI=~H(M{Wvi0PB@eXO;qR7D6byF9U19P#siVN?*NK^BB402kNc*61D87@x(8TE1D+i zNWF?RQro3CQD4=AKkheI3w5Zjw1Cs7U(^{x2*+vxBOC#jKnJy}b{l@q_d$FD+v}@9 T0Dc9p00000NkvXXu0mjfGJJ~$ diff --git a/plugins/monstro/noise.png b/plugins/monstro/noise.png index cd22af02b51a24ec51095a77b26008a3855a55f7..6d3853f607376550be987391056dd6762a8d9f3d 100644 GIT binary patch delta 508 zcmVG!%c yZ?>|pqdAHxTi{?E2K!vmGqoKIi=BD>ulygF@U^k1tAlVDJGDPqvPalgcVEN1B-aNlRTnsfPuQ-Hvt9Rv^Eid~m<%{w;CIXy z__gHCWbTx*{g}4aHU`|lJ$$UhR@dc2$=#~L!4!tpZ`vI^u0+EIUg0%fR;=Mmb>3xw zNmW%+Z`OJR7Yevrjjr|JaeSNol9@Y_tP~VHZ>>H2n@=w%d6VQx@5>|)k~~dvG0FVD rO#X+NlblKNXispDS93PWLLd7H!KAQ$;ML|!00000NkvXXu0mjf8Y9B9 diff --git a/plugins/monstro/ramp.png b/plugins/monstro/ramp.png index 94f23b59f4d3ae623724cea67c983c344ac83f9d..dbd423efdf7dde81b5d3057472cba0d84532adb5 100644 GIT binary patch delta 466 zcmV;@0WJQ`0*C}NiBL{Q4GJ0x0000DNk~Le0000D0000F2nGNE06!x|cK`qY24YJ` zL;wH)0002_L%V;GAs-0_6$u>z64bLzkx3_i0dPq~K~yNub<({{)o~QZ@z?p@tBDUG zwPsU8=vWSJt)Zcd?a@>alxs_C1QJCA{R=Ker4U4afo)PlThJ0&KI?t>od&&FdGDFe zo6kA#b7JaqE=ITo(yOdIZtUA!yBcjhszmsX#HcVC#Za?PO=k3ju!A4ilqNIW9UV4* za{a3s-NAx(rUo{J4QaY{=*D)#(8RjZ4J;5LlWn|@5LrB^in;S=40i*I`3w z0b!xpGJ7rzUi;`YX~J4R1I`#W41*QgEpk}OHzFjLBj(bD67xv^`n zukJM#9qGH@G1?tkVtrio^UzMIEGJKoRV_4IW_u+Ok?Rwxk$$^XERLtr1^kYfP)Q4s!j2;0#cj>9+AZi4BWyX%*Zfn zjs#GUy~NYkmHi&GtcW^)Kw6vW#Ax+;hU1P6+)HS!ls?nnp_=sVbIxMO;(&4+^$e|{XgIpK-Q+7(is zJL@dN3&koJ^B1UQ#>uKdYbgczz9I0b?Qasrx}HK#wwby85}Sb4q9e05c|X AlmGw# diff --git a/plugins/monstro/rand.png b/plugins/monstro/rand.png index b857b98820cfa9d95ab85e6f7be6a04487de29b4..96c4a49e328b25e46df70e08db6091acee8c3a9a 100644 GIT binary patch delta 427 zcmV;c0aX5%1M~wSiBL{Q4GJ0x0000DNk~Le0000D0000F2nGNE06!x|cab462?iAj zARK}-#*mR)Cw~E4Nkls4;XtNjsX>^;tAY`jL)n#7YP^>F+XlbWC(5o^HWj)KL}MXLn%Y<` z^Cm(a*mOfcp>A{Bhflm-u894CcYc97!T_NmunMdqG@KEG*2#=8(Xpy(yjx1fas<>A zd{K^Fhn@FDdM){7QlX7;l`K#Le3`^&QD002ovPDHLkV1hTUvLgTh delta 334 zcmV-U0kQt{1D69KiBL{Q4GJ0x0000DNk~Le0000E0000G2nGNE049`9I*}nU2?HJr z7b#fcewdM4Cw~C{NklfbDee7QhlP2AoC2R(~#|N{R_U0d#=th}f%urjlb5 z7y*cihjZz)(wqlo60;i_=mKZ})4!VRr{bP~c2Q!u56l8Dz&X$Z?$ZS5MZ|Mi%#J_0 zQFo{-^)i89>gzCIOMOtU)Z?`CKjm6oOn>_r5#73u6Y7C_r=H{-%fMx|uMX6Ab#0hE gSJcCypclIO22hif%Pf=A@c;k-07*qoM6N<$f=8E&-v9sr diff --git a/plugins/monstro/saw.png b/plugins/monstro/saw.png index 7435f68aa2592aa833b4b31e25e182d218575695..56c077f2c529fea4f55046656dcc36e66c5bc71c 100644 GIT binary patch delta 475 zcmV<10VMwI0+9qWiBL{Q4GJ0x0000DNk~Le0000D0000F2nGNE06!x|cK`qY24YJ` zL;wH)0002_L%V;GAs-0_6$uCAc{AjnT{r?4sdVs++p-nY7!ZMR3(-UgEI}?)NKpLgc@r zQ8$&lOlET(Sdw@_<`E^|M@OmZ3q{?3R0IpaJm!;OwHRaL)HLPJ*513LZc1)=Ee*ou6L_t(2&z;jfN(4a= zhT*4%J%C{1-ysC?0w$UpDwv31q~HlWfS|A-h>2ioWFiQ%;eraL>jjL=HZmy#XJHt3 zoLRr9tE*nByS{E_P-YIys>~eaj|Nb5gl@51hA*AK%sj&uKFh6fE0~$b*eIc4HP>r_ z_R8=QbJcv&egJLbuncb^;=Eo{Oo3K$gn2wogMJ+~GZ%4<6+A@5Nz+y89j~y4=ZM(- zYj8!)t988Mpv|VD=G8m)BjTeC>}6&jo26G55%JdLH5J&w0v;pcuBCpAugO$Tp=s|ZLy2Ah diff --git a/plugins/monstro/sin.png b/plugins/monstro/sin.png index f9441bdfbc0d9f2a9efe464ea1aee44d57522b95..acabd5a171a9fc5ccefec61c360de9c09629563b 100644 GIT binary patch delta 523 zcmV+m0`&ck1HuF|iBL{Q4GJ0x0000DNk~Le0000D0000F2nGNE06!x|cK`qY24YJ` zL;wH)0002_L%V;GAs-0_6$u+L`(Ab3kx3|js!2paR4C7F(MyYs0T>7H-}AojIgDE_ zopEWREQArcWTEU>h>c<+AHmi)z=vTkvyuBkIB+V==NURkhhzJ#;?O73{$`ysA=JQ^;&ZZAR{9SdCIrJ=`DtfA^hyo6WkenX*~z6=7S1)tUAL6T*{X`L}zs zGDjM**bC#y?qEkQ9_+_TG)Fa1;~l5|EW*Xg+HT*$Lhvc{LDbsLHhl`qR0iDa0hGwOW=SmlJuZIJxUt7eZLM0lA@$fw}YfN_k}jD z0&3t8cm|@Mf0_I0Rp0>V1JTTqnI(t&9%}`UfNx-t`4`@#TGC!oR%p7q0nC9(21XzO z$DVF-;MO0ws(>MI1H2UA9M~`F+yOS5R7b$b%)XjvOPw{a4ZH%emji{$I#2T^Rx3sv zfp_2pIQRR*Go%$XvoY}G^Sl6d9qhDm?6igjAABik`Y$N|x%B-4jkclu7a?nr P00000NkvXXu0mjf4Uv%l diff --git a/plugins/monstro/sinabs.png b/plugins/monstro/sinabs.png index 067fa0ddb04f4f27fd56baac0416ad8553d08c61..2216224e69d09e64184be0033f77821712ea0c58 100644 GIT binary patch delta 395 zcmV;60d)S41JnZ{iBL{Q4GJ0x0000DNk~Le0000D0000F2nGNE06!x|cab462?iAj zAO+@FZcve1Cw~DvNklpahF_)hya(utOzHPIAuYpm*Tvv%Sk38y~YX=MUH;OK9!M}OF@i_J3BFQs-R*}}tQFE|l) zGHl@vUMG{_iS)8+yer9zzPw8na&4OgN12OE~Ox&3cU)K44E;#N*=}xTNh*E$W|^o>D&Pp7)f& p+;X|0_MYxgsV^(@rS#uF_zk6kf#8G@CcTcUKrlx&fLqqfrNUd&ebpVrqD0d7xk8HsI|IM z*XoBlDfCwD{K3Xt<$DF}0W;tgI9I#u4S^?M1RSe%M1M>xwFVA>H{d#lPqN6MJK!Qi z0N4S>nf3@YS@YCJ$tU>^fz#f21Pp*CBHD;((>y5k{6+_i)%_~h`~;T8y_Pvdp*O&L z&W|f#7gzw#g|Puzz~ntvZviBL{Q4GJ0x0000DNk~Le0000D0000F2nGNE06!x|cK`qY24YJ` zL;wH)0002_L%V;GAs-0_6$u>=Y-P{zkx3_i0TW3?K~yNuozg*0RACSV;II3CBTNL1 z=m}W3F}gMEJct)C9>!adxG;tUiL>ws>Lf-D!+U?bU<||HLa23hRdsd8(dVjgg(?Dt z2w#fVed*)-msTPQGFafOcpDsMdMdn&u*4!6=lg0y*MP1}5q^&6zM7e3I!6Unq1!@# zUgaWp$x_#KZzA0R!|mvooec;fpeMP5iw#~EhJJhyN}|Q(-wwrtHae&)aDUB@%?J1FQ?q z#_``gUcg9fEF@rKWo;?gGsFE+gXkk2g($4l%Ck`7(XPCILnP-DX z5mqtCG{UQ{@pPEJZ(PxcNHdC?pK=oyF~Tn9a2)G(v41unc3-b(XTg$bS^6!lM{yf# z_=xM1*6Lnk?mjU)sYLi9Yzyx*e5=x%Y45V|u<2RY+foid$Z52tXeT|L6cVXajoKj{ zDf~;r9c0EV6bPZzV=;+C3-lN+sjhz3?{)fF>q>GOXK-m;D?R>FL1{(Bd_O&juv1!J z>%#K5(SLRWqnb7<^CnX$X@X-D-8gJwJL&3o7yQ_Fa_g3_p7dh+720qo(kbDZa85dZ;JPy7?w0CT zTAXyA;Q@YPh(&3TY{U`6nQ`@ly5Dyq`X1w6G8_m-$xD^ze*llDk@eL=KRW;b002ov JPDHLkV1hHD(0%{_ delta 320 zcmV-G0l)s61c?J7iBL{Q4GJ0x0000DNk~Le0000E0000G2nGNE049`9I*}nU2?HJr z7b4Fvrx1}_Cw~C(Nkl%L_HS14HnBly6+<5?~hiW_hp}tZlbzAMIUG+iz z^jEia;7LOF>TbT?Nw_tND}fzg3b=`g>nyem90P0Pz<(_ufR%ys?$G)t_>}uACQu2y z^A8okTzaYD53E;UFI@`(XTY9Xl)w={L|iuLa2A*bC>sKmW`OyK_%0@Z7J)vnS*1Fv zC4dceA6NhmfK}jbToA1sxxV_QKB~{P^PBL6`la@AcFzazqXs?&+Q7?jh(Aa-p_#$? SIA8z(00{s|MNUMnLSTZaZ-h<& diff --git a/plugins/monstro/tri.png b/plugins/monstro/tri.png index 9764a36e8bdfdfb2eada0673e3e5846cbf1eabc9..9e1ab81080e60b763bcbd51617661adf52245a4e 100644 GIT binary patch delta 548 zcmV+<0^9xk0@?&KiBL{Q4GJ0x0000DNk~Le0000D0000F2nGNE06!x|cK`qY24YJ` zL;wH)0002_L%V;GAs-0_6$u<5-mk;xkx3_i0m4Z{K~yNuUD7>El>r#W@!$P;&U5V0 zP=cEjPQGv)BB9Ym$f5O_qOA|2U!gf@Xo~X%f?C{_APM5*V^=Wg(&=-Mv0 z{>z^$++;mt^@Y~O(4!2mv4Gu3FYlB-eSB+RJrar=rdkxgLL-^a)J8v3JDL9#8r7nI zxY^!9`;{mzl)_wu`}i5*zA#r@DEF)Xq0E@v(}==srjC@!fs~m#QJ9_F(~udrP}LR9 zOHH98JP=NTo^W#AJIzbYs_PocjMHhwFtn4ENK4p?@CsXzmXeiWXrE4B?Te}_hErM! zYtpi?gUuZKj!j`lT2@#aPH9zLQS4WLLR%|Y5N7Zt)8~nBmgzIT2s6oow$^?nipf0< zW3xdAlAfl6^LzT54w4=O9pft@#jOAyO2@%&oEiA0jx&Q`S31VS8zIHG;jXlTC1FeL zefh&+`?0$GVW9S2*y68{qE63*W$Xl-WjdceRg1{!Q+1ingH8SlDO@R?!BM7L-e|(8 zTS@3vax`I-sfVKoGty!qtOg~H>U7wjGZt6J6p{To<2oHmM@cC>ZAkAh7CvbDy}hCK mPqsJIPoDej(wpF`bomEd%*qydGm?S;0000Sf&BnK!cRyc`JOGTY_+fyQv|Gx-GU%Q#9FWrBpwUj%Bs6MUKrlI z_vUhE?mXy#TByfrK`w%HqrR!jKJuWWHU>6nzr_3u3FWV z|E5-}t41Mef2*jMedg=}BVY;CQL7^#MgJ=?EI$C&z&xe&2oP}|XD2_tMxCio>gD%l z*AoB+ac}}`0B4O_gOt(*umHAz!}e9jz&7vzT=jTY0r$ZEr>c7Xm*p{rr|PphYZUi@ y7vQ>&*fMDi?5IOxLZ+F+f1)1oU#P=o{|@x}>n6pC4u~B90000 Date: Tue, 24 Jun 2014 21:07:15 +0300 Subject: [PATCH 02/11] FxMixerView, FxLine: graphics & layout fixes --- data/themes/default/mixer_send_on.png | Bin 1578 -> 1675 bytes data/themes/default/send_bg_arrow.png | Bin 270 -> 316 bytes include/FxLine.h | 3 +++ src/gui/FxMixerView.cpp | 4 ++-- src/gui/widgets/FxLine.cpp | 20 +++++++++++--------- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/data/themes/default/mixer_send_on.png b/data/themes/default/mixer_send_on.png index 15c8fac44750213687ef9aa08cf855b1302f3b8d..5982ea3f69d31aca2dadd375bf160bec493251c1 100644 GIT binary patch delta 1616 zcmV-W2Cw<542unrDlz{6>HxhWg66aU000SaNLh0L01FcU01FcV0GgZ_00007bV*G` z2i^u45i2F$oxMhpTPT0?Nkl6%sF0cYqXx^B4A0Kk1T)xd=lCl#=fUv;^pi~Rqc48rJO5fcJvAB)>QELMV+364 z;Xuq?CPovun>c@9mIxY2sV9WOix_ct@4L=pSt0Ho2)?$q=AjrIy6p#Fzi-x^84-^F zvwlcmtfx<%m>NtBSXi9D-YrjtvY?0sF(?`XK?A6u=ths+F*g7_IXU-acly4k?|V|0 z`P^MIPsLD7ZDU=HH}b5{N<8QXU&b#^V091z47k5?>#(b93~h$Ok14iN(mg-ArfO%Xwk~#)@ygO zX~!0}T(^^YG@uyNl!KC3mc%j=Vnp;j)ErBR)b;dTN7r=p>kUhX=Q(w3h2__dO-j^% zL~_wkc|(8lcp0rE${=_V%c%7wBR22a%GPV&M?Ep58V)Fj6|pLabwwEqv(#q(hbQlUlt2FB z099S{r>9@!nFk-|>4#D(P+f-(FK2o^^l)``(d7aZjH;?BCkAYv+Qstg3oO5}Kv5SAs+tg06pabjmR_Tf1Y8u=vZ`44 z=P`fYIPyBHODnwm@*P#}+AyLJZT0Xh%Rx495X+x4a=*hw0lt!s6k1Ui$HY|G3p} zzV%a{zyFtWb92MpxNPSY z+_2}P9C~IBHwSla`qCb@eQ-B%P~zE``qT}irep3W2eIt9Z=_}8>YJ{|vte#DP3sET z5f8X4RNi2gA>}@K?lZa196$UPum0*~ranH6rHq^N;)74|+;{i$&aqX_ynT{>y5~2m%U`jTT$ZXbfmj9LKYh zyF_jiecREGTT;_-^2j3ZES;hscXVwsg}$K8BPx&Q*u#KVtYbYj>y49r`Se>SCfAOi zX8CXP#2C;JP*qd|0vpC~;dQ{qJ-Xp$q@2mgNO{8s>w2&pTr6Yh6v+~YTxWko{5Y?8 zW^=}6ylwkcb7H#GH7(t^rEOZewxerWx~4f_cXVw>-*vQYOWQWIF`W(= zYK1GHfvBLeG1!7ACW7E7PI5)O2ZzoKv4j|ib+lGe*gHg@k?H^cIb4WYcbVX60z0I{ zq(h}-s7jU|mx6#XmXd;wo_@B^{B=G O00006~{kkW`0li-nQHAw!2$amUatK!$UM} zO6Z~x42A%v6=EAnB=Lob@r5zrf6(~Ghp2BrOaydGqoG2vK~j;n(n1r1wxCP&2zUZ0 z2oK4p^}n4dAGL8n-;@X=7BL1f7Gnf428bhWT##i^nu;` zzPEB^ach=knT?&qaU>W_eQiT9VjA^^AP7cKUtz4nS0y4=optKVN{ew0@wyKWs>qfWhEr&g;`Yt+eV8CjN*)f?364eEbu8Z_26SktqH^?mE^U z)rC#N18jdBxq-NrlGJKMX$R0H2`;i&=P=#p4L;y~2Q+Gz6xLylrT>;;FqYMsB}`(S zU{WE3=k#bWiiiPckTk9*Hf_}C+cHF`JiqzDvmE`^VbV0^#LGwd?NbMM`N;!Vu^c`4 zJIcJIRIE4|DInhlrDe%hMMa-SatifBiA)jRp(nX8HT+cZs8fLq8fLNfOdV#^A_} zER0VwJ3fhxW0EAsMMexH*FasT;4y%W)0D}x<0Rv~EX^$N#=#?O-+M3d$~<%Dr&ug5 zQx$&}*Is6RVw#D!|Hg8@%F@gQ{UF@A^0{)Oh8mFL2*Cb~AN;lIZ?O=zO6O z5F;pbl_gZZlgbLW-M^EWGZVb=%q#Dg)Zy=p@!Ag$(p+2t;8Ty>&FepY@!yKSZ_D7n ztbAA_oOV{cKoz{#j<$F<+_;I`AH0*l9DaY35IRA-zWM+++;I~wjZq&M`RwhKdC93~ zj}WQ=st`Kbbj#>%Xi!k4-7XX;6|EEv2G9VNLc44iAyl5=12bnP`17F?+&p?Kp$ceF zjy-vZ-+%uFu1qg-Y3c%1v&HcCZM2&$LRGOcf0>iNJi@8xUt|5p`Uq9PR{RR(@V_1J%MwsD+U%3!H8hGYJ}497wCG6$A>^wdWs?^ zZ?=eCJZ}R*(Q2>k3Lg^uFUe@wIeJg4f8eIK=4b!0qblDUEZZ?r5)&m6##n!>HHerF zd+AtI=q8@`itox{(PdoZ1)qQ9;kP0e@u=Jx{-ewE_6?kSZ~4;Jt=m3%dSGbi^qQXa z5+$**&WN$b7;7X=V#G+-%oXjhRV$*whv1CWByyTXaX_J7t0hyj7vA}wOdR0XdQu!l z9M%|&bdBvA$qrMvX5t#qP@yux6Lhz1*Z;e7_~`cKPhz@(zFYPN<-zN;C?6dE1W3NM U#=Qaqf&c&j07*qoM6N<$f|3^Gu>b%7 diff --git a/data/themes/default/send_bg_arrow.png b/data/themes/default/send_bg_arrow.png index daeb9fe65d0751485a381a456316dab9fe3c9b71..8c4bfcf93f39b1619f90db29ada90498c759b63e 100644 GIT binary patch delta 286 zcmeBU+QSsx8Q|y6%O%Cdz`(%k>ERLtq-BBFf`bi6GJg8p1*F)Lyxm95wgVRr7cP+wL*0e0OQ3mlRLXrawA5+w6Mgb38xKY3Qq{ z1|)RERLtq-B8Ef`bi6zB8Dy1xT?adAqwX6f*p0SP;7Z zDJxKfv%n*=n1O*?7=#%aX3dcR3bL1Y`ns~;W0vRDkYc{8mpU<8qrS}3#W5t}@Y_p< zTnz?14i{fpIbtjjMl2WC%fKE7}5`U4zRhwdz3|C*rqf%9up;)Zs&4JC`NEt>!G9m^Dbi6v`p TA2`bcbQXiBtDnm{r-UW|0327E diff --git a/include/FxLine.h b/include/FxLine.h index 2445e2aac..2f55bf3eb 100644 --- a/include/FxLine.h +++ b/include/FxLine.h @@ -61,10 +61,13 @@ public: static const int FxLineHeight; private: + static void drawFxLine( QPainter* p, const FxLine *fxLine, const QString& name, bool isActive, bool sendToThis ); + FxMixerView * m_mv; LcdWidget* m_lcd; int m_channelIndex; QBrush m_backgroundActive; + static QPixmap * s_sendBgArrow; private slots: void renameChannel(); diff --git a/src/gui/FxMixerView.cpp b/src/gui/FxMixerView.cpp index f55112e26..86c6c735d 100644 --- a/src/gui/FxMixerView.cpp +++ b/src/gui/FxMixerView.cpp @@ -121,7 +121,7 @@ FxMixerView::FxMixerView() : channelArea->setMinimumWidth( fxLineSize.width() * 6 ); channelArea->setFixedHeight( fxLineSize.height() + style()->pixelMetric( QStyle::PM_ScrollBarExtent ) ); - ml->addWidget(channelArea); + ml->addWidget( channelArea, 1, Qt::AlignTop ); // show the add new effect channel button QPushButton * newChannelBtn = new QPushButton( embed::getIconPixmap( "new_channel" ), QString::null, this ); @@ -132,7 +132,7 @@ FxMixerView::FxMixerView() : // add the stacked layout for the effect racks of fx channels - ml->addWidget( m_racksWidget, 0, Qt::AlignTop ); + ml->addWidget( m_racksWidget, 0, Qt::AlignTop | Qt::AlignRight ); setCurrentFxLine( m_fxChannelViews[0]->m_fxLine ); diff --git a/src/gui/widgets/FxLine.cpp b/src/gui/widgets/FxLine.cpp index ac051d799..ce696cc10 100644 --- a/src/gui/widgets/FxLine.cpp +++ b/src/gui/widgets/FxLine.cpp @@ -40,12 +40,18 @@ #include "caption_menu.h" const int FxLine::FxLineHeight = 287; +QPixmap * FxLine::s_sendBgArrow = NULL; FxLine::FxLine( QWidget * _parent, FxMixerView * _mv, int _channelIndex) : QWidget( _parent ), m_mv( _mv ), m_channelIndex( _channelIndex ) { + if( ! s_sendBgArrow ) + { + s_sendBgArrow = new QPixmap( embed::getIconPixmap( "send_bg_arrow", 29, 56 ) ); + } + setFixedSize( 33, FxLineHeight ); setAttribute( Qt::WA_OpaquePaintEvent, true ); setCursor( QCursor( embed::getIconPixmap( "hand" ), 0, 0 ) ); @@ -97,7 +103,7 @@ void FxLine::setChannelIndex(int index) { } -static void drawFxLine( QPainter* p, const FxLine *fxLine, const QString& name, bool isActive, bool sendToThis ) +void FxLine::drawFxLine( QPainter* p, const FxLine *fxLine, const QString& name, bool isActive, bool sendToThis ) { int width = fxLine->rect().width(); int height = fxLine->rect().height(); @@ -111,10 +117,7 @@ static void drawFxLine( QPainter* p, const FxLine *fxLine, const QString& name, p->fillRect( fxLine->rect(), isActive ? fxLine->backgroundActive() : p->background() ); - p->setPen( QColor( 0, 0, 0, 75 ) ); - p->drawRect( 0, 0, width-2, height-2 ); - - p->setPen( QColor( 255, 255, 255, 75 ) ); + p->setPen( QColor( 255, 255, 255, isActive ? 100 : 50 ) ); p->drawRect( 1, 1, width-3, height-3 ); p->setPen( isActive ? sh_color : QColor( 0, 0, 0, 50 ) ); @@ -123,8 +126,7 @@ static void drawFxLine( QPainter* p, const FxLine *fxLine, const QString& name, // draw the mixer send background if( sendToThis ) { - p->drawPixmap( 3, 0, 28, 56, - embed::getIconPixmap("send_bg_arrow", 28, 56 ) ); + p->drawPixmap( 2, 0, 29, 56, *FxLine::s_sendBgArrow ); } // draw the channel name @@ -145,11 +147,11 @@ void FxLine::paintEvent( QPaintEvent * ) { FxMixer * mix = engine::fxMixer(); bool sendToThis = mix->channelSendModel( - m_mv->currentFxLine()->m_channelIndex, m_channelIndex) != NULL; + m_mv->currentFxLine()->m_channelIndex, m_channelIndex ) != NULL; QPainter painter; painter.begin( this ); drawFxLine( &painter, this, - mix->effectChannel(m_channelIndex)->m_name, + mix->effectChannel( m_channelIndex )->m_name, m_mv->currentFxLine() == this, sendToThis ); painter.end(); } From d166212d49832a6be2463173bf6679b7efcb39e7 Mon Sep 17 00:00:00 2001 From: Vesa Date: Wed, 25 Jun 2014 20:43:34 +0300 Subject: [PATCH 03/11] basic_filters: optimize RC highpass & bandpass filters For both RC12 and RC24 filter types: handle lowpass separately, because we can then calculate highpass & bandpass with less operations. This shouldn't affect the performance of lowpass, but probably will make highpass and bandpass a bit faster. --- include/basic_filters.h | 397 ++++++++++++++++++++-------------------- 1 file changed, 201 insertions(+), 196 deletions(-) diff --git a/include/basic_filters.h b/include/basic_filters.h index e41046e61..923716a35 100644 --- a/include/basic_filters.h +++ b/include/basic_filters.h @@ -1,11 +1,11 @@ /* * basic_filters.h - simple but powerful filter-class with most used filters * - * original file by ??? + * original file by ??? * modified and enhanced by Tobias Doerffel * * Copyright (c) 2004-2009 Tobias Doerffel - * + * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * * This program is free software; you can redistribute it and/or @@ -127,16 +127,16 @@ public: // reset in/out history for simple filters m_ou1[_chnl] = m_ou2[_chnl] = m_in1[_chnl] = m_in2[_chnl] = 0.0f; - + // reset in/out history for moog-filter m_y1[_chnl] = m_y2[_chnl] = m_y3[_chnl] = m_y4[_chnl] = m_oldx[_chnl] = m_oldy1[_chnl] = m_oldy2[_chnl] = m_oldy3[_chnl] = 0.0f; - + // reset in/out history for RC-filters m_rclp0[_chnl] = m_rcbp0[_chnl] = m_rchp0[_chnl] = m_rclast0[_chnl] = 0.0f; m_rclp1[_chnl] = m_rcbp1[_chnl] = m_rchp1[_chnl] = m_rclast1[_chnl] = 0.0f; - + for(int i=0; i<6; i++) m_vflp[i][_chnl] = m_vfbp[i][_chnl] = m_vfhp[i][_chnl] = m_vflast[i][_chnl] = 0.0f; } @@ -186,130 +186,135 @@ public: // (C) 1998 ... 2009 S.Fendt. Released under the GPL v2.0 or any later version. case Lowpass_RC12: - case Bandpass_RC12: - case Highpass_RC12: { - sample_t lp, hp, bp; - - sample_t in; - - // 4-times oversampled... (even the moog-filter would benefit from this) + sample_t lp, bp, hp, in; for( int n = 4; n != 0; --n ) { in = _in0 + m_rcbp0[_chnl] * m_rcq; - in = (in > +1.f) ? +1.f : in; - in = (in < -1.f) ? -1.f : in; + in = qBound( -1.0f, in, 1.0f ); lp = in * m_rcb + m_rclp0[_chnl] * m_rca; - lp = (lp > +1.f) ? +1.f : lp; - lp = (lp < -1.f) ? -1.f : lp; + lp = qBound( -1.0f, lp, 1.0f ); hp = m_rcc * ( m_rchp0[_chnl] + in - m_rclast0[_chnl] ); - hp = (hp > +1.f) ? +1.f : hp; - hp = (hp < -1.f) ? -1.f : hp; + hp = qBound( -1.0f, hp, 1.0f ); bp = hp * m_rcb + m_rcbp0[_chnl] * m_rca; - bp = (bp > +1.f) ? +1.f : bp; - bp = (bp < -1.f) ? -1.f : bp; + bp = qBound( -1.0f, bp, 1.0f ); m_rclast0[_chnl] = in; m_rclp0[_chnl] = lp; m_rchp0[_chnl] = hp; m_rcbp0[_chnl] = bp; } + return lp; + break; + } + case Highpass_RC12: + case Bandpass_RC12: + { + sample_t hp, bp, in; + for( int n = 4; n != 0; --n ) + { + in = _in0 + m_rcbp0[_chnl] * m_rcq; + in = qBound( -1.0f, in, 1.0f ); - if( m_type == Lowpass_RC12 ) - out = lp; - else if( m_type == Bandpass_RC12 ) - out = bp; - else - out = hp; - - return( out ); + hp = m_rcc * ( m_rchp0[_chnl] + in - m_rclast0[_chnl] ); + hp = qBound( -1.0f, hp, 1.0f ); + + bp = hp * m_rcb + m_rcbp0[_chnl] * m_rca; + bp = qBound( -1.0f, bp, 1.0f ); + + m_rclast0[_chnl] = in; + m_rchp0[_chnl] = hp; + m_rcbp0[_chnl] = bp; + } + return m_type == Highpass_RC12 ? hp : bp; break; } case Lowpass_RC24: - case Bandpass_RC24: - case Highpass_RC24: { - sample_t lp, hp, bp; - - sample_t in; - + sample_t lp, bp, hp, in; for( int n = 4; n != 0; --n ) { // first stage is as for the 12dB case... in = _in0 + m_rcbp0[_chnl] * m_rcq; - in = (in > +1.f) ? +1.f : in; - in = (in < -1.f) ? -1.f : in; + in = qBound( -1.0f, in, 1.0f ); lp = in * m_rcb + m_rclp0[_chnl] * m_rca; - lp = (lp > +1.f) ? +1.f : lp; - lp = (lp < -1.f) ? -1.f : lp; + lp = qBound( -1.0f, lp, 1.0f ); hp = m_rcc * ( m_rchp0[_chnl] + in - m_rclast0[_chnl] ); - hp = (hp > +1.f) ? +1.f : hp; - hp = (hp < -1.f) ? -1.f : hp; + hp = qBound( -1.0f, hp, 1.0f ); bp = hp * m_rcb + m_rcbp0[_chnl] * m_rca; - bp = (bp > +1.f) ? +1.f : bp; - bp = (bp < -1.f) ? -1.f : bp; + bp = qBound( -1.0f, bp, 1.0f ); m_rclast0[_chnl] = in; m_rclp0[_chnl] = lp; + m_rcbp0[_chnl] = bp; + m_rchp0[_chnl] = hp; + + // second stage gets the output of the first stage as input... + in = lp + m_rcbp1[_chnl] * m_rcq; + in = qBound( -1.0f, in, 1.0f ); + + lp = in * m_rcb + m_rclp1[_chnl] * m_rca; + lp = qBound( -1.0f, lp, 1.0f ); + + hp = m_rcc * ( m_rchp1[_chnl] + in - m_rclast1[_chnl] ); + hp = qBound( -1.0f, hp, 1.0f ); + + bp = hp * m_rcb + m_rcbp1[_chnl] * m_rca; + bp = qBound( -1.0f, bp, 1.0f ); + + m_rclast1[_chnl] = in; + m_rclp1[_chnl] = lp; + m_rcbp1[_chnl] = bp; + m_rchp1[_chnl] = hp; + } + return lp; + break; + } + case Highpass_RC24: + case Bandpass_RC24: + { + sample_t hp, bp, in; + for( int n = 4; n != 0; --n ) + { + // first stage is as for the 12dB case... + in = _in0 + m_rcbp0[_chnl] * m_rcq; + in = qBound( -1.0f, in, 1.0f ); + + hp = m_rcc * ( m_rchp0[_chnl] + in - m_rclast0[_chnl] ); + hp = qBound( -1.0f, hp, 1.0f ); + + bp = hp * m_rcb + m_rcbp0[_chnl] * m_rca; + bp = qBound( -1.0f, bp, 1.0f ); + + m_rclast0[_chnl] = in; m_rchp0[_chnl] = hp; m_rcbp0[_chnl] = bp; // second stage gets the output of the first stage as input... - if( m_type == Lowpass_RC24 ) - { - in = lp + m_rcbp1[_chnl] * m_rcq; - } - else if( m_type == Bandpass_RC24 ) - { - in = bp + m_rcbp1[_chnl] * m_rcq; - } - else - { - in = hp + m_rcbp1[_chnl] * m_rcq; - } - in = (in > +1.f) ? +1.f : in; - in = (in < -1.f) ? -1.f : in; + in = m_type == Highpass_RC24 + ? hp + m_rcbp1[_chnl] * m_rcq + : bp + m_rcbp1[_chnl] * m_rcq; - lp = in * m_rcb + m_rclp1[_chnl] * m_rca; - lp = (lp > +1.f) ? +1.f : lp; - lp = (lp < -1.f) ? -1.f : lp; + in = qBound( -1.0f, in, 1.0f ); hp = m_rcc * ( m_rchp1[_chnl] + in - m_rclast1[_chnl] ); - hp = (hp > +1.f) ? +1.f : hp; - hp = (hp < -1.f) ? -1.f : hp; + hp = qBound( -1.0f, hp, 1.0f ); bp = hp * m_rcb + m_rcbp1[_chnl] * m_rca; - bp = (bp > +1.f) ? +1.f : bp; - bp = (bp < -1.f) ? -1.f : bp; + bp = qBound( -1.0f, bp, 1.0f ); m_rclast1[_chnl] = in; - m_rclp1[_chnl] = lp; m_rchp1[_chnl] = hp; m_rcbp1[_chnl] = bp; } - - // output is second stage-lowpass... - if( m_type == Lowpass_RC24 ) - { - out = lp; - } - else if( m_type == Bandpass_RC24 ) - { - out = bp; - } - else - { - out = hp; - } - - return out; + return m_type == Highpass_RC24 ? hp : bp; break; } @@ -317,146 +322,146 @@ public: { sample_t lp, hp, bp, in; - out = 0; - for(int o=0; o<4; o++) - { - // first formant - in = _in0 + m_vfbp[0][_chnl] * m_vfq; - in = (in > +1.f) ? +1.f : in; - in = (in < -1.f) ? -1.f : in; + out = 0; + for(int o=0; o<4; o++) + { + // first formant + in = _in0 + m_vfbp[0][_chnl] * m_vfq; + in = (in > +1.f) ? +1.f : in; + in = (in < -1.f) ? -1.f : in; - lp = in * m_vfb[0] + m_vflp[0][_chnl] * m_vfa[0]; - lp = (lp > +1.f) ? +1.f : lp; - lp = (lp < -1.f) ? -1.f : lp; + lp = in * m_vfb[0] + m_vflp[0][_chnl] * m_vfa[0]; + lp = (lp > +1.f) ? +1.f : lp; + lp = (lp < -1.f) ? -1.f : lp; - hp = m_vfc[0] * ( m_vfhp[0][_chnl] + in - m_vflast[0][_chnl] ); - hp = (hp > +1.f) ? +1.f : hp; - hp = (hp < -1.f) ? -1.f : hp; + hp = m_vfc[0] * ( m_vfhp[0][_chnl] + in - m_vflast[0][_chnl] ); + hp = (hp > +1.f) ? +1.f : hp; + hp = (hp < -1.f) ? -1.f : hp; - bp = hp * m_vfb[0] + m_vfbp[0][_chnl] * m_vfa[0]; - bp = (bp > +1.f) ? +1.f : bp; - bp = (bp < -1.f) ? -1.f : bp; + bp = hp * m_vfb[0] + m_vfbp[0][_chnl] * m_vfa[0]; + bp = (bp > +1.f) ? +1.f : bp; + bp = (bp < -1.f) ? -1.f : bp; - m_vflast[0][_chnl] = in; - m_vflp[0][_chnl] = lp; - m_vfhp[0][_chnl] = hp; - m_vfbp[0][_chnl] = bp; + m_vflast[0][_chnl] = in; + m_vflp[0][_chnl] = lp; + m_vfhp[0][_chnl] = hp; + m_vfbp[0][_chnl] = bp; - in = bp + m_vfbp[2][_chnl] * m_vfq; - in = (in > +1.f) ? +1.f : in; - in = (in < -1.f) ? -1.f : in; + in = bp + m_vfbp[2][_chnl] * m_vfq; + in = (in > +1.f) ? +1.f : in; + in = (in < -1.f) ? -1.f : in; - lp = in * m_vfb[0] + m_vflp[2][_chnl] * m_vfa[0]; - lp = (lp > +1.f) ? +1.f : lp; - lp = (lp < -1.f) ? -1.f : lp; + lp = in * m_vfb[0] + m_vflp[2][_chnl] * m_vfa[0]; + lp = (lp > +1.f) ? +1.f : lp; + lp = (lp < -1.f) ? -1.f : lp; - hp = m_vfc[0] * ( m_vfhp[2][_chnl] + in - m_vflast[2][_chnl] ); - hp = (hp > +1.f) ? +1.f : hp; - hp = (hp < -1.f) ? -1.f : hp; + hp = m_vfc[0] * ( m_vfhp[2][_chnl] + in - m_vflast[2][_chnl] ); + hp = (hp > +1.f) ? +1.f : hp; + hp = (hp < -1.f) ? -1.f : hp; - bp = hp * m_vfb[0] + m_vfbp[2][_chnl] * m_vfa[0]; - bp = (bp > +1.f) ? +1.f : bp; - bp = (bp < -1.f) ? -1.f : bp; + bp = hp * m_vfb[0] + m_vfbp[2][_chnl] * m_vfa[0]; + bp = (bp > +1.f) ? +1.f : bp; + bp = (bp < -1.f) ? -1.f : bp; - m_vflast[2][_chnl] = in; - m_vflp[2][_chnl] = lp; - m_vfhp[2][_chnl] = hp; - m_vfbp[2][_chnl] = bp; - - in = bp + m_vfbp[4][_chnl] * m_vfq; - in = (in > +1.f) ? +1.f : in; - in = (in < -1.f) ? -1.f : in; + m_vflast[2][_chnl] = in; + m_vflp[2][_chnl] = lp; + m_vfhp[2][_chnl] = hp; + m_vfbp[2][_chnl] = bp; - lp = in * m_vfb[0] + m_vflp[4][_chnl] * m_vfa[0]; - lp = (lp > +1.f) ? +1.f : lp; - lp = (lp < -1.f) ? -1.f : lp; + in = bp + m_vfbp[4][_chnl] * m_vfq; + in = (in > +1.f) ? +1.f : in; + in = (in < -1.f) ? -1.f : in; - hp = m_vfc[0] * ( m_vfhp[4][_chnl] + in - m_vflast[4][_chnl] ); - hp = (hp > +1.f) ? +1.f : hp; - hp = (hp < -1.f) ? -1.f : hp; + lp = in * m_vfb[0] + m_vflp[4][_chnl] * m_vfa[0]; + lp = (lp > +1.f) ? +1.f : lp; + lp = (lp < -1.f) ? -1.f : lp; - bp = hp * m_vfb[0] + m_vfbp[4][_chnl] * m_vfa[0]; - bp = (bp > +1.f) ? +1.f : bp; - bp = (bp < -1.f) ? -1.f : bp; + hp = m_vfc[0] * ( m_vfhp[4][_chnl] + in - m_vflast[4][_chnl] ); + hp = (hp > +1.f) ? +1.f : hp; + hp = (hp < -1.f) ? -1.f : hp; - m_vflast[4][_chnl] = in; - m_vflp[4][_chnl] = lp; - m_vfhp[4][_chnl] = hp; - m_vfbp[4][_chnl] = bp; + bp = hp * m_vfb[0] + m_vfbp[4][_chnl] * m_vfa[0]; + bp = (bp > +1.f) ? +1.f : bp; + bp = (bp < -1.f) ? -1.f : bp; - out += bp; + m_vflast[4][_chnl] = in; + m_vflp[4][_chnl] = lp; + m_vfhp[4][_chnl] = hp; + m_vfbp[4][_chnl] = bp; - // second formant - in = _in0 + m_vfbp[0][_chnl] * m_vfq; - in = (in > +1.f) ? +1.f : in; - in = (in < -1.f) ? -1.f : in; + out += bp; - lp = in * m_vfb[1] + m_vflp[1][_chnl] * m_vfa[1]; - lp = (lp > +1.f) ? +1.f : lp; - lp = (lp < -1.f) ? -1.f : lp; + // second formant + in = _in0 + m_vfbp[0][_chnl] * m_vfq; + in = (in > +1.f) ? +1.f : in; + in = (in < -1.f) ? -1.f : in; - hp = m_vfc[1] * ( m_vfhp[1][_chnl] + in - m_vflast[1][_chnl] ); - hp = (hp > +1.f) ? +1.f : hp; - hp = (hp < -1.f) ? -1.f : hp; + lp = in * m_vfb[1] + m_vflp[1][_chnl] * m_vfa[1]; + lp = (lp > +1.f) ? +1.f : lp; + lp = (lp < -1.f) ? -1.f : lp; - bp = hp * m_vfb[1] + m_vfbp[1][_chnl] * m_vfa[1]; - bp = (bp > +1.f) ? +1.f : bp; - bp = (bp < -1.f) ? -1.f : bp; + hp = m_vfc[1] * ( m_vfhp[1][_chnl] + in - m_vflast[1][_chnl] ); + hp = (hp > +1.f) ? +1.f : hp; + hp = (hp < -1.f) ? -1.f : hp; - m_vflast[1][_chnl] = in; - m_vflp[1][_chnl] = lp; - m_vfhp[1][_chnl] = hp; - m_vfbp[1][_chnl] = bp; + bp = hp * m_vfb[1] + m_vfbp[1][_chnl] * m_vfa[1]; + bp = (bp > +1.f) ? +1.f : bp; + bp = (bp < -1.f) ? -1.f : bp; - in = bp + m_vfbp[3][_chnl] * m_vfq; - in = (in > +1.f) ? +1.f : in; - in = (in < -1.f) ? -1.f : in; + m_vflast[1][_chnl] = in; + m_vflp[1][_chnl] = lp; + m_vfhp[1][_chnl] = hp; + m_vfbp[1][_chnl] = bp; - lp = in * m_vfb[1] + m_vflp[3][_chnl] * m_vfa[1]; - lp = (lp > +1.f) ? +1.f : lp; - lp = (lp < -1.f) ? -1.f : lp; + in = bp + m_vfbp[3][_chnl] * m_vfq; + in = (in > +1.f) ? +1.f : in; + in = (in < -1.f) ? -1.f : in; - hp = m_vfc[1] * ( m_vfhp[3][_chnl] + in - m_vflast[3][_chnl] ); - hp = (hp > +1.f) ? +1.f : hp; - hp = (hp < -1.f) ? -1.f : hp; + lp = in * m_vfb[1] + m_vflp[3][_chnl] * m_vfa[1]; + lp = (lp > +1.f) ? +1.f : lp; + lp = (lp < -1.f) ? -1.f : lp; - bp = hp * m_vfb[1] + m_vfbp[3][_chnl] * m_vfa[1]; - bp = (bp > +1.f) ? +1.f : bp; - bp = (bp < -1.f) ? -1.f : bp; + hp = m_vfc[1] * ( m_vfhp[3][_chnl] + in - m_vflast[3][_chnl] ); + hp = (hp > +1.f) ? +1.f : hp; + hp = (hp < -1.f) ? -1.f : hp; - m_vflast[3][_chnl] = in; - m_vflp[3][_chnl] = lp; - m_vfhp[3][_chnl] = hp; - m_vfbp[3][_chnl] = bp; + bp = hp * m_vfb[1] + m_vfbp[3][_chnl] * m_vfa[1]; + bp = (bp > +1.f) ? +1.f : bp; + bp = (bp < -1.f) ? -1.f : bp; - in = bp + m_vfbp[5][_chnl] * m_vfq; - in = (in > +1.f) ? +1.f : in; - in = (in < -1.f) ? -1.f : in; + m_vflast[3][_chnl] = in; + m_vflp[3][_chnl] = lp; + m_vfhp[3][_chnl] = hp; + m_vfbp[3][_chnl] = bp; - lp = in * m_vfb[1] + m_vflp[5][_chnl] * m_vfa[1]; - lp = (lp > +1.f) ? +1.f : lp; - lp = (lp < -1.f) ? -1.f : lp; + in = bp + m_vfbp[5][_chnl] * m_vfq; + in = (in > +1.f) ? +1.f : in; + in = (in < -1.f) ? -1.f : in; - hp = m_vfc[1] * ( m_vfhp[5][_chnl] + in - m_vflast[5][_chnl] ); - hp = (hp > +1.f) ? +1.f : hp; - hp = (hp < -1.f) ? -1.f : hp; + lp = in * m_vfb[1] + m_vflp[5][_chnl] * m_vfa[1]; + lp = (lp > +1.f) ? +1.f : lp; + lp = (lp < -1.f) ? -1.f : lp; - bp = hp * m_vfb[1] + m_vfbp[5][_chnl] * m_vfa[1]; - bp = (bp > +1.f) ? +1.f : bp; - bp = (bp < -1.f) ? -1.f : bp; + hp = m_vfc[1] * ( m_vfhp[5][_chnl] + in - m_vflast[5][_chnl] ); + hp = (hp > +1.f) ? +1.f : hp; + hp = (hp < -1.f) ? -1.f : hp; - m_vflast[5][_chnl] = in; - m_vflp[5][_chnl] = lp; - m_vfhp[5][_chnl] = hp; - m_vfbp[5][_chnl] = bp; + bp = hp * m_vfb[1] + m_vfbp[5][_chnl] * m_vfa[1]; + bp = (bp > +1.f) ? +1.f : bp; + bp = (bp < -1.f) ? -1.f : bp; + + m_vflast[5][_chnl] = in; + m_vflp[5][_chnl] = lp; + m_vfhp[5][_chnl] = hp; + m_vfbp[5][_chnl] = bp; + + out += bp; + } - out += bp; - } - return( out/2.0f ); break; } - + default: // filter out = m_b0a0*_in0 + @@ -504,11 +509,11 @@ public: { _freq = 50.f; } - + m_rca = 1.0f - (1.0f/(m_sampleRate*4)) / ( (1.0f/(_freq*2.0f*M_PI)) + (1.0f/(m_sampleRate*4)) ); m_rcb = 1.0f - m_rca; m_rcc = (1.0f/(_freq*2.0f*M_PI)) / ( (1.0f/(_freq*2.0f*M_PI)) + (1.0f/(m_sampleRate*4)) ); - + // Stretch Q/resonance, as self-oscillation reliably starts at a q of ~2.5 - ~2.6 m_rcq = _q/4.f; } @@ -529,11 +534,11 @@ public: const float fract = ( _freq/14000.f * 4.f ) - (float)vowel; - // interpolate between formant frequencies - const float f0 = _f[vowel+0][0] * ( 1.0f - fract ) + + // interpolate between formant frequencies + const float f0 = _f[vowel+0][0] * ( 1.0f - fract ) + _f[vowel+1][0] * ( fract ); - const float f1 = _f[vowel+0][1] * ( 1.0f - fract ) + + const float f1 = _f[vowel+0][1] * ( 1.0f - fract ) + _f[vowel+1][1] * ( fract ); m_vfa[0] = 1.0f - (1.0f/(m_sampleRate*4)) / @@ -552,7 +557,7 @@ public: ( (1.0f/(f1*2.0f*M_PI)) + (1.0f/(m_sampleRate*4)) ); } - + if( m_type == Moog ) { // [ 0 - 0.5 ] @@ -647,7 +652,7 @@ private: // coeffs for formant-filters float m_vfa[4], m_vfb[4], m_vfc[4], m_vfq; - + typedef sample_t frame[CHANNELS]; // in/out history @@ -655,14 +660,14 @@ private: // in/out history for moog-filter frame m_y1, m_y2, m_y3, m_y4, m_oldx, m_oldy1, m_oldy2, m_oldy3; - + // in/out history for RC-type-filters frame m_rcbp0, m_rclp0, m_rchp0, m_rclast0; frame m_rcbp1, m_rclp1, m_rchp1, m_rclast1; // in/out history for Formant-filters frame m_vfbp[6], m_vflp[6], m_vfhp[6], m_vflast[6]; - + FilterTypes m_type; bool m_doubleFilter; From d6809b45c1aa97580c84c5b935d5e7325b384d14 Mon Sep 17 00:00:00 2001 From: Vesa Date: Thu, 26 Jun 2014 12:41:35 +0300 Subject: [PATCH 04/11] basic_filters: further optimization Use qBound in formant, and return early from calcFilterCoeffs so we don't do needless calculations --- include/basic_filters.h | 93 ++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 58 deletions(-) diff --git a/include/basic_filters.h b/include/basic_filters.h index 923716a35..e27766c3c 100644 --- a/include/basic_filters.h +++ b/include/basic_filters.h @@ -26,8 +26,8 @@ */ -#ifndef _BASIC_FILTERS_H -#define _BASIC_FILTERS_H +#ifndef BASIC_FILTERS_H +#define BASIC_FILTERS_H #ifndef __USE_XOPEN #define __USE_XOPEN @@ -327,20 +327,16 @@ public: { // first formant in = _in0 + m_vfbp[0][_chnl] * m_vfq; - in = (in > +1.f) ? +1.f : in; - in = (in < -1.f) ? -1.f : in; + in = qBound( -1.0f, in, 1.0f ); lp = in * m_vfb[0] + m_vflp[0][_chnl] * m_vfa[0]; - lp = (lp > +1.f) ? +1.f : lp; - lp = (lp < -1.f) ? -1.f : lp; + lp = qBound( -1.0f, lp, 1.0f ); hp = m_vfc[0] * ( m_vfhp[0][_chnl] + in - m_vflast[0][_chnl] ); - hp = (hp > +1.f) ? +1.f : hp; - hp = (hp < -1.f) ? -1.f : hp; + hp = qBound( -1.0f, hp, 1.0f ); bp = hp * m_vfb[0] + m_vfbp[0][_chnl] * m_vfa[0]; - bp = (bp > +1.f) ? +1.f : bp; - bp = (bp < -1.f) ? -1.f : bp; + bp = qBound( -1.0f, bp, 1.0f ); m_vflast[0][_chnl] = in; m_vflp[0][_chnl] = lp; @@ -348,20 +344,16 @@ public: m_vfbp[0][_chnl] = bp; in = bp + m_vfbp[2][_chnl] * m_vfq; - in = (in > +1.f) ? +1.f : in; - in = (in < -1.f) ? -1.f : in; + in = qBound( -1.0f, in, 1.0f ); lp = in * m_vfb[0] + m_vflp[2][_chnl] * m_vfa[0]; - lp = (lp > +1.f) ? +1.f : lp; - lp = (lp < -1.f) ? -1.f : lp; + lp = qBound( -1.0f, lp, 1.0f ); hp = m_vfc[0] * ( m_vfhp[2][_chnl] + in - m_vflast[2][_chnl] ); - hp = (hp > +1.f) ? +1.f : hp; - hp = (hp < -1.f) ? -1.f : hp; + hp = qBound( -1.0f, hp, 1.0f ); bp = hp * m_vfb[0] + m_vfbp[2][_chnl] * m_vfa[0]; - bp = (bp > +1.f) ? +1.f : bp; - bp = (bp < -1.f) ? -1.f : bp; + bp = qBound( -1.0f, bp, 1.0f ); m_vflast[2][_chnl] = in; m_vflp[2][_chnl] = lp; @@ -369,20 +361,16 @@ public: m_vfbp[2][_chnl] = bp; in = bp + m_vfbp[4][_chnl] * m_vfq; - in = (in > +1.f) ? +1.f : in; - in = (in < -1.f) ? -1.f : in; + in = qBound( -1.0f, in, 1.0f ); lp = in * m_vfb[0] + m_vflp[4][_chnl] * m_vfa[0]; - lp = (lp > +1.f) ? +1.f : lp; - lp = (lp < -1.f) ? -1.f : lp; + lp = qBound( -1.0f, lp, 1.0f ); hp = m_vfc[0] * ( m_vfhp[4][_chnl] + in - m_vflast[4][_chnl] ); - hp = (hp > +1.f) ? +1.f : hp; - hp = (hp < -1.f) ? -1.f : hp; + hp = qBound( -1.0f, hp, 1.0f ); bp = hp * m_vfb[0] + m_vfbp[4][_chnl] * m_vfa[0]; - bp = (bp > +1.f) ? +1.f : bp; - bp = (bp < -1.f) ? -1.f : bp; + bp = qBound( -1.0f, bp, 1.0f ); m_vflast[4][_chnl] = in; m_vflp[4][_chnl] = lp; @@ -393,20 +381,16 @@ public: // second formant in = _in0 + m_vfbp[0][_chnl] * m_vfq; - in = (in > +1.f) ? +1.f : in; - in = (in < -1.f) ? -1.f : in; + in = qBound( -1.0f, in, 1.0f ); lp = in * m_vfb[1] + m_vflp[1][_chnl] * m_vfa[1]; - lp = (lp > +1.f) ? +1.f : lp; - lp = (lp < -1.f) ? -1.f : lp; + lp = qBound( -1.0f, lp, 1.0f ); hp = m_vfc[1] * ( m_vfhp[1][_chnl] + in - m_vflast[1][_chnl] ); - hp = (hp > +1.f) ? +1.f : hp; - hp = (hp < -1.f) ? -1.f : hp; + hp = qBound( -1.0f, hp, 1.0f ); bp = hp * m_vfb[1] + m_vfbp[1][_chnl] * m_vfa[1]; - bp = (bp > +1.f) ? +1.f : bp; - bp = (bp < -1.f) ? -1.f : bp; + bp = qBound( -1.0f, bp, 1.0f ); m_vflast[1][_chnl] = in; m_vflp[1][_chnl] = lp; @@ -414,20 +398,16 @@ public: m_vfbp[1][_chnl] = bp; in = bp + m_vfbp[3][_chnl] * m_vfq; - in = (in > +1.f) ? +1.f : in; - in = (in < -1.f) ? -1.f : in; + in = qBound( -1.0f, in, 1.0f ); lp = in * m_vfb[1] + m_vflp[3][_chnl] * m_vfa[1]; - lp = (lp > +1.f) ? +1.f : lp; - lp = (lp < -1.f) ? -1.f : lp; + lp = qBound( -1.0f, lp, 1.0f ); hp = m_vfc[1] * ( m_vfhp[3][_chnl] + in - m_vflast[3][_chnl] ); - hp = (hp > +1.f) ? +1.f : hp; - hp = (hp < -1.f) ? -1.f : hp; + hp = qBound( -1.0f, hp, 1.0f ); bp = hp * m_vfb[1] + m_vfbp[3][_chnl] * m_vfa[1]; - bp = (bp > +1.f) ? +1.f : bp; - bp = (bp < -1.f) ? -1.f : bp; + bp = qBound( -1.0f, bp, 1.0f ); m_vflast[3][_chnl] = in; m_vflp[3][_chnl] = lp; @@ -435,20 +415,16 @@ public: m_vfbp[3][_chnl] = bp; in = bp + m_vfbp[5][_chnl] * m_vfq; - in = (in > +1.f) ? +1.f : in; - in = (in < -1.f) ? -1.f : in; + in = qBound( -1.0f, in, 1.0f ); lp = in * m_vfb[1] + m_vflp[5][_chnl] * m_vfa[1]; - lp = (lp > +1.f) ? +1.f : lp; - lp = (lp < -1.f) ? -1.f : lp; + lp = qBound( -1.0f, lp, 1.0f ); hp = m_vfc[1] * ( m_vfhp[5][_chnl] + in - m_vflast[5][_chnl] ); - hp = (hp > +1.f) ? +1.f : hp; - hp = (hp < -1.f) ? -1.f : hp; + hp = qBound( -1.0f, hp, 1.0f ); bp = hp * m_vfb[1] + m_vfbp[5][_chnl] * m_vfa[1]; - bp = (bp > +1.f) ? +1.f : bp; - bp = (bp < -1.f) ? -1.f : bp; + bp = qBound( -1.0f, bp, 1.0f ); m_vflast[5][_chnl] = in; m_vflp[5][_chnl] = lp; @@ -493,9 +469,6 @@ public: /*, const bool _q_is_bandwidth = false*/ ) { // temp coef vars - _freq = qBound(minFreq(), _freq, 20000.0f); // limit freq and q for not getting - // bad noise out of the filter... - _q = qMax( _q, minQ() ); if( m_type == Lowpass_RC12 || @@ -505,10 +478,7 @@ public: m_type == Bandpass_RC24 || m_type == Highpass_RC24 ) { - if( _freq < 50.f ) - { - _freq = 50.f; - } + _freq = qBound( 50.0f, _freq, 20000.0f ); m_rca = 1.0f - (1.0f/(m_sampleRate*4)) / ( (1.0f/(_freq*2.0f*M_PI)) + (1.0f/(m_sampleRate*4)) ); m_rcb = 1.0f - m_rca; @@ -516,12 +486,15 @@ public: // Stretch Q/resonance, as self-oscillation reliably starts at a q of ~2.5 - ~2.6 m_rcq = _q/4.f; + return; } if( m_type == Formantfilter ) { + _freq = qBound( minFreq(), _freq, 20000.0f ); // limit freq and q for not getting bad noise out of the filter... + // formats for a, e, i, o, u, a - const float _f[5][2] = { { 1000, 1400 }, { 500, 2300 }, + static const float _f[5][2] = { { 1000, 1400 }, { 500, 2300 }, { 320, 3200 }, { 500, 1000 }, { 320, 800 } }; @@ -556,10 +529,13 @@ public: m_vfc[1] = (1.0f/(f1*2.0f*M_PI)) / ( (1.0f/(f1*2.0f*M_PI)) + (1.0f/(m_sampleRate*4)) ); + return; } if( m_type == Moog ) { + _freq = qBound( minFreq(), _freq, 20000.0f ); + // [ 0 - 0.5 ] const float f = _freq / m_sampleRate; // (Empirical tunning) @@ -577,6 +553,7 @@ public: } // other filters + _freq = qBound( minFreq(), _freq, 20000.0f ); const float omega = F_2PI * _freq / m_sampleRate; const float tsin = sinf( omega ); const float tcos = cosf( omega ); From ba700399da875640dd23a710eae5aaf178c7ed8a Mon Sep 17 00:00:00 2001 From: Vesa Date: Thu, 26 Jun 2014 13:15:20 +0300 Subject: [PATCH 05/11] basic_filters - even more optimization Use more efficient interpolation, optimize some calculations --- include/basic_filters.h | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/include/basic_filters.h b/include/basic_filters.h index e27766c3c..f026226a1 100644 --- a/include/basic_filters.h +++ b/include/basic_filters.h @@ -39,6 +39,7 @@ #include "Mixer.h" #include "templates.h" #include "lmms_constants.h" +#include "interpolation.h" //#include //#include @@ -498,21 +499,19 @@ public: { 320, 3200 }, { 500, 1000 }, { 320, 800 } }; + static const float freqRatio = 4.0f / 14000.0f; // Stretch Q/resonance m_vfq = _q/4.f; // frequency in lmms ranges from 1Hz to 14000Hz - const int vowel = (int)( floor( _freq/14000.f * 4.f ) ); - const float fract = ( _freq/14000.f * 4.f ) - - (float)vowel; + const float vowelf = _freq * freqRatio; + const int vowel = static_cast( vowelf ); + const float fract = vowelf - vowel; // interpolate between formant frequencies - const float f0 = _f[vowel+0][0] * ( 1.0f - fract ) + - _f[vowel+1][0] * ( fract ); - - const float f1 = _f[vowel+0][1] * ( 1.0f - fract ) + - _f[vowel+1][1] * ( fract ); + const float f0 = linearInterpolate( _f[vowel+0][0], _f[vowel+1][0], fract ); + const float f1 = linearInterpolate( _f[vowel+0][1], _f[vowel+1][1], fract ); m_vfa[0] = 1.0f - (1.0f/(m_sampleRate*4)) / ( (1.0f/(f0*2.0f*M_PI)) + From 27383f91b7a5fc12ef1f8abbbbc7abe2ed113626 Mon Sep 17 00:00:00 2001 From: Vesa Date: Thu, 26 Jun 2014 13:18:00 +0300 Subject: [PATCH 06/11] basic_filters: replace div with mul --- include/basic_filters.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/basic_filters.h b/include/basic_filters.h index f026226a1..84484aeae 100644 --- a/include/basic_filters.h +++ b/include/basic_filters.h @@ -486,7 +486,7 @@ public: m_rcc = (1.0f/(_freq*2.0f*M_PI)) / ( (1.0f/(_freq*2.0f*M_PI)) + (1.0f/(m_sampleRate*4)) ); // Stretch Q/resonance, as self-oscillation reliably starts at a q of ~2.5 - ~2.6 - m_rcq = _q/4.f; + m_rcq = _q * 0.25f; return; } @@ -502,7 +502,7 @@ public: static const float freqRatio = 4.0f / 14000.0f; // Stretch Q/resonance - m_vfq = _q/4.f; + m_vfq = _q * 0.25f; // frequency in lmms ranges from 1Hz to 14000Hz const float vowelf = _freq * freqRatio; From 92544a793286af01988028358d518ac8165abc33 Mon Sep 17 00:00:00 2001 From: Vesa Date: Thu, 26 Jun 2014 19:21:16 +0300 Subject: [PATCH 07/11] What's this strings for Monstro --- plugins/monstro/Monstro.cpp | 149 +++++++++++++++++++++++++++++++++++- 1 file changed, 145 insertions(+), 4 deletions(-) diff --git a/plugins/monstro/Monstro.cpp b/plugins/monstro/Monstro.cpp index aa61187bd..e34acc2fe 100644 --- a/plugins/monstro/Monstro.cpp +++ b/plugins/monstro/Monstro.cpp @@ -142,7 +142,7 @@ void MonstroSynth::renderOutput( fpp_t _frames, sampleFrame * _buf ) if( mod##_e1 != 0.0f ) car += m_env1_buf[f] * mod##_e1; \ if( mod##_e2 != 0.0f ) car += m_env2_buf[f] * mod##_e2; \ if( mod##_l1 != 0.0f ) car += m_lfo1_buf[f] * mod##_l1; \ - if( mod##_l2 != 0.0f ) car += m_lfo2_buf[f] * mod##_l2; + if( mod##_l2 != 0.0f ) car += m_lfo2_buf[f] * mod##_l2; #define modulatephs( car, mod ) \ if( mod##_e1 != 0.0f ) car += m_env1_buf[f] * mod##_e1; \ @@ -1673,12 +1673,29 @@ MonstroView::MonstroView( Instrument * _instrument, m_opViewButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "opview_active" ) ); m_opViewButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "opview_inactive" ) ); toolTip::add( m_opViewButton, tr( "Operators view" ) ); + m_opViewButton -> setWhatsThis( tr( "The Operators view contains all the operators. These include both audible " + "operators (oscillators) and inaudible operators, or modulators: " + "Low-frequency oscillators and Envelopes. " + "Knobs and other widgets in the Operators view have their own what's this -texts, " + "so you can get more specific help for them that way. " ) ); pixmapButton * m_matViewButton = new pixmapButton( this, NULL ); m_matViewButton -> move( 125,0 ); m_matViewButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "matview_active" ) ); m_matViewButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "matview_inactive" ) ); toolTip::add( m_matViewButton, tr( "Matrix view" ) ); + m_matViewButton -> setWhatsThis( tr( "The Matrix view contains the modulation matrix. Here you can define " + "the modulation relationships between the various operators: Each " + "audible operator (oscillators 1-3) has 3-4 properties that can be " + "modulated by any of the modulators. Using more modulations consumes " + "more CPU power. " + "The view is divided to modulation targets, grouped by the target oscillator. " + "Available targets are volume, pitch, phase, pulse width and sub-osc ratio. " + "Note: some targets are specific to one oscillator only. " + "Each modulation target has 4 knobs, one for each modulator. By default " + "the knobs are at 0, which means no modulation. Turning a knob to 1 causes " + "that modulator to affect the modulation target as much as possible. Turning " + "it to -1 does the same, but the modulation is inversed. " ) ); m_selectedViewGroup = new automatableButtonGroup( this ); m_selectedViewGroup -> addButton( m_opViewButton ); @@ -1850,7 +1867,7 @@ QWidget * MonstroView::setupOperatorsView( QWidget * _parent ) makeknob( m_osc1VolKnob, KNOBCOL1, O1ROW, "Volume", "%", "osc1Knob" ) makeknob( m_osc1PanKnob, KNOBCOL2, O1ROW, "Panning", "", "osc1Knob" ) - makeknob( m_osc1CrsKnob, KNOBCOL3, O1ROW, "Coarse detune", " seminotes", "osc1Knob" ) + makeknob( m_osc1CrsKnob, KNOBCOL3, O1ROW, "Coarse detune", " semitones", "osc1Knob" ) makeknob( m_osc1FtlKnob, KNOBCOL4, O1ROW, "Finetune left", " cents", "osc1Knob" ) makeknob( m_osc1FtrKnob, KNOBCOL5, O1ROW, "Finetune right", " cents", "osc1Knob" ) makeknob( m_osc1SpoKnob, KNOBCOL6, O1ROW, "Stereo phase offset", " deg", "osc1Knob" ) @@ -1863,7 +1880,7 @@ QWidget * MonstroView::setupOperatorsView( QWidget * _parent ) makeknob( m_osc2VolKnob, KNOBCOL1, O2ROW, "Volume", "%", "osc2Knob" ) makeknob( m_osc2PanKnob, KNOBCOL2, O2ROW, "Panning", "", "osc2Knob" ) - makeknob( m_osc2CrsKnob, KNOBCOL3, O2ROW, "Coarse detune", " seminotes", "osc2Knob" ) + makeknob( m_osc2CrsKnob, KNOBCOL3, O2ROW, "Coarse detune", " semitones", "osc2Knob" ) makeknob( m_osc2FtlKnob, KNOBCOL4, O2ROW, "Finetune left", " cents", "osc2Knob" ) makeknob( m_osc2FtrKnob, KNOBCOL5, O2ROW, "Finetune right", " cents", "osc2Knob" ) makeknob( m_osc2SpoKnob, KNOBCOL6, O2ROW, "Stereo phase offset", " deg", "osc2Knob" ) @@ -1879,7 +1896,7 @@ QWidget * MonstroView::setupOperatorsView( QWidget * _parent ) makeknob( m_osc3VolKnob, KNOBCOL1, O3ROW, "Volume", "%", "osc3Knob" ) makeknob( m_osc3PanKnob, KNOBCOL2, O3ROW, "Panning", "", "osc3Knob" ) - makeknob( m_osc3CrsKnob, KNOBCOL3, O3ROW, "Coarse detune", " seminotes", "osc3Knob" ) + makeknob( m_osc3CrsKnob, KNOBCOL3, O3ROW, "Coarse detune", " semitones", "osc3Knob" ) makeknob( m_osc3SpoKnob, KNOBCOL4, O3ROW, "Stereo phase offset", " deg", "osc3Knob" ) makeknob( m_osc3SubKnob, KNOBCOL5, O3ROW, "Sub-osc mix", "", "osc3Knob" ) @@ -1957,6 +1974,130 @@ QWidget * MonstroView::setupOperatorsView( QWidget * _parent ) m_o23ModGroup-> addButton( m_fmButton ); m_o23ModGroup-> addButton( m_pmButton ); + + +//////////////////////////////////// +// // +// whatsthis-information strings // +// // +//////////////////////////////////// + + m_osc1CrsKnob -> setWhatsThis( tr( "The CRS knob changes the tuning of oscillator 1 in semitone steps. " ) ); + m_osc2CrsKnob -> setWhatsThis( tr( "The CRS knob changes the tuning of oscillator 2 in semitone steps. " ) ); + m_osc3CrsKnob -> setWhatsThis( tr( "The CRS knob changes the tuning of oscillator 3 in semitone steps. " ) ); + m_osc1FtlKnob -> setWhatsThis( tr( "FTL and FTR change the finetuning of the oscillator for left and right " + "channels respectively. These can add stereo-detuning to the oscillator " + "which widens the stereo image and causes an illusion of space. " ) ); + m_osc1FtrKnob -> setWhatsThis( tr( "FTL and FTR change the finetuning of the oscillator for left and right " + "channels respectively. These can add stereo-detuning to the oscillator " + "which widens the stereo image and causes an illusion of space. " ) ); + m_osc2FtlKnob -> setWhatsThis( tr( "FTL and FTR change the finetuning of the oscillator for left and right " + "channels respectively. These can add stereo-detuning to the oscillator " + "which widens the stereo image and causes an illusion of space. " ) ); + m_osc2FtrKnob -> setWhatsThis( tr( "FTL and FTR change the finetuning of the oscillator for left and right " + "channels respectively. These can add stereo-detuning to the oscillator " + "which widens the stereo image and causes an illusion of space. " ) ); + m_osc1SpoKnob -> setWhatsThis( tr( "The SPO knob modifies the difference in phase between left and right " + "channels. Higher difference creates a wider stereo image. " ) ); + m_osc2SpoKnob -> setWhatsThis( tr( "The SPO knob modifies the difference in phase between left and right " + "channels. Higher difference creates a wider stereo image. " ) ); + m_osc3SpoKnob -> setWhatsThis( tr( "The SPO knob modifies the difference in phase between left and right " + "channels. Higher difference creates a wider stereo image. " ) ); + m_osc1PwKnob -> setWhatsThis( tr( "The PW knob controls the pulse width, also known as duty cycle, " + "of oscillator 1. Oscillator 1 is a digital pulse wave oscillator, " + "it doesn't produce bandlimited output, which means that you can " + "use it as an audible oscillator but it will cause aliasing. You can " + "also use it as an inaudible source of a sync signal, which can be " + "used to synchronize oscillators 2 and 3. " ) ); + m_osc1SSRButton -> setWhatsThis( tr( "Send Sync on Rise: When enabled, the Sync signal is sent every time " + "the state of oscillator 1 changes from low to high, ie. when the amplitude " + "changes from -1 to 1. " + "Oscillator 1's pitch, phase and pulse width may affect the timing of syncs, " + "but its volume has no effect on them. Sync signals are sent independently " + "for both left and right channels. " ) ); + m_osc1SSFButton -> setWhatsThis( tr( "Send Sync on Fall: When enabled, the Sync signal is sent every time " + "the state of oscillator 1 changes from high to low, ie. when the amplitude " + "changes from 1 to -1. " + "Oscillator 1's pitch, phase and pulse width may affect the timing of syncs, " + "but its volume has no effect on them. Sync signals are sent independently " + "for both left and right channels. " ) ); + m_osc2SyncHButton -> setWhatsThis( tr( "Hard sync: Every time the oscillator receives a sync signal from oscillator 1, " + "its phase is reset to 0 + whatever its phase offset is. " ) ); + m_osc3SyncHButton -> setWhatsThis( tr( "Hard sync: Every time the oscillator receives a sync signal from oscillator 1, " + "its phase is reset to 0 + whatever its phase offset is. " ) ); + m_osc2SyncRButton -> setWhatsThis( tr( "Reverse sync: Every time the oscillator receives a sync signal from oscillator 1, " + "the amplitude of the oscillator gets inverted. " ) ); + m_osc3SyncRButton -> setWhatsThis( tr( "Reverse sync: Every time the oscillator receives a sync signal from oscillator 1, " + "the amplitude of the oscillator gets inverted. " ) ); + m_osc2WaveBox -> setWhatsThis( tr( "Choose waveform for oscillator 2. " ) ); + m_osc3Wave1Box -> setWhatsThis( tr( "Choose waveform for oscillator 3's first sub-osc. " + "Oscillator 3 can smoothly interpolate between two different waveforms. " ) ); + m_osc3Wave2Box -> setWhatsThis( tr( "Choose waveform for oscillator 3's second sub-osc. " + "Oscillator 3 can smoothly interpolate between two different waveforms. " ) ); + m_osc3SubKnob -> setWhatsThis( tr( "The SUB knob changes the mixing ratio of the two sub-oscs of oscillator 3. " + "Each sub-osc can be set to produce a different waveform, and oscillator 3 " + "can smoothly interpolate between them. All incoming modulations to oscillator 3 are applied " + "to both sub-oscs/waveforms in the exact same way. " ) ); + m_mixButton -> setWhatsThis( tr( "In addition to dedicated modulators, Monstro allows oscillator 3 to be modulated by " + "the output of oscillator 2. " + "Mix mode means no modulation: the outputs of the oscillators are simply mixed together. " ) ); + m_amButton -> setWhatsThis( tr( "In addition to dedicated modulators, Monstro allows oscillator 3 to be modulated by " + "the output of oscillator 2. " + "AM means amplitude modulation: Oscillator 3's amplitude (volume) is modulated by oscillator 2. " ) ); + m_fmButton -> setWhatsThis( tr( "In addition to dedicated modulators, Monstro allows oscillator 3 to be modulated by " + "the output of oscillator 2. " + "FM means frequency modulation: Oscillator 3's frequency (pitch) is modulated by oscillator 2. " + "The frequency modulation is implemented as phase modulation, which gives a more stable overall pitch " + "than \"pure\" frequency modulation. " ) ); + m_pmButton -> setWhatsThis( tr( "In addition to dedicated modulators, Monstro allows oscillator 3 to be modulated by " + "the output of oscillator 2. " + "PM means phase modulation: Oscillator 3's phase is modulated by oscillator 2. " + "It differs from frequency modulation in that the phase changes are not cumulative. " ) ); + m_lfo1WaveBox -> setWhatsThis( tr( "Select the waveform for LFO 1. " + "\"Random\" and \"Random smooth\" are special waveforms: " + "they produce random output, where the rate of the LFO controls how often " + "the state of the LFO changes. The smooth version interpolates between these " + "states with cosine interpolation. These random modes can be used to give " + "\"life\" to your presets - add some of that analog unpredictability... " ) ); + m_lfo2WaveBox -> setWhatsThis( tr( "Select the waveform for LFO 2. " + "\"Random\" and \"Random smooth\" are special waveforms: " + "they produce random output, where the rate of the LFO controls how often " + "the state of the LFO changes. The smooth version interpolates between these " + "states with cosine interpolation. These random modes can be used to give " + "\"life\" to your presets - add some of that analog unpredictability... " ) ); + m_lfo1AttKnob -> setWhatsThis( tr( "Attack causes the LFO to come on gradually from the start of the note. " ) ); + m_lfo2AttKnob -> setWhatsThis( tr( "Attack causes the LFO to come on gradually from the start of the note. " ) ); + m_lfo1RateKnob -> setWhatsThis( tr( "Rate sets the speed of the LFO, measured in milliseconds per cycle. Can be synced to tempo. " ) ); + m_lfo2RateKnob -> setWhatsThis( tr( "Rate sets the speed of the LFO, measured in milliseconds per cycle. Can be synced to tempo. " ) ); + m_lfo1PhsKnob -> setWhatsThis( tr( "PHS controls the phase offset of the LFO. " ) ); + m_lfo2PhsKnob -> setWhatsThis( tr( "PHS controls the phase offset of the LFO. " ) ); + + m_env1PreKnob -> setWhatsThis( tr( "PRE, or pre-delay, delays the start of the envelope from the start of the note. 0 means no delay. " ) ); + m_env2PreKnob -> setWhatsThis( tr( "PRE, or pre-delay, delays the start of the envelope from the start of the note. 0 means no delay. " ) ); + m_env1AttKnob -> setWhatsThis( tr( "ATT, or attack, controls how fast the envelope ramps up at start, measured in milliseconds. " + "A value of 0 means instant. " ) ); + m_env2AttKnob -> setWhatsThis( tr( "ATT, or attack, controls how fast the envelope ramps up at start, measured in milliseconds. " + "A value of 0 means instant. " ) ); + m_env1HoldKnob -> setWhatsThis( tr( "HOLD controls how long the envelope stays at peak after the attack phase. " ) ); + m_env2HoldKnob -> setWhatsThis( tr( "HOLD controls how long the envelope stays at peak after the attack phase. " ) ); + m_env1DecKnob -> setWhatsThis( tr( "DEC, or decay, controls how fast the envelope falls off from its peak, measured in milliseconds " + "it would take to go from peak to zero. The actual decay may be shorter if sustain is used. ") ); + m_env2DecKnob -> setWhatsThis( tr( "DEC, or decay, controls how fast the envelope falls off from its peak, measured in milliseconds " + "it would take to go from peak to zero. The actual decay may be shorter if sustain is used. ") ); + m_env1SusKnob -> setWhatsThis( tr( "SUS, or sustain, controls the sustain level of the envelope. The decay phase will not go below this level " + "as long as the note is held. " ) ); + m_env2SusKnob -> setWhatsThis( tr( "SUS, or sustain, controls the sustain level of the envelope. The decay phase will not go below this level " + "as long as the note is held. " ) ); + m_env1RelKnob -> setWhatsThis( tr( "REL, or release, controls how long the release is for the note, measured in how long it would take to " + "fall from peak to zero. Actual release may be shorter, depending on at what phase the note is released. ") ); + m_env2RelKnob -> setWhatsThis( tr( "REL, or release, controls how long the release is for the note, measured in how long it would take to " + "fall from peak to zero. Actual release may be shorter, depending on at what phase the note is released. ") ); + m_env1SlopeKnob -> setWhatsThis( tr( "The slope knob controls the curve or shape of the envelope. A value of 0 creates straight rises and falls. " + "Negative values create curves that start slowly, peak quickly and fall of slowly again. " + "Positive values create curves that start and end quickly, and stay longer near the peaks. " ) ); + m_env2SlopeKnob -> setWhatsThis( tr( "The slope knob controls the curve or shape of the envelope. A value of 0 creates straight rises and falls. " + "Negative values create curves that start slowly, peak quickly and fall of slowly again. " + "Positive values create curves that start and end quickly, and stay longer near the peaks. " ) ); return( view ); } From d9d085d14e8258340d61f3e2402ee05bc675cbd4 Mon Sep 17 00:00:00 2001 From: Vesa Date: Fri, 27 Jun 2014 18:21:18 +0300 Subject: [PATCH 08/11] FxMixer: rewrite mixer routing --- include/FxMixer.h | 55 +++++++- src/core/FxMixer.cpp | 311 ++++++++++++++++++++++--------------------- 2 files changed, 212 insertions(+), 154 deletions(-) diff --git a/include/FxMixer.h b/include/FxMixer.h index 8136d9ed4..0857d696d 100644 --- a/include/FxMixer.h +++ b/include/FxMixer.h @@ -32,7 +32,8 @@ #include "ThreadableJob.h" - +class FxRoute; +typedef QVector FxRouteVector; class FxChannel : public ThreadableJob { @@ -58,11 +59,10 @@ class FxChannel : public ThreadableJob bool m_queued; // are we queued up for rendering yet? // pointers to other channels that this one sends to - QVector m_sends; - QVector m_sendAmount; + FxRouteVector m_sends; // pointers to other channels that send to this one - QVector m_receives; + FxRouteVector m_receives; virtual bool requiresProcessing() const { return true; } @@ -71,6 +71,43 @@ class FxChannel : public ThreadableJob }; +class FxRoute : public QObject +{ + public: + FxRoute( FxChannel * from, FxChannel * to, float amount ); + virtual ~FxRoute(); + + fx_ch_t senderIndex() const + { + return m_from->m_channelIndex; + } + + fx_ch_t receiverIndex() const + { + return m_to->m_channelIndex; + } + + FloatModel * amount() const + { + return m_amount; + } + + FxChannel * sender() const + { + return m_from; + } + + FxChannel * receiver() const + { + return m_to; + } + + private: + FxChannel * m_from; + FxChannel * m_to; + FloatModel * m_amount; +}; + class EXPORT FxMixer : public JournallingObject, public Model { @@ -100,13 +137,16 @@ public: // it is safe to call even if the send already exists void createChannelSend(fx_ch_t fromChannel, fx_ch_t toChannel, float amount = 1.0f); + void createRoute( FxChannel * from, FxChannel * to, float amount ); // delete the connection made by createChannelSend void deleteChannelSend(fx_ch_t fromChannel, fx_ch_t toChannel); + void deleteChannelSend( FxRoute * route ); // determine if adding a send from sendFrom to // sendTo would result in an infinite mixer loop. bool isInfiniteLoop(fx_ch_t fromChannel, fx_ch_t toChannel); + bool checkInfiniteLoop( FxChannel * from, FxChannel * to ); // return the FloatModel of fromChannel sending its output to the input of // toChannel. NULL if there is no send. @@ -129,11 +169,16 @@ public: // reset a channel's name, fx, sends, etc void clearChannel(fx_ch_t channelIndex); + // rename channels when moving etc. if they still have their original name + void validateChannelName( int index, int oldIndex ); + inline fx_ch_t numChannels() const { return m_fxChannels.size(); } + FxRouteVector m_fxRoutes; + private: // the fx channels in the mixer. index 0 is always master. QVector m_fxChannels; @@ -142,7 +187,7 @@ private: void allocateChannelsTo(int num); QMutex m_sendsMutex; - void addChannelLeaf( int _ch, sampleFrame * _buf ); + void addChannelLeaf( FxChannel * ch, sampleFrame * buf ); friend class MixerWorkerThread; friend class FxMixerView; diff --git a/src/core/FxMixer.cpp b/src/core/FxMixer.cpp index 961d6f8d6..59e32e3a6 100644 --- a/src/core/FxMixer.cpp +++ b/src/core/FxMixer.cpp @@ -34,6 +34,25 @@ #include "bb_track_container.h" +FxRoute::FxRoute( FxChannel * from, FxChannel * to, float amount ) : + m_from( from ), + m_to( to ) +{ + //qDebug( "created: %d to %d", m_from->m_channelIndex, m_to->m_channelIndex ); + // create send amount model + m_amount = new FloatModel( amount, 0, 1, 0.001, NULL, + tr( "Amount to send from channel %1 to channel %2" ).arg( m_from->m_channelIndex, m_to->m_channelIndex ) ); +} + + +FxRoute::~FxRoute() +{ + // remove send model + delete m_amount; +} + + + FxChannel::FxChannel( int idx, Model * _parent ) : m_fxChain( NULL ), m_hasInput( false ), @@ -65,7 +84,6 @@ FxChannel::~FxChannel() void FxChannel::doProcessing( sampleFrame * _buf ) { - FxMixer * fxm = engine::fxMixer(); const fpp_t fpp = engine::mixer()->framesPerPeriod(); // ignore the passed _buf @@ -77,20 +95,15 @@ void FxChannel::doProcessing( sampleFrame * _buf ) // this improves cache hit rate _buf = m_buffer; - // SMF: OK, due to the fact, that the data from the audio-tracks has been - // written into our buffer already, all which needs to be done at this - // stage is to process inter-channel sends. I really don't like the idea - // of using threads for this -- it just doesn't make any sense and wastes - // cpu-cylces... so I just go through every child of this channel and - // call the acc. doProcessing() directly. - if( m_muteModel.value() == false ) { // OK, we are not muted, so we go recursively through all the channels // which send to us (our children)... - foreach( fx_ch_t senderIndex, m_receives ) + foreach( FxRoute * senderRoute, m_receives ) { - FxChannel * sender = fxm->effectChannel( senderIndex ); + FxChannel * sender = senderRoute->sender(); + FloatModel * sendModel = senderRoute->amount(); + if( ! sendModel ) qFatal( "Error: no send model found from %d to %d", senderRoute->senderIndex(), m_channelIndex ); // wait for the sender job - either it's just been queued yet, // then ThreadableJob::process() will process it now within this @@ -104,8 +117,7 @@ void FxChannel::doProcessing( sampleFrame * _buf ) if( sender->m_hasInput || sender->m_stillRunning ) { // get the send level... - const float amt = - fxm->channelSendModel( senderIndex, m_channelIndex )->value(); + const float amt = sendModel->value(); // mix it's output with this one's output sampleFrame * ch_buf = sender->m_buffer; @@ -116,7 +128,7 @@ void FxChannel::doProcessing( sampleFrame * _buf ) _buf[f][1] += ch_buf[f][1] * v; } } - + // if sender channel hasInput, then we hasInput too if( sender->m_hasInput ) m_hasInput = true; } @@ -124,10 +136,10 @@ void FxChannel::doProcessing( sampleFrame * _buf ) const float v = m_volumeModel.value(); - if( m_hasInput ) + if( m_hasInput ) { // only start fxchain when we have input... - m_fxChain.startRunning(); + m_fxChain.startRunning(); } if( m_hasInput || m_stillRunning ) { @@ -152,12 +164,12 @@ FxMixer::FxMixer() : FxMixer::~FxMixer() { + while( ! m_fxRoutes.isEmpty() ) + { + deleteChannelSend( m_fxRoutes.first() ); + } for( int i = 0; i < m_fxChannels.size(); ++i ) { - for( int j = 0; j < m_fxChannels[i]->m_sendAmount.size(); ++j) - { - delete m_fxChannels[i]->m_sendAmount[j]; - } delete m_fxChannels[i]; } } @@ -177,10 +189,12 @@ int FxMixer::createChannel() } -void FxMixer::deleteChannel(int index) +void FxMixer::deleteChannel( int index ) { m_fxChannels[index]->m_lock.lock(); + FxChannel * ch = m_fxChannels[index]; + // go through every instrument and adjust for the channel index change TrackContainer::TrackList tracks; tracks += engine::getSong()->tracks(); @@ -207,52 +221,34 @@ void FxMixer::deleteChannel(int index) } // delete all of this channel's sends and receives - while( ! m_fxChannels[index]->m_sends.isEmpty() ) + while( ! ch->m_sends.isEmpty() ) { - deleteChannelSend( index, m_fxChannels[index]->m_sends.first() ); + deleteChannelSend( ch->m_sends.first() ); } - while( ! m_fxChannels[index]->m_receives.isEmpty() ) + while( ! ch->m_receives.isEmpty() ) { - deleteChannelSend( m_fxChannels[index]->m_receives.first(), index ); - } - - for(int i=0; im_sends.size(); ++j) - { - if( m_fxChannels[i]->m_sends[j] > index ) - { - // subtract 1 to make up for the missing channel - --m_fxChannels[i]->m_sends[j]; - } - } - for(int j=0; jm_receives.size(); ++j) - { - if( m_fxChannels[i]->m_receives[j] > index ) - { - // subtract 1 to make up for the missing channel - --m_fxChannels[i]->m_receives[j]; - } - } - + deleteChannelSend( ch->m_receives.first() ); } // actually delete the channel delete m_fxChannels[index]; m_fxChannels.remove(index); + + for( int i = index; i < m_fxChannels.size(); ++i ) + { + validateChannelName( i, i + 1 ); + } } -void FxMixer::moveChannelLeft(int index) +void FxMixer::moveChannelLeft( int index ) { // can't move master or first channel if( index <= 1 || index >= m_fxChannels.size() ) { return; } - m_sendsMutex.lock(); // channels to swap int a = index - 1, b = index; @@ -283,122 +279,132 @@ void FxMixer::moveChannelLeft(int index) } } - for(int i=0; im_sends.size(); ++j) - { - if( m_fxChannels[i]->m_sends[j] == a ) - { - m_fxChannels[i]->m_sends[j] = b; - } - else if( m_fxChannels[i]->m_sends[j] == b ) - { - m_fxChannels[i]->m_sends[j] = a; - } - } - for(int j=0; jm_receives.size(); ++j) - { - if( m_fxChannels[i]->m_receives[j] == a ) - { - m_fxChannels[i]->m_receives[j] = b; - } - else if( m_fxChannels[i]->m_receives[j] == b ) - { - m_fxChannels[i]->m_receives[j] = a; - } - } - } - // actually do the swap FxChannel * tmpChannel = m_fxChannels[a]; m_fxChannels[a] = m_fxChannels[b]; m_fxChannels[b] = tmpChannel; - m_sendsMutex.unlock(); + + validateChannelName( a, b ); + validateChannelName( b, a ); } -void FxMixer::moveChannelRight(int index) +void FxMixer::moveChannelRight( int index ) { - moveChannelLeft(index+1); + moveChannelLeft( index + 1 ); } -void FxMixer::createChannelSend(fx_ch_t fromChannel, fx_ch_t toChannel, - float amount) +void FxMixer::createChannelSend( fx_ch_t fromChannel, fx_ch_t toChannel, + float amount ) { +// qDebug( "requested: %d to %d", fromChannel, toChannel ); // find the existing connection FxChannel * from = m_fxChannels[fromChannel]; - for(int i=0; im_sends.size(); ++i){ - if( from->m_sends[i] == toChannel ) + FxChannel * to = m_fxChannels[toChannel]; + + for( int i=0; im_sends.size(); ++i ) + { + if( from->m_sends[i]->receiver() == to ) { // simply adjust the amount - from->m_sendAmount[i]->setValue(amount); + from->m_sends[i]->amount()->setValue( amount ); return; } } // connection does not exist. create a new one - m_sendsMutex.lock(); - // add to from's sends - from->m_sends.push_back(toChannel); - from->m_sendAmount.push_back(new FloatModel(amount, 0, 1, 0.001, NULL, - tr("Amount to send"))); + createRoute( from, to, amount ); +} - // add to to's receives - m_fxChannels[toChannel]->m_receives.push_back(fromChannel); + +void FxMixer::createRoute( FxChannel * from, FxChannel * to, float amount ) +{ + if( from == to ) + { + return; + } + m_sendsMutex.lock(); + FxRoute * route = new FxRoute( from, to, amount ); + + // add us to from's sends + from->m_sends.append( route ); + + // add us to to's receives + to->m_receives.append( route ); + + // add us to fxmixer's list + engine::fxMixer()->m_fxRoutes.append( route ); m_sendsMutex.unlock(); } - // delete the connection made by createChannelSend -void FxMixer::deleteChannelSend(fx_ch_t fromChannel, fx_ch_t toChannel) +void FxMixer::deleteChannelSend( fx_ch_t fromChannel, fx_ch_t toChannel ) { // delete the send FxChannel * from = m_fxChannels[fromChannel]; FxChannel * to = m_fxChannels[toChannel]; - m_sendsMutex.lock(); - // find and delete the send entry - for(int i=0; im_sends.size(); ++i) { - if( from->m_sends[i] == toChannel ) - { - // delete this index - delete from->m_sendAmount[i]; - from->m_sendAmount.remove(i); - from->m_sends.remove(i); - break; - } - } - // find and delete the receive entry - for(int i=0; im_receives.size(); ++i) + // find and delete the send entry + for( int i = 0; i < from->m_sends.size(); ++i ) { - if( to->m_receives[i] == fromChannel ) + if( from->m_sends[i]->receiver() == to ) { - // delete this index - to->m_receives.remove(i); + deleteChannelSend( from->m_sends[i] ); break; } } +} + + +void FxMixer::deleteChannelSend( FxRoute * route ) +{ + m_sendsMutex.lock(); + // remove us from from's sends + route->sender()->m_sends.remove( route->sender()->m_sends.indexOf( route ) ); + // remove us from to's receives + route->receiver()->m_receives.remove( route->receiver()->m_receives.indexOf( route ) ); + // remove us from fxmixer's list + engine::fxMixer()->m_fxRoutes.remove( engine::fxMixer()->m_fxRoutes.indexOf( route ) ); + delete route; m_sendsMutex.unlock(); } -bool FxMixer::isInfiniteLoop(fx_ch_t sendFrom, fx_ch_t sendTo) { +bool FxMixer::isInfiniteLoop( fx_ch_t sendFrom, fx_ch_t sendTo ) +{ + if( sendFrom == sendTo ) return true; + //m_sendsMutex.lock(); + FxChannel * from = m_fxChannels[sendFrom]; + FxChannel * to = m_fxChannels[sendTo]; + bool b = checkInfiniteLoop( from, to ); + //m_sendsMutex.unlock(); + return b; +} + + +bool FxMixer::checkInfiniteLoop( FxChannel * from, FxChannel * to ) +{ // can't send master to anything - if( sendFrom == 0 ) return true; + if( from == m_fxChannels[0] ) + { + return true; + } // can't send channel to itself - if( sendFrom == sendTo ) return true; + if( from == to ) + { + return true; + } // follow sendTo's outputs recursively looking for something that sends // to sendFrom - for(int i=0; im_sends.size(); ++i) + for( int i=0; i < to->m_sends.size(); ++i ) { - if( isInfiniteLoop( sendFrom, m_fxChannels[sendTo]->m_sends[i] ) ) + if( checkInfiniteLoop( from, to->m_sends[i]->receiver() ) ) { return true; } @@ -409,13 +415,23 @@ bool FxMixer::isInfiniteLoop(fx_ch_t sendFrom, fx_ch_t sendTo) { // how much does fromChannel send its output to the input of toChannel? -FloatModel * FxMixer::channelSendModel(fx_ch_t fromChannel, fx_ch_t toChannel) +FloatModel * FxMixer::channelSendModel( fx_ch_t fromChannel, fx_ch_t toChannel ) { - FxChannel * from = m_fxChannels[fromChannel]; - for(int i=0; im_sends.size(); ++i){ - if( from->m_sends[i] == toChannel ) - return from->m_sendAmount[i]; + if( fromChannel == toChannel ) + { + return NULL; } + FxChannel * from = m_fxChannels[fromChannel]; + FxChannel * to = m_fxChannels[toChannel]; + + foreach( FxRoute * route, from->m_sends ) + { + if( route->receiver() == to ) + { + return route->amount(); + } + } + return NULL; } @@ -423,15 +439,6 @@ FloatModel * FxMixer::channelSendModel(fx_ch_t fromChannel, fx_ch_t toChannel) void FxMixer::mixToChannel( const sampleFrame * _buf, fx_ch_t _ch ) { - // SMF: it seems like here the track-channels are mixed in... but from where - // is this called and when and why...?!? - // - // OK, found it (git grep is your friend...): This is the next part, - // where there is a mix between push and pull model inside the core, as - // the audio-tracks *push* their data into the fx-channels hopefully just - // before the Mixer-Channels are processed... Sorry to say this: but this - // took me senseless hours to find out and is silly, too... - if( m_fxChannels[_ch]->m_muteModel.value() == false ) { m_fxChannels[_ch]->m_lock.lock(); @@ -452,24 +459,22 @@ void FxMixer::prepareMasterMix() -void FxMixer::addChannelLeaf( int _ch, sampleFrame * _buf ) +void FxMixer::addChannelLeaf( FxChannel * ch, sampleFrame * buf ) { - FxChannel * thisCh = m_fxChannels[_ch]; - // if we're muted or this channel is seen already, discount it - if( thisCh->m_queued ) + if( ch->m_queued ) { return; } - foreach( const int senderIndex, thisCh->m_receives ) + foreach( FxRoute * senderRoute, ch->m_receives ) { - addChannelLeaf( senderIndex, _buf ); + addChannelLeaf( senderRoute->sender(), buf ); } // add this channel to job list - thisCh->m_queued = true; - MixerWorkerThread::addJob( thisCh ); + ch->m_queued = true; + MixerWorkerThread::addJob( ch ); } @@ -482,15 +487,14 @@ void FxMixer::masterMix( sampleFrame * _buf ) // and add all channels to job list that have no dependencies // when the channel completes it will check its parent to see if it needs // to be processed. - m_sendsMutex.lock(); + //m_sendsMutex.lock(); MixerWorkerThread::resetJobQueue( MixerWorkerThread::JobQueue::Dynamic ); - addChannelLeaf( 0, _buf ); + addChannelLeaf( m_fxChannels[0], _buf ); while( m_fxChannels[0]->state() != ThreadableJob::Done ) { MixerWorkerThread::startAndWaitForJobs(); } - //m_fxChannels[0]->doProcessing( NULL ); - m_sendsMutex.unlock(); + //m_sendsMutex.unlock(); const float v = m_fxChannels[0]->m_volumeModel.value(); MixHelpers::addMultiplied( _buf, m_fxChannels[0]->m_buffer, v, fpp ); @@ -532,7 +536,7 @@ void FxMixer::clearChannel(fx_ch_t index) ch->m_volumeModel.setValue( 1.0f ); ch->m_muteModel.setValue( false ); ch->m_name = ( index == 0 ) ? tr( "Master" ) : tr( "FX %1" ).arg( index ); - ch->m_volumeModel.setDisplayName(ch->m_name ); + ch->m_volumeModel.setDisplayName( ch->m_name ); // send only to master if( index > 0) @@ -540,17 +544,17 @@ void FxMixer::clearChannel(fx_ch_t index) // delete existing sends while( ! ch->m_sends.isEmpty() ) { - deleteChannelSend( index, ch->m_sends.first() ); + deleteChannelSend( ch->m_sends.first() ); } // add send to master - createChannelSend(index, 0); + createChannelSend( index, 0 ); } // delete receives while( ! ch->m_receives.isEmpty() ) { - deleteChannelSend( ch->m_receives.first(), index ); + deleteChannelSend( ch->m_receives.first() ); } } @@ -575,8 +579,8 @@ void FxMixer::saveSettings( QDomDocument & _doc, QDomElement & _this ) QDomElement sendsDom = _doc.createElement( QString( "send" ) ); fxch.appendChild( sendsDom ); - sendsDom.setAttribute( "channel", ch->m_sends[si] ); - ch->m_sendAmount[si]->saveSettings( _doc, sendsDom, "amount"); + sendsDom.setAttribute( "channel", ch->m_sends[si]->receiverIndex() ); + ch->m_sends[si]->amount()->saveSettings( _doc, sendsDom, "amount" ); } } } @@ -589,7 +593,7 @@ void FxMixer::allocateChannelsTo(int num) createChannel(); // delete the default send to master - deleteChannelSend(m_fxChannels.size()-1, 0); + deleteChannelSend( m_fxChannels.size()-1, 0 ); } } @@ -626,7 +630,7 @@ void FxMixer::loadSettings( const QDomElement & _this ) { thereIsASend = true; int sendTo = chDataItem.attribute( "channel" ).toInt(); - allocateChannelsTo( sendTo) ; + allocateChannelsTo( sendTo ) ; float amount = chDataItem.attribute( "amount" ).toFloat(); createChannelSend( num, sendTo, amount ); } @@ -642,10 +646,19 @@ void FxMixer::loadSettings( const QDomElement & _this ) // create a send from every channel into master for( int i=1; im_name == tr( "FX %1" ).arg( oldIndex ) ) + { + fxc->m_name = tr( "FX %1" ).arg( index ); + } +} From 9243d94484125a3e97bc57d2bcd7e5c1a926c04b Mon Sep 17 00:00:00 2001 From: Vesa Date: Fri, 27 Jun 2014 23:17:21 +0300 Subject: [PATCH 09/11] Fix qstring arg --- data/themes/default/mixer_send_off.png | Bin 1022 -> 817 bytes data/themes/default/mixer_send_on.png | Bin 1675 -> 1476 bytes include/FxLine.h | 3 ++- src/core/FxMixer.cpp | 2 +- src/gui/widgets/FxLine.cpp | 17 ++++++++++++++--- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/data/themes/default/mixer_send_off.png b/data/themes/default/mixer_send_off.png index 1be1ad54f20a570b743b38e04939c58705777d5d..3033c4962ac871abc3d18064610d04fa93c9a224 100644 GIT binary patch delta 752 zcmV8?PLTPJ@4nMp)JR7l6|mCH*TQ5431lMERRD)=B97m3;UfJ|a`f}kL} z5H~^##ck-S{dZbuH+3i7b<<^ns3?kYp)i7pAh)BizruCh&*gIYgA|>Z znD`33Z#J9Qw*Bma&%mc@wfZptpeV|lX0u7F)p}G=(==&{qM)iOp-@QrRaHe*RTM=* z(=?B-2k!vXKcd67Z38eqKF-R@3PVFf7>2>Y!2y{}MrLhoZ80@9MIw=4b8{2RvRGVP z#C2WH&d%7_*Z_aPvMdUP0y{f9vJoM~s1)r!vxS8POw%Nv&(qh}C&dmA4>3)Xdc7{Y zo1L9yZ*R}n&i?*BBO@cEQYmh4Z!rwR<5xSw(Lp#IrdTX;dU^`Lz`y_i#bS|ixh&%v zjRuKCf}^7&pQvFNSe8XN9A` zb*`_kiAH~;G#U-b&&pOa3faU4g+>bg#=)gqhCQYw`m{|rVVkzeh0 zd!$?ZCDC?8R<0D?3CcXxL``}_MNLWnpJ?j5d|=u`;t itzNHZ{{LfN9lrsB8gN&s`5a^b0000(-2L1<-Dlq^60002_L%V+f000SaNLh0L01FcU01FcV0GgZ_00007bV*G` z2i^t~3K=EzpCYG`TPJ@5W=TXrR7l6=l;2NVWf;dl@2{SgZfb}ytTYuOT>z6!r1wU) zB}+^+F1p?AZ}2bi&P(q|%)D}jq!<>>NFbzuS%B39yC$uz&?*Fv14_?1uNSA3)=@6z z<(}l^JkN8^`+VQ;^9x=T5uL{EPw##8_x_)wQ6~~bNTd)ny(WK7G>X^sh{xjuzK?G$ zf#;#L!S|XN6CoOnA|&{pPqZ(Fk_v4MhtHp*oxZ2D-+cY$DUR+0{j2uJsMg9p`|a2F zP8yAbR1(p;my|7C0G6{iHq?Ev1c1aR02^AL-@E_46N`;@;>a%EHi+(2N*T{;|`oH=1nkR|t z*RGRDBp4eTd+EAuZ*NnrR(Z1VBmrz*2&$AKnM{&Sr~g;8jE|3_wPs^u0~^-i{PbEZ zNXg{nB#lOc*>7ig^z$Q(F)S}Hlbz3!ozLR?K1)kW936ihVT_?tsbGxZ!FLbH&Sxo= zN*o^_GchrNP>LX+H)s$9C?U{V^KkAVw{F~G=EE7Z*6i)?k(thL^Ttga$Dv-YQz#UW zQnIkHfYur(;xKe&h)ShGxm-qTjS>PSyN0AYy^)B6>$>Fgd1|{g78e(pdVdOlot+(O zwHmJL0$*fD<^ra^-_|o9WGIzO zEG;j!eUBF(lgs5eJUj$o?ANHdTN@rU)IhpGM%Bn zzrSs#QYnNGY;A3w+eoK!blm98v{TCEGHdH=TupypZToVoxi-_&G!G9CbJ9Ekz;#_# zS69j9atsU(bd=5XW-5fhS|}EajEszsOeWjkWdjPXbDVr9oioO%o(8p@O=bhEwPDa!(^)K*pyi_l94>roEw?}Z zBo}ca$32<$4-7r~=U{I%J$Y^O%3E)5Ub_4`N_TI{m=ifSoyLU!IT1rF8X+Ew0)lwF hFIKMBp7Kh{zn$S?DU}6j-~a#s07*qoM6LruV1k0Z$EW}R diff --git a/data/themes/default/mixer_send_on.png b/data/themes/default/mixer_send_on.png index 5982ea3f69d31aca2dadd375bf160bec493251c1..776398e9fc3ed65e2164aadc2d6407229b7f325d 100644 GIT binary patch delta 1415 zcmV;21$g?44a5tODlrxSo&ZA*yIhR`000SaNLh0L01FcU01FcV0GgZ_00007bV*G` z2i^u76B8pbP~QlVTPS}lNkl7Ks~`(Q8ot_z*m`xRJP;=;`2_FQ}E;!eQgBFpV2qZdD7;pl>XA?U#mj!3-R7Be*} zvYALyGt`3`wXs-|GLc5TA%Pf)#v>>K!q8xI)gbgb81yK*Ih&GcVREGleV5@nJzXp7 znvVoJoqou|p$dOo0QSD}L$NQNJ|;#U6(dbV@ZLiphzJO%Dnd2yy+>6+b@&9mrUdmK z?>xAjb?^P_U;o2XPc0les&eqy5!rb0_?rk%42q1>T1*^Z;s7y%5raqtE&w7G!cMX( zF`xpV!)3)67MDA49`y>UuN{8<@YCUE&9=lwe%#Lnl-_?5G$KqAVvJynL5v}&M?-MX z%p;*e47h6}=l{il!l+RHz{h#&@5e)cY-_uj+}_utCdXOB}}?z88K{W$ArA3w{@zxXZ+ zt|LfZu<6q0(v*55wi z@^2P#?VKo%so&6`_23hkr|o~+=j#f5*iTbdXcaw zBk^9VNh8#!#@ITs!p1wxh!JY75t6h<=lzT1=Qe*4geZ=Xo@4T%S=Rr2nkb2J)?tjP z4*2dl^7THo-6OQVx0j7~&Q$pkM)Cy1I9O+qA@h2tE-^i~pF4hjm~ga)h!EFn-1_7< zxc!CuF}08&3dxqY(9N95hi3@lh%gEfV~Eof8UFwLlQtta?Wz(7l?q%`V%Vyfc2&J+ zUp{}q%I{Axa$u5Mp7|!Kip_I;AZQW*;H<+HC9A(Z#l(;HfhgWORFyI-hPecfr|1rb zGTQNnFsS!cRl)D*ZuOTRU^_XjhwemG$$L5HUil}*f42}3Tv=j^kd1$w;hMx&&&Ev}qduO#LxiCrlp!YhAegm(`09#xor{$2))>m+yWqQBZky^;?y z#=bL++icN0`6)$Spjm)g$ESb%53R@dQxpZ>E5#sV{DH3$-#m`&PFZ{Pz3LFw14;@S zMoB&txJL^|_P;Ia-=3n}EV%UMhj{DguXTtIv@l}mpWmeHWH?d0^R)kdp7g$HicWuq zFD?D`F7C5=Sp`{0fF+dI;d(f;L{nwhu?@|LnJ+2&SXbd7!X;cK^ zdN)Fb4mI?ltC#n>ZG|qk*j|oWk2=3GeeC-;hFPUG{2^Q5&7+bsx^0F8nn3k5Hg z<50m~M+z})lMs<1Xk~l8aQMQaR#AVasMo(N0>b>9+|p}E_qo5m>YRHFkqMEi3NZ!= zD&Xy*S8oDTO+aN>{SZ{`(C~dlOsy*a)!lF3{rJM6h03Dm=I3MysHK^N!I-3JL?cYa z1~tYQCk;vo(x#X|h_yydEnz(YAoDpz4uvlfy4t>!X}_M++sG(QsMh704cbdO1HARv zTl%>sJ~uxnYu7Y!fEi|Cb|HxhWg66aU000SaNLh0L01FcU01FcV0GgZ_00007bV*G` z2i^u45i2F$oxMhpTPT0?Nkl6%sF0cYqXx^B4A0Kk1T)xd=lCl#=fUv;^pi~Rqc48rJO5fcJvAB)>QELMV+364 z;Xuq?CPovun>c@9mIxY2sV9WOix_ct@4L=pSt0Ho2)?$q=AjrIy6p#Fzi-x^84-^F zvwlcmtfx<%m>NtBSXi9D-YrjtvY?0sF(?`XK?A6u=ths+F*g7_IXU-acly4k?|V|0 z`P^MIPsLD7ZDU=HH}b5{N<8QXU&b#^V091z47k5?>#(b93~h$Ok14iN(mg-ArfO%Xwk~#)@ygO zX~!0}T(^^YG@uyNl!KC3mc%j=Vnp;j)ErBR)b;dTN7r=p>kUhX=Q(w3h2__dO-j^% zL~_wkc|(8lcp0rE${=_V%c%7wBR22a%GPV&M?Ep58V)Fj6|pLabwwEqv(#q(hbQlUlt2FB z099S{r>9@!nFk-|>4#D(P+f-(FK2o^^l)``(d7aZjH;?BCkAYv+Qstg3oO5}Kv5SAs+tg06pabjmR_Tf1Y8u=vZ`44 z=P`fYIPyBHODnwm@*P#}+AyLJZT0Xh%Rx495X+x4a=*hw0lt!s6k1Ui$HY|G3p} zzV%a{zyFtWb92MpxNPSY z+_2}P9C~IBHwSla`qCb@eQ-B%P~zE``qT}irep3W2eIt9Z=_}8>YJ{|vte#DP3sET z5f8X4RNi2gA>}@K?lZa196$UPum0*~ranH6rHq^N;)74|+;{i$&aqX_ynT{>y5~2m%U`jTT$ZXbfmj9LKYh zyF_jiecREGTT;_-^2j3ZES;hscXVwsg}$K8BPx&Q*u#KVtYbYj>y49r`Se>SCfAOi zX8CXP#2C;JP*qd|0vpC~;dQ{qJ-Xp$q@2mgNO{8s>w2&pTr6Yh6v+~YTxWko{5Y?8 zW^=}6ylwkcb7H#GH7(t^rEOZewxerWx~4f_cXVw>-*vQYOWQWIF`W(= zYK1GHfvBLeG1!7ACW7E7PI5)O2ZzoKv4j|ib+lGe*gHg@k?H^cIb4WYcbVX60z0I{ zq(h}-s7jU|mx6#XmXd;wo_@B^{B=G O0000m_channelIndex, m_to->m_channelIndex ); // create send amount model m_amount = new FloatModel( amount, 0, 1, 0.001, NULL, - tr( "Amount to send from channel %1 to channel %2" ).arg( m_from->m_channelIndex, m_to->m_channelIndex ) ); + tr( "Amount to send from channel %1 to channel %2" ).arg( m_from->m_channelIndex ).arg( m_to->m_channelIndex ) ); } diff --git a/src/gui/widgets/FxLine.cpp b/src/gui/widgets/FxLine.cpp index ce696cc10..ea8f6353d 100644 --- a/src/gui/widgets/FxLine.cpp +++ b/src/gui/widgets/FxLine.cpp @@ -41,6 +41,7 @@ const int FxLine::FxLineHeight = 287; QPixmap * FxLine::s_sendBgArrow = NULL; +QPixmap * FxLine::s_receiveBgArrow = NULL; FxLine::FxLine( QWidget * _parent, FxMixerView * _mv, int _channelIndex) : QWidget( _parent ), @@ -51,6 +52,10 @@ FxLine::FxLine( QWidget * _parent, FxMixerView * _mv, int _channelIndex) : { s_sendBgArrow = new QPixmap( embed::getIconPixmap( "send_bg_arrow", 29, 56 ) ); } + if( ! s_receiveBgArrow ) + { + s_receiveBgArrow = new QPixmap( embed::getIconPixmap( "receive_bg_arrow", 29, 56 ) ); + } setFixedSize( 33, FxLineHeight ); setAttribute( Qt::WA_OpaquePaintEvent, true ); @@ -103,7 +108,7 @@ void FxLine::setChannelIndex(int index) { } -void FxLine::drawFxLine( QPainter* p, const FxLine *fxLine, const QString& name, bool isActive, bool sendToThis ) +void FxLine::drawFxLine( QPainter* p, const FxLine *fxLine, const QString& name, bool isActive, bool sendToThis, bool receiveFromThis ) { int width = fxLine->rect().width(); int height = fxLine->rect().height(); @@ -126,7 +131,11 @@ void FxLine::drawFxLine( QPainter* p, const FxLine *fxLine, const QString& name, // draw the mixer send background if( sendToThis ) { - p->drawPixmap( 2, 0, 29, 56, *FxLine::s_sendBgArrow ); + p->drawPixmap( 2, 0, 29, 56, *s_sendBgArrow ); + } + else if( receiveFromThis ) + { + p->drawPixmap( 2, 0, 29, 56, *s_receiveBgArrow ); } // draw the channel name @@ -148,11 +157,13 @@ void FxLine::paintEvent( QPaintEvent * ) FxMixer * mix = engine::fxMixer(); bool sendToThis = mix->channelSendModel( m_mv->currentFxLine()->m_channelIndex, m_channelIndex ) != NULL; + bool receiveFromThis = mix->channelSendModel( + m_channelIndex, m_mv->currentFxLine()->m_channelIndex ) != NULL; QPainter painter; painter.begin( this ); drawFxLine( &painter, this, mix->effectChannel( m_channelIndex )->m_name, - m_mv->currentFxLine() == this, sendToThis ); + m_mv->currentFxLine() == this, sendToThis, receiveFromThis ); painter.end(); } From 31b82fe50b8ebf277744067b603f4a1c3aabefbe Mon Sep 17 00:00:00 2001 From: Vesa Date: Fri, 27 Jun 2014 23:19:06 +0300 Subject: [PATCH 10/11] Receive arrow --- data/themes/default/receive_bg_arrow.png | Bin 0 -> 289 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 data/themes/default/receive_bg_arrow.png diff --git a/data/themes/default/receive_bg_arrow.png b/data/themes/default/receive_bg_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..f456176e0f16c2d02029b88bd46bd772aa4d8e7f GIT binary patch literal 289 zcmeAS@N?(olHy`uVBq!ia0vp^vOsLX!3HE5KYi{3Qk(@Ik;M!Q+`=Ht$S`Y;1W=H@ z#M9T6{T`dNu!Z54nZcSsA;}Wgh!W@g+}zZ>5(ej@)Wnk16ovB4k_-iRPv3y>Mm}+% zqS>A?09!e~Et_hQopqJDuFn3u~Xyxx1|^}=bt?|q58 zVkSB5-ih?ZD;k=hAnf$MMlEYrQ9(>FVdQ&MBb@09(FnwEzGB literal 0 HcmV?d00001 From 0058b1064fd194fbaba083fe388ef939741bef51 Mon Sep 17 00:00:00 2001 From: Vesa Date: Sat, 28 Jun 2014 10:06:52 +0300 Subject: [PATCH 11/11] Update channel send model names properly --- include/FxMixer.h | 2 ++ src/core/FxMixer.cpp | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/include/FxMixer.h b/include/FxMixer.h index 0857d696d..1b24bb54b 100644 --- a/include/FxMixer.h +++ b/include/FxMixer.h @@ -101,6 +101,8 @@ class FxRoute : public QObject { return m_to; } + + void updateName(); private: FxChannel * m_from; diff --git a/src/core/FxMixer.cpp b/src/core/FxMixer.cpp index a8f96c6c6..331d2b45d 100644 --- a/src/core/FxMixer.cpp +++ b/src/core/FxMixer.cpp @@ -52,6 +52,15 @@ FxRoute::~FxRoute() } +void FxRoute::updateName() +{ + if( m_amount) + { + m_amount->setDisplayName( + tr( "Amount to send from channel %1 to channel %2" ).arg( m_from->m_channelIndex ).arg( m_to->m_channelIndex ) ); + } +} + FxChannel::FxChannel( int idx, Model * _parent ) : m_fxChain( NULL ), @@ -661,4 +670,16 @@ void FxMixer::validateChannelName( int index, int oldIndex ) { fxc->m_name = tr( "FX %1" ).arg( index ); } + // set correct channel index + fxc->m_channelIndex = index; + + // now check all routes and update names of the send models + foreach( FxRoute * r, fxc->m_sends ) + { + r->updateName(); + } + foreach( FxRoute * r, fxc->m_receives ) + { + r->updateName(); + } }