Compare commits

...

8 Commits

Author SHA1 Message Date
Eric Teunis de Boone 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
(http://lilypond.org) parsable file. Not all of the embellishments
get converted properly, this is espessially true with piobaireachd,
Convert Bagpipe Reader to Lilypond
==================================
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.
If you recognize an embellishment that isn't being parsed, please
send an email regarding the embellishment to jezra@jezra.net and I
will try to add the embellishment to the application.
create an [issue on github](https://github.com/kastdeur/bwwtolily/issues)
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
created .ly file
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
#copyright: 2008 Jezra Lickter
#contributions by ET de Boone
#GPL v3
from argparse import ArgumentParser
import sys,os,re,subprocess
version = "0.5.2"
version = "0.6.3"
#make a print function to handle various version of python
def do_print(string):
@ -23,12 +24,16 @@ class bwwtolily :
self.most_recent_note = 0
self.in_note_group=False
self.slur_tie_pending = False
self.tuplet_pending = False
self.last_group_close=0
'''compile a few regex queries'''
#make a regex to determine if something is a lilypond note
self.regex_lilynote= re.compile("[abcdefgAG][0-9]*")
#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
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
@ -49,45 +54,51 @@ class bwwtolily :
self.regex_strike = re.compile("str([h|l]*[abcdefg])")
#a regex to find dots
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
self.regex_sub_repeat = re.compile("'([0-9]+)")
#a regex to find note slurs, not slur embellishments
self.regex_slur = re.compile("\^(?P<note_count>[0-9])(?P<end_note>[a-z]*)")
#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
self.transpose_dict = {
"!":"\\bar \"|\"\n",
"!I":"\\bar \".|\" \\break \n",
#"''!I":"\\set Score.repeatCommands = #'( end-repeat ) \\break \n",
"''!I":"\\bar \":|\" \\break\n",
#"''!I":"} \\break \n",
"I!''":"\\bar \"|:\"",
"I!":"\\bar \"|.\"",
#"I!''":"\\set Score.repeatCommands = #'( start-repeat )\n",
"!":"\\bar \"|\"\n",
"!I":"\\bar \".|\" \\break \n",
#"''!I":"\\set Score.repeatCommands = #'( end-repeat ) \\break \n",
"''!I":"\\bar \":|\" \\break\n",
#"''!I":"} \\break \n",
"I!''":"\\bar \"|:\"",
"I!":"\\bar \"|.\"",
#"I!''":"\\set Score.repeatCommands = #'( start-repeat )\n",
#"I!''":"\n\\repeat volta 2 {\n",
"_'":"\\set Score.repeatCommands = #'((volta #f)) \\bar \"|\"\n",
"!t":"\\bar \"|\" \\break\n\n",
"thrd":"\\thrwd",
"hvthrd":"\\gripthrwd",
"lhstd":"\\whslurd",
"hgrpc":"\\hcatchc",
"lpeld":"\\lpeld",
"lhpeld":"\\lhpeld",
"ltpeld":"\\ltpeld",
"gbr":"\\gbirl",
"brl":"\\wbirl",
"abr":"\\birl",
"lgstd":"\\dbld",
"gste":"\\slure",
"gstb":"\\slurb",
"grp":"\\grip",
"tar":"\\taor",
"crunl":"\\crun",
"gstd":"\\slurd",
"tdbf":"\\tdblf",
"rodin":"\\bgrip",
#"I!''":"\n\\repeat volta 2 {\n",
"_'":"\\set Score.repeatCommands = #'((volta #f)) \\bar \"|\"\n",
"!t":"\\bar \"|\" \\break\n\n",
"thrd":"\\thrwd",
"hvthrd":"\\gripthrwd",
"lhstd":"\\whslurd",
"hgrpc":"\\hcatchc",
"lpeld":"\\lpeld",
"lhpeld":"\\lhpeld",
"ltpeld":"\\ltpeld",
"gbr":"\\gbirl",
"brl":"\\wbirl",
"abr":"\\birl",
"lgstd":"\\dbld",
"gste":"\\slure",
"gstb":"\\slurb",
"grp":"\\grip",
"tar":"\\taor",
"crunl":"\\crun",
"gstd":"\\slurd",
"tdbf":"\\tdblf",
"rodin":"\\bgrip",
}
#are we adding midi?
if addmidi:
@ -114,7 +125,7 @@ class bwwtolily :
sys.exit()
def parse(self):
'''reate a string that represents the converted
'''create a string that represents the converted
contents of the file'''
#open the file read only
file_handle = open(self.original_file,"r")
@ -130,8 +141,14 @@ class bwwtolily :
result = self.sig_regex.search(file_text)
if result:
self.tune_time_sig = result.group(1)+"/"+result.group(2)
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
'''greedy, multiline, from first ampersand to !'''
@ -153,7 +170,7 @@ class bwwtolily :
self.transpose(element)
def lilynote(self,bwwname):
#convert a bww notename to a lilypond notename
'''convert a bww notename to a lilypond notename'''
#make the notename lowercase
notename = bwwname.lower()
@ -170,7 +187,7 @@ class bwwtolily :
return lilynote
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?
note_result = self.regex_note_info.search(element)
@ -197,48 +214,56 @@ class bwwtolily :
self.most_recent_note-=1
self.tune_elements.append("]")
return
#is the element a grace note?
grace_result=self.regex_grace_note.search(element)
if grace_result:
grace = "\\gr"+self.lilynote( grace_result.group(1) )
self.tune_elements.append(grace)
return
#is the element an echo beat?
echo_beat_result=self.regex_echo_beat.search(element)
if echo_beat_result:
echo_beat = "\\echo"+self.lilynote( echo_beat_result.group(1) )
self.tune_elements.append(echo_beat)
return
#is the element a doubling?
doubling_result=self.regex_doubling.search(element)
if doubling_result:
doubling = "\\dbl"+self.lilynote( doubling_result.group(1) )
self.tune_elements.append(doubling)
return
#is the element a half doubling?
hdoubling_result=self.regex_half_doubling.search(element)
if hdoubling_result:
half_doubling = "\\hdbl"+self.lilynote( hdoubling_result.group(1) )
self.tune_elements.append(half_doubling)
return
#is the element a pele?
pele_result=self.regex_pele.search(element)
if pele_result:
pele = "\\pel"+self.lilynote( pele_result.group(1) )
self.tune_elements.append(pele)
return
#is the element a thumb pele?
tpele_result=self.regex_thumb_pele.search(element)
if tpele_result:
tpele = "\\tpel"+self.lilynote( tpele_result.group(1) )
self.tune_elements.append(tpele)
return
#is the element a hpele?
hpele_result=self.regex_half_pele.search(element)
if hpele_result:
hpele = "\\hpel"+self.lilynote( hpele_result.group(1) )
self.tune_elements.append(hpele)
return
#is the element a strike?
strike_result=self.regex_strike.search(element)
if strike_result:
@ -257,6 +282,7 @@ class bwwtolily :
strike = "\\gra"
self.tune_elements.append(strike)
return
#is the element a dot?
dot_result=self.regex_dot.search(element)
if dot_result:
@ -268,15 +294,43 @@ class bwwtolily :
self.tune_elements[self.most_recent_note]+="."
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?
slur_result = self.regex_slur.search(element)
if slur_result:
#get the matching elements
note_count = slur_result.group("note_count")
end_note = slur_result.group("end_note")
#get the length of the slur as an integer
slur_len = int(note_count)
'''find the position of the note that is slur_len from the end'''
#get the tune_elements lenght
elem_index = len(self.tune_elements)-1
note_count = 0
@ -295,6 +349,7 @@ class bwwtolily :
#add the slur end
self.tune_elements.append(")")
return
#is this a bww tie slur?
if element == "^ts":
self.slur_tie_pending = True
@ -323,6 +378,11 @@ class bwwtolily :
result = self.sig_regex.search(element)
if result:
return
result = self.sig_regex_common.search(element)
if result:
return
try:
dict_result = self.transpose_dict[element]
@ -330,6 +390,7 @@ class bwwtolily :
self.tune_elements.append(dict_result)
return
except:
self.tune_elements.append("%{"+element+"%}")
do_print( "unparsed: "+element)
return