data TrackStatus {
int track
}
interface AudioOutputLib {
event trackFinished(TrackStatus t)
int output_new(int channels, int sampleRate)
bool output_ready(int handle)
bool output_play(int handle, int trackHandle) //extra param to tell us when to emit a progress event after N frames through samples? extra param to loop?
void output_stop(int handle, int trackHandle) //stop-and-discard
void output_stop_all(int handle)
void output_destroy(int handle)
int track_new(int channels, int sampleRate, int4 samples[], bool loop, int loopTo, bool loopAtSet, int loopAt)
bool track_append(int handle, int4 samples[], bool loop, int loopTo, bool loopAtSet, int loopAt)
void track_set_volume(int handle, int1 volume)
void track_finish(int handle)
int track_get_cursor(int handle)
void track_set_cursor(int handle, int index)
int track_get_total_frame_index(int handle)
void track_destroy(int handle)
}
data TrackItem {
AudioTrack track
TrackItem next
}
component provides AudioOut(Destructor), AudioTrack(Destructor) requires native AudioOutputLib lib, io.Output out, data.IntUtil iu {
implementation AudioOut {
int handle
TrackItem tracks
TrackItem last
eventsink trackEvents(EventData ed)
{
TrackStatus t = ed.details
if (ed.type == AudioOutputLib.[trackFinished])
{
TrackItem tp = null
TrackItem tw = tracks
while (tw != null)
{
if (tw.track.handle == t.track)
{
if (tp == null)
{
tracks = tw.next
if (tracks == null)
last = null
}
else
{
tp.next = tw.next
if (tp.next == null)
last = tp
}
emitevent trackFinished(new TrackEvent(tw.track))
break
}
tp = tw
tw = tw.next
}
}
}
AudioOut:AudioOut(store AudioFormat format)
{
handle = lib.output_new(format.channels, format.sampleRate)
sinkevent trackEvents(lib)
}
bool AudioOut:ready()
{
return lib.output_ready(handle)
}
bool AudioOut:play(store AudioTrack track)
{
TrackItem newItem = new TrackItem(track)
if (last == null)
{
tracks = newItem
}
else
{
last.next = newItem
}
last = newItem
return lib.output_play(handle, track.handle)
}
void AudioOut:stop(AudioTrack track) //stop-and-discard
{
lib.output_stop(handle, track.handle)
}
void AudioOut:stopAll()
{
lib.output_stop_all(handle)
}
void Destructor:destroy()
{
lib.output_destroy(handle)
}
}
implementation AudioTrack {
int handle
AudioTrack:AudioTrack(store AudioFormat format, int4 samples[], opt bool loop, opt int loopToFrame, opt int loopAtFrame)
{
handle = lib.track_new(format.sampleRate, format.channels, samples, loop, loopToFrame, isset loopAtFrame, loopAtFrame)
if (handle == 0)
{
throw new Exception("track initialisation failed")
}
}
void AudioTrack:setVolume(int1 volume) //0-100
{
if (volume > 100) volume = 100
lib.track_set_volume(handle, volume)
}
bool AudioTrack:append(int4 samples[], opt bool loop, opt int loopToFrame, opt int loopAtFrame)
{
return lib.track_append(handle, samples, loop, loopToFrame, isset loopAtFrame, loopAtFrame)
}
void AudioTrack:finish()
{
lib.track_finish(handle)
}
int AudioTrack:getFrameIndex()
{
return lib.track_get_cursor(handle)
}
void AudioTrack:setFrameIndex(int index)
{
lib.track_set_cursor(handle, index)
}
int AudioTrack:getTotalFrameIndex()
{
return lib.track_get_total_frame_index(handle)
}
void Destructor:destroy()
{
lib.track_destroy(handle)
}
}
}