audiofile-impl.cpp (12927B)
1 /** @addtogroup io 2 * @{ 3 */ 4 /* 5 Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) 6 This file is part of KFR 7 8 KFR is free software: you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation, either version 2 of the License, or 11 (at your option) any later version. 12 13 KFR is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with KFR. 20 21 If GPL is not suitable for your project, you must purchase a commercial license to use KFR. 22 Buying a commercial license is mandatory as soon as you develop commercial activities without 23 disclosing the source code of your own applications. 24 See https://www.kfrlib.com for details. 25 */ 26 27 #include <kfr/io/audiofile.hpp> 28 CMT_PRAGMA_GNU(GCC diagnostic push) 29 CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wimplicit-fallthrough") 30 CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wunused-function") 31 32 #ifndef KFR_DISABLE_WAV 33 #define DR_WAV_NO_STDIO 34 #define DR_WAV_NO_CONVERSION_API 35 #define DR_WAV_IMPLEMENTATION 36 #include "dr/dr_wav.h" 37 #endif 38 #ifndef KFR_DISABLE_FLAC 39 #define DR_FLAC_IMPLEMENTATION 40 #define DR_FLAC_NO_STDIO 41 #ifndef CMT_ARCH_SSE41 42 #define DRFLAC_NO_SSE41 43 #endif 44 #include "dr/dr_flac.h" 45 #endif 46 #ifndef KFR_DISABLE_MP3 47 #define DR_MP3_IMPLEMENTATION 48 #define DR_MP3_NO_STDIO 49 #include "dr/dr_mp3.h" 50 #endif 51 52 namespace kfr 53 { 54 55 namespace internal_generic 56 { 57 #ifndef KFR_DISABLE_WAV 58 size_t drwav_writer_write_proc(abstract_writer<void>* file, const void* pData, size_t bytesToWrite) 59 { 60 return file->write(pData, bytesToWrite); 61 } 62 drwav_bool32 drwav_writer_seek_proc(abstract_writer<void>* file, int offset, drwav_seek_origin origin) 63 { 64 return file->seek(offset, origin == drwav_seek_origin_start ? seek_origin::begin : seek_origin::current); 65 } 66 size_t drwav_reader_read_proc(abstract_reader<void>* file, void* pBufferOut, size_t bytesToRead) 67 { 68 return file->read(pBufferOut, bytesToRead); 69 } 70 drwav_bool32 drwav_reader_seek_proc(abstract_reader<void>* file, int offset, drwav_seek_origin origin) 71 { 72 return file->seek(offset, origin == drwav_seek_origin_start ? seek_origin::begin : seek_origin::current); 73 } 74 #endif 75 #ifndef KFR_DISABLE_FLAC 76 size_t drflac_reader_read_proc(abstract_reader<void>* file, void* pBufferOut, size_t bytesToRead) 77 { 78 return file->read(pBufferOut, bytesToRead); 79 } 80 drflac_bool32 drflac_reader_seek_proc(abstract_reader<void>* file, int offset, drflac_seek_origin origin) 81 { 82 return file->seek(offset, origin == drflac_seek_origin_start ? seek_origin::begin : seek_origin::current); 83 } 84 #endif 85 #ifndef KFR_DISABLE_MP3 86 size_t drmp3_reader_read_proc(abstract_reader<void>* file, void* pBufferOut, size_t bytesToRead) 87 { 88 return file->read(pBufferOut, bytesToRead); 89 } 90 drmp3_bool32 drmp3_reader_seek_proc(abstract_reader<void>* file, int offset, drmp3_seek_origin origin) 91 { 92 return file->seek(offset, origin == drmp3_seek_origin_start ? seek_origin::begin : seek_origin::current); 93 } 94 #endif 95 96 struct wav_file : drwav 97 { 98 }; 99 struct flac_file : drflac 100 { 101 }; 102 struct mp3_file : drmp3 103 { 104 }; 105 106 void wav_file_deleter::operator()(wav_file* f) 107 { 108 drwav_uninit(f); 109 delete f; 110 } 111 112 void flac_file_deleter::operator()(flac_file* f) 113 { 114 drflac_close(f); 115 } 116 void mp3_file_deleter::operator()(mp3_file* f) 117 { 118 drmp3_uninit(f); 119 delete f; 120 } 121 122 } // namespace internal_generic 123 124 template <typename T> 125 audio_writer_wav<T>::audio_writer_wav(std::shared_ptr<abstract_writer<>>&& writer, const audio_format& fmt) 126 : writer(std::move(writer)), fmt(fmt) 127 { 128 drwav_data_format wav_fmt; 129 wav_fmt.channels = static_cast<drwav_uint32>(fmt.channels); 130 wav_fmt.sampleRate = static_cast<drwav_uint32>(fmt.samplerate); 131 wav_fmt.format = 132 fmt.type >= audio_sample_type::first_float ? DR_WAVE_FORMAT_IEEE_FLOAT : DR_WAVE_FORMAT_PCM; 133 wav_fmt.bitsPerSample = static_cast<drwav_uint32>(audio_sample_bit_depth(fmt.type)); 134 wav_fmt.container = fmt.use_w64 ? drwav_container_w64 : drwav_container_riff; 135 f.reset(new internal_generic::wav_file()); 136 if (!drwav_init_write(f.get(), &wav_fmt, (drwav_write_proc)&internal_generic::drwav_writer_write_proc, 137 (drwav_seek_proc)&internal_generic::drwav_writer_seek_proc, this->writer.get(), 138 nullptr)) 139 { 140 delete f.release(); 141 } 142 } 143 144 template <typename T> 145 size_t audio_writer_wav<T>::write(const T* data, size_t size) 146 { 147 if (!f) 148 return 0; 149 if (fmt.type == audio_sample_type::unknown) 150 return 0; 151 if (fmt.type == audio_sample_traits<T>::type) 152 { 153 const size_t sz = drwav_write_pcm_frames_le(f.get(), size, data); 154 fmt.length += sz; 155 return sz * fmt.channels; 156 } 157 else 158 { 159 univector<uint8_t> native(size * audio_sample_sizeof(fmt.type)); 160 convert(native.data(), fmt.type, data, size); 161 const size_t sz = drwav_write_pcm_frames_le(f.get(), size / fmt.channels, native.data()); 162 fmt.length += sz; 163 return sz * fmt.channels; 164 } 165 } 166 167 template <typename T> 168 audio_writer_wav<T>::~audio_writer_wav() 169 { 170 } 171 172 template <typename T> 173 void audio_writer_wav<T>::close() 174 { 175 f.reset(); 176 writer.reset(); 177 } 178 179 template struct audio_writer_wav<i16>; 180 template struct audio_writer_wav<i24>; 181 template struct audio_writer_wav<i32>; 182 template struct audio_writer_wav<f32>; 183 template struct audio_writer_wav<f64>; 184 185 template <typename T> 186 audio_reader_wav<T>::audio_reader_wav(std::shared_ptr<abstract_reader<>>&& reader) : reader(std::move(reader)) 187 { 188 f.reset(new internal_generic::wav_file()); 189 drwav_init(f.get(), (drwav_read_proc)&internal_generic::drwav_reader_read_proc, 190 (drwav_seek_proc)&internal_generic::drwav_reader_seek_proc, this->reader.get(), nullptr); 191 fmt.channels = f->channels; 192 fmt.samplerate = f->sampleRate; 193 fmt.length = static_cast<imax>(f->totalPCMFrameCount); 194 switch (f->translatedFormatTag) 195 { 196 case DR_WAVE_FORMAT_IEEE_FLOAT: 197 switch (f->bitsPerSample) 198 { 199 case 32: 200 fmt.type = audio_sample_type::f32; 201 break; 202 case 64: 203 fmt.type = audio_sample_type::f64; 204 break; 205 default: 206 fmt.type = audio_sample_type::unknown; 207 break; 208 } 209 break; 210 case DR_WAVE_FORMAT_PCM: 211 switch (f->bitsPerSample) 212 { 213 case 8: 214 fmt.type = audio_sample_type::i8; 215 break; 216 case 16: 217 fmt.type = audio_sample_type::i16; 218 break; 219 case 24: 220 fmt.type = audio_sample_type::i24; 221 break; 222 case 32: 223 fmt.type = audio_sample_type::i32; 224 break; 225 case 64: 226 fmt.type = audio_sample_type::i64; 227 break; 228 default: 229 fmt.type = audio_sample_type::unknown; 230 break; 231 } 232 break; 233 default: 234 fmt.type = audio_sample_type::unknown; 235 break; 236 } 237 } 238 template <typename T> 239 audio_reader_wav<T>::~audio_reader_wav() 240 { 241 } 242 243 template <typename T> 244 size_t audio_reader_wav<T>::read(T* data, size_t size) 245 { 246 if (fmt.type == audio_sample_type::unknown) 247 return 0; 248 if (fmt.type == audio_sample_traits<T>::type) 249 { 250 const size_t sz = drwav_read_pcm_frames(f.get(), size / fmt.channels, data); 251 position += sz; 252 return sz * fmt.channels; 253 } 254 else 255 { 256 univector<uint8_t> native(size * audio_sample_sizeof(fmt.type)); 257 const size_t sz = drwav_read_pcm_frames(f.get(), size / fmt.channels, native.data()); 258 position += sz; 259 convert(data, native.data(), fmt.type, sz * fmt.channels); 260 return sz * fmt.channels; 261 } 262 } 263 264 template <typename T> 265 bool audio_reader_wav<T>::seek(imax offset, seek_origin origin) 266 { 267 switch (origin) 268 { 269 case seek_origin::current: 270 return drwav_seek_to_pcm_frame(f.get(), static_cast<drmp3_uint64>(this->position + offset)); 271 case seek_origin::begin: 272 return drwav_seek_to_pcm_frame(f.get(), static_cast<drmp3_uint64>(offset)); 273 case seek_origin::end: 274 return drwav_seek_to_pcm_frame(f.get(), static_cast<drmp3_uint64>(fmt.length + offset)); 275 } 276 return false; 277 } 278 279 template struct audio_reader_wav<i16>; 280 template struct audio_reader_wav<i24>; 281 template struct audio_reader_wav<i32>; 282 template struct audio_reader_wav<f32>; 283 template struct audio_reader_wav<f64>; 284 285 template <typename T> 286 audio_reader_flac<T>::audio_reader_flac(std::shared_ptr<abstract_reader<>>&& reader) 287 : reader(std::move(reader)) 288 { 289 f.reset(reinterpret_cast<internal_generic::flac_file*>(drflac_open( 290 (drflac_read_proc)&internal_generic::drflac_reader_read_proc, 291 (drflac_seek_proc)&internal_generic::drflac_reader_seek_proc, this->reader.get(), nullptr))); 292 fmt.channels = f->channels; 293 fmt.samplerate = f->sampleRate; 294 fmt.length = static_cast<imax>(f->totalPCMFrameCount); 295 fmt.type = audio_sample_type::i32; 296 } 297 template <typename T> 298 audio_reader_flac<T>::~audio_reader_flac() 299 { 300 } 301 302 template <typename T> 303 size_t audio_reader_flac<T>::read(T* data, size_t size) 304 { 305 if (fmt.type == audio_sample_type::unknown) 306 return 0; 307 if (audio_sample_traits<T>::type == audio_sample_type::i32) 308 { 309 const size_t sz = 310 drflac_read_pcm_frames_s32(f.get(), size / fmt.channels, reinterpret_cast<i32*>(data)); 311 position += sz; 312 return sz * fmt.channels; 313 } 314 else 315 { 316 univector<i32> native(size * sizeof(i32)); 317 const size_t sz = drflac_read_pcm_frames_s32(f.get(), size / fmt.channels, native.data()); 318 position += sz; 319 convert(data, native.data(), sz * fmt.channels); 320 return sz * fmt.channels; 321 } 322 } 323 324 template <typename T> 325 bool audio_reader_flac<T>::seek(imax offset, seek_origin origin) 326 { 327 switch (origin) 328 { 329 case seek_origin::current: 330 return drflac_seek_to_pcm_frame(f.get(), static_cast<drmp3_uint64>(this->position + offset)); 331 case seek_origin::begin: 332 return drflac_seek_to_pcm_frame(f.get(), static_cast<drmp3_uint64>(offset)); 333 case seek_origin::end: 334 return drflac_seek_to_pcm_frame(f.get(), static_cast<drmp3_uint64>(fmt.length + offset)); 335 } 336 return false; 337 } 338 339 template struct audio_reader_flac<i16>; 340 template struct audio_reader_flac<i24>; 341 template struct audio_reader_flac<i32>; 342 template struct audio_reader_flac<f32>; 343 template struct audio_reader_flac<f64>; 344 345 static_assert(sizeof(drmp3_config) == sizeof(uint32_t) * 2); 346 static_assert(sizeof(mp3_config) == sizeof(uint32_t) * 2); 347 348 template <typename T> 349 audio_reader_mp3<T>::audio_reader_mp3(std::shared_ptr<abstract_reader<>>&& reader) : reader(std::move(reader)) 350 { 351 f.reset(new internal_generic::mp3_file()); 352 drmp3_init(f.get(), (drmp3_read_proc)&internal_generic::drmp3_reader_read_proc, 353 (drmp3_seek_proc)&internal_generic::drmp3_reader_seek_proc, this->reader.get(), 354 reinterpret_cast<const drmp3_config*>(&config), nullptr); 355 fmt.channels = f->channels; 356 fmt.samplerate = f->sampleRate; 357 fmt.length = static_cast<imax>(drmp3_get_pcm_frame_count(f.get())); 358 fmt.type = audio_sample_type::i16; 359 } 360 template <typename T> 361 audio_reader_mp3<T>::~audio_reader_mp3() 362 { 363 } 364 365 template <typename T> 366 size_t audio_reader_mp3<T>::read(T* data, size_t size) 367 { 368 if (fmt.type == audio_sample_type::unknown) 369 return 0; 370 if (audio_sample_traits<T>::type == audio_sample_type::i16) 371 { 372 const size_t sz = 373 drmp3_read_pcm_frames_s16(f.get(), size / fmt.channels, reinterpret_cast<i16*>(data)); 374 position += sz; 375 return sz * fmt.channels; 376 } 377 else 378 { 379 univector<i16> native(size * sizeof(i16)); 380 const size_t sz = drmp3_read_pcm_frames_s16(f.get(), size / fmt.channels, native.data()); 381 position += sz; 382 convert(data, native.data(), sz * fmt.channels); 383 return sz * fmt.channels; 384 } 385 } 386 387 template <typename T> 388 bool audio_reader_mp3<T>::seek(imax offset, seek_origin origin) 389 { 390 switch (origin) 391 { 392 case seek_origin::current: 393 return drmp3_seek_to_pcm_frame(f.get(), static_cast<drmp3_uint64>(this->position + offset)); 394 case seek_origin::begin: 395 return drmp3_seek_to_pcm_frame(f.get(), static_cast<drmp3_uint64>(offset)); 396 case seek_origin::end: 397 return drmp3_seek_to_pcm_frame(f.get(), static_cast<drmp3_uint64>(fmt.length + offset)); 398 } 399 return false; 400 } 401 402 template struct audio_reader_mp3<i16>; 403 template struct audio_reader_mp3<i24>; 404 template struct audio_reader_mp3<i32>; 405 template struct audio_reader_mp3<f32>; 406 template struct audio_reader_mp3<f64>; 407 408 } // namespace kfr 409 410 CMT_PRAGMA_GNU(GCC diagnostic pop)