picadae calibration programs
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

VelTablePlayer.py 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. import json
  2. from rt_note_analysis import RT_Analyzer
  3. class VelTablePlayer:
  4. def __init__( self, cfg, api, audio, holdDutyPctD, fn ):
  5. self.cfg = cfg
  6. self.api = api
  7. self.audio = audio
  8. self.rtAnalyzer = RT_Analyzer()
  9. self.holdDutyPctD = holdDutyPctD
  10. self.durMs = 500
  11. self.mode = "across"
  12. self.state = "off"
  13. self.minPitch = 21
  14. self.maxPitch = 108
  15. self.velMapD = {}
  16. self.curMaxPitch = self.maxPitch
  17. self.curMinPitch = self.minPitch
  18. self.curPitch = 21
  19. self.curVelocity = 0
  20. self.curEndMs = 0
  21. self.curBegNoteMs = 0
  22. self.curEndNoteMs = 0
  23. with open(fn,"r") as f:
  24. d = json.load(f)
  25. for pitch,value in d.items():
  26. self.velMapD[ int(pitch) ] = [ int(x[0]) for x in d[pitch] ]
  27. assert self.minPitch in self.velMapD
  28. assert self.maxPitch in self.velMapD
  29. def start( self, minPitch, maxPitch, mode ):
  30. self.curMaxPitch = maxPitch
  31. self.curMinPitch = minPitch
  32. self.curPitch = minPitch
  33. self.curVelocity = 0
  34. self.state = "note_on"
  35. self.mode = mode
  36. self.audio.record_enable(True) # start recording audio
  37. def stop( self ):
  38. self.curPitch = self.minPitch
  39. self._all_notes_off()
  40. self.audio.record_enable(False)
  41. def tick( self, ms ):
  42. if self.state == "off":
  43. pass
  44. elif self.state == "note_on":
  45. self.state = self._note_on(ms)
  46. elif self.state == "playing":
  47. if ms >= self.curEndMs:
  48. self.state = "note_off"
  49. elif self.state == "note_off":
  50. self.state = self._note_off(ms)
  51. def _get_duty_cycle( self, pitch, usec ):
  52. usDutyL = self.holdDutyPctD[pitch]
  53. for i in range(len(usDutyL)):
  54. if usDutyL[i][0] >= usec:
  55. return usDutyL[i][1]
  56. return usDutyL[-1][1]
  57. def _calc_next_pitch( self ):
  58. self.curPitch += 1
  59. while self.curPitch not in self.velMapD and self.curPitch <= self.curMaxPitch:
  60. self.curPitch+1
  61. return self.curPitch <= self.curMaxPitch
  62. def _get_next_note_params( self ):
  63. usec = None
  64. dutyPct = None
  65. doneFl = False
  66. if self.mode == "updown":
  67. if self.curVelocity + 1 < len(self.velMapD[ self.curPitch ]):
  68. self.curVelocity += 1
  69. else:
  70. if self._calc_next_pitch():
  71. self.curVelocity = 0
  72. else:
  73. doneFl = True
  74. else:
  75. if self._calc_next_pitch():
  76. self.curPitch += 1
  77. else:
  78. if self.curVelocity + 1 < len(self.velMapD[ self.curPitch ]):
  79. self.curVelocity += 1
  80. self.curPitch = self.curMinPitch
  81. else:
  82. doneFl = True
  83. if doneFl:
  84. self.audio.record_enable(False)
  85. else:
  86. usec = self.velMapD[self.curPitch][self.curVelocity]
  87. dutyPct = self._get_duty_cycle( self.curPitch, usec )
  88. return self.curPitch, usec, dutyPct
  89. def _note_on( self, ms ):
  90. pitch,usec,dutyPct = self._get_next_note_params()
  91. if not usec:
  92. return "off"
  93. else:
  94. print(self.curPitch,self.curVelocity,usec,dutyPct)
  95. self.curBegNoteMs = self.audio.buffer_sample_ms().value
  96. self.api.set_pwm_duty( pitch, dutyPct )
  97. self.api.note_on_us( pitch, usec )
  98. self.curEndMs = ms + self.durMs
  99. return "playing"
  100. def _note_off( self, ms ):
  101. self.curEndNoteMs = self.audio.buffer_sample_ms().value
  102. self.rtAnalyzer.analyze_note( self.audio, self.curPitch, self.curBegNoteMs, self.curEndNoteMs, self.cfg.analysisArgs['rmsAnalysisArgs'] )
  103. self.api.note_off( self.curPitch )
  104. return "note_on"
  105. def _all_notes_off( self ):
  106. if self.curPitch == 109:
  107. self.state = 'off'
  108. print('done')
  109. else:
  110. self.api.note_off( self.curPitch )
  111. self.curPitch += 1