Compare commits

...

13 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
Eric Teunis de Boone 3996b9f38e New definitions + ArgParse instead of OptParse 2016-11-16 02:40:21 +01:00
Eric Teunis de Boone 9f696d8f77 Added echos for low A,G 2016-10-30 17:47:39 +01:00
Eric Teunis de Boone de90d424ed Merge branch 'master' of https://github.com/kastdeur/bwwtolily 2016-10-20 08:27:20 +02:00
kastdeur 1a27ea5634 Added some embellishments
explicit Heavy throw on D, 
lhstd
gstb
rodin
2016-10-20 02:26:09 +02:00
Eric Teunis de Boone 9e7c008f95 Added rodin 2016-03-11 23:19:53 +01:00
4 changed files with 169 additions and 51 deletions

BIN
Bgreader.hlp Normal file

Binary file not shown.

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 optparse import OptionParser
from argparse import ArgumentParser
import sys,os,re,subprocess
version = "0.4.2"
version = "0.6.3"
#make a print function to handle various version of python
def do_print(string):
@ -23,54 +24,81 @@ 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
self.regex_grace_note = re.compile("([h|l]*[abcdefgt])g")
#a regex to find echo beats
self.regex_echo_beat = re.compile("echo([h|l]*[abcdefgt])")
#a regex to parse doublings
self.regex_doubling = re.compile("^db([h|l]*[g|a|b|c|d|e|f]{1})")
#a regex to parse half_doublings
self.regex_half_doubling = re.compile("^hdb([h|l]*[g|a|b|c|d|e|f]{1})")
#a regex to parse peles
self.regex_pele = re.compile("^pel([la|b|c|d|e|f]{1})")
#a regex to parse half peles
self.regex_half_pele = re.compile("^hpel([la|b|c|d|e|f|hg]{1})")
#a regex to parse thumb peles
self.regex_thumb_pele = re.compile("^tpel([hg|la|b|c|d|e|f]{1})")
#a regex for finding strikes
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",
"gbr":"\\gbirl",
"brl":"\\wbirl",
"abr":"\\birl",
"lgstd":"\\dbld",
"gste":"\\slure",
"grp":"\\grip",
"tar":"\\taor",
"gstd":"\\slurd",
"tdbf":"\\tdblf"
#"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:
@ -97,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")
@ -113,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 !'''
@ -136,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()
@ -153,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)
@ -180,24 +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:
@ -210,12 +276,13 @@ class bwwtolily :
elif strike =="\\slurg":
#let the strike be a grace note on the high g
strike = "\\grg"
#if hte strike is on low a
#if the strike is on low a
elif strike == "\\slura":
#let the strike be a grace not on low a
#let the strike be a grace note on low a
strike = "\\gra"
self.tune_elements.append(strike)
return
#is the element a dot?
dot_result=self.regex_dot.search(element)
if dot_result:
@ -227,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
@ -254,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
@ -282,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]
@ -289,6 +390,7 @@ class bwwtolily :
self.tune_elements.append(dict_result)
return
except:
self.tune_elements.append("%{"+element+"%}")
do_print( "unparsed: "+element)
return
@ -354,31 +456,43 @@ melody = {
#use the bww2lily class
if __name__ == "__main__" :
parser = OptionParser()
parser.add_option("-i", "--in", dest="input",
help="the FILE to convert", metavar="FILE")
parser.add_option("-l", "--lilypond",
parser = ArgumentParser()
parser.add_argument("files", default='', nargs='*')
parser.add_argument("-i", "--in", dest="input",
help="the FILE to convert", metavar="FILE",
)
parser.add_argument("-l", "--lilypond",
action="store_true", dest="runlilypond",default=False,
help="run lilypond after converting the file")
parser.add_option("-m", "--midi",
parser.add_argument("-m", "--midi",
action="store_true", dest="addmidi",default=False,
help="add midi output to the lilypond file")
parser.add_option("-v","--version",dest='version',default=False,
parser.add_argument("-v","--version",dest='version',default=False,
action="store_true",help="print version information and quit")
#parse the args
(options, args) = parser.parse_args()
if options.version:
args = parser.parse_args()
if args.version:
do_print( "bwwtolily: "+version)
sys.exit()
if options.input!=None:
b2l = bwwtolily(options.addmidi)
b2l.set_file(options.input)
if args.input!=None:
b2l = bwwtolily(args.addmidi)
b2l.set_file(args.input)
b2l.parse()
new_file = b2l.create_output_file()
#are we running lilypond?
if options.runlilypond:
if args.runlilypond:
#try to run lilypond as a subprocess
subprocess.check_call("lilypond \""+new_file+"\"",shell=True)
elif args.files:
for f in args.files:
b2l = bwwtolily(args.addmidi)
b2l.set_file(f)
b2l.parse()
new_file = b2l.create_output_file()
#are we running lilypond?
if args.runlilypond:
#try to run lilypond as a subprocess
subprocess.check_call("lilypond \""+new_file+"\"",shell=True)
else:

BIN
embellishments.pdf Normal file

Binary file not shown.