@@ -829,51 +829,130 @@ def temp(self):
829829
830830class 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
872952PWMBuzzer .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