#!/usr/bin/python # -*- coding: utf-8 -*- from lxml import etree import sys import getopt NOTE_TYPE= ["whole", "half", "quarter", "eighth", "16th", "32nd", "64th"] NOTE_TYPE_MULT=[ 4, 2, 1, 0.5, 0.25, 0.125, 0.0625] def noteTypeToIndex(s): i=0 for st in NOTE_TYPE: if s==st: return i i=i+1 return -1 def fretToMidi(string, fret): tab=[0,40,45,50,55,59,64] tab=[0,64,59,55,50,45,40] return tab[string]+fret def xpathExists(obj, path): for x in obj.xpath(path): return True return False def xpathFirst(d, path): for x in d.xpath(path): return x return None class Note: def __init__(self, data): self.octave=0 self.note="R" self.corde=0 self.fret=0 self.midiNote=0 if xpathExists(data,"rest"): self.rest=True else: self.rest=False self.octave=int(xpathFirst(data,"pitch/octave").text) self.note=xpathFirst(data,"pitch/step").text self.corde=int(xpathFirst(data,"notations/technical/string").text) self.fret=int(xpathFirst(data,"notations/technical/fret").text) self.midiNote=fretToMidi(self.corde, self.fret) self.type=noteTypeToIndex(xpathFirst(data,"type").text) self.duree=int(xpathFirst(data,"duration").text) self.voix=int(xpathFirst(data,"voice").text) self.dot=xpathExists(data, "dot") self.beatmult=NOTE_TYPE_MULT[self.type] if self.dot: self.beatmult=1.5*self.beatmult def getMidi(self): return self.midiNote def getTime(self): return self.beatmult def show(self): print(str(self.getMidi())+": \""+str(self.type)+"\" "+str(self.dot)+" "+str(self.rest)) class Measure: def __init__(self, data): self.notes=[] try: self.beats=int(xpathFirst(data, "attributes/time/beats").text) self.beatType=int(xpathFirst(data, "attributes/time/beat-type").text) except: self.notes=[] def addNote(self, note): self.notes.append(note) def noteToString(self): s="" i=0 for x in self.notes: if i>0: s+=", " s+=str(self.notes[i].getTime()) i+=1 return s def timeToString(self): s="" i=0 for x in self.notes: if i>0: s+=", " s+=str(self.notes[i].getTime()) i+=1 return s class Part: def __init__(self, data): self.id=data.get("id") self.notes=[] self.beat=0 self.beatType=0 path="/score-partwise/part-list/score-part[@id='"+self.id+"']/" self.name=xpathFirst(data, path+"part-name").text self.instrument=xpathFirst(data, path+"score-instrument/instrument-name").text self.midiChannel=xpathFirst(data, path+"midi-instrument/midi-channel").text self.midiProgram=xpathFirst(data, path+"midi-instrument/midi-program").text self.measures=[] for d in data.xpath("measure"): m=Measure(d) self.measures.append(m) for n in d.xpath("note"): note=Note(n) self.notes.append(note) m.addNote(note) def length(self): tot=0 for x in self.notes: tot+=x.getTime() return tot def toString(self): return self.name+" : (\""+self.instrument+"\", "+str(self.length())+" beats, "+str(len(self.notes))+" notes)" def noteRangeToString(self, start, end): i=start s="" while i<=end: for x in self.measures[i].notes: s+= ("" if s=="" else ", ")+str(x.getMidi()) i+=1 return s def timeRangeToString(self, start, end): i=start s="" while i<=end: for x in self.measures[i].notes: s+= ("" if s=="" else ", ")+str(x.getTime()) i+=1 return s class System: def __init__(self, path): self.path=path self.partition=[] self.tree = etree.parse(self.path) self.parts=[] for data in self.tree.xpath("/score-partwise/part"): self.parts.append(Part(data)) self.bufferNote="" self.bufferTime="" def noteRange(self, i, start, end): x=self.parts[i-1].noteRangeToString(start-1, end-1) self.bufferNote+= ("" if self.bufferNote=="" else ", ")+x return x; def timeRange(self, i, start, end): x=self.parts[i-1].timeRangeToString(start-1, end-1) self.bufferTime+= ("" if self.bufferTime=="" else ", ")+x return x; def note(self, i): return self.noteRange(i, 1, len(self.parts[i-1].measures)); def time(self, i): return self.timeRange(i, 1, len(self.parts[i-1].measures)); def range(self, i,start, end): self.timeRange(i, start, end) self.noteRange(i, start, end) def track(self, i): self.time(i) self.note(i) def before(self, i, n): self.timeRange(i, 1, n) self.noteRange(i, 1, n) def after(self, i, n): self.timeRange(i, n, len(self.parts[i-1].measures)) self.noteRange(i, n, len(self.parts[i-1].measures)) def new(self): self.bufferNote="" self.bufferTime="" def write(self, f): fd = open(f, "w") fd.write("notes=(ring "+self.bufferNote+")") fd.write("times=(ring "+self.bufferTime+")") fd.close() def print(self): print("notes=(ring "+self.bufferNote+")") print("times=(ring "+self.bufferTime+")") def list(self): i=0 for x in self.parts: print("["+str(i)+"] : "+x.toString()) i+=1 if __name__ == '__main__': def usage(): print("Usage:") print(sys.argv[0]+" PATH_TO_XML [COMMANDS]") print("ou " +sys.argv[0]+" -h | --help : Affiche cette aide") print("ou " +sys.argv[0]+" -l | --list : Liste les pistes") print("COMMANDS:") print("\t-n | --new : Vide le buffer courant") print("\t-r | --range TRACK START END : Ajoute les mesure de la piste TRACK entre les mesure START et END") print("\t-b | --before TRACK INDEX : Ajoute les mesure de la piste TRACK jusqu'a la mesure INDEX") print("\t-a | --after TRACK INDEX : Ajoute les mesure de la piste TRACK à partir de la mesure INDEX") print("\t-t | --track TRACK : Ajoute toutes la piste TRACK au buffer") print("\t-p | --print : Affiche le buffer courant") print("\t-w | --write FILE : Ecrit le buffer dans le fichier FILE") song=None path="/home/fanch/Documents/tabs/Johann Pachelbel - Canon In D (ver 6 by Ezechiel).xml" i=1 op=False if len(sys.argv)==1: usage() sys.exit(-1) while i