Published
Edited
Jan 26, 2021
2 stars
Insert cell
md`# Midi Viewer`
Insert cell
Insert cell
{
const [noteMin, noteMax] = d3.extent(notes, d => d.midi);
const [yMin, yMax] = d3.extent(notes, d => d.time);

const xDomain = d3.range(noteMin, noteMax + 1);
const yDomain = [0, yMax];

const xRange = [0, 100];
const yRange = [0, 100];

const xScale = d3.scaleBand(xDomain, xRange);
const yScale = d3.scaleLinear(yDomain, yRange);

const mapped = notes.map(d => {
const top = yScale(d.time);
const bottom = yScale(d.time + d.duration);
const height = Math.abs(top - bottom);
const left = xScale(d.midi);
const right = left + xScale.bandwidth();
const width = Math.abs(left - right);
return {
...d,
top,
bottom,
height,
left,
right,
width
};
});

const rects = mapped.map(d => {
const { top: y, left: x, width, height } = d;
return svg`<rect ${{
x: `${x}%`,
y: `${y}%`,
width: `${width}%`,
height: `${height}%`
}} />`;
});
mutable log = mapped;
return html`<svg style=${{
width: `100%`,
height: `2000px`
}}>${rects}</svg>`;
}
Insert cell
import { button } from "@jashkenas/inputs"
Insert cell
mutable playing = false
Insert cell
mutable synth = null
Insert cell
function start() {
const synth_ = new Tone.PolySynth(Tone.Synth, {
maxPolyphony: 20,
oscillator: {
partials: [0, 2, 3, 4, 5]
}
}).toDestination();
mutable synth = synth_;
const now = Tone.now();
notes.forEach(note => {
const { name, duration, time, velocity } = note;
synth_.triggerAttackRelease(name, duration, time + now, velocity);
});
}
Insert cell
function stop() {
if (synth) {
synth.disconnect();
mutable synth = null;
}
}
Insert cell
timeScale = 2
Insert cell
mutable log = null
Insert cell
Insert cell
notes = notesRaw.map(d => {
const { midi, name, duration, time, velocity } = d;
const noteName = midiutils.noteNumberToName(midi);
const frequency = midiutils.noteNumberToFrequency(midi);
return {
...d,
name,
duration,
time,
velocity,
number: midi,
noteName,
frequency
};
})
Insert cell
Insert cell
notesRaw = data.tracks[0].notes
Insert cell
data.tracks[0].notes[0].name
Insert cell
data = new ToneJSMidi.Midi(arrayBuffer)
Insert cell
arrayBuffer = await FileAttachment("entertainer.mid").arrayBuffer()
Insert cell
Tone = require('tone@next')
Insert cell
ToneJSMidi = require('@tonejs/midi')
Insert cell
d3 = require('d3')
Insert cell
import { html, svg } from "@observablehq/htl"
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more