audio: array of reverberators

This commit is contained in:
Zack Buhman 2026-06-03 18:23:45 -05:00
parent 057ba291d8
commit 91a44e9c5e
8 changed files with 189 additions and 275 deletions

View File

@ -23,7 +23,9 @@ CFLAGS += -Wno-format
CFLAGS += -Wno-error=unused-function CFLAGS += -Wno-error=unused-function
CFLAGS += -Wno-error=array-bounds CFLAGS += -Wno-error=array-bounds
CFLAGS += -Wno-unknown-pragmas CFLAGS += -Wno-unknown-pragmas
ifneq '' '$(findstring clang++,$(CXX))'
CFLAGS += -Wno-vla-cxx-extension CFLAGS += -Wno-vla-cxx-extension
endif
CFLAGS += -fno-strict-aliasing CFLAGS += -fno-strict-aliasing
CFLAGS += -I./include CFLAGS += -I./include
CFLAGS += -I./data CFLAGS += -I./data
@ -43,7 +45,7 @@ LDFLAGS += -lm
#LDFLAGS += -Wl,--gc-sections #LDFLAGS += -Wl,--gc-sections
#-Wl,--print-gc-sections #-Wl,--print-gc-sections
ifeq ($(UNAME),Linux) ifeq ($(UNAME),Linux)
#LDFLAGS += -Wl,-z noexecstack LDFLAGS += -z noexecstack
endif endif
ifeq ($(UNAME),Darwin) ifeq ($(UNAME),Darwin)
LDFLAGS += -framework Foundation -framework Cocoa -framework IOKit -framework AVFoundation -framework CoreVideo -framework CoreAudio -framework CoreMedia -framework CoreHaptics -framework AudioToolbox -framework GameController -framework ForceFeedback -framework Carbon -framework Metal -framework QuartzCore -framework UniformTypeIdentifiers LDFLAGS += -framework Foundation -framework Cocoa -framework IOKit -framework AVFoundation -framework CoreVideo -framework CoreAudio -framework CoreMedia -framework CoreHaptics -framework AudioToolbox -framework GameController -framework ForceFeedback -framework Carbon -framework Metal -framework QuartzCore -framework UniformTypeIdentifiers
@ -114,9 +116,6 @@ endif
all: main all: main
CC = clang
CXX = clang++
%.o: %.c %.o: %.c
$(CC) $(ARCH) $(CSTD) $(CFLAGS) $(FLAGS) $(OPT) $(DEBUG) -c $< -o $@ $(CC) $(ARCH) $(CSTD) $(CFLAGS) $(FLAGS) $(OPT) $(DEBUG) -c $< -o $@

View File

@ -7,88 +7,57 @@ namespace audio {
constexpr int sample_rate = 48000; constexpr int sample_rate = 48000;
constexpr int channels = 2; constexpr int channels = 2;
template <int maxDelay> struct DelayFilter {
struct FeedbackCombFilter { float * buffer;
private:
//float * buffer;
float buffer[maxDelay];
int index;
public:
int delay;
float gain0;
float gainM;
FeedbackCombFilter(int delay, float gain0, float gainM);
void reset();
float feed(float value);
};
template <int maxDelay>
struct FeedforwardCombFilter {
private:
//float * buffer;
float buffer[maxDelay];
int index;
public:
int delay;
float gain0;
float gainM;
FeedforwardCombFilter(int delay, float gain0, float gainM);
void reset();
float feed(float value);
};
template <int maxDelay>
struct AllpassFilter {
private:
//float * buffer;
float buffer[maxDelay];
int index; int index;
public: const int maxDelay;
int delay; int delay;
float gain0; float gain;
float gainM;
DelayFilter(int maxDelay, int delay, float gain);
AllpassFilter(int delay, float gain0, float gainM);
void reset(); void reset();
float feed(float x); virtual float feed(float value) = 0;
}; };
using FBCF = FeedbackCombFilter<15000>; struct FeedbackCombFilter : DelayFilter {
using FFCF = FeedforwardCombFilter<15000>; FeedbackCombFilter(int maxDelay, int delay, float gain);
using AP = AllpassFilter<2500>; float feed(float value) override;
};
struct FeedforwardCombFilter : DelayFilter {
public:
FeedforwardCombFilter(int maxDelay, int delay, float gain);
float feed(float value) override;
};
struct AllpassFilter : DelayFilter {
AllpassFilter(int maxDelay, int delay, float gain);
float feed(float x) override;
};
using FBCF = FeedbackCombFilter;
using FFCF = FeedforwardCombFilter;
using AP = AllpassFilter;
struct lr { float l; float r; }; struct lr { float l; float r; };
struct FBReverb { struct Reverb {
static constexpr int apCount = 3;
static constexpr int cfCount = 4; static constexpr int cfCount = 4;
static constexpr int apCount = 3;
FBCF cf[cfCount]; DelayFilter * cf;
AP ap[apCount]; DelayFilter * ap;
FBReverb(); Reverb(DelayFilter * cf, DelayFilter * ap);
void reset();
lr feed(float x);
};
struct FFReverb {
static constexpr int __cfCount = 4;
static constexpr int apCount = 3;
FFCF cf[__cfCount];
AP ap[apCount];
FFReverb();
void reset(); void reset();
lr feed(float x); lr feed(float x);
}; };
extern int reverbIndex; extern int reverbIndex;
extern FBReverb fbreverb; extern Reverb * reverbs[];
extern FFReverb ffreverb; extern int const reverbsCount;
extern float wetGain; extern float wetGain;
extern float dryGain; extern float dryGain;

View File

@ -4,6 +4,7 @@
namespace ui namespace ui
{ {
void init();
void draw(MappedInstanceData<SolidInstance> & data, void draw(MappedInstanceData<SolidInstance> & data,
MappedInstanceData<font::BitmapInstance> & fontData); MappedInstanceData<font::BitmapInstance> & fontData);
void update(float mx, float my, bool mLeft, bool mEdge); void update(float mx, float my, bool mLeft, bool mEdge);

View File

@ -86,6 +86,9 @@ namespace ui::widget
T maxExtent; T maxExtent;
T * value; T * value;
Slider()
{}
Slider(char const * label, Slider(char const * label,
int left, int top, int width, int height, int left, int top, int width, int height,
T minValue, T maxValue, T minValue, T maxValue,
@ -117,30 +120,27 @@ namespace ui::widget
char const * label; char const * label;
Slider<int, true> delay; Slider<int, true> delay;
Slider<float, true> gain0; Slider<float, true> gain;
Slider<float, true> gainM;
DelayGainSlider()
{}
DelayGainSlider(char const * label, DelayGainSlider(char const * label,
int left, int top, int left, int top,
int delayMin, int delayMax, int * delayValue, int delayMin, int delayMax, int * delayValue,
float gainMin, float gainMax, float gainMin, float gainMax,
float * gain0Value, float * gainMValue) float * gainValue)
: label(label) : label(label)
, delay("delay", , delay("delay",
left, top, 150, 14, left, top, 150, 14,
delayMin, delayMax, delayMin, delayMax,
delayMin, delayMax, delayMin, delayMax,
delayValue) delayValue)
, gain0("gain0", , gain("gain",
left, top + 30, 150, 14, left, top + 30, 150, 14,
gainMin, gainMax, gainMin, gainMax,
gainMin, gainMax, gainMin, gainMax,
gain0Value) gainValue)
, gainM("gainM",
left, top + 60, 150, 14,
gainMin, gainMax,
gainMin, gainMax,
gainMValue)
{} {}
void draw(MappedInstanceData<SolidInstance> & data, void draw(MappedInstanceData<SolidInstance> & data,

View File

@ -13,14 +13,14 @@
#include "poem.h" #include "poem.h"
namespace audio { namespace audio {
static int const frame_samples = 960; // 20 milliseconds @ 48kHz //static int const frame_samples = 960; // 20 milliseconds @ 48kHz
static int const sample_size = (sizeof (int16_t)); static int const sample_size = (sizeof (int16_t));
static int const max_frame_size = 960 * 3; // 20ms at 48kHz static int const max_frame_size = 960 * 3; // 20ms at 48kHz
static int const max_packet_size = 1275; //static int const max_packet_size = 1275;
static int const half_period_samples = sample_rate / 30; static int const half_period_samples = sample_rate / 30;
static int const half_period_size = half_period_samples * sample_size * channels; //static int const half_period_size = half_period_samples * sample_size * channels;
struct AudioBuffer { struct AudioBuffer {
renpy::language::audio const * audio; renpy::language::audio const * audio;
@ -28,111 +28,87 @@ namespace audio {
uint32_t sample_count; uint32_t sample_count;
}; };
template <int maxDelay> //////////////////////////////////////////////////////////////////////
FeedbackCombFilter<maxDelay>::FeedbackCombFilter(int delay, float gain0, float gainM) // DelayFilter
: delay(delay), gain0(gain0), gainM(gainM) //////////////////////////////////////////////////////////////////////
void DelayFilter::reset()
{ {
//buffer = (float *)malloc((sizeof (float)) * maxDelay); memset(buffer, 0, maxDelay * (sizeof (float)));
}
DelayFilter::DelayFilter(int maxDelay, int delay, float gain)
: index(0)
, maxDelay(maxDelay)
, delay(delay)
, gain(gain)
{
buffer = (float *)malloc(maxDelay * (sizeof (float)));
reset(); reset();
} }
template <int maxDelay> //////////////////////////////////////////////////////////////////////
void FeedbackCombFilter<maxDelay>::reset() // FeedbackCombFilter
{ //////////////////////////////////////////////////////////////////////
index = 0;
memset(buffer, 0, (sizeof (float)) * maxDelay);
}
template <int maxDelay> FeedbackCombFilter::FeedbackCombFilter(int maxDelay, int delay, float gain)
float FeedbackCombFilter<maxDelay>::feed(float value) : DelayFilter(maxDelay, delay, gain)
{}
float FeedbackCombFilter::feed(float value)
{ {
float y = gain0 * value + gainM * buffer[index]; float y = gain * value + gain * buffer[index];
buffer[index] = y; buffer[index] = y;
index = (index + 1) % delay; index = (index + 1) % delay;
return y; return y;
} }
template <int maxDelay> //////////////////////////////////////////////////////////////////////
FeedforwardCombFilter<maxDelay>::FeedforwardCombFilter(int delay, float gain0, float gainM) // FeedForwardCombFilter
: delay(delay), gain0(gain0), gainM(gainM) //////////////////////////////////////////////////////////////////////
{
//buffer = (float *)malloc((sizeof (float)) * maxDelay);
reset();
}
template <int maxDelay> FeedforwardCombFilter::FeedforwardCombFilter(int maxDelay, int delay, float gain)
void FeedforwardCombFilter<maxDelay>::reset() : DelayFilter(maxDelay, delay, gain)
{ {}
index = 0;
memset(buffer, 0, (sizeof (float)) * maxDelay);
}
template <int maxDelay> float FeedforwardCombFilter::feed(float value)
float FeedforwardCombFilter<maxDelay>::feed(float value)
{ {
float y = gain0 * value + gainM * buffer[index]; float y = gain * value + gain * buffer[index];
buffer[index] = value; buffer[index] = value;
index = (index + 1) % delay; index = (index + 1) % delay;
return y; return y;
} }
template <int maxDelay> //////////////////////////////////////////////////////////////////////
AllpassFilter<maxDelay>::AllpassFilter(int delay, float gain0, float gainM) // AllpassFilter
: delay(delay), gain0(gain0), gainM(gainM) //////////////////////////////////////////////////////////////////////
{
//buffer = (float *)malloc((sizeof (float)) * maxDelay);
reset();
}
template <int maxDelay> AllpassFilter::AllpassFilter(int maxDelay, int delay, float gain)
void AllpassFilter<maxDelay>::reset() : DelayFilter(maxDelay, delay, gain)
{ {}
index = 0;
memset(buffer, 0, (sizeof (float)) * maxDelay);
}
template <int maxDelay> float AllpassFilter::feed(float x)
float AllpassFilter<maxDelay>::feed(float x)
{ {
float v = x + -gainM * buffer[index]; float v = x + -gain * buffer[index];
float y = buffer[index] + gain0 * v; float y = buffer[index] + gain * v;
buffer[index] = v; buffer[index] = v;
index = (index + 1) % delay; index = (index + 1) % delay;
return y; return y;
} }
struct AudioInstance { //////////////////////////////////////////////////////////////////////
int audio_index; // Reverberators
AudioBuffer * audio_buffer; //////////////////////////////////////////////////////////////////////
uint32_t sample_index;
uint32_t tail_index;
uint32_t fadeout_end;
uint32_t fadeout_index;
poem::poem const * poem;
};
FBReverb::FBReverb() void Reverb::reset()
: cf{FBCF(3229, 1.0f, 0.733f), // 1687
FBCF(3079, 1.0f, 0.802f), // 1601
FBCF(3943, 1.0f, 0.753f), // 2053
FBCF(4327, 1.0f, 0.733f), // 2251
}
, ap{AP(661, 0.7f, 0.7f), // 347
AP(257, 0.7f, 0.7f), // 113
AP(71, 0.7f, 0.7f), // 37
}
{ }
void FBReverb::reset()
{ {
for (int i = 0; i < cfCount; i++) for (int i = 0; i < cfCount; i++)
cf[i].reset(); cf[i].reset();
for (int i = 0; i < apCount; i++) for (int i = 0; i < apCount; i++)
ap[i].reset(); ap[i].reset();
} }
lr FBReverb::feed(float x) lr Reverb::feed(float x)
{ {
for (int i = 0; i < apCount; i++) { for (int i = 0; i < apCount; i++) {
x = ap[i].feed(x); x = ap[i].feed(x);
@ -151,54 +127,54 @@ namespace audio {
return {a, b}; return {a, b};
} }
Reverb::Reverb(DelayFilter * cf, DelayFilter * ap)
FFReverb::FFReverb() : cf(cf), ap(ap)
: cf{FFCF{9209, 1.0f, 0.742f},
FFCF{9601, 1.0f, 0.733f},
FFCF{10369, 1.0f, 0.715f},
FFCF{11131, 1.0f, 0.697f},
}
, ap{AP{2017, 0.7f, 0.7f},
AP{647, 0.7f, 0.7f},
AP{137, 0.7f, 0.7f},
}
{} {}
void FFReverb::reset() static FFCF forwardCF[4]{FFCF{15000, 9209, 0.742f},
{ FFCF{15000, 9601, 0.733f},
for (int i = 0; i < __cfCount; i++) { FFCF{15000, 10369, 0.715f},
printf("reset cf %d\n", i); FFCF{15000, 11131, 0.697f}};
cf[i].reset();
}
for (int i = 0; i < apCount; i++) static AP forwardAP[3]{AP{2500, 2017, 0.7f},
ap[i].reset(); AP{2500, 647, 0.7f},
} AP{2500, 137, 0.7f}};
Reverb forwardReverb(forwardCF, forwardAP);
lr FFReverb::feed(float x) static FBCF backCF[4]{FBCF{10000, 3229, 0.733f}, // 1687
{ FBCF{10000, 3079, 0.802f}, // 1601
for (int i = 0; i < apCount; i++) { FBCF{10000, 3943, 0.753f}, // 2053
x = ap[i].feed(x); FBCF{10000, 4327, 0.733f}}; // 2251
} static AP backAP[3]{AP{1500, 661, 0.7f}, // 347
AP{1500, 257, 0.7f}, // 113
float x0 = cf[0].feed(x); AP{1500, 71, 0.7f}};
float x1 = cf[1].feed(x); Reverb backReverb(backCF, backAP);
float x2 = cf[2].feed(x);
float x3 = cf[3].feed(x);
float s0 = x0 + x1 + x2 + x3;
//float s0 = x0 + x1 + x2;
return {s0, s0};
}
int reverbIndex = 0; int reverbIndex = 0;
FBReverb fbreverb; Reverb * reverbs[] = {
FFReverb ffreverb; &backReverb,
&forwardReverb,
};
int const reverbsCount = (sizeof (reverbs)) / (sizeof (reverbs[0]));
float dryGain = 1.0; float dryGain = 1.0;
float wetGain = 0.25; float wetGain = 0.25;
float mixChannelGain[mixChannelCount]; float mixChannelGain[mixChannelCount];
//////////////////////////////////////////////////////////////////////
// AudioInstance
//////////////////////////////////////////////////////////////////////
struct AudioInstance {
int audio_index;
AudioBuffer * audio_buffer;
uint32_t sample_index;
uint32_t tail_index;
uint32_t fadeout_end;
uint32_t fadeout_index;
poem::poem const * poem;
};
// //
static SDL_AudioStream * audio_stream; static SDL_AudioStream * audio_stream;
@ -221,8 +197,8 @@ namespace audio {
SDL_ResumeAudioStreamDevice(audio_stream); SDL_ResumeAudioStreamDevice(audio_stream);
audio_instances_count = 0; audio_instances_count = 0;
fbreverb.reset(); for (int i = 0; i < reverbsCount; i++)
ffreverb.reset(); reverbs[i]->reset();
for (int i = 0; i < mixChannelCount; i++) { for (int i = 0; i < mixChannelCount; i++) {
mixChannelGain[i] = 1.0f; mixChannelGain[i] = 1.0f;
@ -566,12 +542,8 @@ namespace audio {
float value = channel_buffer[mix_channel::voice][i * channels + 0]; float value = channel_buffer[mix_channel::voice][i * channels + 0];
lr wet; lr wet;
if (reverbIndex == 0) { assert(reverbIndex >= 0 && reverbIndex < reverbsCount);
wet = fbreverb.feed(value); wet = reverbs[reverbIndex]->feed(value);
}
else {
wet = ffreverb.feed(value);
}
float left = value * dryGain + wet.l * wetGain; float left = value * dryGain + wet.l * wetGain;
float right = value * dryGain + wet.r * wetGain; float right = value * dryGain + wet.r * wetGain;
channel_buffer[mix_channel::voice][i * channels + 0] = left; channel_buffer[mix_channel::voice][i * channels + 0] = left;

View File

@ -1000,6 +1000,12 @@ int main()
// 2.17 // 2.17
printf("audio_time %f\n", audio_time); printf("audio_time %f\n", audio_time);
//////////////////////////////////////////////////////////////////////
// ui
//////////////////////////////////////////////////////////////////////
ui::init();
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// interpreter // interpreter
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////

View File

@ -12,76 +12,13 @@ namespace ui
constexpr int combLeft = 700; constexpr int combLeft = 700;
constexpr int outputMixLeft = 1000; constexpr int outputMixLeft = 1000;
#define BREVERB audio::fbreverb
#define FREVERB audio::ffreverb
widget::DelayGainSlider fap[3] { struct ap_comb {
widget::DelayGainSlider("allpass 0", widget::DelayGainSlider ap[3];
allpassLeft, top + ySpace * 0, widget::DelayGainSlider comb[4];
1, 2500, &FREVERB.ap[0].delay,
0.0, 1.0, &FREVERB.ap[0].gain0, &FREVERB.ap[0].gainM),
widget::DelayGainSlider("allpass 1",
allpassLeft, top + ySpace * 1,
1, 2500, &FREVERB.ap[1].delay,
0.0, 1.0, &FREVERB.ap[1].gain0, &FREVERB.ap[1].gainM),
widget::DelayGainSlider("allpass 2",
allpassLeft, top + ySpace * 2,
1, 2500, &FREVERB.ap[2].delay,
0.0, 1.0, &FREVERB.ap[2].gain0, &FREVERB.ap[2].gainM),
}; };
widget::DelayGainSlider fcomb[4] { ap_comb reverberatorSliders[2];
widget::DelayGainSlider("comb 0",
combLeft, top + ySpace * 0,
100, 15000, &FREVERB.cf[0].delay,
0.0, 1.0, &FREVERB.cf[0].gain0, &FREVERB.cf[0].gainM),
widget::DelayGainSlider("comb 1",
combLeft, top + ySpace * 1,
100, 15000, &FREVERB.cf[1].delay,
0.0, 1.0, &FREVERB.cf[1].gain0, &FREVERB.cf[1].gainM),
widget::DelayGainSlider("comb 2",
combLeft, top + ySpace * 2,
100, 15000, &FREVERB.cf[2].delay,
0.0, 1.0, &FREVERB.cf[2].gain0, &FREVERB.cf[2].gainM),
widget::DelayGainSlider("comb 3",
combLeft, top + ySpace * 3,
100, 15000, &FREVERB.cf[3].delay,
0.0, 1.0, &FREVERB.cf[3].gain0, &FREVERB.cf[3].gainM),
};
widget::DelayGainSlider bap[3] {
widget::DelayGainSlider("allpass 0",
allpassLeft, top + ySpace * 0,
1, 2500, &BREVERB.ap[0].delay,
0.0, 1.0, &BREVERB.ap[0].gain0, &BREVERB.ap[0].gainM),
widget::DelayGainSlider("allpass 1",
allpassLeft, top + ySpace * 1,
1, 2500, &BREVERB.ap[1].delay,
0.0, 1.0, &BREVERB.ap[1].gain0, &BREVERB.ap[1].gainM),
widget::DelayGainSlider("allpass 2",
allpassLeft, top + ySpace * 2,
1, 2500, &BREVERB.ap[2].delay,
0.0, 1.0, &BREVERB.ap[2].gain0, &BREVERB.ap[2].gainM),
};
widget::DelayGainSlider bcomb[4] {
widget::DelayGainSlider("comb 0",
combLeft, top + ySpace * 0,
100, 15000, &BREVERB.cf[0].delay,
0.0, 1.0, &BREVERB.cf[0].gain0, &BREVERB.cf[0].gainM),
widget::DelayGainSlider("comb 1",
combLeft, top + ySpace * 1,
100, 15000, &BREVERB.cf[1].delay,
0.0, 1.0, &BREVERB.cf[1].gain0, &BREVERB.cf[1].gainM),
widget::DelayGainSlider("comb 2",
combLeft, top + ySpace * 2,
100, 15000, &BREVERB.cf[2].delay,
0.0, 1.0, &BREVERB.cf[2].gain0, &BREVERB.cf[2].gainM),
widget::DelayGainSlider("comb 3",
combLeft, top + ySpace * 3,
100, 15000, &BREVERB.cf[3].delay,
0.0, 1.0, &BREVERB.cf[3].gain0, &BREVERB.cf[3].gainM),
};
widget::Slider<float, false> dryGain("dry gain", widget::Slider<float, false> dryGain("dry gain",
outputMixLeft, top + yMixSpace * 0, 150, 14, outputMixLeft, top + yMixSpace * 0, 150, 14,
@ -118,6 +55,38 @@ namespace ui
120, 0, 120, 0,
&audio::reverbIndex); &audio::reverbIndex);
void init()
{
static const char * allpassLabels[3] = {
"allpass 0",
"allpass 1",
"allpass 2",
};
static const char * combLabels[4] = {
"comb 0",
"comb 1",
"comb 2",
"comb 3",
};
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
reverberatorSliders[i].ap[j] =
widget::DelayGainSlider(allpassLabels[j],
allpassLeft, top + ySpace * j,
1, audio::reverbs[i]->ap[j].maxDelay, &audio::reverbs[i]->ap[j].delay,
0.0, 1.0, &audio::reverbs[i]->ap[j].gain);
}
for (int j = 0; j < 4; j++) {
reverberatorSliders[i].comb[j] =
widget::DelayGainSlider(combLabels[j],
combLeft, top + ySpace * j,
100, audio::reverbs[i]->cf[j].maxDelay, &audio::reverbs[i]->cf[j].delay,
0.0, 1.0, &audio::reverbs[i]->cf[j].gain);
}
}
}
void draw(MappedInstanceData<SolidInstance> & data, void draw(MappedInstanceData<SolidInstance> & data,
MappedInstanceData<font::BitmapInstance> & fontData) MappedInstanceData<font::BitmapInstance> & fontData)
{ {
@ -127,8 +96,8 @@ namespace ui
0x80000000, 0x80000000,
}); });
widget::DelayGainSlider * ap = (audio::reverbIndex == 0) ? bap : fap; widget::DelayGainSlider * ap = reverberatorSliders[audio::reverbIndex].ap;
widget::DelayGainSlider * comb = (audio::reverbIndex == 0) ? bcomb : fcomb; widget::DelayGainSlider * comb = reverberatorSliders[audio::reverbIndex].comb;
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
ap[i].draw(data, fontData); ap[i].draw(data, fontData);
@ -148,8 +117,8 @@ namespace ui
void update(float mx, float my, bool mLeft, bool mEdge) void update(float mx, float my, bool mLeft, bool mEdge)
{ {
widget::DelayGainSlider * ap = (audio::reverbIndex == 0) ? bap : fap; widget::DelayGainSlider * ap = reverberatorSliders[audio::reverbIndex].ap;
widget::DelayGainSlider * comb = (audio::reverbIndex == 0) ? bcomb : fcomb; widget::DelayGainSlider * comb = reverberatorSliders[audio::reverbIndex].comb;
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
ap[i].update(mx, my, mLeft, mEdge); ap[i].update(mx, my, mLeft, mEdge);

View File

@ -179,15 +179,13 @@ namespace ui::widget
drawStringCentered(fontData, delay.slider.left + delay.slider.width / 2, delay.slider.top - 16, label); drawStringCentered(fontData, delay.slider.left + delay.slider.width / 2, delay.slider.top - 16, label);
delay.draw(data, fontData); delay.draw(data, fontData);
gain0.draw(data, fontData); gain.draw(data, fontData);
gainM.draw(data, fontData);
} }
void DelayGainSlider::update(float mx, float my, bool mLeft, bool mEdge) void DelayGainSlider::update(float mx, float my, bool mLeft, bool mEdge)
{ {
delay.update(mx, my, mLeft, mEdge); delay.update(mx, my, mLeft, mEdge);
gain0.update(mx, my, mLeft, mEdge); gain.update(mx, my, mLeft, mEdge);
gainM.update(mx, my, mLeft, mEdge);
} }
template <int optionCount> template <int optionCount>