0 votes

Hello! I wanna know if there's a way to check if an specific sound in a sample library is currently playing through the SamplePlayer, like checking by name.

In my project (a musical instrument game), my goal is to play a note if it's not already playing, and checking if a voice is active (SamplePlayer.isvoiceactive) is not a solution, since the index can change because of the polyphonic nature of the instrument.

The instrument have samples named according to its midi number (A1 = 045, E7 = 112, etc), just for you to know what will be inside the notes_playing array.

Here's my current code:

extends Node

var notes_playing = [] 

func _ready():
    set_process(true)

func _process(delta):

    var sample_player = self.get_node("sample_player")

    # If there's notes playing
    if notes_playing != []:

        # Process all notes to play
        for note in notes_playing:

            var current_note = str(note)

            # Avoid issues with two digit sample names (ex: 53 must be 053)
            if int(current_note) < 100:
                current_note = str("0" + current_note)

            # Play note
            if "current_note IN sample_player IS NOT PLAYING":
                sample_player.play(current_note)

    # If there's not notes playing
    if notes_playing == [] and sample_player.is_active()::
        sample_player.stop_all()
in Engine by (21 points)
retagged by

How do you fill the notes_playing array? Is it a list of all notes that should be playing at a given point in time? is_voice_active is what you need, but you have to use it a bit differently.

I think this should help:

# List of notes that should be playing (from your code)
var notes_playing = []

# Get the sample player once and for all
onready var _sample_player = get_node("sample_player")
# Dictionary of active voices, indexed by the note MIDI number
var _active_notes = {}


func _process(delta):
    # The reason why I made two steps is because voices could
    # get re-used in the second step.
    process_notes_to_stop()
    process_notes_to_start()


func process_notes_to_stop():
    # Before playing anything, find which voices are still active
    var ended_notes = []
    for note_id in _active_notes:
        var voice = _active_notes[note_id]
        # If the voice is inactive
        if _sample_player.is_voice_active(voice) == false:
            # We'll remove it from the active notes
            ended_notes.push_back(note_id)
        else:
            # The voice is active, but if it should not be playing, stop it
            if notes_playing.find(note_id) == -1:
                _sample_player.stop(voice)

    # Remove ended notes from the active notes
    for i in ended_notes:
        _active_notes.erase(i)


func process_notes_to_start():
    # For each note that should be playing
    for note_id in notes_playing:
        # If the note is not already playing
        if _active_notes.has(note_id) == false:
            # Play it
            # Note: you only need the name here, otherwise numbers are more lightweight
            var note_name = get_note_name(note_id)
            # play() returns the voice ID, store it in active notes
            _active_notes[note_id] = _sample_player.play(note_name)


# Helper to convert a MIDI integer note to its name
static func get_note_name(note_id):
    var name = str(note_id)
    if note_id < 10:
        return "00" + name
    if note_id < 100:
        return "0" + name
    return name

Please log in or register to answer this question.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.