chenlh
2026-03-10 0f65a1a9267b8a7ab4678ef20b07532e4c8377ca
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
 
#pragma once
 
#include <vector>
#include <memory>
#include <array>
#include <cmath>
#include "Utils.h"
#include "RandomBuffer.h"
 
namespace ReverbHallRoom
{
    class MultitapDelay
    {
    public:
        static const int MaxTaps = 256;
        static const int DelayBufferSize = 192000 * 2;
 
    private:
        //float delayBuffer[DelayBufferSize] = { 0 };
        std::vector<float> delayBuffer;
 
        float tapGains[MaxTaps] = { 0 };
        float tapPosition[MaxTaps] = { 0 };
 
        std::vector<float> seedValues;
 
        int writeIdx;
        int seed;
        float crossSeed;
        int count;
        float lengthSamples;
        float decay;
 
    public:
        MultitapDelay() : delayBuffer(DelayBufferSize, 0)
        {
            writeIdx = 0;
            seed = 0;
            crossSeed = 0.0;
            count = 1;
            lengthSamples = 1000;
            decay = 1.0;
            
            UpdateSeeds();
        }
 
        void SetSeed(int seed)
        {
            this->seed = seed;
            UpdateSeeds();
        }
 
        void SetCrossSeed(float crossSeed)
        {
            this->crossSeed = crossSeed;
            UpdateSeeds();
        }
 
        void SetTapCount(int tapCount)
        {
            if (tapCount < 1) tapCount = 1;
            count = tapCount;
            Update();
        }
 
        void SetTapLength(int tapLengthSamples)
        {
            if (tapLengthSamples < 10) tapLengthSamples = 10;
            lengthSamples = tapLengthSamples;
            Update();
        }
 
        void SetTapDecay(float tapDecay)
        {
            decay = tapDecay;
        }
 
        void Process(float* input, float* output, int bufSize)
        {
            float lengthScaler = lengthSamples / (float)count;
            float totalGain = 3.0 / std::sqrtf(1 + count);
            totalGain *= (1 + decay * 2);
 
            for (int i = 0; i < bufSize; i++)
            {
                delayBuffer[writeIdx] = input[i];
                output[i] = 0;
 
                for (int j = 0; j < count; j++)
                {
                    float offset = tapPosition[j] * lengthScaler;
                    float decayEffective = std::expf(-offset / lengthSamples * 3.3) * decay + (1-decay);
                    int readIdx = writeIdx - (int)offset;
                    if (readIdx < 0) readIdx += DelayBufferSize;
 
                    output[i] += delayBuffer[readIdx] * tapGains[j] * decayEffective * totalGain;
                }
 
                writeIdx = (writeIdx + 1) % DelayBufferSize;
            }
        }
 
        void ClearBuffers()
        {
            Utils::ZeroBuffer(delayBuffer.data(), DelayBufferSize);
        }
 
 
    private:
        void Update()
        {
            int s = 0;
            auto rand = [&]() {return seedValues[s++]; };
 
            for (int i = 0; i < MaxTaps; i++)
            {
                float phase = rand() < 0.5 ? 1 : -1;
                tapGains[i] = Utils::DB2Gainf(-20 + rand() * 20) * phase;
                tapPosition[i] = i + rand();
            }
        }
 
        void UpdateSeeds()
        {
            this->seedValues = RandomBuffer::Generate(seed, MaxTaps * 3, crossSeed);
            Update();
        }
    };
}