finally good audio

This commit is contained in:
2026-06-23 20:38:08 -05:00
parent 3e94d64f4a
commit e94d4c980e
4 changed files with 55 additions and 27 deletions

View File

@@ -33,7 +33,7 @@ private:
void calculateCoefficients(); void calculateCoefficients();
Type type_ = Type::BiquadLowpass; Type type_ = Type::BiquadLowpass;
float sampleRate_ = 44100.0f; float sampleRate_ = 1.0f;
float frequency_ = 6000.0f; float frequency_ = 6000.0f;
float q_ = 0.707f; float q_ = 0.707f;

View File

@@ -12,7 +12,6 @@ PianoString::PianoString(ConfigService* config, LoggerService* logger) : Instrum
void PianoString::noteOn(float frequency, float velocity) { void PianoString::noteOn(float frequency, float velocity) {
logger_->log("Piano", LogFlag::Debug, "Note On");
active_ = true; active_ = true;
frequency_ = frequency; frequency_ = frequency;
@@ -45,7 +44,6 @@ void PianoString::noteOn(float frequency, float velocity) {
} }
void PianoString::noteOff() { void PianoString::noteOff() {
logger_->log("Piano", LogFlag::Debug, "Note Off");
damping_ = 10.0f; damping_ = 10.0f;
recalculateConstants(); recalculateConstants();
} }
@@ -67,41 +65,68 @@ bool PianoString::isActive() {
float PianoString::process(bool& scopeTrigger) { float PianoString::process(bool& scopeTrigger) {
// simulate over string // supersample
for(size_t i = 2; i < segmentCount_ - 2; i++) { for(uint32_t n = 0; n < samplingSteps_; n++) {
float y_xx = stringY_current_[i-1] - 2.0f*stringY_current_[i] + stringY_current_[i+1];
float y_xxxx = stringY_current_[i-2] - 4.0f*stringY_current_[i-1] + 6.0f*stringY_current_[i] - 4.0f*stringY_current_[i+1] + stringY_current_[i+2];
stringY_next_[i] = a1_ * stringY_current_[i] + a2_ * stringY_previous_[i] + r2_ * y_xx - s2_ * y_xxxx;
}
stringY_next_[0] = 0.0f;
stringY_next_[1] = 0.0f;
stringY_next_[segmentCount_-1] = 0.0f;
stringY_next_[segmentCount_-2] = 0.0f;
stringY_previous_ = stringY_current_; // simulate over string
stringY_current_ = stringY_next_; for(size_t i = 2; i < segmentCount_ - 2; i++) {
float y_xx = stringY_current_[i-1] - 2.0f*stringY_current_[i] + stringY_current_[i+1];
float y_xxxx = stringY_current_[i-2] - 4.0f*stringY_current_[i-1] + 6.0f*stringY_current_[i] - 4.0f*stringY_current_[i+1] + stringY_current_[i+2];
stringY_next_[i] = a1_ * stringY_current_[i] + a2_ * stringY_previous_[i] + r2_ * y_xx - s2_ * y_xxxx;
}
stringY_next_[0] = 0.0f;
stringY_next_[1] = 0.0f;
stringY_next_[segmentCount_-1] = 0.0f;
stringY_next_[segmentCount_-2] = 0.0f;
stringY_previous_ = stringY_current_;
stringY_current_ = stringY_next_;
}
phaseTracker_ += frequency_ / sampleRate_;
if(phaseTracker_ > 1.0f) {
phaseTracker_ -= 1.0f;
scopeTrigger = true;
}
float sampleOut = stringY_next_[static_cast<size_t>(samplePosition_*L_*segmentCount_)]; float sampleOut = stringY_next_[static_cast<size_t>(samplePosition_*L_*segmentCount_)];
rms_ = 0.99f * rms_ + 0.01f * sampleOut*sampleOut; rms_ = 0.99f * rms_ + 0.01f * sampleOut*sampleOut;
return 5.0f * sampleOut; return sampleOut;
} }
void PianoString::recalculateConstants() { void PianoString::recalculateConstants() {
L_ = stringLength_ * std::pow(1.005f, -frequency_ + 20.0f) + 0.5f; L_ = stringLength_ * std::pow(1.001f, -frequency_ + 20.0f) + 0.5f;
waveVelocity_ = 1.0f * frequency_ * L_; waveVelocity_ = 2.0f * frequency_ * L_;
samplingSteps_ = 0;
do {
samplingSteps_++;
float effectiveSampleRate_ = sampleRate_ * static_cast<float>(samplingSteps_);
dt_ = 1.0f / effectiveSampleRate_;
float a = (waveVelocity_*dt_/L_)*(waveVelocity_*dt_/L_);
float b = 4.0f*(stiffness_*dt_/(L_*L_))*(stiffness_*dt_/(L_*L_));
if(stiffness_ < 0.00001f) { // avoid divide by zero
segmentCount_ = static_cast<size_t>((L_ * effectiveSampleRate_)/waveVelocity_) - 1;
} else {
segmentCount_ = static_cast<size_t>(std::sqrt((-a+std::sqrt(a*a+4.0*b))/(2.0*b))) - 1;
}
} while (segmentCount_ < 80);
segmentCount_ = std::min(segmentCount_, static_cast<size_t>(80));
dx_ = L_ / static_cast<float>(segmentCount_); dx_ = L_ / static_cast<float>(segmentCount_);
dt_ = 1.0f / sampleRate_;
r1_ = waveVelocity_ * dt_/dx_; r1_ = waveVelocity_ * dt_/dx_;
r2_ = std::pow(waveVelocity_ * dt_/dx_, 2.0f); r2_ = (waveVelocity_ * dt_/dx_)*(waveVelocity_ * dt_/dx_);
s1_ = stiffness_ * dt_/std::pow(dx_, 2.0f); s1_ = stiffness_ * dt_/(dx_*dx_);
s2_ = std::pow(stiffness_ * dt_/std::pow(dx_, 2.0f), 2.0f); s2_ = (stiffness_ * dt_/(dx_*dx_))*(stiffness_ * dt_/(dx_*dx_));
a1_ = 2.0f - 2.0f * damping_ * dt_; a1_ = 2.0f - 2.0f * damping_ * dt_;
a2_ = 2.0f * damping_ * dt_ - 1.0f; a2_ = 2.0f * damping_ * dt_ - 1.0f;
} }

View File

@@ -35,15 +35,15 @@ private:
// constants // constants
// string parameters // string parameters
size_t segmentCount_ = 50; size_t segmentCount_ = 80;
static constexpr float rho_ = 8000.0f; // density, steel, kg/m^3 static constexpr float rho_ = 8000.0f; // density, steel, kg/m^3
static constexpr float radius_ = 0.001f; // meters static constexpr float radius_ = 0.001f; // meters
static constexpr float stringTension_ = 1200.0f; // string tension, N static constexpr float stringTension_ = 1200.0f; // string tension, N
static constexpr float stiffness_ = 0.000f; // stiffness coefficient static constexpr float stiffness_ = 0.0f; // stiffness coefficient
float damping_ = 0.5f; // damping coefficient float damping_ = 0.5f; // damping coefficient
static constexpr float stringLength_ = 5.0f; // length of string at lowest frequency (20 hz) static constexpr float stringLength_ = 4.0f; // length of string at lowest frequency (20 hz)
static constexpr float strikePosition_ = 0.2f; // x of impulse location static constexpr float strikePosition_ = 0.2f; // x of impulse location
static constexpr float impulseWidth_ = 0.02f; // x of impulse width static constexpr float impulseWidth_ = 0.1f; // x of impulse width
static constexpr float impulseVelocity_ = 10000.0f; // x/t of impulse magnitude static constexpr float impulseVelocity_ = 10000.0f; // x/t of impulse magnitude
static constexpr float samplePosition_ = 0.1f; // percentage along L of sampling for audio static constexpr float samplePosition_ = 0.1f; // percentage along L of sampling for audio
float crossSectionalArea_ = pi * std::pow(radius_, 2.0f); // string cross sectional area, assuming circular float crossSectionalArea_ = pi * std::pow(radius_, 2.0f); // string cross sectional area, assuming circular
@@ -54,6 +54,9 @@ private:
// f0_ = waveVelocity_ / (2.0f * stringLength_); // fundamental frequency of a non-stiff string // f0_ = waveVelocity_ / (2.0f * stringLength_); // fundamental frequency of a non-stiff string
// f1_ = f0_ * std::sqrt(1.0f + stiffness_); // fundamental frequency of the stiff string // f1_ = f0_ * std::sqrt(1.0f + stiffness_); // fundamental frequency of the stiff string
uint32_t samplingSteps_ = 1;
float phaseTracker_ = 0.0f;
float dx_ = L_ / static_cast<float>(segmentCount_); float dx_ = L_ / static_cast<float>(segmentCount_);
float dt_ = 1.0f / sampleRate_; float dt_ = 1.0f / sampleRate_;

View File

@@ -63,7 +63,7 @@ void Synth::process(float* out, size_t nFrames) {
mix += voices_[j].process(temp); mix += voices_[j].process(temp);
if(j == lowestVoice) triggered = temp; if(j == lowestVoice) triggered = temp;
} }
mix = tanh(mix/4.0f); // prevent clipping mix = tanh(mix); // prevent clipping
sampleOut = filter_.biquadProcess(mix); sampleOut = filter_.biquadProcess(mix);
out[2*i] = sampleOut; out[2*i] = sampleOut;