step0:星空を飛ぶ宇宙船
リソースエディタで BGM を自分で作り、ゲーム中ずっと流し続けます。
フェーズ 4 で絵を描いたのと同じ assets.pyxres に、今度は音を入れます。
pyxel.playm でループ再生するPyxel の音は 2 段構えになっています。ここを取り違えると「作ったのに鳴らない」となります。
| 用語 | 正体 | 数 |
|---|---|---|
| サウンド (SOUND) |
フレーズ 1 本。音符を横に並べたもの。 メロディ、ベース、効果音などを 1 本ずつ作る | 0 〜 63 |
| ミュージック (MUSIC) |
組み立て表。4 本のチャンネルそれぞれに、 どのサウンドを順に鳴らすかを書いたもの | 0 〜 7 |
| チャンネル (CH) |
同時に鳴らせる音の本数。1 チャンネルにつき同時に 1 音だけ。 Pyxel は 4 本あるので、和音や伴奏は最大 4 声まで | 0 〜 3 |
playm で鳴らすサウンドの中では、1 つの音符が 4 つの情報を持っています。 エディタの画面にも、この 4 つがそのまま並んでいます。
| 項目 | 意味 | 入力に使うキー |
|---|---|---|
| NOTE (音の高さ) |
ドレミ。休符も置ける | ピアノ鍵盤のキー + Enter、または画面をクリック |
| TON (音色) |
T 三角波(やわらかい)/S 矩形波(ファミコンらしい)/
P パルス波(細い)/N ノイズ(打楽器) |
T S P N |
| VOL (音量) |
0(無音)〜 7(最大) |
0 〜 7 |
| EFX (効果) |
N なし/S スライド/V ビブラート/
F フェードアウト/H 半分でフェード/Q 4 分の 1 でフェード |
N S V F H Q |
そして、サウンド全体にかかる設定が SPEED(1 音の長さ)です。
120 で 1 音がちょうど 1 秒。数字が小さいほど速くなります。
初期値の 30 なら 1 音 0.25 秒なので、16 音で 4 秒のループになります。
P を 1 個入れておけば、16 音すべてがパルス波になります。
16 個ぶん打ち込む必要はありません。
(空のままでも鳴ります。その場合は T・7・N と同じ扱いです)
フェーズ 4 と同じコマンドで、同じファイルを開きます。
pyxel edit step0/assets.pyxres
右上のタブ、または Alt + ← / → で SOUND タブへ移動します。
↑ ↓ でピアノロールと TON / VOL / EFX の行を行き来し、← → でステップを移動する次の順で操作します。
0、SPEED が 30 であることを確認するEnter を 16 回くり返すOCTAVE は「今、キーボードのキーがどの高さの音に割り当てられているか」の設定です。 キーは 2 オクターブぶん(下段 12 音+上段 12 音)しかないので、 それを 5 オクターブある音域のどこに当てるかを、この設定で決めます。
| OCTAVE | 下段(Z S X D C V G B H N J M) | 上段(Q 2 W 3 E R 5 T 6 Y 7 U) |
|---|---|---|
3 | C3 〜 B3 | C4 〜 B4(いちばん高い) |
2 | C2 〜 B2 | C3 〜 B3 |
1 | C1 〜 B1 | C2 〜 B2 |
0 | C0 〜 B0(いちばん低い) | C1 〜 B1 |
3・2・1・0 の 4 段になっていて、
明るい帯が今の OCTAVE を示します(上ほど高い音)。
PageDown を 4 回以上押す → 確実にいちばん下(0)になるPageUp を ちょうど 2 回押す → 2 になるPageUp / PageDown を
押しておらず、バーをクリックもしていなければ、そのままで大丈夫です。
N キーの音は A2 = 440 Hz。
楽器のチューニングに使われる、いちばん有名な「ラ」の音です。
キーを押している間は音が鳴る(=試聴できる)ので、押してみて
高すぎず低すぎない、はっきりした「ラ」に聞こえれば合っています。
Ctrl + Z でまとめて戻すか、OCTAVE を直して打ち直してください。
失敗しても壊れるものはありません。
鍵盤はパソコンのキーボードに割り当てられています。下段が今の OCTAVE、 上段がその 1 つ上の高さです。
N キーです。A キーは休符なので、混同しないよう注意してくださいこの割り当てで、次の 16 ステップを打ち込みます。
| ステップ | 押すキー | 入る音 |
|---|---|---|
| 1 / 2 | N Enter → A Enter | ラ(A2)/ 休符 |
| 3 / 4 | Q Enter → A Enter | ド(C3)/ 休符 |
| 5 / 6 | E Enter → A Enter | ミ(E3)/ 休符 |
| 7 / 8 | W Enter → A Enter | レ(D3)/ 休符 |
| 9 / 10 | Q Enter → A Enter | ド(C3)/ 休符 |
| 11 / 12 | N Enter → A Enter | ラ(A2)/ 休符 |
| 13 / 14 | B Enter → A Enter | ソ(G2)/ 休符 |
| 15 / 16 | A Enter → A Enter | 休符 / 休符 |
続いて ↓ キーで TON の行へ移り、次の 3 つを入れます。
P(パルス波)↓ で VOL の行へ移り、1 マス目に 5↓ で EFX の行へ移り、1 マス目に N(効果なし)
SPACE キーで試聴できます(もう一度押すと停止)。
L キーでループ再生に切り替わります。
左上の SOUND の数字を 1 に変え、OCTAVE を 1 に下げます
(PageDown を 1 回。バーの明るい帯が 1 段ぶん下へ動きます)。
今度は 4 拍に 1 回だけ、低い音を置きます。
| ステップ | 押すキー | 入る音 |
|---|---|---|
| 1 〜 4 | N Enter → A Enter ×3 | ラ(A1)+ 休符 3 つ |
| 5 〜 8 | V Enter → A Enter ×3 | ファ(F1)+ 休符 3 つ |
| 9 〜 12 | Q Enter → A Enter ×3 | ド(C2)+ 休符 3 つ |
| 13 〜 16 | C Enter → A Enter ×3 | ミ(E1)+ 休符 3 つ |
T(三角波)4(メロディより控えめに)N30 にする(ここがずれると 2 つが合いません)
Alt + → で MUSIC タブへ移ります。
画面は上から CH0 〜 CH3 の 4 段、その下に サウンド選択ボタン(0 〜 63)が並んでいます。
0 であることを確認する0 をクリックする1 をクリックするSPACE で再生して、メロディとベースが重なって鳴ることを確かめるCtrl + S で保存するCtrl + S を必ず押してください。
| API | 意味 |
|---|---|
pyxel.playm(msc, loop=False) |
ミュージック msc(0 〜 7)を再生する。
loop=True でくり返し |
pyxel.play(ch, snd, loop=False) |
チャンネル ch(0 〜 3)でサウンド snd(0 〜 63)を鳴らす。
効果音向け(step1 で使います) |
pyxel.stop() |
すべてのチャンネルを止める。pyxel.stop(0) のように
チャンネルを指定することもできる |
pyxel.load ですでに読み込まれています
フェーズ 5 で書いた pyxel.load("assets.pyxres") は、
絵だけでなく音も一緒に読み込みます。だから今回、読み込みのコードは足しません。
pyxel.run の直前に 1 行足す self.ship_x = (SCREEN_WIDTH - SHIP_WIDTH) // 2
self.ship_y = 80
pyxel.playm(0, loop=True) # ← 追加:BGM をループ再生する
pyxel.run(self.update, self.draw)
変更はこれだけです。
python step0/star_voyager.py
__init__ に書くのか
これは今回いちばん大事な注意点です。
pyxel.playm は「再生を始めろ」という命令であって、
「鳴らし続けろ」ではありません。1 回呼べば、あとは Pyxel が勝手に鳴らし続けます。
もし update の中に書くと、1 秒間に 30 回「頭から鳴らし直せ」と命令することになります。
その結果、曲の先頭の一瞬だけが延々とくり返され、
ブツブツと途切れた音になります。音が出るのに曲にならないときは、まずここを疑ってください。
02_jump_game.py でも、
pyxel.playm(0, loop=True) は pyxel.run(...) の直前、
__init__ の最後に置かれています。
(pyxel/examples/ フォルダにあります。備忘録の「付属のサンプルはどこにある?」を参照)
loop=True を忘れるとどうなるか
loop の初期値は False です。省略すると 4 秒で曲が終わり、
そのあとは無音のままになります。BGM には必ず loop=True を付けます。
play と playm の使い分けplaym | play | |
|---|---|---|
| 鳴らすもの | ミュージック(最大 4 声) | サウンド 1 本 |
| チャンネル | ミュージックの指定どおり | 自分で番号を選ぶ |
| 向いている用途 | BGM | 効果音(ジャンプ音、爆発音) |
step1 の「お菓子を取る音」「お化けに捕まる音」は pyxel.play で鳴らします。
そのとき、BGM が使っていないチャンネル(今回なら 2 か 3)を選ぶのがコツです。
BGM と同じチャンネルを使うと、効果音が鳴っているあいだ BGM のその声部が止まります。
SPEED は 1 音ぶんの長さで、120 で 1 秒です。したがって —
1 音の長さ = SPEED ÷ 120 秒
曲の長さ = 1 音の長さ × 音符の数
今回: 30 ÷ 120 = 0.25 秒 × 16 音 = 4 秒
メロディとベースの SPEED をそろえ、音符の数もそろえておくと、 ループしたときにずれません。片方だけ 8 音にすると、 ベースが 2 周するあいだにメロディが 1 周する形になります(それが狙いなら、それでも構いません)。
音は耳で確かめるのがいちばんです。1 つずつ変えて聴き比べてください。
| やってみること | 確かめたいこと |
|---|---|
SOUND 0 の SPEED を 15 / 60 に変える |
倍速・半分の速さになる。曲の印象がいちばん大きく変わる設定 |
TON を S(矩形波)や N(ノイズ)に変える |
同じ音符でも音色でまったく別の曲に聞こえる。N は打楽器の音になる |
VOL を 7 / 2 に変える |
音量が変わる。0 にすると無音になる |
EFX を V(ビブラート)や F(フェードアウト)に変える |
音の伸び方が変わる。F は音の終わりが自然に消える |
コードの loop=True を消す |
4 秒で BGM が終わり、そのあと無音になる |
| MUSIC の CH2 にもサウンドを置く | 3 声になる。ノイズ(N)で 16 分のリズムを作るとドラムになる |
MUSIC 0 の CH0 に 0 を2 つ並べる |
メロディが 2 回くり返される。1 曲を複数のサウンドでつなげられる |
フェーズ 6 で覚えた pyxel.btnp の出番です。
M キーで BGM の入/切を切り替えられるようにします。まず __init__ に 1 行足します。
self.bgm_on = True # BGM が鳴っているかどうか
pyxel.playm(0, loop=True)
そして update の先頭に、次を足します。
if pyxel.btnp(pyxel.KEY_M): # M を押した瞬間だけ
if self.bgm_on:
pyxel.stop() # 鳴っていたら止める
else:
pyxel.playm(0, loop=True) # 止まっていたら鳴らす
self.bgm_on = not self.bgm_on # 状態を反転させる
not で反転させる書き方
self.bgm_on = not self.bgm_on は、True なら False に、
False なら True に切り替えるという意味です。
「オン/オフを切り替える」ときの定番の書き方で、
if を 2 つ書くより短くて読みやすくなります。
ここで btn ではなく btnp を使うのも大事な点です。
btn だと、押しているあいだ 1 秒に 30 回も切り替わってしまいます。
| 症状 | 原因と対処 |
|---|---|
| まったく音が鳴らない | エディタで Ctrl + S による保存を忘れている。
または MUSIC のチャンネルにサウンド番号を置いていない |
| エディタでは鳴るのに、ゲームでは無音 | 保存忘れ、または pyxel.playm を書いていない。
pyxel.run より後ろに書いた場合も鳴らない
(run から先へは進みません) |
| ブツブツと途切れた音になる | pyxel.playm を update の中に書いている。
__init__ へ移す |
| 4 秒で音が止まる | loop=True を書いていない |
| メロディだけ、ベースだけしか鳴らない | MUSIC の CH0 と CH1 の両方に置けているか確認する。
片方の VOL が 0 になっていないかも確認する |
| 2 つの音が少しずつずれていく | SOUND 0 と SOUND 1 の SPEED が違う、 または音符の数が違う。どちらもそろえる |
| 音が高すぎる/低すぎる | OCTAVE の設定が違う状態で打ち込んでいる。
PageUp / PageDown で変えられる |
| ピアノロールに音符が入らない | キーを押しただけでは入りません。Enter を押して確定します。
また、カーソルが TON / VOL / EFX の行にあると音符は入りません
(↑ でピアノロールの行に戻す) |
「ラ」を入れたいのに A キーで休符になる |
音名の A(ラ)は N キーです。A キーは休符の割り当てです |
| 間違えた音符を消したい | BackSpace(手前を削除)または Delete(カーソル位置を削除)。
Ctrl + Z で元に戻すこともできます |
| パソコンからは音が出るのに聞こえない | OS 側の音量・ミュート、出力先のデバイスを確認する |
pyxel package で作品を 1 つのファイルにまとめ、
pyxel app2html で HTML 化して、GitHub Pages で公開します。
ブラウザで遊べる形になり、URL を渡すだけで人に見てもらえるようになります。