1/**
2 * Copyright (c) 2006-2023 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21#include "common/config.h"
22
23#include <algorithm>
24#include <sstream>
25
26#include "Sound.h"
27
28#include "ModPlugDecoder.h"
29#include "VorbisDecoder.h"
30#include "GmeDecoder.h"
31#include "WaveDecoder.h"
32#include "FLACDecoder.h"
33
34#ifndef LOVE_NOMPG123
35# include "Mpg123Decoder.h"
36#endif // LOVE_NOMPG123
37
38#ifdef LOVE_SUPPORT_COREAUDIO
39# include "CoreAudioDecoder.h"
40#endif
41
42struct DecoderImpl
43{
44 love::sound::Decoder *(*create)(love::filesystem::FileData *data, int bufferSize);
45 bool (*accepts)(const std::string& ext);
46};
47
48template<typename DecoderType>
49DecoderImpl DecoderImplFor()
50{
51 DecoderImpl decoderImpl;
52 decoderImpl.create = [](love::filesystem::FileData *data, int bufferSize) -> love::sound::Decoder*
53 {
54 return new DecoderType(data, bufferSize);
55 };
56 decoderImpl.accepts = [](const std::string& ext) -> bool
57 {
58 return DecoderType::accepts(ext);
59 };
60 return decoderImpl;
61}
62
63namespace love
64{
65namespace sound
66{
67namespace lullaby
68{
69
70Sound::Sound()
71{
72}
73
74Sound::~Sound()
75{
76#ifndef LOVE_NOMPG123
77 Mpg123Decoder::quit();
78#endif // LOVE_NOMPG123
79}
80
81const char *Sound::getName() const
82{
83 return "love.sound.lullaby";
84}
85
86sound::Decoder *Sound::newDecoder(love::filesystem::FileData *data, int bufferSize)
87{
88 std::string ext = data->getExtension();
89 std::transform(ext.begin(), ext.end(), ext.begin(), tolower);
90
91 std::vector<DecoderImpl> possibleDecoders = {
92#ifndef LOVE_NO_MODPLUG
93 DecoderImplFor<ModPlugDecoder>(),
94#endif // LOVE_NO_MODPLUG
95#ifndef LOVE_NOMPG123
96 DecoderImplFor<Mpg123Decoder>(),
97#endif // LOVE_NOMPG123
98 DecoderImplFor<VorbisDecoder>(),
99#ifdef LOVE_SUPPORT_GME
100 DecoderImplFor<GmeDecoder>(),
101#endif // LOVE_SUPPORT_GME
102#ifdef LOVE_SUPPORT_COREAUDIO
103 DecoderImplFor<CoreAudioDecoder>(),
104#endif
105 DecoderImplFor<WaveDecoder>(),
106 DecoderImplFor<FLACDecoder>(),
107 // DecoderImplFor<OtherDecoder>(),
108 };
109
110 // First find a matching decoder based on extension
111 for (DecoderImpl &possibleDecoder : possibleDecoders)
112 {
113 if (possibleDecoder.accepts(ext))
114 return possibleDecoder.create(data, bufferSize);
115 }
116
117 // If that fails, start probing instead
118 std::stringstream decodingErrors;
119 decodingErrors << "Failed to determine file type:\n";
120 for (DecoderImpl &possibleDecoder : possibleDecoders)
121 {
122 try
123 {
124 sound::Decoder *decoder = possibleDecoder.create(data, bufferSize);
125 return decoder;
126 }
127 catch (love::Exception &e)
128 {
129 decodingErrors << e.what() << '\n';
130 }
131 }
132
133 // Probing failed too, bail with the accumulated errors
134 throw love::Exception(decodingErrors.str().c_str());
135
136 // Unreachable, but here to prevent (possible) warnings
137 return nullptr;
138}
139
140} // lullaby
141} // sound
142} // love
143