1 /**
2 * Copyright 2017 Cut Through Recordings
3 * License: MIT License
4 * Author(s): Ethan Reker
5 */
6 module ddsp.effect.effect;
7 
8 import dplug.core.alignedbuffer;
9 import dplug.core.nogc;
10 
11 /**
12 * Should be inherited by all Audio Effect classes to allow for batch processing
13 */
14 abstract class AudioEffect
15 {
16 public:
17     
18     /**
19     * Process a sample that is passed to the processor, and return the next sample.
20     */
21     abstract float getNextSample(const float input) nothrow @nogc;
22     
23     
24     
25     /**
26     * Should be used to free any delay elements or do any setup before play begins.
27     */
28     abstract void reset() nothrow @nogc;
29 
30     /**
31     *
32     */
33     void setSampleRate(float sampleRate) nothrow @nogc
34     {
35         _sampleRate = sampleRate;
36         reset();
37     }
38 
39     float SampleRate() @property { return _sampleRate; }
40     
41 protected:
42     float _sampleRate;
43 }
44 
45 /// Holds a list of AudioEffects.  getNextSample(input)
46 /// call getNextSample(input) on each effect in the chain
47 class FXChain : AudioEffect
48 {
49 public:
50 
51     this()
52     {
53         _fxChain = makeVec!AudioEffect();
54     }
55     
56     /// Adds an effect to the end of the FX Chain
57     void addEffect(AudioEffect effect)
58     {
59         _fxChain.pushBack(effect);
60     }
61 
62     override void setSampleRate(float sampleRate)
63     {
64         foreach(effect; _fxChain)
65         {
66             effect.setSampleRate(sampleRate);
67         }
68     }
69 
70     /// Override from AudioEffect.  Processes the input through each effect
71     /// and passes the result to the next effect.
72     override float getNextSample(const float input) nothrow @nogc
73     {
74         float output = input;
75         foreach(AudioEffect e; _fxChain)
76         {
77             output = e.getNextSample(output);
78         }
79         return output;
80     }
81 
82     /// Resets each effect in the chain. To clear buffers
83     /// and recalculate coefficients.
84     override void reset() nothrow @nogc
85     {
86         foreach(AudioEffect e; _fxChain){
87             e.reset();
88         }
89     }
90 
91 private:
92 
93     /// Vector of audio effects.
94     Vec!AudioEffect _fxChain;
95 }
96 
97 /**
98 * This function should only be called in a unittest block.
99 * AudioEffect effect : Effect to be tested.
100 * string name : name that will be written to output.
101 * size_t bufferSize : number of samples to be processed.
102 * bool outputResults : determines if output should be printed.
103 */
104 void testEffect(AudioEffect effect, string name, size_t bufferSize = 20000, bool outputResults = false)
105 {
106     import std.stdio;
107     import std.random;
108 
109     Random gen;
110 
111     if(outputResults)
112     {
113         writefln("Testing %s..", name);
114         writefln("Initial State: %s", effect.toString()); 
115     }
116 
117     float[] outputs;
118     string[] stringResults;
119 
120     for(int i = 0; i < bufferSize; ++i){
121         float sample = uniform(0.0L, 1.0L, gen);
122         float val = effect.getNextSample(sample);
123         if(i%1000 == 0){
124             outputs ~= val;
125             stringResults ~= effect.toString();
126         }
127     }
128 
129     if(outputResults)
130     {
131         for(int i = 0; i < outputs.length && i < stringResults.length; ++i)
132         {
133             writefln("Output: %s ||| String: %s    ", outputs[i], stringResults[i]);
134         }
135         writefln("End %s test..", name);
136     }
137 
138 }
139 
140 unittest
141 {
142     import std.stdio;
143     import ddsp.effect.digitaldelay;
144 
145     /*auto fxchain = mallocEmplace!FXChain();
146 
147     auto d = mallocEmplace!DigitalDelay();
148     d.initialize(44100, 2000, 500, 0.5, 0.5);
149 
150     auto d2 = mallocEmplace!DigitalDelay();
151     d2.initialize(44100, 2000, 100,  0.1, 0.9);
152 
153     fxchain.addEffect(d);
154 
155     testEffect(fxchain, "FX Chain");*/
156 }