MIDI Visualizer
An experiment in audio-visual effects. This experiment requires Web MIDI.
(Note that the code only check for connected MIDI devices when it's started; refresh the page if you can't see your device.)
Click to get a new set of colors.
let midiSelect
let channelSelect
function setup() {
let canvas = createCanvas()
canvas.style('filter', 'blur(4px) contrast(300%)')
midiSelect = createSelect()
midiSelect.style('background', color(255))
midiSelect.style('margin', 0)
midiSelect.style('border', '1px solid')
midiSelect.style('border-color', color(0))
midiSelect.parent(canvas.parent())
windowResized()
WebMidi.addListener('connected', ({port}) => {
if(port.type == 'input') {
midiSelect.option(port.name, port.id)
}
})
for (let port of WebMidi.inputs) {
midiSelect.option(port.name, port.id)
}
let listeners = []
let updateListener = () => {
for (let listener of listeners) {
listener.remove()
}
listeners = []
let inp = WebMidi.getInputById(midiSelect.selected())
if (inp) {
listeners.push(...inp.addListener('noteon', noteon))
listeners.push(...inp.addListener('noteoff', noteon))
}
console.log(inp, listeners)
}
midiSelect.changed(() => {
storeItem('device', midiSelect.selected())
updateListener()
})
midiSelect.selected(getItem('device') || '')
WebMidi.enable().then(updateListener)
canvas.mousePressed(resetColors)
resetColors()
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight - 30)
midiSelect.size(windowWidth, 30)
}
function resetColors() {
colors = Array(7).fill().map((_, i) => Array(8).fill().map(_ =>
[random()*random(0.5, 1)*255, random()*random(0.5, 1)*255, random()*random(0.5, 1)*255, random()+random()]
))
}
let pitches = Array(127).fill(0)
let pitchesD = Array(127).fill(0)
function noteon({note, value}) {
pitches[note.number] = value
}
function noteoff({note}) {
notes[note.number] = 0
}
let objs = new Set()
let inhib = Array(pitches.length).fill(0)
let colors = []
function draw() {
let notes = Array(12).fill(0)
for (let i = 0; i < pitches.length; i ++) {
/*circle(map(i, 0, pitches.length, 0, width), 100, notes[i] * 60 + 2)
text(i, map(i, 0, pitches.length, 0, width), 60)*/
pitches[i] *= 0.99
pitchesD[i] += pitches[i]
pitchesD[i] *= 0.94
notes[i % 12] += pitchesD[i]
}
let intervals = Array(colors.length).fill().map(x => Array(12).fill(0))
for (let k = 0; k < intervals.length; k ++) {
for (let i = 0; i < 12; i ++) {
for (let j = 0; j < 12; j ++) {
intervals[k][(j - i + 12) % 12] += (notes[i] * notes[(i + k + 1) % 12] * notes[j]) ** (1/3)
}
}
}
let totalWeight = colors.reduce((e, x, i) => e + x.reduce((e, x, j) => e + x[3] * intervals[i][j], 0), 0)
let col = Array(3).fill().map((_, c) => totalWeight > 0.01 ? colors.reduce((e, x, i) => e + x.reduce((e, x, j) => e + x[c] * x[3] * intervals[i][j] / totalWeight, 0), 0) : 100).map(x => x * 0.9)
col = color(...col)
background(20)
noStroke()
for (let i = 0; i < pitches.length; i ++) {
inhib[i] -= pitches[i]
inhib[i] = min(inhib[i], pitches[i] * 6)
while (inhib[i] < 0) {
inhib[i] += 6
let x = (i + random(0.2)) / pitches.length
x = (x - 0.5)
//x = pow(x * 3, 3) / 3 + 0.5
x = exp(x * 5) / (1 + exp(x * 5))
x = x * width
objs.add({c: col, x: x, y: -20, r: sqrt(pitches[i]) * 50})
}
}
blendMode(ADD)
for (let o of objs) {
fill(o.c)
ellipse(o.x, o.y, o.r * 0.7, o.r)
o.y += random(1, 2)
o.x += random(-1, 1) * 0.3
if (o.y > height + 30) {
objs.delete(o)
}
}
for (let i = 0; i < 1; i+=0.02) {
fill(red(col), green(col), blue(col), 255 * pow(1 - i, 2))
rect(0, 200 * i, width, 200 * 0.02)
}
blendMode(BLEND)
}(Originally seen at https://editor.p5js.org/bojidar-bg/sketches/-oFnFwfbq)
Browse more articles?
← Electric streaks Experiments tagged p5 (15/85) COTR →
|← Experiments tagged music (1/2) Dancing Cairo circles →
← Electric streaks Experiments on this site (15/85) COTR →