Skip to content

Commit 33880f9

Browse files
authored
Update picozero.py
Updated PWMBuzzer to use ValueChange. #3
1 parent cee62d9 commit 33880f9

File tree

1 file changed

+110
-31
lines changed

1 file changed

+110
-31
lines changed

picozero/picozero.py

Lines changed: 110 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -829,51 +829,130 @@ def temp(self):
829829

830830
class PWMBuzzer(PWMOutputDevice):
831831

832-
def __init__(self, pin, freq=440, active_high=True, initial_value=False, duty_factor=1023):
832+
NOTES = {'b0': 31, 'c1': 33, 'c#1': 35, 'd1': 37, 'd#1': 39, 'e1': 41, 'f1': 44, 'f#1': 46, 'g1': 49,'g#1': 52, 'a1': 55,
833+
'a#1': 58, 'b1': 62, 'c2': 65, 'c#2': 69, 'd2': 73, 'd#2': 78,
834+
'e2': 82, 'f2': 87, 'f#2': 93, 'g2': 98, 'g#2': 104, 'a2': 110, 'a#2': 117, 'b2': 123,
835+
'c3': 131, 'c#3': 139, 'd3': 147, 'd#3': 156, 'e3': 165, 'f3': 175, 'f#3': 185, 'g3': 196, 'g#3': 208, 'a3': 220, 'a#3': 233, 'b3': 247,
836+
'c4': 262, 'c#4': 277, 'd4': 294, 'd#4': 311, 'e4': 330, 'f4': 349, 'f#4': 370, 'g4': 392, 'g#4': 415, 'a4': 440,'a#4': 466,'b4': 494,
837+
'c5': 523, 'c#5': 554, 'd5': 587, 'd#5': 622, 'e5': 659, 'f5': 698, 'f#5': 740, 'g5': 784, 'g#5': 831, 'a5': 880, 'a#5': 932, 'b5': 988,
838+
'c6': 1047, 'c#6': 1109, 'd6': 1175, 'd#6': 1245, 'e6': 1319, 'f6': 1397, 'f#6': 1480, 'g6': 1568, 'g#6': 1661, 'a6': 1760, 'a#6': 1865, 'b6': 1976,
839+
'c7': 2093, 'c#7': 2217, 'd7': 2349, 'd#7': 2489,
840+
'e7': 2637, 'f7': 2794, 'f#7': 2960, 'g7': 3136, 'g#7': 3322, 'a7': 3520, 'a#7': 3729, 'b7': 3951,
841+
'c8': 4186, 'c#8': 4435, 'd8': 4699, 'd#8': 4978 }
842+
843+
def __init__(self, pin, freq=440, active_high=True, initial_value=0, volume=0.5, bpm=120, duty_factor=1023):
844+
self._bpm = bpm
845+
self._volume = volume
833846
super().__init__(
834847
pin,
835848
freq=freq,
836849
duty_factor=duty_factor,
837850
active_high=active_high,
838-
initial_value=initial_value)
839-
840-
def play(self, freq=440, duration=1, volume=1, wait=True):
851+
initial_value= (freq, volume),
852+
)
853+
854+
@property
855+
def bpm(self):
856+
return self._bpm
841857

842-
self._pwm.freq(freq)
858+
@bpm.setter
859+
def bpm(self, value):
860+
self._bpm = value
861+
862+
@property
863+
def volume(self):
864+
return self._volume
843865

844-
if volume is not None:
845-
self.value = volume
866+
@volume.setter
867+
def volume(self, value):
868+
self._volume = value
869+
870+
@property
871+
def value(self):
872+
return tuple(self._pwm.freq(), self.volume)
846873

847-
if duration is not None:
848-
if wait:
849-
sleep(duration)
850-
self.off()
874+
@value.setter
875+
def value(self, value):
876+
self._stop_change()
877+
self._write(value)
878+
879+
def _write(self, value):
880+
if value == 0 or value is None or value == '':
881+
volume = 0
882+
else:
883+
if type(value) is not tuple:
884+
value = (value, self.volume)
885+
886+
(freq, volume) = value
887+
freq = self._to_freq(freq)
888+
889+
if freq is not None and freq is not '' and freq !=0:
890+
self._pwm.freq(freq)
851891
else:
852-
self._timer.init(period=int(duration * 1000), mode=Timer.ONE_SHOT, callback=self._stop)
853-
854-
def _stop(self, timer_obj=None):
855-
self.stop()
892+
volume = 0
856893

857-
def on(self, freq=None):
858-
if freq is not None:
859-
self._pwm.freq(freq)
860-
861-
self.value = 1
894+
super()._write(volume)
895+
896+
def pitch(self, freq=440, duration=1, volume=1, wait=True):
897+
if duration is None:
898+
self.value = (freq, volume)
899+
else:
900+
self.off()
901+
self._start_change(lambda : iter([((freq, volume), duration)]), 1, wait)
902+
903+
def _to_freq(self, freq):
904+
if freq is not None and freq is not '' and freq != 0:
905+
if type(freq) is str:
906+
return int(self.NOTES[freq])
907+
elif freq <= 128 and freq > 0: # MIDI
908+
midi_factor = 2**(1/12)
909+
return int(440 * midi_factor ** (freq - 69))
910+
else:
911+
return freq
912+
else:
913+
return None
914+
915+
def to_seconds(self, duration):
916+
return (duration * 60 / self._bpm)
917+
918+
def play(self, tune=440, duration=4, volume=1, n=1, wait=True, multiplier=0.9):
919+
920+
if type(tune) is not list: # use note and duration, no generator
921+
duration = self.to_seconds(duration * multiplier)
922+
self.pitch(tune, duration, volume, wait)
923+
elif type(tune[0]) is not list: # single note don't use a generator
924+
duration = self.to_seconds(tune[1] * multiplier)
925+
self.pitch(tune[0], duration, volume, wait) #, volume, multiplier, wait)
926+
else: # tune with multiple notes
927+
def tune_generator():
928+
for next in tune:
929+
note = next[0]
930+
if len(next) == 2:
931+
duration = self.to_seconds(float(next[1]))
932+
if note == '' or note is None:
933+
yield ((None, 0), duration)
934+
else:
935+
yield ((note, volume), duration * multiplier)
936+
yield ((None, 0), duration * (1 - multiplier))
862937

863-
def stop(self):
864-
self._timer.deinit()
865-
self.value = 0
938+
self.off()
939+
self._start_change(tune_generator, n, wait)
940+
941+
def _stop(self, timer_obj=None):
942+
self.off()
866943

867-
def close(self):
868-
self.stop()
869-
super().close()
944+
def on(self, freq=440, volume=1):
945+
if freq is not None:
946+
self.value = (freq, volume)
947+
948+
def __del__(self):
949+
self.off()
950+
super().__del__()
870951

871-
PWMBuzzer.volume = PWMBuzzer.value
872952
PWMBuzzer.beep = PWMBuzzer.blink
873953

874-
def Speaker(pin, use_tones=True, active_high=True, initial_value=False):
954+
def Speaker(pin, use_tones=True, active_high=True, volume=1, initial_value=False, bpm=120):
875955
if use_tones:
876-
return PWMBuzzer(pin, freq=440, active_high=active_high, initial_value=initial_value)
956+
return PWMBuzzer(pin, freq=440, active_high=active_high, initial_value=volume, bpm=bpm)
877957
else:
878-
return Buzzer(pin, active_high=active_high, initial_value=initial_value)
879-
958+
return Buzzer(pin, active_high=active_high, initial_value=False)

0 commit comments

Comments
 (0)