Browse Source

Added saw wave

Grissess 9 years ago
parent
commit
a3cfdd481d
3 changed files with 44 additions and 10 deletions
  1. 4 0
      client.py
  2. 38 8
      mkiv.py
  3. 2 2
      shiv.py

+ 4 - 0
client.py

@@ -166,6 +166,10 @@ def tri_wave(theta):
     else:
     else:
         return lin_interp(-1, 0, (theta-3*math.pi/2)/(math.pi/2))
         return lin_interp(-1, 0, (theta-3*math.pi/2)/(math.pi/2))
 
 
+@generator('Saw wave (line from (0, 1) to (2pi, -1))')
+def saw_wave(theta):
+    return lin_interp(1, -1, theta/(math.pi * 2))
+
 @generator('Simple square wave (piecewise 1 at x<pi, 0 else)')
 @generator('Simple square wave (piecewise 1 at x<pi, 0 else)')
 def square_wave(theta):
 def square_wave(theta):
     if theta < math.pi:
     if theta < math.pi:

+ 38 - 8
mkiv.py

@@ -92,6 +92,8 @@ for fname in args:
     iv.set('version', '1')
     iv.set('version', '1')
     iv.set('src', os.path.basename(fname))
     iv.set('src', os.path.basename(fname))
     print fname, ': MIDI format,', len(pat), 'tracks'
     print fname, ': MIDI format,', len(pat), 'tracks'
+    if options.verbose:
+        print fname, ': MIDI Parameters:', pat.resolution, 'PPQN,', pat.format, 'format'
 
 
     if options.chansplit:
     if options.chansplit:
         print 'Splitting channels...'
         print 'Splitting channels...'
@@ -126,6 +128,38 @@ for fname in args:
 ##### Merge events from all tracks into one master list, annotated with track and absolute times #####
 ##### Merge events from all tracks into one master list, annotated with track and absolute times #####
     print 'Merging events...'
     print 'Merging events...'
 
 
+    class SortEvent(object):
+        __slots__ = ['ev', 'tidx', 'abstick']
+        def __init__(self, ev, tidx, abstick):
+            self.ev = ev
+            self.tidx = tidx
+            self.abstick = abstick
+
+    sorted_events = []
+    for tidx, track in enumerate(pat):
+        absticks = 0
+        for ev in track:
+            absticks += ev.tick
+            sorted_events.append(SortEvent(ev, tidx, absticks))
+
+    sorted_events.sort(key=lambda x: x.abstick)
+    bpm_at = {0: 120}
+
+    for sev in sorted_events:
+        if isinstance(sev.ev, midi.SetTempoEvent):
+            if options.debug:
+                print fname, ': SetTempo at', sev.abstick, 'to', sev.ev.bpm, ':', sev.ev
+            bpm_at[sev.abstick] = sev.ev.bpm
+
+    if options.verbose:
+        print fname, ': Events:', len(sorted_events)
+        print fname, ': Resolved global BPM:', bpm_at
+        if options.debug:
+            btimes = bpm_at.keys()
+            for i in range(len(btimes) - 1):
+                fev = filter(lambda sev: sev.abstick >= btimes[i] and sev.abstick < btimes[i+1], sorted_events)
+                print fname, ': BPM partition', i, 'contains', len(fev), 'events'
+
     class MergeEvent(object):
     class MergeEvent(object):
         __slots__ = ['ev', 'tidx', 'abstime', 'bank', 'prog']
         __slots__ = ['ev', 'tidx', 'abstime', 'bank', 'prog']
         def __init__(self, ev, tidx, abstime, bank, prog):
         def __init__(self, ev, tidx, abstime, bank, prog):
@@ -138,7 +172,6 @@ for fname in args:
             return '<ME %r in %d @%f>'%(self.ev, self.tidx, self.abstime)
             return '<ME %r in %d @%f>'%(self.ev, self.tidx, self.abstime)
 
 
     events = []
     events = []
-    bpm_at = {0: 120}
     cur_bank = [[0 for i in range(16)] for j in range(len(pat))]
     cur_bank = [[0 for i in range(16)] for j in range(len(pat))]
     cur_prog = [[0 for i in range(16)] for j in range(len(pat))]
     cur_prog = [[0 for i in range(16)] for j in range(len(pat))]
     chg_bank = [[0 for i in range(16)] for j in range(len(pat))]
     chg_bank = [[0 for i in range(16)] for j in range(len(pat))]
@@ -150,12 +183,11 @@ for fname in args:
         abstime = 0
         abstime = 0
         absticks = 0
         absticks = 0
         for ev in track:
         for ev in track:
+            bpm = filter(lambda pair: pair[0] <= absticks, sorted(bpm_at.items(), key=lambda pair: pair[0]))[-1][1]
             if options.debug:
             if options.debug:
-                print ev
-            if isinstance(ev, midi.SetTempoEvent):
-                absticks += ev.tick
-                bpm_at[absticks] = ev.bpm
-            elif isinstance(ev, midi.ProgramChangeEvent):
+                print ev, ': bpm=', bpm
+            absticks += ev.tick
+            if isinstance(ev, midi.ProgramChangeEvent):
                 cur_prog[tidx][ev.channel] = ev.value
                 cur_prog[tidx][ev.channel] = ev.value
                 chg_prog[tidx][ev.channel] += 1
                 chg_prog[tidx][ev.channel] += 1
             elif isinstance(ev, midi.ControlChangeEvent):
             elif isinstance(ev, midi.ControlChangeEvent):
@@ -170,9 +202,7 @@ for fname in args:
             elif isinstance(ev, midi.Event):
             elif isinstance(ev, midi.Event):
                 if isinstance(ev, midi.NoteOnEvent) and ev.velocity == 0:
                 if isinstance(ev, midi.NoteOnEvent) and ev.velocity == 0:
                     ev.__class__ = midi.NoteOffEvent #XXX Oww
                     ev.__class__ = midi.NoteOffEvent #XXX Oww
-                bpm = filter(lambda pair: pair[0] <= absticks, sorted(bpm_at.items(), key=lambda pair: pair[0]))[-1][1]
                 abstime += (60.0 * ev.tick) / (bpm * pat.resolution)
                 abstime += (60.0 * ev.tick) / (bpm * pat.resolution)
-                absticks += ev.tick
                 events.append(MergeEvent(ev, tidx, abstime, cur_bank[tidx][ev.channel], cur_prog[tidx][ev.channel]))
                 events.append(MergeEvent(ev, tidx, abstime, cur_bank[tidx][ev.channel], cur_prog[tidx][ev.channel]))
                 ev_cnts[tidx][ev.channel] += 1
                 ev_cnts[tidx][ev.channel] += 1
 
 

+ 2 - 2
shiv.py

@@ -9,8 +9,8 @@ parser.add_option('-n', '--number', dest='number', action='store_true', help='Sh
 parser.add_option('-g', '--groups', dest='groups', action='store_true', help='Show group names')
 parser.add_option('-g', '--groups', dest='groups', action='store_true', help='Show group names')
 parser.add_option('-N', '--notes', dest='notes', action='store_true', help='Show number of notes')
 parser.add_option('-N', '--notes', dest='notes', action='store_true', help='Show number of notes')
 parser.add_option('-m', '--meta', dest='meta', action='store_true', help='Show meta track information')
 parser.add_option('-m', '--meta', dest='meta', action='store_true', help='Show meta track information')
-parser.add_option('-h', '--histogram', dest='histogram', action='store_true', help='Show a histogram distribution of pitches')
-parser.add_option('-H', '--histogram-tracks', dest='histogram_tracks', action='store_true', help='Show a histogram distribution of pitches per track')
+parser.add_option('--histogram', dest='histogram', action='store_true', help='Show a histogram distribution of pitches')
+parser.add_option('--histogram-tracks', dest='histogram_tracks', action='store_true', help='Show a histogram distribution of pitches per track')
 parser.add_option('-d', '--duration', dest='duration', action='store_true', help='Show the duration of the piece')
 parser.add_option('-d', '--duration', dest='duration', action='store_true', help='Show the duration of the piece')
 parser.add_option('-D', '--duty-cycle', dest='duty_cycle', action='store_true', help='Show the duration of the notes within tracks, and as a percentage of the piece duration')
 parser.add_option('-D', '--duty-cycle', dest='duty_cycle', action='store_true', help='Show the duration of the notes within tracks, and as a percentage of the piece duration')