Skip to content

Commit

Permalink
Missing drums and fix some bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
infojunkie committed Aug 27, 2024
1 parent 5324ec3 commit dc29b76
Show file tree
Hide file tree
Showing 2 changed files with 217 additions and 21 deletions.
81 changes: 60 additions & 21 deletions src/js/musicxml-grooves.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { parseArgs } from 'node:util'
import { createRequire } from 'node:module'
import { validateXMLWithXSD } from 'validate-with-xmllint'
import SaxonJS from 'saxon-js'
import path from 'path'

const require = createRequire(import.meta.url)
const { version } = require('../../package.json')
Expand Down Expand Up @@ -87,21 +88,26 @@ const grooves = 'grooves' in args ? args['grooves'].split(',').map(g => g.trim()
for (const groove of JSON.parse(fs.readFileSync('build/grooves.json'))) {
if (grooves.length > 0 && grooves.indexOf(groove.groove) < 0) continue

console.error(`Generating ${groove.groove}...`)
const musicxml = createMusicXML(groove)
try {
console.error(`Generating ${groove.groove}...`)
const musicxml = createMusicXML(groove)

if ('validate' in args) {
await validateXMLWithXSD(musicxml, 'src/xsd/musicxml.xsd')
.catch(error => {
console.error(`Failed to validate MusicXML: ${error.message}`)
})
}
if ('validate' in args) {
await validateXMLWithXSD(musicxml, 'src/xsd/musicxml.xsd')
.catch(error => {
console.error(`Failed to validate MusicXML: ${error.message}`)
})
}

if ('output' in args) {
fs.writeFileSync(path.join(args['output'], `${groove}.musicxml`), musicxml)
if ('output' in args) {
fs.writeFileSync(path.join(args['output'], `${groove.groove}.musicxml`), musicxml)
}
else {
process.stdout.write(musicxml + '\n')
}
}
else {
process.stdout.write(musicxml + '\n')
catch (error) {
console.error(`Failed to convert ${groove.groove} to MusicXML: ${error}`)
}
}

Expand All @@ -113,7 +119,7 @@ function createMusicXML(groove) {
"http://www.musicxml.org/dtds/partwise.dtd">
<score-partwise version="${MUSICXML_VERSION}">
<work>
<work-title>${groove.groove}</work-title>
<work-title>${escape(groove.groove)}</work-title>
</work>
<identification>
<encoding>
Expand All @@ -140,6 +146,10 @@ function createPartList(groove) {
// It can happen that a MIDI drum voice is used by multiple instruments,
// so we gather all matching instruments and later select those with the most voices.
const tracks = groove.tracks.filter(t => t.track.startsWith('DRUM')).reverse()
if (!tracks.length) {
throw Error('No drum tracks found.')
}

const partCandidates = tracks.reduce((partCandidates, track) => {
track.candidateInstrumentIds = []
const midi = track.midi[0] // In grooves.json, all MIDI notes are the same for each track
Expand Down Expand Up @@ -314,22 +324,38 @@ function createPartEntry(groove, partId, part) {
return n1.onset - n2.onset
}).reduce((notes, note, index, source) => {
const onset = notes.length > 0 ? notes[notes.length-1].onset : 1
const duration = note.onset - onset;
const duration = note.onset - onset
if (duration > 0) {
if (notes.length === 0) {
notes.push({
midi: undefined,
midi: undefined, // rest
onset,
duration
})
}
else {
notes.filter(note => note.onset === onset).forEach(note => { note.duration = duration })
// Maximum duration of a drum beat is 1.
notes.filter(note => note.onset === onset).forEach(note => { note.duration = Math.min(1, duration) })
if (duration > 1) {
notes.push({
midi: undefined,
onset: onset + 1,
duration: duration - 1
})
}
}
}
notes.push(note)
if (index === source.length - 1) {
notes.filter(note => note.duration === undefined).forEach(note => { note.duration = beats + 1 - note.onset })
const duration = beats + 1 - note.onset
notes.filter(note => note.duration === undefined).forEach(note => { note.duration = Math.min(1, duration) })
if (duration > 1) {
notes.push({
midi: undefined,
onset: onset + 1,
duration: duration - 1
})
}
}
return notes
}, []).map((note, index, notes) => {
Expand Down Expand Up @@ -373,7 +399,7 @@ function getNoteTiming(note, _index, _notes, beatType) {
12: '256th',
24: '128th',
48: '64th',
96: '32th',
96: '32nd',
192: '16th',
384: 'eighth',
768: 'quarter',
Expand Down Expand Up @@ -417,10 +443,10 @@ function createInstrument(document, _groove, track) {
target.appendChild(el)
if (obj.hasOwnProperty('children')) {
obj.children.forEach(child => {
createElement(el, child);
});
createElement(el, child)
})
}
return el;
return el
}
return createElement(instruments.documentElement, {
tagName: 'instrument',
Expand Down Expand Up @@ -472,3 +498,16 @@ function createInstrument(document, _groove, track) {
}]
})
}

// https://stackoverflow.com/a/27979933/209184
function escape(unsafe) {
return unsafe.replace(/[<>&'"]/g, function (c) {
switch (c) {
case '<': return '&lt;'
case '>': return '&gt;'
case '&': return '&amp;'
case '\'': return '&apos;'
case '"': return '&quot;'
}
})
}
157 changes: 157 additions & 0 deletions src/xml/drums.xml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,19 @@
<instrument-sound>effect.metronome-bell</instrument-sound>
</drum>
</instrument>
<instrument id="hand-clap">
<part-name lang="en">Hand Clap</part-name>
<part-abbreviation lang="en">Hd. Clp.</part-abbreviation>
<staff-lines>1</staff-lines>
<drum midi="39">
<instrument-name lang="en">Hand Clap</instrument-name>
<display-step>E</display-step>
<display-octave>4</display-octave>
<stem>up</stem>
<notehead>normal</notehead>
<instrument-sound>effect.hand-clap</instrument-sound>
</drum>
</instrument>
<instrument id="bass-drum">
<part-name lang="en">Bass Drum</part-name>
<part-abbreviation lang="en">B. Dr.</part-abbreviation>
Expand Down Expand Up @@ -385,6 +398,27 @@
<instrument-sound>drum.timbale</instrument-sound>
</drum>
</instrument>
<instrument id="agogo">
<part-name lang="en">Agogo</part-name>
<part-abbreviation lang="en">Ago.</part-abbreviation>
<staff-lines>1</staff-lines>
<drum midi="67">
<instrument-name lang="en">High Agogo</instrument-name>
<display-step>F</display-step>
<display-octave>4</display-octave>
<stem>up</stem>
<notehead>normal</notehead>
<instrument-sound>metal.bells.agogo</instrument-sound>
</drum>
<drum midi="68">
<instrument-name lang="en">Low Agogo</instrument-name>
<display-step>D</display-step>
<display-octave>4</display-octave>
<stem>up</stem>
<notehead>normal</notehead>
<instrument-sound>metal.bells.agogo</instrument-sound>
</drum>
</instrument>
<instrument id="cabasa">
<part-name lang="en">Cabasa</part-name>
<part-abbreviation lang="en">Cabs.</part-abbreviation>
Expand All @@ -411,6 +445,48 @@
<instrument-sound>rattle.maraca</instrument-sound>
</drum>
</instrument>
<instrument id="whistle">
<part-name lang="en">Whistle</part-name>
<part-abbreviation lang="en">Wh.</part-abbreviation>
<staff-lines>1</staff-lines>
<drum midi="71">
<instrument-name lang="en">Short High Whistle</instrument-name>
<display-step>F</display-step>
<display-octave>4</display-octave>
<stem>up</stem>
<notehead>normal</notehead>
<instrument-sound>effect.whistle</instrument-sound>
</drum>
<drum midi="72">
<instrument-name lang="en">Long Low Whistle</instrument-name>
<display-step>D</display-step>
<display-octave>4</display-octave>
<stem>up</stem>
<notehead>normal</notehead>
<instrument-sound>effect.whistle</instrument-sound>
</drum>
</instrument>
<instrument id="guiro">
<part-name lang="en">Guiro</part-name>
<part-abbreviation lang="en">Gro.</part-abbreviation>
<staff-lines>1</staff-lines>
<drum midi="73">
<instrument-name lang="en">Short Guiro</instrument-name>
<display-step>F</display-step>
<display-octave>4</display-octave>
<stem>up</stem>
<notehead>normal</notehead>
<instrument-sound>wood.guiro</instrument-sound>
</drum>
<drum midi="74">
<instrument-name lang="en">Long Guiro</instrument-name>
<display-step>D</display-step>
<display-octave>4</display-octave>
<stem>up</stem>
<notehead>normal</notehead>
<instrument-sound>wood.guiro</instrument-sound>
</drum>
</instrument>
<instrument id="claves">
<part-name lang="en">Claves</part-name>
<part-abbreviation lang="en">Clv.</part-abbreviation>
Expand Down Expand Up @@ -445,6 +521,27 @@
<instrument-sound>wood.wood-block</instrument-sound>
</drum>
</instrument>
<instrument id="cuica">
<part-name lang="en">Cuica</part-name>
<part-abbreviation lang="en">Cu.</part-abbreviation>
<staff-lines>1</staff-lines>
<drum midi="78">
<instrument-name lang="en">Mute Cuica</instrument-name>
<display-step>E</display-step>
<display-octave>4</display-octave>
<stem>up</stem>
<notehead>x</notehead>
<instrument-sound>drum.cuica</instrument-sound>
</drum>
<drum midi="79">
<instrument-name lang="en">Open Cuica</instrument-name>
<display-step>E</display-step>
<display-octave>4</display-octave>
<stem>up</stem>
<notehead>normal</notehead>
<instrument-sound>drum.cuica</instrument-sound>
</drum>
</instrument>
<instrument id="triangle">
<part-name lang="en">Triangle</part-name>
<part-abbreviation lang="en">Trgl.</part-abbreviation>
Expand Down Expand Up @@ -479,4 +576,64 @@
<instrument-sound>rattle.shaker</instrument-sound>
</drum>
</instrument>
<instrument id="sleigh-bells">
<part-name lang="en">Sleigh Bells</part-name>
<part-abbreviation lang="en">Sle. Be.</part-abbreviation>
<staff-lines>1</staff-lines>
<drum midi="83">
<instrument-name lang="en">Sleigh Bells</instrument-name>
<display-step>E</display-step>
<display-octave>4</display-octave>
<stem>up</stem>
<notehead>normal</notehead>
<instrument-sound>metal.bells.sleigh-bells</instrument-sound>
</drum>
</instrument>
<instrument id="bell-tree">
<part-name lang="en">Bell Tree</part-name>
<part-abbreviation lang="en">Be. Tr.</part-abbreviation>
<staff-lines>1</staff-lines>
<drum midi="84">
<instrument-name lang="en">Sleigh Bells</instrument-name>
<display-step>E</display-step>
<display-octave>4</display-octave>
<stem>up</stem>
<notehead>normal</notehead>
<instrument-sound>metal.bells.bell-tree</instrument-sound>
</drum>
</instrument>
<instrument id="castanets">
<part-name lang="en">Castanets</part-name>
<part-abbreviation lang="en">Cst.</part-abbreviation>
<staff-lines>1</staff-lines>
<drum midi="85">
<instrument-name lang="en">Castanets</instrument-name>
<display-step>E</display-step>
<display-octave>4</display-octave>
<stem>up</stem>
<notehead>normal</notehead>
<instrument-sound>wood.castanets</instrument-sound>
</drum>
</instrument>
<instrument id="surdo">
<part-name lang="en">Surdo</part-name>
<part-abbreviation lang="en">Srd.</part-abbreviation>
<staff-lines>1</staff-lines>
<drum midi="86">
<instrument-name lang="en">Mute Surdo</instrument-name>
<display-step>E</display-step>
<display-octave>4</display-octave>
<stem>up</stem>
<notehead>x</notehead>
<instrument-sound>drum.surdo</instrument-sound>
</drum>
<drum midi="87">
<instrument-name lang="en">Open Surdo</instrument-name>
<display-step>E</display-step>
<display-octave>4</display-octave>
<stem>up</stem>
<notehead>normal</notehead>
<instrument-sound>drum.surdo</instrument-sound>
</drum>
</instrument>
</instruments>

0 comments on commit dc29b76

Please sign in to comment.