【メロディーメイカー】勇者

# 概要

子ども向けのプログラミング教育プロジェクトとして、YOASOBIの勇者をコーディングしてみました。

<iframe width="400" height="712" src="https://www.youtube.com/embed/-JTBHGPgkfU" title="電子工作で勇者part2" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

# ソースコード

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

# 演奏中ならTrue, 演奏していない時はFalse
is_playing = False

# スケール（melodyの中で使っている音階）
scale = []

# LED
led_pins = [0, 2, 3, 9, 10, 1, 11, 12]
leds = [Pin(pin, Pin.OUT, value=1) for pin in led_pins]

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

# 再生ボタン
playing_button = Pin(13, Pin.IN, Pin.PULL_DOWN)

# 停止ボタン
stop_button = Pin(14, Pin.IN, Pin.PULL_DOWN)

def stop(pin):
    global is_playing
    is_playing = False

stop_button.irq(trigger=Pin.IRQ_RISING, handler=stop)

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


def turn_on_led(index=None):
    """
    LEDを点灯する。
    """
    if index is None:
        for led in leds:
            led.value(0)
    else:
        leds[index].value(0)
        
def turn_off_led(index=None):
    """
    LEDを消灯する。
    """
    if index is None:
        for led in leds:
            led.value(1)
    else:
        leds[index].value(1)


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

    Parameters:
        frequency(int): 周波数
        duration(float): 音の長さ
    """
    if frequency == REST:
        turn_on_led()
        sleep(duration)
        turn_off_led()
        return
    index = scale.index(frequency) % 8
    turn_on_led(index)
    buzzer.freq(frequency)
    buzzer.duty_u16(30000)
    sleep(duration)
    buzzer.duty_u16(0)
    sleep(0.002)
    turn_off_led(index)


def yusya():
    """
    勇者
    """
    global is_playing
    global scale

    BPM = 208
    BEAT = 60 / BPM
    melody = [
        [C6, BEAT/2],[Bb5, BEAT/2],[C6, BEAT/2],[Bb5, BEAT/2],[C6, BEAT/2],[Bb5, BEAT/2],[C6, BEAT/2],[D6, BEAT/2],[REST, BEAT/2],[G5, BEAT*3/4],[REST, BEAT/4],
        [C5, BEAT/2],[D5, BEAT/2],[G5, BEAT/2],[Bb5, BEAT/2],[A5, BEAT/2],[REST, BEAT/2],[F5, BEAT*3/4],[REST, BEAT/4],
        [Bb4, BEAT/2],[C5, BEAT/2],[Bb4, BEAT/2],[C5, BEAT/2],[D5, BEAT],
        [C5, BEAT/2],[D5, BEAT/2],[C5, BEAT/2],[D5, BEAT/2],[G5, BEAT/2],[F5, BEAT/2],[C5, BEAT],[Bb4, BEAT/2],[Bb4, BEAT],
        [G4, BEAT],[A4, BEAT],[Bb4, BEAT],[C5, BEAT],[D5, BEAT],[Eb5, BEAT],[Gb5, BEAT],[G5, BEAT],[A5, BEAT],[Bb5, BEAT],[C6, BEAT],[F5, BEAT],[Eb6, BEAT],[Eb6, BEAT*2],[D6, BEAT],
        [C6, BEAT/2],[Bb5, BEAT/2],[C6, BEAT/2],[D6, BEAT/2],[REST, BEAT/2],[G5, BEAT*3/4],[REST, BEAT/4],
        [C5, BEAT/2],[D5, BEAT/2],[G5, BEAT/2],[Bb5, BEAT/2],[A5, BEAT/2],[REST, BEAT/2],[F5, BEAT*3/4],[REST, BEAT/4],
        [Bb4, BEAT/2],[C5, BEAT/2],[Bb4, BEAT/2],[C5, BEAT/2],[D5, BEAT],
        [C5, BEAT/2],[D5, BEAT/2],[G5, BEAT/2],[F5, BEAT/2],[Bb4, BEAT/2],[Bb4, BEAT/2],[C5, BEAT],[Bb4, BEAT/2],[Bb4, BEAT],
        [G4, BEAT],[A4, BEAT],[Bb4, BEAT],[C5, BEAT],[D5, BEAT],[Eb5, BEAT],[F5, BEAT],[G5, BEAT],[A5, BEAT],[Bb5, BEAT],[A5, BEAT*2],
        [D5, BEAT],[D5, BEAT/2],[D5, BEAT/2],[D6, BEAT/2],[A5, BEAT],[A5, BEAT],[G5, BEAT/2],[G5, BEAT],[REST, BEAT]
    ] 
    is_playing = True

    # 重複のない要素のリストを作成
    unique_elements = []
    for note in melody:
        if note[0] not in unique_elements and note[0] != 0:
            unique_elements.append(note[0])

    scale = sorted(unique_elements)

    for m in melody:
        if is_playing:
            tone(m[0], m[1])
        else:
            break

index = 0
while True:
    turn_on_led(index)
    if playing_button.value() == 1:
        yusya()
    sleep(0.1)
    turn_off_led(index)
    if index < 7:
        index += 1
    else:
        index = 0

```

# メロディーメイカーの作り方

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

https://youtu.be/d7pTfG6R1M8