kfr

Fast, modern C++ DSP framework, FFT, Sample Rate Conversion, FIR/IIR/Biquad Filters (SSE, AVX, AVX-512, ARM NEON)
Log | Files | Refs | README

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)