@@ -14,6 +14,10 @@ import funkin.util.tools.ICloneable;
1414import funkin .util .flixel .sound .FlxPartialSound ;
1515import funkin .Paths .PathsFunction ;
1616import lime .app .Promise ;
17+ import lime .media .AudioSource ;
18+ import openfl .events .Event ;
19+ import openfl .media .Sound ;
20+ import openfl .media .SoundChannel ;
1721import openfl .media .SoundMixer ;
1822
1923#if (openfl >= "8.0.0")
@@ -108,6 +112,11 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
108112 return _waveformData ;
109113 }
110114
115+ /**
116+ * If true, the game will forcefully add this sound's channel to the list of playing sounds.
117+ */
118+ public var important : Bool = false ;
119+
111120 /**
112121 * Are we in a state where the song should play but time is negative?
113122 */
@@ -145,6 +154,14 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
145154 else
146155 {
147156 super .update (elapsedSec );
157+
158+ @:privateAccess
159+ {
160+ if (important && _channel != null && ! SoundMixer .__soundChannels .contains (_channel ))
161+ {
162+ SoundMixer .__soundChannels .push (_channel );
163+ }
164+ }
148165 }
149166 }
150167
@@ -431,13 +448,14 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
431448 * @param persist Whether to keep this `FunkinSound` between states, or destroy it.
432449 * @param onComplete Called when the sound finished playing.
433450 * @param onLoad Called when the sound finished loading. Called immediately for succesfully loaded embedded sounds.
451+ * @param important If `true`, the sound channel will forcefully be added onto the channel array, even if full. Use sparingly!
434452 * @return A `FunkinSound` object, or `null` if the sound could not be loaded.
435453 */
436454 public static function load (embeddedSound : FlxSoundAsset , volume : Float = 1.0 , looped : Bool = false , autoDestroy : Bool = false , autoPlay : Bool = false ,
437- persist : Bool = false , ? onComplete : Void -> Void , ? onLoad : Void -> Void ): Null <FunkinSound >
455+ persist : Bool = false , ? onComplete : Void -> Void , ? onLoad : Void -> Void , important : Bool = false ): Null <FunkinSound >
438456 {
439457 @:privateAccess
440- if (SoundMixer .__soundChannels .length >= SoundMixer .MAX_ACTIVE_CHANNELS )
458+ if (SoundMixer .__soundChannels .length >= SoundMixer .MAX_ACTIVE_CHANNELS && ! important )
441459 {
442460 FlxG .log .error (' FunkinSound could not play sound, channels exhausted! Found ${SoundMixer .__soundChannels .length } active sound channels.' );
443461 return null ;
@@ -462,6 +480,7 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
462480 sound .volume = volume ;
463481 sound .group = FlxG .sound .defaultSoundGroup ;
464482 sound .persist = persist ;
483+ sound .important = important ;
465484
466485 // Make sure to add the sound to the list.
467486 // If it's already in, it won't get re-added.
@@ -534,15 +553,50 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
534553 this ._label = ' unknown' ;
535554 }
536555
556+ @:access (openfl.media. Sound )
557+ @:access (openfl.media. SoundChannel )
558+ @:access (openfl.media. SoundMixer )
559+ override function startSound (startTime : Float )
560+ {
561+ if (! important )
562+ {
563+ super .startSound (startTime );
564+ return ;
565+ }
566+
567+ _time = startTime ;
568+ _paused = false ;
569+
570+ if (_sound == null ) return ;
571+
572+ // Create a channel manually if the sound is considered important.
573+ var pan : Float = FlxMath .bound (SoundMixer .__soundTransform .pan + _transform .pan , - 1 , 1 );
574+ var volume : Float = FlxMath .bound (SoundMixer .__soundTransform .volume * _transform .volume , 0 , MAX_VOLUME );
575+
576+ var audioSource : AudioSource = new AudioSource (_sound .__buffer );
577+ audioSource .offset = Std .int (startTime );
578+ audioSource .gain = volume ;
579+
580+ var position : lime.math. Vector4 = audioSource .position ;
581+ position .x = pan ;
582+ position .z = - 1 * Math .sqrt (1 - Math .pow (pan , 2 ));
583+ audioSource .position = position ;
584+
585+ _channel = new SoundChannel (_sound , audioSource , _transform );
586+ _channel .addEventListener (Event .SOUND_COMPLETE , stopped );
587+ pitch = _pitch ;
588+ active = true ;
589+ }
590+
537591 /**
538592 * Play a sound effect once, then destroy it.
539593 * @param key
540594 * @param volume
541595 * @return A `FunkinSound` object, or `null` if the sound could not be loaded.
542596 */
543- public static function playOnce (key : String , volume : Float = 1.0 , ? onComplete : Void -> Void , ? onLoad : Void -> Void ): Null <FunkinSound >
597+ public static function playOnce (key : String , volume : Float = 1.0 , ? onComplete : Void -> Void , ? onLoad : Void -> Void , important : Bool = false ): Null <FunkinSound >
544598 {
545- var result : Null <FunkinSound > = FunkinSound .load (key , volume , false , true , true , false , onComplete , onLoad );
599+ var result : Null <FunkinSound > = FunkinSound .load (key , volume , false , true , true , false , onComplete , onLoad , important );
546600 return result ;
547601 }
548602
0 commit comments