mirror of
https://github.com/microtherion/VocalEasel.git
synced 2024-12-22 11:14:00 +00:00
Added VLMusicXMLType.reader
This commit is contained in:
parent
8d3e5f6801
commit
9cd9e146f0
172
Filters/VLMusicXMLType.reader
Executable file
172
Filters/VLMusicXMLType.reader
Executable file
|
@ -0,0 +1,172 @@
|
|||
#!/usr/bin/ruby
|
||||
#
|
||||
# VLMusicXMLType.reader - Create plist from MusicXML
|
||||
#
|
||||
|
||||
require File.dirname($0)+'/plistWriter'
|
||||
require File.dirname($0)+'/vl'
|
||||
require 'rexml/document'
|
||||
|
||||
XML = REXML::Document.new $stdin
|
||||
ROOT = XML.root
|
||||
OUTPUT = {}
|
||||
|
||||
if ROOT.name == "score-timewise"
|
||||
$stderr.puts "Can't read timewise MusicXML files yet"
|
||||
exit 1
|
||||
end
|
||||
|
||||
def textOrNot(elt)
|
||||
return elt ? elt.text : ""
|
||||
end
|
||||
|
||||
OUTPUT['title'] =
|
||||
textOrNot ROOT.elements['./work/work-title']
|
||||
OUTPUT['composer'] =
|
||||
textOrNot ROOT.elements['./identification/creator[@type="composer"]']
|
||||
OUTPUT['lyricist'] =
|
||||
textOrNot ROOT.elements['./identification/creator[@type="poet"]']
|
||||
OUTPUT['groove'] =
|
||||
textOrNot ROOT.elements['./identification/miscellaneous-field[@name="VocalEasel-groove"]']
|
||||
|
||||
CHORDS = ROOT.elements['./part[@id="HARM"]']
|
||||
MELODY = ROOT.elements['./part[@id="MELO"]']
|
||||
PROP = {}
|
||||
$LASTPROP = nil
|
||||
|
||||
OUTPUT['measures'] = []
|
||||
OUTPUT['properties'] = []
|
||||
|
||||
def updateProp(meas)
|
||||
if attr = meas.elements['./attributes']
|
||||
if div = attr.elements['./divisions']
|
||||
PROP['divisions'] = div.text.to_i
|
||||
end
|
||||
if key = attr.elements['./key/fifths']
|
||||
PROP['key'] = key.text.to_i
|
||||
end
|
||||
if mode = attr.elements['./key/mode']
|
||||
PROP['mode'] = mode.text == 'minor' ? -1 : 1
|
||||
end
|
||||
if timeNum = attr.elements['./time/beats']
|
||||
PROP['timeNum'] = timeNum.text.to_i
|
||||
end
|
||||
if timeDenom = attr.elements['./time/beat-type']
|
||||
PROP['timeDenom'] = timeDenom.text.to_i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
PITCH = {
|
||||
'C' => 0,
|
||||
'D' => 2,
|
||||
'E' => 4,
|
||||
'F' => 5,
|
||||
'G' => 7,
|
||||
'A' => 9,
|
||||
'B' => 11
|
||||
}
|
||||
|
||||
def parseNote(note)
|
||||
n = {}
|
||||
if note.elements['./rest']
|
||||
n['pitch'] = -128
|
||||
else
|
||||
step = note.elements['./pitch/step']
|
||||
alter = note.elements['./pitch/alter']
|
||||
octave = note.elements['./pitch/octave']
|
||||
n['pitch'] = (step ? PITCH[step.text] : 0) +
|
||||
(alter ? alter.text.to_i : 0) +
|
||||
(octave ? octave.text.to_i+1 : 0)*12
|
||||
end
|
||||
if dur = note.elements['./duration']
|
||||
n['durNum'] = dur.text.to_i
|
||||
n['durDenom'] = PROP['divisions']*4
|
||||
end
|
||||
if note.elements['./tie']
|
||||
n['tied'] = 0
|
||||
if note.elements['./tie[@type="start"]']
|
||||
n['tied'] |= VL::TiedWithNext
|
||||
end
|
||||
if note.elements['./tie[@type="stop"]']
|
||||
n['tied'] |= VL::TiedWithPrev
|
||||
end
|
||||
end
|
||||
return n
|
||||
end
|
||||
|
||||
def makeChord(root, steps, num, denom)
|
||||
chord = {}
|
||||
chord['root'] = root
|
||||
chord['durNum'] = num
|
||||
chord['durDenom'] = denom
|
||||
st = steps.sort
|
||||
pitch = st[0] || -128
|
||||
steps = 0
|
||||
st.each do |step|
|
||||
steps |= 1<<(step-pitch)
|
||||
end
|
||||
chord['pitch'] = pitch
|
||||
chord['steps'] = steps
|
||||
|
||||
return chord
|
||||
end
|
||||
|
||||
CHORDS.elements.each('measure') do |meas|
|
||||
updateProp meas
|
||||
chords = []
|
||||
root = -128
|
||||
steps= []
|
||||
num = nil
|
||||
denom= nil
|
||||
meas.elements.each('note') do |note|
|
||||
if !note.elements['./chord'] && num
|
||||
chords.push makeChord(root, steps, num, denom)
|
||||
root = -128
|
||||
steps= []
|
||||
num = nil
|
||||
denom= nil
|
||||
end
|
||||
note = parseNote(note)
|
||||
num ||= note['durNum']
|
||||
denom||= note['durDenom']
|
||||
if note['pitch'] < 60
|
||||
root = note['pitch']
|
||||
else
|
||||
steps.push note['pitch']
|
||||
end
|
||||
end
|
||||
chords.push makeChord(root, steps, num, denom) if num
|
||||
measNo = meas.attributes['number'].to_i-1
|
||||
OUTPUT['measures'][measNo] = {
|
||||
'measure' => measNo,
|
||||
'properties' => 0,
|
||||
'chords' => chords,
|
||||
'melody' => []
|
||||
}
|
||||
end
|
||||
|
||||
MELODY.elements.each('measure') do |meas|
|
||||
updateProp meas
|
||||
if PROP != $LASTPROP
|
||||
OUTPUT['properties'].push PROP
|
||||
$LASTPROP = PROP
|
||||
end
|
||||
melody = []
|
||||
meas.elements.each('note') do |note|
|
||||
melody.push parseNote(note)
|
||||
end
|
||||
measNo = meas.attributes['number'].to_i-1
|
||||
OUTPUT['measures'][measNo] ||= {
|
||||
'measure'=> measNo,
|
||||
'chords' => []
|
||||
}
|
||||
OUTPUT['measures'][measNo]['properties'] = OUTPUT['properties'].length-1
|
||||
OUTPUT['measures'][measNo]['melody'] = melody
|
||||
end
|
||||
|
||||
writePlist($stdout, OUTPUT)
|
||||
|
||||
# Local Variables:
|
||||
# mode:ruby
|
||||
# End:
|
|
@ -47,7 +47,7 @@ def _encodePlist(object)
|
|||
e.add_element(_encodePlist(elt))
|
||||
end
|
||||
else
|
||||
raise "plistWriter can't encode objects of type `#{object.class}'[#{object.class.id}]"
|
||||
raise "plistWriter can't encode objects of type `#{object.class}'"
|
||||
end
|
||||
|
||||
return e
|
||||
|
|
|
@ -219,8 +219,10 @@ void VLPlistVisitor::VisitChord(VLChord & c)
|
|||
NSDictionary * ndict = [ne nextObject];
|
||||
) {
|
||||
VLLyricsNote note;
|
||||
note.fDuration.fNum = [[ndict objectForKey:@"durNum"] intValue];
|
||||
note.fDuration.fDenom = [[ndict objectForKey:@"durDenom"] intValue];
|
||||
note.fDuration =
|
||||
VLFraction([[ndict objectForKey:@"durNum"] intValue],
|
||||
[[ndict objectForKey:@"durDenom"] intValue],
|
||||
true);
|
||||
note.fPitch = [[ndict objectForKey:@"pitch"] intValue];
|
||||
note.fTied = 0;
|
||||
|
||||
|
@ -272,8 +274,10 @@ advanceAt:
|
|||
NSDictionary * cdict = [ce nextObject];
|
||||
) {
|
||||
VLChord chord;
|
||||
chord.fDuration.fNum = [[cdict objectForKey:@"durNum"] intValue];
|
||||
chord.fDuration.fDenom = [[cdict objectForKey:@"durDenom"] intValue];
|
||||
chord.fDuration =
|
||||
VLFraction([[ndict objectForKey:@"durNum"] intValue],
|
||||
[[ndict objectForKey:@"durDenom"] intValue],
|
||||
true);
|
||||
chord.fPitch = [[cdict objectForKey:@"pitch"] intValue];
|
||||
chord.fRootPitch = [[cdict objectForKey:@"root"] intValue];
|
||||
chord.fSteps = [[cdict objectForKey:@"steps"] intValue];
|
||||
|
@ -356,8 +360,10 @@ advanceAt:
|
|||
) {
|
||||
VLProperties prop;
|
||||
|
||||
prop.fTime.fNum = [[pdict objectForKey:@"timeNum"] intValue];
|
||||
prop.fTime.fDenom = [[pdict objectForKey:@"timeDenom"] intValue];
|
||||
prop.fTime =
|
||||
VLFraction([[ndict objectForKey:@"timeNum"] intValue],
|
||||
[[ndict objectForKey:@"timeDenom"] intValue],
|
||||
false);
|
||||
prop.fKey = [[pdict objectForKey:@"key"] intValue];
|
||||
prop.fMode = [[pdict objectForKey:@"mode"] intValue];
|
||||
prop.fDivisions = [[pdict objectForKey:@"divisions"] intValue];
|
||||
|
|
Loading…
Reference in New Issue
Block a user