From b625250af0b93690b2e271fdd2dcf216c4d42284 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Mon, 6 Apr 2026 10:46:04 +0100 Subject: [PATCH] Few changes to fix the preload failures Adds extra error output for erroneous buffer preload SndStream now correctly sets sndfile to null when it closes, Also extra error reporting around the read function SFXResource now returns a new threadsaferef each time we openstream. This should only be called on a fresh instance. --- Engine/source/sfx/media/sfxSndStream.cpp | 35 +++++-- Engine/source/sfx/sfxProfile.cpp | 112 +++++++++++++---------- Engine/source/sfx/sfxResource.cpp | 6 +- 3 files changed, 100 insertions(+), 53 deletions(-) diff --git a/Engine/source/sfx/media/sfxSndStream.cpp b/Engine/source/sfx/media/sfxSndStream.cpp index eee6d5d69..7dbbca180 100644 --- a/Engine/source/sfx/media/sfxSndStream.cpp +++ b/Engine/source/sfx/media/sfxSndStream.cpp @@ -85,6 +85,7 @@ void SFXSndStream::_close() return; sf_close(sndFile); + sndFile = NULL; } SFXSndStream* SFXSndStream::create(Stream* stream) @@ -99,18 +100,40 @@ SFXSndStream* SFXSndStream::create(Stream* stream) void SFXSndStream::reset() { + if (!sndFile) + return; vio_data.offset = 0; + sf_seek(sndFile, 0, SEEK_SET); } U32 SFXSndStream::read(U8* buffer, U32 length) { if (!sndFile) { - Con::errorf("SFXSndStream - read: Called on uninitialized stream."); + Con::errorf("SFXSndStream - read: Called on uninitialized or closed stream."); + return 0; + } + + if (!buffer) + { + Con::errorf("SFXSndStream - read: NULL buffer passed."); + return 0; + } + + const U32 bytesPerSample = mFormat.getBytesPerSample(); + if (bytesPerSample == 0) + { + Con::errorf("SFXSndStream - read: bytesPerSample is zero, format not initialized?"); + return 0; + } + + U32 framesToRead = length / bytesPerSample; + if (framesToRead == 0) + { + Con::errorf("SFXSndStream - read: length %d too small for bytesPerSample %d", length, bytesPerSample); return 0; } - U32 framesToRead = length / mFormat.getBytesPerSample(); U32 framesRead = 0; switch (sfinfo.format & SF_FORMAT_SUBMASK) @@ -136,11 +159,11 @@ U32 SFXSndStream::read(U8* buffer, U32 length) Con::errorf("SFXSndStream - read: %s", sf_strerror(sndFile)); } - // (convert to frames) - number of frames available < MAX_BUFFER? reset - if (((getPosition() / mFormat.getBytesPerSample()) - sfinfo.frames) < MAX_BUFFER) + sf_count_t currentFrame = sf_seek(sndFile, 0, SEEK_CUR); + if (currentFrame >= sfinfo.frames - (sf_count_t)MAX_BUFFER) { - // reset stream - setPosition(0); + sf_seek(sndFile, 0, SEEK_SET); + vio_data.offset = 0; } diff --git a/Engine/source/sfx/sfxProfile.cpp b/Engine/source/sfx/sfxProfile.cpp index 2af2cb6e2..d8e7875d6 100644 --- a/Engine/source/sfx/sfxProfile.cpp +++ b/Engine/source/sfx/sfxProfile.cpp @@ -275,21 +275,37 @@ void SFXProfile::_onResourceChanged( const Torque::Path& path ) bool SFXProfile::_preloadBuffer() { - AssertFatal( !mDescription->mIsStreaming, "SFXProfile::_preloadBuffer() - must not be called for streaming profiles" ); + AssertFatal(!mDescription->mIsStreaming, "SFXProfile::_preloadBuffer() - must not be called for streaming profiles"); + + if (mFilename == StringTable->EmptyString()) + { + Con::errorf("SFXProfile::_preloadBuffer(%s) - no filename set", getName()); + return false; + } + + Con::printf("SFXProfile::_preloadBuffer(%s) - attempting to preload '%s'", getName(), mFilename); mBuffer = _createBuffer(); - return ( !mBuffer.isNull() ); + if (mBuffer.isNull()) + { + Con::errorf("SFXProfile::_preloadBuffer(%s) - _createBuffer() returned null for '%s'", getName(), mFilename); + return false; + } + + return true; } //----------------------------------------------------------------------------- Resource& SFXProfile::getResource() { - if (!mResource && SFXResource::exists(mFilename)) - mResource = SFXResource::load(mFilename); - else - mResource = NULL; - + if (!mResource) + { + if (SFXResource::exists(mFilename)) + mResource = SFXResource::load(mFilename); + else + Con::errorf("SFXProfile::getResource(%s) - file does not exist: '%s'", getName(), mFilename); + } return mResource; } @@ -317,47 +333,51 @@ SFXBuffer* SFXProfile::getBuffer() SFXBuffer* SFXProfile::_createBuffer() { - SFXBuffer* buffer = 0; - - // Try to create through SFXDevie. - - if( mFilename != StringTable->EmptyString() && SFX ) - { - buffer = SFX->_createBuffer( mFilename, mDescription ); - if( buffer ) - { - #ifdef TORQUE_DEBUG - const SFXFormat& format = buffer->getFormat(); - Con::printf( "%s SFX: %s (%i channels, %i kHz, %.02f sec, %i kb)", - mDescription->mIsStreaming ? "Streaming" : "Loaded", mFilename, - format.getChannels(), - format.getSamplesPerSecond() / 1000, - F32( buffer->getDuration() ) / 1000.0f, - format.getDataLength( buffer->getDuration() ) / 1024 ); - #endif - } - } - - // If that failed, load through SFXResource. - - if( !buffer ) - { - Resource< SFXResource >& resource = getResource(); - if( resource != NULL && SFX ) - { - #ifdef TORQUE_DEBUG - const SFXFormat& format = resource->getFormat(); - Con::printf( "%s SFX: %s (%i channels, %i kHz, %.02f sec, %i kb)", - mDescription->mIsStreaming ? "Streaming" : "Loading", resource->getFileName().c_str(), - format.getChannels(), - format.getSamplesPerSecond(), - F32( resource->getDuration() ) / 1000.0f, - format.getDataLength( resource->getDuration() ) / 1024 ); - #endif + SFXBuffer* buffer = NULL; - ThreadSafeRef< SFXStream > sfxStream = resource->openStream(); - buffer = SFX->_createBuffer( sfxStream, mDescription ); + if (mFilename == StringTable->EmptyString()) + { + Con::errorf("SFXProfile::_createBuffer(%s) - mFilename is empty!", getName()); + return NULL; + } + + if (!SFX) + { + Con::errorf("SFXProfile::_createBuffer(%s) - No SFX system available!", getName()); + return NULL; + } + + // Try to create through SFXDevice. For now this always fails and i think was just here for historical reasons. Function just returns null. + /*buffer = SFX->_createBuffer(mFilename, mDescription); + if (!buffer) + Con::warnf("SFXProfile::_createBuffer(%s) - Device _createBuffer from filename failed, falling back to SFXResource.", getName());*/ + + // If that failed, load through SFXResource. + if (!buffer) + { + if (!SFXResource::exists(mFilename)) + { + Con::errorf("SFXProfile::_createBuffer(%s) - SFXResource::exists() returned false for '%s'", getName(), mFilename); + return NULL; } + + Resource< SFXResource >& resource = getResource(); + if (resource == NULL) + { + Con::errorf("SFXProfile::_createBuffer(%s) - getResource() returned NULL for '%s'", getName(), mFilename); + return NULL; + } + + ThreadSafeRef< SFXStream > sfxStream = resource->openStream(); + if (!sfxStream) + { + Con::errorf("SFXProfile::_createBuffer(%s) - openStream() returned NULL for '%s'", getName(), mFilename); + return NULL; + } + + buffer = SFX->_createBuffer(sfxStream, mDescription); + if (!buffer) + Con::errorf("SFXProfile::_createBuffer(%s) - Device _createBuffer from stream also failed for '%s'", getName(), mFilename); } return buffer; diff --git a/Engine/source/sfx/sfxResource.cpp b/Engine/source/sfx/sfxResource.cpp index fa03a9a58..6f03867aa 100644 --- a/Engine/source/sfx/sfxResource.cpp +++ b/Engine/source/sfx/sfxResource.cpp @@ -79,5 +79,9 @@ bool SFXResource::exists( String filename ) ThreadSafeRef SFXResource::openStream() { - return mStream; + // Open a fresh independent stream from the file each time + ThreadSafeRef freshStream = SFXFileStream::create(mFileName); + if (!freshStream) + Con::errorf("SFXResource::openStream() - failed to reopen '%s'", mFileName.c_str()); + return freshStream; }