diff --git a/gamemaker/extensions/FAudioGMS/FAudioGMS.yy b/gamemaker/extensions/FAudioGMS/FAudioGMS.yy index 966d529..1d77857 100644 --- a/gamemaker/extensions/FAudioGMS/FAudioGMS.yy +++ b/gamemaker/extensions/FAudioGMS/FAudioGMS.yy @@ -25,8 +25,7 @@ {"externalName":"FAudioGMS_StaticSound_LoadWAV","kind":1,"help":"FAudioGMS_StaticSound_LoadWAV(filePath)","hidden":false,"returnType":2,"argCount":0,"args":[ 1, ],"resourceVersion":"1.0","name":"FAudioGMS_StaticSound_LoadWAV","tags":[],"resourceType":"GMExtensionFunction",}, - {"externalName":"FAudioGMS_SoundInstance_Play","kind":1,"help":"FAudioGMS_SoundInstance_Play(id, loop)","hidden":false,"returnType":2,"argCount":0,"args":[ - 2, + {"externalName":"FAudioGMS_SoundInstance_Play","kind":1,"help":"FAudioGMS_SoundInstance_Play(id)","hidden":false,"returnType":2,"argCount":0,"args":[ 2, ],"resourceVersion":"1.0","name":"FAudioGMS_SoundInstance_Play","tags":[],"resourceType":"GMExtensionFunction",}, {"externalName":"FAudioGMS_SoundInstance_Pause","kind":1,"help":"FAudioGMS_SoundInstance_Pause(id)","hidden":false,"returnType":2,"argCount":0,"args":[ @@ -157,11 +156,11 @@ ],"resourceVersion":"1.0","name":"FAudioGMS_SetListenerVelocity","tags":[],"resourceType":"GMExtensionFunction",}, {"externalName":"FAudioGMS_PauseAll","kind":1,"help":"FAudioGMS_PauseAll()","hidden":false,"returnType":2,"argCount":0,"args":[],"resourceVersion":"1.0","name":"FAudioGMS_PauseAll","tags":[],"resourceType":"GMExtensionFunction",}, {"externalName":"FAudioGMS_ResumeAll","kind":1,"help":"FAudioGMS_ResumeAll()","hidden":false,"returnType":2,"argCount":0,"args":[],"resourceVersion":"1.0","name":"FAudioGMS_ResumeAll","tags":[],"resourceType":"GMExtensionFunction",}, - {"externalName":"FAudioGMS_SoundInstance_SetLoopPoints","kind":1,"help":"FAudioGMS_SoundInstance_SetLoopPoints(soundInstanceID, startInMilliseconds, endInMilliseconds)","hidden":false,"returnType":2,"argCount":0,"args":[ + {"externalName":"FAudioGMS_SoundInstance_SetPlayRegion","kind":1,"help":"FAudioGMS_SoundInstance_SetPlayRegion(soundInstanceID, startInMilliseconds, endInMilliseconds)","hidden":false,"returnType":2,"argCount":0,"args":[ 2, 2, 2, - ],"resourceVersion":"1.0","name":"FAudioGMS_SoundInstance_SetLoopPoints","tags":[],"resourceType":"GMExtensionFunction",}, + ],"resourceVersion":"1.0","name":"FAudioGMS_SoundInstance_SetPlayRegion","tags":[],"resourceType":"GMExtensionFunction",}, {"externalName":"FAudioGMS_SetMasteringEffectChain","kind":1,"help":"FAudioGMS_SetMasteringEffectChain(effectChainID, effectGain)","hidden":false,"returnType":2,"argCount":0,"args":[ 2, 2, @@ -169,6 +168,14 @@ {"externalName":"FAudioGMS_SetMasteringEffectGain","kind":1,"help":"FAudioGMS_SetMasteringEffectGain(effectGain)","hidden":false,"returnType":2,"argCount":0,"args":[ 2, ],"resourceVersion":"1.0","name":"FAudioGMS_SetMasteringEffectGain","tags":[],"resourceType":"GMExtensionFunction",}, + {"externalName":"FAudioGMS_SoundInstance_SetLoop","kind":1,"help":"FAudioGMS_SoundInstance_SetLoop(soundInstanceID, loop)","hidden":false,"returnType":2,"argCount":0,"args":[ + 2, + 2, + ],"resourceVersion":"1.0","name":"FAudioGMS_SoundInstance_SetLoop","tags":[],"resourceType":"GMExtensionFunction",}, + {"externalName":"FAudioGMS_SoundInstance_QueueSoundInstance","kind":1,"help":"FAudioGMS_SoundInstance_QueueSoundInstance(soundInstanceID, queueSoundInstanceID)","hidden":false,"returnType":2,"argCount":0,"args":[ + 2, + 2, + ],"resourceVersion":"1.0","name":"FAudioGMS_SoundInstance_QueueSoundInstance","tags":[],"resourceType":"GMExtensionFunction",}, ],"constants":[],"ProxyFiles":[ {"TargetMask":7,"resourceVersion":"1.0","name":"libFAudioGMS.so","tags":[],"resourceType":"GMProxyFile",}, {"TargetMask":3,"resourceVersion":"1.0","name":"FAudioGMSAndroidDummy.ext","tags":[],"resourceType":"GMProxyFile",}, @@ -182,13 +189,14 @@ {"name":"FAudioGMS_SoundInstance_Play","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_SoundInstance_Pause","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_SoundInstance_Stop","path":"extensions/FAudioGMS/FAudioGMS.yy",}, + {"name":"FAudioGMS_SoundInstance_SetLoop","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_SoundInstance_SetPan","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_SoundInstance_SetPitch","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_SoundInstance_SetVolume","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_SoundInstance_Set3DPosition","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_SoundInstance_Set3DVelocity","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_SoundInstance_SetTrackPositionInSeconds","path":"extensions/FAudioGMS/FAudioGMS.yy",}, - {"name":"FAudioGMS_SoundInstance_SetLoopPoints","path":"extensions/FAudioGMS/FAudioGMS.yy",}, + {"name":"FAudioGMS_SoundInstance_SetPlayRegion","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_SoundInstance_SetVolumeOverTime","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_SoundInstance_SetLowPassFilter","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_SoundInstance_SetHighPassFilter","path":"extensions/FAudioGMS/FAudioGMS.yy",}, @@ -197,6 +205,7 @@ {"name":"FAudioGMS_SoundInstance_GetVolume","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_SoundInstance_GetTrackLengthInSeconds","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_SoundInstance_GetTrackPositionInSeconds","path":"extensions/FAudioGMS/FAudioGMS.yy",}, + {"name":"FAudioGMS_SoundInstance_QueueSoundInstance","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_SoundInstance_Destroy","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_SoundInstance_DestroyWhenFinished","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_EffectChain_Create","path":"extensions/FAudioGMS/FAudioGMS.yy",}, diff --git a/gamemaker/scripts/FAudioGMS_Scripts/FAudioGMS_Scripts.gml b/gamemaker/scripts/FAudioGMS_Scripts/FAudioGMS_Scripts.gml index 151070c..9799244 100644 --- a/gamemaker/scripts/FAudioGMS_Scripts/FAudioGMS_Scripts.gml +++ b/gamemaker/scripts/FAudioGMS_Scripts/FAudioGMS_Scripts.gml @@ -19,17 +19,29 @@ function StaticSound(_staticSoundID) constructor { staticSoundID = _staticSoundID; - // Returns a sound instance! + // Create a sound instance from this static sound. + static CreateSoundInstance = function() + { + var instanceID = FAudioGMS_StaticSound_CreateSoundInstance(staticSoundID); + var instance = new SoundInstance(instanceID); + return instance; + } + + // Plays and returns a sound instance! // MUST be destroyed when you aren't referencing it any more or you will leak memory! static Play = function(pan = 0, pitch = 1, volume = 1, loop = false, loopStartInMilliseconds = 0, loopEndInMilliseconds = 0) { var instanceID = FAudioGMS_StaticSound_CreateSoundInstance(staticSoundID); var instance = new SoundInstance(instanceID); - instance.SetLoopPoints(loopStartInMilliseconds, loopEndInMilliseconds); + instance.SetLoop(loop); + if (loop) + { + instance.SetPlayRegion(loopStartInMilliseconds, loopEndInMilliseconds); + } instance.SetPan(pan); instance.SetPitch(pitch); instance.SetVolume(volume); - instance.Play(loop); + instance.Play(); return instance; } @@ -41,12 +53,13 @@ function StaticSound(_staticSoundID) constructor instance.DestroyWhenFinished(); } - // Returns a sound instance! + // Plays and returns a sound instance! // MUST be destroyed when you aren't referencing it any more or you will leak memory! static PlaySpatial = function(xPosition, yPosition, zPosition, pitch = 1, volume = 1, loop = false) { var instanceID = FAudioGMS_StaticSound_CreateSoundInstance(staticSoundID); var instance = new SoundInstance(instanceID); + instance.SetLoop(loop); instance.Set3DPosition(xPosition, yPosition, zPosition); instance.SetPitch(pitch); instance.SetVolume(volume); @@ -89,7 +102,7 @@ function SoundInstance(_soundInstanceID) constructor // Plays the sound or resumes from pause. static Play = function(loop = false) { - FAudioGMS_SoundInstance_Play(soundInstanceID, loop); + FAudioGMS_SoundInstance_Play(soundInstanceID); } // Pauses playback. @@ -116,6 +129,12 @@ function SoundInstance(_soundInstanceID) constructor FAudioGMS_SoundInstance_Set3DVelocity(soundInstanceID, xVelocity, yVelocity, zVelocity); } + // Sets whether the sound instance loops (true) or does not (false). + static SetLoop = function(loop) + { + FAudioGMS_SoundInstance_SetLoop(soundInstanceID, loop); + } + // Sets the panning value of the sound. -1 is farthest left, 1 is farthest right, 0 is center. // NOTE: This is ignored if you have called Set3DPosition. static SetPan = function(pan) @@ -146,14 +165,13 @@ function SoundInstance(_soundInstanceID) constructor // Sets the position of track playback. static SetTrackPosition = function(seconds) { - FAudioGMS_SoundInstance_SetTrackPosition(soundInstanceID, seconds); + FAudioGMS_SoundInstance_SetTrackPositionInSeconds(soundInstanceID, seconds); } - // Sets loop points for the sound instance. - // MUST Be called before Play. - static SetLoopPoints = function(loopStartInMilliseconds, loopEndInMilliseconds) + // Sets the playback region for the sound instance. + static SetPlayRegion = function(loopStartInMilliseconds, loopEndInMilliseconds) { - FAudioGMS_SoundInstance_SetLoopPoints(soundInstanceID, loopStartInMilliseconds, loopEndInMilliseconds); + FAudioGMS_SoundInstance_SetPlayRegion(soundInstanceID, loopStartInMilliseconds, loopEndInMilliseconds); } // Sets a low pass filter on the sound. @@ -196,6 +214,11 @@ function SoundInstance(_soundInstanceID) constructor FAudioGMS_SoundInstance_SetEffectGain(soundInstanceID, gain); } + static QueueSoundInstance = function(queueSoundInstance) + { + FAudioGMS_SoundInstance_QueueSoundInstance(soundInstanceID, queueSoundInstance.soundInstanceID); + } + // Gets the pitch of the sound. static GetPitch = function() { diff --git a/src/FAudioGMS.c b/src/FAudioGMS.c index 83ae79c..fed37c1 100644 --- a/src/FAudioGMS.c +++ b/src/FAudioGMS.c @@ -176,9 +176,12 @@ typedef struct FAudioGMS_StreamingSound float* streamBuffer; uint32_t streamBufferSize; uint32_t mostRecentBufferOffset; /* used for calculating track position */ + uint8_t isFinalBuffer; /* used to detect end of playback */ } FAudioGMS_StreamingSound; -typedef struct FAudioGMS_SoundInstance +typedef struct FAudioGMS_SoundInstance FAudioGMS_SoundInstance; + +struct FAudioGMS_SoundInstance { uint32_t id; FAudioGMS_Voice voice; @@ -207,15 +210,17 @@ typedef struct FAudioGMS_SoundInstance uint8_t isGlobalPaused; - uint32_t loopStart; - uint32_t loopLength; + uint32_t playBegin; + uint32_t playLength; + + FAudioGMS_SoundInstance *queuedSoundInstance; union { FAudioGMS_StaticSound *staticSound; /* static sounds are loaded separately, so they do not belong to the instance */ FAudioGMS_StreamingSound streamingSound; } soundData; -} FAudioGMS_SoundInstance; +}; typedef enum FAudioGMS_EffectType { @@ -312,15 +317,38 @@ static inline FAudioGMS_EffectChain* FAudioGMS_INTERNAL_LookupEffectChain(uint32 } } -/* Forward declare this to avoid annoying BS */ -static void FAudioGMS_INTERNAL_SoundInstance_AddBuffer(FAudioGMS_SoundInstance* instance); +/* Forward declarations to avoid some annoying BS */ -static void FAudioGMS_INTERNAL_StreamingBufferEndCallback(FAudioVoiceCallback* callback, FAudioGMS_SoundInstance *instance) +static void FAudioGMS_INTERNAL_SoundInstance_AddBuffer(FAudioGMS_SoundInstance* instance); +static void FAudioGMS_INTERNAL_SoundInstance_Play(FAudioGMS_SoundInstance* instance); +static void FAudioGMS_INTERNAL_SoundInstance_Stop(FAudioGMS_SoundInstance* instance); + +static void FAudioGMS_INTERNAL_OnBufferEndCallback(FAudioVoiceCallback* callback, FAudioGMS_SoundInstance *instance) { - if (instance->soundState == SoundState_Playing) - { - FAudioGMS_INTERNAL_SoundInstance_AddBuffer(instance); - } + if (instance->isStatic) + { + FAudioGMS_INTERNAL_SoundInstance_Stop(instance); + } + else + { + if (instance->soundData.streamingSound.isFinalBuffer) + { + FAudioGMS_INTERNAL_SoundInstance_Stop(instance); + } + else + { + FAudioGMS_INTERNAL_SoundInstance_AddBuffer(instance); + } + } + + if (instance->soundState == SoundState_Stopped) + { + if (instance->queuedSoundInstance != NULL) + { + FAudioGMS_INTERNAL_SoundInstance_Play(instance->queuedSoundInstance); + instance->queuedSoundInstance = NULL; + } + } } void FAudioGMS_Init(double spatialDistanceScale, double timestep) @@ -448,7 +476,7 @@ void FAudioGMS_Init(double spatialDistanceScale, double timestep) device->listener.Velocity.z = 0; device->listener.pCone = NULL; - device->voiceCallbacks.OnBufferEnd = FAudioGMS_INTERNAL_StreamingBufferEndCallback; + device->voiceCallbacks.OnBufferEnd = FAudioGMS_INTERNAL_OnBufferEndCallback; device->voiceCallbacks.OnBufferStart = NULL; device->voiceCallbacks.OnLoopEnd = NULL; device->voiceCallbacks.OnStreamEnd = NULL; @@ -546,14 +574,14 @@ double FAudioGMS_StaticSound_LoadWAV(char *filePath) } sound->buffer.AudioBytes = (uint32_t)(frameCount * sound->channels * sizeof(float)); - sound->buffer.Flags = FAUDIO_END_OF_STREAM; + sound->buffer.Flags = 0; sound->buffer.LoopBegin = 0; sound->buffer.LoopCount = 0; sound->buffer.LoopLength = 0; + sound->buffer.PlayBegin = 0; + sound->buffer.PlayLength = frameCount; sound->buffer.pAudioData = (uint8_t*) pSampleData; sound->buffer.pContext = NULL; - sound->buffer.PlayBegin = 0; - sound->buffer.PlayLength = frameCount; sound->lengthInSeconds = frameCount / sound->samplesPerSecond; @@ -697,8 +725,10 @@ static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_Init( instance->stereoAzimuth[0] = 0.0f; instance->stereoAzimuth[1] = 0.0f; - instance->loopStart = 0; - instance->loopLength = 0; + instance->playBegin = 0; + instance->playLength = 0; + + instance->queuedSoundInstance = NULL; if (device->soundInstanceIndexStack.count > 0) { @@ -815,6 +845,28 @@ void FAudioGMS_SoundInstance_SetBandPassFilter(double soundInstanceID, double ba } } +void FAudioGMS_SoundInstance_QueueSoundInstance(double soundInstanceID, double queueSoundInstanceID) +{ + FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_LookupSoundInstance((uint32_t)soundInstanceID); + FAudioGMS_SoundInstance* queueInstance = FAudioGMS_INTERNAL_LookupSoundInstance((uint32_t)queueSoundInstanceID); + + if (instance != NULL && queueInstance != NULL) + { + instance->queuedSoundInstance = queueInstance; + } + else + { + if (instance == NULL) + { + Log("QueueSoundInstace: Invalid instance ID!"); + } + else + { + Log("QueueSoundInstance: Invalid queue sound instance ID!"); + } + } +} + static void FAudioGMS_INTERNAL_Apply3D(FAudioGMS_SoundInstance* instance) { F3DAUDIO_EMITTER* emitter = instance->emitter; @@ -849,10 +901,10 @@ static void FAudioGMS_INTERNAL_SoundInstance_AddBuffer(FAudioGMS_SoundInstance* uint32_t defaultRequestedSampleCount = instance->format.nSamplesPerSec / 4; uint32_t requestedSampleCount = defaultRequestedSampleCount; - if (instance->loop && instance->loopLength != 0) + if (instance->playLength != 0) { - uint32_t distanceToLoopPoint = (instance->loopStart + instance->loopLength) - stb_vorbis_get_sample_offset(instance->soundData.streamingSound.fileHandle); - requestedSampleCount = SDL_min(requestedSampleCount, distanceToLoopPoint); + uint32_t distanceToEndPoint = (instance->playBegin + instance->playLength) - stb_vorbis_get_sample_offset(instance->soundData.streamingSound.fileHandle); + requestedSampleCount = SDL_min(requestedSampleCount, distanceToEndPoint); } uint32_t requiredStagingBufferSize = requestedSampleCount * instance->format.nChannels * sizeof(float); @@ -879,10 +931,6 @@ static void FAudioGMS_INTERNAL_SoundInstance_AddBuffer(FAudioGMS_SoundInstance* buffer.PlayLength = sampleCount; buffer.Flags = 0; - /*(sampleCount < instance->soundData.streamingSound.info.sample_rate) ? - FAUDIO_END_OF_STREAM : - 0; - */ buffer.LoopBegin = 0; buffer.LoopCount = 0; buffer.LoopLength = 0; @@ -890,19 +938,19 @@ static void FAudioGMS_INTERNAL_SoundInstance_AddBuffer(FAudioGMS_SoundInstance* FAudioSourceVoice_SubmitSourceBuffer(instance->voice.handle, &buffer, NULL); - /* We have reached the end of the loop region or file! */ - /* FIXME: maybe move this to a OnStreamEnd callback? */ - if (sampleCount < defaultRequestedSampleCount) - { - if (instance->loop) - { - stb_vorbis_seek_frame(instance->soundData.streamingSound.fileHandle, instance->loopStart); - } - else - { - instance->soundState = SoundState_Stopped; - } - } + instance->soundData.streamingSound.isFinalBuffer = 0; + + if (sampleCount < defaultRequestedSampleCount) + { + if (instance->loop) + { + stb_vorbis_seek_frame(instance->soundData.streamingSound.fileHandle, instance->playBegin); + } + else + { + instance->soundData.streamingSound.isFinalBuffer = 1; + } + } } double FAudioGMS_StreamingSound_LoadOGG(char* filePath) @@ -931,6 +979,7 @@ double FAudioGMS_StreamingSound_LoadOGG(char* filePath) instance->soundData.streamingSound.streamBuffer = NULL; instance->soundData.streamingSound.streamBufferSize = 0; instance->soundData.streamingSound.mostRecentBufferOffset = 0; + instance->soundData.streamingSound.isFinalBuffer = 0; FAudioGMS_INTERNAL_SoundInstance_AddBuffer(instance); @@ -987,11 +1036,13 @@ static void FAudioGMS_INTERNAL_SoundInstance_Play(FAudioGMS_SoundInstance* insta if (instance->isStatic) { + instance->soundData.staticSound->buffer.pContext = instance; + if (instance->loop) { instance->soundData.staticSound->buffer.LoopCount = FAUDIO_LOOP_INFINITE; - instance->soundData.staticSound->buffer.LoopBegin = instance->loopStart; - instance->soundData.staticSound->buffer.LoopLength = instance->loopLength; + instance->soundData.staticSound->buffer.LoopBegin = instance->playBegin; + instance->soundData.staticSound->buffer.LoopLength = instance->playLength; } else { @@ -1000,6 +1051,19 @@ static void FAudioGMS_INTERNAL_SoundInstance_Play(FAudioGMS_SoundInstance* insta instance->soundData.staticSound->buffer.LoopLength = 0; } + if (instance->soundState == SoundState_Paused) + { + FAudioSourceVoice_FlushSourceBuffers(instance->voice.handle); + + instance->soundData.staticSound->buffer.PlayBegin = instance->voice.handle->src.curBufferOffset; + instance->soundData.staticSound->buffer.PlayLength = instance->playLength; + } + else + { + instance->soundData.staticSound->buffer.PlayBegin = instance->playBegin; + instance->soundData.staticSound->buffer.PlayLength = instance->playLength; + } + FAudioSourceVoice_SubmitSourceBuffer(instance->voice.handle, &instance->soundData.staticSound->buffer, NULL); } @@ -1007,14 +1071,13 @@ static void FAudioGMS_INTERNAL_SoundInstance_Play(FAudioGMS_SoundInstance* insta instance->soundState = SoundState_Playing; } -void FAudioGMS_SoundInstance_Play(double soundInstanceID, double loop) +void FAudioGMS_SoundInstance_Play(double soundInstanceID) { RETURN_ON_NULL_DEVICE() FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_LookupSoundInstance((uint32_t)soundInstanceID); if (instance != NULL) { - instance->loop = (uint8_t) loop; FAudioGMS_INTERNAL_SoundInstance_Play(instance); } } @@ -1053,7 +1116,7 @@ static void FAudioGMS_INTERNAL_SoundInstance_Stop(FAudioGMS_SoundInstance* insta if (!instance->isStatic) { - stb_vorbis_seek_start(instance->soundData.streamingSound.fileHandle); /* back to the start */ + stb_vorbis_seek_frame(instance->soundData.streamingSound.fileHandle, instance->playBegin); /* back to the start */ FAudioGMS_INTERNAL_SoundInstance_AddBuffer(instance); /* preload so we dont stutter on play */ } } @@ -1070,6 +1133,24 @@ void FAudioGMS_SoundInstance_Stop(double soundInstanceID) FAudioGMS_INTERNAL_SoundInstance_Stop(instance); } +void FAudioGMS_SoundInstance_SetLoop(double soundInstanceID, double loop) +{ + RETURN_ON_NULL_DEVICE() + FAudioGMS_SoundInstance *instance = FAudioGMS_INTERNAL_LookupSoundInstance((uint32_t)soundInstanceID); + + if (instance != NULL) + { + instance->loop = (uint8_t)loop; + + if (instance->isStatic && instance->soundState == SoundState_Playing) + { + /* We need to pause and play so that static buffers get resubmitted */ + FAudioGMS_INTERNAL_SoundInstance_Pause(instance); + FAudioGMS_INTERNAL_SoundInstance_Play(instance); + } + } +} + void FAudioGMS_SoundInstance_SetPan(double soundInstanceID, double pan) { RETURN_ON_NULL_DEVICE() @@ -1179,31 +1260,71 @@ void FAudioGMS_SoundInstance_SetTrackPositionInSeconds(double soundInstanceID, d } } -void FAudioGMS_SoundInstance_SetLoopPoints(double soundInstanceID, double startInMilliseconds, double endInMilliseconds) +static uint32_t FAudioGMS_INTERNAL_SoundInstance_GetTrackPositionInSampleFrames(FAudioGMS_SoundInstance* instance) +{ + if (instance != NULL) + { + if (instance->isStatic) + { + return instance->voice.handle->src.curBufferOffset / sizeof(float); + } + else + { + return instance->soundData.streamingSound.mostRecentBufferOffset + instance->voice.handle->src.curBufferOffset; + } + } + + Log("Invalid sound instance!"); + return 0; +} + +void FAudioGMS_SoundInstance_SetPlayRegion(double soundInstanceID, double startInMilliseconds, double endInMilliseconds) { RETURN_ON_NULL_DEVICE() FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_LookupSoundInstance((uint32_t)soundInstanceID); if (instance != NULL) { - uint32_t loopBeginSampleFrame = instance->format.nSamplesPerSec * (startInMilliseconds / 1000); - uint32_t loopEndSampleFrame = instance->format.nSamplesPerSec * (endInMilliseconds / 1000); - uint32_t loopLength = loopEndSampleFrame - loopBeginSampleFrame; + uint32_t playBeginSampleFrame = instance->format.nSamplesPerSec * (startInMilliseconds / 1000); + uint32_t playEndSampleFrame = instance->format.nSamplesPerSec * (endInMilliseconds / 1000); + uint32_t playLength = playEndSampleFrame - playBeginSampleFrame; - if (loopLength <= 0) + if (playLength <= 0) { - Log("Loop end is less than or equal to loop start! Bailing!"); + Log("Play end is less than or equal to play start! Bailing!"); return; } - instance->loopStart = loopBeginSampleFrame; - instance->loopLength = loopLength; + instance->playBegin = playBeginSampleFrame; + instance->playLength = playLength; - if (!instance->isStatic) + uint32_t currentFrame = FAudioGMS_INTERNAL_SoundInstance_GetTrackPositionInSampleFrames(instance); + + if ( + currentFrame < instance->playBegin || + (currentFrame > instance->playBegin + instance->playLength) + ) { + /* we are outside the play region */ + if (instance->isStatic && instance->soundState == SoundState_Playing) + { + FAudioGMS_INTERNAL_SoundInstance_Stop(instance); + FAudioGMS_INTERNAL_SoundInstance_Play(instance); + } + else if (!instance->isStatic) + { + FAudioSourceVoice_FlushSourceBuffers(instance->voice.handle); + stb_vorbis_seek_frame(instance->soundData.streamingSound.fileHandle, instance->playBegin); + FAudioGMS_INTERNAL_SoundInstance_AddBuffer(instance); + } + } + else { - FAudioSourceVoice_FlushSourceBuffers(instance->voice.handle); - stb_vorbis_seek_frame(instance->soundData.streamingSound.fileHandle, instance->loopStart); - FAudioGMS_INTERNAL_SoundInstance_AddBuffer(instance); + /* we are inside the play region */ + if (instance->isStatic && instance->soundState != SoundState_Stopped) + { + FAudioGMS_INTERNAL_SoundInstance_Pause(instance); + FAudioGMS_INTERNAL_SoundInstance_Play(instance); + } } } } @@ -1283,15 +1404,7 @@ double FAudioGMS_SoundInstance_GetTrackPositionInSeconds(double soundInstanceID) if (instance != NULL) { - if (instance->isStatic) - { - uint32_t sampleFrame = instance->voice.handle->src.curBufferOffset / sizeof(float); - return sampleFrame / instance->format.nSamplesPerSec; - } - else - { - return ((double)instance->soundData.streamingSound.mostRecentBufferOffset + instance->voice.handle->src.curBufferOffset) / instance->format.nSamplesPerSec; - } + return FAudioGMS_INTERNAL_SoundInstance_GetTrackPositionInSampleFrames(instance) / instance->format.nSamplesPerSec; } else { diff --git a/src/FAudioGMS.h b/src/FAudioGMS.h index ff6d7bf..627c211 100644 --- a/src/FAudioGMS.h +++ b/src/FAudioGMS.h @@ -47,23 +47,25 @@ FAUDIOGMSAPI void FAudioGMS_StaticSound_Destroy(double staticSoundID); FAUDIOGMSAPI double FAudioGMS_StreamingSound_LoadOGG(char* filepath); /* returns a sound instance ID */ -FAUDIOGMSAPI void FAudioGMS_SoundInstance_Play(double soundInstanceID, double loop); +FAUDIOGMSAPI void FAudioGMS_SoundInstance_Play(double soundInstanceID); FAUDIOGMSAPI void FAudioGMS_SoundInstance_Pause(double soundInstanceID); FAUDIOGMSAPI void FAudioGMS_SoundInstance_Stop(double soundInstanceID); +FAUDIOGMSAPI void FAudioGMS_SoundInstance_SetPlayRegion(double soundInstanceID, double startInMilliseconds, double endInMilliseconds); +FAUDIOGMSAPI void FAudioGMS_SoundInstance_SetLoop(double soundInstanceID, double loop); FAUDIOGMSAPI void FAudioGMS_SoundInstance_SetPan(double soundInstanceID, double pan); FAUDIOGMSAPI void FAudioGMS_SoundInstance_SetPitch(double soundInstanceID, double pitch); FAUDIOGMSAPI void FAudioGMS_SoundInstance_SetVolume(double soundInstanceID, double volume); FAUDIOGMSAPI void FAudioGMS_SoundInstance_Set3DPosition(double soundInstanceID, double x, double y, double z); FAUDIOGMSAPI void FAudioGMS_SoundInstance_Set3DVelocity(double soundInstanceID, double xVelocity, double yVelocity, double zVelocity); FAUDIOGMSAPI void FAudioGMS_SoundInstance_SetTrackPositionInSeconds(double soundInstanceID, double trackPositionInSeconds); -/* remember to set loop points BEFORE calling Play */ -FAUDIOGMSAPI void FAudioGMS_SoundInstance_SetLoopPoints(double soundInstanceID, double startInMilliseconds, double endInMilliseconds); FAUDIOGMSAPI void FAudioGMS_SoundInstance_SetVolumeOverTime(double soundInstanceID, double volume, double milliseconds); FAUDIOGMSAPI void FAudioGMS_SoundInstance_SetLowPassFilter(double soundInstanceID, double lowPassFilter, double Q); FAUDIOGMSAPI void FAudioGMS_SoundInstance_SetHighPassFilter(double soundInstanceID, double highPassFilter, double Q); FAUDIOGMSAPI void FAudioGMS_SoundInstance_SetBandPassFilter(double soundInstanceID, double bandPassFilter, double Q); +FAUDIOGMSAPI void FAudioGMS_SoundInstance_QueueSoundInstance(double soundInstanceID, double queueSoundInstanceID); + FAUDIOGMSAPI double FAudioGMS_SoundInstance_GetPitch(double soundInstanceID); FAUDIOGMSAPI double FAudioGMS_SoundInstance_GetVolume(double soundInstanceID); FAUDIOGMSAPI double FAudioGMS_SoundInstance_GetTrackLengthInSeconds(double soundInstanceID);