pianometer/globals.js

175 lines
4.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// @ts-check
let midiSelectSlider;
let midiIn;
// for piano visualizer
const state = State('pianometer/', {
color: '#2ee5b8',
rainbowMode: false, // 彩虹模式
velocityMode: false, // 力度模式
});
/** @type {Color} */
let keyOnColor; // 「按下時」的顏色 [HSB Color Mode]
/** @type {Color} */
let pedaledColor; // 「踏板踩住」的顏色 [HSB Color Mode]
let nowPedaling = false; // is it pedaling?(不要動)
let isKeyOn = []; // what notes are being pressed (1 or 0)(不要動)
let isPedaled = []; // what notes are pedaled (1 or 0)(不要動)
let isBlack = [0, 11, 0, 13, 0, 0, 11, 0, 12, 0, 13, 0]; // 是黑鍵嗎?是的話,相對左方的白鍵位移多少?(default: {0, 11, 0, 13, 0, 0, 11, 0, 12, 0, 13, 0}
let border = 3; // 左方留空幾個畫素?(default: 3)
let whiteKeyWidth = 20; // 白鍵多寬?(default: 20)
let whiteKeySpace = 1; // 白鍵間的縫隙多寬?(default: 1)
let blackKeyWidth = 17; // 黑鍵多寬?(default: 17)
let blackKeyHeight = 45; // 黑鍵多高?(default: 45)
let radius = 5; // 白鍵圓角(default: 5)
let bRadius = 4; // 黑鍵圓角(default: 4)
let keyAreaY = 3; // 白鍵從 Y 軸座標多少開始?(default: 3)
let keyAreaHeight = 70; // 白鍵多高?(default: 70)
let cc64now = 0; // 現在的踏板狀態
let cc67now = 0;
let sessionStartTime = new Date();
let sessionTotalSeconds = 0;
let flatNames = false;
// note counter
let notesThisFrame = 0;
let totalNotesPlayed = 0;
let shortTermTotal = new Array(60).fill(0);
let legatoHistory = new Array(60).fill(0);
let notesSMax = 0;
let totalIntensityScore = 0;
// for key pressed counter
let notePressedCount = 0;
let notePressedCountHistory = [];
WebMidi.enable(function (err) { // check if WebMidi.js is enabled
if (err) {
console.log('WebMidi could not be enabled.', err);
} else {
console.log('WebMidi enabled!');
}
//name our visible MIDI input and output ports
console.log('---');
console.log('Inputs Ports: ');
WebMidi.inputs.forEach(({name}, i) => {
console.log(i + ': ' + name);
});
console.log('---');
console.log('Output Ports: ');
WebMidi.outputs.forEach(({name}, i) => {
console.log(i + ': ' + name);
});
midiSelectSlider = select('#slider');
midiSelectSlider.attribute('max', WebMidi.inputs.length - 1);
midiSelectSlider.input(inputChanged);
midiIn = WebMidi.inputs[midiSelectSlider.value()]
inputChanged();
});
function inputChanged() {
isKeyOn.fill(0);
controllerChange(64, 0);
controllerChange(67, 0);
midiIn.removeListener();
midiIn = WebMidi.inputs[midiSelectSlider.value()];
midiIn.addListener('noteon', 'all', function (e) {
console.log('Received \'noteon\' message (' + e.note.number + ', ' + e.velocity + ').');
noteOn(e.note.number, e.velocity);
});
midiIn.addListener('noteoff', 'all', function (e) {
console.log('Received \'noteoff\' message (' + e.note.number + ', ' + e.velocity + ').');
noteOff(e.note.number, e.velocity);
})
midiIn.addListener('controlchange', 'all', function(e) {
console.log('Received control change message:', e.controller.number, e.value);
controllerChange(e.controller.number, e.value)
});
console.log(midiIn.name);
select('#device').html(midiIn.name);
};
/**
* @param {number} pitch
* @param {number} velocity
*/
function noteOn(pitch, velocity) {
totalNotesPlayed++;
notesThisFrame++;
totalIntensityScore += velocity;
// piano visualizer
isKeyOn[pitch] = velocity;
if (nowPedaling) {
isPedaled[pitch] = velocity;
}
}
/**
* @param {number} pitch
* @param {number} _velocity
*/
function noteOff(pitch, _velocity) {
isKeyOn[pitch] = 0;
}
/**
* @param {number} number
* @param {number} value
*/
function controllerChange(number, value) {
// Receive a controllerChange
if (number == 64) {
cc64now = value;
if (value >= 64) {
nowPedaling = true;
for (let i = 0; i < 128; i++) {
// copy key on to pedal
isPedaled[i] = isKeyOn[i];
}
} else if (value < 64) {
nowPedaling = false;
for (let i = 0; i < 128; i++) {
// reset isPedaled
isPedaled[i] = 0;
}
}
}
if (number == 67) {
cc67now = value;
}
}
/**
* @param {HTMLInputElement} cb
*/
function toggleRainbowMode(cb) {
state.rainbowMode = cb.checked;
if (state.rainbowMode) {
select('#colorpicker').attribute('disabled', true)
} else {
select('#colorpicker').removeAttribute('disabled')
}
}
/**
* @param {HTMLInputElement} cb
*/
function toggleVelocityMode(cb) {
state.velocityMode = cb.checked;
}
function changeColor() {
keyOnColor = color(state.color = select('#colorpicker').value());
const darkenedColor = keyOnColor.levels.map(x => Math.floor(x * .7));
pedaledColor = color(`rgb(${darkenedColor[0]}, ${darkenedColor[1]}, ${darkenedColor[2]})`);
}