|
|
|
|
|
|
|
|
var parseCommon = require('./abc_common'); |
|
|
var parseDirective = require('./abc_parse_directive'); |
|
|
var parseKeyVoice = require('./abc_parse_key_voice'); |
|
|
|
|
|
var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) { |
|
|
this.reset = function(tokenizer, warn, multilineVars, tune) { |
|
|
parseKeyVoice.initialize(tokenizer, warn, multilineVars, tune, tuneBuilder); |
|
|
parseDirective.initialize(tokenizer, warn, multilineVars, tune, tuneBuilder); |
|
|
}; |
|
|
this.reset(tokenizer, warn, multilineVars, tune); |
|
|
|
|
|
this.setTitle = function(title, origSize) { |
|
|
if (multilineVars.hasMainTitle) |
|
|
tuneBuilder.addSubtitle(title, { startChar: multilineVars.iChar, endChar: multilineVars.iChar+origSize+2}); |
|
|
else |
|
|
{ |
|
|
tuneBuilder.addMetaText("title", title, { startChar: multilineVars.iChar, endChar: multilineVars.iChar+origSize+2}); |
|
|
multilineVars.hasMainTitle = true; |
|
|
} |
|
|
}; |
|
|
|
|
|
this.setMeter = function(line) { |
|
|
line = tokenizer.stripComment(line); |
|
|
if (line === 'C') { |
|
|
if (multilineVars.havent_set_length === true) { |
|
|
multilineVars.default_length = 0.125; |
|
|
multilineVars.havent_set_length = false; |
|
|
} |
|
|
return {type: 'common_time'}; |
|
|
} else if (line === 'C|') { |
|
|
if (multilineVars.havent_set_length === true) { |
|
|
multilineVars.default_length = 0.125; |
|
|
multilineVars.havent_set_length = false; |
|
|
} |
|
|
return {type: 'cut_time'}; |
|
|
} else if (line === 'o') { |
|
|
if (multilineVars.havent_set_length === true) { |
|
|
multilineVars.default_length = 0.125; |
|
|
multilineVars.havent_set_length = false; |
|
|
} |
|
|
return {type: 'tempus_perfectum'}; |
|
|
} else if (line === 'c') { |
|
|
if (multilineVars.havent_set_length === true) { |
|
|
multilineVars.default_length = 0.125; |
|
|
multilineVars.havent_set_length = false; |
|
|
} |
|
|
return {type: 'tempus_imperfectum'}; |
|
|
} else if (line === 'o.') { |
|
|
if (multilineVars.havent_set_length === true) { |
|
|
multilineVars.default_length = 0.125; |
|
|
multilineVars.havent_set_length = false; |
|
|
} |
|
|
return {type: 'tempus_perfectum_prolatio'}; |
|
|
} else if (line === 'c.') { |
|
|
if (multilineVars.havent_set_length === true) { |
|
|
multilineVars.default_length = 0.125; |
|
|
multilineVars.havent_set_length = false; |
|
|
} |
|
|
return {type: 'tempus_imperfectum_prolatio'}; |
|
|
} else if (line.length === 0 || line.toLowerCase() === 'none') { |
|
|
if (multilineVars.havent_set_length === true) { |
|
|
multilineVars.default_length = 0.125; |
|
|
multilineVars.havent_set_length = false; |
|
|
} |
|
|
return null; |
|
|
} |
|
|
else |
|
|
{ |
|
|
var tokens = tokenizer.tokenize(line, 0, line.length); |
|
|
|
|
|
try { |
|
|
var parseNum = function() { |
|
|
|
|
|
var ret = {value: 0, num: ""}; |
|
|
|
|
|
var tok = tokens.shift(); |
|
|
if (tok.token === '(') |
|
|
tok = tokens.shift(); |
|
|
while (1) { |
|
|
if (tok.type !== 'number') throw "Expected top number of meter"; |
|
|
ret.value += parseInt(tok.token); |
|
|
ret.num += tok.token; |
|
|
if (tokens.length === 0 || tokens[0].token === '/') return ret; |
|
|
tok = tokens.shift(); |
|
|
if (tok.token === ')') { |
|
|
if (tokens.length === 0 || tokens[0].token === '/') return ret; |
|
|
throw "Unexpected paren in meter"; |
|
|
} |
|
|
if (tok.token !== '.' && tok.token !== '+') throw "Expected top number of meter"; |
|
|
ret.num += tok.token; |
|
|
if (tokens.length === 0) throw "Expected top number of meter"; |
|
|
tok = tokens.shift(); |
|
|
} |
|
|
return ret; |
|
|
}; |
|
|
|
|
|
var parseFraction = function() { |
|
|
|
|
|
var ret = parseNum(); |
|
|
if (tokens.length === 0) return ret; |
|
|
var tok = tokens.shift(); |
|
|
if (tok.token !== '/') throw "Expected slash in meter"; |
|
|
tok = tokens.shift(); |
|
|
if (tok.type !== 'number') throw "Expected bottom number of meter"; |
|
|
ret.den = tok.token; |
|
|
ret.value = ret.value / parseInt(ret.den); |
|
|
return ret; |
|
|
}; |
|
|
|
|
|
if (tokens.length === 0) throw "Expected meter definition in M: line"; |
|
|
var meter = {type: 'specified', value: [ ]}; |
|
|
var totalLength = 0; |
|
|
while (1) { |
|
|
var ret = parseFraction(); |
|
|
totalLength += ret.value; |
|
|
var mv = { num: ret.num }; |
|
|
if (ret.den !== undefined) |
|
|
mv.den = ret.den; |
|
|
meter.value.push(mv); |
|
|
if (tokens.length === 0) break; |
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
if (multilineVars.havent_set_length === true) { |
|
|
multilineVars.default_length = totalLength < 0.75 ? 0.0625 : 0.125; |
|
|
multilineVars.havent_set_length = false; |
|
|
} |
|
|
return meter; |
|
|
} catch (e) { |
|
|
warn(e, line, 0); |
|
|
} |
|
|
} |
|
|
return null; |
|
|
}; |
|
|
|
|
|
this.calcTempo = function(relTempo) { |
|
|
var dur = 1/4; |
|
|
if (multilineVars.meter && multilineVars.meter.type === 'specified') { |
|
|
dur = 1 / parseInt(multilineVars.meter.value[0].den); |
|
|
} else if (multilineVars.origMeter && multilineVars.origMeter.type === 'specified') { |
|
|
dur = 1 / parseInt(multilineVars.origMeter.value[0].den); |
|
|
} |
|
|
|
|
|
for (var i = 0; i < relTempo.duration; i++) |
|
|
relTempo.duration[i] = dur * relTempo.duration[i]; |
|
|
return relTempo; |
|
|
}; |
|
|
|
|
|
this.resolveTempo = function() { |
|
|
if (multilineVars.tempo) { |
|
|
this.calcTempo(multilineVars.tempo); |
|
|
tune.metaText.tempo = multilineVars.tempo; |
|
|
delete multilineVars.tempo; |
|
|
} |
|
|
}; |
|
|
|
|
|
this.addUserDefinition = function(line, start, end) { |
|
|
var equals = line.indexOf('=', start); |
|
|
if (equals === -1) { |
|
|
warn("Need an = in a macro definition", line, start); |
|
|
return; |
|
|
} |
|
|
|
|
|
var before = parseCommon.strip(line.substring(start, equals)); |
|
|
var after = parseCommon.strip(line.substring(equals+1)); |
|
|
|
|
|
if (before.length !== 1) { |
|
|
warn("Macro definitions can only be one character", line, start); |
|
|
return; |
|
|
} |
|
|
var legalChars = "HIJKLMNOPQRSTUVWXYhijklmnopqrstuvw~"; |
|
|
if (legalChars.indexOf(before) === -1) { |
|
|
warn("Macro definitions must be H-Y, h-w, or tilde", line, start); |
|
|
return; |
|
|
} |
|
|
if (after.length === 0) { |
|
|
warn("Missing macro definition", line, start); |
|
|
return; |
|
|
} |
|
|
if (multilineVars.macros === undefined) |
|
|
multilineVars.macros = {}; |
|
|
multilineVars.macros[before] = after; |
|
|
}; |
|
|
|
|
|
this.setDefaultLength = function(line, start, end) { |
|
|
var len = line.substring(start, end).replace(/ /g, ""); |
|
|
var len_arr = len.split('/'); |
|
|
if (len_arr.length === 2) { |
|
|
var n = parseInt(len_arr[0]); |
|
|
var d = parseInt(len_arr[1]); |
|
|
if (d > 0) { |
|
|
multilineVars.default_length = n / d; |
|
|
multilineVars.havent_set_length = false; |
|
|
} |
|
|
} else if (len_arr.length === 1 && len_arr[0] === '1') { |
|
|
multilineVars.default_length = 1; |
|
|
multilineVars.havent_set_length = false; |
|
|
} |
|
|
}; |
|
|
|
|
|
|
|
|
var tempoString = { |
|
|
|
|
|
larghissimo: 20, |
|
|
adagissimo: 24, |
|
|
sostenuto: 28, |
|
|
grave: 32, |
|
|
largo: 40, |
|
|
lento: 50, |
|
|
larghetto: 60, |
|
|
adagio: 68, |
|
|
adagietto: 74, |
|
|
andante: 80, |
|
|
andantino: 88, |
|
|
"marcia moderato": 84, |
|
|
"andante moderato": 100, |
|
|
moderato: 112, |
|
|
allegretto: 116, |
|
|
"allegro moderato": 120, |
|
|
allegro: 126, |
|
|
animato: 132, |
|
|
agitato: 140, |
|
|
veloce: 148, |
|
|
"mosso vivo": 156, |
|
|
vivace: 164, |
|
|
vivacissimo: 172, |
|
|
allegrissimo: 176, |
|
|
presto: 184, |
|
|
prestissimo: 210, |
|
|
}; |
|
|
|
|
|
this.setTempo = function(line, start, end, iChar) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
var tokens = tokenizer.tokenize(line, start, end); |
|
|
|
|
|
if (tokens.length === 0) throw "Missing parameter in Q: field"; |
|
|
|
|
|
var tempo = { startChar: iChar+start-2, endChar: iChar+end }; |
|
|
var delaySet = true; |
|
|
var token = tokens.shift(); |
|
|
if (token.type === 'quote') { |
|
|
tempo.preString = token.token; |
|
|
token = tokens.shift(); |
|
|
if (tokens.length === 0) { |
|
|
|
|
|
if (tempoString[tempo.preString.toLowerCase()]) { |
|
|
tempo.bpm = tempoString[tempo.preString.toLowerCase()]; |
|
|
tempo.suppressBpm = true; |
|
|
} |
|
|
return {type: 'immediate', tempo: tempo}; |
|
|
} |
|
|
} |
|
|
if (token.type === 'alpha' && token.token === 'C') { |
|
|
if (tokens.length === 0) throw "Missing tempo after C in Q: field"; |
|
|
token = tokens.shift(); |
|
|
if (token.type === 'punct' && token.token === '=') { |
|
|
|
|
|
if (tokens.length === 0) throw "Missing tempo after = in Q: field"; |
|
|
token = tokens.shift(); |
|
|
if (token.type !== 'number') throw "Expected number after = in Q: field"; |
|
|
tempo.duration = [1]; |
|
|
tempo.bpm = parseInt(token.token); |
|
|
} else if (token.type === 'number') { |
|
|
|
|
|
tempo.duration = [parseInt(token.token)]; |
|
|
if (tokens.length === 0) throw "Missing = after duration in Q: field"; |
|
|
token = tokens.shift(); |
|
|
if (token.type !== 'punct' || token.token !== '=') throw "Expected = after duration in Q: field"; |
|
|
if (tokens.length === 0) throw "Missing tempo after = in Q: field"; |
|
|
token = tokens.shift(); |
|
|
if (token.type !== 'number') throw "Expected number after = in Q: field"; |
|
|
tempo.bpm = parseInt(token.token); |
|
|
} else throw "Expected number or equal after C in Q: field"; |
|
|
|
|
|
} else if (token.type === 'number') { |
|
|
var num = parseInt(token.token); |
|
|
if (tokens.length === 0 || tokens[0].type === 'quote') { |
|
|
|
|
|
tempo.duration = [1]; |
|
|
tempo.bpm = num; |
|
|
} else { |
|
|
delaySet = false; |
|
|
token = tokens.shift(); |
|
|
if (token.type !== 'punct' && token.token !== '/') throw "Expected fraction in Q: field"; |
|
|
token = tokens.shift(); |
|
|
if (token.type !== 'number') throw "Expected fraction in Q: field"; |
|
|
var den = parseInt(token.token); |
|
|
tempo.duration = [num/den]; |
|
|
|
|
|
while (tokens.length > 0 && tokens[0].token !== '=' && tokens[0].type !== 'quote') { |
|
|
token = tokens.shift(); |
|
|
if (token.type !== 'number') throw "Expected fraction in Q: field"; |
|
|
num = parseInt(token.token); |
|
|
token = tokens.shift(); |
|
|
if (token.type !== 'punct' && token.token !== '/') throw "Expected fraction in Q: field"; |
|
|
token = tokens.shift(); |
|
|
if (token.type !== 'number') throw "Expected fraction in Q: field"; |
|
|
den = parseInt(token.token); |
|
|
tempo.duration.push(num/den); |
|
|
} |
|
|
token = tokens.shift(); |
|
|
if (token.type !== 'punct' && token.token !== '=') throw "Expected = in Q: field"; |
|
|
token = tokens.shift(); |
|
|
if (token.type !== 'number') throw "Expected tempo in Q: field"; |
|
|
tempo.bpm = parseInt(token.token); |
|
|
} |
|
|
} else throw "Unknown value in Q: field"; |
|
|
if (tokens.length !== 0) { |
|
|
token = tokens.shift(); |
|
|
if (token.type === 'quote') { |
|
|
tempo.postString = token.token; |
|
|
token = tokens.shift(); |
|
|
} |
|
|
if (tokens.length !== 0) throw "Unexpected string at end of Q: field"; |
|
|
} |
|
|
if (multilineVars.printTempo === false) |
|
|
tempo.suppress = true; |
|
|
return {type: delaySet?'delaySet':'immediate', tempo: tempo}; |
|
|
} catch (msg) { |
|
|
warn(msg, line, start); |
|
|
return {type: 'none'}; |
|
|
} |
|
|
}; |
|
|
|
|
|
this.letter_to_inline_header = function(line, i, startLine) |
|
|
{ |
|
|
var needsNewLine = false |
|
|
var ws = tokenizer.eatWhiteSpace(line, i); |
|
|
i +=ws; |
|
|
if (line.length >= i+5 && line[i] === '[' && line[i+2] === ':') { |
|
|
var e = line.indexOf(']', i); |
|
|
var startChar = multilineVars.iChar + i; |
|
|
var endChar = multilineVars.iChar + e + 1; |
|
|
switch(line.substring(i, i+3)) |
|
|
{ |
|
|
case "[I:": |
|
|
var err = parseDirective.addDirective(line.substring(i+3, e)); |
|
|
if (err) warn(err, line, i); |
|
|
return [ e-i+1+ws ]; |
|
|
case "[M:": |
|
|
var meter = this.setMeter(line.substring(i+3, e)); |
|
|
if (tuneBuilder.hasBeginMusic() && meter) |
|
|
tuneBuilder.appendStartingElement('meter', startChar, endChar, meter); |
|
|
else |
|
|
multilineVars.meter = meter; |
|
|
return [ e-i+1+ws ]; |
|
|
case "[K:": |
|
|
var result = parseKeyVoice.parseKey(line.substring(i+3, e), true); |
|
|
if (result.foundClef && tuneBuilder.hasBeginMusic()) |
|
|
tuneBuilder.appendStartingElement('clef', startChar, endChar, multilineVars.clef); |
|
|
if (result.foundKey && tuneBuilder.hasBeginMusic()) |
|
|
tuneBuilder.appendStartingElement('key', startChar, endChar, parseKeyVoice.fixKey(multilineVars.clef, multilineVars.key)); |
|
|
return [ e-i+1+ws ]; |
|
|
case "[P:": |
|
|
var part = parseDirective.parseFontChangeLine(line.substring(i+3, e)) |
|
|
if (startLine || tune.lines.length <= tune.lineNum) |
|
|
multilineVars.partForNextLine = { title: part, startChar: startChar, endChar: endChar }; |
|
|
else |
|
|
tuneBuilder.appendElement('part', startChar, endChar, {title: part}); |
|
|
return [ e-i+1+ws ]; |
|
|
case "[L:": |
|
|
this.setDefaultLength(line, i+3, e); |
|
|
return [ e-i+1+ws ]; |
|
|
case "[Q:": |
|
|
if (e > 0) { |
|
|
var tempo = this.setTempo(line, i+3, e, multilineVars.iChar); |
|
|
if (tempo.type === 'delaySet') { |
|
|
if (tuneBuilder.hasBeginMusic()) |
|
|
tuneBuilder.appendElement('tempo', startChar, endChar, this.calcTempo(tempo.tempo)); |
|
|
else |
|
|
multilineVars.tempoForNextLine = ['tempo', startChar, endChar, this.calcTempo(tempo.tempo)] |
|
|
} else if (tempo.type === 'immediate') { |
|
|
if (!startLine && tuneBuilder.hasBeginMusic()) |
|
|
tuneBuilder.appendElement('tempo', startChar, endChar, tempo.tempo); |
|
|
else |
|
|
multilineVars.tempoForNextLine = ['tempo', startChar, endChar, tempo.tempo] |
|
|
} |
|
|
return [ e-i+1+ws, line[i+1], line.substring(i+3, e)]; |
|
|
} |
|
|
break; |
|
|
case "[V:": |
|
|
if (e > 0) { |
|
|
needsNewLine = parseKeyVoice.parseVoice(line, i+3, e); |
|
|
|
|
|
return [ e-i+1+ws, line[i+1], line.substring(i+3, e), needsNewLine]; |
|
|
} |
|
|
break; |
|
|
case "[r:": |
|
|
return [ e-i+1+ws ]; |
|
|
|
|
|
default: |
|
|
|
|
|
} |
|
|
} |
|
|
return [ 0 ]; |
|
|
}; |
|
|
|
|
|
this.letter_to_body_header = function(line, i) |
|
|
{ |
|
|
var needsNewLine = false |
|
|
if (line.length >= i+3) { |
|
|
switch(line.substring(i, i+2)) |
|
|
{ |
|
|
case "I:": |
|
|
var err = parseDirective.addDirective(line.substring(i+2)); |
|
|
if (err) warn(err, line, i); |
|
|
return [ line.length ]; |
|
|
case "M:": |
|
|
var meter = this.setMeter(line.substring(i+2)); |
|
|
if (tuneBuilder.hasBeginMusic() && meter) |
|
|
tuneBuilder.appendStartingElement('meter', multilineVars.iChar + i, multilineVars.iChar + line.length, meter); |
|
|
return [ line.length ]; |
|
|
case "K:": |
|
|
var result = parseKeyVoice.parseKey(line.substring(i+2), tuneBuilder.hasBeginMusic()); |
|
|
if (result.foundClef && tuneBuilder.hasBeginMusic()) |
|
|
tuneBuilder.appendStartingElement('clef', multilineVars.iChar + i, multilineVars.iChar + line.length, multilineVars.clef); |
|
|
if (result.foundKey && tuneBuilder.hasBeginMusic()) |
|
|
tuneBuilder.appendStartingElement('key', multilineVars.iChar + i, multilineVars.iChar + line.length, parseKeyVoice.fixKey(multilineVars.clef, multilineVars.key)); |
|
|
return [ line.length ]; |
|
|
case "P:": |
|
|
if (tuneBuilder.hasBeginMusic()) |
|
|
tuneBuilder.appendElement('part', multilineVars.iChar + i, multilineVars.iChar + line.length, {title: line.substring(i+2)}); |
|
|
return [ line.length ]; |
|
|
case "L:": |
|
|
this.setDefaultLength(line, i+2, line.length); |
|
|
return [ line.length ]; |
|
|
case "Q:": |
|
|
var e = line.indexOf('\x12', i+2); |
|
|
if (e === -1) e = line.length; |
|
|
var tempo = this.setTempo(line, i+2, e, multilineVars.iChar); |
|
|
if (tempo.type === 'delaySet') tuneBuilder.appendElement('tempo', multilineVars.iChar + i, multilineVars.iChar + line.length, this.calcTempo(tempo.tempo)); |
|
|
else if (tempo.type === 'immediate') tuneBuilder.appendElement('tempo', multilineVars.iChar + i, multilineVars.iChar + line.length, tempo.tempo); |
|
|
return [ e, line[i], parseCommon.strip(line.substring(i+2))]; |
|
|
case "V:": |
|
|
needsNewLine = parseKeyVoice.parseVoice(line, i+2, line.length); |
|
|
|
|
|
return [ line.length, line[i], parseCommon.strip(line.substring(i+2)), needsNewLine]; |
|
|
default: |
|
|
|
|
|
} |
|
|
} |
|
|
return [ 0 ]; |
|
|
}; |
|
|
|
|
|
var metaTextHeaders = { |
|
|
A: 'author', |
|
|
B: 'book', |
|
|
C: 'composer', |
|
|
D: 'discography', |
|
|
F: 'url', |
|
|
G: 'group', |
|
|
I: 'instruction', |
|
|
N: 'notes', |
|
|
O: 'origin', |
|
|
R: 'rhythm', |
|
|
S: 'source', |
|
|
W: 'unalignedWords', |
|
|
Z: 'transcription' |
|
|
}; |
|
|
|
|
|
this.parseHeader = function(line) { |
|
|
var field = metaTextHeaders[line[0]]; |
|
|
var origSize = line.length-2 |
|
|
var restOfLine = tokenizer.translateString(tokenizer.stripComment(line.substring(2))) |
|
|
if (field === 'unalignedWords' || field === 'notes') { |
|
|
|
|
|
tuneBuilder.addMetaTextArray(field, parseDirective.parseFontChangeLine(restOfLine), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length}); |
|
|
} else if (field !== undefined) { |
|
|
|
|
|
tuneBuilder.addMetaText(field, parseDirective.parseFontChangeLine(restOfLine), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length}); |
|
|
} else { |
|
|
var startChar = multilineVars.iChar; |
|
|
var endChar = startChar + line.length; |
|
|
switch(line[0]) |
|
|
{ |
|
|
case 'H': |
|
|
|
|
|
tuneBuilder.addMetaTextArray("history", parseDirective.parseFontChangeLine(restOfLine), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length}); |
|
|
line = tokenizer.peekLine() |
|
|
while (line && line[1] !== ':') { |
|
|
tokenizer.nextLine() |
|
|
tuneBuilder.addMetaTextArray("history", parseDirective.parseFontChangeLine(tokenizer.translateString(tokenizer.stripComment(line))), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length}); |
|
|
line = tokenizer.peekLine() |
|
|
} |
|
|
break; |
|
|
case 'K': |
|
|
|
|
|
this.resolveTempo(); |
|
|
var result = parseKeyVoice.parseKey(line.substring(2), false); |
|
|
if (!multilineVars.is_in_header && tuneBuilder.hasBeginMusic()) { |
|
|
if (result.foundClef) |
|
|
tuneBuilder.appendStartingElement('clef', startChar, endChar, multilineVars.clef); |
|
|
if (result.foundKey) |
|
|
tuneBuilder.appendStartingElement('key', startChar, endChar, parseKeyVoice.fixKey(multilineVars.clef, multilineVars.key)); |
|
|
} |
|
|
multilineVars.is_in_header = false; |
|
|
break; |
|
|
case 'L': |
|
|
this.setDefaultLength(line, 2, line.length); |
|
|
break; |
|
|
case 'M': |
|
|
multilineVars.origMeter = multilineVars.meter = this.setMeter(line.substring(2)); |
|
|
break; |
|
|
case 'P': |
|
|
|
|
|
if (multilineVars.is_in_header) |
|
|
tuneBuilder.addMetaText("partOrder", parseDirective.parseFontChangeLine(restOfLine), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length}); |
|
|
else |
|
|
multilineVars.partForNextLine = { title: restOfLine, startChar: startChar, endChar: endChar}; |
|
|
break; |
|
|
case 'Q': |
|
|
var tempo = this.setTempo(line, 2, line.length, multilineVars.iChar); |
|
|
if (tempo.type === 'delaySet') multilineVars.tempo = tempo.tempo; |
|
|
else if (tempo.type === 'immediate') { |
|
|
if (!tune.metaText.tempo) |
|
|
tune.metaText.tempo = tempo.tempo; |
|
|
else |
|
|
multilineVars.tempoForNextLine = ['tempo', startChar, endChar, tempo.tempo] |
|
|
} |
|
|
break; |
|
|
case 'T': |
|
|
if (multilineVars.titlecaps) |
|
|
restOfLine = restOfLine.toUpperCase(); |
|
|
this.setTitle(parseDirective.parseFontChangeLine(tokenizer.theReverser(restOfLine)), origSize); |
|
|
break; |
|
|
case 'U': |
|
|
this.addUserDefinition(line, 2, line.length); |
|
|
break; |
|
|
case 'V': |
|
|
parseKeyVoice.parseVoice(line, 2, line.length); |
|
|
if (!multilineVars.is_in_header) |
|
|
return {newline: true}; |
|
|
break; |
|
|
case 's': |
|
|
return {symbols: true}; |
|
|
case 'w': |
|
|
return {words: true}; |
|
|
case 'X': |
|
|
break; |
|
|
case 'E': |
|
|
case 'm': |
|
|
warn("Ignored header", line, 0); |
|
|
break; |
|
|
default: |
|
|
return {regular: true}; |
|
|
} |
|
|
} |
|
|
return {}; |
|
|
}; |
|
|
}; |
|
|
|
|
|
module.exports = ParseHeader; |
|
|
|