XIAO ESP32S3でドレミファソラシドを鳴らす その3

2026年1月2日金曜日

マイコン工作

https://www.notyet-maker.com/2026/01/xiao-esp32s3-2.html

の続き。


1. ESP32S3+MAX98357Aでは「素材音」まで

2. MX MIDI Guitarの“鳴らし方”だけを真似る

3. ESP32S3側でクリーン音を整え、Slash寄りにする。

という3段階の2段階目。


ChatGPTによると、

---

2. では、MX MIDI Guitarの音そのものは作らない。

真似るのは「弾いた瞬間の反応」「減衰の仕方」「揺れの入り方」だけ。


3.で、初めて音としてギターっぽくする。

その方向性の一例が「Slash寄り」。

---

とのこと。


今度はスムーズに、Codexがコードを生成してくれた。

そこそこクリアな音になった。


///

import time, math

import board, audiobusio, synthio


SAMPLE_RATE = 18000

AMP = 0.05

ATTACK = 0.01

DECAY = 0.20

SUSTAIN = 0.25

RELEASE = 0.25

NOTE_ON_SEC = 0.35

NOTE_GAP_SEC = 0.25

VIB_ON = True

VIB_DELAY = 0.08

VIB_RATE = 5.0

VIB_CENTS = 5.0

VIB_STEP = 0.01


i2s = audiobusio.I2SOut(board.D6, board.D3, board.D7)

synth = synthio.Synthesizer(sample_rate=SAMPLE_RATE)

i2s.play(synth)


env = synthio.Envelope(attack_time=ATTACK, decay_time=DECAY, sustain_level=SUSTAIN, release_time=RELEASE)

notes = [261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25]


def cents_to_ratio(cents):

    return 2 ** (cents / 1200.0)


def play_note(freq):

    note = synthio.Note(frequency=freq, envelope=env, amplitude=AMP)

    synth.press(note)

    start = time.monotonic()

    while time.monotonic() - start < NOTE_ON_SEC:

        if VIB_ON and (time.monotonic() - start) > VIB_DELAY:

            t = time.monotonic()

            ratio = cents_to_ratio(math.sin(2 * math.pi * VIB_RATE * t) * VIB_CENTS)

            note.frequency = freq * ratio

        time.sleep(VIB_STEP)

    synth.release(note)

    time.sleep(NOTE_GAP_SEC)


while True:

    for f in notes:

        play_note(f)

///



続いて、

3. ESP32S3側でクリーン音を整え、Slash寄りにする。

に進む。


AdafruitsのMX MIDI Guitarの音色を、ESP32S3+synthio で再構成するには、

下記が必要とのこと。


---

(1) ピッキング直後 5〜15ms の非周期成分を必ず入れる

 - ノイズを足すのではなく

 - 位相が少し乱れた「壊れた周期波形」を使う

 - 振幅は上げない


(2) アタックの時間構造を作る

 - 無音に近い状態(2〜6ms)

 - → 非周期成分(5〜15ms)

 - → 通常の周期波形

   この順序を必ず守る


(3) ピッキング位置差を入れる

 - 毎ノートごとに

  - 3次/5次倍音の係数

  - 非線形量

    を「ごく小さく」ランダムに変える

 - 均質な音を禁止する


(4) その後にだけ

 - 非線形の減衰

 - 遅延ビブラート

---


が、これは、REPLでは実行できないらしい。


---

(1)(2) は「数 ms 単位で同じ処理を回し続ける」必要がある

→ 時間を追いかけるループ(while)が必須。


(3) は「1ノート分の処理をひとまとまりで保持する」必要がある

→ 波形生成・係数決定・発音制御を同一ブロックで扱う必要がある。


(4) は「前段の状態を引き継いで後段に遷移する」必要がある

→ 状態(フェーズ)を保持しながら条件分岐を繰り返す必要がある。


REPLはブロック構造(for / while / def)を安定して保持できない

→ 全文コピペしても、内部では行単位評価になり、

フェーズ・時間・状態の連続性が壊れる。


その結果、

・無音 → 非周期 → 周期

・非線形減衰 → 遅延ビブラート

という 「時間でつながった処理」 が成立せず、

unexpected indent や動作破綻が起きます。

---

ということらしい。


何度も実際に REPL で失敗ログを出していたのに、なかなか、この結論に

達することができず、多くの時間を浪費した...

今後は、code​.​py を使う。


Wio Terminalでは、Arduinoのビルドが面倒だったけど、

ESP32S3は、CircuitPythonを使う分、効率が良いだろう。


このブログを検索

ブログ アーカイブ

XIAO ESP32S3でドレミファソラシドを鳴らす その3

https://www.notyet-maker.com/2026/01/xiao-esp32s3-2.html の続き。 1. ESP32S3+MAX98357Aでは「素材音」まで 2. MX MIDI Guitarの“鳴らし方”だけを真似る 3. ESP32S3側でクリーン音...

QooQ