diff --git a/modules/create-symbols.js b/modules/create-symbols.js index 579daa9..a2157b2 100644 --- a/modules/create-symbols.js +++ b/modules/create-symbols.js @@ -23,29 +23,6 @@ const rdoublesharp = /##|𝄪/; const cScale = [0,2,4,5,7,9,11]; - -function toPitch(stave, key, transpose, pitch) { - return stave.getSpelling( - // key - mod12(key + transpose), - // number - toNoteNumber(pitch) + transpose, - // type - 'note' - ); -} - -function toChord(stave, key, transpose, string) { - return stave.getSpelling( - // key - mod12(key + transpose), - // chord name - transposeChord(string, transpose), - // type - 'chord' - ); -} - const fathercharles = [ // Father Charles Goes Down And Ends Battle, 'F♯', 'C♯', 'G♯', 'D♯', 'A♯', 'E♯', 'B♯', @@ -59,9 +36,9 @@ function byFatherCharlesPitch(a, b) { return ai > bi ? 1 : ai < bi ? -1 : 0 ; } -function getStemDirection(note, head) { +function getStemDirection(centerPitch, head) { return head && head.stemDirection || ( - toNoteNumber(note) < toNoteNumber(head.pitch) ? + toNoteNumber(centerPitch) < toNoteNumber(head.pitch) ? 'down' : 'up' ); } @@ -78,9 +55,9 @@ function toDuration(event) { event[4] ; } -function insertTail(symbols, stemNote, i) { +function insertTail(symbols, stave, i) { const head = symbols[i]; - const stemDirection = getStemDirection(stemNote, head) ; + const stemDirection = getStemDirection(stave.centerPitch, head) ; // Splice stem and tail in before head symbols.splice(i, 0, assign({}, head, { @@ -152,7 +129,7 @@ function subtractStaveRows(stave, r1, r2) { return n + (octave2 - octave1) * 7; } -function createBeam(symbols, stave, beam, stemNote, n) { +function createBeam(symbols, stave, beam, n) { const part = symbols[0].part; // Not enough stems for a beam, give it a tail @@ -161,14 +138,14 @@ function createBeam(symbols, stave, beam, stemNote, n) { throw new Error('Last beam index (' + i + ') cant be greater than n (' + n + ')'); } - return insertTail(symbols, stemNote, beam[0]); + return insertTail(symbols, stave, beam[0]); } // Render stems and beam const stemDirection = symbols[beam[0]] && symbols[beam[0]].stemDirection ? symbols[beam[0]].stemDirection : (beam - .map((i) => subtractStaveRows(stave, stemNote, symbols[i].pitch)) + .map((i) => subtractStaveRows(stave, stave.centerPitch, symbols[i].pitch)) .reduce((t, u) => t + u, 0) / beam.length) < 0 ? 'up' : 'down' ; @@ -185,7 +162,7 @@ function createBeam(symbols, stave, beam, stemNote, n) { while (beam[++b] !== undefined) { i = beam[b]; head = symbols[i]; - line = subtractStaveRows(stave, stemNote, head.pitch); + line = subtractStaveRows(stave, stave.centerPitch, head.pitch); head.stemDirection = stemDirection; head.tieDirection = stemDirection === 'up' ? 'down' : 'up' ; @@ -258,9 +235,10 @@ function createBeam(symbols, stave, beam, stemNote, n) { return stems.length + buffer.length + 1; } -function createSymbols(symbols, bar, stemNote) { +function createSymbols(symbols, bar) { // All events in symbols have the same part - const part = symbols[0].part; + const part = symbols[0].part; + const stave = bar.stave; // Populate accidentals with key signature sharps and flats const accidentals = bar.key.reduce((accidentals, n, i) => { @@ -355,7 +333,7 @@ function createSymbols(symbols, bar, stemNote) { || isAfterBreak(bar.breaks, symbols[beam[beam.length - 1]].beat, head.beat) ) { // Close the current beam - n += createBeam(symbols, bar.stave, beam, stemNote, n); + n += createBeam(symbols, bar.stave, beam, n); beam = undefined; } } @@ -377,7 +355,7 @@ function createSymbols(symbols, bar, stemNote) { } // Otherwise render the stem immediately else { - let stemDirection = getStemDirection(stemNote, head); + let stemDirection = getStemDirection(stave.centerPitch, head); symbols.splice(n++, 0, assign({}, head, { type: 'stem', stemDirection @@ -396,7 +374,7 @@ function createSymbols(symbols, bar, stemNote) { } else { if (head.tie === 'begin' || head.tie === 'middle') { - let stemDirection = getStemDirection(stemNote, head); + let stemDirection = getStemDirection(stave.centerPitch, head); symbols.splice(n++, 0, assign({}, head, { type: 'tie', // Move tie into following grid column @@ -410,7 +388,7 @@ function createSymbols(symbols, bar, stemNote) { // Close the current beam if (beam && beam.length) { - n += createBeam(symbols, bar.stave, beam, stemNote, n); + n += createBeam(symbols, bar.stave, beam, n); beam = undefined; } @@ -533,7 +511,7 @@ function createBars(events, beatkeys, stave, keyscale, meter, transpose) { const events0 = eventsAtBeat(events, 0); meter = events0.find((event) => event[1] === 'meter') || meter ; - +console.log(meter); // First bar. Where meter is at beat 0, also inserts a time signature. let bar = createBar(0, stave, keyscale, meter, tieheads); bars.push(bar); @@ -605,7 +583,7 @@ function createBars(events, beatkeys, stave, keyscale, meter, transpose) { toDuration(event) ; if (event[1] === 'note') { - let pitch = toPitch(stave, key, transpose, event[2]); + let pitch = stave.getSpelling(key, event[2], event[1], transpose); let head = assign({ type: 'head', beat, @@ -631,7 +609,7 @@ function createBars(events, beatkeys, stave, keyscale, meter, transpose) { beat, duration, transpose, - value: toChord(stave, key, transpose, event[2]), + value: stave.getSpelling(key, event[2], event[1], transpose), event: event }); } diff --git a/modules/event/to-spelling.js b/modules/event/to-spelling.js index c4d2de9..8ea2702 100644 --- a/modules/event/to-spelling.js +++ b/modules/event/to-spelling.js @@ -14,7 +14,9 @@ const accidentals = { const rroot = /^[A-G][b#♭♯𝄫𝄪]?/; -export default function toSpelling(key, note) { +export default function toSpelling(key, note, type, transpose) { + key = mod12(key + transpose); + // Make sure key is a key object key = typeof key === 'number' ? keys[key] : typeof key === 'string' ? keys.find((o) => o.name === key) : @@ -37,8 +39,8 @@ export default function toSpelling(key, note) { rest = toNoteOctave(note) || '' ; } - const spelling = key.spellings[mod12(r)]; - const name = noteNames[mod12(r - spelling)]; + const spelling = key.spellings[mod12(r + transpose)]; + const name = noteNames[mod12(r + transpose - spelling)]; const accidental = accidentals[spelling]; if (window.DEBUG && name === undefined) { diff --git a/modules/staves.js b/modules/staves.js index ed59dc0..841438c 100644 --- a/modules/staves.js +++ b/modules/staves.js @@ -10,27 +10,34 @@ export const chords = { export const treble = { clef: 'treble', + centerPitch: 'B4', getSpelling: toSpelling }; export const bass = { clef: 'bass', + centerPitch: 'D3', getSpelling: toSpelling }; export const piano = { clef: 'piano', - getSpelling: toSpelling, + // TEMP + centerPitch: 'B4', + + // TODO: there should be four parts available, soprano alto, tenor bass getPart: function(pitch) { // A part is an object of properties assigned to a symbol. // Render anything below Bb3 on the lower part. return /[012]$|[AC-G][b#♭♯𝄫𝄪]*3$/.test(pitch) ? { - part: 'lower', - centerRow: 'stave-lower' + part: 'lower', + centerPitch: 'D3', + centerRow: 'stave-lower' } : { - centerRow: 'stave-upper' + centerPitch: 'B4', + centerRow: 'stave-upper' } ; } }; @@ -38,9 +45,9 @@ export const piano = { export const drums = { clef: 'drums', - getSpelling: (key, name, type) => { + getSpelling: (key, name, type, transpose) => { if (type === 'chord') { - return getSpelling(key, name); + return getSpelling(key, name, 'chord', transpose); } else if (type === 'note') { // Use standard MIDI note names. We don't want any spelling happening @@ -53,6 +60,7 @@ export const drums = { /*"C♯2": "head[1]", /* Side Stick */ "E♭2": "head[x]", /* Hand Clap */ "F♯2": "head[x]", /* Closed Hi-Hat */ + "G♯2": "head[x]", "A♭2": "head[x]", /* Pedal Hi-Hat */ "B♭2": "head[x]", /* Open Hi-Hat */ "C♯3": "head[x]", /* Crash Cymbal 1 */ @@ -61,6 +69,7 @@ export const drums = { "F3": "head[x]", /* Ride Bell */ "F♯3": "head[x]", /* Tambourine */ "G3": "head[x]", /* Splash Cymbal */ + "G♯3": "head[v]", "A♭3": "head[v]", /* Cowbell*/ "A3": "head[x]", /* Crash Symbol 2 */ "B♭3": "head[v]", /* Vibraslap */ @@ -103,6 +112,8 @@ export const drums = { Returns an object of properties assigned to symbols that belong to a part. **/ + // TEMP + centerPitch: 'B4', getPart: function(pitch) { // A part is an object of properties assigned to a symbol. // Render kick and hihatpedal as part 'feet'. @@ -110,7 +121,7 @@ export const drums = { part: 'feet', stemDirection: 'down', tieDirection: 'down', - centerRow: 'stave-lower' + centerRow: 'stave-lower', } : { // part: Leave part undefined to group with main render stemDirection: 'up', @@ -133,9 +144,12 @@ export const drums = { export const percussion = { clef: 'percussion', - getSpelling: (key, name, type) => { + // TEMP + centerPitch: 'B4', + + getSpelling: (key, name, type, transpose) => { if (type === 'chord') { - return getSpelling(key, name); + return getSpelling(key, name, 'chord', transpose); } else if (type === 'note') { // Use standard MIDI note names. We don't want any spelling happening diff --git a/scribe-script/classes/stave/drums.css b/scribe-script/classes/stave/drums.css index 9ddcdc1..293d279 100644 --- a/scribe-script/classes/stave/drums.css +++ b/scribe-script/classes/stave/drums.css @@ -35,7 +35,7 @@ https://web.mit.edu/merolish/Public/drums.pdf } /* TEMP */ -.drums-stave > .ledge +.drums-stave > .ledge, /* Just a precaution. */ .drums-stave > .acci { display: none !important; @@ -49,51 +49,57 @@ https://web.mit.edu/merolish/Public/drums.pdf grid-row: stave-lower; } -.drums-stave > [data-pitch="B1"] { grid-row: kick; } /* Acoustic Bass Drum */ -.drums-stave > [data-pitch="C2"] { grid-row: kick; } /* Bass Drum 1 */ -.drums-stave > [data-pitch="C♯2"] { grid-row: snare; } /* Side Stick */ -.drums-stave > [data-pitch="D2"] { grid-row: snare; } /* Acoustic Snare */ -.drums-stave > [data-pitch="E♭2"] { grid-row: snare; } /* Hand Clap */ -.drums-stave > [data-pitch="E2"] { grid-row: snare; } /* Electric Snare */ -.drums-stave > [data-pitch="F2"] { grid-row: lowfloortom; } /* Low Floor Tom */ -.drums-stave > [data-pitch="F♯2"] { grid-row: hihat; } /* Closed Hi-Hat */ -.drums-stave > [data-pitch="G2"] { grid-row: floortom; } /* High Floor Tom */ -.drums-stave > [data-pitch="A♭2"] { grid-row: hihatpedal; } /* Pedal Hi-Hat */ -.drums-stave > [data-pitch="A2"] { grid-row: midtom; } /* Low Tom */ -.drums-stave > [data-pitch="B♭2"] { grid-row: hihat; } /* Open Hi-Hat */ -.drums-stave > [data-pitch="B2"] { grid-row: midtom; } /* Low-Mid Tom */ -.drums-stave > [data-pitch="C3"] { grid-row: hightom; } /* Hi-Mid Tom */ -.drums-stave > [data-pitch="C♯3"] { grid-row: crash; } /* Crash Cymbal 1 */ -.drums-stave > [data-pitch="D3"] { grid-row: hightom; } /* High Tom */ -.drums-stave > [data-pitch="E♭3"] { grid-row: ride; } /* Ride Cymbal 1 */ -.drums-stave > [data-pitch="E3"] { grid-row: splash; } /* Chinese Cymbal */ -.drums-stave > [data-pitch="F3"] { grid-row: ride; } /* Ride Bell */ -.drums-stave > [data-pitch="F♯3"] { grid-row: foot; } /* Tambourine */ -.drums-stave > [data-pitch="G3"] { grid-row: splash; } /* Splash Cymbal */ -.drums-stave > [data-pitch="A♭3"] { grid-row: lowtom; } /* Cowbell*/ -.drums-stave > [data-pitch="A3"] { grid-row: crash2; } /* Crash Symbol 2 */ -.drums-stave > [data-pitch="B♭3"] { grid-row: midtom; } /* Vibraslap */ -.drums-stave > [data-pitch="B3"] { grid-row: crash2; } /* Ride Cymbal 2*/ -.drums-stave > [data-pitch="C4"] { grid-row: midtom; } /* Hi Bongo */ -.drums-stave > [data-pitch="C♯4"] { grid-row: lowtom; } /* Low Bongo */ -.drums-stave > [data-pitch="D4"] { grid-row: midtom; } /* Mute Hi Conga */ -.drums-stave > [data-pitch="E♭4"] { grid-row: midtom; } /* Open Hi Conga */ -.drums-stave > [data-pitch="E4"] { grid-row: lowtom; } /* Low Conga */ -.drums-stave > [data-pitch="F4"] { grid-row: hightom; } /* High Timbale */ -.drums-stave > [data-pitch="F♯4"] { grid-row: floortom; } /* Low Timbale */ -.drums-stave > [data-pitch="G4"] { grid-row: splash; } /* High Agogo */ -.drums-stave > [data-pitch="A♭4"] { grid-row: crash; } /* Low Agogo */ -.drums-stave > [data-pitch="A4"] { grid-row: hihat; } /* Cabasa */ -.drums-stave > [data-pitch="B♭4"] { grid-row: hihat; } /* Maracas */ -.drums-stave > [data-pitch="B4"] { grid-row: lowtom; } /* Short Whistle */ -.drums-stave > [data-pitch="C5"] { grid-row: lowtom; } /* Long Whistle */ -.drums-stave > [data-pitch="C♯5"] { grid-row: lowtom; } /* Short Guiro */ -.drums-stave > [data-pitch="D5"] { grid-row: lowtom; } /* Long Guiro */ -.drums-stave > [data-pitch="E♭5"] { grid-row: midtom; } /* Claves */ -.drums-stave > [data-pitch="E5"] { grid-row: midtom; } /* Hi Wood Block */ -.drums-stave > [data-pitch="F5"] { grid-row: lowtom; } /* Low Wood Block */ -.drums-stave > [data-pitch="F♯5"] { grid-row: ride; } /* Mute Cuica */ -.drums-stave > [data-pitch="G5"] { grid-row: ride; } /* Open Cuica */ -.drums-stave > [data-pitch="A♭5"] { grid-row: crash; } /* Mute Triangle */ -.drums-stave > [data-pitch="A5"] { grid-row: crash; } /* Open Triangle */ -.drums-stave > [data-pitch="B♭5"] { grid-row: hihat; } /* Shaker */ +/* Selectors must match the importance of data-pitch selectors found on + the base class .stave, hence the double attribute selector. */ +.drums-stave > [data-pitch][data-pitch="B1"] { grid-row: kick; } /* Acoustic Bass Drum */ +.drums-stave > [data-pitch][data-pitch="C2"] { grid-row: kick; } /* Bass Drum 1 */ +.drums-stave > [data-pitch][data-pitch="C♯2"] { grid-row: snare; } /* Side Stick */ +.drums-stave > [data-pitch][data-pitch="D2"] { grid-row: snare; } /* Acoustic Snare */ +.drums-stave > [data-pitch][data-pitch="E♭2"] { grid-row: snare; } /* Hand Clap */ +.drums-stave > [data-pitch][data-pitch="E2"] { grid-row: snare; } /* Electric Snare */ +.drums-stave > [data-pitch][data-pitch="F2"] { grid-row: lowfloortom; } /* Low Floor Tom */ +.drums-stave > [data-pitch][data-pitch="F♯2"] { grid-row: hihat; } /* Closed Hi-Hat */ +.drums-stave > [data-pitch][data-pitch="G2"] { grid-row: floortom; } /* High Floor Tom */ +.drums-stave > [data-pitch][data-pitch="G♯2"], +.drums-stave > [data-pitch][data-pitch="A♭2"] { grid-row: hihatpedal; } /* Pedal Hi-Hat */ +.drums-stave > [data-pitch][data-pitch="A2"] { grid-row: midtom; } /* Low Tom */ +.drums-stave > [data-pitch][data-pitch="B♭2"] { grid-row: hihat; } /* Open Hi-Hat */ +.drums-stave > [data-pitch][data-pitch="B2"] { grid-row: midtom; } /* Low-Mid Tom */ +.drums-stave > [data-pitch][data-pitch="C3"] { grid-row: hightom; } /* Hi-Mid Tom */ +.drums-stave > [data-pitch][data-pitch="C♯3"] { grid-row: crash; } /* Crash Cymbal 1 */ +.drums-stave > [data-pitch][data-pitch="D3"] { grid-row: hightom; } /* High Tom */ +.drums-stave > [data-pitch][data-pitch="E♭3"] { grid-row: ride; } /* Ride Cymbal 1 */ +.drums-stave > [data-pitch][data-pitch="E3"] { grid-row: splash; } /* Chinese Cymbal */ +.drums-stave > [data-pitch][data-pitch="F3"] { grid-row: ride; } /* Ride Bell */ +.drums-stave > [data-pitch][data-pitch="F♯3"] { grid-row: foot; } /* Tambourine */ +.drums-stave > [data-pitch][data-pitch="G3"] { grid-row: splash; } /* Splash Cymbal */ +.drums-stave > [data-pitch][data-pitch="G♯3"], +.drums-stave > [data-pitch][data-pitch="A♭3"] { grid-row: lowtom; } /* Cowbell*/ +.drums-stave > [data-pitch][data-pitch="A3"] { grid-row: crash2; } /* Crash Symbol 2 */ +.drums-stave > [data-pitch][data-pitch="B♭3"] { grid-row: midtom; } /* Vibraslap */ +.drums-stave > [data-pitch][data-pitch="B3"] { grid-row: crash2; } /* Ride Cymbal 2*/ +.drums-stave > [data-pitch][data-pitch="C4"] { grid-row: midtom; } /* Hi Bongo */ +.drums-stave > [data-pitch][data-pitch="C♯4"] { grid-row: lowtom; } /* Low Bongo */ +.drums-stave > [data-pitch][data-pitch="D4"] { grid-row: midtom; } /* Mute Hi Conga */ +.drums-stave > [data-pitch][data-pitch="E♭4"] { grid-row: midtom; } /* Open Hi Conga */ +.drums-stave > [data-pitch][data-pitch="E4"] { grid-row: lowtom; } /* Low Conga */ +.drums-stave > [data-pitch][data-pitch="F4"] { grid-row: hightom; } /* High Timbale */ +.drums-stave > [data-pitch][data-pitch="F♯4"] { grid-row: floortom; } /* Low Timbale */ +.drums-stave > [data-pitch][data-pitch="G4"] { grid-row: splash; } /* High Agogo */ +.drums-stave > [data-pitch][data-pitch="G♯4"], +.drums-stave > [data-pitch][data-pitch="A♭4"] { grid-row: crash; } /* Low Agogo */ +.drums-stave > [data-pitch][data-pitch="A4"] { grid-row: hihat; } /* Cabasa */ +.drums-stave > [data-pitch][data-pitch="B♭4"] { grid-row: hihat; } /* Maracas */ +.drums-stave > [data-pitch][data-pitch="B4"] { grid-row: lowtom; } /* Short Whistle */ +.drums-stave > [data-pitch][data-pitch="C5"] { grid-row: lowtom; } /* Long Whistle */ +.drums-stave > [data-pitch][data-pitch="C♯5"] { grid-row: lowtom; } /* Short Guiro */ +.drums-stave > [data-pitch][data-pitch="D5"] { grid-row: lowtom; } /* Long Guiro */ +.drums-stave > [data-pitch][data-pitch="E♭5"] { grid-row: midtom; } /* Claves */ +.drums-stave > [data-pitch][data-pitch="E5"] { grid-row: midtom; } /* Hi Wood Block */ +.drums-stave > [data-pitch][data-pitch="F5"] { grid-row: lowtom; } /* Low Wood Block */ +.drums-stave > [data-pitch][data-pitch="F♯5"] { grid-row: ride; } /* Mute Cuica */ +.drums-stave > [data-pitch][data-pitch="G5"] { grid-row: ride; } /* Open Cuica */ +.drums-stave > [data-pitch][data-pitch="G♯5"], +.drums-stave > [data-pitch][data-pitch="A♭5"] { grid-row: crash; } /* Mute Triangle */ +.drums-stave > [data-pitch][data-pitch="A5"] { grid-row: crash; } /* Open Triangle */ +.drums-stave > [data-pitch][data-pitch="B♭5"] { grid-row: hihat; } /* Shaker */ diff --git a/scribe-script/classes/stave/percussion.css b/scribe-script/classes/stave/percussion.css index 75f330c..27f2e8f 100644 --- a/scribe-script/classes/stave/percussion.css +++ b/scribe-script/classes/stave/percussion.css @@ -39,7 +39,8 @@ https://web.mit.edu/merolish/Public/drums.pdf } - -.percussion-stave > [data-pitch] { +/* Selectors must match the importance of data-pitch selectors found on + the base class .stave, hence the double attribute selector. */ +.percussion-stave > [data-pitch][data-pitch] { grid-row: stave-center; } diff --git a/scribe-script/module.js b/scribe-script/module.js index 85f89b7..edf1dc6 100755 --- a/scribe-script/module.js +++ b/scribe-script/module.js @@ -254,7 +254,7 @@ export default define(element('scribe-script', { beat `0` in the data. **/ meter: { - attribute: function(value) { this.key = value; }, + attribute: function(value) { this.meter = value; }, get: function() { return getInternals(this).meter.value; }, set: function(value) { getInternals(this).meter.value = value; } },