Ejemplo n.º 1
0
 def __do_load_grooves(self, grooves_list, path):
     """
     Load grooves and recurse into subdirectories.
     """
     for dirname, dirnames, filenames in os.walk(path): #@UnusedVariable            
         for name in filenames:
             if fnmatch.fnmatch(name, '*.mma'):
                 full_name = os.path.join(dirname, name)
                 song_data = self.__parseGrooves(full_name)
                 if not song_data: continue
                 song_bar_info = song_data.get_bar_info_all()
                 doc = author = time = ''
                 for line in song_bar_info[0].get_lines():
                     action = line[0]
                     if action == Glob.A_BEGIN_BLOCK and line[1] == Glob.A_DOC:
                         doc = BarInfo.get_doc_value(line)
                     elif action == Glob.A_AUTHOR:
                         author = BarInfo.get_author_value(line)
                     elif action == Glob.A_TIME:
                         time = BarInfo.get_time_value(line)
                     elif action == Glob.A_DEF_GROOVE:
                         gname, gdesc = BarInfo.get_defgroove_value(line)
                         grooves_list.append([gname, doc, gdesc, author, time, full_name])
         for name in dirnames:
             path = os.path.join(dirname, name)
             self.__do_load_grooves(grooves_list, path)
Ejemplo n.º 2
0
 def __do_load_grooves(self, grooves_list, path):
     """
     Load grooves and recurse into subdirectories.
     """
     for dirname, dirnames, filenames in os.walk(path):  #@UnusedVariable
         for name in filenames:
             if fnmatch.fnmatch(name, '*.mma'):
                 full_name = os.path.join(dirname, name)
                 song_data = self.__parseGrooves(full_name)
                 if not song_data: continue
                 song_bar_info = song_data.get_bar_info_all()
                 doc = author = time = ''
                 for line in song_bar_info[0].get_lines():
                     action = line[0]
                     if action == Glob.A_BEGIN_BLOCK and line[
                             1] == Glob.A_DOC:
                         doc = BarInfo.get_doc_value(line)
                     elif action == Glob.A_AUTHOR:
                         author = BarInfo.get_author_value(line)
                     elif action == Glob.A_TIME:
                         time = BarInfo.get_time_value(line)
                     elif action == Glob.A_DEF_GROOVE:
                         gname, gdesc = BarInfo.get_defgroove_value(line)
                         grooves_list.append(
                             [gname, doc, gdesc, author, time, full_name])
         for name in dirnames:
             path = os.path.join(dirname, name)
             self.__do_load_grooves(grooves_list, path)
Ejemplo n.º 3
0
 def on_spinbutton2_value_changed_callback(self, spinbutton):
     """ Tempo changed """
     count = str(int(spinbutton.get_value()))
     event = BarInfo.create_event(Glob.A_TEMPO)
     BarInfo.set_tempo_value(event, count)
     self.set_label_from_event(self.__toggled_button, event)
     self.__new_event = event
Ejemplo n.º 4
0
 def on_comboboxentry1_changed_callback(self, widget):
     """ RepeatEnd value changed. """
     # called also when initializing the entries list
     if not self.__toggled_button: return
     try:
         i = int(widget.child.get_text())
     except ValueError:
         return
     count = str(i)
     event = BarInfo.create_event(Glob.A_REPEAT_END)
     BarInfo.set_repeat_end_value(event, count)
     self.set_label_from_event(self.__toggled_button, event)
     self.__newEvent = event
Ejemplo n.º 5
0
 def on_comboboxentry1_changed_callback(self, widget):
     """ RepeatEnd value changed. """
     # called also when initializing the entries list
     if not self.__toggled_button: return
     try:
         i = int(widget.child.get_text())
     except ValueError:
         return
     count = str(i)
     event = BarInfo.create_event(Glob.A_REPEAT_END)
     BarInfo.set_repeat_end_value(event, count)
     self.set_label_from_event(self.__toggled_button, event)
     self.__newEvent = event
Ejemplo n.º 6
0
 def init_window(self, button, event):
     self.__toggled_button = button
     self.__curr_event = event
     self.__newEvent = None
     text = BarInfo.get_repeat_end_value(event)
     self.__entry.set_text(text)
     self.__combobox_entry.grab_focus()
Ejemplo n.º 7
0
 def init_window(self, button, event):
     self.__toggled_button = button
     self.__curr_event = event
     self.__newEvent = None
     text = BarInfo.get_repeat_end_value(event)
     self.__entry.set_text(text)
     self.__combobox_entry.grab_focus()
Ejemplo n.º 8
0
 def set_label_from_event(self, button, event):
     """ Set the label of tempo button correctly
         even if the event in the self.__song.get_data().get_bar_info(0) is missing """
     if event:
         label = BarInfo.get_tempo_value(event) + ' BPM'
         button.set_label(label)
     else:
         button.set_label(EventTempo.__TEMPO_UNDEFINED)
Ejemplo n.º 9
0
 def setUp(self):
     song_data = self.__song_data = SongData([ BarInfo() ], [], 0)
     self.__bar_chords1 = BarChords()
     self.__bar_chords1.set_song_data(song_data)
     self.__bar_chords1.set_chords([['CM7', ' trail1 '], [ 'Am', ' trail2 ']])
     self.__bar_chords2 = BarChords()
     self.__bar_chords2.set_song_data(song_data)
     self.__bar_chords2.set_chords([['CM7', ' trail1 '], [ 'Am', ' trail2 '], [ '/', ' '], ['G', ' trail3 ']])
Ejemplo n.º 10
0
 def __add_event(self, key):
     """ Add selected event and open its window """
     barNum = self.__gui.get_current_bar_number()
     event = BarInfo.create_event(key)
     self.__song.get_data().get_bar_info(barNum).add_event(event)
     self.refresh_all()
     self.__gui.refresh_current_field() # repetition
     # open the new event window
     for triple in self.__triples:
         if triple[3] is event:
             gobject.idle_add(triple[0].clicked)
             break
Ejemplo n.º 11
0
 def init_window(self, button, event):
     # hide back, forward, remove buttons
     if button is self.__togglebutton2: self.__alignment15.hide()
     else: self.__alignment15.show()
     self.__toggled_button = button
     self.__curr_event = event
     self.__new_event = None
     if event:
         self.__spinbutton2.set_value(int(BarInfo.get_tempo_value(event)))
     else:
         self.on_spinbutton2_value_changed_callback(self.__spinbutton2)
     self.__spinbutton2.grab_focus()
Ejemplo n.º 12
0
 def __clear_song(self):
     """
     Called when parsing of mma data failed.
     
     E.g. during opening the new file or parsing data from the source editor.
     The song must have minimum one BarInfo on which the cursor is located.
     
     bar_count = number of bar_chords in the song, number of bar_info is bar_count + 1
     """
     self.__song_data = SongData([ BarInfo() ], [], 0)
     self.__invalid_mma_data = None
     self.__pending_mma_data = None
     self.__last_compile_result = None
Ejemplo n.º 13
0
 def set_label_from_event(self, button, event):
     """ Sets the label of groove button correctly
         even if the event in the self.__song.get_data().get_bar_info(0) is missing. """
     if event: button.set_label(BarInfo.get_groove_value(event))
     else: button.set_label(EventGroove.__GROOVE_UNDEFINED)
Ejemplo n.º 14
0
 def __update_groove_event(self, groove):
     event = BarInfo.create_event(Glob.A_GROOVE)
     BarInfo.set_groove_value(event, groove)
     self.set_label_from_event(self.__toggled_button, event)
     self.__new_event = event
Ejemplo n.º 15
0
 def set_label_from_event(self, button, event):
     """ Sets the label of groove button correctly
         even if the event in the self.__song.get_data().get_bar_info(0) is missing. """
     if event: button.set_label(BarInfo.get_groove_value(event))
     else: button.set_label(EventGroove.__GROOVE_UNDEFINED)
Ejemplo n.º 16
0
 def __update_groove_event(self, groove):
     event = BarInfo.create_event(Glob.A_GROOVE)
     BarInfo.set_groove_value(event, groove)
     self.set_label_from_event(self.__toggled_button, event)
     self.__new_event = event
Ejemplo n.º 17
0
 def create_bar_info(self):
     bar_info = BarInfo()
     bar_info.set_song_data(self)
     return bar_info
Ejemplo n.º 18
0
def parse(inpath):
    """
    Process a mma input file.
    """
    song_bar_info = []
    song_bar_chords = []
    song_bar_count = 0
    bar_number = 0
    bar_info = BarInfo()
    bar_chords = BarChords()

    while True:
        curline = inpath.readline()

        # EOF
        if not curline:
            song_bar_info.append(
                bar_info
            )  # song_bar_info has always one element more then song_bar_chords
            song_bar_count = bar_number
            return SongData(song_bar_info, song_bar_chords, song_bar_count)
        """ convert 0xa0 (non-breakable space) to 0x20 (regular space).
        """
        curline = curline.replace('\xa0', '\x20')

        # empty line
        if curline.rstrip('\n').strip() == '':
            bar_info.add_line([Glob.A_UNKNOWN, curline])
            continue

        l = curline.split()

        # line beginning with macro
        if l[0][0] == '$':
            wline = get_wrapped_line(inpath, curline)
            wline.insert(0, Glob.A_UNKNOWN)
            bar_info.add_line(wline)
            continue
        """ Handle BEGIN and END here. This is outside of the Repeat/End
            and variable expand loops so SHOULD be pretty bullet proof.
            Note that the beginData stuff is global to this module ... the
            Include/Use directives check to make sure we're not doing that
            inside a Begin/End.

            beginData[] is a list which we append to as more Begins are
            encountered.

            The placement here is pretty deliberate. Variable expand comes
            later so you can't macroize BEGIN ... I think this makes sense.

            The tests for 'begin', 'end' and the appending of the current
            begin[] stuff have to be here, in this order.
        """

        action = l[0].upper()  # 1st arg in line

        # parse BEGIN and END block
        if action == 'BEGIN':
            block_action = l[1].upper()
            begin_block = parse_begin_block(inpath, curline)
            if block_action in supported_block_actions:
                tokens = parse_supported_block_action(block_action,
                                                      begin_block)
                begin_block = tokens
            begin_block.insert(0, Glob.A_BEGIN_BLOCK)
            begin_block.insert(1, block_action)
            bar_info.add_line(begin_block)
            continue

        # parse MSET block
        if action == 'MSET':
            mset_block = parse_mset_block(inpath, curline)
            mset_block.insert(0, Glob.A_UNKNOWN)
            bar_info.add_line(mset_block)
            continue

        # parse IF - ENDIF block
        if action == 'IF':
            if_block = parse_if_block(inpath, curline)
            if_block.insert(0, Glob.A_UNKNOWN)
            bar_info.add_line(if_block)
            continue

        # supported commands
        if action in supported_actions:
            wline = get_wrapped_line_join(inpath, curline)
            tokens = parse_supported_action(action, wline)
            tokens.insert(0, action)
            bar_info.add_line(tokens)
            continue

        # if the command is in the simple function table
        if action in simple_funcs:
            wline = get_wrapped_line(inpath, curline)
            wline.insert(0, Glob.A_UNKNOWN)
            bar_info.add_line(wline)
            continue
        """ We have several possibilities ...
            1. The command is a valid assigned track name,
            2. The command is a valid track name, but needs to be
               dynamically allocated,
            3. It's really a chord action
        """

        # track function BASS/DRUM/APEGGIO/CHORD ...
        if '-' in action:
            trk_class, ext = action.split('-', 1)  #@UnusedVariable
        else:
            trk_class = action

        if trk_class in trk_classes:
            # parsing track sequence ?
            parse_seq = len(l) >= 1 and l[1].upper() == 'SEQUENCE'
            wline = []
            while True:
                wline.extend(get_wrapped_line(inpath, curline))
                if not parse_seq: break
                """ Count the number of { and } and if they don't match read more lines and 
                    append. If we get to the EOF then we're screwed and we error out. """
                wline2 = ''.join(wline)
                if wline2.count('{') == wline2.count('}'): break
                curline = inpath.readline()
                if not curline:
                    raise ValueError("Reached EOF, Sequence {}s do not match")
            wline.insert(0, Glob.A_UNKNOWN)
            bar_info.add_line(wline)
            continue

        # join the wrapped line into one line
        wline = get_wrapped_line_join(inpath, curline)

        if wline[0].replace('\\\n', '').strip() == '':
            # line is a comment or empty wrapped line
            act = Glob.A_REMARK if wline[1].strip() else Glob.A_UNKNOWN
            bar_info.add_line([act, wline[0], wline[1]])
            continue

        l, eol = wline
        ### Gotta be a chord data line!
        """ A data line can have an optional bar number at the start
            of the line. Makes debugging input easier. The next
            block strips leading integers off the line. Note that
            a line number on a line by itself it okay.
        """

        before_number = ''
        if action.isdigit():  # isdigit() matches '1', '1234' but not '1a'!
            l2 = l.lstrip()
            before_number_len = len(l) - len(l2)
            before_number = l[0:before_number_len]
            l = l2
            numstr = l.split()[0]
            bar_chords.set_number(int(numstr))
            l = l[len(numstr):]  # remove number
            if len(l.strip()) == 0:  # ignore empty lines
                bar_info.add_line([Glob.A_UNKNOWN, wline[0] + wline[1]])
                continue
        """ We now have a valid line. It'll look something like:

            'Cm', '/', 'z', 'F#@4.5' { lyrics } [ solo ] * 2 
            

            Special processing in needed for 'z' options in chords. A 'z' can
            be of the form 'CHORDzX', 'z!' or just 'z'.
        """
        after_number = None
        last_chord = []
        ctable = []
        i = 0
        solo_count = 0
        lyrics_count = 0
        mismatched_solo = "Mismatched {}s for solo found in chord line"
        mismatched_lyrics = "Mismatched []s for lyrics found in chord line"
        while True:
            chars = ''
            while i < len(l):
                ch = l[i]
                if ch == '{':
                    """ Extract solo(s) from line ... this is anything in {}s.
                        The solo data is pushed into RIFFs and discarded from
                        the current line.
                    """
                    solo_count += 1
                elif ch == '[':
                    """ Set lyrics from [stuff] in the current line.
                        NOTE: lyric.extract() inserts previously created
                        data from LYRICS SET and inserts the chord names
                        if that flag is active.
        
                    """
                    lyrics_count += 1
                elif ch == '}':
                    solo_count -= 1
                    if solo_count < 0:
                        raise ValueError(mismatched_solo)
                elif ch == ']':
                    lyrics_count -= 1
                    if lyrics_count < 0:
                        raise ValueError(mismatched_lyrics)
                elif ch == '*':
                    """ A bar can have an optional repeat count. This must
                        be at the end of bar in the form '* xx'.
                    """
                    pass
                elif ch in '\t\n\\ 0123456789':  # white spaces, \ and repeat count
                    pass
                elif solo_count == 0 and lyrics_count == 0:  # found beginning of the chord
                    break
                chars += ch
                i += 1
            if i == len(l):  # no more chord is coming
                if solo_count != 0:
                    raise ValueError(mismatched_solo)
                if lyrics_count != 0:
                    raise ValueError(mismatched_lyrics)
                if after_number == None:
                    after_number = chars
                else:
                    last_chord.append(chars)
                    ctable.append(last_chord)
                break
            else:  # chord beginning
                if after_number == None:
                    after_number = chars
                else:
                    last_chord.append(chars)
                    ctable.append(last_chord)
                chord_begin = i
                # find the end of the chord
                while i < len(l):
                    if l[i] in '{}[]*\t\n\\ ':
                        break
                    i += 1
                # chord examples: '/', 'z', 'Am7@2', 'Am6zC@3'
                c = l[chord_begin:i]
                last_chord = [c]
        # the trailing string of the last chord can possibly include '\n' after which
        # it would be difficult to add further chords. Therefore move the trailing string
        # of the last chord to eol
        eol = last_chord[1] + eol
        last_chord[1] = ''

        bar_chords.set_before_number(before_number)
        bar_chords.set_after_number(after_number)
        bar_chords.set_eol(eol)
        bar_chords.set_chords(ctable)

        song_bar_info.append(bar_info)
        song_bar_chords.append(bar_chords)

        bar_number = bar_number + 1
        bar_info = BarInfo()
        bar_chords = BarChords()
Ejemplo n.º 19
0
def parse(inpath):
    """
    Process a mma input file.
    """
    song_bar_info = []
    song_bar_chords = []
    song_bar_count = 0
    bar_number = 0
    bar_info = BarInfo()
    bar_chords = BarChords()

    while True:
        curline = inpath.readline()

        # EOF
        if not curline:
            song_bar_info.append(bar_info) # song_bar_info has always one element more then song_bar_chords
            song_bar_count = bar_number
            return SongData(song_bar_info, song_bar_chords, song_bar_count)

        """ convert 0xa0 (non-breakable space) to 0x20 (regular space).
        """
        curline = curline.replace('\xa0', '\x20')

        # empty line
        if curline.rstrip('\n').strip() == '':
            bar_info.add_line([Glob.A_UNKNOWN, curline]);
            continue

        l = curline.split()

        # line beginning with macro
        if l[0][0] == '$':
            wline = get_wrapped_line(inpath, curline)
            wline.insert(0, Glob.A_UNKNOWN)
            bar_info.add_line(wline)
            continue


        """ Handle BEGIN and END here. This is outside of the Repeat/End
            and variable expand loops so SHOULD be pretty bullet proof.
            Note that the beginData stuff is global to this module ... the
            Include/Use directives check to make sure we're not doing that
            inside a Begin/End.

            beginData[] is a list which we append to as more Begins are
            encountered.

            The placement here is pretty deliberate. Variable expand comes
            later so you can't macroize BEGIN ... I think this makes sense.

            The tests for 'begin', 'end' and the appending of the current
            begin[] stuff have to be here, in this order.
        """

        action = l[0].upper()      # 1st arg in line

        # parse BEGIN and END block
        if action == 'BEGIN':
            block_action = l[1].upper()
            begin_block = parse_begin_block(inpath, curline)
            if block_action in supported_block_actions:
                tokens = parse_supported_block_action(block_action, begin_block)
                begin_block = tokens
            begin_block.insert(0, Glob.A_BEGIN_BLOCK)
            begin_block.insert(1, block_action)
            bar_info.add_line(begin_block)
            continue

        # parse MSET block
        if action == 'MSET':
            mset_block = parse_mset_block(inpath, curline)
            mset_block.insert(0, Glob.A_UNKNOWN)
            bar_info.add_line(mset_block)
            continue

        # parse IF - ENDIF block
        if action == 'IF':
            if_block = parse_if_block(inpath, curline)
            if_block.insert(0, Glob.A_UNKNOWN)
            bar_info.add_line(if_block)
            continue

        # supported commands
        if action in supported_actions:
            wline = get_wrapped_line_join(inpath, curline)
            tokens = parse_supported_action(action, wline)
            tokens.insert(0, action)
            bar_info.add_line(tokens)
            continue

        # if the command is in the simple function table
        if action in simple_funcs:
            wline = get_wrapped_line(inpath, curline)
            wline.insert(0, Glob.A_UNKNOWN)
            bar_info.add_line(wline)
            continue

        """ We have several possibilities ...
            1. The command is a valid assigned track name,
            2. The command is a valid track name, but needs to be
               dynamically allocated,
            3. It's really a chord action
        """

        # track function BASS/DRUM/APEGGIO/CHORD ...
        if '-' in action:
            trk_class, ext = action.split('-', 1) #@UnusedVariable
        else:
            trk_class = action

        if trk_class in trk_classes:
            # parsing track sequence ?
            parse_seq = len(l) >= 1 and l[1].upper() == 'SEQUENCE'
            wline = []
            while True:
                wline.extend(get_wrapped_line(inpath, curline))
                if not parse_seq: break
                """ Count the number of { and } and if they don't match read more lines and 
                    append. If we get to the EOF then we're screwed and we error out. """
                wline2 = ''.join(wline)
                if wline2.count('{') == wline2.count('}'): break
                curline = inpath.readline()
                if not curline:
                    raise ValueError("Reached EOF, Sequence {}s do not match")
            wline.insert(0, Glob.A_UNKNOWN)
            bar_info.add_line(wline)
            continue

        # join the wrapped line into one line
        wline = get_wrapped_line_join(inpath, curline)

        if wline[0].replace('\\\n', '').strip() == '':
            # line is a comment or empty wrapped line
            act = Glob.A_REMARK if wline[1].strip() else Glob.A_UNKNOWN
            bar_info.add_line([act , wline[0], wline[1]])
            continue

        l, eol = wline
        ### Gotta be a chord data line!

        """ A data line can have an optional bar number at the start
            of the line. Makes debugging input easier. The next
            block strips leading integers off the line. Note that
            a line number on a line by itself it okay.
        """

        before_number = ''
        if action.isdigit():   # isdigit() matches '1', '1234' but not '1a'!
            l2 = l.lstrip()
            before_number_len = len(l) - len(l2)
            before_number = l[0:before_number_len]
            l = l2
            numstr = l.split()[0]
            bar_chords.set_number(int(numstr))
            l = l[len(numstr):] # remove number
            if len(l.strip()) == 0: # ignore empty lines
                bar_info.add_line([ Glob.A_UNKNOWN, wline[0] + wline[1] ])
                continue

        """ We now have a valid line. It'll look something like:

            'Cm', '/', 'z', 'F#@4.5' { lyrics } [ solo ] * 2 
            

            Special processing in needed for 'z' options in chords. A 'z' can
            be of the form 'CHORDzX', 'z!' or just 'z'.
        """
        after_number = None
        last_chord = []
        ctable = []
        i = 0
        solo_count = 0
        lyrics_count = 0
        mismatched_solo = "Mismatched {}s for solo found in chord line"
        mismatched_lyrics = "Mismatched []s for lyrics found in chord line"
        while True:
            chars = ''
            while i < len(l):
                ch = l[i]
                if ch == '{':
                    """ Extract solo(s) from line ... this is anything in {}s.
                        The solo data is pushed into RIFFs and discarded from
                        the current line.
                    """
                    solo_count += 1
                elif ch == '[':
                    """ Set lyrics from [stuff] in the current line.
                        NOTE: lyric.extract() inserts previously created
                        data from LYRICS SET and inserts the chord names
                        if that flag is active.
        
                    """
                    lyrics_count += 1
                elif ch == '}':
                    solo_count -= 1
                    if solo_count < 0:
                        raise ValueError(mismatched_solo)
                elif ch == ']':
                    lyrics_count -= 1
                    if lyrics_count < 0:
                        raise ValueError(mismatched_lyrics)
                elif ch == '*':
                    """ A bar can have an optional repeat count. This must
                        be at the end of bar in the form '* xx'.
                    """
                    pass
                elif ch in '\t\n\\ 0123456789': # white spaces, \ and repeat count
                    pass
                elif solo_count == 0 and lyrics_count == 0: # found beginning of the chord
                    break
                chars += ch
                i += 1
            if i == len(l): # no more chord is coming
                if solo_count != 0:
                    raise ValueError(mismatched_solo)
                if lyrics_count != 0:
                    raise ValueError(mismatched_lyrics)
                if after_number == None:
                    after_number = chars
                else:
                    last_chord.append(chars)
                    ctable.append(last_chord)
                break
            else: # chord beginning
                if after_number == None:
                    after_number = chars
                else:
                    last_chord.append(chars)
                    ctable.append(last_chord)
                chord_begin = i
                # find the end of the chord
                while i < len(l):
                    if l[i] in '{}[]*\t\n\\ ':
                        break
                    i += 1
                # chord examples: '/', 'z', 'Am7@2', 'Am6zC@3'
                c = l[chord_begin:i]
                last_chord = [ c ]
        # the trailing string of the last chord can possibly include '\n' after which
        # it would be difficult to add further chords. Therefore move the trailing string
        # of the last chord to eol
        eol = last_chord[1] + eol
        last_chord[1] = ''

        bar_chords.set_before_number(before_number)
        bar_chords.set_after_number(after_number)
        bar_chords.set_eol(eol)
        bar_chords.set_chords(ctable)

        song_bar_info.append(bar_info)
        song_bar_chords.append(bar_chords)

        bar_number = bar_number + 1
        bar_info = BarInfo()
        bar_chords = BarChords()
Ejemplo n.º 20
0
 def set_label_from_event(self, button, event):
     """ Sets the label of RepeatEnd button when the count has changed. """
     count = BarInfo.get_repeat_end_value(event)
     if count == "2": label = "RepeatEnd"
     else: label = "RepeatEnd " + count
     button.set_label(label)
Ejemplo n.º 21
0
 def set_label_from_event(self, button, event):
     """ Sets the label of RepeatEnd button when the count has changed. """
     count = BarInfo.get_repeat_end_value(event)
     if count == "2": label = "RepeatEnd"
     else: label = "RepeatEnd " + count
     button.set_label(label)