Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions flixel/sound/FlxSound.hx
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ class FlxSound extends FlxBasic
* Internal tracker for a Flash sound object.
*/
@:allow(flixel.system.frontEnds.SoundFrontEnd.load)
#if FLX_STREAM_SOUND
@:allow(flixel.system.frontEnds.SoundFrontEnd.loadStreamed)
#end
var _sound:Sound;

/**
Expand Down Expand Up @@ -382,6 +385,51 @@ class FlxSound extends FlxBasic
return init(looped, autoDestroy, onComplete);
}

#if FLX_STREAM_SOUND
/**
* Streams a sound from the given file path. Unlike the `load` method, this will load and
* unload chunks of data as the sound plays, keeping memory usage low. This is recommended for
* longer sounds, like music tracks. For shorter sounds like sound effects, it is better to
* use the `load` method, which loads the entire sound into memory before playing it.
*
* Due to a backend limitation, audio streaming is currently only available on native targets
* and OGG/Vorbis audio files.
*
* This does not load sounds from web locations. Use `loadFromURL()` for that, instead.
*
* **Note:** If the `FLX_DEFAULT_SOUND_EXT` flag is enabled, you may omit the file extension
*
* @param path The ID or asset path to the sound asset.
* @param looped Whether or not this sound should loop endlessly.
* @param autoDestroy Whether or not this FlxSound instance should be destroyed when the sound finishes playing.
* @param onComplete Called when the sound finishes playing.
* @return This FlxSound instance (nice for chaining stuff together, if you're into that).
*
* @since 6.2.0
*/
public function loadStreamed(path:String, looped:Bool = false, autoDestroy:Bool = false, ?onComplete:Void->Void):FlxSound
{
cleanup(true);

if (FlxG.assets.exists(path, SOUND))
{
if (FlxG.assets.canStreamSound(path))
{
_sound = FlxG.assets.streamSoundUnsafe(path);

// NOTE: can't pull ID3 info from embedded sound currently
return init(looped, autoDestroy, onComplete);
}

FlxG.log.error('Unable to stream SOUND asset with ID "$path". Expected a .OGG/Vorbis file');
}
else
FlxG.log.error('Could not find a Sound asset with an ID of \'$path\'.');

return this;
}
#end

/**
* Loads a sound from the provided URL.
*
Expand Down
109 changes: 109 additions & 0 deletions flixel/system/frontEnds/AssetFrontEnd.hx
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,116 @@ class AssetFrontEnd

return id;
}

/**
* Gets an instance of a streamed sound. Unlike its "safe" counterpart, there is no log on missing assets.
* Can be set to a custom function to avoid the existing asset system.
*
* Streamed sounds load and unload chunks of audio data during playback, keeping memory usage low.
* The usage of streamed sounds is only recommended for larger audio tracks, such as music.
*
* **Note**: Due to a backend limitation, streamed sounds currently only work on native targets and OGG/Vorbis files.
* Trying to stream an unsupported file format will fall back to regular sound loading behavior.
*
* @param id The ID or asset path for the sound
* @return A new `Sound` object Note: Does not return a `FlxSound`
* @since 6.2.0
*/
public dynamic function streamSoundUnsafe(id:String):Sound
{
return Assets.getMusic(addSoundExtIf(id));
}

/**
* Gets an instance of a streamed sound, logs when the asset is not found.
*
* Streamed sounds load and unload chunks of audio data during playback, keeping memory usage low.
* The usage of streamed sounds is only recommended for larger audio tracks, such as music.
*
* **Note**: Due to a backend limitation, streamed sounds currently only work on native targets and OGG/Vorbis files.
* Trying to stream an unsupported file format will fall back to regular sound loading behavior.
*
* **Note:** If the `FLX_DEFAULT_SOUND_EXT` flag is enabled, you may omit the file extension
*
* @param id The ID or asset path for the sound
* @param useCache Whether to allow use of the asset cache (if one exists)
* @param logStyle How to log, if the asset is not found. Uses `LogStyle.ERROR` by default
* @return A new `Sound` object Note: Does not return a `FlxSound`
* @since 6.2.0
*/
public function streamSound(id:String, ?logStyle:LogStyle):Sound
{
if (logStyle == null)
logStyle = FlxG.log.styles.error;

final log = FlxG.log.advanced.bind(_, logStyle);

if (exists(id, SOUND))
{
if (!canStreamSound(id))
{
log('Unable to stream SOUND asset with ID "$id". Expected a .OGG/Vorbis file');
return null;
}

if (isLocal(id, SOUND))
return streamSoundUnsafe(id);

log('SOUND asset "$id" exists, but only asynchronously');
return null;
}

log('Could not find a SOUND asset with ID \'$id\'.');
return null;
}

/**
* Gets an instance of a streamed sound, logs when the asset is not found.
*
* Streamed sounds load and unload chunks of audio data during playback, keeping memory usage low.
* The usage of streamed sounds is only recommended for larger audio tracks, such as music.
*
* **Note**: Due to a backend limitation, streamed sounds currently only work on native targets and OGG/Vorbis files.
* Trying to stream an unsupported file format will fall back to regular sound loading behavior.
*
* @param id The ID or asset path for the sound
* @param useCache Whether to allow use of the asset cache (if one exists)
* @param logStyle How to log, if the asset is not found. Uses `LogStyle.ERROR` by default
* @return A new `Sound` object Note: Does not return a `FlxSound`
* @since 6.2.0
*/
public function streamSoundAddExt(id:String, ?logStyle:LogStyle):Sound
{
return streamSound(addSoundExt(id));
}

/**
* Checks whether the sound asset with the specified ID can be streamed.
*
* **Note**: Due to a backend limitation, streamed sounds currently only work on native targets and OGG/Vorbis files.
*
* **Note:** If the `FLX_DEFAULT_SOUND_EXT` flag is enabled, you may omit the file extension
*
* @param file The ID or asset path for the asset
* @return Returns whether the sound can be streamed or not.
* @since 6.2.0
*/
public function canStreamSound(id:String):Bool
{
#if lime_vorbis
// Check if file is really OGG/Vorbis
final vorbis = lime.media.vorbis.VorbisFile.fromFile(Assets.getPath(addSoundExtIf(id)));
if (vorbis != null)
{
vorbis.clear();

return true;
}
#end

return false;
}

/**
* Gets the contents of a text-based asset. Unlike its "safe" counterpart, there is no log
* on missing assets
Expand Down
32 changes: 32 additions & 0 deletions flixel/system/frontEnds/SoundFrontEnd.hx
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,38 @@ class SoundFrontEnd
return sound;
}

#if FLX_STREAM_SOUND
/**
* Streams a sound from the given file path. Unlike the `load` method, this will load and
* unload chunks of data as the sound plays, keeping memory usage low. This is recommended for
* longer sounds, like music tracks. For shorter sounds like sound effects, it is better to
* use the `load` method, which loads the entire sound into memory before playing it.
*
* Due to a backend limitation, audio streaming is currently only available on native targets
* and OGG/Vorbis audio files.
*
* **Note:** If the `FLX_DEFAULT_SOUND_EXT` flag is enabled, you may omit the file extension
*
* @param id The ID or asset path to the sound asset.
* @param volume How loud to play it (0 to 1).
* @param looped Whether or not this sound should loop endlessly.
* @param group The group to add this sound to.
* @param autoDestroy Whether or not this FlxSound instance should be destroyed when the sound finishes playing.
* @param autoPlay Whether to play the sound.
* @param onComplete Called when the sound finishes playing.
* @return This FlxSound instance (nice for chaining stuff together, if you're into that).
*
* @since 6.2.0
*/
public function loadStreamed(id:String, volume = 1.0, looped = false, ?group:FlxSoundGroup, autoDestroy = false, autoPlay = false, ?onComplete:()->Void):FlxSound
{
final sound = list.recycle(FlxSound);
sound.loadStreamed(id, looped, autoDestroy, onComplete);
loadHelper(sound, volume, group, autoPlay);
return sound;
}
#end

function loadHelper(sound:FlxSound, volume:Float, group:FlxSoundGroup, autoPlay = false):FlxSound
{
if (group == null)
Expand Down
6 changes: 6 additions & 0 deletions flixel/system/macros/FlxDefines.hx
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ private enum HelperDefine
/** The normalized, absolute path of `FLX_CUSTOM_ASSETS_DIRECTORY`, used internally */
FLX_CUSTOM_ASSETS_DIRECTORY_ABS;
FLX_NO_DEFAULT_SOUND_EXT;
/** Enables audio streaming related APIs */
FLX_STREAM_SOUND;
}

class FlxDefines
Expand Down Expand Up @@ -326,6 +328,10 @@ class FlxDefines
}
else // define boolean inversion
define(FLX_STANDARD_ASSETS_DIRECTORY);

#if lime_vorbis
define(FLX_STREAM_SOUND);
#end

validateLogLevel(FLX_LOG_THROW);
validateLogLevel(FLX_LOG_PLAY_SOUND);
Expand Down