@mfcc64/ytms 15.1.0 → 17.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/script.mjs +302 -122
package/package.json
CHANGED
package/script.mjs
CHANGED
|
@@ -42,11 +42,16 @@ import {ShowCQTElement} from "../../showcqt-element@2/showcqt-element.mjs";
|
|
|
42
42
|
left_color: { def:0xdcb900, min:0, max:0xffffff },
|
|
43
43
|
right_color:{ def:0x00b9dc, min:0, max:0xffffff },
|
|
44
44
|
mid_color: { def:0xdcdcdc, min:0, max:0xffffff },
|
|
45
|
+
saturation: { def: 0, min: 0, max: 30 },
|
|
46
|
+
hue: { def: 0, min:-18, max: 19 },
|
|
47
|
+
hue_range: { def: 18, min:-36, max: 36 },
|
|
45
48
|
interval: { def: 1, min: 1, max: 4 },
|
|
46
49
|
bar_scale: { def: 0, min: 0, max: 4 },
|
|
47
50
|
line_mode: { def: 0, min: 0, max: 4 },
|
|
48
51
|
line_width: { def: 1, min: 1, max: 3 },
|
|
49
52
|
line_color: { def:0xffffff, min:0, max:0xffffff },
|
|
53
|
+
scroll: { def: 0, min: 0, max: 1 },
|
|
54
|
+
coord_color:{ def:0x000000, min:0, max:0xffffff },
|
|
50
55
|
transparent:{ def: 1, min: 0, max: 1 },
|
|
51
56
|
visible: { def: document.location.hostname != "www.youtube.com" ? 1 : 0,
|
|
52
57
|
min: 0, max: 1 },
|
|
@@ -94,7 +99,7 @@ import {ShowCQTElement} from "../../showcqt-element@2/showcqt-element.mjs";
|
|
|
94
99
|
af_links.style.color = "#FFFFFF";
|
|
95
100
|
af_links.style.fontSize = "10pt";
|
|
96
101
|
af_links.style.right = "8px";
|
|
97
|
-
af_links.style.bottom = "8px";
|
|
102
|
+
af_links.style.bottom = "calc(var(--ytms-cqt-bottom, 0px) + 8px)";
|
|
98
103
|
af_links.style.opacity = 1;
|
|
99
104
|
{
|
|
100
105
|
const e = (name, ...args) => {
|
|
@@ -114,14 +119,14 @@ import {ShowCQTElement} from "../../showcqt-element@2/showcqt-element.mjs";
|
|
|
114
119
|
e("div", {id: "message"},
|
|
115
120
|
e("h3", "YouTube Musical Spectrum"),
|
|
116
121
|
e("ul",
|
|
117
|
-
e("li", "By default, the visualization is visible on YT Music
|
|
122
|
+
e("li", "By default, the visualization is visible on YT Music, Spotify, and SoundCloud but hidden on YouTube page."),
|
|
118
123
|
e("li", "Press ", e("b", "Ctrl+Alt+G"), " as a shortcut to show/hide visualization. This is equivalent to check/uncheck ", e("b", "Visible"), " setting."),
|
|
119
124
|
e("li", "Click the ", e("img", {alt: "YTMS"}, {src: icon_16}), " icon at the top left corner to open/close settings."),
|
|
120
125
|
e("li", "Press ", e("b", "Ctrl+Alt+H"), " to open/close settings and show/hide the ", e("img", {alt: "YTMS"}, {src: icon_16}), " icon."),
|
|
121
126
|
e("li", "If you want to change the axis, click it."),
|
|
122
127
|
e("li", "If you want to make your change persistent, click ", e("b", "Set as Default Settings"), " button."),
|
|
123
128
|
e("li", e("b", "New Features:"), " Custom color, custom range," +
|
|
124
|
-
" peak color, bar scale, presets, line
|
|
129
|
+
" peak color, bar scale, line visualizer, hue rotation, more color presets, horizontal scroll, coordinate line."),
|
|
125
130
|
e("li", e("a", {href: "https://github.com/mfcc64/youtube-musical-spectrum#settings"}, {target: "_blank"}, "Read more..."))
|
|
126
131
|
),
|
|
127
132
|
e("p",
|
|
@@ -133,7 +138,6 @@ import {ShowCQTElement} from "../../showcqt-element@2/showcqt-element.mjs";
|
|
|
133
138
|
e("img", {alt: "YTMS"}, {src: icon_16}, {style: "curson: pointer;"}, {id: "open_message"}),
|
|
134
139
|
" Support me on ",
|
|
135
140
|
e("a", {href: "https://www.youtube.com/@mfcc64"}, {target: "_blank"}, "Youtube"), " ",
|
|
136
|
-
e("a", {href: "https://www.patreon.com/mfcc64"}, {target: "_blank"}, "Patreon"), " ",
|
|
137
141
|
e("a", {href: "https://github.com/mfcc64"}, {target: "_blank"}, "GitHub"), " ",
|
|
138
142
|
e("a", {href: "https://paypal.me/mfcc64"}, {target: "_blank"}, "PayPal"), " ",
|
|
139
143
|
e("a", {href: "https://saweria.co/mfcc64"}, {target: "_blank"}, "Saweria")
|
|
@@ -152,7 +156,7 @@ import {ShowCQTElement} from "../../showcqt-element@2/showcqt-element.mjs";
|
|
|
152
156
|
af_links.style.display = !af_links_timeout || (child_menu.visible?.checked ?? true) ? "block" : "none";
|
|
153
157
|
}
|
|
154
158
|
|
|
155
|
-
const message_version =
|
|
159
|
+
const message_version = 13;
|
|
156
160
|
af_links.shadowRoot.getElementById("message").style.display = get_opt("message_version") == message_version ? "none" : "block";
|
|
157
161
|
af_links.shadowRoot.getElementById("close_message").addEventListener("click", function() {
|
|
158
162
|
set_opt("message_version", message_version);
|
|
@@ -162,20 +166,36 @@ import {ShowCQTElement} from "../../showcqt-element@2/showcqt-element.mjs";
|
|
|
162
166
|
af_links.shadowRoot.getElementById("message").style.display = "block";
|
|
163
167
|
});
|
|
164
168
|
|
|
169
|
+
const media_symbol = Symbol("media_symbol");
|
|
170
|
+
let svideos = [];
|
|
171
|
+
if (document.location.hostname == "soundcloud.com") {
|
|
172
|
+
await new Promise((res, rej) => {
|
|
173
|
+
const old = AudioContext.prototype.createMediaElementSource;
|
|
174
|
+
AudioContext.prototype.createMediaElementSource = function(media) {
|
|
175
|
+
const retval = old.call(this, media);
|
|
176
|
+
ShowCQTElement.global_audio_context = this;
|
|
177
|
+
svideos.push(media);
|
|
178
|
+
media[media_symbol] = retval;
|
|
179
|
+
res();
|
|
180
|
+
return retval;
|
|
181
|
+
};
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
165
185
|
const cqt = new ShowCQTElement();
|
|
166
186
|
set_fixed_style(cqt, 9999999);
|
|
167
|
-
cqt.style.left = cqt.style.bottom = 0;
|
|
168
|
-
cqt.style.width = "100%";
|
|
169
187
|
let stop_count = 0;
|
|
170
188
|
const videos = document.getElementsByTagName("video");
|
|
171
|
-
|
|
189
|
+
const require_refresh = ["open.spotify.com", "soundcloud.com"].indexOf(document.location.hostname) < 0;
|
|
172
190
|
cqt.render_callback = function() {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
191
|
+
if (require_refresh) {
|
|
192
|
+
let need_refresh = (videos.length != svideos.length);
|
|
193
|
+
for (let k = 0; k < videos.length && !need_refresh; k++)
|
|
194
|
+
need_refresh = (videos[k] != svideos[k]);
|
|
195
|
+
if (need_refresh) {
|
|
196
|
+
this.dataset.inputs = "video";
|
|
197
|
+
svideos = Array.from(videos);
|
|
198
|
+
}
|
|
179
199
|
}
|
|
180
200
|
|
|
181
201
|
let state = 0;
|
|
@@ -194,15 +214,14 @@ import {ShowCQTElement} from "../../showcqt-element@2/showcqt-element.mjs";
|
|
|
194
214
|
#player { margin-top: 0 !important; }`;
|
|
195
215
|
document.head.appendChild(style);
|
|
196
216
|
af_links.style.zIndex = 11;
|
|
197
|
-
af_links.style.bottom = "calc(var(--ytmusic-player-bar-height, 0) + 8px)";
|
|
198
217
|
cqt.style.zIndex = 10;
|
|
199
218
|
|
|
200
219
|
function update_cqt_bottom() {
|
|
201
220
|
if (document.fullscreenElement) {
|
|
202
|
-
|
|
221
|
+
document.body.style.setProperty("--ytms-cqt-bottom", "0px");
|
|
203
222
|
af_links.style.visibility = "hidden";
|
|
204
223
|
} else {
|
|
205
|
-
|
|
224
|
+
document.body.style.setProperty("--ytms-cqt-bottom", "var(--ytmusic-player-bar-height, 0px)");
|
|
206
225
|
af_links.style.visibility = "visible";
|
|
207
226
|
}
|
|
208
227
|
}
|
|
@@ -211,8 +230,84 @@ import {ShowCQTElement} from "../../showcqt-element@2/showcqt-element.mjs";
|
|
|
211
230
|
update_cqt_bottom();
|
|
212
231
|
}
|
|
213
232
|
|
|
214
|
-
|
|
215
|
-
|
|
233
|
+
function spotify_layout() {
|
|
234
|
+
cqt.style.zIndex = 4;
|
|
235
|
+
af_links.style.zIndex = 5;
|
|
236
|
+
document.body.style.setProperty("--ytms-cqt-bottom", "88px"); // FIXME
|
|
237
|
+
const old_play = HTMLMediaElement.prototype.play;
|
|
238
|
+
HTMLMediaElement.prototype.play = async function() {
|
|
239
|
+
const ret = old_play.call(this);
|
|
240
|
+
if (this.isConnected || this instanceof HTMLAudioElement)
|
|
241
|
+
return ret;
|
|
242
|
+
for (const video of svideos)
|
|
243
|
+
if (this == video)
|
|
244
|
+
return ret;
|
|
245
|
+
|
|
246
|
+
svideos.push(this);
|
|
247
|
+
const source = cqt.audio_context.createMediaElementSource(this);
|
|
248
|
+
source.connect(cqt.audio_input);
|
|
249
|
+
source.connect(cqt.audio_context.destination);
|
|
250
|
+
return ret;
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function soundcloud_layout() {
|
|
255
|
+
cqt.style.zIndex = 1000;
|
|
256
|
+
af_links.style.zIndex = 1001;
|
|
257
|
+
svideos[0][media_symbol].connect(cqt.audio_input);
|
|
258
|
+
document.body.style.setProperty("--ytms-cqt-bottom", "var(--play-controls-height, 0px)");
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
switch (document.location.hostname) {
|
|
262
|
+
case "music.youtube.com": ytmusic_layout(); break;
|
|
263
|
+
case "open.spotify.com": spotify_layout(); break;
|
|
264
|
+
case "soundcloud.com": soundcloud_layout(); break;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const coord_line_h = document.createElement("div");
|
|
268
|
+
const coord_line_v = document.createElement("div");
|
|
269
|
+
set_fixed_style(coord_line_h, cqt.style.zIndex);
|
|
270
|
+
set_fixed_style(coord_line_v, cqt.style.zIndex);
|
|
271
|
+
coord_line_h.style.left = 0;
|
|
272
|
+
coord_line_h.style.width = "100%";
|
|
273
|
+
coord_line_h.style.height = "1px";
|
|
274
|
+
coord_line_v.style.top = 0;
|
|
275
|
+
coord_line_v.style.height = "100%";
|
|
276
|
+
coord_line_v.style.width = "1px";
|
|
277
|
+
coord_line_h.style.pointerEvents = coord_line_v.style.pointerEvents = "none";
|
|
278
|
+
coord_line_h.style.display = coord_line_v.style.display = "none";
|
|
279
|
+
|
|
280
|
+
function update_cqt_layout(child) {
|
|
281
|
+
if (!child_menu.height || !child_menu.scroll || !child_menu.base_note || !child_menu.semitones)
|
|
282
|
+
return;
|
|
283
|
+
|
|
284
|
+
const width = child_menu.semitones.value * 1;
|
|
285
|
+
const base = child_menu.base_note.value - 16;
|
|
286
|
+
if (base + width > 120) {
|
|
287
|
+
child == child_menu.semitones ?
|
|
288
|
+
(child_menu.base_note.value = 120 - width + 16, child_menu.base_note.onchange()) :
|
|
289
|
+
(child_menu.semitones.value = 120 - base, child_menu.semitones.onchange());
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const vleft = -base / width;
|
|
294
|
+
const vwidth = 120 / width;
|
|
295
|
+
|
|
296
|
+
if (child_menu.scroll.value == "0") {
|
|
297
|
+
cqt.style.height = `calc(${ child_menu.height.value / 100} * (100% - var(--ytms-cqt-bottom, 0px)))`;
|
|
298
|
+
cqt.style.width = vwidth * 100 + "%";
|
|
299
|
+
cqt.style.left = vleft * 100 + "%";
|
|
300
|
+
cqt.style.bottom = "var(--ytms-cqt-bottom, 0px)";
|
|
301
|
+
cqt.style.transform = "";
|
|
302
|
+
} else {
|
|
303
|
+
cqt.style.height = child_menu.height.value + "vw";
|
|
304
|
+
cqt.style.width = `calc(${vwidth} * (100vh - var(--ytms-cqt-bottom, 0px)))`;
|
|
305
|
+
cqt.style.left = "100vw";
|
|
306
|
+
cqt.style.bottom = `calc(var(--ytms-cqt-bottom, 0px) + ${vleft} * (100vh - var(--ytms-cqt-bottom, 0px)))`;
|
|
307
|
+
cqt.style.transform = "rotate(-90deg)";
|
|
308
|
+
cqt.style.transformOrigin = "bottom left";
|
|
309
|
+
}
|
|
310
|
+
}
|
|
216
311
|
|
|
217
312
|
child_menu.axis = { value: get_opt("axis") };
|
|
218
313
|
child_menu.axis.onchange = function() { cqt.dataset.axis = axis_list[child_menu.axis.value]; };
|
|
@@ -249,10 +344,14 @@ import {ShowCQTElement} from "../../showcqt-element@2/showcqt-element.mjs";
|
|
|
249
344
|
menu_div.style.backgroundColor = "#000000DD";
|
|
250
345
|
menu_div.style.verticalAlign = "middle";
|
|
251
346
|
menu_div.style.maxHeight = "90%";
|
|
347
|
+
menu_div.style.maxWidth = "90%";
|
|
252
348
|
menu_div.style.overflow = "auto";
|
|
253
|
-
menu_div.style.scrollbarWidth = "
|
|
349
|
+
menu_div.style.scrollbarWidth = "8px";
|
|
350
|
+
menu_div.style.scrollbarColor = "#555555 #222222dd";
|
|
254
351
|
menu_div.style.visibility = "hidden";
|
|
255
352
|
menu_div.style.cursor = "default";
|
|
353
|
+
menu_table.style.width = "860px";
|
|
354
|
+
menu_div.style.display = "block";
|
|
256
355
|
|
|
257
356
|
var current_tr = null;
|
|
258
357
|
var current_tr_count = 0;
|
|
@@ -316,7 +415,7 @@ import {ShowCQTElement} from "../../showcqt-element@2/showcqt-element.mjs";
|
|
|
316
415
|
mic.pan.connect(cqt.audio_input);
|
|
317
416
|
mic.gain.connect(mic.pan);
|
|
318
417
|
|
|
319
|
-
create_child_range_menu("Height", "height",
|
|
418
|
+
create_child_range_menu("Height", "height", update_cqt_layout);
|
|
320
419
|
create_child_range_menu("Bar", "bar", (child) => cqt.dataset.bar = child.value);
|
|
321
420
|
create_child_range_menu("Waterfall", "waterfall", (child) => cqt.dataset.waterfall = child.value);
|
|
322
421
|
create_child_range_menu("Brightness", "brightness", (child) => cqt.dataset.brightness = child.value);
|
|
@@ -355,8 +454,7 @@ import {ShowCQTElement} from "../../showcqt-element@2/showcqt-element.mjs";
|
|
|
355
454
|
create_child_range_menu("Scale X", "scale_x", (child) => cqt.dataset.scaleX = child.value);
|
|
356
455
|
create_child_range_menu("Scale Y", "scale_y", (child) => cqt.dataset.scaleY = child.value);
|
|
357
456
|
|
|
358
|
-
|
|
359
|
-
function create_child_select_bar_scale(title, name) {
|
|
457
|
+
function create_child_select_menu(title, name, select_opt, callback) {
|
|
360
458
|
var tr = get_menu_table_tr();
|
|
361
459
|
set_common_tr_style(tr);
|
|
362
460
|
var td = document.createElement("td");
|
|
@@ -365,60 +463,48 @@ import {ShowCQTElement} from "../../showcqt-element@2/showcqt-element.mjs";
|
|
|
365
463
|
tr.appendChild(td);
|
|
366
464
|
td = document.createElement("td");
|
|
367
465
|
td.colSpan = 3;
|
|
368
|
-
var child =
|
|
466
|
+
var child = document.createElement("select");
|
|
467
|
+
if (name) child_menu[name] = child;
|
|
369
468
|
child.style.cursor = "pointer";
|
|
370
469
|
child.style.width = "100%";
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
var opt = document.createElement("option");
|
|
470
|
+
for (let k = 0; k < select_opt.length; k++) {
|
|
471
|
+
const opt = document.createElement("option");
|
|
374
472
|
opt.textContent = select_opt[k];
|
|
375
473
|
opt.value = k;
|
|
376
474
|
child.appendChild(opt);
|
|
377
475
|
}
|
|
378
|
-
child.value = get_opt(
|
|
476
|
+
if (name) child.value = get_opt(name);
|
|
379
477
|
td.appendChild(child);
|
|
380
478
|
tr.appendChild(td);
|
|
381
|
-
child.onchange =
|
|
382
|
-
switch (child.value) {
|
|
383
|
-
case "1": bar_scale_func = bar_scale_sqrt; break;
|
|
384
|
-
case "2": bar_scale_func = c => bar_scale_db(c, 2); break;
|
|
385
|
-
case "3": bar_scale_func = c => bar_scale_db(c, 3); break;
|
|
386
|
-
case "4": bar_scale_func = c => bar_scale_db(c, 4); break;
|
|
387
|
-
default: bar_scale_func = null;
|
|
388
|
-
}
|
|
389
|
-
};
|
|
479
|
+
child.onchange = () => callback?.(child);
|
|
390
480
|
child.onchange();
|
|
481
|
+
}
|
|
391
482
|
|
|
392
|
-
|
|
393
|
-
for (let k = 3; k < color.length; k += 4)
|
|
394
|
-
color[k] = 0.5 * Math.sqrt(color[k]);
|
|
395
|
-
}
|
|
483
|
+
let bar_scale_func = null;
|
|
396
484
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
}
|
|
485
|
+
function bar_scale_sqrt(color) {
|
|
486
|
+
for (let k = 3; k < color.length; k += 4)
|
|
487
|
+
color[k] = 0.5 * Math.sqrt(color[k]);
|
|
401
488
|
}
|
|
402
|
-
create_child_select_bar_scale("Bar Scale", "bar_scale");
|
|
403
489
|
|
|
404
|
-
function
|
|
405
|
-
|
|
406
|
-
|
|
490
|
+
function bar_scale_db(color, range) {
|
|
491
|
+
for (let k = 3; k < color.length; k += 4)
|
|
492
|
+
color[k] = Math.max(0, (Math.log10(color[k]) + range) / range);
|
|
493
|
+
}
|
|
407
494
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
495
|
+
create_child_select_menu("Bar Scale", "bar_scale",
|
|
496
|
+
[ "Linear", "Sqrt", "Log (40 dB)", "Log (60 dB)", "Log (80 dB)" ], (child) => {
|
|
497
|
+
switch (child.value) {
|
|
498
|
+
case "1": bar_scale_func = bar_scale_sqrt; break;
|
|
499
|
+
case "2": bar_scale_func = c => bar_scale_db(c, 2); break;
|
|
500
|
+
case "3": bar_scale_func = c => bar_scale_db(c, 3); break;
|
|
501
|
+
case "4": bar_scale_func = c => bar_scale_db(c, 4); break;
|
|
502
|
+
default: bar_scale_func = null;
|
|
415
503
|
}
|
|
416
|
-
|
|
417
|
-
cqt.style.width = 12000 / width + "%";
|
|
418
|
-
}
|
|
504
|
+
});
|
|
419
505
|
|
|
420
|
-
create_child_range_menu("Base Note", "base_note",
|
|
421
|
-
create_child_range_menu("Semitones", "semitones",
|
|
506
|
+
create_child_range_menu("Base Note", "base_note", update_cqt_layout);
|
|
507
|
+
create_child_range_menu("Semitones", "semitones", update_cqt_layout);
|
|
422
508
|
|
|
423
509
|
const number2color = n => "#" + (n|0).toString(16).padStart(6, "0");
|
|
424
510
|
const color2number = c => Number.parseInt(c.slice(1), 16);
|
|
@@ -426,6 +512,78 @@ import {ShowCQTElement} from "../../showcqt-element@2/showcqt-element.mjs";
|
|
|
426
512
|
const color_table = new Array(9);
|
|
427
513
|
const peak_color = new Array(3);
|
|
428
514
|
|
|
515
|
+
class ColorRotation {
|
|
516
|
+
constructor() {
|
|
517
|
+
const kr = 0.2126;
|
|
518
|
+
const kb = 0.0722;
|
|
519
|
+
const kg = 1 - (kr + kb);
|
|
520
|
+
const kmul = 2 / Math.sqrt(3);
|
|
521
|
+
|
|
522
|
+
this.mat_r = [ 1, 2 * (kb + kg), kmul * (kb - kg) ];
|
|
523
|
+
this.mat_g = [ 1, -2 * kr, kmul * (kb - kg + 1) ];
|
|
524
|
+
this.mat_b = [ 1, -2 * kr, kmul * (kb - kg - 1) ];
|
|
525
|
+
|
|
526
|
+
this.saturation = 0;
|
|
527
|
+
this.hue = 0;
|
|
528
|
+
this.hue_range = 0;
|
|
529
|
+
this.table_len = 1000;
|
|
530
|
+
this.table = new Float32Array(this.table_len * 3 + 6);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
rgb_from_yuv(res, y, u, v) {
|
|
534
|
+
res[0] = y + this.mat_r[1] * u + this.mat_r[2] * v;
|
|
535
|
+
res[1] = y + this.mat_g[1] * u + this.mat_g[2] * v;
|
|
536
|
+
res[2] = y + this.mat_b[1] * u + this.mat_b[2] * v;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
update(saturation, hue, hue_range) {
|
|
540
|
+
this.saturation = saturation;
|
|
541
|
+
this.hue = hue;
|
|
542
|
+
this.hue_range = hue_range;
|
|
543
|
+
|
|
544
|
+
if (this.saturation == 0)
|
|
545
|
+
return;
|
|
546
|
+
|
|
547
|
+
const res = [ 0, 0, 0 ];
|
|
548
|
+
const hue_step = Math.PI / 18 * hue_range;
|
|
549
|
+
const hue_start = Math.PI / 18 * hue - 0.5 * hue_step;
|
|
550
|
+
const sat_g = 10 ** (saturation / 10 - 1);
|
|
551
|
+
|
|
552
|
+
for (let k = 0; k <= this.table_len + 1; k++) {
|
|
553
|
+
let y = Math.min(1, k / this.table_len);
|
|
554
|
+
let h = hue_start + Math.sin(0.5 * Math.PI * y) * hue_step;
|
|
555
|
+
h = h - 0.23 * Math.sin(3 * h);
|
|
556
|
+
y = y*y;
|
|
557
|
+
let u = Math.cos(h), v = Math.sin(h), s = 0, sum_rcp = 0;
|
|
558
|
+
this.rgb_from_yuv(res, y, u, v);
|
|
559
|
+
for (let c = 0; c < 3; c++) {
|
|
560
|
+
sum_rcp += Math.exp((res[c] - y) * y * sat_g);
|
|
561
|
+
sum_rcp += Math.exp((y - res[c]) * (1 - y) * sat_g);
|
|
562
|
+
}
|
|
563
|
+
s = y * (1 - y) * sat_g / Math.log(sum_rcp);
|
|
564
|
+
this.rgb_from_yuv(res, y, s*u, s*v);
|
|
565
|
+
const gamma = 1/2.2;
|
|
566
|
+
this.table[3*k+0] = Math.max(0, res[0])**gamma;
|
|
567
|
+
this.table[3*k+1] = Math.max(0, res[1])**gamma;
|
|
568
|
+
this.table[3*k+2] = Math.max(0, res[2])**gamma;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
transform(color) {
|
|
573
|
+
const len = color.length / 4;
|
|
574
|
+
for (let k = 0; k < len; k++) {
|
|
575
|
+
const y = Math.max(0, Math.min(1, color[4*k+1])) * this.table_len;
|
|
576
|
+
const idx = Math.floor(y);
|
|
577
|
+
const frac = y - idx;
|
|
578
|
+
const ifrac = 1 - frac;
|
|
579
|
+
color[4*k+0] = this.table[3*idx+0] * ifrac + this.table[3*idx+3] * frac;
|
|
580
|
+
color[4*k+1] = this.table[3*idx+1] * ifrac + this.table[3*idx+4] * frac;
|
|
581
|
+
color[4*k+2] = this.table[3*idx+2] * ifrac + this.table[3*idx+5] * frac;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
const color_rotation = new ColorRotation();
|
|
586
|
+
|
|
429
587
|
function create_child_color_menu(title, name, callback) {
|
|
430
588
|
var tr = get_menu_table_tr();
|
|
431
589
|
set_common_tr_style(tr);
|
|
@@ -466,7 +624,10 @@ import {ShowCQTElement} from "../../showcqt-element@2/showcqt-element.mjs";
|
|
|
466
624
|
if (color[k+3] <= color[k-1] || color[k+3] < color[k+7])
|
|
467
625
|
continue;
|
|
468
626
|
|
|
469
|
-
const alpha = (1 - (k+2) / color.length) ** 2;
|
|
627
|
+
const alpha = (1 - (k+2) / color.length) ** 2 - 0.16;
|
|
628
|
+
if (alpha <= 0)
|
|
629
|
+
break;
|
|
630
|
+
|
|
470
631
|
for (let m = 0; m < 3; m++)
|
|
471
632
|
color[k+m] = Math.min(color[k+m], 1) * (1 - alpha + peak_color[m] * alpha);
|
|
472
633
|
}
|
|
@@ -496,7 +657,25 @@ import {ShowCQTElement} from "../../showcqt-element@2/showcqt-element.mjs";
|
|
|
496
657
|
create_child_color_menu("Mid Color", "mid_color", child => color_int[1] = color2number(child.value));
|
|
497
658
|
create_child_color_menu("Right Color", "right_color", child => color_int[2] = color2number(child.value));
|
|
498
659
|
|
|
660
|
+
function update_color_rotation() {
|
|
661
|
+
color_rotation.update(Number(child_menu.saturation?.value ?? 0),
|
|
662
|
+
Number(child_menu.hue?.value ?? 0),
|
|
663
|
+
Number(child_menu.hue_range?.value ?? 0));
|
|
664
|
+
}
|
|
665
|
+
create_child_range_menu("Saturation", "saturation", update_color_rotation);
|
|
666
|
+
create_child_range_menu("Hue", "hue", child => {
|
|
667
|
+
if (child.value == 19)
|
|
668
|
+
return child.value = -17, child.onchange();
|
|
669
|
+
if (child.value == -18)
|
|
670
|
+
return child.value = 18, child.onchange();
|
|
671
|
+
update_color_rotation();
|
|
672
|
+
});
|
|
673
|
+
create_child_range_menu("Hue Range", "hue_range", update_color_rotation);
|
|
674
|
+
|
|
499
675
|
function transform_color(color) {
|
|
676
|
+
if (color_rotation.saturation > 0)
|
|
677
|
+
return color_rotation.transform(color);
|
|
678
|
+
|
|
500
679
|
if (color_int[0] == 0xdcb900 && color_int[1] == 0xdcdcdc && color_int[2] == 0x00b9dc)
|
|
501
680
|
return;
|
|
502
681
|
|
|
@@ -508,31 +687,7 @@ import {ShowCQTElement} from "../../showcqt-element@2/showcqt-element.mjs";
|
|
|
508
687
|
}
|
|
509
688
|
}
|
|
510
689
|
|
|
511
|
-
|
|
512
|
-
var tr = get_menu_table_tr();
|
|
513
|
-
set_common_tr_style(tr);
|
|
514
|
-
var td = document.createElement("td");
|
|
515
|
-
set_common_left_td_style(td);
|
|
516
|
-
td.textContent = title;
|
|
517
|
-
tr.appendChild(td);
|
|
518
|
-
td = document.createElement("td");
|
|
519
|
-
td.colSpan = 3;
|
|
520
|
-
var child = child_menu[name] = document.createElement("select");
|
|
521
|
-
child.style.cursor = "pointer";
|
|
522
|
-
child.style.width = "100%";
|
|
523
|
-
var select_opt = [ "Off", "Static", "Mid Color", "Average", "Spectrum" ];
|
|
524
|
-
for (var k = 0; k < select_opt.length; k++) {
|
|
525
|
-
var opt = document.createElement("option");
|
|
526
|
-
opt.textContent = select_opt[k];
|
|
527
|
-
opt.value = k;
|
|
528
|
-
child.appendChild(opt);
|
|
529
|
-
}
|
|
530
|
-
child.value = get_opt("line_mode");
|
|
531
|
-
td.appendChild(child);
|
|
532
|
-
tr.appendChild(td);
|
|
533
|
-
child.onchange = () => {};
|
|
534
|
-
}
|
|
535
|
-
create_child_select_line_mode("Line Mode", "line_mode");
|
|
690
|
+
create_child_select_menu("Line Mode", "line_mode", [ "Off", "Static", "Mid Color", "Average", "Spectrum" ]);
|
|
536
691
|
create_child_range_menu("Line Width", "line_width");
|
|
537
692
|
create_child_color_menu("Line Color", "line_color");
|
|
538
693
|
|
|
@@ -639,50 +794,55 @@ import {ShowCQTElement} from "../../showcqt-element@2/showcqt-element.mjs";
|
|
|
639
794
|
tr.appendChild(td);
|
|
640
795
|
}
|
|
641
796
|
|
|
797
|
+
create_child_select_menu("Scroll", "scroll", [ "Vertical", "Horizontal" ], update_cqt_layout);
|
|
642
798
|
create_child_checkbox_menu("Transparent", "transparent", (child) => cqt.dataset.opacity = child.checked ? "transparent" : "opaque");
|
|
643
799
|
create_child_checkbox_menu("Visible", "visible", (child) => {
|
|
644
800
|
cqt.style.display = child.checked ? "block" : "none";
|
|
801
|
+
if (!child.checked)
|
|
802
|
+
coord_line_h.style.display = coord_line_v.style.display = "none";
|
|
645
803
|
update_af_links();
|
|
646
804
|
});
|
|
647
805
|
|
|
648
|
-
function
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
var td = document.createElement("td");
|
|
652
|
-
set_common_left_td_style(td);
|
|
653
|
-
td.textContent = "Presets";
|
|
654
|
-
tr.appendChild(td);
|
|
655
|
-
td = document.createElement("td");
|
|
656
|
-
td.colSpan = 3;
|
|
657
|
-
var child = document.createElement("select");
|
|
658
|
-
child.style.cursor = "pointer";
|
|
659
|
-
child.style.width = "100%";
|
|
806
|
+
function cqt_coord_line_leave(ev) {
|
|
807
|
+
coord_line_h.style.display = coord_line_v.style.display = "none";
|
|
808
|
+
}
|
|
660
809
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
color_juicy_lemon: { text: "Color: Juicy Lemon", command: set_color_juicy_lemon },
|
|
667
|
-
color_rain_forest: { text: "Color: Rain Forest", command: set_color_rain_forest },
|
|
668
|
-
scale_960: { text: "Scale: 960", command: () => set_scale_preset(960) },
|
|
669
|
-
scale_1280: { text: "Scale: 1280", command: () => set_scale_preset(1280) }
|
|
670
|
-
};
|
|
810
|
+
function cqt_coord_line_move(ev) {
|
|
811
|
+
coord_line_h.style.display = coord_line_v.style.display = "block";
|
|
812
|
+
coord_line_h.style.top = ev.clientY + "px";
|
|
813
|
+
coord_line_v.style.left = ev.clientX + "px";
|
|
814
|
+
}
|
|
671
815
|
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
816
|
+
create_child_color_menu("Coord Color", "coord_color", child => {
|
|
817
|
+
if (child.value == "#000000") {
|
|
818
|
+
coord_line_h.style.display = coord_line_v.style.display = "none";
|
|
819
|
+
cqt.removeEventListener("mouseleave", cqt_coord_line_leave);
|
|
820
|
+
cqt.removeEventListener("mousemove", cqt_coord_line_move);
|
|
821
|
+
} else {
|
|
822
|
+
cqt.addEventListener("mouseleave", cqt_coord_line_leave);
|
|
823
|
+
cqt.addEventListener("mousemove", cqt_coord_line_move);
|
|
824
|
+
coord_line_h.style.backgroundColor = coord_line_v.style.backgroundColor = child.value;
|
|
677
825
|
}
|
|
826
|
+
});
|
|
678
827
|
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
828
|
+
function create_child_select_presets() {
|
|
829
|
+
const presets = [
|
|
830
|
+
{ title: "-- Choose Preset --" },
|
|
831
|
+
{ title: "Color: Default", callback: set_color_default },
|
|
832
|
+
{ title: "Color: Deep Blue", callback: set_color_deep_blue },
|
|
833
|
+
{ title: "Color: Flame on Violet", callback: set_color_flame_on_violet },
|
|
834
|
+
{ title: "Color: Mono Fire", callback: set_color_mono_fire },
|
|
835
|
+
{ title: "Color: Evergreen", callback: set_color_evergreen },
|
|
836
|
+
{ title: "Color: Juicy Lemon", callback: set_color_juicy_lemon },
|
|
837
|
+
{ title: "Color: Rain Forest", callback: set_color_rain_forest },
|
|
838
|
+
{ title: "Scale: 960", callback: () => set_scale_preset(960) },
|
|
839
|
+
{ title: "Scale: 1280", callback: () => set_scale_preset(1280) }
|
|
840
|
+
];
|
|
841
|
+
|
|
842
|
+
create_child_select_menu("Presets", null, presets.map(v => v.title), child => {
|
|
843
|
+
presets[child.value|0]?.callback?.();
|
|
844
|
+
child.value = 0;
|
|
845
|
+
});
|
|
686
846
|
|
|
687
847
|
function set_color_preset(...args) {
|
|
688
848
|
child_menu.left_color.value = number2color(args[0]), child_menu.left_color.onchange();
|
|
@@ -690,6 +850,15 @@ import {ShowCQTElement} from "../../showcqt-element@2/showcqt-element.mjs";
|
|
|
690
850
|
child_menu.right_color.value = number2color(args[2]), child_menu.right_color.onchange();
|
|
691
851
|
child_menu.peak_color.value = number2color(args[3]), child_menu.peak_color.onchange();
|
|
692
852
|
child_menu.brightness.value = args[4], child_menu.brightness.onchange();
|
|
853
|
+
child_menu.saturation.value = 0, child_menu.saturation.onchange();
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
function set_color_hue_preset(sat, hue, range, br, peak) {
|
|
857
|
+
child_menu.saturation.value = sat, child_menu.saturation.onchange();
|
|
858
|
+
child_menu.hue.value = hue, child_menu.hue.onchange();
|
|
859
|
+
child_menu.hue_range.value = range, child_menu.hue_range.onchange();
|
|
860
|
+
child_menu.brightness.value = br, child_menu.brightness.onchange();
|
|
861
|
+
child_menu.peak_color.value = number2color(peak), child_menu.peak_color.onchange();
|
|
693
862
|
}
|
|
694
863
|
|
|
695
864
|
function set_color_default() {
|
|
@@ -701,10 +870,18 @@ import {ShowCQTElement} from "../../showcqt-element@2/showcqt-element.mjs";
|
|
|
701
870
|
set_color_preset(0x6400b9, 0x6464dc, 0x0064b9, 0x0000ff, 50);
|
|
702
871
|
}
|
|
703
872
|
|
|
873
|
+
function set_color_flame_on_violet() {
|
|
874
|
+
set_color_hue_preset(20, -3, 18, 10, 0x6633cc);
|
|
875
|
+
}
|
|
876
|
+
|
|
704
877
|
function set_color_mono_fire() {
|
|
705
878
|
set_color_preset(0xb94a25, 0xdc582c, 0xb94a25, 0xff0000, 70);
|
|
706
879
|
}
|
|
707
880
|
|
|
881
|
+
function set_color_evergreen() {
|
|
882
|
+
set_color_hue_preset(20, 15, -18, 10, 0x3366cc);
|
|
883
|
+
}
|
|
884
|
+
|
|
708
885
|
function set_color_juicy_lemon() {
|
|
709
886
|
set_color_preset(0xff004a, 0xffff58, 0x00ff4a, 0xffffff, 33);
|
|
710
887
|
}
|
|
@@ -778,7 +955,8 @@ import {ShowCQTElement} from "../../showcqt-element@2/showcqt-element.mjs";
|
|
|
778
955
|
setTimeout(function(){ child.value = "Reset Default Settings"; }, 300);
|
|
779
956
|
});
|
|
780
957
|
|
|
781
|
-
menu_div.
|
|
958
|
+
menu_div.attachShadow({mode: "open"});
|
|
959
|
+
menu_div.shadowRoot.appendChild(menu_table);
|
|
782
960
|
menu.onclick = function() {
|
|
783
961
|
menu_is_hidden = !menu_is_hidden;
|
|
784
962
|
if (menu_is_hidden)
|
|
@@ -819,6 +997,8 @@ import {ShowCQTElement} from "../../showcqt-element@2/showcqt-element.mjs";
|
|
|
819
997
|
|
|
820
998
|
create_menu();
|
|
821
999
|
document.body.appendChild(cqt);
|
|
1000
|
+
document.body.appendChild(coord_line_h);
|
|
1001
|
+
document.body.appendChild(coord_line_v);
|
|
822
1002
|
document.body.appendChild(af_links);
|
|
823
1003
|
dispatchEvent(new CustomEvent("youtube-musical-spectrum-is-available"));
|
|
824
1004
|
})().catch(e => console.error(e));
|