171 lines
7.6 KiB
Python
171 lines
7.6 KiB
Python
"""
|
|
Music buzzer
|
|
|
|
Micropython library for the Music buzzer
|
|
=======================================================
|
|
|
|
#Based on Author: qiren123(MIDI Music) 20220618
|
|
#Make changes to instantiation 20220622
|
|
#Increase level reversal selection 20220716
|
|
|
|
dahanzimin From the Mixly Team
|
|
"""
|
|
|
|
import time
|
|
import math
|
|
import struct
|
|
|
|
normal_tone = {
|
|
'A1': 55, 'B1': 62, 'C1': 33, 'D1': 37, 'E1': 41, 'F1': 44, 'G1': 49,
|
|
'A2': 110, 'B2': 123, 'C2': 65, 'D2': 73, 'E2': 82, 'F2': 87, 'G2': 98,
|
|
'A3': 220, 'B3': 247, 'C3': 131, 'D3': 147, 'E3': 165, 'F3': 175, 'G3': 196,
|
|
'A4': 440, 'B4': 494, 'C4': 262, 'D4': 294, 'E4': 330, 'F4': 349, 'G4': 392,
|
|
'A5': 880, 'B5': 988, 'C5': 523, 'D5': 587, 'E5': 659, 'F5': 698, 'G5': 784,
|
|
'A6': 1760, 'B6': 1976, 'C6': 1047, 'D6': 1175, 'E6': 1319, 'F6': 1397, 'G6': 1568,
|
|
'A7': 3520, 'B7': 3951, 'C7': 2093, 'D7': 2349, 'E7': 2637, 'F7': 2794, 'G7': 3135,
|
|
'A8': 7040, 'B8': 7902, 'C8': 4186, 'D8': 4699, 'E8': 5274, 'F8': 5588, 'G8': 6271,
|
|
'A9': 14080, 'B9': 15804}
|
|
|
|
Letter = 'ABCDEFG#R'
|
|
|
|
|
|
class MIDI():
|
|
def __init__(self, i2s_bus, rate=22050):
|
|
self.reset()
|
|
self._rate = rate
|
|
self.i2s_bus = i2s_bus
|
|
|
|
def _wave(self, frequency):
|
|
_period = self._rate // frequency
|
|
_samples = bytearray()
|
|
for i in range(_period):
|
|
sample = 32768 + int((32767) * math.sin(2 * math.pi * i / _period))
|
|
_samples.extend(struct.pack("<h", sample))
|
|
return bytes(_samples)
|
|
|
|
def _tone(self, frequency, duration_ms=1000):
|
|
_wave = self._wave(frequency)
|
|
_samples = self._rate * duration_ms // 1000
|
|
_data = _wave * (_samples // (len(_wave) // 2) + 1)
|
|
_data = _data[:_samples * 2]
|
|
|
|
_wbytes = 0
|
|
while _wbytes < len(_data):
|
|
send_size = min(512, len(_data) - _wbytes)
|
|
self.i2s_bus.write(_data[_wbytes: _wbytes + send_size])
|
|
_wbytes += send_size
|
|
|
|
def set_tempo(self, ticks=4, bpm=120):
|
|
self.ticks = ticks
|
|
self.bpm = bpm
|
|
self.beat = 60000 / self.bpm / self.ticks
|
|
|
|
def set_octave(self, octave=4):
|
|
self.octave = octave
|
|
|
|
def set_duration(self, duration=4):
|
|
self.duration = duration
|
|
|
|
def get_tempo(self):
|
|
return (self.ticks, self.bpm)
|
|
|
|
def get_octave(self):
|
|
return self.octave
|
|
|
|
def get_duration(self):
|
|
return self.duration
|
|
|
|
def reset(self):
|
|
self.set_duration()
|
|
self.set_octave()
|
|
self.set_tempo()
|
|
|
|
def parse(self, tone, dict):
|
|
time = self.beat * self.duration
|
|
pos = tone.find(':')
|
|
if pos != -1:
|
|
time = self.beat * int(tone[(pos + 1):])
|
|
tone = tone[:pos]
|
|
freq, tone_size = 1, len(tone)
|
|
if 'R' in tone:
|
|
freq = 20000
|
|
elif tone_size == 1:
|
|
freq = dict[tone[0] + str(self.octave)]
|
|
elif tone_size == 2:
|
|
freq = dict[tone]
|
|
self.set_octave(tone[1:])
|
|
return int(freq), int(time)
|
|
|
|
def midi(self, tone):
|
|
pos = tone.find('#')
|
|
if pos != -1:
|
|
return self.parse(tone.replace('#', ''), normal_tone)
|
|
pos = tone.find('B')
|
|
if pos != -1 and pos != 0:
|
|
return self.parse(tone.replace('B', ''), normal_tone)
|
|
return self.parse(tone, normal_tone)
|
|
|
|
def set_default(self, tone):
|
|
pos = tone.find(':')
|
|
if pos != -1:
|
|
self.set_duration(int(tone[(pos + 1):]))
|
|
tone = tone[:pos]
|
|
|
|
def play(self, tune, duration=None):
|
|
if duration is None:
|
|
self.set_default(tune[0])
|
|
else:
|
|
self.set_duration(duration)
|
|
for tone in tune:
|
|
tone = tone.upper()
|
|
if tone[0] not in Letter:
|
|
continue
|
|
midi = self.midi(tone)
|
|
self._tone(midi[0], midi[1])
|
|
self._tone(20000, 1)
|
|
time.sleep_ms(10)
|
|
|
|
def pitch(self, freq):
|
|
pass
|
|
|
|
def pitch_time(self, freq, delay):
|
|
self._tone(freq, delay)
|
|
time.sleep_ms(10)
|
|
|
|
def stop(self):
|
|
pass
|
|
|
|
DADADADUM = ['r4:2', 'g', 'g', 'g', 'eb:8', 'r:2', 'f', 'f', 'f', 'd:8']
|
|
ENTERTAINER = ['d4:1', 'd#', 'e', 'c5:2', 'e4:1', 'c5:2', 'e4:1',
|
|
'c5:3', 'c:1', 'd', 'd#', 'e', 'c', 'd', 'e:2', 'b4:1', 'd5:2', 'c:4']
|
|
PRELUDE = ['c4:1', 'e', 'g', 'c5', 'e', 'g4', 'c5', 'e', 'c4', 'e', 'g', 'c5', 'e', 'g4', 'c5', 'e', 'c4', 'd', 'g', 'd5', 'f', 'g4', 'd5', 'f', 'c4', 'd', 'g', 'd5', 'f', 'g4', 'd5',
|
|
'f', 'b3', 'd4', 'g', 'd5', 'f', 'g4', 'd5', 'f', 'b3', 'd4', 'g', 'd5', 'f', 'g4', 'd5', 'f', 'c4', 'e', 'g', 'c5', 'e', 'g4', 'c5', 'e', 'c4', 'e', 'g', 'c5', 'e', 'g4', 'c5', 'e']
|
|
ODE = ['e4', 'e', 'f', 'g', 'g', 'f', 'e', 'd', 'c', 'c', 'd', 'e', 'e:6', 'd:2', 'd:8',
|
|
'e:4', 'e', 'f', 'g', 'g', 'f', 'e', 'd', 'c', 'c', 'd', 'e', 'd:6', 'c:2', 'c:8']
|
|
NYAN = ['f#5:1', 'g#', 'c#:1', 'd#:2', 'b4:1', 'd5:1', 'c#', 'b4:2', 'b', 'c#5', 'd', 'd:1', 'c#', 'b4:1', 'c#5:1', 'd#', 'f#', 'g#', 'd#', 'f#', 'c#', 'd', 'b4', 'c#5', 'b4', 'd#5:2', 'f#', 'g#:1', 'd#', 'f#', 'c#', 'd#', 'b4', 'd5', 'd#', 'd', 'c#', 'b4', 'c#5', 'd:2', 'b4:1', 'c#5', 'd#', 'f#', 'c#', 'd', 'c#', 'b4', 'c#5:2', 'b4', 'c#5',
|
|
'b4', 'f#:1', 'g#', 'b:2', 'f#:1', 'g#', 'b', 'c#5', 'd#', 'b4', 'e5', 'd#', 'e', 'f#', 'b4:2', 'b', 'f#:1', 'g#', 'b', 'f#', 'e5', 'd#', 'c#', 'b4', 'f#', 'd#', 'e', 'f#', 'b:2', 'f#:1', 'g#', 'b:2', 'f#:1', 'g#', 'b', 'b', 'c#5', 'd#', 'b4', 'f#', 'g#', 'f#', 'b:2', 'b:1', 'a#', 'b', 'f#', 'g#', 'b', 'e5', 'd#', 'e', 'f#', 'b4:2', 'c#5']
|
|
RINGTONE = ['c4:1', 'd', 'e:2', 'g', 'd:1', 'e',
|
|
'f:2', 'a', 'e:1', 'f', 'g:2', 'b', 'c5:4']
|
|
FUNK = ['c2:2', 'c', 'd#', 'c:1', 'f:2', 'c:1', 'f:2', 'f#',
|
|
'g', 'c', 'c', 'g', 'c:1', 'f#:2', 'c:1', 'f#:2', 'f', 'd#']
|
|
BLUES = ['c2:2', 'e', 'g', 'a', 'a#', 'a', 'g', 'e', 'c2:2', 'e', 'g', 'a', 'a#', 'a', 'g', 'e', 'f', 'a', 'c3', 'd', 'd#', 'd', 'c',
|
|
'a2', 'c2:2', 'e', 'g', 'a', 'a#', 'a', 'g', 'e', 'g', 'b', 'd3', 'f', 'f2', 'a', 'c3', 'd#', 'c2:2', 'e', 'g', 'e', 'g', 'f', 'e', 'd']
|
|
BIRTHDAY = ['c4:4', 'c:1', 'd:4', 'c:4', 'f', 'e:8', 'c:3', 'c:1', 'd:4', 'c:4', 'g',
|
|
'f:8', 'c:3', 'c:1', 'c5:4', 'a4', 'f', 'e', 'd', 'a#:3', 'a#:1', 'a:4', 'f', 'g', 'f:8']
|
|
WEDDING = ['c4:4', 'f:3', 'f:1', 'f:8', 'c:4', 'g:3', 'e:1', 'f:8',
|
|
'c:4', 'f:3', 'a:1', 'c5:4', 'a4:3', 'f:1', 'f:4', 'e:3', 'f:1', 'g:8']
|
|
FUNERAL = ['c3:4', 'c:3', 'c:1', 'c:4', 'd#:3',
|
|
'd:1', 'd:3', 'c:1', 'c:3', 'b2:1', 'c3:4']
|
|
PUNCHLINE = ['c4:3', 'g3:1', 'f#', 'g', 'g#:3', 'g', 'r', 'b', 'c4']
|
|
PYTHON = ['d5:1', 'b4', 'r', 'b', 'b', 'a#', 'b', 'g5', 'r', 'd', 'd', 'r', 'b4', 'c5', 'r', 'c', 'c', 'r', 'd', 'e:5', 'c:1', 'a4', 'r', 'a', 'a', 'g#', 'a', 'f#5', 'r', 'e', 'e', 'r', 'c', 'b4', 'r', 'b', 'b', 'r', 'c5', 'd:5',
|
|
'd:1', 'b4', 'r', 'b', 'b', 'a#', 'b', 'b5', 'r', 'g', 'g', 'r', 'd', 'c#', 'r', 'a', 'a', 'r', 'a', 'a:5', 'g:1', 'f#:2', 'a:1', 'a', 'g#', 'a', 'e:2', 'a:1', 'a', 'g#', 'a', 'd', 'r', 'c#', 'd', 'r', 'c#', 'd:2', 'r:3']
|
|
BADDY = ['c3:3', 'r', 'd:2', 'd#', 'r', 'c', 'r', 'f#:8']
|
|
CHASE = ['a4:1', 'b', 'c5', 'b4', 'a:2', 'r', 'a:1', 'b', 'c5', 'b4', 'a:2', 'r', 'a:2', 'e5', 'd#', 'e', 'f', 'e', 'd#',
|
|
'e', 'b4:1', 'c5', 'd', 'c', 'b4:2', 'r', 'b:1', 'c5', 'd', 'c', 'b4:2', 'r', 'b:2', 'e5', 'd#', 'e', 'f', 'e', 'd#', 'e']
|
|
BA_DING = ['b5:1', 'e6:3']
|
|
WAWAWAWAA = ['e3:3', 'r:1', 'd#:3', 'r:1', 'd:4', 'r:1', 'c#:8']
|
|
JUMP_UP = ['c5:1', 'd', 'e', 'f', 'g']
|
|
JUMP_DOWN = ['g5:1', 'f', 'e', 'd', 'c']
|
|
POWER_UP = ['g4:1', 'c5', 'e4', 'g5:2', 'e5:1', 'g5:3']
|
|
POWER_DOWN = ['g5:1', 'd#', 'c', 'g4:2', 'b:1', 'c5:3']
|