diff --git a/gamemaker/extensions/FAudioGMS/FAudioGMS.yy b/gamemaker/extensions/FAudioGMS/FAudioGMS.yy index 053ddc9..966d529 100644 --- a/gamemaker/extensions/FAudioGMS/FAudioGMS.yy +++ b/gamemaker/extensions/FAudioGMS/FAudioGMS.yy @@ -7,7 +7,7 @@ "packageId": "", "productId": "", "author": "", - "date": "2021-10-22T04:46:44.6241287+05:00", + "date": "2021-10-21T16:46:44.6241287-07:00", "license": "", "description": "", "helpfile": "", @@ -77,10 +77,10 @@ 2, ],"resourceVersion":"1.0","name":"FAudioGMS_SoundInstance_SetVolumeOverTime","tags":[],"resourceType":"GMExtensionFunction",}, {"externalName":"FAudioGMS_StopAll","kind":1,"help":"FAudioGMS_StopAll()","hidden":false,"returnType":2,"argCount":0,"args":[],"resourceVersion":"1.0","name":"FAudioGMS_StopAll","tags":[],"resourceType":"GMExtensionFunction",}, - {"externalName":"FAudioGMS_SoundInstance_SetTrackPosition","kind":1,"help":"FAudioGMS_SoundInstance_SetTrackPosition(soundInstanceID, trackPositionInSeconds)","hidden":false,"returnType":2,"argCount":0,"args":[ + {"externalName":"FAudioGMS_SoundInstance_SetTrackPositionInSeconds","kind":1,"help":"FAudioGMS_SoundInstance_SetTrackPositionInSeconds(soundInstanceID, trackPositionInSeconds)","hidden":false,"returnType":2,"argCount":0,"args":[ 2, 2, - ],"resourceVersion":"1.0","name":"FAudioGMS_SoundInstance_SetTrackPosition","tags":[],"resourceType":"GMExtensionFunction",}, + ],"resourceVersion":"1.0","name":"FAudioGMS_SoundInstance_SetTrackPositionInSeconds","tags":[],"resourceType":"GMExtensionFunction",}, {"externalName":"FAudioGMS_SoundInstance_GetTrackLengthInSeconds","kind":1,"help":"FAudioGMS_SoundInstance_GetTrackLengthInSeconds(soundInstanceID)","hidden":false,"returnType":2,"argCount":0,"args":[ 2, ],"resourceVersion":"1.0","name":"FAudioGMS_SoundInstance_GetTrackLengthInSeconds","tags":[],"resourceType":"GMExtensionFunction",}, @@ -157,10 +157,22 @@ ],"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":[ + 2, + 2, + 2, + ],"resourceVersion":"1.0","name":"FAudioGMS_SoundInstance_SetLoopPoints","tags":[],"resourceType":"GMExtensionFunction",}, + {"externalName":"FAudioGMS_SetMasteringEffectChain","kind":1,"help":"FAudioGMS_SetMasteringEffectChain(effectChainID, effectGain)","hidden":false,"returnType":2,"argCount":0,"args":[ + 2, + 2, + ],"resourceVersion":"1.0","name":"FAudioGMS_SetMasteringEffectChain","tags":[],"resourceType":"GMExtensionFunction",}, + {"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",}, ],"constants":[],"ProxyFiles":[ {"TargetMask":7,"resourceVersion":"1.0","name":"libFAudioGMS.so","tags":[],"resourceType":"GMProxyFile",}, - {"TargetMask":7,"resourceVersion":"1.0","name":"libSDL2.so","tags":[],"resourceType":"GMProxyFile",}, {"TargetMask":3,"resourceVersion":"1.0","name":"FAudioGMSAndroidDummy.ext","tags":[],"resourceType":"GMProxyFile",}, + {"TargetMask":7,"resourceVersion":"1.0","name":"libSDL2-2.0.so.0","tags":[],"resourceType":"GMProxyFile",}, ],"copyToTargets":200,"order":[ {"name":"FAudioGMS_Init","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_StaticSound_LoadWAV","path":"extensions/FAudioGMS/FAudioGMS.yy",}, @@ -175,7 +187,8 @@ {"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_SetTrackPosition","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_SetVolumeOverTime","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_SoundInstance_SetLowPassFilter","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_SoundInstance_SetHighPassFilter","path":"extensions/FAudioGMS/FAudioGMS.yy",}, @@ -192,6 +205,8 @@ {"name":"FAudioGMS_EffectChain_Destroy","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_SoundInstance_SetEffectChain","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_SoundInstance_SetEffectGain","path":"extensions/FAudioGMS/FAudioGMS.yy",}, + {"name":"FAudioGMS_SetMasteringEffectChain","path":"extensions/FAudioGMS/FAudioGMS.yy",}, + {"name":"FAudioGMS_SetMasteringEffectGain","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_SetListenerPosition","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_SetListenerVelocity","path":"extensions/FAudioGMS/FAudioGMS.yy",}, {"name":"FAudioGMS_ResumeAll","path":"extensions/FAudioGMS/FAudioGMS.yy",}, @@ -242,4 +257,4 @@ "name": "FAudioGMS", "tags": [], "resourceType": "GMExtension", -} +} \ No newline at end of file diff --git a/gamemaker/scripts/FAudioGMS_Scripts/FAudioGMS_Scripts.gml b/gamemaker/scripts/FAudioGMS_Scripts/FAudioGMS_Scripts.gml index aa6781f..686abd6 100644 --- a/gamemaker/scripts/FAudioGMS_Scripts/FAudioGMS_Scripts.gml +++ b/gamemaker/scripts/FAudioGMS_Scripts/FAudioGMS_Scripts.gml @@ -21,10 +21,11 @@ function StaticSound(_staticSoundID) constructor // 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) + 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.SetPan(pan); instance.SetPitch(pitch); instance.SetVolume(volume); @@ -148,6 +149,11 @@ function SoundInstance(_soundInstanceID) constructor FAudioGMS_SoundInstance_SetTrackPosition(soundInstanceID, seconds); } + static SetLoopPoints = function(loopStartInMilliseconds, loopEndInMilliseconds) + { + FAudioGMS_SoundInstance_SetLoopPoints(soundInstanceID, loopStartInMilliseconds, loopEndInMilliseconds); + } + // Sets a low pass filter on the sound. // frequency: 0.0 <-> 1.0. 1.0 means all sound gets through. // Q: set this to 1 unless you know what you're doing diff --git a/src/FAudioGMS.c b/src/FAudioGMS.c index 9bbd60c..dad40b2 100644 --- a/src/FAudioGMS.c +++ b/src/FAudioGMS.c @@ -166,8 +166,6 @@ typedef struct FAudioGMS_StaticSound FAudioBuffer buffer; uint32_t channels; uint32_t samplesPerSecond; - uint32_t loopStart; - uint32_t loopLength; uint32_t lengthInSeconds; } FAudioGMS_StaticSound; @@ -208,6 +206,9 @@ typedef struct FAudioGMS_SoundInstance uint8_t isGlobalPaused; + uint32_t loopStart; + uint32_t loopLength; + union { FAudioGMS_StaticSound *staticSound; /* static sounds are loaded separately, so they do not belong to the instance */ @@ -553,9 +554,6 @@ double FAudioGMS_StaticSound_LoadWAV(char *filePath) sound->buffer.PlayBegin = 0; sound->buffer.PlayLength = frameCount; - sound->loopStart = 0; - sound->loopLength = 0; - sound->lengthInSeconds = frameCount / sound->samplesPerSecond; if (device->staticSoundIndexStack.count > 0) @@ -698,6 +696,9 @@ static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_Init( instance->stereoAzimuth[0] = 0.0f; instance->stereoAzimuth[1] = 0.0f; + instance->loopStart = 0; + instance->loopLength = 0; + if (device->soundInstanceIndexStack.count > 0) { instance->id = IdStack_Pop(&device->soundInstanceIndexStack); @@ -844,12 +845,20 @@ static void FAudioGMS_INTERNAL_Apply3D(FAudioGMS_SoundInstance* instance) static void FAudioGMS_INTERNAL_SoundInstance_AddBuffer(FAudioGMS_SoundInstance* instance) { - uint32_t requestedSampleCount = instance->format.nSamplesPerSec / 4; + uint32_t defaultRequestedSampleCount = instance->format.nSamplesPerSec / 4; + uint32_t requestedSampleCount = defaultRequestedSampleCount; + + if (instance->loop && instance->loopLength != 0) + { + uint32_t distanceToLoopPoint = (instance->loopStart + instance->loopLength) - stb_vorbis_get_sample_offset(instance->soundData.streamingSound.fileHandle); + requestedSampleCount = SDL_min(requestedSampleCount, distanceToLoopPoint); + } uint32_t requiredStagingBufferSize = requestedSampleCount * instance->format.nChannels * sizeof(float); if (instance->soundData.streamingSound.streamBufferSize < requiredStagingBufferSize) { instance->soundData.streamingSound.streamBuffer = SDL_realloc(instance->soundData.streamingSound.streamBuffer, requiredStagingBufferSize); + instance->soundData.streamingSound.streamBufferSize = requiredStagingBufferSize; } /* NOTE: this function returns samples per channel, not total samples */ @@ -878,13 +887,13 @@ static void FAudioGMS_INTERNAL_SoundInstance_AddBuffer(FAudioGMS_SoundInstance* FAudioSourceVoice_SubmitSourceBuffer(instance->voice.handle, &buffer, NULL); - /* We have reached the end of the file! */ + /* We have reached the end of the loop region or file! */ /* FIXME: maybe move this to a OnStreamEnd callback? */ - if (sampleCount < requestedSampleCount) + if (sampleCount < defaultRequestedSampleCount) { if (instance->loop) { - stb_vorbis_seek_start(instance->soundData.streamingSound.fileHandle); + stb_vorbis_seek_frame(instance->soundData.streamingSound.fileHandle, instance->loopStart); } else { @@ -977,8 +986,8 @@ static void FAudioGMS_INTERNAL_SoundInstance_Play(FAudioGMS_SoundInstance* insta if (instance->loop) { instance->soundData.staticSound->buffer.LoopCount = FAUDIO_LOOP_INFINITE; - instance->soundData.staticSound->buffer.LoopBegin = instance->soundData.staticSound->loopStart; - instance->soundData.staticSound->buffer.LoopLength = instance->soundData.staticSound->loopLength; + instance->soundData.staticSound->buffer.LoopBegin = instance->loopStart; + instance->soundData.staticSound->buffer.LoopLength = instance->loopLength; } else { @@ -1166,6 +1175,35 @@ void FAudioGMS_SoundInstance_SetTrackPositionInSeconds(double soundInstanceID, d } } +void FAudioGMS_SoundInstance_SetLoopPoints(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; + + if (loopLength <= 0) + { + Log("Loop end is less than or equal to loop start! Bailing!"); + return; + } + + instance->loopStart = loopBeginSampleFrame; + instance->loopLength = loopLength; + + if (!instance->isStatic) + { + FAudioSourceVoice_FlushSourceBuffers(instance->voice.handle); + stb_vorbis_seek_frame(instance->soundData.streamingSound.fileHandle, instance->loopStart); + FAudioGMS_INTERNAL_SoundInstance_AddBuffer(instance); + } + } +} + void FAudioGMS_SoundInstance_SetVolumeOverTime(double soundInstanceID, double volume, double milliseconds) { RETURN_ON_NULL_DEVICE() diff --git a/src/FAudioGMS.h b/src/FAudioGMS.h index 51eced7..ff6d7bf 100644 --- a/src/FAudioGMS.h +++ b/src/FAudioGMS.h @@ -57,6 +57,8 @@ FAUDIOGMSAPI void FAudioGMS_SoundInstance_SetVolume(double soundInstanceID, doub 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);