Open mindinsomnia opened 3 years ago
I'm not sure if this is worth the additional work. For instance, there are already two ways to edit the gravity of a RigidBody – using the "mass" and "weight" properties. The fact that you can see both properties at the same time introduces more confusion than anything else. This would have to be revised first before we can consider adding support for more properties that can be edited in different ways.
Technically, it could be done by adding a property hint that indicates that a property is to be specified using decibels. Then we can add an editor setting that forces all decibels to be specified using a linear scale instead. (I don't think this should be specified in the node itself, as this is clearly an user preference.)
This way of working would be less confusing, but it'd also require adding a property hint for every property that may be specified in multiple ways – be it mass/weight, FOV in degrees/millimeters, volume in decibels/linear scale…
Also, if we consider this to be a documentation issue, we can amend the class reference to quickly explain how decibel volumes work.
As someone who's actually familiar with audio programming, and intimately familiar with sound design and music production, not being able to read or modify raw amplitude directly is basically unthinkable. Decibels are not how perceived volume works, they're part of how mixing works, and being forced to go through decibels when doing things like hand-writing background music crossfading is just plain wrong.
For the hand-written background music crossfading example, the two tracks have to meet at -9db, -6db, or -3db, depending on what approach you're doing. In terms of raw amplitude, crossfading like this is a simple linear transition with an exponent thrown on top. And having to write extra code to convert from amplitude to decibels on top of that is bizarre. And don't say "just do the fade in decibels", that would either be straight up wrong or involve a weird mapping curve that approximates doing it in linear amplitude in the first place. Incidentally, the -6db version of this is what you want to do if you're doing that dynamic music mixing thing where you have multiple different copies of the same track with different instrumentation and blend between them based on what's happening in the gameplay. That's an easy example why being able to do this correctly on the game logic side of things (not the engine side, where it would be technical debt) is actually meaningfully useful, not just theoretically useful, and you shouldn't have to go through decibels to do it.
There's a similar problem if you somehow manage to get control of left and right channel volumes independently, and program audio emitter panning and distance attenuation from scratch instead of using the engine's spatialization features (which you very well might want to do if you're doing something like making a competitive FPS where exactly how panning and distance attenuation work are a core part of game balance). There are several different "panning laws" (different functions for converting panning values into per-channel volume), but in code they're all best represented with amplitude curves, not decibel curves, because decibels are for audio mixing and audio analysis, not audio programming. There are likewise also multiple different approaches to distance attenuation, which is less interesting for 3d games (where you're obligated to use inverse square falloff) but very interesting for 2d games (where you can do pretty much anything, and any approach you could think of is valid). I used to work on a competitive 2d shooter called Gang Garrison 2 where the specific distance attenuation curve that offscreen sounds had was integral to how the game's balance worked, and if I hypothetically wanted to remake that game in godot, replicating that attenuation curve would be a valid thing to worry about.
There are a lot of things of this nature that are just far easier and more correct to do in amplitude than decibels. I don't need to be told how decibels work. I already know how they work, what they're for, and where and why they're used. They're just not a drop-in replacement for raw amplitude, you need to get your hands dirty with raw amplitude eventually if you do anything sufficiently interesting with volume values. And doing all of that on top of code that maps to decibels just to map back to amplitude later inside the engine is bizarre.
Honestly, I'd just scrap the decibels and use direct linear volume adjustment if we want to have just 1. I'm always using linear2db() to set values, which the engine then converts back to linear to do the math anyway, so it seems like 2 unnecessary steps when almost no devs think in db anyway.
Also, the decibels aren't even quite correct -- I think k the engine is set up so -40db is 0 in linear, when it should be -infinity, so somebody could try to set something to, like, -50db to get 0.00001 and actually be getting 0 (unlikely, but you never know). I feel like, for the vast majority of people, using linear values (ex: I want to fade in something, so I go from 0 to 1) is far more straightforward than using decibels. I'm not even sure how you'd do that in db directly. I always use linear2db, but it took a while for me to find that function initially since it's a global function, not like a setter function on the audio objects themselves.
Also, there is some inconsistency in naming -- some things use unit_db and others use volume_db. I wouldn't change this for 3.x, but it might be worth switching to linear values for 4.x.
Now that https://github.com/godotengine/godot/pull/50009 has been merged, it should be possible to implement this as an editor helper.
Now that godotengine/godot#50009 has been merged, it should be possible to implement this as an editor helper.
Aand that didn't age well, in the end rotation_degrees
needed to be reintroduced altough I think the case was weaker than this (I mean, radians and degrees are at least linearly related).
I think volume_linear
should be exposed as a property, just to be able use it with animations and tweens. I have exactly zero projects which has audio and doesn't have the following script or similiar just for this reason:
@tool
extends AudioStreamPlayer
@export_range(0, 2) var volume_linear : float = 1.0:
set(value):
volume_db = linear_to_db(value)
get:
return db_to_linear(volume_db)
I mean, it works and it isn't much code, but just the fact that it's required for working with audio through built-in tools is a bit baffling. Or is there some other possibility for fading sound with animationplayer or tween through volume_db
? Some specific easing values?
How about making it default to a linear scale (so it works nicely in animations and tweens), and then have a tickbox in the inspector to change it to decibal scale for the audio professionals to use?
How about making it default to a linear scale (so it works nicely in animations and tweens)
We can't change the default behavior to avoid breaking compatibility with existing projects. All we can do is implement @aXu-AP's suggestion, which adds a new property while preserving the existing one's behavior. The decibel-based property can then be hidden from the inspector as the linear one would replace it (they represent the same underlying value).
Save the change for Godot 5 so it doesn't affect 4 projects.
We should never shy away from a user useful change for fear of breaking projects. Better to make the change sooner rather than later when even more historic projects will exist. It only gets worse until it's fixed.
You know Godot 5 is years away at this point?
We could add an editor setting to switch between dB
and Linear %
plus an inspector plugin that would replace the field if Linear %
is selected.
Another good argument for including a volume_linear
property is the improved ease of tweening. Smoothly fading music in and out is a common task, but AFAIK the current code to do such a thing is rather unwieldy:
# Fade volume from its current value to 0.0 over 1 second
var tween = create_tween()
tween.tween_method(func(v): _music_player.volume_db = linear_to_db(v), db_to_linear(_music_player.volume_db), 0.0, 1.0)
If a volume_linear
property was provided, it would be much simpler and readable:
# Fade volume from its current value to 0.0 over 1 second
var tween = create_tween()
tween.tween_property(_music_player, "volume_linear", 0.0, 1.0)
A smooth volume fade has an exponent term in it somewhere (something like v^1.5
or v^2
), but yes, even a linear volume fade is way more correct than fading in terms of decibels!
It'll probably be a little while before I actually give this a go, but I was thinking of doing a PR for this, and wanted to explain my plan in case anyone had thoughts on things I should do differently.
As of right now, my plan is to implement a volume_linear
property pretty much exactly as aXu-AP described here, and how I implemented volume fading via tweens in my own comment:
volume_linear
simply returns db_to_linear(volume_db)
.volume_linear
simply sets volume_db = linear_to_db(value)
.This will provide a more intuitive interface for people not as familiar with decibels, fulfilling most of their use cases. Tweening volumes will also be much more intuitive.
I'm not very familiar with the math of converting decibels to other scales, so I think it's best that I leave the db_to_linear
and linear_to_db
methods alone. If there are issues with them, someone more knowledgeable about those conversions can handle them. Then, their improvements will take effect both where those methods are manually used, as well as in the performance of the volume_linear
property.
Hmm, I swear internally it stored the values as linear (maybe that was Godot 3, or maybe my memory is terrible). I kind of feel like if it's going to be done, it would make more sense to use a linear value internally so calculations like these aren't being done while mixing:
multiplier *= Math::db_to_linear(internal->volume_db);
AFAIK, all the math needs linear values, so it would make more sense to just use those natively, then change the volume_db to set volume_linear = db_to_linear(volume_db);
Describe the project you are working on: It's not really relevant to this general usability improvement suggestion.
Describe the problem or limitation you are having in your project: It's a usability suggestion so it's not a limitation or a problem, it's just something that will make using Godot more comfortable and enjoyable for users.
Describe the feature / enhancement and how it helps to overcome the problem or limitation: An option to choose between two different units for volume sliders in Godot. Db (as in Decibels) or Linear Scale, which is a sliding value between 0% and 100%.
I have read the Godot manual and I understand it's point of view expressed that it is a good idea in the long term to learn how to work with Decibels for professional audio work. However in my opinion it would be a usability improvement to offer the user the ability to choose between using Decibels and Linear Scale for the following reasons:
As the manual acknowledges, this is something most users are not going to be familiar with. A Godot user's first experience should be as intuitive as possible, and linear scale is the most intuitive volume control for most people.
In many instances, particularly for first time users of Godot, or indie game developers, or users who are new to game development in general, the benefits of working in Decibels may not apply at all. One of the mentioned benefits of working with Decibels in the manual is "will allow you to communicate better with audio professionals", but for a indie game developer learning Godot for the first time, they would be lucky to even know an audio professional. More than likely, most beginners will be adding simple sound effects to actions in their game, clicks to menu actions, or a 'tada!' success sound effect to winning a level, and a simple volume slider would be more than enough for that task.
Plenty of software offers a choice between units that represent the same thing in different ways. Design software offers the choice between working in pixel measurements or millimeters/inches/etc. In Blender camera field of view can be specified in either angles (something game developers would be more accustomed to) or millimeters (something photographers would be more accustomed to).
Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams: I propose that internally, Godot always uses Decibels, but optionally can present either a Decibel slider, or Linear Scale slider.
The result is a simple cosmetic change on how the option actually looks in the UI:
Before:
After:
Internally, when in Linear Scale mode, the slider's value is converted to Decibels and stored in the Decibel property. Hence when the user switches between units, the conversion is automatic.
I think in addition to the UI option, this should be replicated in the API for AudioStreamPlayer.
Right now already AudioStreamPlayer has a 'volume_db' property, all that would need to be added is a 'volume_linear' property or perhaps even just 'volume', and internally when it's set the value could be automatically converted into decibel scale and stored in volume_db.
If this enhancement will not be used often, can it be worked around with a few lines of script?: N/A
Is there a reason why this should be core and not an add-on in the asset library?: N/A