Pygame初心者必見!mixer.get_busyの基本から応用まで

2025-05-31

戻り値

  • False (偽): ミキサーは現在サウンドを再生していません(または、サウンドがキューに入っていてもまだ再生が開始されていない場合)。
  • True (真): ミキサーが現在サウンドを再生中です。

使用例

import pygame

pygame.mixer.init()

# サウンドファイルをロード
try:
    sound = pygame.mixer.Sound("your_sound_file.wav") # あなたのサウンドファイル名に置き換えてください
except pygame.error as e:
    print(f"サウンドファイルのロードエラー: {e}")
    pygame.mixer.quit()
    exit()

# サウンドを再生
sound.play()

# ミキサーがビジーかどうかを確認
if pygame.mixer.get_busy():
    print("サウンドが再生中です!")
else:
    print("サウンドは再生されていません。")

# (必要に応じて、サウンドが終了するまで待つなどの処理)
# pygame.time.wait(int(sound.get_length() * 1000))

pygame.mixer.quit()

解説

この関数は、特にゲームのループ内でサウンドの再生状況を監視する際に非常に便利です。例えば、

  • ゲームの状態に応じた処理
    サウンドが再生中である間は、特定のゲーム内イベントを一時停止したり、別の処理を行ったりすることができます。
  • 効果音の再生キュー管理
    特定の効果音が終了するのを待ってから次の効果音を再生したい場合などに使用できます。
  • BGM の二重再生を防ぐ
    既に BGM が再生中であれば、新しい BGM を再生しないようにすることができます。


pygame.error: mixer system not initialized

これは、mixer.get_busy() を呼び出す前にPygameのミキサーモジュールが初期化されていない場合に発生する最も一般的なエラーです。

原因

  • pygame.mixer.quit() を呼び出した後に get_busy() を呼び出そうとしている。
  • pygame.mixer.init() または pygame.init() を呼び出していない。

解決策
プログラムの開始時に必ずミキサーを初期化してください。通常は pygame.init() でPygame全体を初期化すればミキサーも初期化されますが、音声だけを使う場合は pygame.mixer.init() を明示的に呼び出すこともできます。

import pygame

# 1. Pygame全体を初期化(推奨)
pygame.init() 

# または、ミキサーだけを初期化
# pygame.mixer.init() 

# ... (サウンドのロードと再生) ...

if pygame.mixer.get_busy():
    print("サウンド再生中")

# 終了処理
pygame.mixer.quit()
pygame.quit()

サウンドが再生されていないのに get_busy() が True を返す(またはその逆)

これは、get_busy() の動作を誤解している場合や、プログラムのロジックに問題がある場合に発生します。

原因

  • 非同期処理の理解不足
    play() はサウンドの再生を「開始」するだけで、再生が「完了」するまで待機しません。get_busy() はその瞬間の状態を返します。
  • チャンネルの混同
    pygame.mixer.get_busy() はミキサー全体がビジーかどうかを報告します。特定のサウンドオブジェクトやチャンネルが再生中かどうかを確認したい場合は、pygame.mixer.Sound オブジェクトや pygame.mixer.Channel オブジェクトの get_busy() メソッドを使用する必要があります。
  • サウンドがループ再生されている
    ループ再生している場合、get_busy() は常に True を返します。
  • サウンドが非常に短い
    短い効果音の場合、play() を呼び出してすぐに get_busy() をチェックすると、まだミキサーが再生を開始していない、またはすぐに終了してしまっているため False を返すことがあります。

解決策

  • ループ再生を考慮する
    ループしている限り get_busy()True を返します。ループ再生を停止したい場合は stop() メソッドを使用します。
  • 特定のサウンドの再生状況を確認したい場合
    import pygame
    
    pygame.init()
    pygame.mixer.set_num_channels(8) # 必要に応じてチャンネル数を設定
    
    sound1 = pygame.mixer.Sound("sound1.wav")
    sound2 = pygame.mixer.Sound("sound2.wav")
    
    channel1 = sound1.play() # チャンネルオブジェクトを取得
    
    if channel1.get_busy(): # 特定のチャンネルが再生中かを確認
        print("Sound1 が再生中です。")
    
    if pygame.mixer.get_busy(): # ミキサー全体が再生中かを確認
        print("ミキサー全体がビジーです。")
    
    pygame.quit()
    
  • 短いサウンドの場合
    サウンドが再生されるのを待つために pygame.time.wait()pygame.time.delay() を少し追加して確認するか、ループ内で定期的に get_busy() をチェックするなどの工夫が必要です。

サウンドがまったく再生されない

get_busy() に直接関係するエラーではありませんが、サウンドが再生されないと get_busy() も常に False を返すため、関連する問題として挙げられます。

原因

  • pygame.display.set_mode() でウィンドウが作成されていない
    一部の環境では、ウィンドウが作成されていないと音声が再生されない場合があります(特に一部の古いPygameバージョンや特定のOS設定)。
  • OSのサウンド設定で音が出ていない、またはPygameがアクセスできない。
  • 音量がゼロに設定されている。 (pygame.mixer.Sound.set_volume(), pygame.mixer.music.set_volume(), pygame.mixer.set_master_volume())
  • サウンドファイルが破損している、またはPygameがサポートしていない形式。 (Pygameは通常 WAV, OGG, MP3 をサポートしますが、MP3は環境によってコーデックの問題が発生する場合があります)
  • サウンドファイルのパスが間違っている、またはファイルが存在しない。

解決策

  • pygame.display.set_mode() を先に呼び出す。
  • OSのサウンド設定を確認する。
  • 音量設定の確認
    pygame.mixer.init()
    sound = pygame.mixer.Sound("your_sound_file.wav")
    sound.set_volume(0.5) # 例: 0.5に設定
    sound.play()
    print(f"サウンドの音量: {sound.get_volume()}")
    print(f"マスター音量: {pygame.mixer.get_master_volume()}")
    
  • サウンドファイルの確認
    • ファイルパスが正しいか確認する。
    • ファイルが破損していないか、別のプレイヤーで再生できるか確認する。
    • Pygameがサポートする形式であるか確認する。

プログラムが固まる(無限ループ)

get_busy() を使用したループでよく見られる問題です。

原因
サウンドが終了するのを待つために while pygame.mixer.get_busy(): pass のようなループを使用すると、Pygameが他のイベント(ウィンドウの更新など)を処理する機会がなくなり、プログラムがフリーズしたように見えます。

解決策
ループ内では必ず pygame.time.Clock().tick()pygame.event.get() などを呼び出して、Pygameがイベントを処理できるようにします。

import pygame

pygame.init()
screen = pygame.display.set_mode((600, 400)) # ウィンドウも作成
clock = pygame.time.Clock()

sound = pygame.mixer.Sound("your_sound_file.wav")
sound.play()

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    if not pygame.mixer.get_busy():
        print("サウンド再生が終了しました。")
        # 例えば、サウンドが終了したらループを抜ける
        # running = False 
        
    screen.fill((0, 0, 0))
    pygame.display.flip()
    clock.tick(60) # フレームレートを制限し、イベント処理を許可

pygame.quit()


基本的な使用例:サウンドが再生中かを確認する

最も基本的な使い方は、サウンドを再生した後にミキサーが忙しいかどうか(つまり、音が鳴っているか)を確認することです。

import pygame
import time # 時間を制御するために使用

pygame.init() # Pygameの全モジュールを初期化

# ミキサーモジュールを初期化(pygame.init()がこれを行う場合が多いが、明示的に行うことも可能)
# pygame.mixer.init() 

# 音源ファイルをロード
# ここではダミーファイル名を使っています。実際には存在する .wav または .ogg ファイルに置き換えてください。
try:
    sound_effect = pygame.mixer.Sound("explosion.wav") # サウンドファイル名に置き換えてください
except pygame.error as e:
    print(f"サウンドファイルのロードエラー: {e}")
    print("有効なサウンドファイル(例: .wav, .ogg)をスクリプトと同じディレクトリに置いてください。")
    pygame.quit()
    exit()

print("サウンドを再生します。")
sound_effect.play() # サウンドを再生

# サウンドが再生中かどうかを確認
if pygame.mixer.get_busy():
    print("ミキサーは現在サウンドを再生中です!")
else:
    print("ミキサーは現在サウンドを再生していません。")

# 少し待ってから再度確認(短いサウンドの場合、すぐに終わってしまう可能性があるため)
time.sleep(0.5) # 0.5秒待つ

if pygame.mixer.get_busy():
    print("0.5秒後もミキサーはサウンドを再生中です。")
else:
    print("0.5秒後、ミキサーはサウンドを再生していません(サウンドが終了した可能性があります)。")

# サウンドが完全に終了するのを待つ(例:サウンドの長さを取得して待つ)
# sound_effect.get_length() は秒単位で長さを返します
# time.sleep(sound_effect.get_length() + 0.1) 

pygame.quit() # Pygameを終了

解説
sound_effect.play() の直後に pygame.mixer.get_busy() を呼び出すと、ミキサーがサウンドの再生を開始していれば True を返します。非常に短いサウンドの場合、get_busy()True を返す期間は非常に短いため、time.sleep() などで少し待ってから再度確認すると、サウンドが終了しているために False を返すことがあります。

ゲームループ内での使用例:BGMの二重再生を防ぐ

ゲームにおいて、BGMが既に再生中であれば、再度再生しないようにしたい場合があります。

import pygame

pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("BGM管理の例")

# BGMファイルをロード
# ここではダミーファイル名を使っています。実際には存在する .ogg または .mp3 ファイルに置き換えてください。
try:
    pygame.mixer.music.load("background_music.ogg") # BGMファイル名に置き換えてください
except pygame.error as e:
    print(f"BGMファイルのロードエラー: {e}")
    print("有効なBGMファイル(例: .ogg, .mp3)をスクリプトと同じディレクトリに置いてください。")
    pygame.quit()
    exit()

running = True
music_playing = False # BGMが再生中かどうかを追跡するフラグ

print("スペースキーを押してBGMの再生/停止を切り替えます。")

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                # ミキサーが現在何かを再生しているかチェック
                if not pygame.mixer.get_busy(): # ミキサーが何も再生していない場合
                    print("BGMを再生します。")
                    # -1 はBGMを無限ループで再生することを意味します
                    pygame.mixer.music.play(-1) 
                    music_playing = True
                else: # ミキサーが何かを再生中の場合
                    # ここではBGMだけを対象にしているので、BGMが再生中かを確認する
                    if pygame.mixer.music.get_busy(): # BGMが再生中かを確認
                        print("BGMを停止します。")
                        pygame.mixer.music.stop()
                        music_playing = False
                    else:
                        print("ミキサーはビジーですが、BGMではありません。")

    # ゲームのロジックや描画をここに追加

    screen.fill((50, 50, 50))
    pygame.display.flip()

pygame.quit()

解説
この例では、pygame.mixer.get_busy() を使って、ミキサー全体が忙しいかどうかをチェックしています。BGMの再生/停止をスペースキーで行う際に、もしミキサーが何も再生していなければBGMを再生します。また、BGMが再生中の場合は停止します。 pygame.mixer.music.get_busy() はBGM(ストリーミング音楽)に特化した再生状況を返しますが、pygame.mixer.get_busy() は効果音(pygame.mixer.Sound)も含めてミキサー全体の状態を返します。この例では、BGMだけを対象にしているので、両方を組み合わせて使うのが適切です。

pygame.mixer.get_busy() を使うことで、プログラムをフリーズさせずにサウンドの終了を待つことができます。

import pygame

pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("サウンド終了待機(非ブロッキング)")
clock = pygame.time.Clock() # フレームレート制御用

# 効果音ファイルをロード
try:
    long_sound = pygame.mixer.Sound("long_effect.wav") # 長めのサウンドファイル名に置き換えてください
except pygame.error as e:
    print(f"サウンドファイルのロードエラー: {e}")
    print("有効なサウンドファイル(例: .wav, .ogg)をスクリプトと同じディレクトリに置いてください。")
    pygame.quit()
    exit()

print("長めのサウンドを再生します。")
long_sound.play()

sound_finished_message_shown = False

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    # サウンドが再生中かどうかを毎フレームチェック
    if not pygame.mixer.get_busy() and not sound_finished_message_shown:
        print("サウンドの再生が終了しました!")
        sound_finished_message_shown = True # メッセージが複数回表示されないようにフラグを立てる

    # ゲームの他のロジックや描画
    screen.fill((100, 100, 100))
    # テキスト表示など
    font = pygame.font.Font(None, 36)
    text = font.render(f"サウンド再生中: {pygame.mixer.get_busy()}", True, (255, 255, 255))
    screen.blit(text, (50, 50))

    pygame.display.flip()
    clock.tick(60) # 毎秒60フレームに制限

pygame.quit()

解説
この例では、ゲームループ内で繰り返し pygame.mixer.get_busy() をチェックしています。サウンドが終了すると False を返すので、そのタイミングで特定の処理(例: メッセージ表示)を行うことができます。このようにすることで、サウンドの終了を待っている間も、ゲームは通常通り動作し続けることができます(非ブロッキング)。

pygame.mixer.get_busy() は、Pygameのサウンドミキサーが全体としてサウンドを再生中であるかどうかを判断するために非常に有用です。これらの例は、その基本的な使い方から、ゲームループ内でのBGM管理、非ブロッキングでのサウンド終了待機など、様々なシナリオでどのように活用できるかを示しています。



pygame.mixer.get_busy() は、Pygameのミキサーが現在サウンドを再生中であるかどうかを全体として確認するのに便利ですが、より特定の状況や柔軟な制御が必要な場合には、いくつかの代替方法があります。

pygame.mixer.Channel.get_busy() を使う