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#define DR_FLAC_IMPLEMENTATION
22#include "FLACDecoder.h"
23
24#include <set>
25#include "common/Exception.h"
26
27namespace love
28{
29namespace sound
30{
31namespace lullaby
32{
33
34FLACDecoder::FLACDecoder(Data *data, int nbufferSize)
35: Decoder(data, nbufferSize)
36{
37 flac = drflac_open_memory(data->getData(), data->getSize(), nullptr);
38 if (flac == nullptr)
39 throw love::Exception("Could not load FLAC file");
40}
41
42FLACDecoder::~FLACDecoder()
43{
44 drflac_close(flac);
45}
46
47bool FLACDecoder::accepts(const std::string &ext)
48{
49 // dr_flac supports FLAC encapsulated in Ogg, but unfortunately
50 // LOVE detects .ogg extension as Vorbis. It would be a good idea
51 // to always probe in the future (see #1487 and commit ccf9e63).
52 // Please remove once it's no longer the case.
53 static const std::string supported[] =
54 {
55 "flac", "ogg", ""
56 };
57
58 for (int i = 0; !(supported[i].empty()); i++)
59 {
60 if (supported[i].compare(ext) == 0)
61 return true;
62 }
63
64 return false;
65}
66
67love::sound::Decoder *FLACDecoder::clone()
68{
69 return new FLACDecoder(data.get(), bufferSize);
70}
71
72int FLACDecoder::decode()
73{
74 // `bufferSize` is in bytes, so divide by 2.
75 drflac_uint64 read = drflac_read_pcm_frames_s16(flac, bufferSize / 2 / flac->channels, (drflac_int16 *) buffer);
76 read *= 2 * flac->channels;
77
78 if ((int) read < bufferSize)
79 eof = true;
80
81 return (int) read;
82}
83
84bool FLACDecoder::seek(double s)
85{
86 drflac_uint64 seekPosition = (drflac_uint64) (s * flac->sampleRate);
87
88 drflac_bool32 result = drflac_seek_to_pcm_frame(flac, seekPosition);
89 if (result)
90 eof = false;
91
92 return result;
93}
94
95bool FLACDecoder::rewind()
96{
97 return seek(0);
98}
99
100bool FLACDecoder::isSeekable()
101{
102 return true;
103}
104
105int FLACDecoder::getChannelCount() const
106{
107 return flac->channels;
108}
109
110int FLACDecoder::getBitDepth() const
111{
112 return 16;
113}
114
115int FLACDecoder::getSampleRate() const
116{
117 return flac->sampleRate;
118}
119
120double FLACDecoder::getDuration()
121{
122 return ((double) flac->totalPCMFrameCount) / ((double) flac->sampleRate);
123}
124
125} // lullaby
126} // sound
127} // love
128