123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- import types
- import time
- from random import randrange
-
- class PolyNoteTester:
- def __init__( self, cfg, api ):
- self.api = api
-
- r = types.SimpleNamespace(**cfg.PolyNoteTester)
- self.cfg = r
-
- if r.mode == "simple":
- print("mode:simple")
- self.schedL = self._gen_simple_sched(r)
- else:
- print("mode:poly")
- self.schedL = self._gen_sched(r)
-
-
- self.schedL = sorted( self.schedL, key=lambda x: x[0] )
- self.nextMs = 0 # next transition time
- self.schedIdx = 0 # next event to play
- self.isStartedFl = False
-
- #self._report()
-
- def _report( self ):
- for t,cmd,pitch,atkUs in self.schedL:
- print("%s %6i %3i %5i" % (cmd,t,pitch,atkUs))
-
- def _gen_simple_sched( self, r ):
- """ Play each note sequentially from lowest to highest. """
- durMs = int(r.minNoteDurMs + (r.maxNoteDurMs - r.minNoteDurMs)/2)
- ioMs = int(r.minInterOnsetMs + (r.maxInterOnsetMs - r.minInterOnsetMs)/2)
- atkUs = int(r.minAttackUsec + (r.maxAttackUsec - r.minAttackUsec)/2)
- schedL = []
-
- t0 = 0
- for pitch in range(r.minPitch,r.maxPitch+1):
- schedL.append((t0,'on',pitch,atkUs))
- schedL.append((t0+durMs,'off',pitch,0))
- t0 += durMs + ioMs
-
- return schedL
-
-
- def _does_note_overlap( self, beg0Ms, end0Ms, beg1Ms, end1Ms ):
- """ if note 0 is entirely before or after note 1 """
- return not (beg0Ms > end1Ms or end0Ms < beg1Ms)
-
- def _do_any_notes_overlap( self, begMs, endMs, begEndL ):
- for beg1,end1 in begEndL:
- if self._does_note_overlap(begMs,endMs,beg1,end1):
- return True
- return False
-
- def _get_last_end_time( self, begEndL ):
- end0 = 0
- for beg,end in begEndL:
- if end > end0:
- end0 = end
-
- return end0
-
-
- def _gen_sched( self, r ):
-
- pitchL = [ randrange(r.minPitch,r.maxPitch) for _ in range(r.noteCount) ]
- durMsL = [ randrange(r.minNoteDurMs, r.maxNoteDurMs) for _ in range(r.noteCount) ]
- ioMsL = [ randrange(r.minInterOnsetMs, r.maxInterOnsetMs) for _ in range(r.noteCount) ]
- atkUsL = [ randrange(r.minAttackUsec, r.maxAttackUsec) for _ in range(r.noteCount) ]
- schedL = []
- pitchD = {} # pitch: [ (begMs,endMs) ]
-
- t0 = 0
- # for each pitch,dur,ioi,atkUs tuple
- for pitch,durMs,interOnsetMs,atkUs in zip(pitchL,durMsL,ioMsL,atkUsL):
-
- # calc note begin and end time
- begMs = t0
- endMs = t0 + durMs
-
- # if this pitch hasn't yet been added to pitchD
- if pitch not in pitchD:
- pitchD[ pitch ] = [ (begMs,endMs) ]
- else:
-
- # if the proposed note overlaps with other notes for this pitch
- if self._do_any_notes_overlap( begMs, endMs, pitchD[pitch] ):
- # move this pitch past the last note
- begMs = self._get_last_end_time( pitchD[pitch] ) + interOnsetMs
- endMs = begMs + durMs
-
- # add the new note to pitchD
- pitchD[ pitch ].append( (begMs,endMs) )
-
-
- # update the schedule
- schedL.append( (begMs, 'on', pitch, atkUs))
- schedL.append( (endMs, 'off', pitch, 0 ))
-
- t0 += interOnsetMs
-
-
- return schedL
-
-
- def start( self ):
- self.schedIdx = 0
- self.nextMs = 0
- self.api.set_hold_duty_all(self.cfg.holdDutyPct)
- self.isStartedFl = True
-
-
- def stop( self ):
- self.isStartedFl = False
- self.api.all_notes_off()
-
-
- def tick( self, ms ):
-
- while self.isStartedFl and ms >= self.nextMs and self.schedIdx < len(self.schedL):
-
- t0,cmd,pitch,usec = self.schedL[self.schedIdx]
-
- if cmd == 'on':
- if pitch not in self.cfg.skipPitchL:
- decay_level = self.api.calc_decay_level( usec )
- self.api.note_on_us( pitch, usec, decay_level )
- print("on %i %i %i" % (pitch,usec,decay_level))
-
- elif cmd == 'off':
- if pitch not in self.cfg.skipPitchL:
- self.api.note_off( pitch )
- print("off %i" % pitch)
-
- self.schedIdx += 1
- if self.schedIdx < len(self.schedL):
- self.nextMs = ms + (self.schedL[self.schedIdx][0] - t0)
- else:
- self.isStartedFl = False
- print("Done.")
-
-
-
-
-
-
|