LCOV - code coverage report
Current view: top level - src/audio/dsp - wav_loader.cpp (source / functions) Coverage Total Hit
Test: merged.info Lines: 83.1 % 65 54
Test Date: 2026-06-07 15:51:50 Functions: 100.0 % 2 2

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

Generated by: LCOV version 2.0-1