-
-
Save LongJohnCoder/363d8697db8b858c945defce673a40a4 to your computer and use it in GitHub Desktop.
midi-to-blobs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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