示例#1
0
文件: macro.py 项目: Nodd/MobileMMA
    def sysvar(self, s):
        """ Create an internal macro. """

        # Simple/global     system values

        if s == 'KEYSIG':
            return keySig.getKeysig()

        elif s == 'TIME':
            return str(gbl.QperBar)

        elif s == 'TEMPO':
            return str(gbl.tempo)

        elif s == 'OFFSET':
            return str(gbl.tickOffset)

        elif s == 'VOLUME':
            return    str(int(MMA.volume.volume * 100))  # INT() is important
            
        elif s == 'VOLUMERATIO':
            return str((MMA.volume.vTRatio * 100))

        elif s == 'LASTVOLUME':
            return str(int(MMA.volume.lastVolume * 100))

        elif s == 'GROOVE':
            return MMA.grooves.currentGroove

        elif s == 'GROOVELIST':
            return ' '.join(sorted([ x for x in MMA.grooves.glist.keys() if type(x) == type('')]))

        elif s == 'TRACKLIST':
            return ' '.join(sorted(gbl.tnames.keys()))

        elif s == 'LASTGROOVE':
            return MMA.grooves.lastGroove

        elif s == 'SEQ':
            return str(gbl.seqCount)

        elif s == 'SEQRND':
            if MMA.seqrnd.seqRnd[0] == 0: return "Off"
            if MMA.seqrnd.seqRnd[0] == 1: return "On"
            return ' '.join(MMA.seqrnd.seqRnd[1:])

        elif s == 'SEQSIZE':
            return str(gbl.seqSize)

        elif s == 'SWINGMODE':
            return MMA.swing.settings()

        elif s == 'TICKPOS':
            return str(gbl.tickOffset)

        elif s == 'TRANSPOSE':
            return str(gbl.transpose)

        elif s == 'STACKVALUE':
            if not self.pushstack:
                error( "Empty push/pull variable stack")
            return self.pushstack.pop()

        elif s == 'DEBUG':
            return "Debug=%s  Filenames=%s Patterns=%s " \
                    "Sequence=%s Runtime=%s Warnings=%s Expand=%s " \
                    "Roman=%s Plectrum=%s Groove=%s" % \
                    (gbl.debug, gbl.showFilenames, gbl.pshow, gbl.seqshow, \
                    gbl.showrun,  int(not gbl.noWarn), gbl.showExpand, 
                    gbl.rmShow, gbl.plecShow, gbl.gvShow)


        elif s == 'LASTDEBUG':
            return "Debug=%s  Filenames=%s Patterns=%s " \
                    "Sequence=%s Runtime=%s Warnings=%s Expand=%s " \
                    "Roman=%s Plectrum=%s Groove=%s" % \
                    (gbl.Ldebug, gbl.LshowFilenames, gbl.Lpshow, gbl.Lseqshow, \
                    gbl.Lshowrun,  int(not gbl.LnoWarn), gbl.LshowExpand,
                    gbl.LrmShow, gbl.LplecShow, gbl.LgvShow)

        elif s == 'VEXPAND':
            if self.expandMode:
                return "On"
            else:
                return "Off"

        elif s == "MIDIPLAYER":
            return "%s Background=%s Delay=%s." % \
            (' '.join(MMA.player.midiPlayer), MMA.player.inBackGround, 
                      MMA.player.waitTime)

        elif s == "MIDISPLIT":
            return ' '.join([str(x) for x in MMA.midi.splitChannels])

        elif s == 'SEQRNDWEIGHT':
            return ' '.join([str(x) for x in MMA.seqrnd.seqRndWeight])

        elif s == 'LIBPATH':
            return ' '.join(MMA.paths.libPath)

        elif s == 'INCPATH':
            return ' '.join(MMA.paths.incPath)

        elif s == 'VOICETR':
            return MMA.translate.vtable.retlist()

        elif s == 'TONETR':
            return MMA.translate.dtable.retlist()

        elif s == 'OUTPATH':
            return gbl.outPath

        elif s == 'BARNUM':
            return str(gbl.barNum + 1)

        elif s == 'LINENUM':
            return str(gbl.lineno)

        elif s == 'LYRIC':
            return lyric.setting()

        # Track vars ... these are in format TRACKNAME_VAR

        a=s.rfind('_')
        if a==-1:
            error("Unknown system variable $_%s" % s)

        tname = s[:a]
        func = s[a+1:]

        try:
            t=gbl.tnames[tname]
        except KeyError:
            error("System variable $_%s refers to nonexistent track." % s )


        if func == 'ACCENT':
            r=[]
            for s in t.accent:
                r.append("{")
                for b,v in s:
                    r.append('%g' % (b/float(gbl.BperQ)+1))
                    r.append(str(int(v * 100)))
                r.append("}")
            return ' '.join(r)

        elif func == 'ARTICULATE':
            return ' '.join([str(x) for x in t.artic])

        elif func == 'CHORDS':
            r = []
            for l in t.chord:
                r.append('{' + ' '.join(l) + '}')
            return ' '.join(r)

        elif func == 'CHANNEL':
            return str(t.channel)

        elif func == 'COMPRESS':
            return ' '.join([str(x) for x in t.compress])

        elif func == 'DIRECTION':
            if t.vtype == 'ARIA':
                return ' '.join([str(x) for x in t.selectDir])
            else:
                return ' '.join([str(x) for x in t.direction])

        elif func == 'DUPROOT':
            if t.vtype != "CHORD":
                error("Only CHORD tracks have DUPROOT")
            return t.getDupRootSetting()

        elif func == 'HARMONY':
            return ' '.join([str(x) for x in t.harmony])

        elif func == 'HARMONYVOLUME':
            return ' '.join([str(int(a * 100)) for a in t.harmonyVolume])

        elif func == 'INVERT':
            return ' '.join([str(x) for x in t.invert])

        elif func == 'LIMIT':
            return str( t.chordLimit )

        elif func == 'MALLET':
            if t.vtype not in ("SOLO", "MELODY"):
                error("Mallet only valid in SOLO and MELODY tracks")
            return "Mallet Rate=%i Decay=%i" % (t.mallet, t.malletDecay*100)

        elif func == 'MIDINOTE':
            return MMA.midinote.mopts(t)

        elif func == 'OCTAVE':
            return ' '.join([str(a/12) for a in t.octave])

        elif func == 'MOCTAVE':
            return ' '.join([str((a/12)-1) for a in t.octave])
            
        elif func == 'ORNAMENT':
            return MMA.ornament.getOrnOpts(t)

        elif func == 'RANGE':
            return ' '.join([str(x) for x in t.chordRange])

        elif func == 'RSKIP':
            m=''
            if t.rSkipBeats:
                m = "Beats=%s " % ','.join(['%g' % (x/float(gbl.BperQ)+1) for x in t.rSkipBeats])
            m += ' '.join([str(int(a * 100)) for a in t.rSkip])
            return m

        elif func == 'RTIME':
            tmp = []
            for a1, a2 in t.rTime:
                if a1 == a2:
                    tmp.append('%s' % abs(a1))
                else:
                    tmp.append('%s,%s' % ( a1, a2))
            return ' '.join(tmp)


        elif func == 'RVOLUME':
            tmp = []
            for a1, a2 in t.rVolume:
                a1 = int(a1 * 100)
                a2 = int(a2 * 100)
                if a1 == a2:
                    tmp.append('%s' % abs(a1))
                else:
                    tmp.append('%s,%s' % ( a1, a2))
            return ' '.join(tmp)
      
        elif func == 'SEQUENCE':
            tmp = []
            for a in range(gbl.seqSize):
                tmp.append('{' + t.formatPattern(t.sequence[a]) + '}')
            return ' '.join(tmp)

        elif func == 'SEQRND':
            if t.seqRnd: return 'On'
            else:        return 'Off'

        elif func == 'SEQRNDWEIGHT':
            return ' '.join([str(x) for x in t.seqRndWeight])

        elif func == 'SPAN':
            return "%s %s" % (t.spanStart, t.spanEnd)

        elif func == 'STRUM':
            r=[]
            for v in t.strum:
                if v == None:
                    r.append("0")
                else:
                    a,b = v
                    if a==b:
                        r.append("%s" % a)
                    else:
                        r.append("%s,%s" % (a,b))
                
            return ' '.join(r)

        elif func == 'TONE':
            if t.vtype != "DRUM":
                error("Only DRUM tracks have TONE")
            return ' '.join([MMA.midiC.valueToDrum(a) for a in t.toneList])

        elif func == 'UNIFY':
            return ' '.join([str(x) for x in t.unify])

        elif func == 'VOICE':
            return ' '.join([MMA.midiC.valueToInst(a) for a in t.voice])


        elif func == 'VOICING':
            if t.vtype != 'CHORD':
                error("Only CHORD tracks have VOICING")
            t=t.voicing
            return "Mode=%s Range=%s Center=%s RMove=%s Move=%s Dir=%s" % \
                (t.mode, t.range, t.center, t.random, t.bcount, t.dir)

        elif func == 'VOLUME':
            return ' '.join([str(int(a * 100)) for a in t.volume])

        else:
            error("Unknown system track variable %s" % s)
示例#2
0
    def sysvar(self, s):
        """ Create an internal macro. """

        # Simple/global     system values

        if s == 'KEYSIG':
            return keySig.getKeysig()

        elif s == 'TIME':
            return str(gbl.QperBar)

        elif s == 'TEMPO':
            return str(gbl.tempo)

        elif s == 'OFFSET':
            return str(gbl.tickOffset)

        elif s == 'VOLUME':
            return str(int(MMA.volume.volume * 100))  # INT() is important

        elif s == 'VOLUMERATIO':
            return str((MMA.volume.vTRatio * 100))

        elif s == 'LASTVOLUME':
            return str(int(MMA.volume.lastVolume * 100))

        elif s == 'GROOVE':
            return MMA.grooves.currentGroove

        elif s == 'GROOVELIST':
            return ' '.join(
                sorted([
                    x for x in MMA.grooves.glist.keys() if type(x) == type('')
                ]))

        elif s == 'TRACKLIST':
            return ' '.join(sorted(gbl.tnames.keys()))

        elif s == 'LASTGROOVE':
            return MMA.grooves.lastGroove

        elif s == 'SEQ':
            return str(gbl.seqCount)

        elif s == 'SEQRND':
            if MMA.seqrnd.seqRnd[0] == 0: return "Off"
            if MMA.seqrnd.seqRnd[0] == 1: return "On"
            return ' '.join(MMA.seqrnd.seqRnd[1:])

        elif s == 'SEQSIZE':
            return str(gbl.seqSize)

        elif s == 'SWINGMODE':
            return MMA.swing.settings()

        elif s == 'TICKPOS':
            return str(gbl.tickOffset)

        elif s == 'TRANSPOSE':
            return str(gbl.transpose)

        elif s == 'STACKVALUE':
            if not self.pushstack:
                error("Empty push/pull variable stack")
            return self.pushstack.pop()

        elif s == 'DEBUG':
            return "Debug=%s  Filenames=%s Patterns=%s " \
                    "Sequence=%s Runtime=%s Warnings=%s Expand=%s " \
                    "Roman=%s Plectrum=%s Groove=%s" % \
                    (gbl.debug, gbl.showFilenames, gbl.pshow, gbl.seqshow, \
                    gbl.showrun,  int(not gbl.noWarn), gbl.showExpand,
                    gbl.rmShow, gbl.plecShow, gbl.gvShow)

        elif s == 'LASTDEBUG':
            return "Debug=%s  Filenames=%s Patterns=%s " \
                    "Sequence=%s Runtime=%s Warnings=%s Expand=%s " \
                    "Roman=%s Plectrum=%s Groove=%s" % \
                    (gbl.Ldebug, gbl.LshowFilenames, gbl.Lpshow, gbl.Lseqshow, \
                    gbl.Lshowrun,  int(not gbl.LnoWarn), gbl.LshowExpand,
                    gbl.LrmShow, gbl.LplecShow, gbl.LgvShow)

        elif s == 'VEXPAND':
            if self.expandMode:
                return "On"
            else:
                return "Off"

        elif s == "MIDIPLAYER":
            return "%s Background=%s Delay=%s." % \
            (' '.join(MMA.player.midiPlayer), MMA.player.inBackGround,
                      MMA.player.waitTime)

        elif s == "MIDISPLIT":
            return ' '.join([str(x) for x in MMA.midi.splitChannels])

        elif s == 'SEQRNDWEIGHT':
            return ' '.join([str(x) for x in MMA.seqrnd.seqRndWeight])

        elif s == 'LIBPATH':
            return ' '.join(MMA.paths.libPath)

        elif s == 'INCPATH':
            return ' '.join(MMA.paths.incPath)

        elif s == 'VOICETR':
            return MMA.translate.vtable.retlist()

        elif s == 'TONETR':
            return MMA.translate.dtable.retlist()

        elif s == 'OUTPATH':
            return gbl.outPath

        elif s == 'BARNUM':
            return str(gbl.barNum + 1)

        elif s == 'LINENUM':
            return str(gbl.lineno)

        elif s == 'LYRIC':
            return lyric.setting()

        # Track vars ... these are in format TRACKNAME_VAR

        a = s.rfind('_')
        if a == -1:
            error("Unknown system variable $_%s" % s)

        tname = s[:a]
        func = s[a + 1:]

        try:
            t = gbl.tnames[tname]
        except KeyError:
            error("System variable $_%s refers to nonexistent track." % s)

        if func == 'ACCENT':
            r = []
            for s in t.accent:
                r.append("{")
                for b, v in s:
                    r.append('%g' % (b / float(gbl.BperQ) + 1))
                    r.append(str(int(v * 100)))
                r.append("}")
            return ' '.join(r)

        elif func == 'ARTICULATE':
            return ' '.join([str(x) for x in t.artic])

        elif func == 'CHORDS':
            r = []
            for l in t.chord:
                r.append('{' + ' '.join(l) + '}')
            return ' '.join(r)

        elif func == 'CHANNEL':
            return str(t.channel)

        elif func == 'COMPRESS':
            return ' '.join([str(x) for x in t.compress])

        elif func == 'DIRECTION':
            if t.vtype == 'ARIA':
                return ' '.join([str(x) for x in t.selectDir])
            else:
                return ' '.join([str(x) for x in t.direction])

        elif func == 'DUPROOT':
            if t.vtype != "CHORD":
                error("Only CHORD tracks have DUPROOT")
            return t.getDupRootSetting()

        elif func == 'HARMONY':
            return ' '.join([str(x) for x in t.harmony])

        elif func == 'HARMONYVOLUME':
            return ' '.join([str(int(a * 100)) for a in t.harmonyVolume])

        elif func == 'INVERT':
            return ' '.join([str(x) for x in t.invert])

        elif func == 'LIMIT':
            return str(t.chordLimit)

        elif func == 'MALLET':
            if t.vtype not in ("SOLO", "MELODY"):
                error("Mallet only valid in SOLO and MELODY tracks")
            return "Mallet Rate=%i Decay=%i" % (t.mallet, t.malletDecay * 100)

        elif func == 'MIDINOTE':
            return MMA.midinote.mopts(t)

        elif func == 'OCTAVE':
            return ' '.join([str(a / 12) for a in t.octave])

        elif func == 'MOCTAVE':
            return ' '.join([str((a / 12) - 1) for a in t.octave])

        elif func == 'ORNAMENT':
            return MMA.ornament.getOrnOpts(t)

        elif func == 'RANGE':
            return ' '.join([str(x) for x in t.chordRange])

        elif func == 'RSKIP':
            m = ''
            if t.rSkipBeats:
                m = "Beats=%s " % ','.join(
                    ['%g' % (x / float(gbl.BperQ) + 1) for x in t.rSkipBeats])
            m += ' '.join([str(int(a * 100)) for a in t.rSkip])
            return m

        elif func == 'RTIME':
            tmp = []
            for a1, a2 in t.rTime:
                if a1 == a2:
                    tmp.append('%s' % abs(a1))
                else:
                    tmp.append('%s,%s' % (a1, a2))
            return ' '.join(tmp)

        elif func == 'RVOLUME':
            tmp = []
            for a1, a2 in t.rVolume:
                a1 = int(a1 * 100)
                a2 = int(a2 * 100)
                if a1 == a2:
                    tmp.append('%s' % abs(a1))
                else:
                    tmp.append('%s,%s' % (a1, a2))
            return ' '.join(tmp)

        elif func == 'SEQUENCE':
            tmp = []
            for a in range(gbl.seqSize):
                tmp.append('{' + t.formatPattern(t.sequence[a]) + '}')
            return ' '.join(tmp)

        elif func == 'SEQRND':
            if t.seqRnd: return 'On'
            else: return 'Off'

        elif func == 'SEQRNDWEIGHT':
            return ' '.join([str(x) for x in t.seqRndWeight])

        elif func == 'SPAN':
            return "%s %s" % (t.spanStart, t.spanEnd)

        elif func == 'STRUM':
            r = []
            for v in t.strum:
                if v == None:
                    r.append("0")
                else:
                    a, b = v
                    if a == b:
                        r.append("%s" % a)
                    else:
                        r.append("%s,%s" % (a, b))

            return ' '.join(r)

        elif func == 'TONE':
            if t.vtype != "DRUM":
                error("Only DRUM tracks have TONE")
            return ' '.join([MMA.midiC.valueToDrum(a) for a in t.toneList])

        elif func == 'UNIFY':
            return ' '.join([str(x) for x in t.unify])

        elif func == 'VOICE':
            return ' '.join([MMA.midiC.valueToInst(a) for a in t.voice])

        elif func == 'VOICING':
            if t.vtype != 'CHORD':
                error("Only CHORD tracks have VOICING")
            t = t.voicing
            return "Mode=%s Range=%s Center=%s RMove=%s Move=%s Dir=%s" % \
                (t.mode, t.range, t.center, t.random, t.bcount, t.dir)

        elif func == 'VOLUME':
            return ' '.join([str(int(a * 100)) for a in t.volume])

        else:
            error("Unknown system track variable %s" % s)
示例#3
0
    def trackBar(self, pattern, ctable):
        """ Do the aria bar.

        Called from self.bar()

        """

        sc = self.seq
        unify = self.unify[sc]

        for p in pattern:
            ct = self.getChordInPos(p.offset, ctable)

            if ct.ariaZ:
                continue

            thisChord = ct.chord.tonic + ct.chord.chordType
            stype = self.scaleType[sc]
            chrange = self.chordRange[sc]

            # Generate notelist if nesc. Note that in the keysig, scale and
            # range funcs restart() is called ... self.notes is reset.

            if stype == 'CHORD' and (not self.notes
                                     or self.lastChord != thisChord):
                notelist = ct.chord.noteList
                self.notes = []

            elif stype == 'CHROMATIC' and (not self.notes
                                           or self.lastChord != thisChord):
                notelist = [ct.chord.rootNote + x for x in range(0, 12)]
                self.notes = []

            elif stype == 'KEY' and not self.notes:
                k = keySig.getKeysig()
                ch, t = k.split()
                if t.lower() == 'minor':
                    ch += "m"
                notelist = list(MMA.chords.ChordNotes(ch).scaleList)

            elif (stype == 'SCALE' or stype == 'AUTO') and \
                    (not self.notes or self.lastChord != thisChord):
                notelist = list(ct.chord.scaleList)
                self.notes = []

            self.lastChord = thisChord

            # we have the base list of notes (scale, chord, etc) and
            # now we make it the right length & octave.
            if not self.notes:
                o = 0
                while chrange >= 1:
                    for a in notelist:
                        self.notes.append(a + o)
                    o += 12
                    chrange -= 1

                if chrange > 0 and chrange < 1:  # for fractional scale lengths
                    chrange = int(len(notelist) * chrange)
                    if chrange < 2:  # important, must be at least 2 notes in a scale
                        chrange = 2
                    for a in notelist[:chrange]:
                        self.notes.append(a + o)

            # grab a note from the list

            if self.dirptr >= len(self.selectDir):
                self.dirptr = 0

            # the direction ptr is either an int(-4..4) or a string of 'r', 'rr, etc.

            a = self.selectDir[self.dirptr]

            if isinstance(a, int):
                self.noteptr += a
            else:
                a = random.choice(range(-len(a), len(a) + 1))
                self.noteptr += a

            if self.noteptr >= len(self.notes):

                if a > 0:
                    self.noteptr = 0
                else:
                    self.noteptr = len(self.notes) - 1
            elif self.noteptr < 0:
                if a < 0:
                    self.noteptr = len(self.notes) - 1
                else:
                    self.noteptr = 0

            note = self.notes[self.noteptr]

            # delete note just selected if that's the mode
            if self.deplete[sc]:
                self.notes.remove(note)
            self.dirptr += 1

            # output

            if not self.harmonyOnly[sc]:
                notelist = [(note, p.vol)]
            else:
                notelist = []

            if self.harmony[sc]:
                h = MMA.harmony.harmonize(self.harmony[sc], note,
                                          ct.chord.noteList)
                harmlist = list(
                    zip(h, [p.vol * self.harmonyVolume[sc]] * len(h)))
            else:
                harmlist = []

            self.sendChord(notelist + harmlist, p.duration, p.offset)
    def trackBar(self, pattern, ctable):
        """ Do the aria bar.

        Called from self.bar()

        """

        sc = self.seq
        unify = self.unify[sc]

        for p in pattern:
            ct = self.getChordInPos(p.offset, ctable)

            if ct.ariaZ:
                continue

            thisChord = ct.chord.tonic + ct.chord.chordType
            stype = self.scaleType[sc]
            chrange = self.chordRange[sc]

            # Generate notelist if nesc. Note that in the keysig, scale and
            # range funcs restart() is called ... self.notes is reset.

            if stype == 'CHORD' and (not self.notes or self.lastChord != thisChord):
                notelist = ct.chord.noteList
                self.notes = []

            elif stype == 'CHROMATIC' and (not self.notes or self.lastChord != thisChord):
                notelist = [ct.chord.rootNote + x for x in range(0, 12)]
                self.notes = []

            elif stype == 'KEY' and not self.notes:
                k = keySig.getKeysig()
                ch, t = k.split()
                if t.lower() == 'minor':
                    ch += "m"
                notelist = list(MMA.chords.ChordNotes(ch).scaleList)

            elif (stype == 'SCALE' or stype == 'AUTO') and \
                    (not self.notes or self.lastChord != thisChord):
                notelist = list(ct.chord.scaleList)
                self.notes = []

            self.lastChord = thisChord

            # we have the base list of notes (scale, chord, etc) and
            # now we make it the right length & octave.
            if not self.notes:
                o = 0
                while chrange >= 1:
                    for a in notelist:
                        self.notes.append(a + o)
                    o += 12
                    chrange -= 1

                if chrange > 0 and chrange < 1:  # for fractional scale lengths
                    chrange = int(len(notelist) * chrange)
                    if chrange < 2:   # important, must be at least 2 notes in a scale
                        chrange = 2
                    for a in notelist[:chrange]:
                        self.notes.append(a + o)

            # grab a note from the list

            if self.dirptr >= len(self.selectDir):
                self.dirptr = 0

            # the direction ptr is either an int(-4..4) or a string of 'r', 'rr, etc.

            a = self.selectDir[self.dirptr]

            if isinstance(a, int):
                self.noteptr += a
            else:
                a = random.choice(range(-len(a), len(a) + 1))
                self.noteptr += a

            if self.noteptr >= len(self.notes):

                if a > 0:
                    self.noteptr = 0
                else:
                    self.noteptr = len(self.notes) - 1
            elif self.noteptr < 0:
                if a < 0:
                    self.noteptr = len(self.notes) - 1
                else:
                    self.noteptr = 0

            note = self.notes[self.noteptr]

            # delete note just selected if that's the mode
            if self.deplete[sc]:
                self.notes.remove(note)
            self.dirptr += 1

            # output

            if not self.harmonyOnly[sc]:
                notelist = [(note, p.vol)]
            else:
                notelist = []

            if self.harmony[sc]:
                h = MMA.harmony.harmonize(self.harmony[sc], note, ct.chord.noteList)
                harmlist = list(zip(h, [p.vol * self.harmonyVolume[sc]] * len(h)))
            else:
                harmlist = []

            self.sendChord(notelist + harmlist, p.duration, p.offset)
示例#5
0
    def sysvar(self, s):
        """ Create an internal macro. """

        # Check for system functions.

        m = re.match(r'([^\(]+)\((.*)\)$', s)
        if m:
            return self.sysfun(m.group(1), m.group(2))

        # Simple/global     system values

        if s == 'CHORDADJUST':
            return ' '.join([
                "%s=%s" % (a, MMA.chords.cdAdjust[a])
                for a in sorted(MMA.chords.cdAdjust)
            ])

        elif s == 'FILENAME':
            a = gbl.inpath.fname
            if isinstance(a, int):
                return ''
            else:
                return str(gbl.inpath.fname)

        elif s == 'FILEPATH':
            a = gbl.inpath.fname
            if isinstance(a, int):
                return ''
            else:
                return path.abspath(gbl.inpath.fname)

        elif s == 'SONGPATH':
            a = gbl.infile
            if isinstance(a, int):
                return ''
            else:
                return path.abspath(gbl.infile)

        elif s == 'KEYSIG':
            return keySig.getKeysig()

        elif s == 'TIME':
            return str(gbl.QperBar)

        elif s == 'CTABS':
            return ','.join([
                str((float(x) / gbl.BperQ) + 1) for x in MMA.parseCL.chordTabs
            ])

        elif s == 'TIMESIG':
            return timeSig.getAscii()

        elif s == 'TEMPO':  # get the current tempo via the record in midi.py
            tmp = gbl.tempo
            for o, t in MMA.midi.tempoChanges:
                if o > gbl.tickOffset:
                    break
                tmp = t
            return str(tmp)

        elif s == 'OFFSET':
            return str(gbl.tickOffset)

        elif s == 'SONGFILENAME':
            return str(gbl.infile)

        elif s == 'VOLUME':
            return str(int(MMA.volume.volume * 100))  # INT() is important

        elif s == 'VOLUMERATIO':
            return str((MMA.volume.vTRatio * 100))

        elif s == 'LASTVOLUME':
            return str(int(MMA.volume.lastVolume * 100))

        elif s == 'GROOVE':
            return MMA.grooves.currentGroove

        elif s == 'GROOVELIST':
            return ' '.join(
                sorted([
                    x for x in MMA.grooves.glist.keys() if isinstance(x, str)
                ]))

        elif s == 'TRACKLIST':
            return ' '.join(sorted(gbl.tnames.keys()))

        elif s == 'LASTGROOVE':
            return MMA.grooves.lastGroove

        elif s == 'PLUGINS':
            from MMA.regplug import simplePlugs  # to avoid circular import error
            return ' '.join(simplePlugs)

        elif s == 'TRACKPLUGINS':
            from MMA.regplug import trackPlugs  # to avoid circular import error
            return ' '.join(trackPlugs)

        elif s == 'DATAPLUGINS':
            from MMA.regplug import dataPlugs  # to avoid circular import error
            return ' '.join(dataPlugs)

        elif s == 'SEQ':
            return str(gbl.seqCount)

        elif s == 'SEQRND':
            if MMA.seqrnd.seqRnd[0] == 0:
                return "Off"
            if MMA.seqrnd.seqRnd[0] == 1:
                return "On"
            return ' '.join(MMA.seqrnd.seqRnd[1:])

        elif s == 'SEQSIZE':
            return str(gbl.seqSize)

        elif s == 'SWINGMODE':
            return MMA.swing.settings()

        elif s == 'TICKPOS':
            return str(gbl.tickOffset)

        elif s == 'TRANSPOSE':
            return str(gbl.transpose)

        elif s == 'STACKVALUE':
            if not self.pushstack:
                error("Empty push/pull variable stack")
            return self.pushstack.pop()

        elif s == 'DEBUG':
            return MMA.debug.getFlags()

        elif s == 'LASTDEBUG':
            return MMA.debug.getLFlags()

        elif s == 'VEXPAND':
            if self.expandMode:
                return "On"
            else:
                return "Off"

        elif s == "MIDIPLAYER":
            return "%s Background=%s Delay=%s." % \
                (' '.join(MMA.player.midiPlayer), MMA.player.inBackGround,
                 MMA.player.waitTime)

        elif s == "MIDISPLIT":
            return ' '.join([str(x) for x in MMA.midi.splitChannels])

        elif s == "MIDIASSIGNS":
            x = []
            for c, n in sorted(gbl.midiAssigns.items()):
                if n:
                    x.append("%s=%s" % (c, ','.join(n)))
            return ' '.join(x)

        elif s == 'SEQRNDWEIGHT':
            return ' '.join([str(x) for x in MMA.seqrnd.seqRndWeight])

        elif s == 'AUTOLIBPATH':
            return ' '.join(MMA.paths.libDirs)

        elif s == 'LIBPATH':
            return ' '.join(MMA.paths.libPath)

        elif s == 'MMAPATH':
            return gbl.MMAdir

        elif s == 'INCPATH':
            return ' '.join(MMA.paths.incPath)

        elif s == 'PLUGPATH':
            return ' '.join(MMA.paths.plugPaths)

        elif s == 'VOICETR':
            return MMA.translate.vtable.retlist()

        elif s == 'TONETR':
            return MMA.translate.dtable.retlist()

        elif s == 'OUTPATH':
            return gbl.outPath

        elif s == 'BARNUM':
            return str(gbl.barNum + 1)

        elif s == 'LINENUM':
            return str(gbl.lineno)

        elif s == 'LYRIC':
            return MMA.lyric.lyric.setting()

        # Some time/date macros. Useful for generating copyright strings

        elif s == 'DATEYEAR':
            return str(datetime.datetime.now().year)

        elif s == 'DATEDATE':
            return datetime.datetime.now().strftime("%Y-%m-%d")

        elif s == 'DATETIME':
            return datetime.datetime.now().strftime("%H:%M:%S")

        # Track vars ... these are in format TRACKNAME_VAR

        a = s.rfind('_')
        if a == -1:
            error("Unknown system variable $_%s" % s)

        tname = s[:a]
        func = s[a + 1:]

        try:
            t = gbl.tnames[tname]
        except KeyError:
            error("System variable $_%s refers to nonexistent track." % s)

        if func == 'ACCENT':
            r = []
            for s in t.accent:
                r.append("{")
                for b, v in s:
                    r.append('%g' % (b / float(gbl.BperQ) + 1))
                    r.append(str(int(v * 100)))
                r.append("}")
            return ' '.join(r)

        elif func == 'ARTICULATE':
            return ' '.join([str(x) for x in t.artic])

        elif func == 'CHORDS':
            r = []
            for l in t.chord:
                r.append('{' + ' '.join(l) + '}')
            return ' '.join(r)

        elif func == 'CHANNEL':
            return str(t.channel)

        elif func == 'COMPRESS':
            return ' '.join([str(x) for x in t.compress])

        elif func == 'DELAY':
            return ' '.join([str(x) for x in t.delay])

        elif func == 'DIRECTION':
            if t.vtype == 'ARIA':
                return ' '.join([str(x) for x in t.selectDir])
            else:
                return ' '.join([str(x) for x in t.direction])

        elif func == 'DUPROOT':
            if t.vtype != "CHORD":
                error("Only CHORD tracks have DUPROOT")
            return t.getDupRootSetting()

        elif func == 'FRETNOISE':
            return t.getFretNoiseOptions()

        elif func == 'HARMONY':
            return ' '.join([str(x) for x in t.harmony])

        elif func == 'HARMONYONLY':
            return ' '.join([str(x) for x in t.harmonyOnly])

        elif func == 'HARMONYVOLUME':
            return ' '.join([str(int(i * 100)) for i in t.harmonyVolume])

        elif func == 'INVERT':
            return ' '.join([str(x) for x in t.invert])

        elif func == 'LIMIT':
            return "%s mode=%s" % (t.chordLimit[0], t.chordLimit[1])

        elif func == 'MALLET':
            if t.vtype not in ("SOLO", "MELODY"):
                error("Mallet only valid in SOLO and MELODY tracks")
            return "Mallet Rate=%i Decay=%i" % (t.mallet, t.malletDecay * 100)

        elif func == 'MIDINOTE':
            return MMA.midinote.mopts(t)

        elif func == 'MIDIVOLUME':
            return "%s" % t.cVolume

        elif func == 'OCTAVE':
            return ' '.join([str(i // 12) for i in t.octave])

        elif func == 'MOCTAVE':
            return ' '.join([str((i // 12) - 1) for i in t.octave])

        elif func == 'ORNAMENT':
            return MMA.ornament.getOrnOpts(t)

        elif func == 'PLUGINS':
            from MMA.regplug import trackPlugs  # avoids circular import
            return ' '.join(trackPlugs)

        elif func == 'RANGE':
            return ' '.join([str(x) for x in t.chordRange])

        elif func == 'RSKIP':
            m = ''
            if t.rSkipBeats:
                m = "Beats=%s " % ','.join(
                    ['%g' % (x / float(gbl.BperQ) + 1) for x in t.rSkipBeats])
            m += ' '.join([str(int(i * 100)) for i in t.rSkip])
            return m

        elif func == 'RDURATION':
            tmp = []
            for a1, a2 in t.rDuration:
                a1 = int(a1 * 100)
                a2 = int(a2 * 100)
                if a1 == a2:
                    tmp.append('%s' % abs(a1))
                else:
                    tmp.append('%s,%s' % (a1, a2))

            return ' '.join(tmp)

        elif func == 'RTIME':
            tmp = []
            for a1, a2 in t.rTime:
                if a1 == a2:
                    tmp.append('%s' % abs(a1))
                else:
                    tmp.append('%s,%s' % (a1, a2))
            return ' '.join(tmp)

        elif func == 'RVOLUME':
            tmp = []
            for a1, a2 in t.rVolume:
                a1 = int(a1 * 100)
                a2 = int(a2 * 100)
                if a1 == a2:
                    tmp.append('%s' % abs(a1))
                else:
                    tmp.append('%s,%s' % (a1, a2))
            return ' '.join(tmp)

        elif func == 'RPITCH':
            return MMA.rpitch.getOpts(t)

        elif func == 'SEQUENCE':
            tmp = []
            for a in range(gbl.seqSize):
                tmp.append('{' + t.formatPattern(t.sequence[a]) + '}')
            return ' '.join(tmp)

        elif func == 'SEQRND':
            if t.seqRnd:
                return 'On'
            else:
                return 'Off'

        elif func == 'SEQRNDWEIGHT':
            return ' '.join([str(x) for x in t.seqRndWeight])

        elif func == 'SPAN':
            return "%s %s" % (t.spanStart, t.spanEnd)

        elif func == 'STICKY':
            if t.sticky:
                return "True"
            else:
                return "False"

        elif func == 'STRUM':
            r = []
            for v in t.strum:
                if v is None:
                    r.append("0")
                else:
                    a, b = v
                    if a == b:
                        r.append("%s" % a)
                    else:
                        r.append("%s,%s" % (a, b))

            return ' '.join(r)

        elif func == 'STRUMADD':
            return ' '.join([str(x) for x in t.strumAdd])

        elif func == 'TRIGGER':
            return MMA.trigger.getTriggerOptions(t)

        elif func == 'TONE':
            if t.vtype in ('MELODY', 'SOLO'):
                if not t.drumType:
                    error("Melody/Solo tracks must be DRUMTYPE for tone.")
                return str(MMA.midiC.valueToDrum(t.drumTone))

            elif t.vtype != 'DRUM':
                error("Tracktype %s doesn't have TONE" % t.vtype)

            return ' '.join([MMA.midiC.valueToDrum(a) for a in t.toneList])

        elif func == 'UNIFY':
            return ' '.join([str(x) for x in t.unify])

        elif func == 'VOICE':
            return ' '.join([MMA.midiC.valueToInst(a) for a in t.voice])

        elif func == 'VOICING':
            if t.vtype != 'CHORD':
                error("Only CHORD tracks have VOICING")
            t = t.voicing
            return "Mode=%s Range=%s Center=%s RMove=%s Move=%s Dir=%s" % \
                (t.mode, t.range, t.center, t.random, t.bcount, t.dir)

        elif func == 'VOLUME':
            return ' '.join([str(int(a * 100)) for a in t.volume])

        else:
            error("Unknown system track variable %s" % s)