diff --git a/Makefile b/Makefile index feb05d6..50e1032 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,9 @@ CFLAGS += -Wno-format CFLAGS += -Wno-error=unused-function CFLAGS += -Wno-error=array-bounds CFLAGS += -Wno-unknown-pragmas +ifneq '' '$(findstring clang++,$(CXX))' CFLAGS += -Wno-vla-cxx-extension +endif CFLAGS += -fno-strict-aliasing CFLAGS += -I./include CFLAGS += -I./data @@ -43,7 +45,7 @@ LDFLAGS += -lm #LDFLAGS += -Wl,--gc-sections #-Wl,--print-gc-sections ifeq ($(UNAME),Linux) -#LDFLAGS += -Wl,-z noexecstack +LDFLAGS += -z noexecstack endif 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 @@ -114,9 +116,6 @@ endif all: main -CC = clang -CXX = clang++ - %.o: %.c $(CC) $(ARCH) $(CSTD) $(CFLAGS) $(FLAGS) $(OPT) $(DEBUG) -c $< -o $@ diff --git a/include/audio.h b/include/audio.h index dc5cb12..7afa9a8 100644 --- a/include/audio.h +++ b/include/audio.h @@ -7,88 +7,57 @@ namespace audio { constexpr int sample_rate = 48000; constexpr int channels = 2; - template - struct FeedbackCombFilter { - 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 - 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 - struct AllpassFilter { - private: - //float * buffer; - float buffer[maxDelay]; + struct DelayFilter { + float * buffer; int index; - public: + const int maxDelay; int delay; - float gain0; - float gainM; + float gain; + + DelayFilter(int maxDelay, int delay, float gain); - AllpassFilter(int delay, float gain0, float gainM); void reset(); - float feed(float x); + virtual float feed(float value) = 0; }; - using FBCF = FeedbackCombFilter<15000>; - using FFCF = FeedforwardCombFilter<15000>; - using AP = AllpassFilter<2500>; + struct FeedbackCombFilter : DelayFilter { + FeedbackCombFilter(int maxDelay, int delay, float gain); + 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 FBReverb { + struct Reverb { + static constexpr int apCount = 3; static constexpr int cfCount = 4; - static constexpr int apCount = 3; - FBCF cf[cfCount]; - AP ap[apCount]; + DelayFilter * cf; + DelayFilter * ap; - FBReverb(); - 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(); + Reverb(DelayFilter * cf, DelayFilter * ap); void reset(); lr feed(float x); }; extern int reverbIndex; - extern FBReverb fbreverb; - extern FFReverb ffreverb; + extern Reverb * reverbs[]; + extern int const reverbsCount; extern float wetGain; extern float dryGain; diff --git a/include/ui.h b/include/ui.h index ed9e71b..a177380 100644 --- a/include/ui.h +++ b/include/ui.h @@ -4,6 +4,7 @@ namespace ui { + void init(); void draw(MappedInstanceData & data, MappedInstanceData & fontData); void update(float mx, float my, bool mLeft, bool mEdge); diff --git a/include/ui/widget.h b/include/ui/widget.h index 0d5bd77..d02a117 100644 --- a/include/ui/widget.h +++ b/include/ui/widget.h @@ -86,6 +86,9 @@ namespace ui::widget T maxExtent; T * value; + Slider() + {} + Slider(char const * label, int left, int top, int width, int height, T minValue, T maxValue, @@ -117,30 +120,27 @@ namespace ui::widget char const * label; Slider delay; - Slider gain0; - Slider gainM; + Slider gain; + + DelayGainSlider() + {} DelayGainSlider(char const * label, int left, int top, int delayMin, int delayMax, int * delayValue, float gainMin, float gainMax, - float * gain0Value, float * gainMValue) + float * gainValue) : label(label) , delay("delay", left, top, 150, 14, delayMin, delayMax, delayMin, delayMax, delayValue) - , gain0("gain0", - left, top + 30, 150, 14, - gainMin, gainMax, - gainMin, gainMax, - gain0Value) - , gainM("gainM", - left, top + 60, 150, 14, - gainMin, gainMax, - gainMin, gainMax, - gainMValue) + , gain("gain", + left, top + 30, 150, 14, + gainMin, gainMax, + gainMin, gainMax, + gainValue) {} void draw(MappedInstanceData & data, diff --git a/src/audio.cpp b/src/audio.cpp index bb53fa2..2fb1610 100644 --- a/src/audio.cpp +++ b/src/audio.cpp @@ -13,14 +13,14 @@ #include "poem.h" 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 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_size = half_period_samples * sample_size * channels; + //static int const half_period_size = half_period_samples * sample_size * channels; struct AudioBuffer { renpy::language::audio const * audio; @@ -28,111 +28,87 @@ namespace audio { uint32_t sample_count; }; - template - FeedbackCombFilter::FeedbackCombFilter(int delay, float gain0, float gainM) - : delay(delay), gain0(gain0), gainM(gainM) + ////////////////////////////////////////////////////////////////////// + // DelayFilter + ////////////////////////////////////////////////////////////////////// + + 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(); } - template - void FeedbackCombFilter::reset() - { - index = 0; - memset(buffer, 0, (sizeof (float)) * maxDelay); - } + ////////////////////////////////////////////////////////////////////// + // FeedbackCombFilter + ////////////////////////////////////////////////////////////////////// - template - float FeedbackCombFilter::feed(float value) + FeedbackCombFilter::FeedbackCombFilter(int maxDelay, int delay, float gain) + : 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; index = (index + 1) % delay; return y; } - template - FeedforwardCombFilter::FeedforwardCombFilter(int delay, float gain0, float gainM) - : delay(delay), gain0(gain0), gainM(gainM) - { - //buffer = (float *)malloc((sizeof (float)) * maxDelay); - reset(); - } + ////////////////////////////////////////////////////////////////////// + // FeedForwardCombFilter + ////////////////////////////////////////////////////////////////////// - template - void FeedforwardCombFilter::reset() - { - index = 0; - memset(buffer, 0, (sizeof (float)) * maxDelay); - } + FeedforwardCombFilter::FeedforwardCombFilter(int maxDelay, int delay, float gain) + : DelayFilter(maxDelay, delay, gain) + {} - template - float FeedforwardCombFilter::feed(float value) + float FeedforwardCombFilter::feed(float value) { - float y = gain0 * value + gainM * buffer[index]; + float y = gain * value + gain * buffer[index]; buffer[index] = value; index = (index + 1) % delay; return y; } - template - AllpassFilter::AllpassFilter(int delay, float gain0, float gainM) - : delay(delay), gain0(gain0), gainM(gainM) - { - //buffer = (float *)malloc((sizeof (float)) * maxDelay); - reset(); - } + ////////////////////////////////////////////////////////////////////// + // AllpassFilter + ////////////////////////////////////////////////////////////////////// - template - void AllpassFilter::reset() - { - index = 0; - memset(buffer, 0, (sizeof (float)) * maxDelay); - } + AllpassFilter::AllpassFilter(int maxDelay, int delay, float gain) + : DelayFilter(maxDelay, delay, gain) + {} - template - float AllpassFilter::feed(float x) + float AllpassFilter::feed(float x) { - float v = x + -gainM * buffer[index]; - float y = buffer[index] + gain0 * v; + float v = x + -gain * buffer[index]; + float y = buffer[index] + gain * v; buffer[index] = v; index = (index + 1) % delay; return y; } - 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; - }; + ////////////////////////////////////////////////////////////////////// + // Reverberators + ////////////////////////////////////////////////////////////////////// - FBReverb::FBReverb() - : 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() + void Reverb::reset() { for (int i = 0; i < cfCount; i++) cf[i].reset(); - for (int i = 0; i < apCount; i++) ap[i].reset(); } - lr FBReverb::feed(float x) + lr Reverb::feed(float x) { for (int i = 0; i < apCount; i++) { x = ap[i].feed(x); @@ -151,54 +127,54 @@ namespace audio { return {a, b}; } + Reverb::Reverb(DelayFilter * cf, DelayFilter * ap) + : cf(cf), ap(ap) + {} - FFReverb::FFReverb() - : 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}, - } - { } + static FFCF forwardCF[4]{FFCF{15000, 9209, 0.742f}, + FFCF{15000, 9601, 0.733f}, + FFCF{15000, 10369, 0.715f}, + FFCF{15000, 11131, 0.697f}}; - void FFReverb::reset() - { - for (int i = 0; i < __cfCount; i++) { - printf("reset cf %d\n", i); - cf[i].reset(); - } + static AP forwardAP[3]{AP{2500, 2017, 0.7f}, + AP{2500, 647, 0.7f}, + AP{2500, 137, 0.7f}}; + Reverb forwardReverb(forwardCF, forwardAP); - for (int i = 0; i < apCount; i++) - ap[i].reset(); - } - - lr FFReverb::feed(float x) - { - for (int i = 0; i < apCount; i++) { - x = ap[i].feed(x); - } - - float x0 = cf[0].feed(x); - float x1 = cf[1].feed(x); - 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}; - } + static FBCF backCF[4]{FBCF{10000, 3229, 0.733f}, // 1687 + FBCF{10000, 3079, 0.802f}, // 1601 + FBCF{10000, 3943, 0.753f}, // 2053 + FBCF{10000, 4327, 0.733f}}; // 2251 + static AP backAP[3]{AP{1500, 661, 0.7f}, // 347 + AP{1500, 257, 0.7f}, // 113 + AP{1500, 71, 0.7f}}; + Reverb backReverb(backCF, backAP); int reverbIndex = 0; - FBReverb fbreverb; - FFReverb ffreverb; + Reverb * reverbs[] = { + &backReverb, + &forwardReverb, + }; + int const reverbsCount = (sizeof (reverbs)) / (sizeof (reverbs[0])); float dryGain = 1.0; float wetGain = 0.25; 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; @@ -221,8 +197,8 @@ namespace audio { SDL_ResumeAudioStreamDevice(audio_stream); audio_instances_count = 0; - fbreverb.reset(); - ffreverb.reset(); + for (int i = 0; i < reverbsCount; i++) + reverbs[i]->reset(); for (int i = 0; i < mixChannelCount; i++) { mixChannelGain[i] = 1.0f; @@ -566,12 +542,8 @@ namespace audio { float value = channel_buffer[mix_channel::voice][i * channels + 0]; lr wet; - if (reverbIndex == 0) { - wet = fbreverb.feed(value); - } - else { - wet = ffreverb.feed(value); - } + assert(reverbIndex >= 0 && reverbIndex < reverbsCount); + wet = reverbs[reverbIndex]->feed(value); float left = value * dryGain + wet.l * wetGain; float right = value * dryGain + wet.r * wetGain; channel_buffer[mix_channel::voice][i * channels + 0] = left; diff --git a/src/main.cpp b/src/main.cpp index d208d5b..2d302e3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1000,6 +1000,12 @@ int main() // 2.17 printf("audio_time %f\n", audio_time); + ////////////////////////////////////////////////////////////////////// + // ui + ////////////////////////////////////////////////////////////////////// + + ui::init(); + ////////////////////////////////////////////////////////////////////// // interpreter ////////////////////////////////////////////////////////////////////// diff --git a/src/ui.cpp b/src/ui.cpp index 3dc980f..6b5972b 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -12,76 +12,13 @@ namespace ui constexpr int combLeft = 700; constexpr int outputMixLeft = 1000; -#define BREVERB audio::fbreverb -#define FREVERB audio::ffreverb - widget::DelayGainSlider fap[3] { - widget::DelayGainSlider("allpass 0", - allpassLeft, top + ySpace * 0, - 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), + struct ap_comb { + widget::DelayGainSlider ap[3]; + widget::DelayGainSlider comb[4]; }; - widget::DelayGainSlider fcomb[4] { - 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), - }; + ap_comb reverberatorSliders[2]; widget::Slider dryGain("dry gain", outputMixLeft, top + yMixSpace * 0, 150, 14, @@ -118,6 +55,38 @@ namespace ui 120, 0, &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 & data, MappedInstanceData & fontData) { @@ -127,8 +96,8 @@ namespace ui 0x80000000, }); - widget::DelayGainSlider * ap = (audio::reverbIndex == 0) ? bap : fap; - widget::DelayGainSlider * comb = (audio::reverbIndex == 0) ? bcomb : fcomb; + widget::DelayGainSlider * ap = reverberatorSliders[audio::reverbIndex].ap; + widget::DelayGainSlider * comb = reverberatorSliders[audio::reverbIndex].comb; for (int i = 0; i < 3; i++) ap[i].draw(data, fontData); @@ -148,8 +117,8 @@ namespace ui void update(float mx, float my, bool mLeft, bool mEdge) { - widget::DelayGainSlider * ap = (audio::reverbIndex == 0) ? bap : fap; - widget::DelayGainSlider * comb = (audio::reverbIndex == 0) ? bcomb : fcomb; + widget::DelayGainSlider * ap = reverberatorSliders[audio::reverbIndex].ap; + widget::DelayGainSlider * comb = reverberatorSliders[audio::reverbIndex].comb; for (int i = 0; i < 3; i++) ap[i].update(mx, my, mLeft, mEdge); diff --git a/src/ui/widget.cpp b/src/ui/widget.cpp index e527627..45222da 100644 --- a/src/ui/widget.cpp +++ b/src/ui/widget.cpp @@ -179,15 +179,13 @@ namespace ui::widget drawStringCentered(fontData, delay.slider.left + delay.slider.width / 2, delay.slider.top - 16, label); delay.draw(data, fontData); - gain0.draw(data, fontData); - gainM.draw(data, fontData); + gain.draw(data, fontData); } void DelayGainSlider::update(float mx, float my, bool mLeft, bool mEdge) { delay.update(mx, my, mLeft, mEdge); - gain0.update(mx, my, mLeft, mEdge); - gainM.update(mx, my, mLeft, mEdge); + gain.update(mx, my, mLeft, mEdge); } template