diff --git a/changes.txt b/changes.txt index 3bfc063d4..efca25435 100644 --- a/changes.txt +++ b/changes.txt @@ -8,6 +8,8 @@ Released: N/A * Added love.window.get/setVSync, to allow setting vsync without recreating the window. * Added love.window.getSafeArea, currently only fully implemented on iOS. +* Changed audio file type detection, so it probes all supported backends for unrecognized extensions. + * Fixed the deprecation system not fully restarting when love.event.quit("restart") is used. * Fixed love.math.hash returning an incorrect hash for certain input sizes. * Fixed t.audio.mixwithsystem. diff --git a/src/modules/sound/lullaby/Sound.cpp b/src/modules/sound/lullaby/Sound.cpp index 2c77165a1..64e205490 100644 --- a/src/modules/sound/lullaby/Sound.cpp +++ b/src/modules/sound/lullaby/Sound.cpp @@ -21,6 +21,7 @@ #include "common/config.h" #include +#include #include "Sound.h" @@ -38,6 +39,27 @@ # include "CoreAudioDecoder.h" #endif +struct DecoderImpl +{ + love::sound::Decoder *(*create)(love::filesystem::FileData *data, int bufferSize); + bool (*accepts)(const std::string& ext); +}; + +template +DecoderImpl DecoderImplFor() +{ + DecoderImpl decoderImpl; + decoderImpl.create = [](love::filesystem::FileData *data, int bufferSize) -> love::sound::Decoder* + { + return new DecoderType(data, bufferSize); + }; + decoderImpl.accepts = [](const std::string& ext) -> bool + { + return DecoderType::accepts(ext); + }; + return decoderImpl; +} + namespace love { namespace sound @@ -66,37 +88,53 @@ sound::Decoder *Sound::newDecoder(love::filesystem::FileData *data, int bufferSi std::string ext = data->getExtension(); std::transform(ext.begin(), ext.end(), ext.begin(), tolower); - sound::Decoder *decoder = nullptr; - - // Find a suitable decoder here, and return it. - if (false) - /* nothing */; + std::vector possibleDecoders = { #ifndef LOVE_NO_MODPLUG - else if (ModPlugDecoder::accepts(ext)) - decoder = new ModPlugDecoder(data, bufferSize); + DecoderImplFor(), #endif // LOVE_NO_MODPLUG #ifndef LOVE_NOMPG123 - else if (Mpg123Decoder::accepts(ext)) - decoder = new Mpg123Decoder(data, bufferSize); + DecoderImplFor(), #endif // LOVE_NOMPG123 - else if (VorbisDecoder::accepts(ext)) - decoder = new VorbisDecoder(data, bufferSize); + DecoderImplFor(), #ifdef LOVE_SUPPORT_GME - else if (GmeDecoder::accepts(ext)) - decoder = new GmeDecoder(data, bufferSize); + DecoderImplFor(), #endif // LOVE_SUPPORT_GME #ifdef LOVE_SUPPORT_COREAUDIO - else if (CoreAudioDecoder::accepts(ext)) - decoder = new CoreAudioDecoder(data, bufferSize); + DecoderImplFor(), #endif - else if (WaveDecoder::accepts(ext)) - decoder = new WaveDecoder(data, bufferSize); - /*else if (FLACDecoder::accepts(ext)) - decoder = new FLACDecoder(data, bufferSize);*/ + DecoderImplFor(), + // DecoderImplFor(), + // DecoderImplFor(), + }; - // else if (OtherDecoder::accept(ext)) + // First find a matching decoder based on extension + for (DecoderImpl &possibleDecoder : possibleDecoders) + { + if (possibleDecoder.accepts(ext)) + return possibleDecoder.create(data, bufferSize); + } - return decoder; + // If that fails, start probing instead + std::stringstream decodingErrors; + decodingErrors << "Failed to determine file type:\n"; + for (DecoderImpl &possibleDecoder : possibleDecoders) + { + try + { + sound::Decoder *decoder = possibleDecoder.create(data, bufferSize); + return decoder; + } + catch (love::Exception &e) + { + decodingErrors << e.what() << '\n'; + } + } + + // Probing failed too, bail with the accumulated errors + throw love::Exception(decodingErrors.str().c_str()); + + // Unreachable, but here to prevent (possible) warnings + return nullptr; } } // lullaby