前の記事:
Python pygame (GUI プログラミング) モジュールの最も完全なチュートリアル (7)_Python-ZZY のブログ - CSDN ブログ
リスト:
README.md · Python-ZZY/Python-Pygame の最も完全なチュートリアル - Gitee.com
23 高度なサウンド操作
参考文献:
https://pyga.me/docs/ref/sndarray.html
https://pyga.me/docs/ref/midi.html
23.1 MIDI経由でサウンドを出力する
pygame.midi モジュールは MIDI (Musical Instrument Digital Interface) を操作します。さまざまな電子楽器が MIDI を介してコンピューターと通信します。MIDI 入力を管理すると、一部の MIDI 入力デバイスから情報を取得できます。MIDI を出力すると、楽器をシミュレートして音符を演奏できます。
pg.camera と同様に、midi は pygame に自動的にインポートされないため、追加のインポートと初期化が必要です。
import pygame as pg
from pygame import midi
pg.init()
midi.init()
以下のプログラムは、MIDI 経由で低音から高音までのスケール (隣接する音符の間は半音) を再生する方法を示しています。
import pygame as pg
from pygame import midi
pg.init()
midi.init()
port = midi.get_default_output_id() # 获取默认的MIDI输出
midi_out = midi.Output(port)
# 速度范围0 - 127,速度127时音符持续时间最长
velocity = 100
# 声调最高音符名为127
max_note = 127
try:
for note in range(0, max_note + 1):
print(note)
midi_out.note_on(note, velocity) # 按下音符
# 音符播放是非阻塞的,不会等一个音符播完再执行下面的代码
pg.time.wait(800) # 等待一段时间后再执行代码
midi_out.note_off(note) # 释放音符
finally: # 退出midi
del midi_out
midi.quit()
上記のコードは、まず get_default_output_id メソッドを通じてデフォルトの MIDI デバイスを取得し、次に MIDI 出力を管理するための Output オブジェクトを作成します。次に、Output.note_on 経由でノートを押し、800 ミリ秒待った後にノートを放します。
最後に、finally コード ブロックを通じて、例外が発生したかどうかに関係なく、midi を終了する必要があります。明示的に終了しなくても問題が発生する可能性は低いですが、公式の提案では、MIDI 終了を確実にするために、finally を追加することになっています。
note_on メソッドは 3 つのパラメータを受け取ります。1 つ目はノート コードです。範囲は 0 ~ 127 で、隣接するノート間の差は 1 半音です。数値が大きいほどピッチが高くなります。MIDI ノート コード テーブルを参照してください。2 番目のパラメータは音の大きさ (なぜ公式が速度を使って表現するのかはわかりません) を示し、範囲も 0 ~ 127 で、数値が大きいほど音が大きくなります。3 番目のパラメーター channel はオプションで、再生するチャンネルを示します。note_on とは対照的に、同じパラメータを使用してノートを解放するための note_off メソッドもあります。
23.2 楽器音のシミュレーション
pg.midi.Output オブジェクトには set_instrument メソッドもあり、音符の音色をさまざまな楽器の音色に設定できます。デフォルトのサウンドはピアノです。
音色を設定するには音色コードを指定する必要がありますが、すべてのコードについてはMIDI128音色カラーコード表を参照してください。音色エンコーディングの範囲は 0 ~ 127 のままです。
pg.midi.Output.set_instrument(instrument_id, channel=0) -> None
次の例では、すべてのパッチのサウンドを再生します。
import pygame as pg
from pygame import midi
pg.init()
midi.init()
port = midi.get_default_output_id() # 获取默认的MIDI输出
midi_out = midi.Output(port)
velocity = 100
max_instrument = 72
try:
for instrument in range(70, max_instrument + 1):
print(instrument)
midi_out.set_instrument(instrument) # 设置音色
midi_out.note_on(80, velocity) # 按下音符
pg.time.wait(800)
midi_out.note_off(80) # 释放音符
finally:
del midi_out
midi.quit()
23.3 生の MIDI メッセージ データの書き込み
midi.Output.write は、ノートの再生を制御するためにさらに MIDI データを書き込むために使用されます。
Output.write(data) -> None
データは複数の小さなリストを含むリストでなければならず、各リストは MIDI イベント (以下、理解しやすいように「オペレーション」と呼びます) を表します。操作リストは情報リストとタイムスタンプで構成されます。情報リストは通常 3 つの値または 1 つの値で、最初の値はステータス ビットを表し、次の値はデータ ビットを表します (オプション、デフォルトは 0)。たとえば、次のようなデータリストがあります。
port = midi.get_default_output_id()
midi_out = midi.Output(port, latency=1) # 设置延迟为1
program_change = 192
note_on = 144
note_off = 128
data = [
[[program_change, 40, 0], 0],
[[note_on, 80, 127], 0],
[[note_off, 80, 127], 1000],
]
midi_out.write(data)
このデータ リストには、プログラム (つまり楽器の音) の変更、音符を押す、音符を離すという 3 つの MIDI 操作が含まれています。タイムスタンプは、アクションがいつトリガーされたかを示します。たとえば、このデータは、時間が 0ms のときに音色を変更し、ピッチ 80、強度 127 の音符を押し、80 の場合、強度 127 の音符を押します。
write を使用する場合、Output クラスの latency パラメーターは通常 0 より大きい値に設定する必要があることに注意してください。Latency は遅延、つまりデータを書き込むまでの遅延を表し、単位は ms です。遅延が設定されていない場合、タイムスタンプは無効になり、すべての操作が同時に実行されます (個人的にはこの設定はあまり良くないと思います)。あまり遅延は必要ないので1に設定しました。遅延を 2000 に設定すると、書き込み操作が処理されるまでに 2000 ミリ秒の遅延が発生します。レイテンシーはタイムスタンプにカウントされません。
前述したように、各操作にはタイムスタンプで構成される操作情報が含まれています。では、前の操作情報は何を表すのでしょうか? この記事を参照してください:一般的な MIDI メッセージのステータス ビットとデータ ビットの意味表。ステータス ビットのコードにより、後続のデータ ビットの意味が決まります。例えば、ステータスビット144は、ノートがチャンネル1で押されていることを意味し、次のデータビットはそれぞれノートコードとラウドネスコードを表す。ステータスビット128は、ノートがチャンネル1上でリリースされたことを表し、次のデータビットはそれぞれノートコードとラウドネスコードを表す。ステータスビット 192 はチャンネル 1 の音色を変更することを意味し、その後ろに楽器の音色コードを意味するデータが 1 ビットだけあります。データは 1 ビットだけ必要なので、最後のデータ ビットは空白のままで 0 のままで問題ありません。 。
さらに、データリストが整然としており、操作はタイムスタンプに従って小さいものから大きいものまで並べる必要があり、そうしないと一部の操作が正しく実行されないことにも注意する必要があります。例えば:
data = [
[[program_change, 70, 0], 0],
[[note_on, 80, 127], 0],
[[note_on, 100, 127], 1000],
[[note_off, 80, 127], 2000],
[[note_off, 100, 127], 2000],
]
'上面是正确的排列 (0 <= 1000 <= 2000 <= 2000)'
data = [
[[program_change, 70, 0], 0],
[[note_on, 80, 127], 0],
[[note_off, 80, 127], 2000],
[[note_on, 100, 127], 1000],
[[note_off, 100, 127], 2000],
]
'上面是错误的排列,时间戳没有从小到大排列'
'(0 <= 2000 !< 1000 <= 2000)'
'如果使用这种方法排列将执行不到[[note_on, 100, 127], 1000]这一段'
上記の正しいコードに従って演奏すると、次の効果が得られます: 最初に音色を変更して 80 ノートを演奏し、1 秒後に 100 ノートを演奏し、1 秒後に 2 つのノートの再生を同時に終了します。
23.4 MIDI モジュール インデックス - 楽器デジタル インターフェイス
Event : midi は入力時と出力時にそれぞれ MIDIIN と MIDIOUT という 2 つのイベントを生成します。
init() -> なし、quit() -> なし
MIDIを初期化/終了します。
入力(device_id) -> なし
入力(device_id、buffer_size) -> なし
MIDI 入力オブジェクトを作成します。device_id は入力デバイスの識別子、buffer_id はバッファリングできる入力イベントの数です。
Input.close() -> なし
MIDI 入力をオフにしてみてください (Windows システムでは問題になる可能性があります)。
Input.poll() -> bool
MIDI入力データがあるかどうかを判定する
Input.read(num_events) -> midi_event_list
未処理の MIDI 入力イベントを読み取って返します。num_events はイベントの数を表します。
出力(device_id) -> なし
出力(device_id, latency=0) -> なし
出力(device_id、buffer_size=256) -> なし
出力(device_id、latency、buffer_size) -> なし
MIDI 出力オブジェクトを作成します。buffer_size はバッファリングされた出力イベントの数、latency は出力遅延時間です。
Output.abort() -> なし
MIDI 送信を中止します (送信が終了する前にデータが終了する可能性があります)
Output.close() -> なし
MIDI 出力オブジェクトを閉じます (Windows では問題が発生する可能性があります)
Output.note_off(note、velocity=None、channel=0) -> なし
ノートを放します。ノートはノートコード、ベロシティは速度、チャンネルはチャンネルです。
Output.note_on(ノート, ベロシティ, チャンネル=0) -> なし
ノートを押します。ノートはノートコード、ベロシティは速度、チャンネルはチャンネルです。
Output.set_instrument(instrument_id, channel=0) -> なし
楽器の音を設定する
Output.pitch_bend(値=0、チャンネル=0) -> なし
MIDI 出力のピッチを微調整します。正の値は上昇を意味し、負の値は下降を意味します。範囲は -8192 ~ +8191 で、4096 ごとに半音を表します。例: -8192 は 2 半音 (つまり 1 音全体) 下げることを意味し、4096 は 1 半音上げることを意味します。
Output.write(data) -> なし
複数の MIDI 操作を記述する
Output.write_short(ステータス) -> なし
Output.write_short(ステータス、データ1=0、データ2=0) -> なし
単一の MIDI オペレーションを書き込みます。status はステータス ビット、data1、data2 はそれぞれ 2 つのデータ ビットです。タイムスタンプは考慮されません。
Output.write_sys_ex(when, msg) -> なし
システムメッセージが満載の MIDI オペレーションを作成します。
midi_output.write_sys_ex(0, '\xF0\x7D\x10\x11\x12\x13\xF7')
# 相当于:
midi_output.write_sys_ex(pg.midi.time(), # midi计时器的时间
[0xF0, 0x7D, 0x10, 0x11, 0x12, 0x13, 0xF7])
get_default_input_id() -> デフォルト ID
デフォルトの MIDI 入力デバイスを取得する
get_default_output_id() -> デフォルト ID
デフォルトの MIDI 出力デバイスを取得する
get_device_info(an_id) -> (interf、名前、入力、出力、オープン済み)
get_device_info(an_id) -> なし
指定されたデバイス ID の情報を取得します。戻り値は通常タプルであり、IDが範囲を超える場合はNoneを返します。タプル内の各値の意味: interf はデバイス インターフェイスを説明する文字列 (「ALSA」など) を表し、name はデバイス名 (「Midi Through Port-0」など) を表し、input はデバイスがinput device (1 または 0)、output はデバイスが出力デバイスであるかどうかを示します (1 または 0)、opened はデバイスが開いているかどうかを示します。
midis2events(midi_events, device_id) -> [イベント, ...]
MIDI イベントを pygame イベントに変換します。midi_events は、Output.write に渡されるデータ パラメーター内の各操作のリストです。
time() -> 時間
MIDI タイマーによって取得された時間を返します (midi.init からカウントされます)。
frequency_to_midi(midi_note) -> midi_note
周波数を MIDI ノート コードに変換します (最も近いノートに四捨五入)
midi_to_ansi_note(midi_note) -> ansi_note
MIDIノートコードをANSIノート形式の文字列に変換します。
MidiException(errno) -> なし
MIDI例外。MIDI デバイスが見つからない場合、またはその他の理由でエラーが報告されることがあります。
23.5 sndarray モジュールのインデックス付け - Sound 配列と numpy 配列
pg.sndarray は、pg.mixer.Sound と numpy 配列の間の変換に使用され、pg.surfarray のような numpy ライブラリに依存します。
サウンド データは 1 秒あたり数千のサンプルで構成されており、各サンプルは特定の瞬間における波の振幅です。たとえば、22khz 形式では、配列の要素番号 5 は 5/22000 秒後の波の振幅です。
配列(サウンド) -> 配列
サウンド オブジェクトをコピーして numpy 配列に変換します。配列を変更してもサウンド オブジェクト自体は変更されません。
サンプル(サウンド) -> 配列
サウンド オブジェクト間を numpy 配列に変換します。配列を変更するとサウンド オブジェクト自体が変更されます。
make_sound(配列) -> サウンド
サウンド サンプルの配列を Sound オブジェクトに変換します。
24 パイゲームの探索
参考資料: pygame — pygame-ce v2.4.0 ドキュメント
24.1 pygameメインモジュールインデックス
pygame のメインモジュールには特に重要な内容はありません。読者は pygame を学習する際に、メインモジュールでよく使用される関数をすでに理解しているため、いくつかの関数の使用方法は次に整理されます。
メインの pygame モジュールで使用されそうなものは次の 4 つだけです (残りはほとんど役に立ちません)。
init() -> (numpass、numfail)
pygame のすべてのサブモジュールを初期化し、成功した初期化と失敗した初期化の数を返します。
実際、pygame の各サブモジュールには init メソッドと quit メソッドがあり、これらは単一のサブモジュールを初期化して終了するために使用されます。Pygame には多くの機能があり、単にゲームを作成するだけでなく、音楽の再生などにも使用される場合があります。pygame.mixer モジュールのみを使用する必要がある場合は、pygame 全体を初期化する必要はなく、pygame.init() の代わりに pygame.mixer.init() を呼び出すだけです。
quit() -> なし
init メソッドの逆で、pygame を終了します。このメソッドは pygame ウィンドウを閉じます。pg.quit メソッドを呼び出しても、Python プログラム全体は終了せず、pygame のみが終了します。Python プログラムが完全に終了することを確認するために、終了時に sys.exit を呼び出す必要がある場合があります。
register_quit(呼び出し可能) -> なし
機能を登録します。pygame.quit が呼び出されたときに呼び出されます。
エラー
pygame.error は Exception を継承し、pygame 関連の例外を示します。例外キャッチに使用できます。
24.2 環境変数
pygame の動作の一部は、環境変数、つまり os.environ の操作によって制御できます。例えば:
import os
os.environ["环境变量名"] = "环境变量值"
以下は、考えられる pygame 関連の環境変数とその使用法です。
PM_RECOMMENDED_INPUT_DEVICE
デフォルトのMIDI入力デバイスを設定する
PM_RECOMMENDED_OUTPUT_DEVICE
デフォルトの MIDI 出力デバイスを設定する
PYGAME_DISPLAY
pygameの表示インデックス(つまり、pg.display.set_modeの表示パラメータ)。デフォルトは「0」です。
PYGAME_FORCE_SCALE
set_mode にズーム表示モードを強制的に使用します (「デフォルト」または「写真」)。「写真」が設定されている場合、スケーリングには、可能な場合は最も低速ですが最高品質の異方性スケーリング アルゴリズムが使用されます。pygame.display.set_mode() を呼び出す前に設定する必要があります
PYGAME_BLEND_ALPHA_SDL2
これにより、pygame はすべてのアルファ ブレンドに SDL2 ブリッターを使用するようになります。SDL2 レンダラーはデフォルトよりも高速な場合がありますが、異なる計算式を使用するため、最終的な色が異なる場合があります。インポートされたすべての pygame モジュールを初期化するには、pygame.init() を呼び出す前に設定する必要があります。
PYGAME_HIDE_SUPPORT_PROMPT
pygame起動時に出力されるプロンプトを非表示にするかどうかは、「1」に設定すると非表示になります。
PYGAME_CAMERA
「opencv」などのカメラのバックエンドを設定します。pg.camera が初期化される前に呼び出す必要があります。
SDL_IME_SHOW_UI
入力候補ボックスを表示するかどうか。pg.display.set_mode の前に呼び出す必要があります
SDL_VIDEO_CENTERED
ウィンドウを画面の中央に配置するかどうか。pg.display.set_mode の前に呼び出す必要があります
SDL_VIDEO_WINDOW_POS
pygame ウィンドウの位置 (左上隅) を「x, y」の形式で設定します。pg.display.set_mode の前に呼び出す必要があります
SDL_VIDEO_ALLOW_SCREENSAVER
デフォルトでは、pygame の実行中にスクリーン セーバーは無効になります。「1」に設定すると、スクリーン セーバー システムの表示が許可されることを意味します。
SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS
デフォルトでは、ウィンドウにフォーカスがない場合、ゲームパッドなどのデバイスは更新されません。ただし、この環境変数を使用すると、ウィンドウがバックグラウンドにあるときでもジョイスティックの更新を取得できます。pygame.init() を呼び出す前に設定する必要があります。
24.3 _sdl2
実験的な SDL2 機能の一部が pygame._sdl2 モジュールに含まれていますが、将来変更される可能性があります。_sdl2 にはいくつかのサブモジュールも含まれています。_sdl2 は pygame に自動的にインポートされません。
_sdl2 には次のモジュールが含まれています。
モジュール名 | 説明 |
コントローラ | コントローラー(ゲームパッドなど)の操作 |
触る | タッチスクリーン入力 |
窓 | pygameマルチウィンドウの作成 |
ビデオ | 画像、テクスチャなどが含まれます。 |
次の投稿
作業中です(時間がかかる可能性があります)...