1
1
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
2
2
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
3
3
4
- #define DR_MP3_IMPLEMENTATION
5
- #define DR_MP3_NO_STDIO
4
+ #define MINIMP3_IMPLEMENTATION
5
+ #define MINIMP3_NO_STDIO
6
6
7
7
#include " DecoderCommon.hpp"
8
8
#include " DecoderMP3.hpp"
9
9
#include < cstdio>
10
10
11
- namespace
12
- {
13
- signed skipID3V2TagIfPresent (std::FILE *fd)
14
- {
15
- constexpr auto ID3V2FrameOffset = 0 ;
16
- constexpr auto ID3V2FrameHeaderSize = 10 ;
17
- constexpr auto ID3V2FrameMagicString = " ID3" ;
18
- constexpr auto ID3V2FrameMagicStringLength = 3 ;
19
- std::uint8_t frameBuffer[ID3V2FrameHeaderSize];
20
-
21
- /* Seek to the beginning of the frame and read frame's header */
22
- if (std::fseek (fd, ID3V2FrameOffset, SEEK_SET) != 0 ) {
23
- return -EIO;
24
- }
25
- if (std::fread (frameBuffer, sizeof (*frameBuffer), ID3V2FrameHeaderSize, fd) != ID3V2FrameHeaderSize) {
26
- return -EIO;
27
- }
28
-
29
- /* Check magic */
30
- if (strncmp (reinterpret_cast <const char *>(frameBuffer), ID3V2FrameMagicString, ID3V2FrameMagicStringLength) !=
31
- 0 ) {
32
- return 0 ;
33
- }
34
-
35
- /* The tag size (minus the 10-byte header) is encoded into four bytes,
36
- * but the most significant bit needs to be masked in each byte.
37
- * Those frame indices are just copied from the ID3V2 docs. */
38
- const auto ID3V2TagTotalSize = (((frameBuffer[6 ] & 0x7F ) << 21 ) | ((frameBuffer[7 ] & 0x7F ) << 14 ) |
39
- ((frameBuffer[8 ] & 0x7F ) << 7 ) | ((frameBuffer[9 ] & 0x7F ) << 0 )) +
40
- ID3V2FrameHeaderSize;
41
-
42
- /* Skip the tag */
43
- if (std::fseek (fd, ID3V2FrameOffset + ID3V2TagTotalSize, SEEK_SET) != 0 ) {
44
- return -EIO;
45
- }
46
- return ID3V2TagTotalSize;
47
- }
48
- } // namespace
49
-
50
11
namespace audio
51
12
{
52
- DecoderMP3::DecoderMP3 (const std::string &filePath) : Decoder(filePath), mp3(std::make_unique<drmp3>())
13
+ DecoderMP3::DecoderMP3 (const std::string &filePath)
14
+ : Decoder(filePath), dec(std::make_unique<mp3dec_ex_t >()), io(std::make_unique<mp3dec_io_t >())
53
15
{
54
16
if (fileSize == 0 ) {
55
17
return ;
56
18
}
57
19
58
- const auto tagSkipStatus = skipID3V2TagIfPresent (fd);
59
- if (tagSkipStatus < 0 ) {
60
- LOG_ERROR (" Failed to skip ID3V2 tag, error %d" , tagSkipStatus);
61
- }
62
- else if (tagSkipStatus == 0 ) {
63
- LOG_INFO (" No ID3V2 tag to skip" );
64
- }
20
+ io->read = mp3Read;
21
+ io->read_data = this ;
22
+ io->seek = mp3Seek;
23
+ io->seek_data = this ;
24
+ dec->io = io.get ();
65
25
66
- if (drmp3_init (mp3 .get (), drmp3Read, drmp3Seek, this , nullptr ) == DRMP3_FALSE ) {
67
- LOG_ERROR (" Unable to initialize MP3 decoder " );
26
+ if (mp3dec_ex_open_cb (dec .get (), dec-> io , MP3D_SEEK_TO_SAMPLE) ) {
27
+ LOG_ERROR (" Failed to open minimp3 " );
68
28
return ;
69
29
}
70
30
71
31
/* NOTE: Always convert to S16LE as an internal format */
72
- channelCount = mp3-> channels ;
73
- sampleRate = mp3-> sampleRate ;
32
+ channelCount = dec-> info . channels ;
33
+ sampleRate = dec-> info . hz ;
74
34
bitsPerSample = 16 ;
75
35
isInitialized = true ;
76
36
}
@@ -80,7 +40,7 @@ namespace audio
80
40
if (!isInitialized) {
81
41
return ;
82
42
}
83
- drmp3_uninit (mp3 .get ());
43
+ mp3dec_ex_close (dec .get ());
84
44
isInitialized = false ;
85
45
}
86
46
@@ -90,18 +50,16 @@ namespace audio
90
50
LOG_ERROR (" MP3 decoder not initialized" );
91
51
return ;
92
52
}
93
- const auto totalFramesCount = drmp3_get_pcm_frame_count (mp3.get ());
94
- drmp3_seek_to_pcm_frame (mp3.get (), totalFramesCount * pos);
95
- position = static_cast <float >(totalFramesCount) * pos / static_cast <float >(sampleRate);
53
+ mp3dec_ex_seek (dec.get (), pos);
96
54
}
97
55
98
56
std::int32_t DecoderMP3::decode (std::uint32_t samplesToRead, std::int16_t *pcmData)
99
57
{
100
- const auto samplesRead = drmp3_read_pcm_frames_s16 (
101
- mp3.get (), samplesToRead / channelCount, reinterpret_cast <drmp3_int16 *>(pcmData));
58
+ const auto samplesRead = mp3dec_ex_read (dec.get (), reinterpret_cast <mp3d_sample_t *>(pcmData), samplesToRead);
102
59
if (samplesRead > 0 ) {
103
60
/* Calculate frame duration in seconds */
104
- position += static_cast <float >(samplesRead) / static_cast <float >(sampleRate);
61
+ const auto samplesPerChannel = static_cast <float >(samplesRead) / static_cast <float >(channelCount);
62
+ position += samplesPerChannel / static_cast <float >(sampleRate);
105
63
}
106
64
else if (!fileExists (fd)) {
107
65
/* Unfortunately this second check of file existence is needed
@@ -110,10 +68,10 @@ namespace audio
110
68
LOG_WARN (" File '%s' was deleted during playback!" , filePath.c_str ());
111
69
return fileDeletedRetCode;
112
70
}
113
- return samplesRead * channelCount ;
71
+ return samplesRead;
114
72
}
115
73
116
- std::size_t DecoderMP3::drmp3Read (void *pUserData, void * pBufferOut, std::size_t bytesToRead)
74
+ std::size_t DecoderMP3::mp3Read (void *pBufferOut, std::size_t bytesToRead, void *pUserData )
117
75
{
118
76
const auto decoderContext = reinterpret_cast <DecoderMP3 *>(pUserData);
119
77
@@ -126,11 +84,9 @@ namespace audio
126
84
return std::fread (pBufferOut, 1 , bytesToRead, decoderContext->fd );
127
85
}
128
86
129
- drmp3_bool32 DecoderMP3::drmp3Seek ( void *pUserData, int offset, drmp3_seek_origin origin )
87
+ int DecoderMP3::mp3Seek (std:: uint64_t offset, void *pUserData )
130
88
{
131
89
const auto decoderContext = reinterpret_cast <DecoderMP3 *>(pUserData);
132
- const auto seekError =
133
- std::fseek (decoderContext->fd , offset, origin == drmp3_seek_origin_start ? SEEK_SET : SEEK_CUR);
134
- return (seekError == 0 ) ? DRMP3_TRUE : DRMP3_FALSE;
90
+ return std::fseek (decoderContext->fd , offset, SEEK_SET);
135
91
}
136
92
} // namespace audio
0 commit comments