From 810bae60b850f79bb401c30fe2094e9eabf53136 Mon Sep 17 00:00:00 2001 From: jxzhe Date: Wed, 5 Apr 2023 14:40:27 +0800 Subject: [PATCH] Add Velocity Mode When toggled, the color of each note will be affected by its velocity. Suitable when practicing this kind of stuff: https://wiwi.video/w/uuwkerA14WnDnysFCh6q4z?start=11m1s --- globals.js | 16 +++++++---- index.html | 9 +++++- piano-visualizer.js | 67 ++++++++++++++++++++++++++++++--------------- style.css | 10 +++---- 4 files changed, 68 insertions(+), 34 deletions(-) diff --git a/globals.js b/globals.js index f9bf036..df9475b 100644 --- a/globals.js +++ b/globals.js @@ -17,6 +17,7 @@ let bRadius = 4; // 黑鍵圓角(default: 4) let keyAreaY = 3; // 白鍵從 Y 軸座標多少開始?(default: 3) let keyAreaHeight = 70; // 白鍵多高?(default: 70) let rainbowMode = false; // 彩虹模式 (default: false) +let velocityMode = false; // 力度模式 (default: false) let cc64now = 0; // 現在的踏板狀態 let cc67now = 0; @@ -92,9 +93,9 @@ function noteOn(pitch, velocity) { totalIntensityScore += velocity; // piano visualizer - isKeyOn[pitch] = 1; + isKeyOn[pitch] = velocity; if (nowPedaling) { - isPedaled[pitch] = 1; + isPedaled[pitch] = velocity; } } @@ -136,9 +137,12 @@ function toggleRainbowMode(cb) { select('#colorpicker').removeAttribute('disabled') } +function toggleVelocityMode(cb) { + velocityMode = cb.checked; +} + function changeColor() { - keyOnColor = pedaledColor = color(select('#colorpicker').value()); - darkenedColor = keyOnColor.levels.map(x => floor(x * .7)); - pedaledColor = color(`rgb(${darkenedColor[0]}, ${darkenedColor[1]}, ${darkenedColor[2]})`) - console.log(pedaledColor.levels); + keyOnColor = color(select('#colorpicker').value()); + let darkenedColor = keyOnColor.levels.map(x => floor(x * .7)); + pedaledColor = color(`rgb(${darkenedColor[0]}, ${darkenedColor[1]}, ${darkenedColor[2]})`); } \ No newline at end of file diff --git a/index.html b/index.html index 06517f1..95e2197 100644 --- a/index.html +++ b/index.html @@ -31,7 +31,14 @@
彩虹模式 -
+
+ 力度模式 + +
diff --git a/piano-visualizer.js b/piano-visualizer.js index ca9b8ee..0a9a6b8 100644 --- a/piano-visualizer.js +++ b/piano-visualizer.js @@ -49,16 +49,28 @@ function drawWhiteKeys() { for (let i = 21; i < 109; i++) { if (isBlack[i % 12] == 0) { // it's a white key - if (isKeyOn[i] == 1 && !rainbowMode) { - fill(keyOnColor); // keypressed - } else if (isKeyOn[i] == 1 && rainbowMode) { - fill(map(i, 21, 108, 0, 1080) % 360, 100, 100, 100); // rainbowMode - } else if (isPedaled[i] == 1 && !rainbowMode) { - fill(pedaledColor); // pedaled - } else if (isPedaled[i] == 1 && rainbowMode) { - fill(map(i, 21, 108, 0, 1080) % 360, 100, 70, 100); // pedaled rainbowMode + if (velocityMode) { + let m = max(isKeyOn[i], isPedaled[i]) * .9 + .1; + if ((isKeyOn[i] || isPedaled[i]) && !rainbowMode) { + let whitenedColor = keyOnColor.levels.map(x => floor(x * m + 255 * (1 - m))); + fill(`rgb(${whitenedColor[0]}, ${whitenedColor[1]}, ${whitenedColor[2]})`); // keypressed + } else if ((isKeyOn[i] || isPedaled[i]) && rainbowMode) { + fill(map(i, 21, 108, 0, 1080) % 360, 100 * m, 100, 100); // rainbowMode + } else { + fill(0, 0, 100); // white key + } } else { - fill(0, 0, 100); // white key + if (isKeyOn[i] && !rainbowMode) { + fill(keyOnColor); // keypressed + } else if (isKeyOn[i] && rainbowMode) { + fill(map(i, 21, 108, 0, 1080) % 360, 100, 100, 100); // rainbowMode + } else if (isPedaled[i] && !rainbowMode) { + fill(pedaledColor); // pedaled + } else if (isPedaled[i] && rainbowMode) { + fill(map(i, 21, 108, 0, 1080) % 360, 100, 70, 100); // pedaled rainbowMode + } else { + fill(0, 0, 100); // white key + } } let thisX = border + wIndex * (whiteKeyWidth + whiteKeySpace); rect(thisX, keyAreaY, whiteKeyWidth, keyAreaHeight, radius); @@ -80,16 +92,28 @@ function drawBlackKeys() { if (isBlack[i % 12] > 0) { // it's a black key - if (isKeyOn[i] == 1 && !rainbowMode) { - fill(keyOnColor); // keypressed - } else if (isKeyOn[i] == 1 && rainbowMode) { - fill(map(i, 21, 108, 0, 1080) % 360, 100, 100, 100); // rainbowMode - } else if (isPedaled[i] == 1 && !rainbowMode) { - fill(pedaledColor); // pedaled - } else if (isPedaled[i] == 1 && rainbowMode) { - fill(map(i, 21, 108, 0, 1080) % 360, 100, 70, 100); // pedaled rainbowMode + if (velocityMode) { + let m = max(isKeyOn[i], isPedaled[i]) * .9 + .1; + if ((isKeyOn[i] || isPedaled[i]) && !rainbowMode) { + let darkenedColor = keyOnColor.levels.map(x => floor(x * m)); + fill(`rgb(${darkenedColor[0]}, ${darkenedColor[1]}, ${darkenedColor[2]})`); // keypressed + } else if ((isKeyOn[i] || isPedaled[i]) && rainbowMode) { + fill(map(i, 21, 108, 0, 1080) % 360, 100, 100 * m, 100); // rainbowMode + } else { + fill(0, 0, 0); // black key + } } else { - fill(0, 0, 0); // white key + if (isKeyOn[i] && !rainbowMode) { + fill(keyOnColor); // keypressed + } else if (isKeyOn[i] && rainbowMode) { + fill(map(i, 21, 108, 0, 1080) % 360, 100, 100, 100); // rainbowMode + } else if (isPedaled[i] && !rainbowMode) { + fill(pedaledColor); // pedaled + } else if (isPedaled[i] && rainbowMode) { + fill(map(i, 21, 108, 0, 1080) % 360, 100, 70, 100); // pedaled rainbowMode + } else { + fill(0, 0, 0); // black key + } } let thisX = border + (wIndex - 1) * (whiteKeyWidth + whiteKeySpace) + isBlack[i % 12]; @@ -147,7 +171,7 @@ function pushHistories() { shortTermTotal.push(notesThisFrame); shortTermTotal.shift(); notesThisFrame = 0; - legatoHistory.push(isKeyOn.reduce((accumulator, currentValue) => accumulator + currentValue, 0)); + legatoHistory.push(isKeyOn.reduce((accumulator, currentValue) => accumulator + !!currentValue, 0)); legatoHistory.shift(); @@ -183,8 +207,7 @@ function getPressedKeys(returnString = true) { let pressedOrPedaled = []; for (let i = 0; i < isKeyOn.length; i++) { - pressedOrPedaled[i] = isKeyOn[i] === 1 || isPedaled[i] === 1 ? 1 : 0; - + pressedOrPedaled[i] = isKeyOn[i] || isPedaled[i]; } let noteNames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']; // default if sharp @@ -196,7 +219,7 @@ function getPressedKeys(returnString = true) { const pressedKeys = []; for (let i = 0; i < pressedOrPedaled.length; i++) { - if (pressedOrPedaled[i] === 1) { + if (pressedOrPedaled[i]) { const noteName = noteNames[i % 12]; const octave = Math.floor(i / 12) - 1; pressedKeys.push(`${noteName}${octave}`); diff --git a/style.css b/style.css index d6a410b..b000fc6 100644 --- a/style.css +++ b/style.css @@ -552,7 +552,7 @@ input[type=checkbox] { visibility: hidden; } -label[for=rainbow-mode-checkbox] { +label.custom-checkbox { cursor: pointer; width: 50px; height: 25px; @@ -563,7 +563,7 @@ label[for=rainbow-mode-checkbox] { transition: .3s; } -label[for=rainbow-mode-checkbox]:after { +label.custom-checkbox:after { content: ''; position: absolute; top: 1.25px; @@ -575,15 +575,15 @@ label[for=rainbow-mode-checkbox]:after { transition: .3s; } -input:checked + label[for=rainbow-mode-checkbox] { +input:checked + label.custom-checkbox { background: #6f42c1; } -label[for=rainbow-mode-checkbox]:active:after { +label.custom-checkbox:active:after { width: 32.5px; } -input:checked + label[for=rainbow-mode-checkbox]:after { +input:checked + label.custom-checkbox:after { left: calc(100% - 1.25px); transform: translateX(-100%); } \ No newline at end of file