123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- import json
- from rt_note_analysis import RT_Analyzer
-
- class VelTablePlayer:
-
- def __init__( self, cfg, api, audio, holdDutyPctD, fn ):
- self.cfg = cfg
- self.api = api
- self.audio = audio
- self.rtAnalyzer = RT_Analyzer()
- self.holdDutyPctD = holdDutyPctD
- self.durMs = 500
- self.mode = "across"
- self.state = "off"
- self.minPitch = 21
- self.maxPitch = 108
- self.velMapD = {}
-
- self.curMaxPitch = self.maxPitch
- self.curMinPitch = self.minPitch
- self.curPitch = 21
- self.curVelocity = 0
- self.curEndMs = 0
- self.curBegNoteMs = 0
- self.curEndNoteMs = 0
-
- with open(fn,"r") as f:
- d = json.load(f)
-
- for pitch,value in d.items():
- self.velMapD[ int(pitch) ] = [ int(x[0]) for x in d[pitch] ]
-
- assert self.minPitch in self.velMapD
- assert self.maxPitch in self.velMapD
-
-
- def start( self, minPitch, maxPitch, mode ):
- self.curMaxPitch = maxPitch
- self.curMinPitch = minPitch
- self.curPitch = minPitch
- self.curVelocity = 0
- self.state = "note_on"
- self.mode = mode
- self.audio.record_enable(True) # start recording audio
-
- def stop( self ):
- self.curPitch = self.minPitch
- self._all_notes_off()
- self.audio.record_enable(False)
-
- def tick( self, ms ):
- if self.state == "off":
- pass
-
- elif self.state == "note_on":
- self.state = self._note_on(ms)
-
- elif self.state == "playing":
- if ms >= self.curEndMs:
- self.state = "note_off"
-
- elif self.state == "note_off":
- self.state = self._note_off(ms)
-
-
- def _get_duty_cycle( self, pitch, usec ):
- usDutyL = self.holdDutyPctD[pitch]
-
- for i in range(len(usDutyL)):
- if usDutyL[i][0] >= usec:
- return usDutyL[i][1]
-
- return usDutyL[-1][1]
-
- def _calc_next_pitch( self ):
-
- self.curPitch += 1
- while self.curPitch not in self.velMapD and self.curPitch <= self.curMaxPitch:
- self.curPitch+1
-
- return self.curPitch <= self.curMaxPitch
-
- def _get_next_note_params( self ):
-
- usec = None
- dutyPct = None
- doneFl = False
-
- if self.mode == "updown":
- if self.curVelocity + 1 < len(self.velMapD[ self.curPitch ]):
- self.curVelocity += 1
- else:
-
- if self._calc_next_pitch():
- self.curVelocity = 0
- else:
- doneFl = True
-
- else:
-
- if self._calc_next_pitch():
- self.curPitch += 1
- else:
- if self.curVelocity + 1 < len(self.velMapD[ self.curPitch ]):
- self.curVelocity += 1
- self.curPitch = self.curMinPitch
- else:
- doneFl = True
-
- if doneFl:
- self.audio.record_enable(False)
- else:
- usec = self.velMapD[self.curPitch][self.curVelocity]
-
- dutyPct = self._get_duty_cycle( self.curPitch, usec )
-
-
- return self.curPitch, usec, dutyPct
-
- def _note_on( self, ms ):
-
- pitch,usec,dutyPct = self._get_next_note_params()
-
- if not usec:
- return "off"
- else:
- print(self.curPitch,self.curVelocity,usec,dutyPct)
- self.curBegNoteMs = self.audio.buffer_sample_ms().value
- self.api.set_pwm_duty( pitch, dutyPct )
- self.api.note_on_us( pitch, usec )
- self.curEndMs = ms + self.durMs
- return "playing"
-
- def _note_off( self, ms ):
-
- self.curEndNoteMs = self.audio.buffer_sample_ms().value
- self.rtAnalyzer.analyze_note( self.audio, self.curPitch, self.curBegNoteMs, self.curEndNoteMs, self.cfg.analysisArgs['rmsAnalysisArgs'] )
- self.api.note_off( self.curPitch )
- return "note_on"
-
-
- def _all_notes_off( self ):
- if self.curPitch == 109:
- self.state = 'off'
- print('done')
- else:
- self.api.note_off( self.curPitch )
- self.curPitch += 1
|