Old 01-13-2020, 06:58 PM   #1
Zeno
Human being with feelings
 
Zeno's Avatar
 
Join Date: Sep 2018
Location: Germany
Posts: 205
Default VU Meter Embedded UI: Need some HELP!

Hey guys, I need a little help here!
I'm completely overwhelmed with the @gfx part.
But there are some things I wanna change:

1. the size in the FX window

The width is optimal when desc and "Warn Level" are vertically lined up.




2. how is it possible to limit the size of the black background graphic in TCP?





3. the UI representation in the MCP is currently too small. It should be about the size of the 2nd picture.



Code:
//**************************************************************************************************
// Simple VU Meter - a fine freeware by chris-s
// V1.1; 10-Jan-2017
// Disclaimer: Use of this software is on your own risk

// Modified by Zeno
// V1.3; 14-Jan-2020
   - graphic appearance: color scheme adapted, more modern look
   - added simplified Embedded UI in MCP & TCP (added by CrashAlpha)
   - scale adjusted, fine tuning
   - added volume slider for gain adjustments
   - added hidden sliders for peak LEDs left/mid and right/side
   - added hidden sliders for vu meter readout left/mid and right/side
   

   Hidden sliders can be used as triggers for scripts and parameter modulation !!
   
   Ex: Modulate slider6 with slider50 to get a simple compressor. Use slider3 to set time constants. 

//*************************************** END INFO **************************************************



desc:VU Meter (ZenoMOD)
//tags: analysis analyzer vu meter
//author: chris-s , Zeno

// hidden sliders: remove the "-" in front of the name to activate

// Sliders                                // Name           // Visibility

slider1:-18<-20,0,0.5>                    Ref Level
slider2:-6<-20,0,0.1>                     Warn Level
slider3:50<0,100>                         -Response          // Hidden
slider4:0<0,2,1{Stereo,Mono,Mid/Side}>    Mode
slider5:0.0053<0,.01,0.0001>              -Damping           // Hidden
slider6:0<-12,12,0.1>                     Volume (dB)

slider50: -20<-20,0,3>                    -VU Left/Mid      // Hidden     
slider51: -20<-20,0,3>                    -VU Right/Side   // Hidden
slider52: 0<0,1>                          -Peak LED L        // Hidden
slider53: 0<0,1>                          -Peak LED R        // Hidden


  
// Hide side meters
options:no_meter

in_pin:left input
in_pin:right input
out_pin:left output
out_pin:right output

 
/***************************************** END DESC *****************/



@init

//========================================= VOLUME ==================/
AMP_dB_i=1/8.68588963806504;

db=slider6; // initialize here but not in @slider for playback start


//======================================== VU METER =================/
errcnt = 0;
tot_nbr_spl = 0;
scnt = 0;

fact_up = 0;

offset = 0.0074;

nd_posL = nd_posR = 0;
nd_speedL = nd_speedR = 0;

dt = 10 / srate;

mom = 0.00042;
damp = 1 - 0.0053 * (48000 / srate);

dbL = dbR = 0;
overL = overR = 0;


print = 10;
print[0] = -20;
print[1] = -10;
print[2] = -7;
print[3] = -5;
print[4] = -3;
print[5] = -2;
print[6] = -1;
print[7] = 0;
print[8] = 1;
print[9] = 2;
print[10] = 3;


pos = 30;
pos[0] = 0;
pos[1] = .1650;
pos[2] = .2641;
pos[3] = .3519;
pos[4] = .4626;
pos[5] = .5284;
pos[6] = .6022;
pos[7]  = .6849;
pos[8]  = .7779;
pos[9] = .8822;
pos[10] = 1;

/**************************************** END @INIT *****************/



@slider

//======================================== VOLUME ===================/
ddb=0.0;


//======================================== VU METER =================/
fact_up = 10 ^ (( -slider1 - 10)/20) * 0.3785 ;

wl   = slider2;
mode = slider4;
lim = 10 ^ (wl / 20);

mom = 0.00010 + 0.00032 *  slider3^3 / 125000;   

damp = 1 - slider5 * (48000 / srate);

/**************************************** END @SLIDER ***************/



@block

//========================================= VOLUME ==================/
cnt=0;
ddb=0.0;

db_chg_splpos=slider_next_chg(1, tgtdb);
db_chg_splpos > 0 ? 
(
  db=slider6;
) : (
  tgtdb = slider6;
  db_chg_splpos = samplesblock;
);

ddb=(tgtdb-db)/db_chg_splpos;

/**************************************** END @BLOCK ****************/



@sample

//========================================= VOLUME ==================/
cnt == db_chg_splpos ? (
  ddb=0.0;
  db_chg_splpos=slider_next_chg(1, tgtdb);
  db_chg_splpos > cnt ? (
    ddb=(tgtdb-db)/(db_chg_splpos-cnt);
  );
);


adj=exp(db*AMP_DB_i);

spl0 *= adj;
spl1 *= adj;

db += ddb;
cnt += 1;


//======================================== VU METER =================/
tot_nbr_spl += 1;

smpL = spl0; 
smpR = spl1;

mode == 1 ? ( 
  smpL = (spl0 + spl1) * 0.5;
  smpR = smpL;  
);

mode >= 2 ? ( 
  smpL = (spl0 + spl1) * 0.5;
  smpR = (spl0 - spl1) * 0.5;  
);

smpL = abs(smpL);
smpR = abs(smpR);

scnt += 1;

scnt === 10 ? (
    
    // move left needle
  
    force = smpL * fact_up  -  (nd_posL * .1 + offset);
    
    nd_speedL += force * dt / mom;  
    nd_speedL = nd_speedL * damp;
    nd_posL += nd_speedL * dt;
    nd_posL < 0 || nd_posL > 1 ? nd_speedL = 0;
  
    nd_posL = min(max(nd_posL,0),1);
  
    // move right needle

    force = smpR * fact_up  - (nd_posR * .1 + offset);
    
    nd_speedR += force * dt / mom;  
    nd_speedR = nd_speedR * damp;
    nd_posR += nd_speedR * dt;
    nd_posR < 0 || nd_posR > 1 ? nd_speedR = 0;
  
    nd_posR = min(max(nd_posR,0),1);
     
    overL -= 10;
    overR -= 10;

    scnt = 0;  
);

tot_nbr_spl_g  = tot_nbr_spl;

overL_g = overL;
overR_g = overR;
nd_posL_g = nd_posL;
nd_posR_g = nd_posR;

tot_nbr_spl_g === tot_nbr_spl ? (
  dbL = (nd_posL_g * 23) - 20;
  dbR = (nd_posR_g * 23) - 20;
) : (
  errcnt += 1; // thread collision
);

smpL > lim ? overL = srate;
smpR > lim ? overR = srate;

slider50 = dbL;   
slider51 = dbR;   
slider52 = overL_g;
slider53 = overR_g;

/**************************************** END @SAMPLE ***************/



@gfx 480 236

// override drawing functions for graphical window scaling
gsc = min(gfx_w/480,gfx_h/236); igsc = 1.5/gsc;
gxo = max(0,  gfx_w/2 - gfx_h*480/236/2);

function gfx_lineto(x,y,aa) ( gfx_x*=gsc; gfx_y*=gsc; gfx_x+=gxo; 
	   gfx_lineto(x*gsc+gxo,y*gsc,aa); gfx_x-=gxo; gfx_x*=igsc; gfx_y*=igsc; );

function gfx_rectto(x,y)(gfx_x*=gsc; gfx_y*=gsc; gfx_x+=gxo; gsc>.5 ? 
	   gfx_rectto(x*gsc+gxo,y*gsc); gfx_x-=gxo;  gfx_x*=igsc; gfx_y*=igsc; );

function gfx_drawnumber(y,x) (
	gsc>.5 ? (
		gsc<.7 && x>1 ? x=1;
		gfx_x*=gsc; gfx_y*=gsc; gfx_x+=gxo; gfx_drawnumber(y,x); gfx_x-=gxo;  gfx_x*=igsc; gfx_y*=igsc; 
	);
);

function gfx_drawchar(x) (gsc>.5 ? gfx_drawchar(x););
function gfx_drawstr(x) (gsc>.5 ? gfx_drawstr(x););
function gfx_printf(x,y) ( gsc>.5 ? gfx_printf(x,y); );
function gfx_arc(x, y, r, a1, a2, aa) (gsc>.5 ? gfx_arc(x, y, r, a1, a2, aa) : gfx_arc(x, y, r, a1, a2, 0); );



// paint gfx 
fontinit != 1 ? (
  gfx_setfont(1, "Arial", 14, '');
  gfx_setfont(2, "Arial", 20, 'b');

  fontinit = 1;
);

gfx_a = 1;

w1 = $pi * 16.5 / 180; 
w2 = $pi * 45 / 180;

xw = max(1,floor((gfx_w-30) / 2));
yw = floor(xw / 1.5);

r1 = floor(yw * 0.85);

chan = 0;

while (chan <= 1) (
  xd = 10 + chan*(xw+10);
  mode === 1 ? xd += floor(xw/2);
  
  yd = 10;

  xa = floor(xd + xw / 2);
  ya = floor(yd + yw * 1.1);

  // meter backgr   
  gfx_r=0;gfx_g=1;gfx_b=.9;  
  gfx_rect(xd,yd,xw,yw);
     
  // scale   
  gfx_r=gfx_g=gfx_b = 0; // black 
  gfx_arc(xa, ya, r1, -45 * ($pi / 180), w2, 1);

  gfx_r=.95; gfx_g=0; gfx_b = 0; // red 
  gfx_arc(xa, ya, r1 + 1, w1, w2, 1);
  gfx_arc(xa, ya, r1 + 2, w1, w2, 1);  
  gfx_arc(xa, ya, r1 + 3, w1, w2, 1);  
  gfx_arc(xa, ya, r1 + 4, w1, w2, 1);    
  
   
  gfx_setfont(1);
  
  gfx_r=gfx_g=gfx_b = 0.2; // black 
  
  
  // Draw scale notches and values if scaling allows
  gsc >.5 ? (
  
	jj = 0;
	while ( jj <= 10 ) (
		ii = print[jj];
    
		ph =  pos[jj];
		ph = (45 + ph*90) * $pi / 180; 
    
		cosp = cos(ph) * r1;
		sinp = sin(ph) * r1;
    
		x1 = xa - cosp ;
		y1 = ya - sinp ;

		x2 = xa - cosp * 1.1;
		y2 = ya - sinp * 1.1;
		
		x3 = xa - cosp * 1.15;
		y3 = ya - sinp * 1.11;
		
		gfx_x = x1;
		gfx_y = y1; 
		gfx_lineto(x2, y2);
			
		gfx_x = x3 - 8;   
		gfx_y = y3 - gfx_texth;
		   
		gfx_printf("%3d", ii);
		   
		jj += 1;
		   
		jj == 8 ? ( gfx_r = 1; gfx_g = gfx_b = 0 );  
	); 
  );
  
  // Peak  
  gfx_r=gfx_g=gfx_b = 0.0; // black 
    
  gfx_x = xd + xw * .9 - 30;
  gfx_y = yd + yw * .9 - 10;
  gfx_drawstr("PEAK");
  
  // VU
  gfx_setfont(2); // large
  gfx_r=gfx_g=gfx_b = 0.0; // black 
  
  gfx_x = xa - 10;
  gfx_y = yd + yw * .6;
  gfx_drawstr("VU");
  
  
  // draw LEDs
  gfx_r = .95; gfx_g = gfx_b = 0.1; // red 
    
  (chan == 0 && overL_g > 0) || (chan == 1 && overR_g > 0)  ? (   
     gfx_circle(xd + xw*0.9 + 6, yd + yw * 0.9 - 4, 4, 1, 1);
  );
  
  
  // draw needle
  chan == 0 ? ph = dbL : ph = dbR;

  ph = 45 + (ph+20)/23*90; 
  ph = ph * ($pi / 180);
  
  cosp = cos(ph);
  sinp = sin(ph);
    
  x1 = xa - cosp * r1 * 0.15;
    y1 = ya - sinp * r1 * 0.15;
  
    x2 = xa - cosp * r1 * 1.1;
    y2 = ya - sinp * r1 * 1.1;
  
    gfx_r=gfx_g=gfx_b = 0; // black                   
  
    gfx_x = x1;
    gfx_y = y1; 
    gfx_lineto(x2, y2);

    // draw thick needle lines and shadows if scaling allows
    gsc >.5 ? (
	gfx_x = x1+1;
	gfx_y = y1;
	gfx_lineto(x2+1, y2);
  
	//needle shadow
	gfx_x = x1+4;
	gfx_y = y1; 
	gfx_lineto(x2+4, y2);
    );
    
    //needle circle
    gfx_circle(xa,ya,r1*0.16,1,0); 
    
    //channel labeling 
    gfx_r=gfx_g=gfx_b = 1; // white 
  
    gfx_x = xd;
    gfx_y = yd+yw+2;
    
    chan == 0 ?
	gfx_drawstr("LEFT / MID") :
	gfx_drawstr("RIGHT / SIDE") ;
  
    chan += 1;
    
    mode === 1 ? chan += 1;
  );
  
  
  
  /****************************** EOF *******************************/

Thanks

Last edited by Zeno; 01-14-2020 at 01:13 PM.
Zeno is offline   Reply With Quote
Old 01-14-2020, 08:56 AM   #2
Zeno
Human being with feelings
 
Zeno's Avatar
 
Join Date: Sep 2018
Location: Germany
Posts: 205
Default

And - I don't know if this is possible at all - but it would be perfect if the MCP always shows only the left/mid meter... regardless of what is set in the plugin.

Is there anyone who is skilled enough to help me with this and explain these things to me? I am willing to learn
Zeno is offline   Reply With Quote
Old 01-14-2020, 09:30 AM   #3
CrashAlpha
Human being with feelings
 
CrashAlpha's Avatar
 
Join Date: May 2010
Posts: 74
Default

So, I'm certainly no expert on this as I'm just getting into this but when I run your code I am not experiencing the cut-off problem below the meters that you are. I am running Reaper in Windows 10 - could this be a platform-dependent scaling issue and you may need to look more closely at the function overrides under @gfx (you have probably figured out @gfx 480 200 declares the starting window size).

Code:
@gfx 480 200

// override drawing functions for graphical window scaling
gsc = min(gfx_w/480,gfx_h/200); igsc = 1.0/gsc;
gxo = max(0,  gfx_w/2 - gfx_h*480/200/2);
function gfx_lineto(x,y,aa) ( gfx_x*=gsc; gfx_y*=gsc; gfx_x+=gxo; 
     gfx_lineto(x*gsc+gxo,y*gsc,aa); gfx_x-=gxo; gfx_x*=igsc; gfx_y*=igsc; );
function gfx_rectto(x,y)(gfx_x*=gsc; gfx_y*=gsc; gfx_x+=gxo; gsc>.5 ? 
     gfx_rectto(x*gsc+gxo,y*gsc); gfx_x-=gxo;  gfx_x*=igsc; gfx_y*=igsc;);
function gfx_drawnumber(y,x) (
  gsc>.5 ? (
    gsc<.7 && x>1 ? x=1;
    gfx_x*=gsc; gfx_y*=gsc; gfx_x+=gxo; 
    gfx_drawnumber(y,x); gfx_x-=gxo;  gfx_x*=igsc; gfx_y*=igsc; 
  );
);
function gfx_drawchar(x) (gsc>.5 ? gfx_drawchar(x););
function gfx_drawstr(x) (gsc>.5 ? gfx_drawstr(x););
function gfx_printf(x,y) ( gsc>.5 ? gfx_printf(x,y) );
function gfx_arc(x, y, r, a1, a2, aa) (gsc>.5 ? gfx_arc(x, y, r, a1, a2, aa) : gfx_arc(x, y, r, a1, a2, 0); );
I think we'd need to look at a JS that left-aligns slider text the way you want to figure out how that works, I don't see any options that allow for left alignment under @sliders.

Unfortunately I tried setting only ONE meter for the MCP embedded UI but the problem is that it still occupies only half the space of the reserved graphic window defined by @gfx 480 200, so you get one meter and then an empty black space where the right/side meter would be.

Perhaps someone with more gfx experience can help.
CrashAlpha is offline   Reply With Quote
Old 01-14-2020, 09:45 AM   #4
Zeno
Human being with feelings
 
Zeno's Avatar
 
Join Date: Sep 2018
Location: Germany
Posts: 205
Default

Quote:
Originally Posted by CrashAlpha View Post
So, I'm certainly no expert on this as I'm just getting into this but when I run your code I am not experiencing the cut-off problem below the meters that you are. I am running Reaper in Windows 10 - could this be a platform-dependent scaling issue and you may need to look more closely at the function overrides under @gfx (you have probably figured out @gfx 480 200 declares the starting window size).

I think we'd need to look at a JS that left-aligns slider text the way you want to figure out how that works, I don't see any options that allow for left alignment under @sliders.

Unfortunately I tried setting only ONE meter for the MCP embedded UI but the problem is that it still occupies only half the space of the reserved graphic window defined by @gfx 480 200, so you get one meter and then an empty black space where the right/side meter would be.

Perhaps someone with more gfx experience can help.
In this point I am less concerned with the text than with the size of the graphic. As I understand it, the sliders adapt to the size of the graphic. So I would have to resize the graphic so that the desc text "VU Meter (ZenoMOD)" is in line with the slider text "Warn Level" and "Volume (dB)". This way the graphic would have a good size in proportion.

The problem is, I have been playing around with the numbers under @gfx for a while. I changed "480 200" to "480 235" and this fixes the problem with the cut off edge. I thought if 235 is the height, then 480 must be responsible for the width. but if i change the number 480, nothing happens - absolutely nothing.
Of course i could resize the window to any size i want and then save the preset as default, but this misses the target a bit.

But big thanks for your help so far
Zeno is offline   Reply With Quote
Old 01-14-2020, 10:54 AM   #5
CrashAlpha
Human being with feelings
 
CrashAlpha's Avatar
 
Join Date: May 2010
Posts: 74
Default

Quote:
Originally Posted by Zeno View Post
I thought if 235 is the height, then 480 must be responsible for the width. but if i change the number 480, nothing happens - absolutely nothing.
I think that's to be expected. According to the documentation:
Quote:
The @gfx section gets executed around 30 times a second when the plug-ins GUI is open. You can do whatever processing you like in this (Typically using gfx_*()). Note that this code runs in a separate thread from the audio processing, so you may have both running simultaneously which could leave certain variables/RAM in an unpredictable state.

The @gfx section has two optional parameters, which can specify the desired width/height of the graphics area. Set either of these to 0 (or omit them) to specify that the code doesn't care what size it gets. Note that these are simply hints to request this size -- you may not always get the specified size. Your code in this section should use the gfx_w, gfx_h variables to actually determine drawing dimensions.
https://www.reaper.fm/sdk/js/js.php

Maybe try no parameters or 0 to see what automatic resizing does?
CrashAlpha is offline   Reply With Quote
Old 01-14-2020, 12:22 PM   #6
Zeno
Human being with feelings
 
Zeno's Avatar
 
Join Date: Sep 2018
Location: Germany
Posts: 205
Default

Quote:
Originally Posted by CrashAlpha View Post
Maybe try no parameters or 0 to see what automatic resizing does?
that makes it even worse
Zeno is offline   Reply With Quote
Old 01-14-2020, 05:25 PM   #7
CrashAlpha
Human being with feelings
 
CrashAlpha's Avatar
 
Join Date: May 2010
Posts: 74
Default

Quote:
Originally Posted by Zeno View Post
that makes it even worse
For strip embedding I think the most useful thing would be a single LED style VU Bar for the summed channel which is more easily scaled to fit.
CrashAlpha is offline   Reply With Quote
Old 01-14-2020, 07:10 PM   #8
Zeno
Human being with feelings
 
Zeno's Avatar
 
Join Date: Sep 2018
Location: Germany
Posts: 205
Default

Quote:
Originally Posted by CrashAlpha View Post
For strip embedding I think the most useful thing would be a single LED style VU Bar for the summed channel which is more easily scaled to fit.
Yes maybe, I don't know.
Right now I'm trying to figure out things like how Reaper knows what this refers to:
Code:
// draw LEDs
  gfx_r = .95; gfx_g = gfx_b = 0.1; // red
I mean, I know what it refers to because it says "// draw LEDs". But how does reaper know that? That's why I'm so overwhelmed here.
I have tried to assign variables to such lines to be able to work with them flexibly. But that was not successful.
I don't think I see the connection between these code lines in the gfx section. really frustrating
Zeno is offline   Reply With Quote
Old 01-14-2020, 08:44 PM   #9
CrashAlpha
Human being with feelings
 
CrashAlpha's Avatar
 
Join Date: May 2010
Posts: 74
Default

Quote:
Originally Posted by Zeno View Post
Yes maybe, I don't know.
Right now I'm trying to figure out things like how Reaper knows what this refers to:
Code:
// draw LEDs
  gfx_r = .95; gfx_g = gfx_b = 0.1; // red
I mean, I know what it refers to because it says "// draw LEDs". But how does reaper know that? That's why I'm so overwhelmed here.
I have tried to assign variables to such lines to be able to work with them flexibly. But that was not successful.
I don't think I see the connection between these code lines in the gfx section. really frustrating
It doesn't have anything to do with drawing LEDs, it sets the RGB (red green blue) balance of the next graphic operation. So, next line, rectangle, arc or text write will be using the RGB settings of the line above. The code to draw the LEDs is probably below that. Then, I'd expect code defining yellow and green LEDs with more drawing, I would guess gfx_rectto(x,y) or gfx_rect(x,y) to draw the individual LEDs if a rectangular bar type.

EDIT: just realized you may be referring to the signal clip (warn) LED of the VU, that will be a gfx_circle() not a rectangle.

Look it up here: https://www.reaper.fm/sdk/js/gfx.php#js_gfx

Last edited by CrashAlpha; 01-14-2020 at 08:47 PM. Reason: correcting LED explanation
CrashAlpha 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 09:51 PM.


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