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
|