1
0
Fork 0
mirror of https://github.com/kastdeur/bwwtolily.git synced 2025-06-18 05:06:38 +02:00

Compare commits

...

8 commits

Author SHA1 Message Date
8eb1e5021e Bugfix: invalid prewhitespace caused IndentationError 2022-01-21 12:43:18 +01:00
Eric Teunis de Boone
ab2ad69d75 Added Tuplet Support
Closes #1
2019-02-11 01:05:07 +01:00
Eric Teunis de Boone
9a43ba9688 '^[abcdef]' ties are old ties
Do not look for the e tie, as this is the new 'end of tie'
2019-02-11 00:51:47 +01:00
Eric Teunis de Boone
b9bfeed838 Parse note ties of the form '^t[abcdef]' 2019-02-11 00:23:21 +01:00
Eric Teunis de Boone
b29a4fd5d9 Read (cut) common time signature
if no time signature found, try to find a (cut) common time signature.
default to 4/4.
2019-01-28 01:13:19 +01:00
ET de Boone
075ecbf087
Updated README.md
Ask to make an issue instead of mailing to jezra@jezra.net
2018-10-28 03:17:39 +01:00
Eric Teunis de Boone
d5e4378d3f Unparsed elements are now inserted as a comment
so we know the position
2018-10-28 02:08:09 +01:00
Eric Teunis de Boone
bb079e8b02 Readability: Fixed some indentation and missing newlines 2018-10-28 02:06:53 +01:00
2 changed files with 110 additions and 45 deletions

View file

@ -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
```

View file

@ -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