Wrapper - Audio; Cleaning up audio implementation, adding threading, and position/etc as well as accessors etc.

Wrapper - Examples; Adding a simple audio usage example. Audio is WIP in general.
This commit is contained in:
underscorediscovery
2013-12-10 00:38:32 -03:30
parent 9af557b566
commit cb14b151ef
9 changed files with 492 additions and 89 deletions

View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,13 @@
sound.ogg / sound.wav
http://www.freesound.org/people/FreqMan/sounds/42899/
The files are under the following license :
This work is licensed under the Attribution License.
See the above link for more details.
ambience.ogg
https://soundcloud.com/underscorediscovery/menuambience

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<project>
<meta
title="lime example - Simple Audio Example"
package="com.limeframework.audioexample"
version="1.0.0"
company="limeframework"
/>
<app main="Main" path="bin" file="lime_example_audio" />
<window
width="960"
height="640"
orientation="landscape"
background="0x161616"
depth-buffer="true"
fps="60"
vsync="true"
resizable="true"
/>
<assets path="Assets" rename="assets" include="*"/>
<source path="src" />
<haxelib name="lime" />
</project>

View File

@@ -0,0 +1,107 @@
//Ported and modified from OpenFL samples
//underscorediscovery
import lime.AudioHandler.Sound;
import lime.utils.Assets;
import lime.Lime;
//Import GL stuff from lime
import lime.gl.GL;
//Press any key to reset the music
//Click to play a sound
class Main {
public var lib : Lime;
//Some value to mess with the clear color
private var red_value : Float = 1.0;
private var red_direction : Int = 1;
private var dt : Float = 0.016;
private var end_dt : Float = 0;
public function new() { }
public function ready( _lime : Lime ) {
//Store a reference
lib = _lime;
// Init the shaders and view
init();
} //ready
public function init() {
lib.audio.create('music', 'assets/ambience.ogg', true );
lib.audio.create('sound', 'assets/sound.ogg', false);
lib.audio.create('sound_wav', 'assets/sound.wav', false);
lib.audio.get('music').play(5);
lib.audio.get('music').on_complete(function(sound:Sound){
trace("music complete!");
});
} //init
//Called each frame by lime for logic (called before render)
public function update() {
dt = haxe.Timer.stamp() - end_dt;
end_dt = haxe.Timer.stamp();
//an awful magic number to change the value slowly
red_value += (red_direction * 0.3) * dt;
if(red_value >= 1) {
red_value = 1;
red_direction = -red_direction;
} else if(red_value <= 0) {
red_value = 0;
red_direction = -red_direction;
}
} //update
//Called by lime
public function onmousemove(_event:Dynamic) {
}
//Called by lime
public function onmousedown(_event:Dynamic) {
lib.audio.get('sound').play(3,0);
}
//Called by lime
public function onmouseup(_event:Dynamic) {
}
//Called by lime
public function onkeydown(_event:Dynamic) {
lib.audio.get('music').position = 0.0;
}
//Called by lime
public function onkeyup(_event:Dynamic) {
}
//Called by lime
public function render() {
//Set the viewport for GL
GL.viewport( 0, 0, lib.config.width, lib.config.height );
//Set the clear color to a weird color that bounces around
GL.clearColor( red_value, red_value*0.5, red_value*0.3, 1);
//Clear the buffers
GL.clear( GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT );
} //render
} //Main

View File

@@ -3,7 +3,272 @@ package lime;
import lime.utils.Libs;
#if (!audio_thread_disabled && lime_native)
#if neko
import neko.vm.Thread;
import neko.vm.Mutex;
#else
import cpp.vm.Thread;
import cpp.vm.Mutex;
#end
#end //audio_thread_disabled
class AudioHandler {
public var lib : Lime;
public function new( _lib:Lime ) { lib = _lib; }
#if (!audio_thread_disabled && lime_native)
@:noCompletion public static var audio_state:AudioThreadState;
@:noCompletion public static var audio_message_check_complete = 1;
@:noCompletion public static var audio_thread_is_idle:Bool = true;
@:noCompletion public static var audio_thread_running:Bool = false;
#end
public var sounds : Map<String, Sound>;
public function startup() {
sounds = new Map();
#if (!audio_thread_disabled && lime_native)
audio_state = new AudioThreadState ();
audio_thread_running = true;
audio_thread_is_idle = false;
audio_state.main_thread = Thread.current ();
audio_state.audio_thread = Thread.create( audio_thread_handler );
#end //#(!audio_thread_disabled && lime_native)
} //startup
@:noCompletion public function update() {
for(sound in sounds) {
if(sound.ismusic) {
sound.check_complete();
}
}
}
public function create(_name:String, _file:String, ?_music:Bool = false ) {
if(sounds.exists(_name)) {
throw ">>> Named sounds are not allowed to have duplicate names";
}
#if lime_native
var _handle = lime_sound_from_file( lime.AssetData.path.get(_file), _music );
var _sound = new Sound(_name, _handle, _music);
sounds.set(_name, _sound);
#end //lime_native
}
public function get( _name:String ) : Sound {
return sounds.get(_name);
}
#if (!audio_thread_disabled && lime_native)
public function audio_thread_handler() {
while (audio_thread_running) {
var thread_message:Dynamic = Thread.readMessage (false);
if (thread_message == audio_message_check_complete) {
audio_state.check();
}
if (!audio_thread_is_idle) {
audio_state.update();
Sys.sleep (0.01);
} else {
Sys.sleep (0.2);
}
}
audio_thread_running = false;
audio_thread_is_idle = true;
}
#end //(!audio_thread_disabled && lime_native)
#if lime_native
private static var lime_sound_from_file = Libs.load("lime","lime_sound_from_file", 2);
private static var lime_sound_from_data = Libs.load("lime","lime_sound_from_data", 3);
#end //lime_native
} //AudioHandler
class Sound {
public var name : String;
public var handle : Dynamic;
public var channel : Dynamic;
public var ismusic : Bool = false;
var on_complete_handler : Sound->Void;
@:isVar public var volume(default, set) : Float = 1.0;
@:isVar public var pan(default, set) : Float = 0.0;
@:isVar public var position(get, set) : Float = 0.0;
#if (!audio_thread_disabled && lime_native)
@:noCompletion private var added_to_thread:Bool;
#end
private var _transform:SoundTransform;
public function new(_name:String, _handle:Dynamic, ?_music:Bool = false, ?_sound:Dynamic = null) {
name = _name;
handle = _handle;
channel = _sound;
ismusic = _music;
//reuse.
_transform = new SoundTransform(volume,pan);
}
public function play(?_loops:Int = 0, ?_start:Float = 0.0) {
channel = null;
#if lime_native
channel = lime_sound_channel_create(handle, _start, _loops, _transform);
#end //lime_native
}
public function stop() {
if(channel != null) {
#if (!audio_thread_disabled && lime_native)
if( ismusic ) {
AudioHandler.audio_state.remove(this);
}
#end
#if lime_native
lime_sound_channel_stop(channel);
#end //lime_native
channel = null;
}
}
@:noCompletion public function do_on_complete() {
if(on_complete_handler != null) {
on_complete_handler(this);
}
}
public function on_complete(_function:Sound->Void) {
on_complete_handler = _function;
}
@:noCompletion public function do_check_complete ():Bool {
if( lime_sound_channel_is_complete(channel) ) {
handle = null;
channel = null;
return true;
}
return false;
} //do_check_complete
@:noCompletion public function check_complete() {
#if (!audio_thread_disabled && lime_native)
if (added_to_thread || (channel != null && ismusic)) {
if (!added_to_thread) {
trace('adding to a thread ' + name);
AudioHandler.audio_state.add( this );
added_to_thread = true;
}
AudioHandler.audio_state.audio_thread.sendMessage( AudioHandler.audio_message_check_complete );
return false;
}
#else
if( do_check_complete() ) {
do_on_complete();
return true;
}
#end
return false;
}
function set_volume(_v:Float) : Float {
_transform.volume = _v;
#if lime_native
lime_sound_channel_set_transform(channel,_transform);
#end //lime_native
return volume = _v;
}
function set_pan(_p:Float) : Float {
_transform.pan = _p;
#if lime_native
lime_sound_channel_set_transform(channel,_transform);
#end //lime_native
return pan = _p;
}
function set_position(_p:Float) : Float {
#if lime_native
lime_sound_channel_set_position(channel, _p);
#end //lime_native
return position = _p;
}
function get_position() : Float {
#if lime_native
position = lime_sound_channel_get_position(channel);
#end //lime_native
return position;
}
#if lime_native
private static var lime_sound_channel_is_complete = Libs.load ("lime", "lime_sound_channel_is_complete", 1);
private static var lime_sound_channel_create = Libs.load("lime","lime_sound_channel_create", 4);
private static var lime_sound_channel_stop = Libs.load("lime","lime_sound_channel_stop", 1);
private static var lime_sound_channel_set_transform = Libs.load("lime","lime_sound_channel_set_transform", 2);
private static var lime_sound_channel_get_position = Libs.load ("lime", "lime_sound_channel_get_position", 1);
private static var lime_sound_channel_set_position = Libs.load ("lime", "lime_sound_channel_set_position", 2);
#end //lime_native
}
class SoundTransform {
public var pan:Float;
public var volume:Float;
@@ -15,98 +280,83 @@ class SoundTransform {
public function clone() {
return new SoundTransform(volume, pan);
}
}
class Sound {
public var handle : Dynamic;
public var sound : Dynamic;
} //SoundTransform
@:isVar public var volume(default, set) : Float = 1.0;
@:isVar public var pan(default, set) : Float = 0.0;
private var _transform:SoundTransform;
public function new(_handle:Dynamic, ?_sound:Dynamic = null){
handle = _handle;
sound = _sound;
//reuse.
_transform = new SoundTransform(volume,pan);
}
#if (!audio_thread_disabled && lime_native)
public function play(?_loops:Int = 0, ?_start:Float = 0.0) {
sound = null;
#if lime_native
sound = lime_sound_channel_create(handle, _start, _loops, _transform);
#end //lime_native
}
class AudioThreadState {
public var audio_thread:Thread;
public var sound_list:Map <Sound, Bool>;
public var main_thread:Thread;
public var mutex:Mutex;
public function new () {
mutex = new Mutex ();
sound_list = new Map ();
}
public function add (sound:Sound):Void {
mutex.acquire ();
if (!sound_list.exists(sound)) {
sound_list.set (sound, false);
AudioHandler.audio_thread_is_idle = false;
}
mutex.release ();
}
public function check() {
for (sound in sound_list.keys()) {
public function stop() {
if(sound != null) {
var is_complete = sound_list.get(sound);
if (is_complete) {
sound.do_on_complete();
mutex.acquire ();
sound_list.remove( sound );
mutex.release ();
} //isComplete
}
}
public function remove( sound:Sound ):Void {
mutex.acquire ();
if( sound_list.exists(sound) ) {
sound_list.remove(sound);
if (Lambda.count (sound_list) == 0) {
AudioHandler.audio_thread_is_idle = true;
}
}
mutex.release ();
}
public function update() {
mutex.acquire ();
for (sound in sound_list.keys()) {
var is_complete = sound.do_check_complete();
sound_list.set( sound, is_complete );
}
mutex.release ();
}
} //AudioThreadState
#if lime_native
lime_sound_channel_stop(sound);
#end //lime_native
sound = null;
}
}
public function set_volume(_v:Float) : Float {
_transform.volume = _v;
#if lime_native
lime_sound_channel_set_transform(sound,_transform);
#end //lime_native
return volume = _v;
}
public function set_pan(_p:Float) : Float {
_transform.pan = _p;
#if lime_native
lime_sound_channel_set_transform(sound,_transform);
#end //lime_native
return pan = _p;
}
#if lime_native
private static var lime_sound_channel_create = Libs.load("lime","lime_sound_channel_create", 4);
private static var lime_sound_channel_stop = Libs.load("lime","lime_sound_channel_stop", 1);
private static var lime_sound_channel_set_transform = Libs.load("lime","lime_sound_channel_set_transform", 2);
#end //lime_native
}
class AudioHandler {
public var lib : Lime;
public function new( _lib:Lime ) { lib = _lib; }
public var sounds : Map<String, Sound>;
public function startup() {
//test audio junks
sounds = new Map();
}
public function create_sound(_name:String, _file:String, ?_music:Bool = false ) {
if(sounds.exists(_name)) {
throw ">>> Named sounds are not allowed to have duplicate names";
}
#if lime_native
var _handle = lime_sound_from_file( lime.AssetData.path.get(_file), _music);
var _sound = new Sound(_handle);
sounds.set(_name, _sound);
#end //lime_native
}
#if lime_native
private static var lime_sound_from_file = Libs.load("lime","lime_sound_from_file", 2);
private static var lime_sound_from_data = Libs.load("lime","lime_sound_from_data", 3);
#end //lime_native
}
#end // (!audio_thread_disabled && lime_native)

View File

@@ -307,9 +307,12 @@ class Lime {
_debug('on_update ' + Timer.stamp(), true, false);
#if lime_native
Timer.__checkTimers();
Timer.__checkTimers();
#end
//process any audio
audio.update();
if(!has_shutdown) {
#if lime_native