Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

micro:bit v2 で Rust コードを書いて "Happy Birthday" を再生する

このセクションでは、micro:bit のスピーカーで "Happy Birthday" の曲を再生します。

microbit-bsp クレートが提供する関数群は micro:bit には非常に便利ですが、ESP32 や Raspberry Pi Pico のような異なる MCU 間でも使えるものが欲しいと考えました。そこで、Quarter や Half などの音楽用語を使って、音符と長さをより分かりやすく定義できる別のクレートを作成しました。次のセクションでは、そのクレートを使って、より再利用しやすく移植性の高い方法で曲を再生していきます。

このために、tinytones というクレートを使います。このクレートには "Happy Birthday" の曲が組み込まれているため、音程や長さを自分で定義する必要はありません。

このクレートは、自分自身のメロディーを定義するための Pitch enum と Tone struct も提供します。また、Quarter や Half のような音楽上の長さを、曲のテンポに基づいた実際の時間値へ変換するヘルパー関数も含まれています。

テンプレートからプロジェクトを作成する

このプロジェクトでは、microbit-bsp(Embassy 付き)を使用します。テンプレートを使って新しいプロジェクトを生成するには、次のコマンドを実行してください。

cargo generate --git https://github.com/ImplFerris/mb2-template.git --rev 3d07b56
  • プロジェクト名の入力を求められたら、"play-song" のような名前を入力します。

  • async を使うかどうかを尋ねられたら、"true" を選択します。

  • "BSP" または "HAL" のどちらを使うか尋ねられたら、"BSP" を選択します。

Cargo.toml を更新する

tinytones クレートを追加します。Cargo.toml ファイルを開き、次の行を追加してください。

tinytones = { version="0.1.0" }

インポート

このプログラムに必要なインポートは次のとおりです。main.rs ファイルを開き、以下のように更新してください。

#![allow(unused)]
fn main() {
// テンプレートに最初から含まれているもの
use embassy_executor::Spawner;
use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _};

// 追加のインポート
use embassy_nrf::pwm::SimplePwm;
use microbit_bsp::{
    Microbit,
    speaker::{Note, Pitch, PwmSpeaker},
};
use tinytones::{Tone, songs};

}

初期化

まず、ボードを初期化します。このボードインスタンスから、pwm0 ペリフェラルと内蔵スピーカーにアクセスできます。これらの両方を、基本的な PWM 出力を設定する embassy-nrf クレートのヘルパー struct である SimplePwm に渡します。

次に、この SimplePwm インスタンスを microbit-bsp クレートの struct である PwmSpeaker に渡します。これにより、音程と長さを指定して音を再生できるようになります。

#![allow(unused)]
fn main() {
let board = Microbit::default();
let mut speaker = PwmSpeaker::new(SimplePwm::new_1ch(board.pwm0, board.speaker));
}

曲を選ぶ

tinytones クレートは、組み込みの曲やメロディーのセットを提供しています。完全な一覧はドキュメントで確認できます。

この例では、"Happy Birthday" の曲を再生します。そのために、Tone::new を呼び出して Tone struct を初期化します。第 1 引数は曲のテンポ(曲がどれくらい速く、または遅く再生されるか)です。曲に用意されている定義済みテンポを使うこともできますし、自分で指定することもできます(例: 150)。第 2 引数はメロディーで、音符のリスト(それぞれに音程と長さがある)です。

#![allow(unused)]
fn main() {
let song = Tone::new(songs::happy_birthday::TEMPO, songs::happy_birthday::MELODY);
}

曲をループ再生する

曲を読み込んだら、再生できます。Toneiter() メソッドを提供しており、これによってメロディー内の各音符を順番に取り出すイテレーターが得られます。各音符は (pitch, duration) のペアです。

ループの中では、各音符を 1 つずつ処理していきます。音程が Rest の場合、それは無音の休符を意味します。その場合は、Timer::after_millis を使ってその音符の長さだけ待機します。

それ以外の音符については、speaker.play() メソッドを使って音を再生します。ここには Note を渡しますが、これは pitch.freq_u32() を使って音程を周波数へ変換し、そこに音符の長さを渡すことで作成します。

#![allow(unused)]
fn main() {
loop {
    for (pitch, note_duration) in song.iter() {
        if pitch == tinytones::note::Pitch::Rest {
            Timer::after_millis(note_duration).await;
            continue;
        }

        speaker
            .play(&Note(
                Pitch::Frequency(pitch.freq_u32()),
                note_duration as u32,
            ))
            .await;
    }
    Timer::after_secs(5).await;
}
}

曲全体の再生が終わったら、再びループして最初から再生する前に 5 秒待機します。

完全なコード

#![no_std]
#![no_main]

use embassy_executor::Spawner;
use embassy_nrf::pwm::SimplePwm;
use embassy_time::Timer;
use microbit_bsp::{
    Microbit,
    speaker::{Note, Pitch, PwmSpeaker},
};
use tinytones::{Tone, songs};
use {defmt_rtt as _, panic_probe as _};

#[embassy_executor::main]
async fn main(_spawner: Spawner) -> ! {
    let board = Microbit::default();
    let mut speaker = PwmSpeaker::new(SimplePwm::new_1ch(board.pwm0, board.speaker));

    let song = Tone::new(songs::happy_birthday::TEMPO, songs::happy_birthday::MELODY);
    loop {
        for (pitch, note_duration) in song.iter() {
            if pitch == tinytones::note::Pitch::Rest {
                Timer::after_millis(note_duration).await;
                continue;
            }

            speaker
                .play(&Note(
                    Pitch::Frequency(pitch.freq_u32()),
                    note_duration as u32,
                ))
                .await;
        }
        Timer::after_secs(5).await;
    }
}

既存のプロジェクトをクローンする

作成済みのプロジェクトをクローンして(または参照して)、bsp-embassy/play-song フォルダーへ移動することもできます。

git clone https://github.com/ImplFerris/microbit-projects
cd microbit-projects/bsp-embassy/play-song

書き込み

プログラムを micro:bit に書き込むと、メロディーが聞こえるはずです。

cargo flash