Skip to content

Instantly share code, notes, and snippets.

@LongJohnCoder
Forked from OverlappingElvis/index.js
Created December 17, 2020 17:18
Show Gist options
  • Save LongJohnCoder/363d8697db8b858c945defce673a40a4 to your computer and use it in GitHub Desktop.
Save LongJohnCoder/363d8697db8b858c945defce673a40a4 to your computer and use it in GitHub Desktop.
midi-to-blobs
const fs = require(`fs`)
const _ = require(`lodash`)
const { Player } = require(`midi-player-js`)
const blessed = require(`blessed`)
const contrib = require(`blessed-contrib`)
const VOWELS = _.range(5)
const CONSONANTS = _.range(15)
const VOICES = [`Soprano`, `Mezzo-Soprano`, `Tenor`, `Bass`]
const player = new Player()
player.loadFile(`./test.mid`)
const songTime = player.getSongTime()
const allEvents = player.getEvents()
const MAX_TICKS = _.last(_.maxBy(allEvents, (events) => _.last(events).tick)).tick
const noteEventsOnly = allEvents.map(track => track.filter(event => event.name === `Note on`)).filter(track => !_.isEmpty(track))
const timelines = noteEventsOnly.map((track, index) => {
return {
title: `Track ${index}`,
x: track.map(event => event.tick),
y: track.map(event => event.noteNumber),
style: {
line: _.times(3, () => Math.random() * 255)
}
}
})
const trackAssignments = [``, ``, ``, ``]
const screen = blessed.screen()
const grid = new contrib.grid({
rows: 8,
cols: 2,
screen: screen
})
const trackList = grid.set(0, 0, 6, 1, contrib.table, {
keys: true,
columnWidth: [14, 8]
})
const line = grid.set(0, 1, 6, 1, contrib.line, {
showLegend: true
})
const log = grid.set(6, 0, 1, 2, contrib.log)
const save = grid.set(6, 1, 1, 2, blessed.button, {
mouse: true,
content: `Export`
})
save.on(`press`, () => {
const parsedEvents = trackAssignments.map((trackIndex) => {
const track = noteEventsOnly[parseInt(trackIndex, 10)]
return track.map((event) => {
return {
timeSeconds: (event.tick / MAX_TICKS) * songTime + (Math.random() * 0.025 * _.sample([1, -1])),
midiPitch: event.noteNumber,
librettoChunk: {
vowel: {
name: _.sample(VOWELS),
duration: 0.20000000298023224
},
suffix: [
{
name: _.sample(CONSONANTS),
duration: 0.10000000149011612
}
]
}
}
})
}).map((track) => {
return {
notes: track,
startSuffix: [
{
name: _.sample(CONSONANTS),
duration: 0.10000000149011612
}
]
}
})
const song = {
theme: 1,
parts: parsedEvents
}
fs.writeFile(`test.json`, JSON.stringify(song), () => {
log.log(`Wrote song to test.json`)
screen.render()
})
})
line.setData(timelines)
screen.key(['escape', 'q', 'C-c'], function(ch, key) {
return process.exit(0);
})
trackList.focus()
const setTracklistData = () => {
trackList.setData({
headers: [`Part`, `Track`],
data: VOICES.map((val, index) => [val, trackAssignments[index]])
})
}
setTracklistData()
trackList.rows.on(`select`, function(event) {
let prompt = blessed.prompt({
left: `center`,
top: `center`,
height: `shrink`,
width: `shrink`,
border: `line`
})
screen.append(prompt)
prompt.input(`Set track number`, ``, (err, value) => {
log.log(`Assigning track ${value} to ${event.index}`)
trackAssignments[event.index - 2] = value
prompt = null
setTracklistData()
screen.render()
})
})
log.log(`Started MIDI to Blob Opera.`)
screen.render()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment