10 #define MINIMP3_IMPLEMENTATION
11 #define MINIMP3_FLOAT_OUTPUT
16 constexpr size_t MinMp3DataSize
= 16384;
17 constexpr size_t MaxMp3DataSize
= MinMp3DataSize
* 8;
19 size_t append_file_data(std::istream
&file
, alure::Vector
<uint8_t> &data
, size_t count
)
21 size_t old_size
= data
.size();
22 if(old_size
>= MaxMp3DataSize
|| count
== 0)
24 count
= std::min(count
, MaxMp3DataSize
- old_size
);
25 data
.resize(old_size
+ count
);
28 file
.read(reinterpret_cast<char*>(data
.data()+old_size
), count
);
29 size_t got
= file
.gcount();
30 data
.resize(old_size
+ got
);
35 size_t find_i3dv2(alure::ArrayView
<uint8_t> data
)
37 if(data
.size() > 10 && memcmp(data
.data(), "ID3", 3) == 0)
38 return (((data
[6]&0x7f) << 21) | ((data
[7]&0x7f) << 14) |
39 ((data
[8]&0x7f) << 7) | ((data
[9]&0x7f) )) + 10;
43 int decode_frame(std::istream
&file
, mp3dec_t
&mp3
, alure::Vector
<uint8_t> &file_data
,
44 float *sample_data
, mp3dec_frame_info_t
*frame_info
)
46 if(file_data
.size() < MinMp3DataSize
&& !file
.eof())
48 size_t todo
= MinMp3DataSize
- file_data
.size();
49 append_file_data(file
, file_data
, todo
);
52 int samples_to_get
= mp3dec_decode_frame(&mp3
, file_data
.data(), file_data
.size(),
53 sample_data
, frame_info
);
54 while(samples_to_get
== 0 && !file
.eof())
56 if(append_file_data(file
, file_data
, MinMp3DataSize
) == 0)
58 samples_to_get
= mp3dec_decode_frame(&mp3
, file_data
.data(), file_data
.size(),
59 sample_data
, frame_info
);
61 return samples_to_get
;
69 class Mp3Decoder final
: public Decoder
{
70 UniquePtr
<std::istream
> mFile
;
72 Vector
<uint8_t> mFileData
;
75 Vector
<float> mSampleData
;
76 mp3dec_frame_info_t mLastFrame
{};
77 mutable std::mutex mMutex
;
79 mutable std::streamsize mSampleCount
{-1};
80 ChannelConfig mChannels
{ChannelConfig::Mono
};
81 SampleType mSampleType
{SampleType::UInt8
};
85 Mp3Decoder(UniquePtr
<std::istream
> file
, Vector
<uint8_t>&& initial_data
,
86 const mp3dec_t
&mp3
, const mp3dec_frame_info_t
&first_frame
,
87 ChannelConfig chans
, SampleType stype
, int srate
) noexcept
88 : mFile(std::move(file
)), mFileData(std::move(initial_data
)), mMp3(mp3
)
89 , mLastFrame(first_frame
), mChannels(chans
), mSampleType(stype
), mSampleRate(srate
)
91 ~Mp3Decoder() override
{ }
93 ALuint
getFrequency() const noexcept override
;
94 ChannelConfig
getChannelConfig() const noexcept override
;
95 SampleType
getSampleType() const noexcept override
;
97 uint64_t getLength() const noexcept override
;
98 bool seek(uint64_t pos
) noexcept override
;
100 std::pair
<uint64_t,uint64_t> getLoopPoints() const noexcept override
;
102 ALuint
read(ALvoid
*ptr
, ALuint count
) noexcept override
;
105 ALuint
Mp3Decoder::getFrequency() const noexcept
{ return mSampleRate
; }
106 ChannelConfig
Mp3Decoder::getChannelConfig() const noexcept
{ return mChannels
; }
107 SampleType
Mp3Decoder::getSampleType() const noexcept
{ return mSampleType
; }
109 uint64_t Mp3Decoder::getLength() const noexcept
111 if(LIKELY(mSampleCount
>= 0))
114 std::lock_guard
<std::mutex
> _(mMutex
);
117 std::streamsize oldfpos
= mFile
->tellg();
118 if(oldfpos
< 0 || !mFile
->seekg(0))
124 Vector
<uint8_t> file_data
;
129 append_file_data(*mFile
, file_data
, MinMp3DataSize
);
131 size_t id_size
= find_i3dv2(file_data
);
134 if(id_size
<= file_data
.size())
135 file_data
.erase(file_data
.begin(), file_data
.begin()+id_size
);
138 mFile
->ignore(id_size
- file_data
.size());
143 std::streamsize count
= 0;
145 // Read the next frame.
146 mp3dec_frame_info_t frame_info
{};
147 int samples_to_get
= decode_frame(*mFile
, mp3
, file_data
, nullptr, &frame_info
);
148 if(samples_to_get
<= 0) break;
150 // Don't continue if the frame changed format
151 if((mChannels
== ChannelConfig::Mono
&& frame_info
.channels
!= 1) ||
152 (mChannels
== ChannelConfig::Stereo
&& frame_info
.channels
!= 2) ||
153 mSampleRate
!= frame_info
.hz
)
156 // Keep going to the next frame
157 if(file_data
.size() >= (size_t)frame_info
.frame_bytes
)
158 file_data
.erase(file_data
.begin(), file_data
.begin()+frame_info
.frame_bytes
);
161 mFile
->ignore(frame_info
.frame_bytes
- file_data
.size());
164 count
+= samples_to_get
;
166 mSampleCount
= count
;
169 mFile
->seekg(oldfpos
);
173 bool Mp3Decoder::seek(uint64_t pos
) noexcept
175 // Use temporary local storage to avoid trashing current data in case of
177 Vector
<uint8_t> file_data
;
182 // Seeking to somewhere in the file. Backup the current file position and
183 // reset back to the beginning.
184 // TODO: Obvious optimization: Track the current sample offset and don't
185 // rewind if seeking forward.
187 std::streamsize oldfpos
= mFile
->tellg();
188 if(oldfpos
< 0 || !mFile
->seekg(0))
191 append_file_data(*mFile
, file_data
, MinMp3DataSize
);
193 size_t id_size
= find_i3dv2(file_data
);
196 if(id_size
<= file_data
.size())
197 file_data
.erase(file_data
.begin(), file_data
.begin()+id_size
);
200 mFile
->ignore(id_size
- file_data
.size());
207 // Read the next frame.
208 mp3dec_frame_info_t frame_info
{};
209 int samples_to_get
= decode_frame(*mFile
, mp3
, file_data
, nullptr, &frame_info
);
210 if(samples_to_get
<= 0) break;
212 // Don't continue if the frame changed format
213 if((mChannels
== ChannelConfig::Mono
&& frame_info
.channels
!= 1) ||
214 (mChannels
== ChannelConfig::Stereo
&& frame_info
.channels
!= 2) ||
215 mSampleRate
!= frame_info
.hz
)
218 if((uint64_t)samples_to_get
> pos
- curpos
)
220 // Desired sample is within this frame, decode the samples and go
221 // to the desired offset.
222 Vector
<float> sample_data(MINIMP3_MAX_SAMPLES_PER_FRAME
);
223 samples_to_get
= decode_frame(*mFile
, mp3
, file_data
, sample_data
.data(), &frame_info
);
225 if((uint64_t)samples_to_get
> pos
- curpos
)
227 sample_data
.resize(samples_to_get
* frame_info
.channels
);
228 sample_data
.erase(sample_data
.begin(),
229 sample_data
.begin() + (pos
-curpos
)*frame_info
.channels
);
230 file_data
.erase(file_data
.begin(), file_data
.begin()+frame_info
.frame_bytes
);
231 mSampleData
= std::move(sample_data
);
232 mFileData
= std::move(file_data
);
233 mLastFrame
= frame_info
;
239 // Keep going to the next frame
240 if(file_data
.size() >= (size_t)frame_info
.frame_bytes
)
241 file_data
.erase(file_data
.begin(), file_data
.begin()+frame_info
.frame_bytes
);
244 mFile
->ignore(frame_info
.frame_bytes
- file_data
.size());
247 curpos
+= samples_to_get
;
250 // Seeking failed. Restore original file position.
252 mFile
->seekg(oldfpos
);
256 std::pair
<uint64_t,uint64_t> Mp3Decoder::getLoopPoints() const noexcept
258 return {0, std::numeric_limits
<uint64_t>::max()};
261 ALuint
Mp3Decoder::read(ALvoid
*ptr
, ALuint count
) noexcept
270 std::lock_guard
<std::mutex
> _(mMutex
);
273 ALuint todo
= count
-total
;
275 if(!mSampleData
.empty())
277 // Write out whatever samples we have.
278 todo
= std::min
<ALuint
>(todo
, mSampleData
.size()/mLastFrame
.channels
);
280 size_t numspl
= todo
*mLastFrame
.channels
;
281 if(mSampleType
== SampleType::Float32
)
283 std::copy(mSampleData
.begin(), mSampleData
.begin()+numspl
, dst
.f
);
288 mp3dec_f32_to_s16(mSampleData
.data(), dst
.s
, numspl
);
291 mSampleData
.erase(mSampleData
.begin(), mSampleData
.begin()+numspl
);
297 // Read directly into the output buffer if it doesn't need conversion
298 // and there's enough guaranteed room.
300 if(mSampleType
== SampleType::Float32
&&
301 todo
*mLastFrame
.channels
>= MINIMP3_MAX_SAMPLES_PER_FRAME
)
305 mSampleData
.resize(MINIMP3_MAX_SAMPLES_PER_FRAME
);
306 samples_ptr
= mSampleData
.data();
309 mp3dec_frame_info_t frame_info
{};
310 int samples_to_get
= decode_frame(*mFile
, mMp3
, mFileData
, samples_ptr
, &frame_info
);
311 if(samples_to_get
<= 0)
317 // Format changing not supported. End the stream.
318 if((mChannels
== ChannelConfig::Mono
&& frame_info
.channels
!= 1) ||
319 (mChannels
== ChannelConfig::Stereo
&& frame_info
.channels
!= 2) ||
320 mSampleRate
!= frame_info
.hz
)
326 // Remove used file data, update sample storage size with what we got
327 mFileData
.erase(mFileData
.begin(), mFileData
.begin()+frame_info
.frame_bytes
);
328 mLastFrame
= frame_info
;
329 if(!mSampleData
.empty())
330 mSampleData
.resize(samples_to_get
* frame_info
.channels
);
333 dst
.f
+= samples_to_get
* frame_info
.channels
;
334 total
+= samples_to_get
;
342 Mp3DecoderFactory::Mp3DecoderFactory() noexcept
346 Mp3DecoderFactory::~Mp3DecoderFactory()
350 SharedPtr
<Decoder
> Mp3DecoderFactory::createDecoder(UniquePtr
<std::istream
> &file
) noexcept
352 Vector
<uint8_t> initial_data
;
357 // Make sure the file is valid and we get some samples.
358 if(append_file_data(*file
, initial_data
, MinMp3DataSize
) == 0)
361 // If the file contains an ID3v2 tag, skip it.
362 // TODO: Read it? Does it have e.g. sample length or loop points?
363 size_t id_size
= find_i3dv2(initial_data
);
366 if(id_size
<= initial_data
.size())
367 initial_data
.erase(initial_data
.begin(), initial_data
.begin()+id_size
);
370 file
->ignore(id_size
- initial_data
.size());
371 initial_data
.clear();
375 mp3dec_frame_info_t frame_info
{};
376 int samples_to_get
= decode_frame(*file
, mp3
, initial_data
, nullptr, &frame_info
);
377 if(!samples_to_get
) return nullptr;
379 if(frame_info
.hz
< 1)
382 ChannelConfig chans
= ChannelConfig::Mono
;
383 if(frame_info
.channels
== 1)
384 chans
= ChannelConfig::Mono
;
385 else if(frame_info
.channels
== 2)
386 chans
= ChannelConfig::Stereo
;
390 SampleType stype
= SampleType::Int16
;
391 if(ContextImpl::GetCurrent()->isSupported(chans
, SampleType::Float32
))
392 stype
= SampleType::Float32
;
394 return MakeShared
<Mp3Decoder
>(std::move(file
), std::move(initial_data
), mp3
,
395 frame_info
, chans
, stype
, frame_info
.hz
);