7
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PyxelAdvent Calendar 2024

Day 14

Pyxel アプリで Oggファイルを再生する(ローカルPC、Web、plumOS-RN)

Last updated at Posted at 2024-12-13

注意
バージョンや環境によってはうまく動かない可能性があります
投稿時の各バージョンは以下です

  • pyxel:2.2.7
  • pygame-ce:2.5.2
  • plumOS-RN:v2.0

はじめに

Pyxelは1.0がリリースされた時にちょっと触ったぐらいの経験だったのですが、、、
以下の2つの投稿を見て、久々に Pyxel 熱が再燃してきました🏃

最近は、以下のようなテキストアドベンチャーエンジンもどきを、少しずつ作っています👀
Pyxelの思想を考えると、少々邪道な作りですが、、、
※イメージバンク乱用していたり、BGMはpygame使ってフリー素材のOggファイルに頼り切りだったり
image.png
PCで動かせるのはもちろん、Webで実行出来たり、中華ゲーム機(plumOS利用)で実行出来たり、色々なプラットフォームで動かせるのは楽しいです👾

ただ、上述の通り、BGM再生をOggに頼り切ってしまうと、
WebやplumOSで実行する際に一手間が必要になってきます。

この投稿では、WebやplumOS-RNでOggを再生する方法の一例を記載しています。

この投稿のソースコードは以下にコミットしています。

1.ローカルPC

まずは、ローカルPCでのOggファイル再生です。

ソースコードは以下です。
pygame-ceを使用しているだけなので、あまり特別なことはしていませんね。

sample.py
import pyxel
import pygame


class Sample:
    def __init__(self):
        self.play_flag = False

        # Oggファイルパス
        self.ogg_path = "maou_bgm_acoustic22.ogg"

        # pygame初期化
        pygame.mixer.init()

        # Pyxel初期化
        pyxel.init(256, 256)
        pyxel.run(self.update, self.draw)

    def update(self):
        if not self.play_flag:
            # Oggファイル読み込み
            pygame.mixer.music.load(self.ogg_path)

            # Oggファイル再生
            pygame.mixer.music.play(-1)  # -1はループ再生

            self.play_flag = True

    def draw(self):
        pyxel.cls(7)

        # 再生表示
        if self.play_flag:
            pyxel.text(2, 2, "Now Playing...", 1)
            pyxel.text(2, 10, self.ogg_path, 1)


Sample()

実行する時は以下の通り。

sample.py
cd 01.Local-PC
python sample.py

2.Web

次にWeb実行です。
せっかくのWeb実行なので、GitHub Pagesに公開しています。

Web実行用のソースコードは以下です。
Pythonコード自体はローカルPCと同じソースコードですね。

import pyxel
import pygame


class Sample:
    def __init__(self):
        self.play_flag = False

        # Oggファイルパス
        self.ogg_path = "maou_bgm_acoustic22.ogg"

        # pygame初期化
        pygame.mixer.init()

        # Pyxel初期化
        pyxel.init(256, 256)
        pyxel.run(self.update, self.draw)

    def update(self):
        if not self.play_flag:
            # Oggファイル読み込み
            pygame.mixer.music.load(self.ogg_path)

            # Oggファイル再生
            pygame.mixer.music.play(-1)  # -1はループ再生

            self.play_flag = True

    def draw(self):
        pyxel.cls(7)

        # 再生表示
        if self.play_flag:
            pyxel.text(2, 2, "Now Playing...", 1)
            pyxel.text(2, 10, self.ogg_path, 1)


Sample()

htmlファイルには少し対応が必要です。

PyxelのWeb実行では、追加で利用できるパッケージが限られています(PyxelはPyodideを利用しているため、Pyxelの制約と言うよりはPyodideの制約)
利用できるパッケージは、Pyodide 対応パッケージに記載されている通りです。今回は pygame-ce を利用しています。

追加パッケージを利用する場合には、<pyxel-play>タグの packages にパッケージ名を追加します。

index.html
<!DOCTYPE html>
<html>
    <head>
        <script src="https://cdn.jsdelivr.net/gh/kitao/pyxel/wasm/pyxel.js"></script>
    </head>

    <body>
        <pyxel-play root="." name="02.Web.pyxapp" packages="pygame-ce"></pyxel-play>
    </body>
</html>

実行する時は以下の通り。

sample.py
cd 02.Web
pyxel package ./ sample.py
python -m http.server 8000  # http://localhost:8000

3.plumOS-RN

最後にplumOS-RNでの実行です。
少々、録画の音量が小さいですが、以下のように動作しています。

ローカルPCやWebでは、pygame-ce が利用できたので、pygame-ce のBGM再生機能をそのまま使用しました。
plumOS-RNでは、任意のパッケージは(現時点では)追加できないので、もう少し別の対応をしています。

【2024年12月14日追記】
ゲームで見るITの世界さんから情報いただきました。
portsやSSH接続でpipインストール出来るとのこと(試していませんがPythonスクリプトからのsubprocessでもいける?)
これで、sample.pyはどのプラットフォームでも共通で行けますね。ありがとうございます。

以下は、訂正前の情報です。作業ログとして残しておきます👀

pygame-ce は内部では、SDL2と言うマルチメディアライブラリを利用して、マルチメディアを扱っています。

plumOS-RNにも、SDL2自体はインストールされているため、
Pythonから直接SDL2を使用します(/usr/lib/の下にsoファイルがいます)

sample.py
import ctypes
from ctypes import c_int, c_char_p

import pyxel


class Sample:
    def __init__(self):
        self.play_flag = False

        # Oggファイルパス
        self.ogg_path = "maou_bgm_acoustic22.ogg"

        # Pyxel初期化
        pyxel.init(256, 256)
        pyxel.run(self.update, self.draw)

    def update(self):
        if not self.play_flag:
            # SDL2およびSDL2_mixerの共有ライブラリをロード
            sdl2 = ctypes.CDLL("/usr/lib/libSDL2.so")
            sdl2_mixer = ctypes.CDLL("/usr/lib/libSDL2_mixer.so")

            # SDL2およびSDL2_mixerの関数を定義
            sdl2.SDL_Init.argtypes = [c_int]
            sdl2.SDL_Init.restype = c_int
            sdl2_mixer.Mix_Init.argtypes = [c_int]
            sdl2_mixer.Mix_Init.restype = c_int
            sdl2_mixer.Mix_OpenAudio.argtypes = [c_int, c_int, c_int, c_int]
            sdl2_mixer.Mix_OpenAudio.restype = c_int
            sdl2_mixer.Mix_LoadMUS.argtypes = [c_char_p]
            sdl2_mixer.Mix_LoadMUS.restype = ctypes.c_void_p
            sdl2_mixer.Mix_PlayMusic.argtypes = [ctypes.c_void_p, c_int]
            sdl2_mixer.Mix_PlayMusic.restype = c_int

            # SDL2を初期化
            sdl2.SDL_Init(0x00000010)  # オーディオサブシステムを有効化

            # SDL_mixerのOGGサポートを有効化
            sdl2_mixer.Mix_Init(0x00000002)  # Oggの初期化フラグ

            # オーディオデバイスを初期化
            # 周波数: 44100Hz, フォーマット: 16ビット, チャンネル: ステレオ, チャンクサイズ: 1024
            sdl2_mixer.Mix_OpenAudio(44100, 0x8010, 2, 1024)

            # Oggファイル読み込み
            music = sdl2_mixer.Mix_LoadMUS(self.ogg_path.encode("utf-8"))

            # Oggファイル再生
            sdl2_mixer.Mix_PlayMusic(music, -1)  # -1はループ再生

            self.play_flag = True

        # AボタンかBボタンで終了
        if pyxel.btnp(pyxel.GAMEPAD1_BUTTON_A) or pyxel.btnp(pyxel.GAMEPAD1_BUTTON_B):
            pyxel.quit()

    def draw(self):
        pyxel.cls(7)

        # 再生表示
        if self.play_flag:
            pyxel.text(2, 2, "Now Playing...", 1)
            pyxel.text(2, 10, self.ogg_path, 1)


Sample()

実行する時は以下の通り。
出来上がった「03.plumOS-RN.pyxapp」をWinSCPなどで、plumOS-RNを導入した中華ゲーム機へコピーしてください。

sample.py
cd 03.plumOS-RN
pyxel package ./ sample.py

使用BGMについて

BGMは、魔王魂 様の アコースティック22 を使用しております。
魔王塊様はゲーム制作の強い味方です。ありがとうございます🙇


以上、Oggファイルを再生したお話でした。

7
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?