Skip to content

Commit b99e311

Browse files
logarithmic volume control for global soundtray / volume (#3248)
* logarithmic volume control for global soundtray / volume * use logarithmic sound volume at the transform * clamp volume again * small fixes * add dynamic FlxG.applySoundCurve * fix coverage --------- Co-authored-by: GeoKureli-BlackbookPro <[email protected]>
1 parent 0d72dc2 commit b99e311

File tree

3 files changed

+73
-4
lines changed

3 files changed

+73
-4
lines changed

flixel/sound/FlxSound.hx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -594,13 +594,26 @@ class FlxSound extends FlxBasic
594594
@:allow(flixel.sound.FlxSoundGroup)
595595
function updateTransform():Void
596596
{
597-
_transform.volume = #if FLX_SOUND_SYSTEM (FlxG.sound.muted ? 0 : 1) * FlxG.sound.volume * #end
598-
(group != null ? group.volume : 1) * _volume * _volumeAdjust;
599-
597+
_transform.volume = calcTransformVolume();
598+
600599
if (_channel != null)
601600
_channel.soundTransform = _transform;
602601
}
603602

603+
function calcTransformVolume():Float
604+
{
605+
final volume = (group != null ? group.volume : 1.0) * _volume * _volumeAdjust;
606+
607+
#if FLX_SOUND_SYSTEM
608+
if (FlxG.sound.muted)
609+
return 0.0;
610+
611+
return FlxG.sound.applySoundCurve(FlxG.sound.volume * volume);
612+
#else
613+
return volume;
614+
#end
615+
}
616+
604617
/**
605618
* An internal helper function used to attempt to start playing
606619
* the sound and populate the _channel variable.

flixel/system/frontEnds/SoundFrontEnd.hx

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,35 @@ class SoundFrontEnd
379379
}
380380
#end
381381
}
382-
382+
383+
/**
384+
* Takes the volume scale used by Flixel fields and gives the final transformed volume that is
385+
* actually used to play the sound. To reverse this operation, use `reverseSoundCurve`. This
386+
* field is `dynamic` and can be overwritten.
387+
*/
388+
public dynamic function applySoundCurve(volume:Float)
389+
{
390+
return volume;
391+
392+
// Example of linear to logarithmic sound curve:
393+
// final clampedVolume = Math.max(0, Math.min(1, volume));
394+
// return Math.exp(Math.log(0.001) * (1 - clampedVolume));
395+
}
396+
397+
/**
398+
* Takes a transformed volume and returns the corresponding volume scale used by Flixel fields.
399+
* Used to reverse the operation of `applySoundCurve`. This field is `dynamic` and can be
400+
* set to a custom function.
401+
*/
402+
public dynamic function reverseSoundCurve(curvedVolume:Float)
403+
{
404+
return curvedVolume;
405+
406+
// Example of logarithmic to linear sound curve:
407+
// final clampedVolume = Math.max(minValue, Math.min(1, x));
408+
// return 1 - (Math.log(clampedVolume) / Math.log(0.001));
409+
}
410+
383411
function new()
384412
{
385413
#if FLX_SAVE

tests/unit/src/flixel/system/frontEnds/SoundFrontEndTest.hx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package flixel.system.frontEnds;
22

33
import flixel.FlxG;
4+
import massive.munit.Assert;
45

56
class SoundFrontEndTest
67
{
@@ -22,5 +23,32 @@ class SoundFrontEndTest
2223
{
2324
FlxG.sound.load("assets/invalid").play();
2425
}
26+
27+
@Test // #1511
28+
function testSoundCurve()
29+
{
30+
Assert.areEqual(1.0, FlxG.sound.applySoundCurve(1));
31+
Assert.areEqual(1.0, FlxG.sound.reverseSoundCurve(1));
32+
33+
FlxG.sound.applySoundCurve = function (volume)
34+
{
35+
final clampedVolume = Math.max(0, Math.min(1, volume));
36+
return Math.exp(Math.log(0.001) * (1 - volume));
37+
};
38+
39+
FlxG.sound.reverseSoundCurve = function (volume)
40+
{
41+
final clampedVolume = Math.max(0.001, Math.min(1, volume));
42+
return 1 - (Math.log(clampedVolume) / Math.log(0.001));
43+
};
44+
45+
FlxAssert.areNear(1.0, FlxG.sound.applySoundCurve(1));
46+
FlxAssert.areNear(1.0, FlxG.sound.reverseSoundCurve(1));
47+
FlxAssert.areNear(0.001, FlxG.sound.applySoundCurve(0));
48+
FlxAssert.areNear(0.0, FlxG.sound.reverseSoundCurve(0));
49+
FlxAssert.areNear(0.031, FlxG.sound.applySoundCurve(0.5));
50+
FlxAssert.areNear(0.899, FlxG.sound.reverseSoundCurve(0.5));
51+
FlxAssert.areNear(0.5, FlxG.sound.reverseSoundCurve(FlxG.sound.applySoundCurve(0.5)));
52+
}
2553
#end
2654
}

0 commit comments

Comments
 (0)