Here's a super-quick conversion of the VU-meter script changed to use the new audio interface in JScript Panel 3.6.6.
// ==PREPROCESSOR==
// @name "JSP3 VU Meter"
// ==/PREPROCESSOR==
var timer_SetInterval = 30; //ms
var VUMeterFb2k = false; // true: foobar2000 VU Meter style; false: free style
var font,font_t = "";
var g_text = "";
var ww = 0, wh = 0;
var colours = {
text : 0,
background : 0,
highlight : 0,
}
var color_1;
var color_2;
var color = [];
var step = 20; // more is less space between bars (cpu powers consumed) and vice versa.
var minDB = -60; //dB as Foobar2000' s built - in VU Meter
var db = [];
var ColourTypeCUI = {
text: 0,
selection_text: 1,
inactive_selection_text: 2,
background: 3,
selection_background: 4,
inactive_selection_background: 5,
active_item_frame: 6
};
var ColourTypeDUI = {
text: 0,
background: 1,
highlight: 2,
selection: 3
};
var FontTypeCUI = {
items : 0,
labels : 1,
};
var FontTypeDUI = {
defaults : 0,
tabs : 1,
lists : 2,
playlists : 3,
statusbar : 4,
console : 5,
};
function update_colours() {
if (window.IsDefaultUI) {
colours.text = window.GetColourDUI(ColourTypeDUI.text);
colours.highlight = window.GetColourDUI(ColourTypeDUI.highlight);
colours.background = window.GetColourDUI(ColourTypeDUI.background);
} else {
colours.text = window.GetColourCUI(ColourTypeCUI.text);
colours.background = window.GetColourCUI(ColourTypeCUI.background);
colours.highlight = blendColours(colours.text, colours.background, 0.4);
}
//custom colours override
// colours.text = RGB(255,255,255);
// colours.highlight = RGB(0,0,250);
// colours.background = RGB(0,0,0);
color_1 = colours.text; // or any color RGB(250,250,250);
color_2 = colours.highlight; // or any color RGB(0,0,0);
color = [];
for (var i = 0; i <= step; i++) {
color.push(blendColours(color_1, color_2, (i / step)));
db.push((minDB / step) * (step - i))
}
}
function update_font() {
if (window.IsDefaultUI) {
font = window.GetFontDUI(FontTypeDUI.defaults);
} else {
font = window.GetFontCUI(FontTypeCUI.items);
}
// adjust size
font_t = font;
var obj = JSON.parse(font_t);
obj.Size -= 4;
font_t = JSON.stringify(obj);
}
update_colours();
update_font();
function on_colours_changed() {
update_colours();
window.Repaint();
}
function on_mouse_lbtn_up(x, y) {
window.ShowConfigure();
}
function on_size() {
ww = window.Width;
wh = window.Height;
}
//------------- just an implementation /////////////
function RGB(r,g,b) { return (0xff000000|(r<<16)|(g<<8)|(b)); }
function RGBA(r, g, b, a) { return ((a << 24) | (r << 16) | (g << 8) | (b)); }
function toRGB(col) {
var a = col - 0xFF000000;
return [a >> 16, a >> 8 & 0xFF, a & 0xFF];
}
function blendColours(c1, c2, factor) { //@Marc2003
var c1 = toRGB(c1);
var c2 = toRGB(c2);
var r = Math.round(c1[0] + factor * (c2[0] - c1[0]));
var g = Math.round(c1[1] + factor * (c2[1] - c1[1]));
var b = Math.round(c1[2] + factor * (c2[2] - c1[2]));
return (0xff000000 | (r << 16) | (g << 8) | (b));
}
function on_paint(gr) {
gr.FillRectangle(0, 0, ww, wh, colours.background);
//
LM = RMS_level1; // ~ VUMeter.LeftLevel;
RM = RMS_level2; // ~ VUMeter.RightLevel;
L = Peak_level1; // ~ VUMeter.LeftPeak;
R = Peak_level2; // ~ VUMeter.RightPeak;
var h = 20; // VUh_bar;
var VUh_bar = 20; //
var VU_x = 20; //VUx;
var VUy = 5;
var VUh_off = h + 5;
var VUw = ww - 20;
var yL = (VUy + h);
var yLM = (VUy + h) + VUh_bar;
var yRM = (VUy + h) + VUh_bar + VUh_off;
var yR = (VUy + h) + VUh_bar + VUh_off + VUh_bar;
var dbLM = PctToDB(LM),
dbRM = PctToDB(RM),
dbL = PctToDB(L),
dbR = PctToDB(R);
if (VUMeterFb2k) {// foobar2000 VUMeter style
if (!(dbLM == 0 || dbLM == -Infinity)) {
// 65 : -60db- 0dB (+ 5dB offset at the end beyond 0dB ) scale
var wLM = Math.round(ww * ((100 + Number(dbLM)) / 65 - 40 / 65));
var wRM = Math.round(ww * ((100 + Number(dbRM)) / 65 - 40 / 65));
var wL = Math.round(ww * ((100 + Number(dbL)) / 65 - 40 / 65));
var wR = Math.round(ww * ((100 + Number(dbR)) / 65 - 40 / 65));
FillGradientRectangle(gr, VU_x, yLM, wLM, h - 1, 1, colours.text, colours.highlight);
FillGradientRectangle(gr, VU_x, yRM, wRM, h - 1, 1, colours.text, colours.highlight);
FillGradientRectangle(gr, VU_x, yL, wL, h - 1, 1, colours.text, colours.highlight);
FillGradientRectangle(gr, VU_x, yR, wR, h - 1, 1, colours.text, colours.highlight);
}
} else { // free style
h = 15;
var offset = Math.floor((VUw - VU_x) / (step + 1)); //step+1 : number of bars and we need 1 more bar at the end
var w = Math.floor((VUw - VU_x) / (step + 4)); // step+4 : width bar. we need some spaces between bars.
for (var i = 0; i <= step; i++) {
if (i > 0) {
dbLM = PctToDB(LM),
dbRM = PctToDB(RM),
dbL = PctToDB(L),
dbR = PctToDB(R);
}
gr.FillRectangle(VU_x + i * offset, yLM, w, h, dbLM >= db[i] ? color[i] : RGBA(0, 0, 0, 0));
gr.FillRectangle(VU_x + i * offset, yRM, w, h, dbRM >= db[i] ? color[i] : RGBA(0, 0, 0, 0));
if ((dbL > db[i] && dbL < db[i + 1])) {
var wL = i * offset + offset / Math.abs(db[i + 1] - db[i]) * Math.abs(dbL - db[i]);
gr.FillRectangle(VU_x, yL, wL, h, color[i]);
}
if ((dbR > db[i] && dbR < db[i + 1])) {
var wR = i * offset + offset / Math.abs(db[i + 1] - db[i]) * Math.abs(dbR - db[i]);
gr.FillRectangle(VU_x, yR, wR, h, color[i]);
}
}
}
// X-,Y-axis
for (var i = (65 - 5) / 5, j = 0; i >= 0; i--, j++)
gr.WriteText("-" + 5 * i + "dB", font_t, colours.text, VU_x / 2 + j * (ww - VU_x) / 13, yR + h + 10, ww, wh);
gr.WriteText("FL", font_t, colours.text, 0, yLM, ww, wh);
gr.WriteText("FL", font_t, colours.text, 0, yL, ww, wh);
gr.WriteText("FR", font_t, colours.text, 0, yRM, ww, wh);
gr.WriteText("FR", font_t, colours.text, 0, yR, ww, wh);
FillGradientRectangle(gr, VU_x, yR + h + 5, ww, 1, 1, colours.text, colours.highlight);
}
function clear_meter() {
RMS_level1 = 0;
RMS_level2 = 0;
Peak_level1 = 0;
Peak_level2 = 0;
prev_time = 0;
window.Repaint();
}
function on_playback_new_track(handler) {
VUMeter();
}
function on_playback_stop(reason) {
if (reason != 2) { // not starting another track
offVUMeterTimer();
clear_meter();
}
}
function on_playback_pause(state) {
state ? offVUMeterTimer() : onVUMeterTimer();
}
var RMS_level1 = RMS_level2 = Peak_level1 = Peak_level2 = 0; // RMS and Peak level of each 2 channels.
var timer_SetInterval_id = null;
var prev_time = 0;
function on_script_unload() {
}
function PctToDB(num) {
// input : num [0-1]
// output: dB [-100,0]
return ((2000 * Math.log(num) / Math.LN10) / 100).toFixed(2);
}
function onVUMeterTimer() {
if (!fb.IsPlaying || fb.IsPaused) return;
if (timer_SetInterval_id === null) {
timer_SetInterval_id = window.SetInterval(function() {
if (fb.PlaybackTime) {
var cur_time = fb.PlaybackTime;
var chunk = fb.GetAudioChunk(cur_time - prev_time);
if (chunk) {
prev_time = cur_time;
var data = chunk.Data.toArray();
if (data) {
var ch_count = chunk.ChannelCount;
var frame_len = chunk.SampleCount;
var ch2_idx = 1;
if (ch_count < 2) ch2_idx = 0;
var sum1 = 0;
var sum2 = 0;
var peak1 = 0;
var peak2 = 0;
for (var i = 0; i < data.length; i += ch_count) {
var l = data[i];
var r = data[i + ch2_idx];
if (l > peak1) peak1 = l;
if (r > peak2) peak2 = r;
sum1 += l * l;
sum2 += r * r;
}
RMS_level1 = Math.sqrt(sum1/frame_len);
RMS_level2 = Math.sqrt(sum2/frame_len);
Peak_level1 = peak1;
Peak_level2 = peak2;
}
}
}
//(window.RepaintRect(x, y, w, h);
window.Repaint();
}, timer_SetInterval);
}
}
function offVUMeterTimer() {
if (timer_SetInterval_id) window.ClearInterval(timer_SetInterval_id);
timer_SetInterval_id = null;
}
onVUMeterTimer();
function VUMeter() {
offVUMeterTimer(); //turn off timer
var handle = fb.IsPlaying ? fb.GetNowPlaying() : false;
if (!handle) return;
// set VUMeter timer tiktok
onVUMeterTimer();
}
function FillGradientRectangle(gr, x, y, w, h, direction, colour1, colour2) { //@Marc2003
var stops = [[0, colour1], [1, colour2]];
var brush = {
Start: [0, 0],
Stops: stops
};
if (direction == 0)
brush.End = [0, h];
else
brush.End = [w, 0];
gr.FillRectangle(x, y, w, h, JSON.stringify(brush));
}
//EOF
Edit: tiny bit cleaned up version.