Old 03-26-2020, 04:38 AM   #1
solarfall
Human being with feelings
 
Join Date: Sep 2013
Posts: 72
Default New Free Plugin Alert! ClassicChannel & ClassicBus

Hello good people! I'm constantly working on new projects as quarantine goes on. Here are two new toys for you.

https://www.patreon.com/posts/35284587

ClassicChannel

A tool meant to warm up your digital tracks. No global link this time, but slightly different coloration for each instance is mantained. Features pre/post emphasis and uses slightly more cpu than previous plugins. Use it on every track for cumulative effect, or just where needed. No particular indications here.

ClassicBus

A derivation of ClassicChannel with less coloration and harmonics, but with same character. Use it on busses or directly on your mixbuss for heavy coloration.

Suggested use:

ClassicChannel on every track as first insert; ClassicBus on every bus followed by ClassicChannel; ClassicBus on MixBus as first insert. This will seriously warm up your mix.

Warning: Use the trim input wisely unless you want a distorted mess.

Enjoy!
solarfall is offline   Reply With Quote
Old 03-27-2020, 02:25 AM   #2
HoJo
Human being with feelings
 
Join Date: Dec 2007
Location: Germany
Posts: 246
Default

Thanks a lot, for your time and effort!
Will try out as soon as possible.

BR,
HoJo
HoJo is offline   Reply With Quote
Old 03-27-2020, 04:42 AM   #3
SaulT
Human being with feelings
 
Join Date: Oct 2013
Location: Seattle, WA
Posts: 806
Default

In ClassicChannel (classic based on...?) why multiply atan by 0.14? This limits the amplitude to +/- 0.2 or so, right? So basically a really hard clip above -14 dB? This doesnt seem like something a console channel would ever do.

I would like to suggest a more generalized function:

spl0 = atan(a*spl0+0.001)*b;

where b is 1/a and a is between 0 and maybe 3, with lower numbers being less linear?
Graph it, you'll see what I mean.

Something similar can be done with the ClassicBus function, perhaps

spl0 = atan(a*spl0/(a+abs(spl0))+0.0001);

although I vastly prefer the first as it avoids the division and an abs() call.

A suggestion? Instead of making it completely a different random call every time you press play, perhaps have a knob that allows some degree of user control. Maybe even vary the parameters of the plugin over time?
SaulT is offline   Reply With Quote
Old 03-27-2020, 05:13 AM   #4
solarfall
Human being with feelings
 
Join Date: Sep 2013
Posts: 72
Default

Quote:
Originally Posted by SaulT View Post
In ClassicChannel (classic based on...?) why multiply atan by 0.14? This limits the amplitude to +/- 0.2 or so, right? So basically a really hard clip above -14 dB? This doesnt seem like something a console channel would ever do.

I would like to suggest a more generalized function:

spl0 = atan(a*spl0+0.001)*b;

where b is 1/a and a is between 0 and maybe 3, with lower numbers being less linear?
Graph it, you'll see what I mean.

Something similar can be done with the ClassicBus function, perhaps

spl0 = atan(a*spl0/(a+abs(spl0))+0.0001);

although I vastly prefer the first as it avoids the division and an abs() call.

Hello SaulT. For me classic sound is the NEVE sound. Now, this plugin only draws inspiration from neve sound. It's far from it.

This plugin is calibrated to -18dbFS input. My goal is to get a fair amount of harmonics at that input level. So i need to multiply the signal in the atan function to get harmonics and subsequently divide it to gain match the input. Try removing the 0.14. It's gonna get loud!

Quote:
A suggestion? Instead of making it completely a different random call every time you press play, perhaps have a knob that allows some degree of user control. Maybe even vary the parameters of the plugin over time?
Thanks for pointing that out as i now discovered the ext_noinit parameter which avoids a call on every play.
I'm gonna fix this asap.

http://reaper.fm/sdk/js/js.php#sec_init
solarfall is offline   Reply With Quote
Old 03-27-2020, 10:10 PM   #5
SaulT
Human being with feelings
 
Join Date: Oct 2013
Location: Seattle, WA
Posts: 806
Default

Quote:
Hello SaulT. For me classic sound is the NEVE sound. Now, this plugin only draws inspiration from neve sound. It's far from it.
I've never had the opportunity to use one... but I'll say that this has gotten me wondering if I should dig out the electronics textbook so I can study the preamp and see what makes it tick, see if I can take a hack at modeling the sound!


Quote:
This plugin is calibrated to -18dbFS input. My goal is to get a fair amount of harmonics at that input level. So i need to multiply the signal in the atan function to get harmonics and subsequently divide it to gain match the input. Try removing the 0.14. It's gonna get loud!
Driving input, ok, makes sense. It doesn't compensate correctly, different material requires different compensation. This is especially noticeable with the +18 dB trim option, I get different results with sine, noise, and music. E.g. a gainOut value of 4 or so worked a lot better with noise but with music it was more like 2. Maybe consider using automatic volume compensation instead? E.g. take an RMS with a 300-400 ms window of both the input and output and multiply the output by the ratio.

Something I also noticed is that adding 0.001 to atan() does effectively nothing. Raising that value does add some even-order harmonics though, I thought that 0.3 or so had some good character while 0.8 sounded pleasing to me, although in a different way.

Also... needs oversampling!
SaulT is offline   Reply With Quote
Old 03-28-2020, 03:09 AM   #6
solarfall
Human being with feelings
 
Join Date: Sep 2013
Posts: 72
Default

Quote:
Originally Posted by SaulT View Post
In ClassicChannel (classic based on...?) why multiply atan by 0.14? This limits the amplitude to +/- 0.2 or so, right? So basically a really hard clip above -14 dB? This doesnt seem like something a console channel would ever do.

I would like to suggest a more generalized function:

spl0 = atan(a*spl0+0.001)*b;

where b is 1/a and a is between 0 and maybe 3, with lower numbers being less linear?
Graph it, you'll see what I mean.

Something similar can be done with the ClassicBus function, perhaps

spl0 = atan(a*spl0/(a+abs(spl0))+0.0001);

although I vastly prefer the first as it avoids the division and an abs() call.

A suggestion? Instead of making it completely a different random call every time you press play, perhaps have a knob that allows some degree of user control. Maybe even vary the parameters of the plugin over time?
Quote:
Originally Posted by SaulT View Post
I've never had the opportunity to use one... but I'll say that this has gotten me wondering if I should dig out the electronics textbook so I can study the preamp and see what makes it tick, see if I can take a hack at modeling the sound!




Driving input, ok, makes sense. It doesn't compensate correctly, different material requires different compensation. This is especially noticeable with the +18 dB trim option, I get different results with sine, noise, and music. E.g. a gainOut value of 4 or so worked a lot better with noise but with music it was more like 2. Maybe consider using automatic volume compensation instead? E.g. take an RMS with a 300-400 ms window of both the input and output and multiply the output by the ratio.

Something I also noticed is that adding 0.001 to atan() does effectively nothing. Raising that value does add some even-order harmonics though, I thought that 0.3 or so had some good character while 0.8 sounded pleasing to me, although in a different way.

Also... needs oversampling!
Yeah oversampling...too complex for me..i can't implement it. Help
solarfall is offline   Reply With Quote
Old 03-31-2020, 07:04 PM   #7
SaulT
Human being with feelings
 
Join Date: Oct 2013
Location: Seattle, WA
Posts: 806
Default

So I was thinking something like this...

volume compensation added
"preamp" input continuous from -18 to +18 dB
adjustable saturation
adjustable harmonic balance
pseudorandom channel variations with seed ("hey I like 506 but not 32 etc")
2x oversampling

I'm stopping there because it makes the point, but that's a start.
I would probably bump up the effect of channel variations, I think they're
pretty minimal. I would want more character in general, tbh, but I'm iffy
on how it handles higher signal levels, it fuzzes out on full mixes. Obvs this
isn't what it's built for, but that's still something to consider.

This is making me want to roll my own preamp plugin...

Code:
 
//tags: saturation glue tonal shaping

desc:ClassicChannel - St Remix

slider1:0<-18,18,0.1>Input Trim (dB)
slider2:1<1,10,0.1>Saturation
slider3:0<0,1,0.01>even-order coloration bias
slider4:0<0,1024,1>color seed (0 = random)
slider5:0<0,1,1{off,2x}>oversampling

//options:no_meter

@init

/* added code */

function singlepole(val,targ,coeff) (val*coeff + targ*(1-coeff); );
function get_coeff(ms) ( exp(-1/(srate*0.001*ms)); );
function get_prng() instance(seed) ( seed = (seed * 9821 + 6925) % 65531; seed/65531; );
function randval(x) instance(seed) ( seed = (seed * 9821 + 6925) % 65531; seed*x/65531; );
function rms(in) instance(rms,coeff,val) ( rms = singlepole(rms,in*in,coeff); val = sqrt(rms); );
function rms_set(ms) ( this.coeff = get_coeff(ms); );


//--------------------Halfband filter (19-tap)


function os_os2()
  instance(y18, y17, y16, y15, y14, y13, y12, y11, y10,
		y9, y8, y7, y6, y5, y4, y3, y2, y1, y0)
(
  y18 = y16; y17 = y15; y16 = y14; y15 = y13;
  y14 = y12; y13 = y11; y12 = y10; y11 =  y9;
  y10 =  y8;  y9 =  y7;  y8 =  y6;  y7 =  y5;
   y6 =  y4;  y5 =  y3;  y4 =  y2;  y3 =  y1;
   y2 =  y0;
);

function os_up2(x)
  instance(x9, x8, x7, x6, x5, x4, x3, x2, x1, x0,
	   y18, y17, y16, y15, y14, y13, y12, y11, y10,
		y9, y8, y7, y6, y5, y4, y3, y2, y1, y0)
(
  x9 = x8; x8 = x7; x7 = x6; x6 = x5; x5 = x4; x4 = x3;
  x3 = x2; x2 = x1; x1 = x0; x0 = x * 2;

  this.os_os2();
  y1 = 0.0028*(x0+x9) - 0.0118*(x1+x8) + 0.0334*(x2+x7) 
	- 0.0849*(x3+x6) + 0.3106*(x4+x5);
  y0 = 0.5*x4;
);

function os_down2()
  instance(y18, y16, y14, y12, y10, y9, y8, y6, y4, y2, y0)
(
  0.0028*(y0+y18) - 0.0118*(y2+y16) + 0.0334*(y4+y14) 
  - 0.0849*(y6+y12) + 0.3106*(y8+y10) + 0.5*y9;
);


/* end added code */

function bqd(xn)
  instance(a0,a1,a2,b1,b2,z1,z2,xn,xn_1,xn_2,yn,yn_1,yn_2)
(
    yn = xn * a0 + z1;
    z1 = xn * a1 + z2 - b1 * yn;
    z2 = xn * a2 - b2 * yn;
    yn;
);


function hpSet(F,Q)
  instance(a0,a1,a2,b1,b2,xn,xn_1,xn_2,yn,yn_1,yn_2,V,K,norm,F,Q,peakGain)
(
  F ?
  (
    V = 10^(abs(peakGain)/ 20.0);
    K = tan($pi * F/osrate);
    norm = 1 / (1 + K / Q + K * K);
    a0 = 1 * norm;
    a1 = -2 * a0;
    a2 = a0;
    b1 = 2 * (K * K - 1) * norm;
    b2 = (1 - K / Q + K * K) * norm;
  ):(a0 = 1; a1 = a2 = b1 = b2 = 0;)
);


function lpSet(F,Q)
  instance(a0,a1,a2,b1,b2,c0,d0,xn,xn_1,xn_2,yn,yn_1,yn_2,V,K,norm,F,Q,peakGain)
(
  F ?
  (
    V = 10^(abs(peakGain)/ 20.0);
    K = tan($pi * F/osrate);
    norm = 1 / (1 + K / Q + K * K);
    a0 = K * K * norm;
    a1 = 2 * a0;
    a2 = a0;
    b1 = 2 * (K * K - 1) * norm;
    b2 = (1 - K / Q + K * K) * norm;
  ):(a0 = 1; a1 = a2 = b1 = b2 = 0;)
);

function lsSet(F,peakGain)
  instance(a0,a1,a2,b1,b2,c0,d0,xn,xn_1,xn_2,yn,yn_1,yn_2,V,K,norm,F,Q,peakGain)
(
  V = 10^(abs(peakGain)/ 20.0);
  K = tan($pi * F/osrate);
  peakGain >= 0  ?  // boost
  (
      norm = 1 / (1 + sqrt(2) * K + K * K);
      a0 = (1 + sqrt(2*V) * K + V * K * K) * norm;
      a1 = 2 * (V * K * K - 1) * norm;
      a2 = (1 - sqrt(2*V) * K + V * K * K) * norm;
      b1 = 2 * (K * K - 1) * norm;
      b2 = (1 - sqrt(2) * K + K * K) * norm;
  ):(
      norm = 1 / (1 + sqrt(2*V) * K + V * K * K);
      a0 = (1 + sqrt(2) * K + K * K) * norm;
      a1 = 2 * (K * K - 1) * norm;
      a2 = (1 - sqrt(2) * K + K * K) * norm;
      b1 = 2 * (V * K * K - 1) * norm;
      b2 = (1 - sqrt(2*V) * K + V * K * K) * norm;
  );
);

function hsSet(F,peakGain)
  instance(a0,a1,a2,b1,b2,c0,d0,xn,xn_1,xn_2,yn,yn_1,yn_2,V,K,norm,F,Q,peakGain)
(
  V = 10^(abs(peakGain)/ 20.0);
  K = tan($pi * F/osrate);
  peakGain >= 0  ?  // boost
  (
      norm = 1 / (1 + sqrt(2) * K + K * K);
      a0 = (V + sqrt(2*V) * K + K * K) * norm;
      a1 = 2 * (K * K - V) * norm;
      a2 = (V - sqrt(2*V) * K + K * K) * norm;
      b1 = 2 * (K * K - 1) * norm;
      b2 = (1 - sqrt(2) * K + K * K) * norm;
  ):(
      norm = 1 / (V + sqrt(2*V) * K + K * K);
      a0 = (1 + sqrt(2) * K + K * K) * norm;
      a1 = 2 * (K * K - 1) * norm;
      a2 = (1 - sqrt(2) * K + K * K) * norm;
      b1 = 2 * (K * K - V) * norm;
      b2 = (V - sqrt(2*V) * K + K * K) * norm;
  );
);

function pkSet(F,Q,peakGain)
  instance(a0,a1,a2,b1,b2,c0,d0,xn,xn_1,xn_2,yn,yn_1,yn_2,V,K,norm,F,Q,peakGain)
(
  V = 10^(abs(peakGain)/ 20.0);
  K = tan($pi * F/osrate);
  peakGain >= 0  ?  // boost
  (
      norm = 1 / (1 + 1/Q * K + K * K);
      a0 = (1 + V/Q * K + K * K) * norm;
      a1 = 2 * (K * K - 1) * norm;
      a2 = (1 - V/Q * K + K * K) * norm;
      b1 = a1;
      b2 = (1 - 1/Q * K + K * K) * norm;
  ):(
      norm = 1 / (1 + V/Q * K + K * K);
      a0 = (1 + 1/Q * K + K * K) * norm;
      a1 = 2 * (K * K - 1) * norm;
      a2 = (1 - 1/Q * K + K * K) * norm;
      b1 = a1;
      b2 = (1 - V/Q * K + K * K) * norm;
  );
);

c.hpF  = 11;     c.hpQ   =  1.1;
c.lpF  = 21000;  c.lpQ   =  0.2;
c.lsF  = 90;     c.lsG   =  0.2;
c.hsF  = 6000;   c.hsG   = -0.3;
c.p1F  = 2000;    c.p1Q   =  0.2;  c.p1G = -0.3;
c.p2F  = 4500;   c.p2Q   =  0.2;  c.p2G = -0.4;
c.empF = 100;    c.empG  =  -12;


function channel_init()
 instance(hp,lp,ls,hs,pk1,pk2,emph,demph)
(
  emph.hsSet(c.empF,c.empG);
  demph.hsSet(c.empF,-c.empG);
  hp.hpSet(c.hpF + r.randval(10), c.hpQ);
  lp.lpSet(c.lpF - r.randval(1000), c.lpQ);
  ls.lsSet(c.lsF, c.lsG + r.randval(0.1));
  hs.hsSet(c.hsF, c.hsG - r.randval(0.1));
  pk1.pkSet(c.p1F + r.randval(100), c.p1Q, c.p1G + r.randval(0.1));
  pk2.pkSet(c.p2F - r.randval(100), c.p2Q, c.p2G - r.randval(0.1));
);


function channel_process(in)
 instance(hp,lp,ls,hs,pk1,pk2,emph,demph,out)
(
  in *= preamp;
  in = emph.bqd(in);
//  in = 0.14*atan(10*in+offset);
  in = atan(color*spl0+offset) * icolor;
  in = demph.bqd(in);
  in = hp.bqd(in);
  in = lp.bqd(in);
  in = hs.bqd(in);
  in = ls.bqd(in);
  in = pk1.bqd(in);
  in = pk2.bqd(in);
);

rms0.rms_set(300);
rms1.rms_set(300);
rms2.rms_set(300);
rms3.rms_set(300);


@slider

preamp = 10^(slider1 * 0.05);
color = slider2;
icolor = 1/color;
offset = slider3;

slider4 ? r.seed = slider4 : r.seed = (rand()*2-1)*65000;
oversample = 2^(slider5);
osrate = oversample * srate;


ch0.channel_init();
ch1.channel_init();
ch2.channel_init();
ch3.channel_init();

@sample

rms0.rms(spl0);
rms1.rms(spl1);

oversample == 2 ? (

  s0.os_up2(spl0);
  s1.os_up2(spl1);
  
  s0.y1 = ch0.channel_process(s0.y1);
  s0.y0 = ch0.channel_process(s0.y0);
  s1.y1 = ch1.channel_process(s1.y1);
  s1.y0 = ch1.channel_process(s1.y0);

  spl0 = s0.os_down2();
  spl1 = s1.os_down2();
  
  ) : (
  
  spl0 = ch2.channel_process(spl0);
  spl1 = ch3.channel_process(spl1);
  
  );
  

rms2.rms(spl0);
rms3.rms(spl1);

spl0 *= rms0.val/rms2.val;
spl1 *= rms1.val/rms3.val;
SaulT is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 01:23 PM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2020, vBulletin Solutions Inc.