-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy pathImpulseResponse.cpp
More file actions
110 lines (99 loc) · 3.48 KB
/
ImpulseResponse.cpp
File metadata and controls
110 lines (99 loc) · 3.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//
// ImpulseResponse.cpp
// NeuralAmpModeler-macOS
//
// Created by Steven Atkinson on 12/30/22.
//
#include "Resample.h"
#include "wav.h"
#include "ImpulseResponse.h"
dsp::ImpulseResponse::ImpulseResponse(const char* fileName, const double sampleRate)
: mWavState(dsp::wav::LoadReturnCode::ERROR_OTHER)
, mSampleRate(sampleRate)
{
// Try to load the WAV
this->mWavState = dsp::wav::Load(fileName, this->mRawAudio, this->mRawAudioSampleRate);
if (this->mWavState != dsp::wav::LoadReturnCode::SUCCESS)
{
std::stringstream ss;
ss << "Failed to load IR at " << fileName << std::endl;
}
else
// Set the weights based on the raw audio.
this->_SetWeights();
}
dsp::ImpulseResponse::ImpulseResponse(const IRData& irData, const double sampleRate)
: mWavState(dsp::wav::LoadReturnCode::SUCCESS)
, mSampleRate(sampleRate)
{
this->mRawAudio = irData.mRawAudio;
this->mRawAudioSampleRate = irData.mRawAudioSampleRate;
this->_SetWeights();
}
dsp::ImpulseResponse::ImpulseResponse(const unsigned char* data, size_t dataSize, double sampleRate)
: mWavState(dsp::wav::LoadReturnCode::SUCCESS)
, mSampleRate(sampleRate)
{
// Load the raw data from memory
this->mWavState = dsp::wav::Load(data, dataSize, this->mRawAudio, this->mRawAudioSampleRate);
if (this->mWavState != dsp::wav::LoadReturnCode::SUCCESS)
{
std::stringstream ss;
ss << "Failed to load IR from embedded data array." << std::endl;
}
else
{
this->_SetWeights();
}
}
double** dsp::ImpulseResponse::Process(double** inputs, const size_t numChannels, const size_t numFrames)
{
this->_PrepareBuffers(numChannels, numFrames);
this->_UpdateHistory(inputs, numChannels, numFrames);
for (size_t i = 0, j = this->mHistoryIndex - this->mHistoryRequired; i < numFrames; i++, j++)
{
auto input = Eigen::Map<const Eigen::VectorXf>(&this->mHistory[j], this->mHistoryRequired + 1);
this->mOutputs[0][i] = (double)this->mWeight.dot(input);
}
// Copy out for more-than-mono.
for (size_t c = 1; c < numChannels; c++)
for (size_t i = 0; i < numFrames; i++)
this->mOutputs[c][i] = this->mOutputs[0][i];
this->_AdvanceHistoryIndex(numFrames);
return this->_GetPointers();
}
void dsp::ImpulseResponse::_SetWeights()
{
if (this->mRawAudioSampleRate == mSampleRate)
{
this->mResampled.resize(this->mRawAudio.size());
memcpy(this->mResampled.data(), this->mRawAudio.data(), sizeof(float) * this->mResampled.size());
}
else
{
// Cubic resampling
std::vector<float> padded;
padded.resize(this->mRawAudio.size() + 2);
padded[0] = 0.0f;
padded[padded.size() - 1] = 0.0f;
memcpy(padded.data() + 1, this->mRawAudio.data(), sizeof(float) * this->mRawAudio.size());
dsp::ResampleCubic<float>(padded, this->mRawAudioSampleRate, mSampleRate, 0.0, this->mResampled);
}
// Simple implementation w/ no resample...
const size_t irLength = std::min(this->mResampled.size(), this->mMaxLength);
this->mWeight.resize(irLength);
// Gain reduction.
// https://github.com/sdatkinson/NeuralAmpModelerPlugin/issues/100#issuecomment-1455273839
// Add sample rate-dependence
const float gain = pow(10, -18 * 0.05) * 48000 / mSampleRate;
for (size_t i = 0, j = irLength - 1; i < irLength; i++, j--)
this->mWeight[j] = gain * this->mResampled[i];
this->mHistoryRequired = irLength - 1;
}
dsp::ImpulseResponse::IRData dsp::ImpulseResponse::GetData()
{
IRData irData;
irData.mRawAudio = this->mRawAudio;
irData.mRawAudioSampleRate = this->mRawAudioSampleRate;
return irData;
}