Ver código fonte

Added a queued sound source.

Brucey 1 ano atrás
pai
commit
ffc0709716

+ 98 - 0
examples/queued.bmx

@@ -0,0 +1,98 @@
+SuperStrict
+
+Framework SDL.SDLRenderMax2d
+
+'
+' Choose SDL or MiniAudio backend
+Import Audio.AudioSDL
+'Import Audio.AudioMiniAudio
+
+Graphics 800,600,0
+
+Global sound:TSound = LoadSound(Null, SOLOUD_SOUND_QUEUED)
+
+Local driver:TSoloudAudioDriver = TSoloudAudioDriver(GetAudioDriver())
+Local so:TSoLoud = driver._soloud
+
+Local queue:TSLQueued = TSLQueued(TSoloudSound(sound)._sound)
+
+'Local buf:Byte[]
+' create a  buffer with 1 second of sine wave at 44100hz C5, where Sin() takes degrees
+Local sampleRate:Int = 44100
+Local frequency:Float = sampleRate / 168.0
+Local samplesForOneSecond:Int = sampleRate * 2
+
+' create byte buffer large enough to hold the float samples
+Local data:Byte[samplesForOneSecond * 4] 
+
+' create a float pointer to the byte buffer
+Local floatPtr:Float Ptr = Float Ptr(data)
+
+For Local i:Int = 0 Until samplesForOneSecond
+	Local sample:Float = Sin(i * (360.0 * frequency / sampleRate))
+	floatPtr[i] = sample ' store the float sample directly
+Next
+
+queue.writeData(data, size_t(samplesForOneSecond * 4))
+queue.writeData(data, size_t(samplesForOneSecond * 4))
+
+so.setVisualizationEnable(True)
+
+Global channel:TChannel = PlaySound(sound)
+Local volume:Float = 1
+
+Local ms:Int = MilliSecs()
+
+While not keydown(KEY_ESCAPE)
+	Cls
+
+	Local ts:Int = MilliSecs()
+	local size:Size_T = queue.size()
+
+	If size < 20000 Then
+		queue.writeData(data, size_t(samplesForOneSecond * 4))
+		ms = ts
+	EndIf
+
+	Local StaticArray wavData:Float[256]
+	Local StaticArray fftData:Float[256]
+	Local buf:Float Ptr = so.getWave()
+	MemCopy(wavData, buf, 246 * 4)
+	buf = so.calcFFT()
+	MemCopy(fftData, buf, 256 * 4)
+	
+	SetColor(255, 255, 255)
+
+	DrawText samplesForOneSecond * 4, 10, 10
+	DrawText size, 10, 20
+
+	For Local i:int = 0 Until 256
+		Local d:Float = wavData[i]
+		Local height:Float = d * 128
+		If d > 0 Then
+			DrawRect( 30 + i * 3, 200 - height, 3, height )
+		Else
+			DrawRect( 30 + i * 3, 200, 3, Abs(height) )
+		End If
+	Next
+
+	SetColor(248, 58, 10)
+	For Local i:int = 0 Until 246
+		Local d:Float = fftData[i]
+		Local height:Float = Min(200, d * 2)
+
+		DrawRect( 30 + i * 3, 200 - height, 2, height )
+	Next
+
+	SetColor(255, 255, 255)
+
+	Local y:Int = 350
+	DrawRect(20, y, 760, 20)
+
+	SetColor(0, 0, 0)
+	DrawRect(21, y + 1, 758, 18)
+
+
+	Flip
+
+Wend

+ 9 - 0
soloud.mod/common.bmx

@@ -373,6 +373,15 @@ Extern
 	Function bmx_soloud_streamfile_new:Byte Ptr(obj:Object)
 	Function bmx_soloud_streamfile_free(handle:Byte Ptr)
 	
+	Function bmx_soloud_queued_create:Byte Ptr()
+	Function bmx_soloud_queued_write(aQd:Byte Ptr, buffer:Byte Ptr, size:Size_T)
+	Function bmx_soloud_queued_destroy(aQd:Byte Ptr)
+	Function bmx_soloud_queued_stop(aQd:Byte Ptr)
+	Function bmx_soloud_queued_setVolume(aQd:Byte Ptr, aVolume:Float)
+	Function bmx_soloud_queued_setLooping(aQd:Byte Ptr, aLoop:Int)
+	Function bmx_soloud_queued_setAutoStop(aQd:Byte Ptr, aAutoStop:Int)
+	Function bmx_soloud_queued_count:Size_T(aQd:Byte Ptr)
+
 End Extern
 
 

+ 272 - 0
soloud.mod/dataqueue/dataqueue.c

@@ -0,0 +1,272 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <[email protected]>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "dataqueue.h"
+
+typedef struct data_queue_packet
+{
+    size_t datalen;  /* bytes currently in use in this packet. */
+    size_t startpos;  /* bytes currently consumed in this packet. */
+    struct data_queue_packet *next;  /* next item in linked list. */
+    uint8_t data[1];  /* packet data */
+} data_queue_packet;
+
+struct data_queue
+{
+    data_queue_packet *head; /* device fed from here. */
+    data_queue_packet *tail; /* queue fills to here. */
+    data_queue_packet *pool; /* these are unused packets. */
+    size_t packet_size;   /* size of new packets */
+    size_t queued_bytes;  /* number of bytes of data in the queue. */
+};
+
+
+static size_t min(const size_t a, const size_t b) {
+    return a <= b ? a : b;
+}
+
+static void bmx_queue_list_free(data_queue_packet *packet) {
+    while (packet) {
+        data_queue_packet *next = packet->next;
+        free(packet);
+        packet = next;
+    }
+}
+
+/* this all expects that you managed thread safety elsewhere. */
+
+data_queue * bmx_queue_new(const size_t _packetlen, const size_t initialslack) {
+    data_queue *queue = (data_queue *) malloc(sizeof (data_queue));
+
+    if (!queue) {
+        return 0;
+    } else {
+        const size_t packetlen = _packetlen ? _packetlen : 1024;
+        const size_t wantpackets = (initialslack + (packetlen - 1)) / packetlen;
+        size_t i;
+
+        memset(queue, 0, sizeof(data_queue));
+        queue->packet_size = packetlen;
+
+        for (i = 0; i < wantpackets; i++) {
+            data_queue_packet *packet = (data_queue_packet *) malloc(sizeof (data_queue_packet) + packetlen);
+            if (packet) { /* don't care if this fails, we'll deal later. */
+                packet->datalen = 0;
+                packet->startpos = 0;
+                packet->next = queue->pool;
+                queue->pool = packet;
+            }
+        }
+    }
+
+    return queue;
+}
+
+void bmx_queue_free(data_queue *queue) {
+    if (queue) {
+        bmx_queue_list_free(queue->head);
+        bmx_queue_list_free(queue->pool);
+        bmx_queue_free(queue);
+    }
+}
+
+void bmx_queue_clear(data_queue *queue, const size_t slack) {
+    const size_t packet_size = queue ? queue->packet_size : 1;
+    const size_t slackpackets = (slack + (packet_size-1)) / packet_size;
+    data_queue_packet *packet;
+    data_queue_packet *prev = 0;
+    size_t i;
+
+    if (!queue) {
+        return;
+    }
+
+    packet = queue->head;
+
+    /* merge the available pool and the current queue into one list. */
+    if (packet) {
+        queue->tail->next = queue->pool;
+    } else {
+        packet = queue->pool;
+    }
+
+    /* Remove the queued packets from the device. */
+    queue->tail = 0;
+    queue->head = 0;
+    queue->queued_bytes = 0;
+    queue->pool = packet;
+
+    /* Optionally keep some slack in the pool to reduce memory allocation pressure. */
+    for (i = 0; packet && (i < slackpackets); i++) {
+        prev = packet;
+        packet = packet->next;
+    }
+
+    if (prev) {
+        prev->next = 0;
+    } else {
+        queue->pool = 0;
+    }
+
+    bmx_queue_free(packet);  /* free extra packets */
+}
+
+static data_queue_packet * bmx_queue_packet_allocate(data_queue *queue) {
+    data_queue_packet *packet;
+
+    packet = queue->pool;
+    if (packet != 0) {
+        /* we have one available in the pool. */
+        queue->pool = packet->next;
+    } else {
+        /* Have to allocate a new one! */
+        packet = (data_queue_packet *) malloc(sizeof (data_queue_packet) + queue->packet_size);
+        if (packet == 0) {
+            return 0;
+        }
+    }
+
+    packet->datalen = 0;
+    packet->startpos = 0;
+    packet->next = 0;
+                
+    if (queue->tail == 0) {
+        queue->head = packet;
+    } else {
+        queue->tail->next = packet;
+    }
+    queue->tail = packet;
+    return packet;
+}
+
+
+int bmx_queue_write(data_queue *queue, const void *_data, const size_t _len) {
+    size_t len = _len;
+    const uint8_t *data = (const uint8_t *) _data;
+    const size_t packet_size = queue ? queue->packet_size : 0;
+    data_queue_packet *orighead;
+    data_queue_packet *origtail;
+    size_t origlen;
+    size_t datalen;
+
+    if (!queue) {
+        return 0;
+    }
+
+    orighead = queue->head;
+    origtail = queue->tail;
+    origlen = origtail ? origtail->datalen : 0;
+
+    while (len > 0) {
+        data_queue_packet *packet = queue->tail;
+
+        if (!packet || (packet->datalen >= packet_size)) {
+            /* tail packet missing or completely full; we need a new packet. */
+            packet = bmx_queue_packet_allocate(queue);
+            if (!packet) {
+                /* uhoh, reset so we've queued nothing new, free what we can. */
+                if (!origtail) {
+                    packet = queue->head;  /* whole queue. */
+                } else {
+                    packet = origtail->next;  /* what we added to existing queue. */
+                    origtail->next = 0;
+                    origtail->datalen = origlen;
+                }
+                queue->head = orighead;
+                queue->tail = origtail;
+                queue->pool = 0;
+
+                bmx_queue_list_free(packet);  /* give back what we can. */
+                return -1;
+            }
+        }
+
+        datalen = min(len, packet_size - packet->datalen);
+        memcpy(packet->data + packet->datalen, data, datalen);
+        data += datalen;
+        len -= datalen;
+        packet->datalen += datalen;
+        queue->queued_bytes += datalen;
+    }
+
+    return 0;
+}
+
+size_t bmx_queue_peek(data_queue *queue, void *_buf, const size_t _len) {
+    size_t len = _len;
+    uint8_t *buf = (uint8_t *) _buf;
+    uint8_t *ptr = buf;
+    data_queue_packet *packet;
+
+    if (!queue) {
+        return 0;
+    }
+
+    for (packet = queue->head; len && packet; packet = packet->next) {
+        const size_t avail = packet->datalen - packet->startpos;
+        const size_t cpy = min(len, avail);
+
+        memcpy(ptr, packet->data + packet->startpos, cpy);
+        ptr += cpy;
+        len -= cpy;
+    }
+
+    return (size_t) (ptr - buf);
+}
+
+size_t bmx_queue_read(data_queue *queue, void *_buf, const size_t _len) {
+    size_t len = _len;
+    uint8_t *buf = (uint8_t *) _buf;
+    uint8_t *ptr = buf;
+    data_queue_packet *packet;
+
+    if (!queue) {
+        return 0;
+    }
+
+    while ((len > 0) && ((packet = queue->head) != 0)) {
+        const size_t avail = packet->datalen - packet->startpos;
+        const size_t cpy = min(len, avail);
+
+        memcpy(ptr, packet->data + packet->startpos, cpy);
+        packet->startpos += cpy;
+        ptr += cpy;
+        queue->queued_bytes -= cpy;
+        len -= cpy;
+
+        if (packet->startpos == packet->datalen) {  /* packet is done, put it in the pool. */
+            queue->head = packet->next;
+
+            packet->next = queue->pool;
+            queue->pool = packet;
+        }
+    }
+
+    if (queue->head == 0) {
+        queue->tail = 0;  /* in case we drained the queue entirely. */
+    }
+
+    return (size_t) (ptr - buf);
+}
+
+size_t bmx_queue_count(data_queue *queue) {
+    return queue ? queue->queued_bytes : 0;
+}

+ 50 - 0
soloud.mod/dataqueue/dataqueue.h

@@ -0,0 +1,50 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <[email protected]>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#ifndef max_dataqueue_h_
+#define max_dataqueue_h_
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* this is not (currently) a public API. But maybe it should be! */
+
+struct data_queue;
+typedef struct data_queue data_queue;
+
+data_queue *bmx_queue_new(const size_t packetlen, const size_t initialslack);
+void bmx_queue_free(data_queue *queue);
+void bmx_queue_clear(data_queue *queue, const size_t slack);
+int bmx_queue_write(data_queue *queue, const void *data, const size_t len);
+size_t bmx_queue_read(data_queue *queue, void *buf, const size_t len);
+size_t bmx_queue_peek(data_queue *queue, void *buf, const size_t len);
+size_t bmx_queue_count(data_queue *queue);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* max_dataqueue_h_ */
+
+

+ 142 - 1
soloud.mod/glue.cpp

@@ -1,5 +1,5 @@
 #include "soloud_file.h"
-
+#include "dataqueue.h"
 
 extern "C" {
 
@@ -65,3 +65,144 @@ SoLoud::File * bmx_soloud_streamfile_new(BBObject * handle) {
 void bmx_soloud_streamfile_free(SoLoud::File * file) {
 	delete file;
 }
+
+
+namespace SoLoud
+{
+	class QueuedSource;
+
+	class QueuedSourceInstance : public AudioSourceInstance
+	{
+		QueuedSource *mParent;
+	public:
+		QueuedSourceInstance(QueuedSource *aParent);
+		virtual unsigned int getAudio(float *aBuffer, unsigned int aSamplesToRead, unsigned int aBufferSize);
+		virtual bool hasEnded();
+	};
+
+	class QueuedSource : public AudioSource
+	{
+	public:
+		data_queue * queue;
+
+		QueuedSource();
+		virtual ~QueuedSource();
+		virtual AudioSourceInstance *createInstance();
+		virtual void queueAudio(void * buffer, size_t size);
+	};
+};
+
+
+
+namespace SoLoud
+{
+
+	QueuedSourceInstance::QueuedSourceInstance(QueuedSource *aParent)
+	{
+		mParent = aParent;
+	}
+
+	unsigned int QueuedSourceInstance::getAudio(float *aBuffer, unsigned int aSamplesToRead, unsigned int aBufferSize)
+	{
+		unsigned int offset = 0;
+		float tmp[512 * MAX_CHANNELS];
+		unsigned int i, j, k;
+		unsigned int samples = aSamplesToRead;
+
+		for (i = 0; i < aSamplesToRead; i += 512)
+		{
+			unsigned int blockSize = (aSamplesToRead - i) > 512 ? 512 : aSamplesToRead - i;
+
+			memset(tmp, 0, 512 * MAX_CHANNELS * sizeof(float) );
+			size_t read = bmx_queue_read(mParent->queue, tmp, blockSize * 4 * 2);
+			read = read / 8;
+			offset += read;
+
+			for (j = 0; j < blockSize; j++)
+			{
+				for (k = 0; k < mChannels; k++)
+				{
+					aBuffer[k * aSamplesToRead + i + j] = tmp[j * mChannels + k];
+				}
+			}
+		}
+
+		return samples;
+
+	}
+
+	bool QueuedSourceInstance::hasEnded()
+	{
+		return 0;
+		// This audio source never ends.
+		//return bmx_queue_count(mParent->queue) == 0;
+	}
+
+	QueuedSource::QueuedSource()
+	{
+		mBaseSamplerate = 44100.0;
+		mChannels = 2;
+		queue = bmx_queue_new(9216, 9216);
+	}
+
+	QueuedSource::~QueuedSource()
+	{
+		stop();
+	}
+
+	void QueuedSource::queueAudio(void * buffer, size_t size)
+	{
+		bmx_queue_write(queue, buffer, size);
+	}
+
+	AudioSourceInstance * QueuedSource::createInstance() 
+	{
+		return new QueuedSourceInstance(this);
+	}
+
+};
+
+extern "C" {
+
+
+void bmx_soloud_queued_write(SoLoud::AudioSource * src, void * buffer, size_t size) {
+	SoLoud::QueuedSource* source = static_cast<SoLoud::QueuedSource*>(src);
+	source->queueAudio(buffer, size);
+}
+
+void bmx_soloud_queued_destroy(void * aClassPtr)
+{
+  delete (SoLoud::QueuedSource *)aClassPtr;
+}
+
+void * bmx_soloud_queued_create()
+{
+  return (void *)new SoLoud::QueuedSource();
+}
+
+void bmx_soloud_queued_stop(void * aClassPtr) {
+	SoLoud::QueuedSource * cl = (SoLoud::QueuedSource *)aClassPtr;
+	cl->stop();
+}
+
+void bmx_soloud_queued_setVolume(void * aClassPtr, float aVolume) {
+	SoLoud::QueuedSource * cl = (SoLoud::QueuedSource *)aClassPtr;
+	cl->setVolume(aVolume);
+}
+
+void bmx_soloud_queued_setLooping(void * aClassPtr, int aLoop) {
+	SoLoud::QueuedSource * cl = (SoLoud::QueuedSource *)aClassPtr;
+	cl->setLooping(!!aLoop);
+}
+
+void bmx_soloud_queued_setAutoStop(void * aClassPtr, int aAutoStop) {
+	SoLoud::QueuedSource * cl = (SoLoud::QueuedSource *)aClassPtr;
+	cl->setAutoStop(!!aAutoStop);
+}
+
+size_t bmx_soloud_queued_count(void * aClassPtr) {
+	SoLoud::QueuedSource * cl = (SoLoud::QueuedSource *)aClassPtr;
+	return bmx_queue_count(cl->queue);
+}
+
+}

+ 134 - 0
soloud.mod/soloud.bmx

@@ -1681,3 +1681,137 @@ End Type
 Type TSLFilter
 End Type
 
+
+Rem
+bbdoc: Audio source for playing audio from a dynamic buffer.
+End Rem
+Type TSLQueued Extends TSLAudioSource
+
+	Method New()
+		asPtr = bmx_soloud_queued_create()
+	End Method
+	
+	Rem
+	bbdoc: Writes @size bytes of audio data to the queue.
+	End Rem
+	Method writeData(data:Byte Ptr, size:Size_T)
+		bmx_soloud_queued_write(asPtr, data, size)
+	End Method
+
+	Rem
+	bbdoc: Returns the number of bytes queued up and ready to play.
+	End Rem
+	Method size:Size_T()
+		Return bmx_soloud_queued_count(asPtr)
+	End Method
+
+	Rem
+	bbdoc: Sets default volume for instances.
+	End Rem
+	Method setVolume(volume:Float) Override
+		bmx_soloud_queued_setVolume(asPtr, volume)
+	End Method
+	
+	Rem
+	bbdoc: Sets the looping of the instances created from this audio source.
+	End Rem
+	Method setLooping(loop:Int) Override
+		bmx_soloud_queued_setLooping(asPtr, loop)
+	End Method
+
+	Rem
+	bbdoc: Sets whether audio should auto-stop when it ends or not.
+	End Rem
+	Method setAutoStop(autoStop:Int) Override
+		bmx_soloud_queued_setAutoStop(asPtr, autoStop)
+	End Method
+	
+	Rem
+	bbdoc: Sets the minimum and maximum distances for 3d audio source (closer to min distance = max vol)
+	End Rem
+	Method set3dMinMaxDistance(minDistance:Float, maxDistance:Float) Override
+	End Method
+	
+	Rem
+	bbdoc: Sets attenuation model and rolloff factor for 3d audio source.
+	End Rem
+	Method set3dAttenuation(attenuationModel:Int, attenuationRolloffFactor:Float) Override
+	End Method
+
+	Rem
+	bbdoc: Sets doppler factor to reduce or enhance doppler effect, default = 1.0
+	End Rem
+	Method set3dDopplerFactor(dopplerFactor:Float) Override
+	End Method
+
+	Rem
+	bbdoc: Enables 3d processing.
+	about: Implicitly set by play3d calls.
+	End Rem
+	Method set3dListenerRelative(listenerRelative:Int) Override
+	End Method
+
+	Rem
+	bbdoc: Sets the coordinates for this audio source to be relative to listener's coordinates.
+	End Rem
+	Method set3dDistanceDelay(distanceDelay:Int) Override
+	End Method
+
+	Rem
+	bbdoc: Enables delaying the start of the sound based on the distance.
+	End Rem
+	Method set3dCollider(collider:TSLAudioCollider) Override
+		' TODO
+	End Method
+
+	Rem
+	bbdoc: Sets a custom 3d audio collider.
+	about: Set to Null to disable.
+	End Rem
+	Method set3dColliderEx(collider:TSLAudioCollider, userData:Int) Override
+		' TODO
+	End Method
+
+	Rem
+	bbdoc: Sets a custom attenuator.
+	about: Set to Null to disable.
+	End Rem
+	Method set3dAttenuator(attenuator:TSLAudioAttenuator) Override
+		' TODO
+	End Method
+
+	Rem
+	bbdoc: Sets behavior for inaudible sounds.
+	End Rem
+	Method setInaudibleBehavior(mustTick:Int, kill:Int) Override
+'		Speech_setInaudibleBehavior(asPtr, mustTick, kill)
+	End Method
+
+	Rem
+	bbdoc: Sets filter.
+	about: Set to NULL to clear the filter.
+	End Rem
+	Method setFilter(filterId:Int, filter:TSLFilter) Override
+		' TODO
+	End Method
+
+	Rem
+	bbdoc: Stops all instances of this audio source.
+	End Rem
+	Method stop() Override
+		bmx_soloud_queued_stop(asPtr)
+	End Method
+
+
+	Method destroy() Override
+		If asPtr Then
+			bmx_soloud_queued_destroy(asPtr)
+			asPtr = Null
+		End If
+	End Method
+
+	Method Delete()
+		destroy()
+	End Method
+	
+End Type

+ 2 - 0
soloud.mod/source.bmx

@@ -143,3 +143,5 @@ Import "soloud/src/audiosource/wav/stb_vorbis.c"
 
 Import "glue.cpp"
 
+Import "dataqueue/*.h"
+Import "dataqueue/dataqueue.c"

+ 12 - 0
soloudaudio.mod/soloudaudio.bmx

@@ -57,6 +57,7 @@ Const SOLOUD_SOUND_MONOTONE:Int =  $00010000
 Const SOLOUD_SOUND_TEDSID:Int =    $00020000
 Const SOLOUD_SOUND_SPEECH:Int =    $00040000
 Const SOLOUD_SOUND_AY:Int =        $00080000
+Const SOLOUD_SOUND_QUEUED:Int =    $00800000
 
 Const SOLOUD_SOUND_PAUSE_INAUDIBLE:Int = $10000000
 Const SOLOUD_SOUND_PROTECT:Int = $20000000
@@ -161,6 +162,17 @@ Type TSoloudSound Extends TSound
 
 			Return this
 		End If
+
+		If loopFlag & SOLOUD_SOUND_QUEUED Then
+			Local this:TSoloudSound = New TSoloudSound
+			this._sound = New TSLQueued
+
+			If loopFlag & SOUND_LOOP Then
+				this.isLooped = True
+			End If
+
+			Return this
+		End If
 	
 		Local sound:TSLLoadableAudioSource