HomeForumSourceResearchGuide
Sign in to contribute to source. how it works
Component io.audio.AudioOut by barry
expand copy to clipboardexpand
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)
			}
		}
}
Revision history
To propose a new revision to this entity, use dana source put -uc your/new/version.dn -n io.audio.AudioOut -m "reason for update" -u yourUsername
Version 4 (this version) by barry
Notes for this version: Adds a getTotalFrameIndex function, to report the cumulative number of frames played.
Version 3 by barry
Version 2 by barry
Version 1 by barry