Add files via upload
First upload.
This commit is contained in:
parent
6e81aec6e8
commit
b458744d00
6 changed files with 5366 additions and 0 deletions
122
globals.js
Normal file
122
globals.js
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
let midiSelectSlider;
|
||||||
|
|
||||||
|
// for piano visualizer
|
||||||
|
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 keyOnColor // set it in setup()
|
||||||
|
let pedaledColor // set it in setup()
|
||||||
|
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 rainbowMode = false; // 彩虹模式 (default: false)
|
||||||
|
let cc64now = 0; // 現在的踏板狀態
|
||||||
|
let cc67now = 0;
|
||||||
|
|
||||||
|
let sessionStartTime = new Date();
|
||||||
|
let sessionTotalSeconds = 0;
|
||||||
|
|
||||||
|
// note counter
|
||||||
|
let notesThisFrame = 0;
|
||||||
|
let totalNotesPlayed = 0;
|
||||||
|
let shortTermTotal = new Array(60).fill(0);
|
||||||
|
let legatoHistory = new Array(60).fill(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: ");
|
||||||
|
for (i = 0; i < WebMidi.inputs.length; i++) {
|
||||||
|
console.log(i + ": " + WebMidi.inputs[i].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("---");
|
||||||
|
console.log("Output Ports: ");
|
||||||
|
for (i = 0; i < WebMidi.outputs.length; i++) {
|
||||||
|
console.log(i + ": " + WebMidi.outputs[i].name);
|
||||||
|
}
|
||||||
|
midiSelectSlider = select("#slider");
|
||||||
|
midiSelectSlider.attribute("max", WebMidi.inputs.length - 1);
|
||||||
|
midiSelectSlider.changed(inputChanged);
|
||||||
|
midiIn = WebMidi.inputs[midiSelectSlider.value()]
|
||||||
|
inputChanged();
|
||||||
|
});
|
||||||
|
|
||||||
|
function inputChanged() {
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
function noteOn(pitch, velocity) {
|
||||||
|
totalNotesPlayed++;
|
||||||
|
notesThisFrame++;
|
||||||
|
totalIntensityScore += velocity;
|
||||||
|
|
||||||
|
// piano visualizer
|
||||||
|
isKeyOn[pitch] = 1;
|
||||||
|
if (nowPedaling) {
|
||||||
|
isPedaled[pitch] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function noteOff(pitch, velocity) {
|
||||||
|
isKeyOn[pitch] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
46
index.html
Normal file
46
index.html
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>好和弦的鋼琴鍵盤顯示器</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<script src="p5.min.js"></script>
|
||||||
|
<script src="webmidi.js"></script>
|
||||||
|
<script src="globals.js"></script>
|
||||||
|
<script src="piano-visualizer.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="main">
|
||||||
|
<div id="controls" class="center">
|
||||||
|
<div>
|
||||||
|
<h3>鋼琴鍵盤顯示器 by NiceChord</h3>
|
||||||
|
<h5>選擇 MIDI 裝置</h5>
|
||||||
|
<input id="slider" type="range" min="0" max="0" value="0">
|
||||||
|
<div id="device">Select Input: </div>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="center">
|
||||||
|
|
||||||
|
<div id="piano-visualizer">
|
||||||
|
<!-- Our sketch will go here! -->
|
||||||
|
</div>
|
||||||
|
<span style="font-size: 11px;">
|
||||||
|
TIME:使用時間 | NOTE COUNT:總彈奏音符數 | NOTES/S:最近一秒鐘彈奏音符數 | LEGATO:圓滑指數(最近一秒鐘平均來說有幾個鍵被同時按住) <br />
|
||||||
|
CALORIES:消耗熱量(估計值,好玩就好)| KEYS:現在正在被按住或被踏板留住的音 | PEDALS:左右踏板深度顯示 <br />
|
||||||
|
(密技:點鍵盤最左上角的角落,可以儲存截圖) <br /><br />
|
||||||
|
</span>
|
||||||
|
|
||||||
|
|
||||||
|
覺得好用嗎?到 <a href="https://nicechord.com">NiceChord.com</a> 逛逛支持我!
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
2
p5.min.js
vendored
Normal file
2
p5.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
222
piano-visualizer.js
Normal file
222
piano-visualizer.js
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
createCanvas(1098, 118).parent('piano-visualizer');
|
||||||
|
colorMode(HSB, 360, 100, 100, 100);
|
||||||
|
keyOnColor = color(326, 100, 100, 100); // <---- 編輯這裡換「按下時」的顏色![HSB Color Mode]
|
||||||
|
pedaledColor = color(326, 100, 70, 100); // <---- 編輯這裡換「踏板踩住」的顏色![HSB Color Mode]
|
||||||
|
smooth(2);
|
||||||
|
frameRate(60);
|
||||||
|
initKeys();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
background(0, 0, 20, 100);
|
||||||
|
pushHistories();
|
||||||
|
drawWhiteKeys();
|
||||||
|
drawBlackKeys();
|
||||||
|
// drawPedalLines();
|
||||||
|
// drawNotes();
|
||||||
|
|
||||||
|
drawTexts();
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateSessionTime() {
|
||||||
|
let currentTime = new Date();
|
||||||
|
let timeElapsed = currentTime - sessionStartTime;
|
||||||
|
// Convert time elapsed to hours, minutes, and seconds
|
||||||
|
let seconds = Math.floor((timeElapsed / 1000) % 60);
|
||||||
|
let minutes = Math.floor((timeElapsed / (1000 * 60)) % 60);
|
||||||
|
let hours = Math.floor((timeElapsed / (1000 * 60 * 60)) % 24);
|
||||||
|
sessionTotalSeconds = Math.floor(timeElapsed / 1000);
|
||||||
|
// Pad minutes and seconds with leading zeros
|
||||||
|
let paddedMinutes = String(minutes).padStart(2, '0');
|
||||||
|
let paddedSeconds = String(seconds).padStart(2, '0');
|
||||||
|
let timeText = `${hours}:${paddedMinutes}:${paddedSeconds}`;
|
||||||
|
return timeText;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initKeys() {
|
||||||
|
for (i = 0; i<128; i++) {
|
||||||
|
isKeyOn[i] = 0;
|
||||||
|
isPedaled[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawWhiteKeys() {
|
||||||
|
let wIndex = 0; // white key index
|
||||||
|
stroke(0, 0, 0);
|
||||||
|
strokeWeight(1);
|
||||||
|
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
|
||||||
|
} else {
|
||||||
|
fill(0, 0, 100); // white key
|
||||||
|
}
|
||||||
|
let thisX = border + wIndex*(whiteKeyWidth+whiteKeySpace);
|
||||||
|
rect(thisX, keyAreaY, whiteKeyWidth, keyAreaHeight, radius);
|
||||||
|
// println(wIndex);
|
||||||
|
wIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawBlackKeys() {
|
||||||
|
let wIndex = 0; // white key index
|
||||||
|
stroke(0, 0, 0);
|
||||||
|
strokeWeight(1.5);
|
||||||
|
for (let i = 21; i < 109; i++) {
|
||||||
|
if (isBlack[i % 12] == 0) {
|
||||||
|
// it's a white key
|
||||||
|
wIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
} else {
|
||||||
|
fill(0, 0, 0); // white key
|
||||||
|
}
|
||||||
|
|
||||||
|
let thisX = border + (wIndex-1)*(whiteKeyWidth+whiteKeySpace) + isBlack[i % 12];
|
||||||
|
rect(thisX, keyAreaY-1, blackKeyWidth, blackKeyHeight, bRadius);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawTexts() {
|
||||||
|
stroke(0, 0, 10, 100);
|
||||||
|
fill(0, 0, 100, 90)
|
||||||
|
textFont('Monospace');
|
||||||
|
textStyle(BOLD);
|
||||||
|
textSize(14);
|
||||||
|
textAlign(LEFT, TOP);
|
||||||
|
|
||||||
|
// TIME
|
||||||
|
let timeText = "TIME" + "\n" + calculateSessionTime();
|
||||||
|
text(timeText, 5, 79);
|
||||||
|
|
||||||
|
// PEDAL
|
||||||
|
let pedalText = "PEDALS" + "\nL " + convertNumberToBars(cc67now) + " R " + convertNumberToBars(cc64now)
|
||||||
|
text(pedalText, 860, 79);
|
||||||
|
|
||||||
|
// NOTES
|
||||||
|
let notesText = "NOTE COUNT" + "\n" + totalNotesPlayed;
|
||||||
|
text(notesText, 95, 79);
|
||||||
|
|
||||||
|
// CALORIES
|
||||||
|
let caloriesText = "CALORIES" + "\n" + (totalIntensityScore/250).toFixed(3); // 250 Intensity = 1 kcal.
|
||||||
|
text(caloriesText, 350, 79);
|
||||||
|
|
||||||
|
// SHORT-TERM DENSITY
|
||||||
|
let shortTermDensity = shortTermTotal.reduce((accumulator, currentValue) => accumulator + currentValue, 0); // Sum the array.
|
||||||
|
let shortTermDensityText = "NOTES/S" + "\n" + shortTermDensity;
|
||||||
|
text(shortTermDensityText, 200, 79);
|
||||||
|
|
||||||
|
// LEGATO SCORE
|
||||||
|
let legatoScore = legatoHistory.reduce((accumulator, currentValue) => accumulator + currentValue, 0)
|
||||||
|
legatoScore /= 60;
|
||||||
|
let legatoText = "LEGATO" + "\n" + legatoScore.toFixed(2);
|
||||||
|
text(legatoText, 280, 79);
|
||||||
|
|
||||||
|
// NOW PLAYING
|
||||||
|
let nowPlayingText = "KEYS" + "\n" + truncateString(getPressedKeys(), 47);
|
||||||
|
text(nowPlayingText, 440, 79);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pushHistories() {
|
||||||
|
shortTermTotal.push(notesThisFrame);
|
||||||
|
shortTermTotal.shift();
|
||||||
|
notesThisFrame = 0;
|
||||||
|
|
||||||
|
|
||||||
|
legatoHistory.push(isKeyOn.reduce((accumulator, currentValue) => accumulator + currentValue, 0));
|
||||||
|
legatoHistory.shift();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertNumberToBars(number) {
|
||||||
|
if (number < 0 || number > 127) {
|
||||||
|
throw new Error('Number must be between 0 and 127');
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxBars = 10;
|
||||||
|
const scaleFactor = 128 / maxBars;
|
||||||
|
|
||||||
|
// Calculate the number of bars
|
||||||
|
const numberOfBars = Math.ceil(number / scaleFactor);
|
||||||
|
|
||||||
|
// Create a string with the calculated number of "|" characters
|
||||||
|
const barString = '|'.repeat(numberOfBars);
|
||||||
|
|
||||||
|
// Calculate the number of "." characters required to fill the remaining space
|
||||||
|
const numberOfDots = maxBars - numberOfBars;
|
||||||
|
|
||||||
|
// Create a string with the calculated number of "." characters
|
||||||
|
const dotString = '.'.repeat(numberOfDots);
|
||||||
|
|
||||||
|
// Combine the "|" and "." strings
|
||||||
|
const combinedString = barString + dotString;
|
||||||
|
|
||||||
|
return combinedString;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPressedKeys() {
|
||||||
|
let pressedOrPedaled = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < isKeyOn.length; i++) {
|
||||||
|
pressedOrPedaled[i] = isKeyOn[i] === 1 || isPedaled[i] === 1 ? 1 : 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let noteNames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']; // default if sharp
|
||||||
|
if ([0, 1, 3, 5, 8, 10].includes(pressedOrPedaled.indexOf(1) % 12)) {
|
||||||
|
// flat
|
||||||
|
noteNames = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B'];
|
||||||
|
}
|
||||||
|
|
||||||
|
const pressedKeys = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < pressedOrPedaled.length; i++) {
|
||||||
|
if (pressedOrPedaled[i] === 1) {
|
||||||
|
const noteName = noteNames[i % 12];
|
||||||
|
const octave = Math.floor(i / 12) - 1;
|
||||||
|
pressedKeys.push(`${noteName}${octave}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pressedKeys.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
function truncateString(str, maxLength = 40) {
|
||||||
|
if (str.length <= maxLength) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str.slice(0, maxLength - 3) + '...';
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseClicked() {
|
||||||
|
// Save the canvas content as an image file
|
||||||
|
if (mouseX < 50 && mouseY < 50) {
|
||||||
|
saveCanvas('nicechord-pianometer', 'png');
|
||||||
|
}
|
||||||
|
}
|
547
style.css
Normal file
547
style.css
Normal file
|
@ -0,0 +1,547 @@
|
||||||
|
/*! style.css v1.0.0 | ISC License | https://github.com/ungoldman/style.css */
|
||||||
|
html {
|
||||||
|
color: rgb(210, 209, 202);
|
||||||
|
background-color: #202328;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "avenir next", avenir, "segoe ui", "fira sans", roboto, noto, "droid sans", "liberation sans", "lucida grande", "helvetica neue", helvetica, "franklin gothic medium", "century gothic", cantarell, oxygen, ubuntu, sans-serif;
|
||||||
|
font-size: calc(14px + 0.25vw);
|
||||||
|
line-height: 1.55;
|
||||||
|
-webkit-font-kerning: normal;
|
||||||
|
font-kerning: normal;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
-webkit-font-feature-settings: "kern", "liga"1, "calt"0;
|
||||||
|
font-feature-settings: "kern", "liga"1, "calt"0;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#main {
|
||||||
|
display: flex;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#controls {
|
||||||
|
width: 600px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#piano-visualizer {
|
||||||
|
margin-top: 0.2rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
article,
|
||||||
|
aside,
|
||||||
|
footer,
|
||||||
|
header,
|
||||||
|
nav,
|
||||||
|
section,
|
||||||
|
figcaption,
|
||||||
|
figure,
|
||||||
|
main {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
box-sizing: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
p,
|
||||||
|
blockquote,
|
||||||
|
ul,
|
||||||
|
ol,
|
||||||
|
dl,
|
||||||
|
table,
|
||||||
|
pre {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 1.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
small {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1.25em;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 small,
|
||||||
|
h2 small,
|
||||||
|
h3 small,
|
||||||
|
h4 small,
|
||||||
|
h5 small,
|
||||||
|
h6 small {
|
||||||
|
color: #777;
|
||||||
|
font-size: 0.7em;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 code,
|
||||||
|
h2 code,
|
||||||
|
h3 code,
|
||||||
|
h4 code,
|
||||||
|
h5 code,
|
||||||
|
h6 code {
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 2.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 1.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
font-size: 1.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h6 {
|
||||||
|
font-size: 1.15em;
|
||||||
|
color: #575757;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
background-color: transparent;
|
||||||
|
-webkit-text-decoration-skip: objects;
|
||||||
|
color: #0074d9;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:active,
|
||||||
|
a:hover {
|
||||||
|
outline-width: 0;
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:active,
|
||||||
|
a:focus,
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul,
|
||||||
|
ol {
|
||||||
|
padding: 0;
|
||||||
|
padding-left: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul ol,
|
||||||
|
ol ol {
|
||||||
|
list-style-type: lower-roman;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul ul,
|
||||||
|
ul ol,
|
||||||
|
ol ul,
|
||||||
|
ol ol {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul ul ol,
|
||||||
|
ul ol ol,
|
||||||
|
ol ul ol,
|
||||||
|
ol ol ol {
|
||||||
|
list-style-type: lower-alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
li>p {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
margin: 0 0 1rem;
|
||||||
|
padding: 0 1rem;
|
||||||
|
color: #7d7d7d;
|
||||||
|
border-left: 4px solid #d6d6d6;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote> :first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote> :last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
font-weight: inherit;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
mark {
|
||||||
|
background-color: #ff0;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub,
|
||||||
|
sup {
|
||||||
|
font-size: 75%;
|
||||||
|
line-height: 0;
|
||||||
|
position: relative;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub {
|
||||||
|
bottom: -0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
sup {
|
||||||
|
top: -0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
code,
|
||||||
|
pre,
|
||||||
|
kbd,
|
||||||
|
samp {
|
||||||
|
font-family: menlo, inconsolata, consolas, "fira mono", "noto mono", "droid sans mono", "liberation mono", "dejavu sans mono", "ubuntu mono", monaco, "courier new", monospace;
|
||||||
|
font-size: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre,
|
||||||
|
code {
|
||||||
|
background-color: #f7f7f7;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
overflow: auto;
|
||||||
|
word-wrap: normal;
|
||||||
|
padding: 1em;
|
||||||
|
line-height: 1.45;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre code {
|
||||||
|
background: transparent;
|
||||||
|
display: inline;
|
||||||
|
padding: 0;
|
||||||
|
line-height: inherit;
|
||||||
|
word-wrap: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre code::before,
|
||||||
|
pre code::after {
|
||||||
|
content: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre>code {
|
||||||
|
border: 0;
|
||||||
|
font-size: 1em;
|
||||||
|
white-space: pre;
|
||||||
|
word-break: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
padding: 0.2em 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
code::before,
|
||||||
|
code::after {
|
||||||
|
letter-spacing: -0.2em;
|
||||||
|
content: '\00a0';
|
||||||
|
}
|
||||||
|
|
||||||
|
kbd {
|
||||||
|
background-color: #e6e6e6;
|
||||||
|
background-image: linear-gradient(#fafafa, #e6e6e6);
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
border: 1px solid #d6d6d6;
|
||||||
|
border-radius: 2px;
|
||||||
|
box-shadow: 0 1px 0 #d6d6d6;
|
||||||
|
color: #303030;
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 0.95em;
|
||||||
|
margin: 0 1px;
|
||||||
|
padding: 5px 5px 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
td,
|
||||||
|
th {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
word-break: normal;
|
||||||
|
word-break: keep-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
table th,
|
||||||
|
table td {
|
||||||
|
padding: 6px 13px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
table th {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
table tr {
|
||||||
|
background-color: #fff;
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
table tr:nth-child(2n) {
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
box-sizing: content-box;
|
||||||
|
overflow: visible;
|
||||||
|
background: transparent;
|
||||||
|
height: 4px;
|
||||||
|
padding: 0;
|
||||||
|
margin: 1em 0;
|
||||||
|
background-color: #e7e7e7;
|
||||||
|
border: 0 none;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr::before {
|
||||||
|
display: table;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
hr::after {
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-style: none;
|
||||||
|
border: 0;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg:not(:root) {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure {
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure img {
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #c7c7c7;
|
||||||
|
padding: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
figcaption {
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 0.75em;
|
||||||
|
font-weight: 200;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
abbr[title] {
|
||||||
|
border-bottom: none;
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration: underline dotted;
|
||||||
|
}
|
||||||
|
|
||||||
|
dfn {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl dt {
|
||||||
|
padding: 0;
|
||||||
|
margin-top: 1em;
|
||||||
|
font-size: 1em;
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl dd {
|
||||||
|
padding: 0 1em;
|
||||||
|
margin-bottom: 1.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
audio,
|
||||||
|
video {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
audio:not([controls]) {
|
||||||
|
display: none;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
optgroup,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 100%;
|
||||||
|
line-height: 1.15;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
input {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
select {
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
html [type="button"],
|
||||||
|
[type="reset"],
|
||||||
|
[type="submit"] {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
}
|
||||||
|
|
||||||
|
button::-moz-focus-inner,
|
||||||
|
[type="button"]::-moz-focus-inner,
|
||||||
|
[type="reset"]::-moz-focus-inner,
|
||||||
|
[type="submit"]::-moz-focus-inner {
|
||||||
|
border-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:-moz-focusring,
|
||||||
|
[type="button"]:-moz-focusring,
|
||||||
|
[type="reset"]:-moz-focusring,
|
||||||
|
[type="submit"]:-moz-focusring {
|
||||||
|
outline: 1px dotted ButtonText;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
border: 1px solid #c0c0c0;
|
||||||
|
margin: 0 2px;
|
||||||
|
padding: 0.35em 0.625em 0.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
legend {
|
||||||
|
color: inherit;
|
||||||
|
display: table;
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
progress {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="checkbox"],
|
||||||
|
[type="radio"] {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="number"]::-webkit-inner-spin-button,
|
||||||
|
[type="number"]::-webkit-outer-spin-button {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="search"] {
|
||||||
|
-webkit-appearance: textfield;
|
||||||
|
outline-offset: -2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="search"]::-webkit-search-cancel-button,
|
||||||
|
[type="search"]::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[disabled] {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-file-upload-button {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
details,
|
||||||
|
menu {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
summary {
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
4427
webmidi.js
Normal file
4427
webmidi.js
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue