diff --git a/Buzzer/README.md b/Buzzer/README.md index 08998164b776e5c9ed075058a1fd80ee11beefa6..c6c19fe0eacdb2aa8adfbd592d26314bebd20ae7 100644 --- a/Buzzer/README.md +++ b/Buzzer/README.md @@ -32,30 +32,74 @@   我们在可以在主函数中使用以下代码导入此库。 -```python +``` python from NumberedMusicalNotation import NumberedMusicalNotation ```   在对象构造函数中,我们需要传入一个已经构造好的 `PWM` 对象。 -```python +``` python # 此处省略 PWM 对象的构造过程 nmn = NumberedMusicalNotation(pwm) #构造 对象 ``` -  设置拍速,以 `137` 为例。拍速对应简谱上左上角的 `符号 音符 = xxx`,在简谱中这个符号表示拍速,即一分钟内经过的拍子数量。通过这个可以计算出每两拍之间的间隔时间。如图所示: +--- + +  `nmn.setSpeed` 方法,表示设置拍速。该方法需要传入 `1` 个参数,即对应简谱中的 `音乐符号=xxx`。以 `137` 为例。如图所示: ![](assets/image/Snipaste_2021-07-16_17-42-02.png) -```python -nmn.speed(137) +``` python +nmn.setSpeed(137) ``` -  设置拍号,以 `4/4` 为例。拍号对应简谱上左上角的 `符号 x/y`,在简谱中这个符号表示拍号。在当前简谱中说明以 `4` 分音符为 `1` 拍,每小节有 `4` 拍。其中只有 `4` 分音符为一拍与蜂鸣器播放的声音有关,也就是对应每一个单音的时值。在设置时该值只和 `y` 有关。如图所示: +--- + +  `nmn.setTimeSignature` 方法,表示设置拍号。该方法需要传入 `1` 个参数,即对应简谱上左上角的 `符号 x/y`,在设置时该值只和 `y` 有关。以 `4/4` 为例,如图所示: ![](assets/image/Snipaste_2021-07-16_17-47-31.png) -```python -nmn.timeSignature(4) +``` python +nmn.setTimeSignature(4) +``` + +--- + +  `nmn.setPreAdd` 方法,表示整体基础音高。有些控制电路不支持向蜂鸣器传递较小的频率,因此为了让简谱中所有的音都能正常播放,并且不破坏音律的节奏,我们可以对简谱中每个音都进行整体提升音高。该方法需要传入 `1` 个参数,即需要对整个简谱升高或降低的八度数量,例如: + +``` python +nmn.setPreAdd(2) +``` + +> 注:如控制芯片为 `Hi3861` 建议设置 `setPreAdd` 参数为 `2`。 + +--- + +  `nmn.playNotation` 方法,表示控制蜂鸣器播放音乐。该方法需要传入 `1` 个参数,即对应简谱上的包含增减时符的单音字符。以 `Do` 为例: + +``` python +nmn.playNotation('1') +``` + +  符号对应如下: + +* `b数字`:音高降半音 +* `+`:音高高八度 +* `-`:音高降八度 +* `*`:时值延长前一个音的一半 +* `.`:时值延长一个四分音符(半音符、全音符等) +* `_`:时值减半(八分音符、十六分音符等) + +  以上符号可以根据简谱内容随意组合,例如: + +``` python +musicList = [ + '--6', '-3', '-4_', '-3__', '-2__', '-3', +] + + +for monophonic in musicList: + nmn.playNotation(monophonic) ``` +--- \ No newline at end of file diff --git a/Buzzer/assets/code/NumberedMusicalNotation.py b/Buzzer/assets/code/NumberedMusicalNotation.py index 5b284a559bfee59566a853151559d90675369c02..f29c46d6f9e54ebb50f1809bb870391318158ce0 100644 --- a/Buzzer/assets/code/NumberedMusicalNotation.py +++ b/Buzzer/assets/code/NumberedMusicalNotation.py @@ -3,14 +3,58 @@ import utime import gc import ure + class NumberedMusicalNotation: def __init__(self, pwm): self.pwm = pwm + self.setMajor('C') + + self.beatSpeed = 120 + self.beatNumber = 4 + self.preAdd = 0 + + def tone(self, freq): + self.pwm.duty(50) + self.pwm.freq(freq) + + def noTone(self): + self.pwm.duty(0) + + def setSpeed(self, beatSpeed): + self.beatSpeed = beatSpeed + + def setTimeSignature(self, beatNumber): + self.beatNumber = beatNumber + + def setPreAdd(self, p): + self.preAdd = p + + def setMajor(self, major): + majorDict = { + 'C': 262, + '#C': 277, + 'bD': 277, + 'D': 294, + '#D': 311, + 'bE': 311, + 'E': 330, + 'F': 349, + '#F': 370, + 'bG': 370, + 'G': 392, + '#G': 415, + 'bA': 415, + 'A': 440, + '#A': 466, + 'bB': 466, + 'B': 494 + } + frequency = [] for i in range(12): - f = 262 * math.pow(2, i/12) + f = majorDict[major] * math.pow(2, i/12) frequency.append(f) self.scaleDict = { @@ -29,24 +73,7 @@ class NumberedMusicalNotation: '7': int(frequency[11]) } - self.beatSpeed = 120 - self.beatNumber = 4 - - def tone(self, freq, still): - self.pwm.duty(50) - self.pwm.freq(freq) - utime.sleep_ms(int(still)) - - def noTone(self): - self.pwm.duty(0) - - def speed(self, beatSpeed): - self.beatSpeed = beatSpeed - - def timeSignature(self, beatNumber): - self.beatNumber = beatNumber - - def playNotation(self, monophonic, preAdd = 0): + def playNotation(self, monophonic): scaleKey = '' if(monophonic.find('b') != -1): @@ -57,7 +84,8 @@ class NumberedMusicalNotation: upNumber = monophonic.count('+') downNumber = monophonic.count('-') - realRate = self.scaleDict[scaleKey] * math.pow(2, upNumber) * (1 / math.pow(2, downNumber)) + realRate = self.scaleDict[scaleKey] * \ + math.pow(2, upNumber) * (1 / math.pow(2, downNumber)) quarterNote = (60 / self.beatSpeed) * self.beatNumber * (1 / 4) @@ -65,18 +93,25 @@ class NumberedMusicalNotation: downNumber = monophonic.count('_') halfNumber = monophonic.count('*') - voiceTime = quarterNote * (1 / math.pow(2, downNumber)) + timeValue = quarterNote * (1 / math.pow(2, downNumber)) if(halfNumber >= 1): - voiceTime *= 1.5 + timeValue *= 1.5 - voiceTime += quarterNote * upNumber + timeValue += quarterNote * upNumber + + hitTime = 0.8 * timeValue + voiceTime = timeValue - hitTime if(realRate != 0): - self.tone(int(realRate * math.pow(2, preAdd)), int(voiceTime * 1000)) - else: + self.tone(int(realRate * math.pow(2, self.preAdd))) + utime.sleep_ms(int(hitTime * 1000)) + self.noTone() utime.sleep_ms(int(voiceTime * 1000)) - + else: + self.noTone() + utime.sleep_ms(int(timeValue * 1000)) + self.noTone() - gc.collect() \ No newline at end of file + gc.collect()