Cleanup
[carla.git] / source / modules / ysfx / sources / ysfx_audio_flac.cpp
blob35c6e329c097605768db47ae2b491aa9fe85643a
1 // Copyright 2021 Jean Pierre Cimalando
2 //
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
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
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"
20 #include <memory>
21 #include <cstring>
23 #if defined(__GNUC__)
24 # pragma GCC diagnostic push
25 # pragma GCC diagnostic ignored "-Wunused-function"
26 #endif
28 #define DR_FLAC_IMPLEMENTATION
29 #define DRFLAC_API static
30 #define DRFLAC_PRIVATE static
31 #include "dr_flac.h"
33 #if defined(__GNUC__)
34 # pragma GCC diagnostic pop
35 #endif
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>;
42 ///
43 struct ysfx_flac_reader_t {
44 drflac_u flac;
45 uint32_t nbuff = 0;
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)
56 #if !defined(_WIN32)
57 drflac_u flac{drflac_open_file(path, NULL)};
58 #else
59 drflac_u flac{drflac_open_file_w(ysfx::widen(path).c_str(), NULL)};
60 #endif
61 if (!flac)
62 return nullptr;
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_;
72 delete 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;
81 return info;
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);
94 reader->nbuff = 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;
102 if (nbuff > count)
103 nbuff = (uint32_t)count;
105 if (nbuff == 0)
106 return 0;
108 const float *src = &reader->buff[reader->flac->channels - reader->nbuff];
109 for (uint32_t i = 0; i < nbuff; ++i)
110 samples[i] = src[i];
112 reader->nbuff -= nbuff;
113 return 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;
122 if (count == 0)
123 return readtotal;
124 else {
125 uint64_t copied = ysfx_flac_unload_buffer(reader_, samples, count);
126 samples += copied;
127 count -= copied;
128 readtotal += copied;
131 if (count == 0)
132 return readtotal;
133 else {
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;
137 // f32->f64
138 for (uint64_t i = readsamples; i-- > 0; )
139 samples[i] = f32buf[i];
140 samples += readsamples;
141 count -= readsamples;
142 readtotal += readsamples;
145 if (count == 0)
146 return readtotal;
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);
150 samples += copied;
151 count -= copied;
152 readtotal += copied;
155 return readtotal;
158 const ysfx_audio_format_t ysfx_audio_format_flac = {
159 &ysfx_flac_can_handle,
160 &ysfx_flac_open,
161 &ysfx_flac_close,
162 &ysfx_flac_info,
163 &ysfx_flac_avail,
164 &ysfx_flac_rewind,
165 &ysfx_flac_read,