Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

All sounds should have built-in fade on play, seek and queue_free to avoid zero crossing pops/clicks #5697

Closed
elvisish opened this issue Nov 1, 2022 · 7 comments

Comments

@elvisish
Copy link

elvisish commented Nov 1, 2022

Describe the project you are working on

Shooter game.

Describe the problem or limitation you are having in your project

Whenever a sound is stopped playing, changed to a new sound or the object is destroyed (stopping the sound) there will be a loud pop if the sound stops on a zero crossing.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

A built-in fade to avoid this happening would significantly improve how sounds are heard by the player and make it much easier for the user to play sounds without having to setup multiple AudioPlayers, toggle between them or setup tweens for fading the volume.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

In the audio playing backend, a short 0.1ms fade before any audio object is changed or stopped would almost entirely solve zero crossings pops.

If this enhancement will not be used often, can it be worked around with a few lines of script?

It would need to be pretty low level so the user didn’t need to be concerned with it.

Is there a reason why this should be core and not an add-on in the asset library?

It would need to be low level to happen between calls.

@TheDuriel
Copy link

This sounds like a workaround to a known bug. So, I vote for fixing the pop.

@dalexeev
Copy link
Member

dalexeev commented Nov 1, 2022

4.0 introduced the AudioStreamPlayer.max_polyphony property. For short sounds you can use the following manager:

extends Node
## SFX singleton.

const _MAX_POLYPHONY_MAP = {
    #'sound.wav': 4,
}

var _players := {}

func play(path: String) -> void:
    var player: AudioStreamPlayer = _players.get(path)
    if !player:
        player = AudioStreamPlayer.new()
        player.bus = &'SFX'
        player.stream = load('res://sfx/' + path)
        player.max_polyphony = _MAX_POLYPHONY_MAP.get(path, 1)
        add_child(player)
        _players[path] = player
    player.play()

This way, the sound will not be clipped when a node is removed, when a scene is changed, or when max_polyphony sounds of the same type overlap each other.

@elvisish
Copy link
Author

elvisish commented Nov 1, 2022

This sounds like a workaround to a known bug. So, I vote for fixing the pop.

What is the bug? I thought it had been attempted to be fixed?

4.0 introduced the AudioStreamPlayer.max_polyphony property. For short sounds you can use the following manager:

extends Node

## SFX singleton.



const _MAX_POLYPHONY_MAP = {

    #'sound.wav': 4,

}



var _players := {}



func play(path: String) -> void:

    var player: AudioStreamPlayer = _players.get(path)

    if !player:

        player = AudioStreamPlayer.new()

        player.bus = &'SFX'

        player.stream = load('res://sfx/' + path)

        player.max_polyphony = _MAX_POLYPHONY_MAP.get(path, 1)

        add_child(player)

        _players[path] = player

    player.play()

This way, the sound will not be clipped when a node is removed, when a scene is changed, or when max_polyphony sounds of the same type overlap each other.

Is there no solution for 3.x?

@dalexeev
Copy link
Member

dalexeev commented Nov 1, 2022

Is there no solution for 3.x?

extends Node
# SFX singleton.

const _POOL_SIZE = 16

var _current := 0

func _ready() -> void:
    for _i in _POOL_SIZE:
        var player := AudioStreamPlayer.new()
        player.bus = 'SFX'
        add_child(player)

func play(path: String) -> void:
    var player: AudioStreamPlayer = get_child(_current)
    player.stream = load('res://sfx/' + path)
    player.play()
    _current = (_current + 1) % _POOL_SIZE

@Mickeon
Copy link

Mickeon commented Nov 1, 2022

I feel like the issue attempted to be solved with the Proposal is no longer an issue in Godot 4.

@Calinou
Copy link
Member

Calinou commented Nov 1, 2022

Duplicate of godotengine/godot#22016 (this is a bug).

@Calinou Calinou closed this as not planned Won't fix, can't repro, duplicate, stale Nov 1, 2022
@elvisish
Copy link
Author

elvisish commented Nov 1, 2022

Duplicate of godotengine/godot#22016 (this is a bug).

I think this is different as there are pops and clicks is the sample is stopped, as far as I’m aware 4.0 does not take into account stopping the sample on zero crossings by applying a tiny fade out?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants