Examples

Basic Music Player

A simple music player with play/pause/stop controls:

extends Control

var player: AudioStreamPlayer
var stream: AudioStreamOpenMPT

func _ready():
    # Setup player
    player = AudioStreamPlayer.new()
    add_child(player)

    # Load module
    stream = AudioStreamOpenMPT.new()
    if stream.load_from_file("res://music/song.mod") == OK:
        player.stream = stream
        print("Loaded: ", stream.get_title())
    else:
        push_error("Failed to load module")

func play_music():
    player.play()

func pause_music():
    player.stream_paused = !player.stream_paused

func stop_music():
    player.stop()

Module Information Display

Display detailed information about a loaded module:

extends Node

func display_module_info(stream: AudioStreamOpenMPT):
    print("=" * 50)
    print("MODULE INFORMATION")
    print("=" * 50)

    # Metadata
    print("Title:    ", stream.get_title())
    print("Artist:   ", stream.get_artist())
    print("Duration: ", "%.2f" % stream.get_length(), " seconds")
    print("BPM:      ", stream.get_bpm())

    # Structure
    print("\nSTRUCTURE:")
    print("Channels:    ", stream.get_num_channels())
    print("Orders:      ", stream.get_num_orders())
    print("Patterns:    ", stream.get_num_patterns())
    print("Instruments: ", stream.get_num_instruments())
    print("Samples:     ", stream.get_num_samples())

    # List channels
    print("\nCHANNELS:")
    var channels = stream.get_channel_names()
    for i in range(channels.size()):
        print("  %2d: %s" % [i, channels[i]])

    # List instruments
    print("\nINSTRUMENTS:")
    var instruments = stream.get_instrument_names()
    for i in range(instruments.size()):
        if instruments[i] != "":
            print("  %2d: %s" % [i, instruments[i]])

    # Module message
    var message = stream.get_message()
    if message != "":
        print("\nMESSAGE:")
        print(message)

Interactive Music Player

A player with tempo and pitch control:

extends Control

@onready var player = $AudioStreamPlayer
@onready var tempo_slider = $TempoSlider
@onready var pitch_slider = $PitchSlider
@onready var position_label = $PositionLabel

func _ready():
    var stream = AudioStreamOpenMPT.new()
    stream.load_from_file("res://music/song.mod")
    player.stream = stream
    player.play()

    # Setup sliders
    tempo_slider.min_value = 0.5
    tempo_slider.max_value = 2.0
    tempo_slider.value = 1.0
    tempo_slider.value_changed.connect(_on_tempo_changed)

    pitch_slider.min_value = 0.5
    pitch_slider.max_value = 2.0
    pitch_slider.value = 1.0
    pitch_slider.value_changed.connect(_on_pitch_changed)

func _process(_delta):
    # Update position display
    var playback = player.get_stream_playback() as AudioStreamPlaybackOpenMPT
    if playback:
        var pos = playback.get_position()
        var order = playback.get_current_order()
        var pattern = playback.get_current_pattern()
        var row = playback.get_current_row()

        position_label.text = "Time: %.2fs | Order: %d | Pattern: %d | Row: %d" % [
            pos, order, pattern, row
        ]

func _on_tempo_changed(value: float):
    var playback = player.get_stream_playback() as AudioStreamPlaybackOpenMPT
    if playback:
        playback.set_tempo_factor(value)

func _on_pitch_changed(value: float):
    var playback = player.get_stream_playback() as AudioStreamPlaybackOpenMPT
    if playback:
        playback.set_pitch_factor(value)

Pattern-based Music System

Use pattern navigation for dynamic music:

extends Node

var player: AudioStreamPlayer
var playback: AudioStreamPlaybackOpenMPT

# Music intensity levels mapped to orders
const MUSIC_CALM = 0
const MUSIC_MEDIUM = 4
const MUSIC_INTENSE = 8

func _ready():
    player = AudioStreamPlayer.new()
    add_child(player)

    var stream = AudioStreamOpenMPT.new()
    stream.load_from_file("res://music/dynamic_soundtrack.mod")
    player.stream = stream

    playback = player.get_stream_playback() as AudioStreamPlaybackOpenMPT
    playback.set_repeat_count(-1)  # Loop forever

    player.play()
    set_music_intensity(MUSIC_CALM)

func set_music_intensity(order: int):
    """Change music intensity by jumping to different order"""
    if playback:
        playback.set_position_order_row(order, 0)
        print("Music intensity changed to order ", order)

# Example: Change intensity based on game state
func _on_enemy_spawned():
    set_music_intensity(MUSIC_MEDIUM)

func _on_boss_fight_started():
    set_music_intensity(MUSIC_INTENSE)

func _on_battle_ended():
    set_music_intensity(MUSIC_CALM)

Module Browser

Browse and play modules from a directory:

extends Control

@onready var file_list = $FileList
@onready var player = $AudioStreamPlayer
@onready var info_label = $InfoLabel

var modules_dir = "res://music/"
var current_stream: AudioStreamOpenMPT

func _ready():
    load_module_list()

func load_module_list():
    var dir = DirAccess.open(modules_dir)
    if dir:
        dir.list_dir_begin()
        var file_name = dir.get_next()

        while file_name != "":
            if not dir.current_is_dir():
                if is_tracker_file(file_name):
                    file_list.add_item(file_name)
            file_name = dir.get_next()

        dir.list_dir_end()

func is_tracker_file(filename: String) -> bool:
    var ext = filename.get_extension().to_lower()
    return ext in ["mod", "xm", "s3m", "it", "mptm"]

func _on_file_list_item_selected(index: int):
    var filename = file_list.get_item_text(index)
    load_and_play_module(modules_dir + filename)

func load_and_play_module(path: String):
    current_stream = AudioStreamOpenMPT.new()

    if current_stream.load_from_file(path) == OK:
        player.stream = current_stream
        player.play()

        # Update info display
        info_label.text = """
        Title: %s
        Artist: %s
        Duration: %.2f seconds
        Channels: %d
        Instruments: %d
        """ % [
            current_stream.get_title(),
            current_stream.get_artist(),
            current_stream.get_length(),
            current_stream.get_num_channels(),
            current_stream.get_num_instruments()
        ]
    else:
        info_label.text = "Failed to load: " + path

Random Module Player

Randomly select and play modules with crossfade:

extends Node

var player1: AudioStreamPlayer
var player2: AudioStreamPlayer
var current_player: AudioStreamPlayer
var next_player: AudioStreamPlayer

var module_paths: Array[String] = [
    "res://music/song1.mod",
    "res://music/song2.xm",
    "res://music/song3.s3m",
]

func _ready():
    # Setup two players for crossfading
    player1 = AudioStreamPlayer.new()
    player2 = AudioStreamPlayer.new()
    add_child(player1)
    add_child(player2)

    current_player = player1
    next_player = player2

    play_random_module()

func play_random_module():
    var path = module_paths[randi() % module_paths.size()]

    var stream = AudioStreamOpenMPT.new()
    if stream.load_from_file(path) == OK:
        current_player.stream = stream
        current_player.play()

        print("Now playing: ", stream.get_title())

        # Schedule next song
        var duration = stream.get_length()
        get_tree().create_timer(duration - 2.0).timeout.connect(_on_song_ending)

func _on_song_ending():
    # Start crossfade to next song
    start_crossfade()

func start_crossfade():
    # Load next song into next_player
    var path = module_paths[randi() % module_paths.size()]
    var stream = AudioStreamOpenMPT.new()

    if stream.load_from_file(path) == OK:
        next_player.stream = stream
        next_player.volume_db = -80
        next_player.play()

        # Crossfade
        var tween = create_tween()
        tween.set_parallel(true)
        tween.tween_property(current_player, "volume_db", -80, 2.0)
        tween.tween_property(next_player, "volume_db", 0, 2.0)
        tween.finished.connect(_on_crossfade_complete)

func _on_crossfade_complete():
    current_player.stop()
    # Swap players
    var temp = current_player
    current_player = next_player
    next_player = temp

    # Schedule next transition
    var stream = current_player.stream as AudioStreamOpenMPT
    var duration = stream.get_length()
    get_tree().create_timer(duration - 2.0).timeout.connect(_on_song_ending)