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
|