aboutsummaryrefslogtreecommitdiff
path: root/downsamp.py
blob: f7a0255aa5959e36ba62754e2f18c3632c546b39 (plain)
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
from xml.etree import ElementTree as ET
import optparse
import os

parser = optparse.OptionParser()
parser.add_option('-f', '--frequency', dest='frequency', type='float', help='How often to switch between active streams')
parser.set_defaults(frequency=0.016)
options, args = parser.parse_args()

class Note(object):
    def __init__(self, time, dur, pitch, ampl):
        self.time = time
        self.dur = dur
        self.pitch = pitch
        self.ampl = ampl

for fname in args:
    try:
        iv = ET.parse(fname).getroot()
    except IOError:
        import traceback
        traceback.print_exc()
        print fname, ': Bad file'
        continue

    print '----', fname, '----'

    notestreams = iv.findall("./streams/stream[@type='ns']")
    print len(notestreams), 'notestreams'

    print 'Loading all events...'

    evs = []

    dur = 0.0

    for ns in notestreams:
        for note in ns.findall('note'):
            n = Note(
                float(note.get('time')),
                float(note.get('dur')),
                float(note.get('pitch')),
                float(note.get('ampl', float(note.get('vel', 127.0)) / 127.0)),
            )
            evs.append(n)
            if n.time + n.dur > dur:
                dur = n.time + n.dur

    print len(evs), 'events'
    print dur, 'duration'

    print 'Scheduling events...'

    sched = {}

    t = 0.0
    i = 0
    while t <= dur:
        nextt = t + options.frequency
        #print '-t', t, 'nextt', nextt

        evs_now = [n for n in evs if n.time <= t and t < n.time + n.dur]
        if evs_now:
            holding = False
            count = 0
            while count < len(evs_now):
                selidx = (count + i) % len(evs_now)
                sel = evs_now[selidx]
                sched[t] = (sel.pitch, sel.ampl)
                if sel.time + sel.dur >= nextt:
                    holding = True
                    break
                t = sel.time + sel.dur
                count += 1
            if not holding:
                sched[t] = (0, 0)
        else:
            sched[t] = (0, 0)

        t = nextt
        i += 1

    print len(sched), 'events scheduled'

    print 'Writing out schedule...'

    newiv = ET.Element('iv')
    newiv.append(iv.find('meta'))
    newivstreams = ET.SubElement(newiv, 'streams')
    newivstream = ET.SubElement(newivstreams, 'stream', type='ns')

    prevt = None
    prevev = None
    for t, ev in sorted(sched.items(), key=lambda pair: pair[0]):
        if prevt is not None:
            if prevev[0] != 0:
                ET.SubElement(newivstream, 'note',
                        pitch = str(prevev[0]),
                        ampl = str(prevev[1]),
                        time = str(prevt),
                        dur = str(t - prevt),
                )
        prevev = ev
        prevt = t

    t = dur
    if prevev[0] != 0:
        ET.SubElement(newivstream, 'note',
                pitch = str(prevev[0]),
                ampl = str(prevev[1]),
                time = str(prevt),
                dur = str(t - prevt),
        )

    print 'Done.'
    txt = ET.tostring(newiv, 'UTF-8')
    open(os.path.splitext(os.path.basename(fname))[0]+'.downsampled.iv', 'wb').write(txt)