1 // Copyright 2021 Jean Pierre Cimalando
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 // SPDX-License-Identifier: Apache-2.0
18 #include "ysfx_audio_flac.hpp"
19 #include "ysfx_utils.hpp"
24 # pragma GCC diagnostic push
25 # pragma GCC diagnostic ignored "-Wunused-function"
28 #define DR_FLAC_IMPLEMENTATION
29 #define DRFLAC_API static
30 #define DRFLAC_PRIVATE static
34 # pragma GCC diagnostic pop
37 struct drflac_u_deleter
{
38 void operator()(drflac
*x
) const noexcept
{ drflac_close(x
); }
40 using drflac_u
= std::unique_ptr
<drflac
, drflac_u_deleter
>;
43 struct ysfx_flac_reader_t
{
46 std::unique_ptr
<float[]> buff
;
49 static bool ysfx_flac_can_handle(const char *path
)
51 return ysfx::path_has_suffix(path
, "flac");
54 static ysfx_audio_reader_t
*ysfx_flac_open(const char *path
)
57 drflac_u flac
{drflac_open_file(path
, NULL
)};
59 drflac_u flac
{drflac_open_file_w(ysfx::widen(path
).c_str(), NULL
)};
63 std::unique_ptr
<ysfx_flac_reader_t
> reader
{new ysfx_flac_reader_t
};
64 reader
->flac
= std::move(flac
);
65 reader
->buff
.reset(new float[reader
->flac
->channels
]);
66 return (ysfx_audio_reader_t
*)reader
.release();
69 static void ysfx_flac_close(ysfx_audio_reader_t
*reader_
)
71 ysfx_flac_reader_t
*reader
= (ysfx_flac_reader_t
*)reader_
;
75 static ysfx_audio_file_info_t
ysfx_flac_info(ysfx_audio_reader_t
*reader_
)
77 ysfx_flac_reader_t
*reader
= (ysfx_flac_reader_t
*)reader_
;
78 ysfx_audio_file_info_t info
;
79 info
.channels
= reader
->flac
->channels
;
80 info
.sample_rate
= (ysfx_real
)reader
->flac
->sampleRate
;
84 static uint64_t ysfx_flac_avail(ysfx_audio_reader_t
*reader_
)
86 ysfx_flac_reader_t
*reader
= (ysfx_flac_reader_t
*)reader_
;
87 return reader
->nbuff
+ reader
->flac
->channels
* (reader
->flac
->totalPCMFrameCount
- reader
->flac
->currentPCMFrame
);
90 static void ysfx_flac_rewind(ysfx_audio_reader_t
*reader_
)
92 ysfx_flac_reader_t
*reader
= (ysfx_flac_reader_t
*)reader_
;
93 drflac_seek_to_pcm_frame(reader
->flac
.get(), 0);
97 static uint64_t ysfx_flac_unload_buffer(ysfx_audio_reader_t
*reader_
, ysfx_real
*samples
, uint64_t count
)
99 ysfx_flac_reader_t
*reader
= (ysfx_flac_reader_t
*)reader_
;
101 uint32_t nbuff
= reader
->nbuff
;
103 nbuff
= (uint32_t)count
;
108 const float *src
= &reader
->buff
[reader
->flac
->channels
- reader
->nbuff
];
109 for (uint32_t i
= 0; i
< nbuff
; ++i
)
112 reader
->nbuff
-= nbuff
;
116 static uint64_t ysfx_flac_read(ysfx_audio_reader_t
*reader_
, ysfx_real
*samples
, uint64_t count
)
118 ysfx_flac_reader_t
*reader
= (ysfx_flac_reader_t
*)reader_
;
119 uint32_t channels
= reader
->flac
->channels
;
120 uint64_t readtotal
= 0;
125 uint64_t copied
= ysfx_flac_unload_buffer(reader_
, samples
, count
);
134 float *f32buf
= (float *)samples
;
135 uint64_t readframes
= drflac_read_pcm_frames_f32(reader
->flac
.get(), count
/ channels
, f32buf
);
136 uint64_t readsamples
= channels
* readframes
;
138 for (uint64_t i
= readsamples
; i
-- > 0; )
139 samples
[i
] = f32buf
[i
];
140 samples
+= readsamples
;
141 count
-= readsamples
;
142 readtotal
+= readsamples
;
147 else if (drflac_read_pcm_frames_f32(reader
->flac
.get(), 1, reader
->buff
.get()) == 1) {
148 reader
->nbuff
= channels
;
149 uint64_t copied
= ysfx_flac_unload_buffer(reader_
, samples
, count
);
158 const ysfx_audio_format_t ysfx_audio_format_flac
= {
159 &ysfx_flac_can_handle
,