Attention | Topic was automatically imported from the old Question2Answer platform. | |
Asked By | Joel Gomes da Silva | |
Old Version | Published before Godot 3 was released. |
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.is_voice_active) 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()
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
Zylann | 2016-11-06 01:05