Skip to content

Commit

Permalink
Changes according to feedback on the PR.
Browse files Browse the repository at this point in the history
  • Loading branch information
larspalo committed May 8, 2024
1 parent 57e7c82 commit 18591dc
Show file tree
Hide file tree
Showing 16 changed files with 154 additions and 140 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
- Added tone balance (bass/treble harmonics balance) voicing option
- Added a tone balance (bass/treble harmonics balance) voicing option
# 3.14.2 (2024-04-29)
- Fixed divisional couplers with setter divisionals https://github.com/GrandOrgue/grandorgue/issues/1787
- Fixed behavior of "Detect complex MIDI setup" with Note events in different cases https://github.com/GrandOrgue/grandorgue/issues/1762
Expand Down
2 changes: 1 addition & 1 deletion help/grandorgue.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5422,7 +5422,7 @@ Within windchests, the ranks are ordered as found in the definition file.
<title>Tone balance</title>
<para>
This setting adjusts the bass/treble harmonics balance of the pipes.
The value is a converted to a frequency adjustment where a negative
The value is a converted to a cutoff frequency for a filter where a negative
number means less high frequencies and a positive number means less
low frequencies. Allowed range is {-100, +100}. A tone balance value
which is not zero on a child level will override a value set at any
Expand Down
1 change: 1 addition & 0 deletions src/grandorgue/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ sound/GOSoundSamplerPool.cpp
sound/GOSoundStateHandler.cpp
sound/GOSound.cpp
sound/GOSoundFilter.cpp
sound/GOSoundToneBalanceFilter.cpp
updater/GOUpdateChecker.cpp
yaml/GOSaveableToYaml.cpp
yaml/go-wx-yaml.cpp
Expand Down
5 changes: 3 additions & 2 deletions src/grandorgue/model/pipe-config/GOPipeConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,10 +195,11 @@ void GOPipeConfig::SetPitchMember(float cents, float &member) {
SetSmallMember(cents, member, &GOPipeUpdateCallback::UpdateTuning);
}

void GOPipeConfig::SetToneBalanceMember(int value, int &member) {
void GOPipeConfig::SetToneBalanceValue(int8_t value) {
if (value < -100)
value = -100;
if (value > 100)
value = 100;
SetSmallMember(value, member, &GOPipeUpdateCallback::UpdateToneBalance);
SetSmallMember(
value, m_ToneBalanceValue, &GOPipeUpdateCallback::UpdateToneBalance);
}
11 changes: 4 additions & 7 deletions src/grandorgue/model/pipe-config/GOPipeConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
#ifndef GOPIPECONFIG_H
#define GOPIPECONFIG_H

#include <algorithm>
#include <cstdint>

#include <wx/string.h>

#include "GOBool3.h"
Expand Down Expand Up @@ -37,10 +37,10 @@ class GOPipeConfig {
float m_PitchCorrection;
float m_ManualTuning;
float m_AutoTuningCorrection;
int m_ToneBalanceValue;
uint16_t m_DefaultDelay;
uint16_t m_Delay;
uint16_t m_ReleaseTail; // the max release length in ms
int8_t m_ToneBalanceValue;
int8_t m_BitsPerSample;
int8_t m_Channels;
int8_t m_LoopLoad;
Expand Down Expand Up @@ -81,7 +81,6 @@ class GOPipeConfig {
}

void SetPitchMember(float cents, float &member);
void SetToneBalanceMember(int value, int &member);

public:
GOPipeConfig(GOPipeConfigListener &listener, GOPipeUpdateCallback *callback);
Expand Down Expand Up @@ -130,10 +129,8 @@ class GOPipeConfig {
SetPitchMember(cents, m_AutoTuningCorrection);
}

int GetToneBalanceValue() const { return m_ToneBalanceValue; }
void SetToneBalanceValue(int value) {
SetToneBalanceMember(value, m_ToneBalanceValue);
}
int8_t GetToneBalanceValue() const { return m_ToneBalanceValue; }
void SetToneBalanceValue(int8_t value);

uint16_t GetDefaultDelay() const { return m_DefaultDelay; }
uint16_t GetDelay() const { return m_Delay; }
Expand Down
2 changes: 1 addition & 1 deletion src/grandorgue/model/pipe-config/GOPipeConfigNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ uint16_t GOPipeConfigNode::GetEffectiveReleaseTail() const {
return releaseTail;
}

int GOPipeConfigNode::GetEffectiveToneBalanceValue() const {
int8_t GOPipeConfigNode::GetEffectiveToneBalanceValue() const {
if (m_PipeConfig.GetToneBalanceValue())
return m_PipeConfig.GetToneBalanceValue();
else
Expand Down
2 changes: 1 addition & 1 deletion src/grandorgue/model/pipe-config/GOPipeConfigNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class GOPipeConfigNode : private GOSaveableObject {

uint16_t GetEffectiveReleaseTail() const;

int GetEffectiveToneBalanceValue() const;
int8_t GetEffectiveToneBalanceValue() const;

uint8_t GetEffectiveBitsPerSample() const {
return GetEffectiveUint8(
Expand Down
10 changes: 5 additions & 5 deletions src/grandorgue/sound/GOSoundEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,8 @@ bool GOSoundEngine::ProcessSampler(
sampler->p_SoundProvider = NULL;

sampler->fader.Process(n_frames, temp, volume);
if (sampler->toneState.IsToApply())
sampler->toneState.ProcessBuffer(n_frames, temp);
if (sampler->toneBalanceFilterState.IsToApply())
sampler->toneBalanceFilterState.ProcessBuffer(n_frames, temp);

/* Add these samples to the current output buffer shifting
* right by the necessary amount to bring the sample gain back
Expand Down Expand Up @@ -428,7 +428,7 @@ GOSoundSampler *GOSoundEngine::CreateTaskSample(
sampler->time = start_time;
sampler->fader.SetVelocityVolume(
sampler->p_SoundProvider->GetVelocityVolume(sampler->velocity));
sampler->toneState.Init(
sampler->toneBalanceFilterState.Init(
sampler->p_SoundProvider->GetToneBalance()->GetFilter());
sampler->is_release = isRelease;
sampler->m_SamplerTaskId = samplerTaskId;
Expand Down Expand Up @@ -473,7 +473,7 @@ void GOSoundEngine::SwitchToAnotherAttack(GOSoundSampler *pSampler) {
pSampler->fader.NewAttacking(gain_target, cross_fade_len, m_SampleRate);
pSampler->is_release = false;

new_sampler->toneState.Init(
new_sampler->toneBalanceFilterState.Init(
new_sampler->p_SoundProvider->GetToneBalance()->GetFilter());

StartSampler(new_sampler);
Expand Down Expand Up @@ -623,7 +623,7 @@ void GOSoundEngine::CreateReleaseSampler(GOSoundSampler *handle) {
new_sampler->m_AudioGroupId = handle->m_AudioGroupId;
new_sampler->fader.SetVelocityVolume(
new_sampler->p_SoundProvider->GetVelocityVolume(new_sampler->velocity));
new_sampler->toneState.Init(
new_sampler->toneBalanceFilterState.Init(
new_sampler->p_SoundProvider->GetToneBalance()->GetFilter());
StartSampler(new_sampler);
handle->time = m_CurrentTime;
Expand Down
92 changes: 46 additions & 46 deletions src/grandorgue/sound/GOSoundFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,59 +8,59 @@
#include "GOSoundFilter.h"

GOSoundFilter::GOSoundFilter() {
m_type = FilterType::TYPE_NONE;
m_samplerate = 0;
Init(GO_FILTER_TYPE::LPF, 0, 0);
}

void GOSoundFilter::Init(GO_FILTER_TYPE type, double frequency, double gain) {
m_type = type;
m_B0 = 0;
m_B1 = 0;
m_A1 = 0;
}

void GOSoundFilter::Init(FilterType type, double frequency, double gain) {
// if for any reason m_samlerate is not set, don't even try using filter
if (m_samplerate == 0) {
m_isToApply = false;
m_type = FilterType::TYPE_NONE;
return;
} else {
double a0 = 1;
double a1 = 0;
double b0 = 0;
double b1 = 0;
double amp = pow(10, (gain / 40.0));
double w0 = 2.0 * 3.14159265358979323846 * frequency / m_samplerate;
double cosW0 = cos(w0);
double sinW0 = sin(w0);
}
m_type = type;

double a0 = 1;
double a1 = 0;
double b0 = 0;
double b1 = 0;
double amp = pow(10, (gain / 40.0));
double w0 = 2.0 * 3.14159265358979323846 * frequency / m_samplerate;
double cosW0 = cos(w0);
double sinW0 = sin(w0);

switch (m_type) {
case GO_FILTER_TYPE::LPF:
b0 = sinW0;
b1 = sinW0;
a0 = sinW0 + cosW0 + 1.0;
a1 = (sinW0 - cosW0 - 1.0);
break;
case GO_FILTER_TYPE::HPF:
b0 = 1.0 + cosW0;
b1 = -(1.0 + cosW0);
a0 = sinW0 + cosW0 + 1.0;
a1 = (sinW0 - cosW0 - 1.0);
break;
case GO_FILTER_TYPE::LOW_SHELF:
b0 = amp * sinW0 + cosW0 + 1.0;
b1 = amp * sinW0 - cosW0 - 1.0;
a0 = 1.0 / amp * sinW0 + cosW0 + 1.0;
a1 = 1.0 / amp * sinW0 - cosW0 - 1.0;
break;
case GO_FILTER_TYPE::HIGH_SHELF:
b0 = sinW0 + amp + amp * cosW0;
b1 = sinW0 - amp - amp * cosW0;
a0 = sinW0 + 1.0 / amp + 1.0 / amp * cosW0;
a1 = sinW0 - 1.0 / amp - 1.0 / amp * cosW0;
break;
default:
break;
}
m_B0 = b0 / a0;
m_B1 = b1 / a0;
m_A1 = a1 / a0;
switch (m_type) {
case FilterType::TYPE_LPF:
b0 = sinW0;
b1 = sinW0;
a0 = sinW0 + cosW0 + 1.0;
a1 = (sinW0 - cosW0 - 1.0);
break;
case FilterType::TYPE_HPF:
b0 = 1.0 + cosW0;
b1 = -(1.0 + cosW0);
a0 = sinW0 + cosW0 + 1.0;
a1 = (sinW0 - cosW0 - 1.0);
break;
case FilterType::TYPE_LOW_SHELF:
b0 = amp * sinW0 + cosW0 + 1.0;
b1 = amp * sinW0 - cosW0 - 1.0;
a0 = 1.0 / amp * sinW0 + cosW0 + 1.0;
a1 = 1.0 / amp * sinW0 - cosW0 - 1.0;
break;
case FilterType::TYPE_HIGH_SHELF:
b0 = sinW0 + amp + amp * cosW0;
b1 = sinW0 - amp - amp * cosW0;
a0 = sinW0 + 1.0 / amp + 1.0 / amp * cosW0;
a1 = sinW0 - 1.0 / amp - 1.0 / amp * cosW0;
break;
default:
break;
}
m_B0 = b0 / a0;
m_B1 = b1 / a0;
m_A1 = a1 / a0;
}
50 changes: 27 additions & 23 deletions src/grandorgue/sound/GOSoundFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,17 @@
#define GOSOUNDFILTER_H_

#include <cmath>

enum class GO_FILTER_TYPE { LPF, HPF, LOW_SHELF, HIGH_SHELF };
#include <cstdint>

class GOSoundFilter {
public:
enum class FilterType : uint8_t {
TYPE_NONE = 0,
TYPE_LPF,
TYPE_HPF,
TYPE_LOW_SHELF,
TYPE_HIGH_SHELF
};
class FilterState {
public:
FilterState() { Init(nullptr); }
Expand All @@ -23,16 +29,26 @@ class GOSoundFilter {
m_state[i] = 0;
}
bool IsToApply() { return m_filter->IsToApply(); }
void ProcessBuffer(unsigned n_blocks, float *buffer);
inline void ProcessBuffer(unsigned n_blocks, float *buffer) {
float out[2];
for (unsigned int i = 0; i < n_blocks; i++, buffer += 2) {
out[0] = m_filter->m_B0 * buffer[0] + m_state[0];
out[1] = m_filter->m_B0 * buffer[1] + m_state[1];
m_state[0] = m_filter->m_B1 * buffer[0] - m_filter->m_A1 * out[0];
m_state[1] = m_filter->m_B1 * buffer[1] - m_filter->m_A1 * out[1];

buffer[0] = out[0];
buffer[1] = out[1];
}
}

private:
float m_state[2];
const GOSoundFilter *m_filter;
};

private:
GO_FILTER_TYPE m_type;
bool m_isToApply;
FilterType m_type;
unsigned m_samplerate;

// Calculated filter coefficients
Expand All @@ -42,24 +58,12 @@ class GOSoundFilter {

public:
GOSoundFilter();
void Init(GO_FILTER_TYPE type, double frequency, double gain = 0);
bool IsToApply() const { return m_isToApply; }
void SetIsToApply(bool apply) { m_isToApply = apply; }
void SetSamplerate(unsigned samplerate) { m_samplerate = samplerate; }
};

inline void GOSoundFilter::FilterState::ProcessBuffer(
unsigned n_blocks, float *buffer) {
float out[2];
for (unsigned int i = 0; i < n_blocks; i++, buffer += 2) {
out[0] = m_filter->m_B0 * buffer[0] + m_state[0];
out[1] = m_filter->m_B0 * buffer[1] + m_state[1];
m_state[0] = m_filter->m_B1 * buffer[0] - m_filter->m_A1 * out[0];
m_state[1] = m_filter->m_B1 * buffer[1] - m_filter->m_A1 * out[1];

buffer[0] = out[0];
buffer[1] = out[1];
void Init(FilterType type, double frequency, double gain = 0);
bool IsToApply() const { return static_cast<bool>(m_type); }
void SetSamplerate(unsigned samplerate) {
m_samplerate = samplerate;
m_type = FilterType::TYPE_NONE;
}
}
};

#endif /* GOSOUNDFILTER_H_ */
2 changes: 1 addition & 1 deletion src/grandorgue/sound/GOSoundProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ void GOSoundProvider::SetTuning(float cent) {
m_Tuning = pow(pow(2, 1.0 / 1200.0), cent);
}

void GOSoundProvider::SetToneBalanceValue(int value) {
void GOSoundProvider::SetToneBalanceValue(int8_t value) {
m_ToneBalanceValue = value;
m_ToneBalance.Init(m_ToneBalanceValue);
}
Expand Down
16 changes: 9 additions & 7 deletions src/grandorgue/sound/GOSoundProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#include "ptrvector.h"

#include "GOBool3.h"
#include "GOSoundToneBalance.h"
#include "GOSoundToneBalanceFilter.h"
#include "GOStatisticCallback.h"

class GOSoundAudioSection;
Expand Down Expand Up @@ -42,8 +42,8 @@ class GOSoundProvider : public GOStatisticCallback {
float m_MidiPitchFract;
float m_Gain;
float m_Tuning;
int m_ToneBalanceValue;
GOSoundToneBalance m_ToneBalance;
int8_t m_ToneBalanceValue;
GOSoundToneBalanceFilter m_ToneBalance;
bool m_IsWaveTremulantActive;
unsigned m_ReleaseTail;
ptr_vector<GOSoundAudioSection> m_Attack;
Expand Down Expand Up @@ -85,10 +85,12 @@ class GOSoundProvider : public GOStatisticCallback {

float GetTuning() const;
void SetTuning(float cent);
int GetToneBalanceValue() const;
void SetToneBalanceValue(int value);
int8_t GetToneBalanceValue() const;
void SetToneBalanceValue(int8_t value);
void SetToneBalanceFilterSamplerate(unsigned samplerate);
const GOSoundToneBalance *GetToneBalance() const { return &m_ToneBalance; }
const GOSoundToneBalanceFilter *GetToneBalance() const {
return &m_ToneBalance;
}
unsigned GetReleaseTail() const { return m_ReleaseTail; }
void SetReleaseTail(unsigned releaseTail) { m_ReleaseTail = releaseTail; }

Expand All @@ -112,7 +114,7 @@ inline float GOSoundProvider::GetGain() const { return m_Gain; }

inline float GOSoundProvider::GetTuning() const { return m_Tuning; }

inline int GOSoundProvider::GetToneBalanceValue() const {
inline int8_t GOSoundProvider::GetToneBalanceValue() const {
return m_ToneBalanceValue;
}

Expand Down
2 changes: 1 addition & 1 deletion src/grandorgue/sound/GOSoundSampler.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ struct GOSoundSampler {
unsigned m_AudioGroupId;
audio_section_stream stream;
GOSoundFader fader;
GOSoundFilter::FilterState toneState;
GOSoundFilter::FilterState toneBalanceFilterState;
uint64_t time;
unsigned velocity;
unsigned delay;
Expand Down
Loading

0 comments on commit 18591dc

Please sign in to comment.