Old 08-01-2010, 03:59 AM   #1
Analogy
Human being with feelings
 
Join Date: Sep 2009
Posts: 871
Default Prototype strobe tuner

Code:
desc:strobe tuner

slider1:0<0,11,{A,A#,B,C,C#,D,D#,E,F,F#,G,G#}>Note

@init
bufpos=0;
phase=0;

@slider
frequency=55*2^(slider1/12);
samplespercycle=srate/frequency;

@sample
spl0=spl0;
spl1=spl1;
bufpos[0]=abs(spl0);
bufpos+=1;

@gfx 0 0
bufsize=bufpos;
bufpos=0;
gfx_mode=1;
gfx_r=1;
gfx_g=1;
gfx_b=1;

loopid=0;
loop(bufsize,
gfx_a=loopid[0];

gfx_x=gfx_w*phase;
gfx_y=0;
gfx_lineto(gfx_x,gfx_h,0);

loopid+=1;
(phase+=1/samplespercycle)>1 ? phase-=1;
);
That's right, it's a strobe tuner written in JS using @gfx. Surprisingly low CPU usage, considering the method.

Any suggestions/patches are appreciated.

Last edited by Analogy; 08-01-2010 at 04:31 AM.
Analogy is offline   Reply With Quote
Old 08-02-2010, 12:44 AM   #2
jamieskeen
Human being with feelings
 
Join Date: Dec 2006
Location: Charleston, WV
Posts: 742
Default

wow, looks promising. gonna check it out
jamieskeen is offline   Reply With Quote
Old 08-02-2010, 02:13 AM   #3
Analogy
Human being with feelings
 
Join Date: Sep 2009
Posts: 871
Default

BTW, since this is working by drawing vertical lines, you can reduce CPU usage by making the window shorter. A taller window makes the lines it has to draw longer, eating more CPU. A wider window doesn't seem to have any effect.

The improvements I'm working on right now are about improving the visuals - eliminating the flickering and vertical banding. I might also copy some code over from Meters/Tuner to autodetect the basic note.
Analogy is offline   Reply With Quote
Old 08-02-2010, 05:20 AM   #4
Analogy
Human being with feelings
 
Join Date: Sep 2009
Posts: 871
Default

Code:
desc:strobe tuner

slider1:0<0,11,{A,A#,B,C,C#,D,D#,E,F,F#,G,G#}>Note

@init
phase=1;
lastphase=1;
writebuf=0;
readbuf=1;
writebufsize=0;
readbufsize=0;
lastx=0;
coordinatelist=0;
coordinatelist[0]=0;
coordinatelist[1]=0;
coordinatelist[3]=1;
coordinatelist[4]=0;
coordinatelist[5]=1;
gfx_r=0;
gfx_g=0;
gfx_b=0;
gfx_a=1;
gfx_x=gfx_w;
gfx_y=0;
mutex=0;

@slider
frequency=55*2^(slider1/12);
samplespercycle=srate/frequency;

@sample
spl0=spl0;
spl1=spl1;
while(mutex;);
mutex=1;
writebufsize[writebuf+10]=abs(spl0);
writebufsize+=2;
mutex=0;

@gfx 0 0

//Reduce flickering by double buffering
while(mutex;);
mutex=1;
readbufsize=writebufsize;
writebuf=readbuf;
writebufsize=0;
mutex=0;
readbuf=(readbuf!=1);
readbufsize/=2;
gfx_mode=1;
gfx_x=gfx_w*phase;
loopid=0;

//Reduce flickering by only painting
//the display a whole number of times
stopdrawing=floor(readbufsize/samplespercycle)*samplespercycle*2;

loop(readbufsize,

loopid<stopdrawing ? (

//Keep display same brightness regardless of screen width
gfx_r=loopid[readbuf+10]*gfx_w/500;
gfx_b=gfx_g=gfx_r;

//Trying to reduce vertical banding.
//Why doesn't this work?
lastphase>phase ? (
gfx_lineto(gfx_w*phase,0,1);
):(
gfx_lineto(0,0,0);
gfx_x=gfx_w;
gfx_lineto(gfx_w*phase,0,0);
);

);

loopid+=2;

lastphase=phase;
(phase-=1/samplespercycle)<0 ? phase+=1;
);

coordinatelist[2]=gfx_w;
coordinatelist[6]=gfx_w;
coordinatelist[7]=gfx_h-1;

//We draw a single line of pixels and
//stretch it to fill the entire display
gfx_blitext(-1,0,0);
CPU usage is much lower now, regardless of screen size. I'm generating the display by drawing only one row of pixels and using gfx_blitext to fill the rest of the screen. Much faster!

I've introduced double buffering and vsync type techniques to reduce flickering. I've attempted to reduce vertical banding but it's not working. =/ If someone could take a look at that and figure out what I'm doing wrong I'd be obliged. I have a feeling it's a fencepost error.

There is the occasional white flash that I'd like to get rid of. I thought that it was maybe a contention issue between audio and gfx threads so I added a mutex... Didn't work. =/ Another thing I'd like a fresh set of eyes to look at.

Last edited by Analogy; 08-02-2010 at 05:36 AM.
Analogy is offline   Reply With Quote
Old 12-15-2013, 01:25 AM   #5
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 217
Default

Very nice, Analogy!

I made a 12-band version that displays all 12 notes at once. I modeled it after your first one because A) the flickering doesn't bother me and B) it's simpler and I'm lazy.

I added a calibration slider. I also inverted samplespercycle so that the main loop doesn't have as much dividing.

I wanted to add a way to display different bands for higher octaves like a mechanical strobe tuner does. But I couldn't figure out how to.

Code:
desc: chromatic strobe tuner

slider1: 440<430,450,1>calibration frequency

@init
bufpos=0;
gfx_mode=1;
gfx_r=gfx_g=gfx_b=1;
Frequency=0;		// array of 12 frequencies / srate
Phase=12;		// array of 12 phases
memset(Phase,0,12);
Wave=24;		// big array of spl values

@slider
i=0;
loop(12,
  Frequency[i]=(slider1/4)*2^((i+3)/12)/srate;
  i+=1;
);

@sample
Wave[bufpos]=abs(spl0);
bufpos+=1;

@gfx 600 400
bufsize=bufpos;
bufpos=0;
gfx_a=1;
gfx_y=4;
gfx_x=1*gfx_w/24-4;  gfx_drawchar($'C');
gfx_x=5*gfx_w/24-4;  gfx_drawchar($'D');
gfx_x=9*gfx_w/24-4;  gfx_drawchar($'E');
gfx_x=11*gfx_w/24-4; gfx_drawchar($'F');
gfx_x=15*gfx_w/24-4; gfx_drawchar($'G');
gfx_x=19*gfx_w/24-4; gfx_drawchar($'A');
gfx_x=23*gfx_w/24-4; gfx_drawchar($'B');

n=0;
loop(12,
  (7*n+1)%12<7 ? gfx_b=1 : gfx_b=0.7;	// black keys are yellowish
  p=0;
  loop(bufsize,
    gfx_a=Wave[p];
    gfx_x=n*gfx_w/12;
    gfx_y=gfx_h*Phase[n];
    gfx_lineto(gfx_x+gfx_w/12-5,gfx_y,0);
    Phase[n]+=Frequency[n];
    Phase[n]>1 ? Phase[n]-=1;
    p+=1;
  );
  n+=1;
);
Kite is offline   Reply With Quote
Old 12-11-2017, 08:12 PM   #6
CodeLurker
Human being with feelings
 
Join Date: Dec 2012
Posts: 16
Default Epic!

This is awesome! The 12-band one works great. Just the thing I need for alternative guitar tunings, and very accurate tuning in the first place. I don't even have to wait for the needle to quit jumping around.

I opened this and ReaTune in a floating window. I love that I can set the A pitch to greater accuracy than three significant digits.

Last edited by CodeLurker; 12-11-2017 at 08:21 PM.
CodeLurker is offline   Reply With Quote
Old 12-15-2017, 10:24 AM   #7
jcjr
Human being with feelings
 
Join Date: Dec 2015
Location: SE TN USA
Posts: 77
Default

Quote:
Originally Posted by Analogy View Post
I've introduced double buffering and vsync type techniques to reduce flickering. I've attempted to reduce vertical banding but it's not working. =/ If someone could take a look at that and figure out what I'm doing wrong I'd be obliged. I have a feeling it's a fencepost error.

There is the occasional white flash that I'd like to get rid of. I thought that it was maybe a contention issue between audio and gfx threads so I added a mutex... Didn't work. =/ Another thing I'd like a fresh set of eyes to look at.
Congrats! Haven't looked at the code. For many years once in awhile I'd try to think up efficient strobe tuner code and would eventually quit in total confusion. The actual mechanical device is so simple, but seems somehow subtle to translate into code.

On the graphics flashing-- Maybe you already have this in your code, apologies not reading it-- My only jsfx graphics experience is a couple of "fairly fancy" meter sets in a compressor jsfx and a limiter jsfx.

The meter code draws several things on-top of each other. It does some picture region blitting and some line-drawing.

However, on entry to @gfx, I set the jsfx graphics output destination to an offscreen bitmap. I do all the drawing to that offscreen bitmap. Only at the final exit lines of @gfx do I set the graphics output dest to the screen and finally blit the completed offscreen bitmap to the "real screen". I haven't caught the meters flickering, but maybe in some situations they would flicker.

But you say you are double-buffering, so maybe yer already doing that-- Thats what I had thought was the definition of gui double-buffering back in the day-- Draw everything offscreen then just blit the final result to screen.
jcjr is offline   Reply With Quote
Old 12-15-2017, 01:42 PM   #8
CodeLurker
Human being with feelings
 
Join Date: Dec 2012
Posts: 16
Default

Since he's (she's?) posted his code here, it's not like he's trying to keep others from modifying it. I'd say, if you know how to blit plugin graphics like that, feel free to modify his plugin to do it. I notice there's a little flashiness even when tuning a pure sine wave with it. OTOH, it is nothing that prevents me from using it.
CodeLurker is offline   Reply With Quote
Old 12-15-2017, 05:22 PM   #9
jcjr
Human being with feelings
 
Join Date: Dec 2015
Location: SE TN USA
Posts: 77
Default

Quote:
Originally Posted by CodeLurker View Post
Since he's (she's?) posted his code here, it's not like he's trying to keep others from modifying it. I'd say, if you know how to blit plugin graphics like that, feel free to modify his plugin to do it. I notice there's a little flashiness even when tuning a pure sine wave with it. OTOH, it is nothing that prevents me from using it.
Sorry I really was trying to be helpful without getting real involved with it. Lately I'm lucky to get two brain cells to spark together. The OP asked a question which I attempted to (at least partially) answer.

I suppose an empty offscreen bitmap could be created but I would have to go study jsfx docs because I never learned how yet. In my meter code I load several bitmaps from png files and use one of those as my offscreen bitmap, so I didn't have to learn how to make an offscreen bitmap from scratch, though am wildly guessing it is probably possible.

gx_TmpLoadResult = gfx_loadimg(0, 0);

I "superstitiously" decorate vars for "where they were declared" in attempt to keep myself out of trouble possibly accidentally having two or more same-name vars kicking around in jsfx, declared at different sections. So if the var had been declared in @init it would have been named g_TmpLoadResult and if declared in @block named b_TmpLoadResult and if declared in @sample would have been named s_TmpLoadResult.

Also I surround my gfx_loadimg() calls with lots of error checking which is perhaps silly, trying to prevent the plugin from trying to draw if for whatever reason the images can't be found or loaded.

Anyway, sans error checking paranoia, first there are several loadimg calls for various little pictures. I keep variables so that when a load succeeds, it remembers and doesn't keep redundantly loading the same image file over and over every time it hits that part at the beginning of the @gfx code.
gx_TmpLoadResult = gfx_loadimg(1, 1);
gx_TmpLoadResult = gfx_loadimg(2, 2);

So here is the line that directs all blitting and line drawing to that first background picture bitmap I loaded in. I call it right after the above lines which load the images if they need loading.

(gx_DoTheGFX > 0) ? //only do graphics if pics are loaded
(
//gfx_blit(source image, scale, rotation, srcx, srcy, srcw, srch, destx, desty, destw, desth, rotxoffs, rotyoffs)
gfx_dest = 0; //set drawing dest to the background meter picture
gfx_blit(1, 1.0, 0.0, 0, 0, 535, 26, 93, 50, 535, 26, 0, 0); //offscreen blit INPUT meter background, as if all LED's are turned off
gfx_blit(1, 1.0, 0.0, 0, 0, 535, 26, 93, 112, 535, 26, 0, 0); //offscreen blit OUTPUT meter background
gfx_blit(1, 1.0, 0.0, 0, 26, 535, 26, 93, 174, 535, 26, 0, 0); //offscreen blit GAIN meter background
gfx_blit(1, 1.0, 0.0, 0, 104, 535, 26, 93, 236, 535, 26, 0, 0); //offscreen blit Auto-Release meter background

That gfx_dest = 0 is the line that tells jsfx to draw lines and to blit into the bitmap created when I loaded image 0. Then there are a few sample lines blitting parts of background into that offscreen bitmap, and it goes on awhile blitting various little pieces of bitmap and drawing little line segments.

Then after it has drawn all the little pieces of the meters into bitmap 0, these are the last two lines in @gfx--

gfx_dest = -1; //set drawing target to the plugin window
gfx_blit(0, 1.0, 0.0, 0, 0, 664, 290, 0, 0, gfx_w, gfx_h, 0, 0); //blit the updated offscreen meter image

-1 is the destination number for the screen. We just change the dest to the screen, then one blit to blast the finished composite image of the meters to the visible plugin window.
jcjr is offline   Reply With Quote
Old 12-21-2017, 09:12 PM   #10
hopi
Human being with feelings
 
hopi's Avatar
 
Join Date: Oct 2008
Location: Right Hear
Posts: 15,618
Default

Quote:
Originally Posted by Kite View Post
Very nice, Analogy!

I made a 12-band version that displays all 12 notes at once. I modeled it after your first one because A) the flickering doesn't bother me and B) it's simpler and I'm lazy.

I added a calibration slider. I also inverted samplespercycle so that the main loop doesn't have as much dividing.

I wanted to add a way to display different bands for higher octaves like a mechanical strobe tuner does. But I couldn't figure out how to.

Code:
desc: chromatic strobe tuner

slider1: 440<430,450,1>calibration frequency

@init
bufpos=0;
gfx_mode=1;
gfx_r=gfx_g=gfx_b=1;
Frequency=0;        // array of 12 frequencies / srate
Phase=12;        // array of 12 phases
memset(Phase,0,12);
Wave=24;        // big array of spl values

@slider
i=0;
loop(12,
  Frequency[i]=(slider1/4)*2^((i+3)/12)/srate;
  i+=1;
);

@sample
Wave[bufpos]=abs(spl0);
bufpos+=1;

@gfx 600 400
bufsize=bufpos;
bufpos=0;
gfx_a=1;
gfx_y=4;
gfx_x=1*gfx_w/24-4;  gfx_drawchar($'C');
gfx_x=5*gfx_w/24-4;  gfx_drawchar($'D');
gfx_x=9*gfx_w/24-4;  gfx_drawchar($'E');
gfx_x=11*gfx_w/24-4; gfx_drawchar($'F');
gfx_x=15*gfx_w/24-4; gfx_drawchar($'G');
gfx_x=19*gfx_w/24-4; gfx_drawchar($'A');
gfx_x=23*gfx_w/24-4; gfx_drawchar($'B');

n=0;
loop(12,
  (7*n+1)%12<7 ? gfx_b=1 : gfx_b=0.7;    // black keys are yellowish
  p=0;
  loop(bufsize,
    gfx_a=Wave[p];
    gfx_x=n*gfx_w/12;
    gfx_y=gfx_h*Phase[n];
    gfx_lineto(gfx_x+gfx_w/12-5,gfx_y,0);
    Phase[n]+=Frequency[n];
    Phase[n]>1 ? Phase[n]-=1;
    p+=1;
  );
  n+=1;
);
this one is pretty nice... but a few thoughts

It seems to need a fairly hi volume of input ... lower levels don't show up well or if low enough don't show up at all...

Now this gets worse if you resize the GUI to quite large

I don't know beans about JSFX code so maybe there is nothing to do about it...
__________________
...should be fixed for the next build... http://tinyurl.com/cr7o7yl
https://soundcloud.com/hopikiva
hopi 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 12:57 AM.


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