LCOV - code coverage report
Current view: top level - src/audio/dsp - wav_loader.cpp (source / functions) Coverage Total Hit
Test: merged.info Lines: 83.3 % 72 60
Test Date: 2026-06-01 11:15:25 Functions: 100.0 % 2 2

            Line data    Source code
       1              : #define DR_WAV_IMPLEMENTATION
       2              : #include "dr_wav.h"
       3              : 
       4              : #include "audio/dsp/wav_loader.h"
       5              : #include <iostream>
       6              : #include <cmath>
       7              : 
       8              : namespace Amplitron {
       9              : 
      10           15 : std::vector<float> resample_linear(const std::vector<float>& input,
      11              :                                    int from_rate, int to_rate) {
      12           15 :     if (input.empty() || from_rate <= 0 || to_rate <= 0 || from_rate == to_rate)
      13            0 :         return input;
      14              : 
      15           15 :     double ratio = static_cast<double>(from_rate) / static_cast<double>(to_rate);
      16           10 :     size_t out_len = static_cast<size_t>(
      17           15 :         std::ceil(static_cast<double>(input.size()) / ratio));
      18           15 :     if (out_len == 0) return {};
      19              : 
      20           15 :     std::vector<float> output(out_len);
      21         1587 :     for (size_t i = 0; i < out_len; ++i) {
      22         1572 :         double src_idx = static_cast<double>(i) * ratio;
      23         1572 :         size_t idx0 = static_cast<size_t>(src_idx);
      24         1572 :         double frac = src_idx - static_cast<double>(idx0);
      25              : 
      26         1572 :         if (idx0 + 1 < input.size()) {
      27         1554 :             output[i] = static_cast<float>(
      28         1554 :                 input[idx0] * (1.0 - frac) + input[idx0 + 1] * frac);
      29          536 :         } else if (idx0 < input.size()) {
      30           18 :             output[i] = input[idx0];
      31            6 :         } else {
      32            0 :             output[i] = 0.0f;
      33              :         }
      34          524 :     }
      35           15 :     return output;
      36           20 : }
      37              : 
      38           93 : WavData load_wav_file(const std::string& filepath,
      39              :                       int target_sample_rate,
      40              :                       int max_length_samples) {
      41           93 :     WavData result;
      42              : 
      43           31 :     drwav wav;
      44           93 :     if (!drwav_init_file(&wav, filepath.c_str(), nullptr)) {
      45           40 :         std::cerr << "Cabinet IR: failed to open WAV file: " << filepath << std::endl;
      46            6 :         return result;
      47              :     }
      48              : 
      49           84 :     result.sample_rate = static_cast<int>(wav.sampleRate);
      50           84 :     result.channels = static_cast<int>(wav.channels);
      51              : 
      52           84 :     drwav_uint64 total_frames = wav.totalPCMFrameCount;
      53           84 :     if (total_frames == 0) {
      54           24 :         std::cerr << "Cabinet IR: WAV file is empty: " << filepath << std::endl;
      55           18 :         drwav_uninit(&wav);
      56           12 :         return result;
      57              :     }
      58              : 
      59              :     // Bound frame count to max_length_samples before allocation
      60           66 :     drwav_uint64 frames_to_read = std::min(total_frames,
      61           66 :         static_cast<drwav_uint64>(max_length_samples));
      62              : 
      63              :     // Read bounded frames as interleaved float
      64           66 :     std::vector<float> interleaved(static_cast<size_t>(frames_to_read * wav.channels));
      65           88 :     drwav_uint64 frames_read = drwav_read_pcm_frames_f32(&wav, frames_to_read,
      66           22 :                                                           interleaved.data());
      67           66 :     drwav_uninit(&wav);
      68              : 
      69           66 :     if (frames_read == 0) {
      70            0 :         std::cerr << "Cabinet IR: failed to read WAV data: " << filepath << std::endl;
      71            0 :         result.sample_rate = 0;
      72            0 :         return result;
      73              :     }
      74              : 
      75              :     // Mix down to mono
      76           66 :     size_t num_frames = static_cast<size_t>(frames_read);
      77           66 :     result.samples.resize(num_frames);
      78              : 
      79           66 :     if (result.channels == 1) {
      80           88 :         result.samples.assign(interleaved.begin(),
      81           88 :                               interleaved.begin() + static_cast<ptrdiff_t>(num_frames));
      82           22 :     } else {
      83            0 :         int ch = result.channels;
      84            0 :         for (size_t f = 0; f < num_frames; ++f) {
      85            0 :             float sum = 0.0f;
      86            0 :             for (int c = 0; c < ch; ++c)
      87            0 :                 sum += interleaved[f * static_cast<size_t>(ch) + static_cast<size_t>(c)];
      88            0 :             result.samples[f] = sum / static_cast<float>(ch);
      89            0 :         }
      90              :     }
      91              : 
      92              :     // Resample if needed
      93           66 :     if (target_sample_rate > 0 && target_sample_rate != result.sample_rate) {
      94           25 :         result.samples = resample_linear(result.samples,
      95           15 :                                          result.sample_rate, target_sample_rate);
      96           15 :         result.sample_rate = target_sample_rate;
      97            5 :     }
      98              : 
      99              :     // Cap length
     100           88 :     if (max_length_samples > 0 &&
     101           66 :         static_cast<int>(result.samples.size()) > max_length_samples) {
     102            3 :         std::cerr << "Cabinet IR: IR truncated from "
     103            3 :                   << result.samples.size() << " to " << max_length_samples
     104            3 :                   << " samples" << std::endl;
     105            3 :         result.samples.resize(static_cast<size_t>(max_length_samples));
     106            1 :     }
     107              : 
     108           44 :     return result;
     109           75 : }
     110              : 
     111              : } // namespace Amplitron
        

Generated by: LCOV version 2.0-1