File: plugin.py

package info (click to toggle)
mma 21.09-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 51,828 kB
  • sloc: python: 16,751; sh: 26; makefile: 18; perl: 12
file content (140 lines) | stat: -rw-r--r-- 4,245 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# extend plugin

# This plugin is a sortof reverse truncate. It parses its arguments
# and splits the data out into 2 lines: an original line short enough for the
# current time, a truncate line and shortened line.
# The goal is to take:
#   Time 3
#   @extend side=right len=4 22 Am Bm C7 E9
#   ... into ...
#   22 Am Bm C7
#   Truncate side=right 1
#   22 E9
#   

import MMA.gbl as gbl
import MMA.timesig
from MMA.common import *

def run(ln):
    barLen = None     # We do need to fill this value
    side = 1          # default to left (1)
    timesig = None    # optional. Helpful if importing results into score prog.
    
    ln, opts = opt2pair(ln)  # Use MMA to gather options
    for cmd, o in opts:
        if cmd.upper()=='SIDE':
            side = o
        elif cmd.upper() == 'LEN':
            barLen = stoi(o, "@Extend LEN option expecting integer")
            if barLen == gbl.QperBar:
                error("@Extend: Expected the Len= to be different from the current TIME value.")
        elif cmd.upper() == "TIMESIG":
            timesig = o

    # Do some sanity/validity tests
    
    if '*' in ln:
        error("@Extend: does not support the '*' multiplier in data lines.")

    for a in ln:
        if '{' in a:
            error("@Extend: Does not support embedded solo/melody. Use Riff instead.")

        if '@' in a:
            error("@Extend: the '@' notation in chord data lines is not supported. " \
                      "You probably don't need to use it since it makes very little " \
                      "difference to the final sound. But, you can always create 2 chord " \
                      "lines and a Truncate by hand.")
            
    if barLen == None:
        error("@Extend: requires a LEN=x option. x is the new length of bar")

    if barLen > gbl.QperBar * 2:
        error("@Extend: doesn't support lines longer than 2x the current TIME setting.")

    # Create new lines for MMA to consider
    
    line1 = []
    line2 = []

    # we're shortening the line (just a normal Truncate) so
    # we don't need the split data. Just end up with
    #   Truncate ...
    #   Data
    if barLen <= gbl.QperBar:
        line2 = ln[:]

    # lengthen. End with:
    #   Data for full bar
    #   Truncate ..
    #   Data for partial bar
    else:
        if ln[0].isdigit():
            line1.append(ln[0])
            line2.append(ln[0])
            ln=ln[1:]
        for c,b in enumerate(ln):
            if c < gbl.QperBar:
                line1.append(b)
            else:
                line2.append(b)
        if len(line2)==0 or len(line2) == 1 and line2[0].isdigit:
            line2.append('/')

    len2 = int(barLen-gbl.QperBar)
    if len2<1:
        len2=barLen

    # Generate input for MMA. 
    ret = []
    
    if timesig:
        oldtime=MMA.timesig.timeSig.getAscii()
        ret.append(["Timesig", timesig])

    if len2 <= gbl.QperBar:
        ret.append(line1)

    ret.append( ["Truncate", 'side=%s' % side, '%s' % len2 ] )

    ret.append(line2)

    if timesig:
        ret.append(["Timesig",  oldtime])

    # And now MMA will happily do it all.
    gbl.inpath.push(ret, [gbl.lineno] * len(ret))

# Entry for usage (mma -Iextend)

def printUsage():
    print("""
@Extend len=dd [other options] Chord Data

Convert a data line into parts so that it can be longer (in beats)
than what the current Time supports. For example, you might have a
song in 3/4 which switches to 4/4 for a few bars. This function
will split the data lines into parts with interleaving TRUNCATE
lines. You can use a short length and it will work as a normal 
Truncate function.

A few differences between this plugin and the native Truncate:
  The is no Count option
  The length is specified with Len=dd
  The new bar length must be an integer value

Supported options are:
  Side=right,left,beat  -- defaults to left
  Len=count             -- new bar length REQUIRED
  TimeSig=N/D           -- inserts a timesig event in the midi file

Caution: Do not attempt to use this in Begin/End block. The line will
         recurse and you will end up in an infinite loop.

Following the options is a MMA data line with optional line number and chords.

  Author: bvdp, 2018/12/25. """)