import sys,os,types,json from random import randrange class NoteTester: def __init__( self, cfg, api ): self.cfg = cfg self.api = api r = types.SimpleNamespace(**cfg.NoteTester) self.durMsL = [ randrange(r.minNoteDurMs, r.maxNoteDurMs) for _ in range(r.noteCount) ] self.pauseMsL = [ randrange(r.minPauseDurMs, r.maxPauseDurMs) for _ in range(r.noteCount) ] self.eventL = [] self.nextMs = 0 # next transition time self.eventIdx = 0 # next event to play self.noteOnFl = False # True if note is currently sounding self.pitch = r.pitch # self.filename = r.filename self.isStartedFl = False self.minAttackUsec = r.minAttackUsec self.maxAttackUsec = r.maxAttackUsec def start( self ): self.eventIdx = 0 self.noteOnFl = False self.nextMs = 0 self.isStartedFl = True def stop( self ): self.isStartedFl = False self.write() def tick( self, ms ): if self.isStartedFl and ms > self.nextMs: offsMs = 0 if self.noteOnFl: self.noteOnFl = False self.api.note_off( self.pitch ) offsMs = self.pauseMsL[ self.eventIdx ] self.eventIdx += 1 print("off:%i ms" % (offsMs)) else: usec = self.minAttackUsec + (int(self.eventIdx * 250) % int(self.maxAttackUsec - self.minAttackUsec)) decay_level = self.api.calc_decay_level( usec ) self.api.note_on_us( self.pitch, usec, decay_level ) offsMs = self.durMsL[ self.eventIdx ] print("usec:%i %i dcy:%i" % (usec,offsMs, decay_level) ) self.noteOnFl = True self.eventL.append( (ms, self.noteOnFl) ) self.nextMs = ms + offsMs if self.eventIdx >= len(self.durMsL): self.write(); self.isStartedFl = False print("done % i" % (len(self.eventL))) def write( self ): with open(self.filename,"w") as f: json.dump({ "eventL":self.eventL },f ) def note_tester_compare( nt_fn, logica_fn ): eventL = [] logicaL = [] with open(nt_fn,"r") as f: r = json.load(f) eventL = r['eventL'] eventL = [ (ms-eventL[0][0], level ) for ms,level in eventL ] with open(logica_fn,"r") as f: logicaL = [ ( d['count']/16e3,d['level']) for d in json.load(f) if d['signal'] == 0 ] logicaL = [ (ms-logicaL[0][0], level!=0 ) for ms,level in logicaL ] print(len(eventL)) print(len(logicaL)) #edL = [ eventL[i][0] - eventL[i-1][0] for i in range(2,len(eventL)) ] #ldL = [ logicaL[i][0] - logicaL[i-1][0] for i in range(2,len(logicaL)) ] #print(edL[:10]) #print(ldL[:10]) durMs = 0 ms = 0 for i,(t0,t1) in enumerate(zip(eventL,logicaL)): t = t0[0] # eventL[] time dt = int(t - t1[0]) # diff between eventL[] and logicaL[] time fl = ' ' if t0[1] == t1[1] else '*' # mark level mismatch with '*' print("%5i %7i %4i %i %s" % (i,durMs,dt,t0[1],fl)) durMs = t-ms ms = t if __name__ == "__main__": nt_fn = "note_tester.json" logica_fn = sys.argv[1] if len(sys.argv) > 2: nt_fn = sys.argv[2] note_tester_compare( nt_fn, logica_fn)