mirror of
https://github.com/kastdeur/bwwtolily.git
synced 2025-06-18 05:06:38 +02:00
Compare commits
8 commits
Author | SHA1 | Date | |
---|---|---|---|
8eb1e5021e | |||
![]() |
ab2ad69d75 | ||
![]() |
9a43ba9688 | ||
![]() |
b9bfeed838 | ||
![]() |
b29a4fd5d9 | ||
![]() |
075ecbf087 | ||
![]() |
d5e4378d3f | ||
![]() |
bb079e8b02 |
2 changed files with 110 additions and 45 deletions
20
README.md
20
README.md
|
@ -1,17 +1,21 @@
|
||||||
bwwtolily will attempt to convert a .bww or .bmw file to a lilypond
|
Convert Bagpipe Reader to Lilypond
|
||||||
(http://lilypond.org) parsable file. Not all of the embellishments
|
==================================
|
||||||
get converted properly, this is espessially true with piobaireachd,
|
|
||||||
|
This is a utility to convert a .bww or .bmw file to a [lilypond](https://lilypond.org) parsable file.
|
||||||
|
Not all of the embellishments get converted properly, this is espessially true with piobaireachd,
|
||||||
and the program will list the embellishments that were not converted.
|
and the program will list the embellishments that were not converted.
|
||||||
|
|
||||||
If you recognize an embellishment that isn't being parsed, please
|
If you recognize an embellishment that isn't being parsed, please
|
||||||
send an email regarding the embellishment to jezra@jezra.net and I
|
create an [issue on github](https://github.com/kastdeur/bwwtolily/issues)
|
||||||
will try to add the embellishment to the application.
|
|
||||||
|
|
||||||
usage:
|
usage:
|
||||||
>bwwtolily -i /path/to/a/bww/file
|
```
|
||||||
|
$ bwwtolily /path/to/a/bww/file
|
||||||
|
```
|
||||||
|
|
||||||
optionally, using the "-l" flag will try to run lilypond on the
|
optionally, using the "-l" flag will try to run lilypond on the
|
||||||
created .ly file
|
created .ly file
|
||||||
example:
|
example:
|
||||||
>bwwtolily -i /path/to/bww/file -l
|
```
|
||||||
|
$ bwwtolily /path/to/bww/file -l
|
||||||
|
```
|
||||||
|
|
135
bwwtolily.py
135
bwwtolily.py
|
@ -2,12 +2,13 @@
|
||||||
#
|
#
|
||||||
#bwwtolily: will convert a bww file to a lilypond file
|
#bwwtolily: will convert a bww file to a lilypond file
|
||||||
#copyright: 2008 Jezra Lickter
|
#copyright: 2008 Jezra Lickter
|
||||||
|
#contributions by ET de Boone
|
||||||
#GPL v3
|
#GPL v3
|
||||||
|
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
import sys,os,re,subprocess
|
import sys,os,re,subprocess
|
||||||
|
|
||||||
version = "0.5.2"
|
version = "0.6.3"
|
||||||
|
|
||||||
#make a print function to handle various version of python
|
#make a print function to handle various version of python
|
||||||
def do_print(string):
|
def do_print(string):
|
||||||
|
@ -23,12 +24,16 @@ class bwwtolily :
|
||||||
self.most_recent_note = 0
|
self.most_recent_note = 0
|
||||||
self.in_note_group=False
|
self.in_note_group=False
|
||||||
self.slur_tie_pending = False
|
self.slur_tie_pending = False
|
||||||
|
self.tuplet_pending = False
|
||||||
self.last_group_close=0
|
self.last_group_close=0
|
||||||
|
|
||||||
'''compile a few regex queries'''
|
'''compile a few regex queries'''
|
||||||
#make a regex to determine if something is a lilypond note
|
#make a regex to determine if something is a lilypond note
|
||||||
self.regex_lilynote= re.compile("[abcdefgAG][0-9]*")
|
self.regex_lilynote= re.compile("[abcdefgAG][0-9]*")
|
||||||
#try to determine the time signature
|
#try to determine the time signature
|
||||||
self.sig_regex = re.compile("([0-9])_([0-9])")
|
self.sig_regex = re.compile("([0-9]{1,2})_([0-9]{1,2})")
|
||||||
|
#alternative time signature for (cut) common time
|
||||||
|
self.sig_regex_common = re.compile("C_\W")
|
||||||
#a regex to find notes
|
#a regex to find notes
|
||||||
self.regex_note_info=re.compile("(?P<note>[A-Z]+)(?P<dir>[a-z]*)_(?P<time>[0-9]{1,2})")
|
self.regex_note_info=re.compile("(?P<note>[A-Z]+)(?P<dir>[a-z]*)_(?P<time>[0-9]{1,2})")
|
||||||
#a regex to find grace notes
|
#a regex to find grace notes
|
||||||
|
@ -49,45 +54,51 @@ class bwwtolily :
|
||||||
self.regex_strike = re.compile("str([h|l]*[abcdefg])")
|
self.regex_strike = re.compile("str([h|l]*[abcdefg])")
|
||||||
#a regex to find dots
|
#a regex to find dots
|
||||||
self.regex_dot = re.compile("'[h|l]*[abcdefg]")
|
self.regex_dot = re.compile("'[h|l]*[abcdefg]")
|
||||||
|
#a regex to find old note ties
|
||||||
|
self.regex_old_tie = re.compile("\^t[h|l]?[abcdfg]")
|
||||||
|
#a regex to find tuplets
|
||||||
|
self.regex_tuplet = re.compile("\^(?P<upper>[0-9])(?P<lower>[0-9]?)(?P<type>[se])")
|
||||||
|
|
||||||
#a regex to find sub repeats
|
#a regex to find sub repeats
|
||||||
self.regex_sub_repeat = re.compile("'([0-9]+)")
|
self.regex_sub_repeat = re.compile("'([0-9]+)")
|
||||||
#a regex to find note slurs, not slur embellishments
|
#a regex to find note slurs, not slur embellishments
|
||||||
self.regex_slur = re.compile("\^(?P<note_count>[0-9])(?P<end_note>[a-z]*)")
|
self.regex_slur = re.compile("\^(?P<note_count>[0-9])(?P<end_note>[a-z]*)")
|
||||||
|
|
||||||
#we need a list to ignore
|
#we need a list to ignore
|
||||||
self.ignore_elements = ("sharpf","sharpc","space","&")
|
self.ignore_elements = ("sharpf","sharpc","space","&", "C")
|
||||||
#create a dictionary of common bww elements and their lily counterparts
|
#create a dictionary of common bww elements and their lily counterparts
|
||||||
self.transpose_dict = {
|
self.transpose_dict = {
|
||||||
"!":"\\bar \"|\"\n",
|
"!":"\\bar \"|\"\n",
|
||||||
"!I":"\\bar \".|\" \\break \n",
|
"!I":"\\bar \".|\" \\break \n",
|
||||||
#"''!I":"\\set Score.repeatCommands = #'( end-repeat ) \\break \n",
|
#"''!I":"\\set Score.repeatCommands = #'( end-repeat ) \\break \n",
|
||||||
"''!I":"\\bar \":|\" \\break\n",
|
"''!I":"\\bar \":|\" \\break\n",
|
||||||
#"''!I":"} \\break \n",
|
#"''!I":"} \\break \n",
|
||||||
"I!''":"\\bar \"|:\"",
|
"I!''":"\\bar \"|:\"",
|
||||||
"I!":"\\bar \"|.\"",
|
"I!":"\\bar \"|.\"",
|
||||||
#"I!''":"\\set Score.repeatCommands = #'( start-repeat )\n",
|
#"I!''":"\\set Score.repeatCommands = #'( start-repeat )\n",
|
||||||
|
|
||||||
#"I!''":"\n\\repeat volta 2 {\n",
|
#"I!''":"\n\\repeat volta 2 {\n",
|
||||||
"_'":"\\set Score.repeatCommands = #'((volta #f)) \\bar \"|\"\n",
|
"_'":"\\set Score.repeatCommands = #'((volta #f)) \\bar \"|\"\n",
|
||||||
"!t":"\\bar \"|\" \\break\n\n",
|
"!t":"\\bar \"|\" \\break\n\n",
|
||||||
"thrd":"\\thrwd",
|
"thrd":"\\thrwd",
|
||||||
"hvthrd":"\\gripthrwd",
|
"hvthrd":"\\gripthrwd",
|
||||||
"lhstd":"\\whslurd",
|
"lhstd":"\\whslurd",
|
||||||
"hgrpc":"\\hcatchc",
|
"hgrpc":"\\hcatchc",
|
||||||
"lpeld":"\\lpeld",
|
"lpeld":"\\lpeld",
|
||||||
"lhpeld":"\\lhpeld",
|
"lhpeld":"\\lhpeld",
|
||||||
"ltpeld":"\\ltpeld",
|
"ltpeld":"\\ltpeld",
|
||||||
"gbr":"\\gbirl",
|
"gbr":"\\gbirl",
|
||||||
"brl":"\\wbirl",
|
"brl":"\\wbirl",
|
||||||
"abr":"\\birl",
|
"abr":"\\birl",
|
||||||
"lgstd":"\\dbld",
|
"lgstd":"\\dbld",
|
||||||
"gste":"\\slure",
|
"gste":"\\slure",
|
||||||
"gstb":"\\slurb",
|
"gstb":"\\slurb",
|
||||||
"grp":"\\grip",
|
"grp":"\\grip",
|
||||||
"tar":"\\taor",
|
"tar":"\\taor",
|
||||||
"crunl":"\\crun",
|
"crunl":"\\crun",
|
||||||
"gstd":"\\slurd",
|
"gstd":"\\slurd",
|
||||||
"tdbf":"\\tdblf",
|
"tdbf":"\\tdblf",
|
||||||
"rodin":"\\bgrip",
|
"rodin":"\\bgrip",
|
||||||
}
|
}
|
||||||
#are we adding midi?
|
#are we adding midi?
|
||||||
if addmidi:
|
if addmidi:
|
||||||
|
@ -114,7 +125,7 @@ class bwwtolily :
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
def parse(self):
|
def parse(self):
|
||||||
'''reate a string that represents the converted
|
'''create a string that represents the converted
|
||||||
contents of the file'''
|
contents of the file'''
|
||||||
#open the file read only
|
#open the file read only
|
||||||
file_handle = open(self.original_file,"r")
|
file_handle = open(self.original_file,"r")
|
||||||
|
@ -130,8 +141,14 @@ class bwwtolily :
|
||||||
result = self.sig_regex.search(file_text)
|
result = self.sig_regex.search(file_text)
|
||||||
if result:
|
if result:
|
||||||
self.tune_time_sig = result.group(1)+"/"+result.group(2)
|
self.tune_time_sig = result.group(1)+"/"+result.group(2)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.tune_time_sig = "4/4"
|
result = self.sig_regex_common.search(file_text)
|
||||||
|
if result:
|
||||||
|
self.tune_time_sig = "2/2"
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.tune_time_sig = "4/4"
|
||||||
|
|
||||||
#get the tunes note info
|
#get the tunes note info
|
||||||
'''greedy, multiline, from first ampersand to !'''
|
'''greedy, multiline, from first ampersand to !'''
|
||||||
|
@ -153,7 +170,7 @@ class bwwtolily :
|
||||||
self.transpose(element)
|
self.transpose(element)
|
||||||
|
|
||||||
def lilynote(self,bwwname):
|
def lilynote(self,bwwname):
|
||||||
#convert a bww notename to a lilypond notename
|
'''convert a bww notename to a lilypond notename'''
|
||||||
#make the notename lowercase
|
#make the notename lowercase
|
||||||
notename = bwwname.lower()
|
notename = bwwname.lower()
|
||||||
|
|
||||||
|
@ -170,7 +187,7 @@ class bwwtolily :
|
||||||
return lilynote
|
return lilynote
|
||||||
|
|
||||||
def transpose(self,element):
|
def transpose(self,element):
|
||||||
#receive a bww element and return a lilypond equivelent
|
'''receive a bww element and return a lilypond equivalent'''
|
||||||
|
|
||||||
#is the element a note?
|
#is the element a note?
|
||||||
note_result = self.regex_note_info.search(element)
|
note_result = self.regex_note_info.search(element)
|
||||||
|
@ -197,48 +214,56 @@ class bwwtolily :
|
||||||
self.most_recent_note-=1
|
self.most_recent_note-=1
|
||||||
self.tune_elements.append("]")
|
self.tune_elements.append("]")
|
||||||
return
|
return
|
||||||
|
|
||||||
#is the element a grace note?
|
#is the element a grace note?
|
||||||
grace_result=self.regex_grace_note.search(element)
|
grace_result=self.regex_grace_note.search(element)
|
||||||
if grace_result:
|
if grace_result:
|
||||||
grace = "\\gr"+self.lilynote( grace_result.group(1) )
|
grace = "\\gr"+self.lilynote( grace_result.group(1) )
|
||||||
self.tune_elements.append(grace)
|
self.tune_elements.append(grace)
|
||||||
return
|
return
|
||||||
|
|
||||||
#is the element an echo beat?
|
#is the element an echo beat?
|
||||||
echo_beat_result=self.regex_echo_beat.search(element)
|
echo_beat_result=self.regex_echo_beat.search(element)
|
||||||
if echo_beat_result:
|
if echo_beat_result:
|
||||||
echo_beat = "\\echo"+self.lilynote( echo_beat_result.group(1) )
|
echo_beat = "\\echo"+self.lilynote( echo_beat_result.group(1) )
|
||||||
self.tune_elements.append(echo_beat)
|
self.tune_elements.append(echo_beat)
|
||||||
return
|
return
|
||||||
|
|
||||||
#is the element a doubling?
|
#is the element a doubling?
|
||||||
doubling_result=self.regex_doubling.search(element)
|
doubling_result=self.regex_doubling.search(element)
|
||||||
if doubling_result:
|
if doubling_result:
|
||||||
doubling = "\\dbl"+self.lilynote( doubling_result.group(1) )
|
doubling = "\\dbl"+self.lilynote( doubling_result.group(1) )
|
||||||
self.tune_elements.append(doubling)
|
self.tune_elements.append(doubling)
|
||||||
return
|
return
|
||||||
|
|
||||||
#is the element a half doubling?
|
#is the element a half doubling?
|
||||||
hdoubling_result=self.regex_half_doubling.search(element)
|
hdoubling_result=self.regex_half_doubling.search(element)
|
||||||
if hdoubling_result:
|
if hdoubling_result:
|
||||||
half_doubling = "\\hdbl"+self.lilynote( hdoubling_result.group(1) )
|
half_doubling = "\\hdbl"+self.lilynote( hdoubling_result.group(1) )
|
||||||
self.tune_elements.append(half_doubling)
|
self.tune_elements.append(half_doubling)
|
||||||
return
|
return
|
||||||
|
|
||||||
#is the element a pele?
|
#is the element a pele?
|
||||||
pele_result=self.regex_pele.search(element)
|
pele_result=self.regex_pele.search(element)
|
||||||
if pele_result:
|
if pele_result:
|
||||||
pele = "\\pel"+self.lilynote( pele_result.group(1) )
|
pele = "\\pel"+self.lilynote( pele_result.group(1) )
|
||||||
self.tune_elements.append(pele)
|
self.tune_elements.append(pele)
|
||||||
return
|
return
|
||||||
|
|
||||||
#is the element a thumb pele?
|
#is the element a thumb pele?
|
||||||
tpele_result=self.regex_thumb_pele.search(element)
|
tpele_result=self.regex_thumb_pele.search(element)
|
||||||
if tpele_result:
|
if tpele_result:
|
||||||
tpele = "\\tpel"+self.lilynote( tpele_result.group(1) )
|
tpele = "\\tpel"+self.lilynote( tpele_result.group(1) )
|
||||||
self.tune_elements.append(tpele)
|
self.tune_elements.append(tpele)
|
||||||
return
|
return
|
||||||
|
|
||||||
#is the element a hpele?
|
#is the element a hpele?
|
||||||
hpele_result=self.regex_half_pele.search(element)
|
hpele_result=self.regex_half_pele.search(element)
|
||||||
if hpele_result:
|
if hpele_result:
|
||||||
hpele = "\\hpel"+self.lilynote( hpele_result.group(1) )
|
hpele = "\\hpel"+self.lilynote( hpele_result.group(1) )
|
||||||
self.tune_elements.append(hpele)
|
self.tune_elements.append(hpele)
|
||||||
return
|
return
|
||||||
|
|
||||||
#is the element a strike?
|
#is the element a strike?
|
||||||
strike_result=self.regex_strike.search(element)
|
strike_result=self.regex_strike.search(element)
|
||||||
if strike_result:
|
if strike_result:
|
||||||
|
@ -257,6 +282,7 @@ class bwwtolily :
|
||||||
strike = "\\gra"
|
strike = "\\gra"
|
||||||
self.tune_elements.append(strike)
|
self.tune_elements.append(strike)
|
||||||
return
|
return
|
||||||
|
|
||||||
#is the element a dot?
|
#is the element a dot?
|
||||||
dot_result=self.regex_dot.search(element)
|
dot_result=self.regex_dot.search(element)
|
||||||
if dot_result:
|
if dot_result:
|
||||||
|
@ -268,15 +294,43 @@ class bwwtolily :
|
||||||
self.tune_elements[self.most_recent_note]+="."
|
self.tune_elements[self.most_recent_note]+="."
|
||||||
return
|
return
|
||||||
|
|
||||||
|
#is the element an old note tie
|
||||||
|
old_tie_result = self.regex_old_tie.search(element)
|
||||||
|
if old_tie_result:
|
||||||
|
self.tune_elements[self.most_recent_note]+="~"
|
||||||
|
return
|
||||||
|
|
||||||
|
#is the element a tuplet
|
||||||
|
tuplet_result = self.regex_tuplet.search(element)
|
||||||
|
if tuplet_result:
|
||||||
|
upper = tuplet_result.group("upper")
|
||||||
|
lower = tuplet_result.group("lower")
|
||||||
|
start = tuplet_result.group("type")
|
||||||
|
|
||||||
|
if start == 's':
|
||||||
|
if not lower:
|
||||||
|
lower = 2
|
||||||
|
|
||||||
|
fraction = "{}/{}".format(upper, lower)
|
||||||
|
|
||||||
|
self.tune_elements.append("\\tuplet {} {{".format(fraction))
|
||||||
|
elif start == 'e':
|
||||||
|
self.tune_elements.append("}")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
#is the element a slur?
|
#is the element a slur?
|
||||||
slur_result = self.regex_slur.search(element)
|
slur_result = self.regex_slur.search(element)
|
||||||
if slur_result:
|
if slur_result:
|
||||||
#get the matching elements
|
#get the matching elements
|
||||||
note_count = slur_result.group("note_count")
|
note_count = slur_result.group("note_count")
|
||||||
end_note = slur_result.group("end_note")
|
end_note = slur_result.group("end_note")
|
||||||
|
|
||||||
#get the length of the slur as an integer
|
#get the length of the slur as an integer
|
||||||
slur_len = int(note_count)
|
slur_len = int(note_count)
|
||||||
'''find the position of the note that is slur_len from the end'''
|
'''find the position of the note that is slur_len from the end'''
|
||||||
|
|
||||||
#get the tune_elements lenght
|
#get the tune_elements lenght
|
||||||
elem_index = len(self.tune_elements)-1
|
elem_index = len(self.tune_elements)-1
|
||||||
note_count = 0
|
note_count = 0
|
||||||
|
@ -295,6 +349,7 @@ class bwwtolily :
|
||||||
#add the slur end
|
#add the slur end
|
||||||
self.tune_elements.append(")")
|
self.tune_elements.append(")")
|
||||||
return
|
return
|
||||||
|
|
||||||
#is this a bww tie slur?
|
#is this a bww tie slur?
|
||||||
if element == "^ts":
|
if element == "^ts":
|
||||||
self.slur_tie_pending = True
|
self.slur_tie_pending = True
|
||||||
|
@ -323,6 +378,11 @@ class bwwtolily :
|
||||||
result = self.sig_regex.search(element)
|
result = self.sig_regex.search(element)
|
||||||
if result:
|
if result:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
result = self.sig_regex_common.search(element)
|
||||||
|
if result:
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
dict_result = self.transpose_dict[element]
|
dict_result = self.transpose_dict[element]
|
||||||
|
@ -330,6 +390,7 @@ class bwwtolily :
|
||||||
self.tune_elements.append(dict_result)
|
self.tune_elements.append(dict_result)
|
||||||
return
|
return
|
||||||
except:
|
except:
|
||||||
|
self.tune_elements.append("%{"+element+"%}")
|
||||||
do_print( "unparsed: "+element)
|
do_print( "unparsed: "+element)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue