From a77b9a39aa1cd2374f6eff327f7274e0ac35e86f Mon Sep 17 00:00:00 2001 From: Nikita Krapivin Date: Sat, 8 Jan 2022 15:36:24 +0500 Subject: [PATCH 1/3] Update Android support once again. And get rid of an unused argument in SetListenerOrientation. --- android/FAudioGMS_JNI.c | 39 +++++++- .../screwyoyo/faudiogms/FAudioGMSNative.java | 99 +++++++++++++++---- gamemaker/extensions/FAudioGMS/FAudioGMS.yy | 3 +- src/FAudioGMS.c | 1 - src/FAudioGMS.h | 1 - 5 files changed, 115 insertions(+), 28 deletions(-) diff --git a/android/FAudioGMS_JNI.c b/android/FAudioGMS_JNI.c index 04737a0..4cd415e 100644 --- a/android/FAudioGMS_JNI.c +++ b/android/FAudioGMS_JNI.c @@ -94,14 +94,14 @@ Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1StaticSound_1Destroy JNIEXPORT jdouble JNICALL Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1StreamingSound_1LoadOGG -(JNIEnv* jniEnv, jclass jniThis, jstring _filepath) +(JNIEnv* jniEnv, jclass jniThis, jstring _filepath, jdouble _bufferSizeInBytes) { jboolean isCopy; const char* filepath; jdouble ret; filepath = (*jniEnv)->GetStringUTFChars(jniEnv, _filepath, &isCopy); - ret = FAudioGMS_StreamingSound_LoadOGG((char *)filepath); + ret = FAudioGMS_StreamingSound_LoadOGG((char *)filepath, _bufferSizeInBytes); (*jniEnv)->ReleaseStringUTFChars(jniEnv, _filepath, filepath); return ret; } @@ -130,6 +130,22 @@ Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1Stop return NOTHING; } +JNIEXPORT jdouble JNICALL +Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1QueueSyncPlay +(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID) +{ + FAudioGMS_SoundInstance_QueueSyncPlay(_soundInstanceID); + return NOTHING; +} + +JNIEXPORT jdouble JNICALL +Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1SyncPlay +(JNIEnv* jniEnv, jclass jniThis) +{ + FAudioGMS_SoundInstance_SyncPlay(); + return NOTHING; +} + JNIEXPORT jdouble JNICALL Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1SetPlayRegion (JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID, jdouble _startInMilliseconds, jdouble _endInMilliseconds) @@ -186,6 +202,14 @@ Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1Set3DVelo return NOTHING; } +JNIEXPORT jdouble JNICALL +Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1Set3DOrientation +(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID, jdouble _xFront, jdouble _yFront, jdouble _zFront, jdouble _xTop, jdouble _yTop, jdouble _zTop) +{ + FAudioGMS_SoundInstance_Set3DOrientation(_soundInstanceID, _xFront, _yFront, _zFront, _xTop, _yTop, _zTop); + return NOTHING; +} + JNIEXPORT jdouble JNICALL Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1SetTrackPositionInSeconds (JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID, jdouble _trackPositionInSeconds) @@ -327,8 +351,7 @@ Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1EffectChain_1AddReverb _reverbGain, _decayTime, _density, - _roomSize - ); + _roomSize); return NOTHING; } @@ -388,6 +411,14 @@ Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SetListenerVelocity return NOTHING; } +JNIEXPORT jdouble JNICALL +Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SetListenerOrientation +(JNIEnv* jniEnv, jclass jniThis, jdouble _xFront, jdouble _yFront, jdouble _zFront, jdouble _xTop, jdouble _yTop, jdouble _zTop) +{ + FAudioGMS_SetListenerOrientation(_xFront, _yFront, _zFront, _xTop, _yTop, _zTop); + return NOTHING; +} + JNIEXPORT jdouble JNICALL Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1PauseAll (JNIEnv* jniEnv, jclass jniThis) diff --git a/gamemaker/extensions/FAudioGMS/AndroidSource/Sdk/org.screwyoyo.faudiogms/src/main/java/org/screwyoyo/faudiogms/FAudioGMSNative.java b/gamemaker/extensions/FAudioGMS/AndroidSource/Sdk/org.screwyoyo.faudiogms/src/main/java/org/screwyoyo/faudiogms/FAudioGMSNative.java index bfd143f..d5be5a0 100644 --- a/gamemaker/extensions/FAudioGMS/AndroidSource/Sdk/org.screwyoyo.faudiogms/src/main/java/org/screwyoyo/faudiogms/FAudioGMSNative.java +++ b/gamemaker/extensions/FAudioGMS/AndroidSource/Sdk/org.screwyoyo.faudiogms/src/main/java/org/screwyoyo/faudiogms/FAudioGMSNative.java @@ -12,30 +12,73 @@ public class FAudioGMSNative /* exactly as in FAudioGMS_JNI.c: */ public native double FAudioGMS_Init(double spatialDistanceScale, double timestep); - public native double FAudioGMS_StaticSound_LoadWAV(String filePath); - public native double FAudioGMS_StaticSound_CreateSoundInstance(double staticSoundID); + public native double FAudioGMS_StaticSound_LoadWAV( + String filePath); /* returns a static sound ID */ + public native double FAudioGMS_StaticSound_CreateSoundInstance( + double staticSoundID); /* returns a sound instance ID */ public native double FAudioGMS_StaticSound_Destroy(double staticSoundID); - public native double FAudioGMS_StreamingSound_LoadOGG(String filepath); + /* returns a sound instance ID */ + public native double FAudioGMS_StreamingSound_LoadOGG( + String filepath, + double bufferSizeInBytes); /* if 0 is passed we will use a sensible default*/ public native double FAudioGMS_SoundInstance_Play(double soundInstanceID); public native double FAudioGMS_SoundInstance_Pause(double soundInstanceID); public native double FAudioGMS_SoundInstance_Stop(double soundInstanceID); - public native double FAudioGMS_SoundInstance_SetPlayRegion(double soundInstanceID, double startInMilliseconds, double endInMilliseconds); + public native double FAudioGMS_SoundInstance_QueueSyncPlay(double soundInstanceID); + public native double FAudioGMS_SoundInstance_SyncPlay(); + + public native double FAudioGMS_SoundInstance_SetPlayRegion( + double soundInstanceID, + double startInMilliseconds, + double endInMilliseconds); public native double FAudioGMS_SoundInstance_SetLoop(double soundInstanceID, double loop); public native double FAudioGMS_SoundInstance_SetPan(double soundInstanceID, double pan); public native double FAudioGMS_SoundInstance_SetPitch(double soundInstanceID, double pitch); public native double FAudioGMS_SoundInstance_SetVolume(double soundInstanceID, double volume); - public native double FAudioGMS_SoundInstance_Set3DPosition(double soundInstanceID, double x, double y, double z); - public native double FAudioGMS_SoundInstance_Set3DVelocity(double soundInstanceID, double xVelocity, double yVelocity, double zVelocity); - public native double FAudioGMS_SoundInstance_SetTrackPositionInSeconds(double soundInstanceID, double trackPositionInSeconds); - public native double FAudioGMS_SoundInstance_SetVolumeOverTime(double soundInstanceID, double volume, double milliseconds); - public native double FAudioGMS_SoundInstance_SetLowPassFilter(double soundInstanceID, double lowPassFilter, double Q); - public native double FAudioGMS_SoundInstance_SetHighPassFilter(double soundInstanceID, double highPassFilter, double Q); - public native double FAudioGMS_SoundInstance_SetBandPassFilter(double soundInstanceID, double bandPassFilter, double Q); + public native double FAudioGMS_SoundInstance_Set3DPosition( + double soundInstanceID, + double x, + double y, + double z); + public native double FAudioGMS_SoundInstance_Set3DVelocity( + double soundInstanceID, + double xVelocity, + double yVelocity, + double zVelocity); + public native double FAudioGMS_SoundInstance_Set3DOrientation( + double soundInstanceID, + double xFront, + double yFront, + double zFront, + double xTop, + double yTop, + double zTop); + public native double FAudioGMS_SoundInstance_SetTrackPositionInSeconds( + double soundInstanceID, + double trackPositionInSeconds); + public native double FAudioGMS_SoundInstance_SetVolumeOverTime( + double soundInstanceID, + double volume, + double milliseconds); + public native double FAudioGMS_SoundInstance_SetLowPassFilter( + double soundInstanceID, + double lowPassFilter, + double Q); + public native double FAudioGMS_SoundInstance_SetHighPassFilter( + double soundInstanceID, + double highPassFilter, + double Q); + public native double FAudioGMS_SoundInstance_SetBandPassFilter( + double soundInstanceID, + double bandPassFilter, + double Q); - public native double FAudioGMS_SoundInstance_QueueSoundInstance(double soundInstanceID, double queueSoundInstanceID); + public native double FAudioGMS_SoundInstance_QueueSoundInstance( + double soundInstanceID, + double queueSoundInstanceID); public native double FAudioGMS_SoundInstance_GetPitch(double soundInstanceID); public native double FAudioGMS_SoundInstance_GetVolume(double soundInstanceID); @@ -62,25 +105,41 @@ public class FAudioGMSNative double reverbGain, double decayTime, double density, - double roomSize - ); + double roomSize); public native double FAudioGMS_EffectChain_Destroy(double effectChainID); /* * NOTE: Any changes to the effect chain will NOT apply after this is set! - * You MUST call SetEffectChain again if you make changes to the effect chain parameters! + * You MUST call SetEffectChain again if you make changes to the effect + * chain parameters! */ - public native double FAudioGMS_SoundInstance_SetEffectChain(double soundInstanceID, double effectChainID, double effectGain); - public native double FAudioGMS_SoundInstance_SetEffectGain(double soundInstanceID, double effectGain); + public native double FAudioGMS_SoundInstance_SetEffectChain( + double soundInstanceID, + double effectChainID, + double effectGain); + public native double FAudioGMS_SoundInstance_SetEffectGain( + double soundInstanceID, + double effectGain); public native double FAudioGMS_SetMasteringEffectChain(double effectChainID, double effectGain); public native double FAudioGMS_SetMasteringEffectGain(double effectGain); public native double FAudioGMS_SetListenerPosition(double x, double y, double z); - public native double FAudioGMS_SetListenerVelocity(double xVelocity, double yVelocity, double zVelocity); + public native double FAudioGMS_SetListenerVelocity( + double xVelocity, + double yVelocity, + double zVelocity); + public native double FAudioGMS_SetListenerOrientation( + double xFront, + double yFront, + double zFront, + double xTop, + double yTop, + double zTop); - public native double FAudioGMS_PauseAll(); /* mobile platforms, man... */ - public native double FAudioGMS_ResumeAll(); /* same thing here */ + public native double FAudioGMS_PauseAll(); /* useful for mobile platforms, etc + */ + public native double FAudioGMS_ResumeAll(); /* same as above */ public native double FAudioGMS_StopAll(); public native double FAudioGMS_Update(); diff --git a/gamemaker/extensions/FAudioGMS/FAudioGMS.yy b/gamemaker/extensions/FAudioGMS/FAudioGMS.yy index db24bd5..6f9da2d 100644 --- a/gamemaker/extensions/FAudioGMS/FAudioGMS.yy +++ b/gamemaker/extensions/FAudioGMS/FAudioGMS.yy @@ -190,8 +190,7 @@ 2, 2, ],"resourceVersion":"1.0","name":"FAudioGMS_SoundInstance_Set3DOrientation","tags":[],"resourceType":"GMExtensionFunction",}, - {"externalName":"FAudioGMS_SetListenerOrientation","kind":1,"help":"FAudioGMS_SetListenerOrientation(soundInstanceID, xFront, yFront, zFront, xTop, yTop, zTop)","hidden":false,"returnType":2,"argCount":0,"args":[ - 2, + {"externalName":"FAudioGMS_SetListenerOrientation","kind":1,"help":"FAudioGMS_SetListenerOrientation(xFront, yFront, zFront, xTop, yTop, zTop)","hidden":false,"returnType":2,"argCount":0,"args":[ 2, 2, 2, diff --git a/src/FAudioGMS.c b/src/FAudioGMS.c index f7c144a..7ccbbf5 100644 --- a/src/FAudioGMS.c +++ b/src/FAudioGMS.c @@ -1664,7 +1664,6 @@ void FAudioGMS_SetListenerVelocity(double xVelocity, double yVelocity, double zV } void FAudioGMS_SetListenerOrientation( - double soundInstanceID, double xFront, double yFront, double zFront, diff --git a/src/FAudioGMS.h b/src/FAudioGMS.h index 001f0cc..e24eff8 100644 --- a/src/FAudioGMS.h +++ b/src/FAudioGMS.h @@ -160,7 +160,6 @@ extern "C" double yVelocity, double zVelocity); FAUDIOGMSAPI void FAudioGMS_SetListenerOrientation( - double soundInstanceID, double xFront, double yFront, double zFront, -- 2.25.1 From c37921a18119b56087ae4622d565d71ec9d3a7d4 Mon Sep 17 00:00:00 2001 From: Nikita Krapivin Date: Sat, 8 Jan 2022 16:03:38 +0500 Subject: [PATCH 2/3] Update Android prebuilt libs. --- .../FAudioGMS/AndroidSource/libs/arm64-v8a/libFAudioGMS.so | 4 ++-- .../FAudioGMS/AndroidSource/libs/armeabi-v7a/libFAudioGMS.so | 4 ++-- .../FAudioGMS/AndroidSource/libs/x86/libFAudioGMS.so | 4 ++-- .../FAudioGMS/AndroidSource/libs/x86_64/libFAudioGMS.so | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/gamemaker/extensions/FAudioGMS/AndroidSource/libs/arm64-v8a/libFAudioGMS.so b/gamemaker/extensions/FAudioGMS/AndroidSource/libs/arm64-v8a/libFAudioGMS.so index 3606317..6c4387e 100644 --- a/gamemaker/extensions/FAudioGMS/AndroidSource/libs/arm64-v8a/libFAudioGMS.so +++ b/gamemaker/extensions/FAudioGMS/AndroidSource/libs/arm64-v8a/libFAudioGMS.so @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c125bd766e0fa651fbfcb395543993f77c787c6d6c1c101d46ba517819beb660 -size 281696 +oid sha256:35a5da90b37902896e47b65cf869d59e72e707ce0784f0c15b8aac948999e20a +size 216160 diff --git a/gamemaker/extensions/FAudioGMS/AndroidSource/libs/armeabi-v7a/libFAudioGMS.so b/gamemaker/extensions/FAudioGMS/AndroidSource/libs/armeabi-v7a/libFAudioGMS.so index daac046..7e94881 100644 --- a/gamemaker/extensions/FAudioGMS/AndroidSource/libs/armeabi-v7a/libFAudioGMS.so +++ b/gamemaker/extensions/FAudioGMS/AndroidSource/libs/armeabi-v7a/libFAudioGMS.so @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a43b954d1d673c0c5d441c9b609efe0e42f70f673086577db871da135de49180 -size 199440 +oid sha256:fa96dc3050152bfb6c9686dc388bef9b5d0e1d76291ff643ed1ab54c6ecbf197 +size 162576 diff --git a/gamemaker/extensions/FAudioGMS/AndroidSource/libs/x86/libFAudioGMS.so b/gamemaker/extensions/FAudioGMS/AndroidSource/libs/x86/libFAudioGMS.so index 13473a0..4865e44 100644 --- a/gamemaker/extensions/FAudioGMS/AndroidSource/libs/x86/libFAudioGMS.so +++ b/gamemaker/extensions/FAudioGMS/AndroidSource/libs/x86/libFAudioGMS.so @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:64a589c40744b1645defb9b79a1f50e791eeb7d9cb69b9675c8f6654390d2ce1 -size 314064 +oid sha256:7fca3db51563892f0c4a5b8c63f87ec5bc371f47302273c83f481c48f5641301 +size 240336 diff --git a/gamemaker/extensions/FAudioGMS/AndroidSource/libs/x86_64/libFAudioGMS.so b/gamemaker/extensions/FAudioGMS/AndroidSource/libs/x86_64/libFAudioGMS.so index 1eb305d..e1816b1 100644 --- a/gamemaker/extensions/FAudioGMS/AndroidSource/libs/x86_64/libFAudioGMS.so +++ b/gamemaker/extensions/FAudioGMS/AndroidSource/libs/x86_64/libFAudioGMS.so @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bbe06366eb5c6088b572a67c3745520567d9490d81a388372b54b1ad50eeccff -size 310640 +oid sha256:748f0899f1b45f4a6c17003555d180fec53aace4a38893787841598cab5a4506 +size 236912 -- 2.25.1 From 48a6501f47f041694770f219685b3cfc9ae853f1 Mon Sep 17 00:00:00 2001 From: Nikita Krapivin Date: Sat, 8 Jan 2022 16:43:38 +0500 Subject: [PATCH 3/3] Give GML scripts some love. --- gamemaker/objects/AUDIO/CleanUp_0.gml | 16 ++++++++++ gamemaker/objects/AUDIO/Create_0.gml | 11 ++++++- gamemaker/objects/AUDIO/Step_2.gml | 3 +- .../FAudioGMS_Scripts/FAudioGMS_Scripts.gml | 30 +++++++++++++++++-- 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/gamemaker/objects/AUDIO/CleanUp_0.gml b/gamemaker/objects/AUDIO/CleanUp_0.gml index d8dbe47..5dfb697 100644 --- a/gamemaker/objects/AUDIO/CleanUp_0.gml +++ b/gamemaker/objects/AUDIO/CleanUp_0.gml @@ -1 +1,17 @@ +/// @description Clean up all resources when the game is about to end. + +/* Destroy sound instances first: */ +// sndInst.Stop(); +// sndInst.Destroy(); +// sndInst = undefined; + +/* Only then destroy static sounds: */ +// snd.Destroy(); +// snd = undefined; + +/* And only then, destroy effect chains */ +effChain.Destroy(); +effChain = undefined; + +/* Finish up the system */ FAudioGMS_Destroy(); diff --git a/gamemaker/objects/AUDIO/Create_0.gml b/gamemaker/objects/AUDIO/Create_0.gml index 9c5ef31..9a7d480 100644 --- a/gamemaker/objects/AUDIO/Create_0.gml +++ b/gamemaker/objects/AUDIO/Create_0.gml @@ -1,6 +1,15 @@ +/// @description Initialize audio. + +/* First initialize the system: */ var spatialDistanceScale = 50; // makes "3D" audio louder -FAudioGMS_Init(spatialDistanceScale, 1 / 60); +var timestep = game_get_speed(gamespeed_microseconds) / 1000000; // default, autodetect from GM timestep. +FAudioGMS_Init(spatialDistanceScale, timestep); /* Init Effects Chains Here */ +effChain = new EffectChain(); +effChain.AddDefaultReverb(); /* Load Audio Assets Here */ +// snd = LoadStaticSound("go-go-go-tigerblood.wav"); +// sndInst = snd.Play(); +// sndInst.SetEffectChain(effChain, 1); // apply default reverb to the instance. diff --git a/gamemaker/objects/AUDIO/Step_2.gml b/gamemaker/objects/AUDIO/Step_2.gml index 69c3986..008a1d2 100644 --- a/gamemaker/objects/AUDIO/Step_2.gml +++ b/gamemaker/objects/AUDIO/Step_2.gml @@ -1 +1,2 @@ -FAudioGMS_Update(); \ No newline at end of file +/// @description MUST be called once per frame! +FAudioGMS_Update(); diff --git a/gamemaker/scripts/FAudioGMS_Scripts/FAudioGMS_Scripts.gml b/gamemaker/scripts/FAudioGMS_Scripts/FAudioGMS_Scripts.gml index df7f48a..a9421dd 100644 --- a/gamemaker/scripts/FAudioGMS_Scripts/FAudioGMS_Scripts.gml +++ b/gamemaker/scripts/FAudioGMS_Scripts/FAudioGMS_Scripts.gml @@ -88,10 +88,10 @@ function StaticSound(_staticSoundID) constructor // The audio is streamed off the disk, so only a small amount of memory is used at a time. // Good for things like music or voiceover playback. // Note that StreamingSounds are SoundInstances. -function LoadStreamingSound(filename) +function LoadStreamingSound(filename, bufferSizeInBytes = 0) { var filePath = GetPathPrepend() + "audio/streaming/" + filename; - soundInstanceID = FAudioGMS_StreamingSound_LoadOGG(filePath); + soundInstanceID = FAudioGMS_StreamingSound_LoadOGG(filePath, bufferSizeInBytes); return new SoundInstance(soundInstanceID); } @@ -128,6 +128,12 @@ function SoundInstance(_soundInstanceID) constructor { FAudioGMS_SoundInstance_Set3DVelocity(soundInstanceID, xVelocity, yVelocity, zVelocity); } + + // Sets the 3-dimensional orientation of the sound. + static Set3DOrientation = function(xFront, yFront, zFront, xTop, yTop, zTop) + { + FAudioGMS_SoundInstance_Set3DOrientation(soundInstanceID, xFront, yFront, zFront, xTop, yTop, zTop); + } // Sets whether the sound instance loops (true) or does not (false). static SetLoop = function(loop) @@ -167,6 +173,12 @@ function SoundInstance(_soundInstanceID) constructor { FAudioGMS_SoundInstance_SetTrackPositionInSeconds(soundInstanceID, seconds); } + + // Queues this sound instance for playing in sync. + static QueueSyncPlay = function() + { + FAudioGMS_SoundInstance_QueueSyncPlay(soundInstanceID); + } // Sets the playback region for the sound instance. static SetPlayRegion = function(loopStartInMilliseconds, loopEndInMilliseconds) @@ -216,7 +228,7 @@ function SoundInstance(_soundInstanceID) constructor static QueueSoundInstance = function(queueSoundInstance) { - FAudioGMS_SoundInstance_QueueSoundInstance(soundInstanceID, queueSoundInstance.soundInstanceID); + FAudioGMS_SoundInstance_QueueSoundInstance(soundInstanceID, queueSoundInstance.soundInstanceID); } // Gets the pitch of the sound. @@ -263,6 +275,12 @@ function SoundInstance(_soundInstanceID) constructor SetVolume(1); } +// Plays the sound instance queue. +function SyncPlay() +{ + FAudioGMS_SoundInstance_SyncPlay(); +} + // Effect chains allow you to modify sound playback using audio effects. // Right now only reverb is implemented, but more effects will probably come later. function EffectChain() constructor @@ -348,6 +366,12 @@ function SetListenerVelocity(xVelocity, yVelocity, zVelocity) FAudioGMS_SetListenerVelocity(xVelocity, yVelocity, zVelocity); } +// Sets the orientation of the listener for 3D audio. +function SetListenerOrientation(xFront, yFront, zFront, xTop, yTop, zTop) +{ + FAudioGMS_SetListenerOrientation(xFront, yFront, zFront, xTop, yTop, zTop); +} + // Stops all audio playback. function StopAllAudio() { -- 2.25.1