【進撃の東さん】第4回：メロディーメイカーで遊んでみましょう

# 概要

子どもが楽しくプログラミングを学べるように電子工作で好きなメロディを鳴らすプロジェクトを作ってみました。

こんな感じです。

https://youtube.com/shorts/qY-kMSDMOo0

作り方は動画で解説してます。

https://youtu.be/d7pTfG6R1M8


## ソースコード

以下の手順で曲を追加することができます。

* メソッドを作成する
* BPMを指定する
* melodyの配列に音符をコーディングする
* toneで音を鳴らす

```python:main.py
from machine import Pin, PWM
from utime import sleep


# NPNトランジスタのベース
buzzer = PWM(Pin(15))

# LED
led_red = Pin(0, Pin.OUT, value=1)
led_green = Pin(2, Pin.OUT, value=1)
led_blue = Pin(3, Pin.OUT, value=1)
led_yellow = Pin(9, Pin.OUT, value=1)
led_white = Pin(10, Pin.OUT, value=1)

# ボタン
button_red = Pin(1, Pin.IN, Pin.PULL_DOWN)
button_green = Pin(11, Pin.IN, Pin.PULL_DOWN)
button_blue = Pin(12, Pin.IN, Pin.PULL_DOWN)
button_yellow= Pin(13, Pin.IN, Pin.PULL_DOWN)
button_orange = Pin(14, Pin.IN, Pin.PULL_DOWN)

# 音の周波数
REST=    0
C4  =  262
Db4 =  277
D4  =  294
Eb4 =  311
E4  =  330
F4  =  349
Gb4 =  370
G4  =  392
Ab4 =  415
A4  =  440
Bb4 =  466
B4  =  494
C5  =  523
Db5 =  554
D5  =  587
Eb5 =  622
E5  =  659
F5  =  698
Gb5 =  740
G5  =  784
Ab5 =  831
A5  =  880
Bb5 =  932
B5  =  988
C6  = 1047
Db6 = 1109
D6  = 1175
Eb6 = 1245
E6  = 1319
F6  = 1397
Gb6 = 1480
G6  = 1568
Ab6 = 1661
A6  = 1760

# 光っているLEDを管理する変数
color = 0

def turn_on_led(color):
    """
    指定したLEDを点灯する。
    """
    if color == 0:
        led_red.value(0)
    elif color == 1:
        led_green.value(0)
    elif color == 2:
        led_blue.value(0)
    elif color == 3:
        led_yellow.value(0)
    elif color == 4:
        led_white.value(0)
        
def turn_off_led(color):
    """
    指定したLEDを消灯する。
    """
    if color == 0:
        led_red.value(1)
    elif color == 1:
        led_green.value(1)
    elif color == 2:
        led_blue.value(1)
    elif color == 3:
        led_yellow.value(1)
    elif color == 4:
        led_white.value(1)

    
def tone(frequency, duration):
    """
    パッシブブザーで音を鳴らす。

    Parameters:
        frequency(int): 周波数
        duration(float): 音の長さ
    """
    global color
    if frequency == REST:
        turn_on_led(0)
        turn_on_led(1)
        turn_on_led(2)
        turn_on_led(3)
        turn_on_led(4)
        sleep(duration)
        turn_off_led(0)
        turn_off_led(1)
        turn_off_led(2)
        turn_off_led(3)
        turn_off_led(4)
        return
    turn_on_led(color)
    buzzer.freq(frequency)
    buzzer.duty_u16(30000)
    sleep(duration)
    buzzer.duty_u16(0)
    sleep(0.002)
    turn_off_led(color)
    if color < 4:
        color += 1
    else:
        color = 0
    
def puricure():
    """
    ひろがるスカイ！プリキュア〜Hero Girls〜
    """
    BPM = 184
    BEAT = 60 / BPM
    melody = [
        [D6, BEAT/2],[C6, BEAT/2],[B5, BEAT/2],[A5, 1.5*BEAT],[G5, BEAT],
        [D6, BEAT/2],[C6, BEAT/2],[B5, BEAT/2],[A5, 1.5*BEAT],[G5, BEAT],
        [D6, BEAT/2],[C6, BEAT/2],[B5, BEAT/2],[A5, 1.5*BEAT],[A5, BEAT/2],[B5,BEAT/2],[REST, BEAT/2],
        [Gb5, BEAT],[Gb5, BEAT],[G5, BEAT/2],[G5, 2*BEAT],[REST, BEAT*3/4],
        [G5, BEAT/2],[C6, BEAT/2],[B5, BEAT/2],[A5, BEAT/2],[B5, 2*BEAT],
        [G5, BEAT/2],[E6, BEAT/2],[D6, BEAT/2],[C6, BEAT/2],[D6, 1.5*BEAT],
        [G5, BEAT],[A5, 1.5*BEAT],[D6, BEAT/2],[D6, 4*BEAT],
        [D6, BEAT/2],[C6, BEAT/2],[B5, BEAT/2],[A5, 1.5*BEAT],[G5, BEAT],
        [D6, BEAT/2],[C6, BEAT/2],[B5, BEAT/2],[A5, 1.5*BEAT],[G5, BEAT],
        [D6, BEAT/2],[C6, BEAT/2],[B5, BEAT/2],[A5, 1.5*BEAT],[A5, BEAT/2],[B5,BEAT/2],[REST, BEAT/2],
        [Gb5, BEAT/2],[REST, BEAT/2],[G5, 2*BEAT],
        [A5, BEAT],[B5,BEAT],[Db6, 1.5*BEAT],[A5, BEAT/2],[A5, 3*BEAT],
        [D5, BEAT],[D5, BEAT],[G5,BEAT/2],[A5, BEAT],[B5,BEAT/2],[C6, BEAT],[B5,3*BEAT],
        [D5, BEAT],[D5, BEAT],[G5,BEAT/2],[D6, BEAT],[C6,BEAT/2],[B5, BEAT/2],[C6,BEAT/2],[B5,BEAT/2],[A5, BEAT/2],[G5,2*BEAT],
        [G5,BEAT/2],[Gb5,BEAT/2],[G5,BEAT],[D6, BEAT/2],[C6,4*BEAT],[REST, BEAT/2],
        [D6, BEAT],[C6,BEAT],[B5,BEAT],[REST, BEAT],[D6, 3*BEAT],[REST, BEAT]
    ]
    for m in melody:
        tone(m[0], m[1])
        
def watashihasaikyo():
    """
    私は最強
    """
    BPM = 192
    BEAT = 60 / BPM
    melody = [
        [E5, 3*BEAT],[Gb5, BEAT],[A5, BEAT],[Ab5, BEAT],[E5, BEAT],[Db5, BEAT],[B4, 3*BEAT],
        [B4, BEAT/2],[B4, BEAT/2],[A5, BEAT],[Ab5, BEAT],[E5, BEAT],[Db5, BEAT],[E5, 3*BEAT],
        [B5, BEAT],[B5, BEAT],[A5, BEAT],[Ab5, BEAT],[Gb5, BEAT],[E5, 2*BEAT],
        [E5, BEAT],[A5, BEAT],[Ab5, BEAT/2],[Gb5, BEAT/2],[E5, BEAT/2],[Gb5, BEAT],[E5, BEAT/2],[Gb5, BEAT],
        [E5, 2*BEAT],[E5, BEAT],[E5, BEAT/2],[E5, BEAT/2],[E5, BEAT],[B5, BEAT],[B5, BEAT],[Db6, BEAT],[B5, 1.5*BEAT],
        [B4, BEAT/2],[B5, BEAT/2],[A5, BEAT/2],[Ab5, BEAT/2],[Gb5, BEAT/2],[E5, BEAT],[Db5, BEAT],[E5, BEAT],[A5, BEAT],[Ab5, 3*BEAT],
        [E6, BEAT/2],[E6, BEAT/2],[E6, BEAT],[Eb6, BEAT],[Db6,BEAT],[B5, BEAT],[E5, 2*BEAT],
        [E5, BEAT],[A5, BEAT],[Ab5, BEAT],[Gb5, BEAT],[E5, 2*BEAT],[E6, 3*BEAT],[REST, BEAT]

    ]
    for m in melody:
        tone(m[0], m[1])
        
def dancehall():
    """
    ダンスホール
    """
    BPM = 110
    BEAT = 60 / BPM
    melody = [
        [Gb5, BEAT/4],[REST, BEAT/4],[E5, BEAT/4],[REST, BEAT/4],[D5, BEAT/4],[REST, BEAT/4],
        [Gb5, BEAT/2],[REST, BEAT/2],[A5, BEAT*3/4],[D5, BEAT/4],[REST, BEAT/4],
        [D5, BEAT/4],[D5, BEAT/4],[D5, BEAT/4],[D5, BEAT/4],[REST, BEAT/4],[D5, BEAT/4],[REST, BEAT/4],
        [D5, BEAT/2],[REST, BEAT/2],[B4,BEAT*3/4],[A4, BEAT/4],[REST, BEAT/4],
        [Gb5, BEAT/4],[Gb5, BEAT/4],[Gb5, BEAT/4],[Gb5, BEAT/4],[Gb5, BEAT/4],[E5, BEAT/4],[D5, BEAT/4],
        [Gb5, BEAT/2],[REST, BEAT/2],[A5, BEAT/4],[A5, BEAT/2],[B5, BEAT*3/4],
        [A5, BEAT/2],[Gb5, BEAT/4],[E5, BEAT/4],[D5, BEAT/4],[B4, BEAT/4],
        [D5, BEAT/2],[REST, BEAT/2],[E5, BEAT*3/4],[D5, BEAT/2],[REST, BEAT/4],
        [D5, BEAT/4],[B4, BEAT/4],[D5, BEAT/4],[E5, BEAT/4],[Gb5, BEAT/4],[A5, BEAT/4],
        [D6, BEAT/2],[REST, BEAT/2],[E6, BEAT*3/4],[D6, BEAT/2],[REST, BEAT*1.5]
    ]
    for m in melody:
        tone(m[0], m[1])
        
def meguminohito():
    """
    め組の人
    """
    BPM = 112
    BEAT = 60 / BPM
    melody = [
        [D5, BEAT],[D4, BEAT],[Eb4, BEAT/4],[D5, BEAT/4],[REST, BEAT/4],[D5, BEAT/4],[REST, BEAT/4],[D5, BEAT/4],[REST, BEAT/4],[D5, BEAT/8],
        [C5, BEAT/2],[C5, BEAT/2],[C5, BEAT/2],[D5, BEAT/2],[Bb4, BEAT/4],[D4, BEAT/4],[REST, BEAT/4],[D4, BEAT],[REST, BEAT/4],
        [D5, BEAT],[D4, BEAT],[Eb4, BEAT/4],[D5, BEAT/4],[REST, BEAT/4],[D5, BEAT/4],[REST, BEAT/4],[D5, BEAT/4],[REST, BEAT/4],[D5, BEAT/8],
        [C5, BEAT/2],[C5, BEAT/2],[C5, BEAT/2],[D5, BEAT/2],[G5, BEAT/2],[REST, BEAT*1.5],
        [D5, BEAT],[D4, BEAT],[Eb4, BEAT/4],[D5, BEAT/4],[REST, BEAT/4],[D5, BEAT/4],[REST, BEAT/4],[D5, BEAT/4],[REST, BEAT/4],[D5, BEAT/8],
        [C5, BEAT/2],[C5, BEAT/2],[C5, BEAT/2],[D5, BEAT/2],[Bb4, BEAT/4],[D4, BEAT/4],[REST, BEAT/4],[D4, BEAT],[REST, BEAT/4],
        [D5, BEAT],[D4, BEAT],[Eb4, BEAT/4],[D5, BEAT/4],[REST, BEAT/4],[D5, BEAT/4],[REST, BEAT/4],[D5, BEAT/4],[REST, BEAT/4],[D5, BEAT/8],
        [C5, BEAT/2],[C5, BEAT/2],[C5, BEAT/2],[D5, BEAT/2],[G5, BEAT/2],[REST, BEAT*1.5]
    ]
    for m in melody:
        tone(m[0], m[1])
    
def shapeofyou():
    """
    Shape Of You
    """
    BPM = 96
    BEAT = 60 / BPM
    melody = [
        [Db5, BEAT/4],[REST, BEAT/2],[E5, BEAT/4],[REST, BEAT/2],[Db5, BEAT/4],[REST, BEAT/4],
        [Db5, BEAT/4],[REST, BEAT/2],[E5, BEAT/4],[REST, BEAT/2],[Db5, BEAT/4],[REST, BEAT/4],
        [Db5, BEAT/4],[REST, BEAT/2],[E5, BEAT/4],[REST, BEAT/2],[Db5, BEAT/4],[REST, BEAT/4],
        [Eb5, BEAT/4],[REST, BEAT/2],[Db5, BEAT/4],[REST, BEAT/2],[B4, BEAT/4],[REST, BEAT/4],
        [Db5, BEAT/4],[REST, BEAT/2],[E5, BEAT/4],[REST, BEAT/2],[Db5, BEAT/4],[REST, BEAT/4],
        [Db5, BEAT/4],[REST, BEAT/2],[E5, BEAT/4],[REST, BEAT/2],[Db5, BEAT/4],[REST, BEAT/4],
        [Db5, BEAT/4],[REST, BEAT/2],[E5, BEAT/4],[REST, BEAT/2],[Db5, BEAT/4],[REST, BEAT/4],
        [Eb5, BEAT/4],[REST, BEAT/2],[Db5, BEAT/4],[REST, BEAT/2],[B4, BEAT/4],[REST, BEAT/4],
    ]
    for m in melody:
        tone(m[0], m[1])

def yorunikakeru():
    """
    夜に駆ける
    """
    BPM = 130
    BEAT = 60 / BPM
    melody = [
        [Eb6, BEAT/2],[D6, BEAT/2],[Bb5, BEAT/2],[Bb5, BEAT*3/4],[C6, BEAT/4],[REST, BEAT/4],[G5, BEAT*3/4],[F5, BEAT/2],
        [Eb5, BEAT/2],[F5, BEAT/2],[C6, BEAT/2],[Bb5, BEAT/2],[F5, BEAT/4],[G5, BEAT/4],[REST, BEAT/4],[Eb5, BEAT/4],[F5, BEAT/2],[Eb5, BEAT/2],
        [REST, BEAT/2],[Eb5, BEAT/2],[Bb5, BEAT/2],[Ab5, BEAT/2],[G5, BEAT/2],[F5, BEAT/2],[Eb5, BEAT/2],[D5, BEAT/2],[Eb5, BEAT/2],[F5, BEAT/2],[Ab5, BEAT/2],
        [G5, BEAT/2],[F5, BEAT/4],[G5, BEAT/4],[REST, BEAT/4],[C6, BEAT*3/4],[Bb5, BEAT/2],
        [REST, BEAT/2],[G5, BEAT/2],[Bb5, BEAT/2],[C6, BEAT*3/4],[Ab5, BEAT*3/4],[G5, BEAT/2],[F5, BEAT/2],[Eb5, BEAT/2],[F5, BEAT/2],[C6, BEAT/2],
        [Bb5, BEAT/2],[C6, BEAT/4],[G5, BEAT/4],[REST, BEAT/4],[Eb5, BEAT/4],[F5, BEAT/2],[Eb5, BEAT/2],
        [REST, BEAT/2],[C5, BEAT/2],[D5, BEAT/2],[Eb5, BEAT/2],[C5, BEAT/2],[Eb5, BEAT/2],[F5, BEAT/2],[G5, BEAT/2],[Eb5, BEAT/2],[G5, BEAT/2],[C6, BEAT/2],[B5, BEAT*2],
        [REST, BEAT/2],
    ]
    for m in melody:
        tone(m[0], m[1])

def ashitagaarusa():
    """
    明日があるさ
    """
    BPM = 110
    BEAT = 60 / BPM
    melody = [
        [Eb4, BEAT/2],[C5, BEAT*3/4],[C5, BEAT*3/4],[Bb4, BEAT/2],[Bb4, BEAT/2],[Ab4, BEAT],[G4, BEAT/2],
        [Bb4, BEAT/2],[Ab4, BEAT/2],[Ab4, BEAT/2],[F4, BEAT/2],[Eb4, BEAT],[REST, BEAT/2],
        [Eb4, BEAT/2],[C5, BEAT*3/4],[C5, BEAT*3/4],[Bb4, BEAT/2],[Bb4, BEAT/2],[Ab4, BEAT/2],[Ab4, BEAT/2],[G4, BEAT/2],
        [F4, BEAT/2],[Bb4, BEAT/2],[Bb4, BEAT/2],[C5, BEAT/2],[Bb4, BEAT/2],[REST, BEAT],
        [Eb4, BEAT/2],[C5, BEAT*3/4],[C5, BEAT*3/4],[Bb4, BEAT/2],[Bb4, BEAT/2],[Ab4, BEAT/2],[REST, BEAT/2],
        [Ab4, BEAT/2],[Db5, BEAT*3/4],[Db5, BEAT*3/4],[C5, BEAT/2],[C5, BEAT/2],[Bb4, BEAT/2],[REST, BEAT/2],
        [Bb4, BEAT/2],[C5, BEAT*3/4],[Bb4, BEAT*3/4],[Ab4, BEAT/2],[G4, BEAT/2],[Eb4, BEAT/2],[G4, BEAT/2],[Bb4, BEAT/2],[Ab4, BEAT*2],[REST, BEAT/2]
    ]
    for m in melody:
        tone(m[0], m[1])

def idol():
    """
    YOASOBI: アイドル
    """
    BPM = 166
    BEAT = 60 / BPM
    melody = [
        [E5, BEAT/2],[G5, BEAT/2],[A5, BEAT],[E6, BEAT],[A5, BEAT],[G5, BEAT/2],[A5, BEAT],[E6, BEAT/2],[A5, BEAT/2],[G5, BEAT/2],[A5, BEAT/2],[REST, BEAT/2],
        [E5, BEAT/2],[G5, BEAT/2],[A5, BEAT],[C6, BEAT],[B5, BEAT],[G5, BEAT/2],
        [A5, BEAT],[B5, BEAT/2],[C6, BEAT/2],[D6, BEAT/2],[F6, BEAT/2],[REST, BEAT/2],[E6, BEAT],
        [A5, BEAT],[E6, BEAT],[A5, BEAT],[G5, BEAT/2],[A5, BEAT],[E6, BEAT/2],[A5, BEAT/2],[G5, BEAT/2],[A5, BEAT/2],[REST, BEAT/2],
        [E5, BEAT/2],[G5, BEAT/2],[A5, BEAT],[C6, BEAT],[B5, BEAT],[G5, BEAT/2],[A5, BEAT],[A5, BEAT],[G5, BEAT/2],[A5, BEAT],[REST, BEAT/2]
    ]
    for m in melody:
        tone(m[0], m[1])
    
def kaijyunohanauta():
    """
    Vaundy: 怪獣の鼻歌
    """
    BPM = 150
    BEAT = 60 / BPM
    melody = [
        [D5, BEAT/2],[D5, BEAT/2],[B4, BEAT/2],[D5, BEAT],[REST, BEAT/2],[B4, BEAT/2],[D5, BEAT],[REST, BEAT/2],
        [B4, BEAT/2],[D5, BEAT/2],[D5, BEAT/2],[D5, BEAT/2],[D4, BEAT/2],[REST, BEAT/2],
        [D5, BEAT/2],[D5, BEAT/2],[B4, BEAT/2],[D5, BEAT],[REST, BEAT/2],[B4, BEAT/2],[D5, BEAT/2],[D4, BEAT/2],[REST, BEAT/2],
        [D5, BEAT/2],[D5, BEAT/2],[D5, BEAT/2],[D5, BEAT/2],[D4, BEAT/2],[REST, BEAT/2],
        [D5, BEAT/2],[D5, BEAT/2],[D5, BEAT/2],[E5, BEAT],[F5, BEAT/2],[E5, BEAT],[D5, BEAT/2],[D5, BEAT*3.5],
        [D5, BEAT],[D5, BEAT/2],[A5, BEAT/2],[G5, BEAT/2],[G5, BEAT/2],[Gb5, BEAT],[G5, BEAT/2],[Gb5, BEAT*3.5]
    ]
    for m in melody:
        tone(m[0], m[1])
        
def aotonatsu():
    """
    Mrs.GREEN APPLE: 青と夏
    """
    BPM = 185
    BEAT = 60 / BPM
    melody = [
        [B4, BEAT],[E5, BEAT],[Gb5, BEAT],[Ab5, BEAT],[A5, BEAT],[B5, BEAT*7/4],[REST, BEAT/4],[B5, BEAT],
        [B5, BEAT],[A5, BEAT],[Ab5, BEAT],[Gb5, BEAT],[E5, BEAT],[Ab5, BEAT*2],[REST, BEAT],
        [B4, BEAT],[E5, BEAT],[Gb5, BEAT],[Ab5, BEAT],[A5, BEAT],[B5, BEAT],[E5, BEAT/2],[E5, BEAT/2],[E5, BEAT],
        [A5, BEAT],[Ab5, BEAT],[Gb5, BEAT/2],[E5, BEAT/2],[E5, BEAT],[Gb5, BEAT],[E5, BEAT*2],[REST, BEAT],
        [B4, BEAT],[E5, BEAT],[Gb5, BEAT],[Ab5, BEAT],[A5, BEAT],[B5, BEAT],[E5, BEAT],[E5, BEAT],
        [Db6, BEAT],[B5, BEAT],[A5, BEAT],[Ab5, BEAT],[A5, BEAT],[Ab5, BEAT*1.5],[REST, BEAT/2],
        [E5, BEAT*2],[E6, BEAT],[B5, BEAT],[A5, BEAT],[Ab5, BEAT],[E5, BEAT],[REST, BEAT],
        [B4, BEAT],[B4, BEAT],[Ab5, BEAT],[E5, BEAT],[Gb5, BEAT],[Eb5, BEAT],[E5, BEAT*1.5],[REST, BEAT],
    ]
    for m in melody:
        tone(m[0], m[1])
        

while True:
    turn_on_led(color)
    if button_red.value() == 1:
        idol()
        #yorunikakeru()
    elif button_green.value() == 1:
        kaijyunohanauta()
        #ashitagaarusa()   
    elif button_blue.value() == 1:
        aotonatsu()
        #dancehall()
    elif button_yellow.value() == 1:
        yorunikakeru()
    elif button_orange.value() == 1:
        dancehall()
    sleep(0.1)
    turn_off_led(color)
    if color < 4:
        color += 1
    else:
        color = 0
    
```