├── .gitignore
├── Ambience
├── MDAAmbience.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ └── PluginProcessor.h
├── Bandisto
├── MDABandisto.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ └── PluginProcessor.h
├── BeatBox
├── MDABeatBox.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ └── PluginProcessor.h
├── DX10
├── DX10.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ └── PluginProcessor.h
├── Degrade
├── MDADegrade.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ └── PluginProcessor.h
├── Delay
├── MDADelay.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ └── PluginProcessor.h
├── Detune
├── MDADetune.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ └── PluginProcessor.h
├── Dynamics
├── MDADynamics.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ └── PluginProcessor.h
├── EPiano
├── MDAEPiano.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ ├── PluginProcessor.h
│ └── mdaEPianoData.h
├── Envelope
├── MDAEnvelope.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ └── PluginProcessor.h
├── Image
├── MDAImage.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ └── PluginProcessor.h
├── JX10
├── JX10.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ └── PluginProcessor.h
├── LICENSE.txt
├── Limiter
├── MDALimiter.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ └── PluginProcessor.h
├── Loudness
├── MDALoudness.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ └── PluginProcessor.h
├── Overdrive
├── MDAOverdrive.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ └── PluginProcessor.h
├── Piano
├── MDAPiano.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ ├── PluginProcessor.h
│ └── mdaPianoData.h
├── README.markdown
├── RezFilter
├── MDARezFilter.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ └── PluginProcessor.h
├── RingMod
├── MDARingMod.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ └── PluginProcessor.h
├── Shepard
├── MDAShepard.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ └── PluginProcessor.h
├── Splitter
├── MDASplitter.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ └── PluginProcessor.h
├── Stereo
├── MDAStereo.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ └── PluginProcessor.h
├── SubSynth
├── MDASubSynth.jucer
├── README.markdown
└── Source
│ ├── PluginProcessor.cpp
│ └── PluginProcessor.h
└── TestTone
├── MDATestTone.jucer
├── README.markdown
└── Source
├── PluginProcessor.cpp
└── PluginProcessor.h
/.gitignore:
--------------------------------------------------------------------------------
1 | **/.DS_Store
2 | **/Builds
3 | **/JuceLibraryCode
4 | **/*.filtergraph
5 |
6 |
--------------------------------------------------------------------------------
/Ambience/MDAAmbience.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
9 |
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 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Ambience/README.markdown:
--------------------------------------------------------------------------------
1 | # Ambience
2 |
3 | Small space reverberator. Designed to simulate a distant mic in small rooms, without the processor overhead of a full reverb plug-in. Can be used to add "softness" to drums and to simulate someone talking "off mic".
4 |
5 | | Parameter | Description |
6 | | --------- | ----------- |
7 | | Size | Room size (variable from "cardboard box" through "vocal booth" to "medium studio") |
8 | | HF Damp | Gentle low-pass filter to emulate the high frequency absorption of softer wall surfaces |
9 | | Mix | Wet / dry mix (affects perceived distance) |
10 | | Output | Level trim |
11 |
--------------------------------------------------------------------------------
/Ambience/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class MDAAmbienceAudioProcessor : public juce::AudioProcessor
6 | {
7 | public:
8 | MDAAmbienceAudioProcessor();
9 | ~MDAAmbienceAudioProcessor() override;
10 |
11 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
12 | void releaseResources() override;
13 | void reset() override;
14 |
15 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
16 |
17 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
18 |
19 | juce::AudioProcessorEditor *createEditor() override;
20 | bool hasEditor() const override { return true; }
21 |
22 | const juce::String getName() const override;
23 |
24 | bool acceptsMidi() const override { return false; }
25 | bool producesMidi() const override { return false; }
26 | bool isMidiEffect() const override { return false; }
27 | double getTailLengthSeconds() const override { return 0.0; }
28 |
29 | int getNumPrograms() override;
30 | int getCurrentProgram() override;
31 | void setCurrentProgram(int index) override;
32 | const juce::String getProgramName(int index) override;
33 | void changeProgramName(int index, const juce::String &newName) override;
34 |
35 | void getStateInformation(juce::MemoryBlock &destData) override;
36 | void setStateInformation(const void *data, int sizeInBytes) override;
37 |
38 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
39 |
40 | private:
41 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
42 |
43 | void update();
44 | void resetState();
45 |
46 | void flushBuffers();
47 |
48 | // Delay lines. The maximum length of these is hardcoded to 1024 samples.
49 | float *_buf1, *_buf2, *_buf3, *_buf4;
50 |
51 | // Read position in the delay buffers.
52 | int _pos;
53 |
54 | // This sets the length of the delays.
55 | float _size;
56 |
57 | // Feedback coefficient for the allpass filters.
58 | float _feedback;
59 |
60 | // Low-pass filter coefficient for HF damping.
61 | float _damp;
62 |
63 | // Low-pass filter state value.
64 | float _filter;
65 |
66 | // Wet/dry mix.
67 | float _wet, _dry;
68 |
69 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MDAAmbienceAudioProcessor)
70 | };
71 |
--------------------------------------------------------------------------------
/Bandisto/MDABandisto.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
9 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
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 |
--------------------------------------------------------------------------------
/Bandisto/README.markdown:
--------------------------------------------------------------------------------
1 | # Bandisto
2 |
3 | The original Multi-band distortion VST plug-in
4 |
5 | This plug is like MultiBand but uses 3 bands of clipping instead of compression. This is unlikely to be a plug you use every day, but when you want to recreate the sound of torn bass-bins you know where to come!
6 |
7 | | Parameter | Description |
8 | | --------- | ----------- |
9 | | Listen | Audition the low, mid and high bands individually |
10 | | L <> M | Low / mid crossover frequency |
11 | | M <> H | Mid / high crossover frequency |
12 | | L/M/H Dist | Distortion amount for each of the 3 bands |
13 | | L/M/H Out | Output level trims |
14 | | Mode | Set clipping to Bipolar (top and bottom of waveform) or Unipolar (just tops) |
15 |
--------------------------------------------------------------------------------
/Bandisto/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class MDABandistoAudioProcessor : public juce::AudioProcessor
6 | {
7 | public:
8 | MDABandistoAudioProcessor();
9 | ~MDABandistoAudioProcessor() override;
10 |
11 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
12 | void releaseResources() override;
13 | void reset() override;
14 |
15 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
16 |
17 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
18 |
19 | juce::AudioProcessorEditor *createEditor() override;
20 | bool hasEditor() const override { return true; }
21 |
22 | const juce::String getName() const override;
23 |
24 | bool acceptsMidi() const override { return false; }
25 | bool producesMidi() const override { return false; }
26 | bool isMidiEffect() const override { return false; }
27 | double getTailLengthSeconds() const override { return 0.0; }
28 |
29 | int getNumPrograms() override;
30 | int getCurrentProgram() override;
31 | void setCurrentProgram(int index) override;
32 | const juce::String getProgramName(int index) override;
33 | void changeProgramName(int index, const juce::String &newName) override;
34 |
35 | void getStateInformation(juce::MemoryBlock &destData) override;
36 | void setStateInformation(const void *data, int sizeInBytes) override;
37 |
38 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
39 |
40 | private:
41 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
42 |
43 | void update();
44 | void resetState();
45 |
46 | float sampleRate;
47 | float driv1, trim1; // drive and gain for low band
48 | float driv2, trim2; // ... mid band
49 | float driv3, trim3; // ... high band
50 | float fi1, fo1; // filter coefficients
51 | float fi2, fo2;
52 | float fb1, fb2, fb3; // filter delays
53 | float sideLevel; // output level for the stereo data
54 | int valve; // 1 if unipolar mode, 0 if bipolar
55 |
56 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MDABandistoAudioProcessor)
57 | };
58 |
--------------------------------------------------------------------------------
/BeatBox/MDABeatBox.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
9 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
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 |
--------------------------------------------------------------------------------
/BeatBox/README.markdown:
--------------------------------------------------------------------------------
1 | # BeatBox
2 |
3 | Drum replacer / enhancer
4 |
5 | Contains three samples (kick, snare and hat) designed to be triggered by incoming audio in three frequency ranges. The plug-in has built-in drum sounds based on the *Roland CR-78*.
6 |
7 | | Parameter | Description |
8 | | --------- | ----------- |
9 | | Hat Thr | Trigger threshold level |
10 | | Hat Rate | Maximum trigger rate |
11 | | Hat Mix | Sample playback level |
12 | | Kik Thr | |
13 | | Kik Trig | Trigger filter frequency - switches to "key listen" mode while adjusted |
14 | | Kik Mix | |
15 | | Snr Thr | |
16 | | Snr Trig | Trigger filter frequency - increase if snare sample is triggered by kick drum |
17 | | Snr Mix | |
18 | | Dynamics | Apply input signal level variations to output |
19 | | Thru Mix | Allow some of the input signal to be mixed with the output |
20 |
21 | The original plug-in also had a recording mode parameter that let the (advanced) user replace the hi-hat, kick, and snare samples. I did not include this in the JUCE version as it wasn't very convenient to use.
22 |
--------------------------------------------------------------------------------
/BeatBox/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class MDABeatBoxAudioProcessor : public juce::AudioProcessor
6 | {
7 | public:
8 | MDABeatBoxAudioProcessor();
9 | ~MDABeatBoxAudioProcessor() override;
10 |
11 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
12 | void releaseResources() override;
13 | void reset() override;
14 |
15 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
16 |
17 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
18 |
19 | juce::AudioProcessorEditor *createEditor() override;
20 | bool hasEditor() const override { return true; }
21 |
22 | const juce::String getName() const override;
23 |
24 | bool acceptsMidi() const override { return false; }
25 | bool producesMidi() const override { return false; }
26 | bool isMidiEffect() const override { return false; }
27 | double getTailLengthSeconds() const override { return 0.0; }
28 |
29 | int getNumPrograms() override;
30 | int getCurrentProgram() override;
31 | void setCurrentProgram(int index) override;
32 | const juce::String getProgramName(int index) override;
33 | void changeProgramName(int index, const juce::String &newName) override;
34 |
35 | void getStateInformation(juce::MemoryBlock &destData) override;
36 | void setStateInformation(const void *data, int sizeInBytes) override;
37 |
38 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
39 |
40 | private:
41 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
42 |
43 | void update();
44 | void resetState();
45 | void synth();
46 |
47 | float sampleRate;
48 |
49 | float hthr; // hi-hat threshold
50 | float hfil; // high-pass filter state
51 | float hlev; // hat mix
52 | int hdel; // minimum delay in samples between successive hi-hats
53 |
54 | float kthr; // kick threshold
55 | float ksf1, ksf2; // filter coeffs
56 | float ksb1, ksb2; // filter state
57 | float klev; // kick mix
58 | int kdel; // minimum delay in samples between successive kicks
59 |
60 | float kww; // Kik Trig parameter
61 | int ksfx; // if 0, normal operation; if > 0, key listen mode
62 |
63 | float sthr; // snare threshold
64 | float sf1, sf2, sf3; // filter coeffs
65 | float sb1, sb2; // filter state
66 | float slev; // snare mix
67 | int sdel; // minimum delay in samples between successive snares
68 |
69 | float ww; // Snr Trig parameter
70 | int sfx; // if 0, normal operation; if > 0, key listen mode
71 |
72 | float dyne; // current envelope level
73 | float dyna; // envelope attack
74 | float dynr; // envelope release
75 |
76 | float dynm; // Dynamics parameter
77 | float mix; // Thru Mix parameter
78 |
79 | std::unique_ptr hbuf; // buffer containing hi-hat sound
80 | std::unique_ptr kbuf; // kick sound
81 | std::unique_ptr sbufL; // snare is stereo
82 | std::unique_ptr sbufR;
83 |
84 | int hbuflen; // hi-hat buffer length
85 | int kbuflen; // kick buffer length
86 | int sbuflen; // snare buffer length
87 |
88 | int hbufpos; // current position in hi-hat buffer
89 | int kbufpos; // in kick buffer
90 | int sbufpos; // in snare buffer
91 |
92 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MDABeatBoxAudioProcessor)
93 | };
94 |
--------------------------------------------------------------------------------
/DX10/DX10.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
10 |
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 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/DX10/README.markdown:
--------------------------------------------------------------------------------
1 | # DX10
2 |
3 | Simple FM synthesizer. Sounds similar to the later Yamaha DX synths including the heavy bass but with a warmer, cleaner tone.
4 |
5 | | Parameter | Description |
6 | | --------- | ----------- |
7 | | Attack | Envelope attack time |
8 | | Decay | Envelope decay time |
9 | | Release | Envelope release time |
10 | | Ratio | Modulator frequency (as a multiple of the carrier frequency) |
11 | | Fine Ratio | Fine control of modulator frequency for detuning and inharmonic effects |
12 | | Mod Level 1 | Initial modulator level |
13 | | Mod Decay| Time for modulator level to reach... |
14 | | Mod Level 2 | Final modulator level |
15 | | Mod Release | Time for modulator level to reach zero |
16 | | Vel Sens | Veclocity control of modulator level (brightness) |
17 | | Vibrato | Vibrato amount (note that heavy vibrato may also cause additional tone modulation effects) |
18 | | Octave | Octave shift |
19 |
20 | The plug-in is 8-voice polyphonic and is designed for high quality (low aliasing) and low processor usage - this means that some features that would increase processor usage have been left out!
21 |
--------------------------------------------------------------------------------
/DX10/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | const int NPARAMS = 16; // number of parameters
6 | const int NVOICES = 8; // max polyphony
7 |
8 | const float SILENCE = 0.0003f; // voice choking
9 |
10 | // Describes a factory preset.
11 | struct DX10Program
12 | {
13 | DX10Program(const char *name,
14 | float p0, float p1, float p2, float p3,
15 | float p4, float p5, float p6, float p7,
16 | float p8, float p9, float p10, float p11,
17 | float p12, float p13, float p14, float p15);
18 | char name[24];
19 | float param[NPARAMS];
20 | };
21 |
22 | // State for an active voice.
23 | struct Voice
24 | {
25 | // What note triggered this voice, or SUSTAIN when the key is released
26 | // but the sustain pedal is still held down. 0 if the voice is inactive.
27 | int note;
28 |
29 | // Carrier oscillator
30 | float car; // current phase value
31 | float dcar; // phase increment
32 |
33 | // Modulator sine oscillator
34 | float dmod; // phase increment
35 | float mod0;
36 | float mod1;
37 |
38 | // Carrier envelope
39 | float env; // current envelope level
40 | float cenv; // smoothed envelope that includes the attack portion
41 | float catt; // smoothing coefficient for attack
42 | float cdec; // decay mutiplier
43 |
44 | // Modulator envelope
45 | float menv; // current envelope level
46 | float mlev; // target level
47 | float mdec; // decay multiplier
48 | };
49 |
50 | class DX10AudioProcessor : public juce::AudioProcessor
51 | {
52 | public:
53 | DX10AudioProcessor();
54 | ~DX10AudioProcessor() override;
55 |
56 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
57 | void releaseResources() override;
58 | void reset() override;
59 |
60 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
61 |
62 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
63 |
64 | juce::AudioProcessorEditor *createEditor() override;
65 | bool hasEditor() const override { return true; }
66 |
67 | const juce::String getName() const override;
68 |
69 | bool acceptsMidi() const override { return true; }
70 | bool producesMidi() const override { return false; }
71 | bool isMidiEffect() const override { return false; }
72 | double getTailLengthSeconds() const override { return 0.0; }
73 |
74 | int getNumPrograms() override;
75 | int getCurrentProgram() override;
76 | void setCurrentProgram(int index) override;
77 | const juce::String getProgramName(int index) override;
78 | void changeProgramName(int index, const juce::String &newName) override;
79 |
80 | void getStateInformation(juce::MemoryBlock &destData) override;
81 | void setStateInformation(const void *data, int sizeInBytes) override;
82 |
83 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
84 |
85 | private:
86 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
87 |
88 | void update();
89 | void resetState();
90 |
91 | void createPrograms();
92 | void processEvents(juce::MidiBuffer &midiMessages);
93 | void noteOn(int note, int velocity);
94 |
95 | // The factory presets.
96 | std::vector _programs;
97 |
98 | // Index of the active preset.
99 | int _currentProgram;
100 |
101 | // The current sample rate and 1 / sample rate.
102 | float _sampleRate, _inverseSampleRate;
103 |
104 | // MIDI note on / note off events for the current block. Each event is
105 | // described by 3 values: delta time, note number, velocity.
106 | static const int EVENTBUFFER = 120;
107 | int _notes[EVENTBUFFER + 8];
108 |
109 | // Special event code that marks the end of the MIDI events list.
110 | const int EVENTS_DONE = 99999999;
111 |
112 | // Special "note number" that says this voice is now kept alive by the
113 | // sustain pedal being pressed down. As soon as the pedal is released,
114 | // this voice will fade out.
115 | const int SUSTAIN = 128;
116 |
117 | // List of the active voices.
118 | Voice _voices[NVOICES] = { 0 };
119 |
120 | // How many voices are currently in use.
121 | int _numActiveVoices;
122 |
123 | // The LFO only updates every 100 samples. This counter keeps track of when
124 | // the next update is.
125 | int _lfoStep;
126 |
127 | // Used by the LFO to approximate a sine wave.
128 | float _lfo0, _lfo1;
129 |
130 | // Current amount of mod wheel + vibrato modulation. Because the LFO is only
131 | // updated every 100 samples, we need to keep track of this across calls to
132 | // processBlock().
133 | float _modulationAmount;
134 |
135 | // === Parameter values ===
136 |
137 | // Tuning: number of octaves up or down.
138 | float _tune;
139 |
140 | // Fine-tuning: between -1.0 and +1.0 semitones (or -100 to +100 cents).
141 | float _fineTune;
142 |
143 | // Modulator ratio as a multiple of the carrier frequency.
144 | float _ratio;
145 |
146 | // Carrier envelope settings.
147 | float _attack, _decay, _release;
148 |
149 | // Modulator envelope settings.
150 | float _modInitialLevel, _modDecay, _modSustain, _modRelease;
151 |
152 | // Velocity sensitivity for the modulator envelope (for brightness).
153 | float _velocitySensitivity;
154 |
155 | // The amount of vibrato to apply.
156 | float _vibrato;
157 |
158 | // Amount of waveshaping to add extra harmonics.
159 | float _richness;
160 |
161 | // How much to mix the modulator waveform into the final sound by itself.
162 | // Normally the modulator is only used to change the carrier, but for some
163 | // extra snazz you can make the modulator waveform audible as well.
164 | float _modMix;
165 |
166 | // Phase increment for the LFO.
167 | float _lfoInc;
168 |
169 | // === MIDI CC values ===
170 |
171 | // Status of the damper pedal: 64 = pressed, 0 = released.
172 | int _sustain;
173 |
174 | // Output gain in linear units. Can be changed by MIDI CC 7.
175 | float _volume;
176 |
177 | // Modulation wheel value. Used to add more vibrato.
178 | float _modWheel;
179 |
180 | // Pitch bend value.
181 | float _pitchBend;
182 |
183 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DX10AudioProcessor)
184 | };
185 |
--------------------------------------------------------------------------------
/Degrade/MDADegrade.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
9 |
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 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Degrade/README.markdown:
--------------------------------------------------------------------------------
1 | # Degrade
2 |
3 | This plug-in reduces the bit-depth and sample rate of the input audio (using the Quantize and Sample Rate parameters) and has some other features for attaining the sound of vintage digital hardware. The headroom control is a peak clipper, and the Non-Linearity controls add some harmonic distortion to thicken the sound. Post Filter is a low-pass filter to remove some of the grit introduced by the other controls.
4 |
5 | | Parameter | Description |
6 | | --------- | ----------- |
7 | | Headroom | Peak clipping threshold |
8 | | Quantize | Bit depth (typically 8 or below for "telephone" quality) |
9 | | Sample Rate | Reduced sample rate |
10 | | Sample Mode | Sample or Hold for different sound characters |
11 | | Post Filter | Low-pass filter to muffle the distortion produced by the previous controls |
12 | | Non-Linearity | Additional harmonic distortion "thickening" |
13 | | Non-Linear Mode | Odd or Even for different sound characters |
14 | | Output | Level trim |
15 |
--------------------------------------------------------------------------------
/Degrade/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class MDADegradeAudioProcessor : public juce::AudioProcessor
6 | {
7 | public:
8 | MDADegradeAudioProcessor();
9 | ~MDADegradeAudioProcessor() override;
10 |
11 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
12 | void releaseResources() override;
13 | void reset() override;
14 |
15 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
16 |
17 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
18 |
19 | juce::AudioProcessorEditor *createEditor() override;
20 | bool hasEditor() const override { return true; }
21 |
22 | const juce::String getName() const override;
23 |
24 | bool acceptsMidi() const override { return false; }
25 | bool producesMidi() const override { return false; }
26 | bool isMidiEffect() const override { return false; }
27 | double getTailLengthSeconds() const override { return 0.0; }
28 |
29 | int getNumPrograms() override;
30 | int getCurrentProgram() override;
31 | void setCurrentProgram(int index) override;
32 | const juce::String getProgramName(int index) override;
33 | void changeProgramName(int index, const juce::String &newName) override;
34 |
35 | void getStateInformation(juce::MemoryBlock &destData) override;
36 | void setStateInformation(const void *data, int sizeInBytes) override;
37 |
38 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
39 |
40 | private:
41 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
42 |
43 | void update();
44 | float filterFreq(float hz);
45 | void resetState();
46 |
47 | // To reduce the sampling rate, we only read from the input buffer every
48 | // sampleInterval samples.
49 | int _sampleInterval, _sampleIndex;
50 |
51 | // This is 1.0 if sample-and-hold mode is active, 0.0 if not.
52 | float _mode;
53 |
54 | // Used to perform quantizing.
55 | float _g1, _g2;
56 |
57 | // Non-linearity values for negative and positive samples.
58 | float _linNeg, _linPos;
59 |
60 | // Level for headroom clipping.
61 | float _clip;
62 |
63 | // Output gain.
64 | float _g3;
65 |
66 | // Filter coefficients.
67 | float _fi, _fo;
68 |
69 | // Sum of the previous samples in sample-and-hold mode.
70 | float _accum;
71 |
72 | // The most recently computed sample value, before filtering.
73 | float _currentSample;
74 |
75 | // Delay units for the 8 filter stages.
76 | float _buf1, _buf2, _buf3, _buf4, _buf6, _buf7, _buf8, _buf9;
77 |
78 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MDADegradeAudioProcessor)
79 | };
80 |
--------------------------------------------------------------------------------
/Delay/MDADelay.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
9 |
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 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Delay/README.markdown:
--------------------------------------------------------------------------------
1 | # Delay
2 |
3 | Simple stereo delay with feedback tone control.
4 |
5 | | Parameter | Description |
6 | | --------- | ----------- |
7 | | Left Delay | Left channel delay time |
8 | | Right Delay | Right channel delay as a percentage of left channel delay - variable to left, fixed ratios to right |
9 | | Feedback | Feedback (sum of left and right outputs) |
10 | | FB Tone | Feedback filtering - low-pass to left, high-pass to right |
11 | | FX Mix | Wet / dry mix |
12 | | Output | Level trim |
13 |
--------------------------------------------------------------------------------
/Delay/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class MDADelayAudioProcessor : public juce::AudioProcessor
6 | {
7 | public:
8 | MDADelayAudioProcessor();
9 | ~MDADelayAudioProcessor() override;
10 |
11 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
12 | void releaseResources() override;
13 | void reset() override;
14 |
15 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
16 |
17 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
18 |
19 | juce::AudioProcessorEditor *createEditor() override;
20 | bool hasEditor() const override { return true; }
21 |
22 | const juce::String getName() const override;
23 |
24 | bool acceptsMidi() const override { return false; }
25 | bool producesMidi() const override { return false; }
26 | bool isMidiEffect() const override { return false; }
27 | double getTailLengthSeconds() const override { return 0.0; }
28 |
29 | int getNumPrograms() override;
30 | int getCurrentProgram() override;
31 | void setCurrentProgram(int index) override;
32 | const juce::String getProgramName(int index) override;
33 | void changeProgramName(int index, const juce::String &newName) override;
34 |
35 | void getStateInformation(juce::MemoryBlock &destData) override;
36 | void setStateInformation(const void *data, int sizeInBytes) override;
37 |
38 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
39 |
40 | private:
41 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
42 |
43 | void update();
44 | void resetState();
45 |
46 | // Maps the position of the right delay slider to a percentage of the left
47 | // channel delay time. Moving the slider to the left gives you a variable
48 | // ratio between 0% and 200%. Moving the slider to the right chooses from a
49 | // set of fixed ratios. At the center position, the ratio is 200%.
50 | static float rightDelayRatio(float param);
51 |
52 | // Maximum delay time in milliseconds. Feel free to make this smaller or
53 | // larger. The original plug-in used a fixed number of samples, but that
54 | // would make the maximum delay time different if the sample rate changed.
55 | static constexpr float _delayMaxMsec = 500.0f;
56 |
57 | // Maximum length of the delay buffer in samples.
58 | int _delayMax;
59 |
60 | // This buffer stores the delayed samples. There is only one delay buffer,
61 | // which means any echos from the delayed signal are actually mono.
62 | std::vector _delayBuffer;
63 |
64 | // Delay time in samples for the left & right channels.
65 | int _ldel, _rdel;
66 |
67 | // Write position in the delay buffer. This is where we will write the next
68 | // new sample value.
69 | int _pos;
70 |
71 | // Wet & dry mix.
72 | float _wet, _dry;
73 |
74 | // Amount of echo feedback.
75 | float _feedback;
76 |
77 | // Low & high mix for the crossover filter.
78 | float _lmix, _hmix;
79 |
80 | // Low-pass filter coefficient.
81 | float _filt;
82 |
83 | // Delay unit for the low-pass filter.
84 | float _filt0;
85 |
86 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MDADelayAudioProcessor)
87 | };
88 |
--------------------------------------------------------------------------------
/Detune/MDADetune.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
9 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
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 |
--------------------------------------------------------------------------------
/Detune/README.markdown:
--------------------------------------------------------------------------------
1 | # Detune
2 |
3 | A low-quality stereo pitch shifter for the sort of chorus and detune effects found on multi-effects hardware.
4 |
5 | | Parameter | Description |
6 | | --------- | ----------- |
7 | | Detune | Detune amount in cents (left channel is lowered in pitch, right channel is raised) |
8 | | Mix | Wet / dry mix |
9 | | Output | Level trim |
10 | | Latency | Trade-off between latency and low-frequency response |
11 |
12 | This plug-in is a pitch shifter designed to produce the classic detune effect, where the left channel is shifted down in pitch and the right channel is shifted up. This sounds similar to a chorus effect, but with less obvious modulation. The delay inherent in the pitch shifting process can be adjusted with the Latency control — longer settings are needed to make low frequency signals sound smoother, but can also add a nice doubling effect to vocals.
13 |
--------------------------------------------------------------------------------
/Detune/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class MDADetuneAudioProcessor : public juce::AudioProcessor
6 | {
7 | public:
8 | MDADetuneAudioProcessor();
9 | ~MDADetuneAudioProcessor() override;
10 |
11 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
12 | void releaseResources() override;
13 | void reset() override;
14 |
15 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
16 |
17 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
18 |
19 | juce::AudioProcessorEditor *createEditor() override;
20 | bool hasEditor() const override { return true; }
21 |
22 | const juce::String getName() const override;
23 |
24 | bool acceptsMidi() const override { return false; }
25 | bool producesMidi() const override { return false; }
26 | bool isMidiEffect() const override { return false; }
27 | double getTailLengthSeconds() const override { return 0.0; }
28 |
29 | int getNumPrograms() override;
30 | int getCurrentProgram() override;
31 | void setCurrentProgram(int index) override;
32 | const juce::String getProgramName(int index) override;
33 | void changeProgramName(int index, const juce::String &newName) override;
34 |
35 | void getStateInformation(juce::MemoryBlock &destData) override;
36 | void setStateInformation(const void *data, int sizeInBytes) override;
37 |
38 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
39 |
40 | private:
41 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
42 |
43 | void update();
44 | void resetState();
45 |
46 | static constexpr int BUFMAX = 4096;
47 |
48 | float buf[BUFMAX]; // circular buffer for delay line (mono)
49 | float win[BUFMAX]; // crossfade window
50 |
51 | float sampleRate;
52 | int buflen; // delay length
53 |
54 | int pos0; // write pointer in the circular buffer
55 | float pos1, dpos1; // read pointer and step size for left channel
56 | float pos2, dpos2; // and for right channel
57 |
58 | float wet, dry; // output levels
59 |
60 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MDADetuneAudioProcessor)
61 | };
62 |
--------------------------------------------------------------------------------
/Dynamics/MDADynamics.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
9 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
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 |
--------------------------------------------------------------------------------
/Dynamics/README.markdown:
--------------------------------------------------------------------------------
1 | # Dynamics
2 |
3 | Modern-sounding Compressor / Limiter / Gate with low processor usage
4 |
5 | This plug-in is a very ordinary analog-style compressor and noise gate, designed to sound like the dynamics section from a large- format mixer. A peak limiter is preset to 0 dB FS (the compressor release time parameter also sets the limiter release).
6 |
7 | | Parameter | Description |
8 | | --------- | ----------- |
9 | | Threshold | |
10 | | Ratio | Very wide range allows "overcompression" where output gets quieter as input gets louder |
11 | | Output | Level trim |
12 | | Attack | |
13 | | Release | |
14 | | Limiter | Limiter threshold - the limiter has zero attack time but uses the same release time as the compressor |
15 | | Gate Thresh | |
16 | | Gate Attack | |
17 | | Gate Release | |
18 |
--------------------------------------------------------------------------------
/Dynamics/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class MDADynamicsAudioProcessor : public juce::AudioProcessor
6 | {
7 | public:
8 | MDADynamicsAudioProcessor();
9 | ~MDADynamicsAudioProcessor() override;
10 |
11 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
12 | void releaseResources() override;
13 | void reset() override;
14 |
15 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
16 |
17 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
18 |
19 | juce::AudioProcessorEditor *createEditor() override;
20 | bool hasEditor() const override { return true; }
21 |
22 | const juce::String getName() const override;
23 |
24 | bool acceptsMidi() const override { return false; }
25 | bool producesMidi() const override { return false; }
26 | bool isMidiEffect() const override { return false; }
27 | double getTailLengthSeconds() const override { return 0.0; }
28 |
29 | int getNumPrograms() override;
30 | int getCurrentProgram() override;
31 | void setCurrentProgram(int index) override;
32 | const juce::String getProgramName(int index) override;
33 | void changeProgramName(int index, const juce::String &newName) override;
34 |
35 | void getStateInformation(juce::MemoryBlock &destData) override;
36 | void setStateInformation(const void *data, int sizeInBytes) override;
37 |
38 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
39 |
40 | private:
41 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
42 |
43 | void update();
44 | void resetState();
45 |
46 | float threshold; // threshold for compressor
47 | float ratio; // ratio for compressor
48 | float trim; // makeup gain
49 | float attack; // envelope attack coefficient
50 | float release; // envelope release coefficient
51 | float limiterThreshold; // limiter threshold
52 | float gateThreshold; // gate threshold
53 | float gateAttack; // gate attack coefficient
54 | float gateRelease; // gate release coefficient
55 | float dry; // dry/wet mix amount
56 | bool compressOnly; // if false, also apply limiter & gate
57 |
58 | float env; // current envelope level
59 | float limiterEnv; // envelope used by the limiter
60 | float gateEnv; // envelope used by the gate
61 |
62 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MDADynamicsAudioProcessor)
63 | };
64 |
--------------------------------------------------------------------------------
/EPiano/MDAEPiano.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
12 |
14 |
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 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/EPiano/README.markdown:
--------------------------------------------------------------------------------
1 | # EPiano
2 |
3 | Rhodes piano. This plug-in is extremely similar to MDA Piano, but uses different samples. It also has some basic LFO modulation.
4 |
--------------------------------------------------------------------------------
/EPiano/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | const int NPARAMS = 12; // number of parameters
6 | const int NPROGS = 8; // number of programs
7 | const int NVOICES = 32; // max polyphony
8 |
9 | const float SILENCE = 0.0001f; // voice choking
10 |
11 | // Describes a factory preset.
12 | struct MDAEPianoProgram
13 | {
14 | MDAEPianoProgram(const char *name,
15 | float p0, float p1, float p2, float p3,
16 | float p4, float p5, float p6, float p7,
17 | float p8, float p9, float p10, float p11);
18 | char name[24];
19 | float param[NPARAMS];
20 | };
21 |
22 | // A keygroup maps notes to waveforms. All the waveforms are stored inside one
23 | // big lookup table (see mdaEPianoData.h). There are 15 keygroups, each covering
24 | // 4 semitones. That's 60 notes in total. A piano has 88 keys so very low notes
25 | // all share the same waveform; likewise for very high notes. The waveforms are
26 | // mono, 22050 Hz, and consist of an attack portion and a loop portion.
27 | struct Keygroup
28 | {
29 | int root; // MIDI root note (usually the note in the middle of the keygroup)
30 | int high; // highest note this waveform should be used for
31 | int pos; // index of the first sample in the lookup table
32 | int end; // index of the last sample in the lookup table
33 | int loop; // how far from end the first sample of the loop is
34 | };
35 |
36 | // State for an active voice.
37 | struct Voice
38 | {
39 | // What note triggered this voice, or SUSTAIN when the key is released
40 | // but the sustain pedal is held down.
41 | int note;
42 |
43 | // The increment for stepping through the waveform table. This is stored as
44 | // a fixed point value, where 65536 = 1.0. For example, a step size of 0.5
45 | // has a delta of 32768.
46 | int delta;
47 |
48 | // The fractional part of the current position in the waveform. This is
49 | // stored using 16 bits. The highest value it can have is 65535, which is
50 | // approximately 0.99999.
51 | int frac;
52 |
53 | // These are copied from the keygroup for this note. When we start playing
54 | // the note, pos is incremented by delta until it reaches end, and then it
55 | // wraps back to the loop index.
56 | int pos;
57 | int end;
58 | int loop;
59 |
60 | // The current envelope level and the exponential decay value that the
61 | // envelope is multiplied with on every step. Setting the decay to 0.99
62 | // will fade out the sound almost immediately (used for all notes off).
63 | float env;
64 | float decay;
65 |
66 | // Panning volumes for the left and right channels.
67 | float outl;
68 | float outr;
69 | };
70 |
71 | class MDAEPianoAudioProcessor : public juce::AudioProcessor
72 | {
73 | public:
74 | MDAEPianoAudioProcessor();
75 | ~MDAEPianoAudioProcessor() override;
76 |
77 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
78 | void releaseResources() override;
79 | void reset() override;
80 |
81 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
82 |
83 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
84 |
85 | juce::AudioProcessorEditor *createEditor() override;
86 | bool hasEditor() const override { return true; }
87 |
88 | const juce::String getName() const override;
89 |
90 | bool acceptsMidi() const override { return true; }
91 | bool producesMidi() const override { return false; }
92 | bool isMidiEffect() const override { return false; }
93 | double getTailLengthSeconds() const override { return 0.0; }
94 |
95 | int getNumPrograms() override;
96 | int getCurrentProgram() override;
97 | void setCurrentProgram(int index) override;
98 | const juce::String getProgramName(int index) override;
99 | void changeProgramName(int index, const juce::String &newName) override;
100 |
101 | void getStateInformation(juce::MemoryBlock &destData) override;
102 | void setStateInformation(const void *data, int sizeInBytes) override;
103 |
104 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
105 |
106 | private:
107 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
108 |
109 | void update();
110 | void resetState();
111 |
112 | void createPrograms();
113 | void processEvents(juce::MidiBuffer &midiMessages);
114 | void noteOn(int note, int velocity);
115 |
116 | // The factory presets.
117 | std::vector _programs;
118 |
119 | // Index of the active preset.
120 | int _currentProgram;
121 |
122 | // The current sample rate and 1 / sample rate.
123 | float _sampleRate, _inverseSampleRate;
124 |
125 | // MIDI note on / note off events for the current block. Each event is
126 | // described by 3 values: delta time, note number, velocity.
127 | static const int EVENTBUFFER = 120;
128 | int _notes[EVENTBUFFER + 8];
129 |
130 | // Special event code that marks the end of the MIDI events list.
131 | const int EVENTS_DONE = 99999999;
132 |
133 | // Special "note number" that says this voice is now kept alive by the
134 | // sustain pedal being pressed down. As soon as the pedal is released,
135 | // this voice will fade out.
136 | const int SUSTAIN = 128;
137 |
138 | // Big lookup table with waveforms containing the piano samples.
139 | short *_waves;
140 |
141 | // Maps the waveforms from the _waves lookup table to ranges of notes.
142 | Keygroup _keygroups[33] = { 0 };
143 |
144 | // List of the active voices.
145 | Voice _voices[NVOICES];
146 |
147 | // How many voices are currently in use.
148 | int _numActiveVoices;
149 |
150 | // Status of the damper pedal: 64 = pressed, 0 = released.
151 | int _sustain;
152 |
153 | // Output gain in linear units. Can be changed by MIDI CC 7.
154 | float _volume;
155 |
156 | // Max number of voices of polyphony.
157 | int _polyphony;
158 |
159 | // Envelope decay length (lower is shorter). Used when playing a new note.
160 | float _envDecay;
161 |
162 | // Value of the envelope release parameter, 0.0 - 1.0. This is used after a
163 | // note off event (if the sustain pedal is not pressed).
164 | float _envRelease;
165 |
166 | // This changes which waveform to use for a given note, by not selecting
167 | // the note's own keygroup but one of its neighboring keygroups.
168 | int _hardnessOffset;
169 |
170 | // Settings for the treble boost filter.
171 | float _trebleGain;
172 | float _filtCoef;
173 |
174 | // Delay units for the treble boost filter.
175 | float _filtL, _filtR;
176 |
177 | // Amount of modulation: 0.0 means 100% autopanning, 0.5 = no modulation,
178 | // 1.0 = 100% tremolo.
179 | float _modulation;
180 |
181 | // Amount of modulation (LFO depth) for left and right channels.
182 | float _lmod, _rmod;
183 |
184 | // The LFO phase increment in radians.
185 | float _lfoRate;
186 |
187 | // Current phase for the LFO. _lf0 describes a sine wave, while _lfo1 is a
188 | // cosine wave.
189 | float _lfo0, _lfo1;
190 |
191 | // Used to set the envelope level for new notes. Value between 0.25 and 3.0.
192 | float _velocitySensitivity;
193 |
194 | // Amount of fine-tuning, in semitones.
195 | float _fine;
196 |
197 | // Amount of random detuning.
198 | float _random;
199 |
200 | // For calculating the stereo width.
201 | float _width;
202 |
203 | // Amount of overdrive.
204 | float _overdrive;
205 |
206 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MDAEPianoAudioProcessor)
207 | };
208 |
--------------------------------------------------------------------------------
/Envelope/MDAEnvelope.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
9 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
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 |
--------------------------------------------------------------------------------
/Envelope/README.markdown:
--------------------------------------------------------------------------------
1 | # Envelope
2 |
3 | Envelope follower and VCA
4 |
5 | | Parameter | Description |
6 | | --------- | ----------- |
7 | | Output | see below |
8 | | Attack | |
9 | | Release | |
10 | | Gain | Level trim |
11 |
12 | The Output parameter can have the following values:
13 |
14 | - **L x |R|**: multiplies left channel signal by right channel level (VCA mode)
15 | - **IN/ENV**: left channel is not processed, right output is a DC signal derived from the input signal level
16 | - **FLAT/ENV**: as IN/ENV but the left channel is processed to remove level variations
17 |
18 | Normally two Envelope plug-ins will be used with the first set to **FLAT/ENV** to separate the signal waveform and envelope and the second set to **L x |R|** to recombine them. Effects applied to either the left or right channel between these plug-ins can be used to process the waveform and envelope separately, for example delaying the envelope relative to the waveform, or applying waveshaping with a constant "drive" level.
19 |
20 | Note that in **L x |R|** mode with a mono input the plug-in acts as a 2:1 expander.
21 |
22 | > **WARNING!** This plug is intended for advanced users and is best suited to modular environents such as AudioMulch. It can output high levels of DC which may damage speakers and other equipment.
23 |
--------------------------------------------------------------------------------
/Envelope/Source/PluginProcessor.cpp:
--------------------------------------------------------------------------------
1 | #include "PluginProcessor.h"
2 |
3 | MDAEnvelopeAudioProcessor::MDAEnvelopeAudioProcessor()
4 | : AudioProcessor(BusesProperties()
5 | .withInput ("Input", juce::AudioChannelSet::stereo(), true)
6 | .withOutput("Output", juce::AudioChannelSet::stereo(), true))
7 | {
8 | }
9 |
10 | MDAEnvelopeAudioProcessor::~MDAEnvelopeAudioProcessor()
11 | {
12 | }
13 |
14 | const juce::String MDAEnvelopeAudioProcessor::getName() const
15 | {
16 | return JucePlugin_Name;
17 | }
18 |
19 | int MDAEnvelopeAudioProcessor::getNumPrograms()
20 | {
21 | return 1;
22 | }
23 |
24 | int MDAEnvelopeAudioProcessor::getCurrentProgram()
25 | {
26 | return 0;
27 | }
28 |
29 | void MDAEnvelopeAudioProcessor::setCurrentProgram(int index)
30 | {
31 | }
32 |
33 | const juce::String MDAEnvelopeAudioProcessor::getProgramName(int index)
34 | {
35 | return {};
36 | }
37 |
38 | void MDAEnvelopeAudioProcessor::changeProgramName(int index, const juce::String &newName)
39 | {
40 | }
41 |
42 | void MDAEnvelopeAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock)
43 | {
44 | resetState();
45 | }
46 |
47 | void MDAEnvelopeAudioProcessor::releaseResources()
48 | {
49 | }
50 |
51 | void MDAEnvelopeAudioProcessor::reset()
52 | {
53 | resetState();
54 | }
55 |
56 | bool MDAEnvelopeAudioProcessor::isBusesLayoutSupported(const BusesLayout &layouts) const
57 | {
58 | return layouts.getMainOutputChannelSet() == juce::AudioChannelSet::stereo();
59 | }
60 |
61 | void MDAEnvelopeAudioProcessor::resetState()
62 | {
63 | env = 0.0f;
64 | releaseRate = 0.0f;
65 | }
66 |
67 | void MDAEnvelopeAudioProcessor::update()
68 | {
69 | mode = apvts.getRawParameterValue("Output")->load();
70 |
71 | // Convert attack time to filter coefficient.
72 | float fParam2 = apvts.getRawParameterValue("Attack")->load();
73 | attack = std::pow(10.0f, -0.002f - 4.0f * fParam2);
74 |
75 | // Convert release time to filter coefficient.
76 | float fParam3 = apvts.getRawParameterValue("Release")->load();
77 | release = 1.0f - std::pow(10.0f, -2.0f - 3.0f * fParam3);
78 |
79 | // Convert decibels to linear gain.
80 | float fParam4 = apvts.getRawParameterValue("Gain")->load();
81 | gain = std::pow(10.f, 0.05f * fParam4);
82 |
83 | // Constant gain across modes.
84 | if (mode == 0) {
85 | gain *= 2.0f;
86 | } else {
87 | gain *= 0.5f;
88 | }
89 | }
90 |
91 | void MDAEnvelopeAudioProcessor::processBlock(juce::AudioBuffer &buffer, juce::MidiBuffer &midiMessages)
92 | {
93 | juce::ScopedNoDenormals noDenormals;
94 | auto totalNumInputChannels = getTotalNumInputChannels();
95 | auto totalNumOutputChannels = getTotalNumOutputChannels();
96 |
97 | // Clear any output channels that don't contain input data.
98 | for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i) {
99 | buffer.clear(i, 0, buffer.getNumSamples());
100 | }
101 |
102 | update();
103 |
104 | const float *in1 = buffer.getReadPointer(0);
105 | const float *in2 = buffer.getReadPointer(1);
106 | float *out1 = buffer.getWritePointer(0);
107 | float *out2 = buffer.getWritePointer(1);
108 |
109 | if (releaseRate > 1.0f - release) { // can be unstable if release changed
110 | releaseRate = 1.0f - release;
111 | }
112 |
113 | bool flat = (mode == 2); // flatten output audio?
114 |
115 | if (mode > 0) { // envelope follower mode
116 | for (int i = 0; i < buffer.getNumSamples(); ++i) {
117 | // Combine both channels into a single signal (make mono).
118 | float b = in1[i] + in2[i];
119 |
120 | // Basic envelope follower: If the input signal exceeds the current
121 | // envelope value, then increase the envelope. The attack determines
122 | // how fast this happens, using a one-pole filter. Otherwise, if the
123 | // signal is below the current envelope value, decrease the envelope
124 | // level using the release coefficient.
125 |
126 | float x = (b < 0.0f) ? -b : b; // rectify
127 | if (x > env) {
128 | env += attack * (x - env); // attack
129 | releaseRate = 1.0f - release; // reset rate
130 | } else {
131 | env *= release + releaseRate; // release
132 | releaseRate *= 0.9999f; // increase release rate
133 | }
134 |
135 | // Audio output is the combined signal.
136 | x = gain * b;
137 |
138 | // Flatten audio signal by dividing by envelope value.
139 | if (flat) {
140 | if (env < 0.01f) { // don't divide by zero
141 | x *= 100.0f;
142 | } else {
143 | x /= env;
144 | }
145 | }
146 |
147 | out1[i] = x; // audio on left channel
148 | out2[i] = 0.5f * env; // envelope on right channel
149 | }
150 | } else { // VCA mode
151 | for (int i = 0; i < buffer.getNumSamples(); ++i) {
152 | float a = in1[i];
153 | float b = in2[i];
154 |
155 | // Same envelope follower as above, but only on right channel.
156 | float x = (b < 0.0f) ? -b : b;
157 | if (x > env) {
158 | env += attack * (x - env);
159 | releaseRate = 1.0f - release;
160 | } else {
161 | env *= release + releaseRate;
162 | releaseRate *= 0.9999f;
163 | }
164 |
165 | // Apply the envelope to the audio from the left channel.
166 | x = gain * a * env;
167 |
168 | // Output the same audio signal on both channels.
169 | out1[i] = x;
170 | out2[i] = x;
171 | }
172 | }
173 | }
174 |
175 | juce::AudioProcessorEditor *MDAEnvelopeAudioProcessor::createEditor()
176 | {
177 | return new juce::GenericAudioProcessorEditor(*this);
178 | }
179 |
180 | void MDAEnvelopeAudioProcessor::getStateInformation(juce::MemoryBlock &destData)
181 | {
182 | copyXmlToBinary(*apvts.copyState().createXml(), destData);
183 | }
184 |
185 | void MDAEnvelopeAudioProcessor::setStateInformation(const void *data, int sizeInBytes)
186 | {
187 | std::unique_ptr xml(getXmlFromBinary(data, sizeInBytes));
188 | if (xml.get() != nullptr && xml->hasTagName(apvts.state.getType())) {
189 | apvts.replaceState(juce::ValueTree::fromXml(*xml));
190 | }
191 | }
192 |
193 | juce::AudioProcessorValueTreeState::ParameterLayout MDAEnvelopeAudioProcessor::createParameterLayout()
194 | {
195 | juce::AudioProcessorValueTreeState::ParameterLayout layout;
196 |
197 | layout.add(std::make_unique(
198 | juce::ParameterID("Output", 1),
199 | "Output",
200 | juce::StringArray { "L x |R|", "IN/ENV", "FLAT/ENV" },
201 | 0));
202 |
203 | layout.add(std::make_unique(
204 | juce::ParameterID("Attack", 1),
205 | "Attack",
206 | juce::NormalisableRange(),
207 | 0.25f,
208 | juce::AudioParameterFloatAttributes()
209 | .withLabel("ms")
210 | .withStringFromValueFunction([](float value, int)
211 | {
212 | return juce::String(int(std::pow(10.0f, 3.0f * value)));
213 | })));
214 |
215 | layout.add(std::make_unique(
216 | juce::ParameterID("Release", 1),
217 | "Release",
218 | juce::NormalisableRange(),
219 | 0.4f,
220 | juce::AudioParameterFloatAttributes()
221 | .withLabel("ms")
222 | .withStringFromValueFunction([](float value, int)
223 | {
224 | return juce::String(int(std::pow(10.0f, 4.0f * value)));
225 | })));
226 |
227 | // Comment from original code:
228 | // attack & release times not accurate - included to make user happy!
229 |
230 | layout.add(std::make_unique(
231 | juce::ParameterID("Gain", 1),
232 | "Gain",
233 | juce::NormalisableRange(-20.0f, 20.0f, 0.01f),
234 | 0.0f,
235 | juce::AudioParameterFloatAttributes().withLabel("dB")));
236 |
237 | return layout;
238 | }
239 |
240 | juce::AudioProcessor *JUCE_CALLTYPE createPluginFilter()
241 | {
242 | return new MDAEnvelopeAudioProcessor();
243 | }
244 |
--------------------------------------------------------------------------------
/Envelope/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class MDAEnvelopeAudioProcessor : public juce::AudioProcessor
6 | {
7 | public:
8 | MDAEnvelopeAudioProcessor();
9 | ~MDAEnvelopeAudioProcessor() override;
10 |
11 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
12 | void releaseResources() override;
13 | void reset() override;
14 |
15 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
16 |
17 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
18 |
19 | juce::AudioProcessorEditor *createEditor() override;
20 | bool hasEditor() const override { return true; }
21 |
22 | const juce::String getName() const override;
23 |
24 | bool acceptsMidi() const override { return false; }
25 | bool producesMidi() const override { return false; }
26 | bool isMidiEffect() const override { return false; }
27 | double getTailLengthSeconds() const override { return 0.0; }
28 |
29 | int getNumPrograms() override;
30 | int getCurrentProgram() override;
31 | void setCurrentProgram(int index) override;
32 | const juce::String getProgramName(int index) override;
33 | void changeProgramName(int index, const juce::String &newName) override;
34 |
35 | void getStateInformation(juce::MemoryBlock &destData) override;
36 | void setStateInformation(const void *data, int sizeInBytes) override;
37 |
38 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
39 |
40 | private:
41 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
42 |
43 | void update();
44 | void resetState();
45 |
46 | int mode; // 0, 1, 2
47 | float attack; // attack coefficient
48 | float release; // release coefficient
49 | float gain; // output gain
50 |
51 | float env; // current envelope level
52 | float releaseRate; // release delta
53 |
54 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MDAEnvelopeAudioProcessor)
55 | };
56 |
--------------------------------------------------------------------------------
/Image/MDAImage.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
9 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
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 |
--------------------------------------------------------------------------------
/Image/README.markdown:
--------------------------------------------------------------------------------
1 | # Image
2 |
3 | Stereo image adjuster and MS matrix
4 |
5 | Allows the level and pan of mono and stereo components to be adjusted separately, or components to be separated for individual processing before recombining with a second *Image* plug-in.
6 |
7 | | Parameter | Description |
8 | | --------- | ----------- |
9 | | Mode | see below |
10 | | S Width | Stereo width (level of stereo component) |
11 | | S Pan | Stereo image "skew" |
12 | | M Level | Centre "depth" |
13 | | M Pan | Centre pan |
14 | | Output | Level trim (a 6dB correction may be required for some MS encoded material) |
15 |
16 | Possible modes:
17 |
18 | - **LR->LR**: stereo image adjustment
19 | - **LR->MS**: encode to MS
20 | - **MS->LR**: decode from MS
21 | - **SM->LR**: decode from MS (input channels reversed)
22 |
--------------------------------------------------------------------------------
/Image/Source/PluginProcessor.cpp:
--------------------------------------------------------------------------------
1 | #include "PluginProcessor.h"
2 |
3 | MDAImageAudioProcessor::MDAImageAudioProcessor()
4 | : AudioProcessor(BusesProperties()
5 | .withInput ("Input", juce::AudioChannelSet::stereo(), true)
6 | .withOutput("Output", juce::AudioChannelSet::stereo(), true))
7 | {
8 | }
9 |
10 | MDAImageAudioProcessor::~MDAImageAudioProcessor()
11 | {
12 | }
13 |
14 | const juce::String MDAImageAudioProcessor::getName() const
15 | {
16 | return JucePlugin_Name;
17 | }
18 |
19 | int MDAImageAudioProcessor::getNumPrograms()
20 | {
21 | return 1;
22 | }
23 |
24 | int MDAImageAudioProcessor::getCurrentProgram()
25 | {
26 | return 0;
27 | }
28 |
29 | void MDAImageAudioProcessor::setCurrentProgram(int index)
30 | {
31 | }
32 |
33 | const juce::String MDAImageAudioProcessor::getProgramName(int index)
34 | {
35 | return {};
36 | }
37 |
38 | void MDAImageAudioProcessor::changeProgramName(int index, const juce::String &newName)
39 | {
40 | }
41 |
42 | void MDAImageAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock)
43 | {
44 | resetState();
45 | }
46 |
47 | void MDAImageAudioProcessor::releaseResources()
48 | {
49 | }
50 |
51 | void MDAImageAudioProcessor::reset()
52 | {
53 | resetState();
54 | }
55 |
56 | bool MDAImageAudioProcessor::isBusesLayoutSupported(const BusesLayout &layouts) const
57 | {
58 | return layouts.getMainOutputChannelSet() == juce::AudioChannelSet::stereo();
59 | }
60 |
61 | void MDAImageAudioProcessor::resetState()
62 | {
63 | l2l = 1.0f;
64 | r2r = 1.0f;
65 | l2r = 0.0f;
66 | r2l = 0.0f;
67 | }
68 |
69 | void MDAImageAudioProcessor::update()
70 | {
71 | float w = apvts.getRawParameterValue("S Width")->load() * 0.01f; // -2 .. 2
72 | float k = apvts.getRawParameterValue("S Pan")->load() * 0.01f + 1.0f; // 0 .. 2
73 | float c = apvts.getRawParameterValue("M Level")->load() * 0.01f; // -2 .. 2
74 | float b = apvts.getRawParameterValue("M Pan")->load() * 0.01f + 1.0f; // 0 .. 2
75 |
76 | // Convert decibels to linear gain.
77 | float g = std::pow(10.0, 0.05f * apvts.getRawParameterValue("Output")->load());
78 |
79 | /*
80 | Calculate gain coefficients, where:
81 |
82 | l2l = gain for left input going into left output
83 | r2l = gain for right input going into left output
84 | r2r = gain for right input going into right output
85 | l2r = gain for left input going into right output
86 |
87 | ┌────────────┐ l2l ┌────────────┐
88 | │ ├──────────────────────────────────▶│ │
89 | │ L In ├─────────────────────┐ │ L Out │
90 | │ │ l2r ┌──┼────────────▶│ │
91 | └────────────┘ │ │ └────────────┘
92 | │ │
93 | ┌────────────┐ │ │ ┌────────────┐
94 | │ │ r2l │ └────────────▶│ │
95 | │ R In ├──────────────────┘ │ R Out │
96 | │ ├──────────────────────────────────▶│ │
97 | └────────────┘ r2r └────────────┘
98 | */
99 |
100 | int mode = int(apvts.getRawParameterValue("Mode")->load());
101 | switch (mode) {
102 | case 0: // SM->LR
103 | r2l = g * c * (2.0f - b);
104 | l2l = g * w * (2.0f - k);
105 | r2r = g * c * b;
106 | l2r = -g * w * k;
107 | break;
108 |
109 | case 1: // MS->LR
110 | l2l = g * c * (2.0f - b);
111 | r2l = g * w * (2.0f - k);
112 | l2r = g * c * b;
113 | r2r = -g * w * k;
114 | break;
115 |
116 | case 2: // LR->LR
117 | g *= 0.5f;
118 | l2l = g * (c * (2.0f - b) + w * (2.0f - k));
119 | r2l = g * (c * (2.0f - b) - w * (2.0f - k));
120 | l2r = g * (c * b - w * k);
121 | r2r = g * (c * b + w * k);
122 | break;
123 |
124 | case 3: // LR->MS
125 | g *= 0.5f;
126 | l2l = g * (2.0f - b) * (2.0f - k);
127 | r2l = g * (2.0f - b) * k;
128 | l2r = -g * b * (2.0f - k);
129 | r2r = g * b * k;
130 | break;
131 | }
132 | }
133 |
134 | void MDAImageAudioProcessor::processBlock(juce::AudioBuffer &buffer, juce::MidiBuffer &midiMessages)
135 | {
136 | juce::ScopedNoDenormals noDenormals;
137 | auto totalNumInputChannels = getTotalNumInputChannels();
138 | auto totalNumOutputChannels = getTotalNumOutputChannels();
139 |
140 | // Clear any output channels that don't contain input data.
141 | for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i) {
142 | buffer.clear(i, 0, buffer.getNumSamples());
143 | }
144 |
145 | update();
146 |
147 | const float *in1 = buffer.getReadPointer(0);
148 | const float *in2 = buffer.getReadPointer(1);
149 | float *out1 = buffer.getWritePointer(0);
150 | float *out2 = buffer.getWritePointer(1);
151 |
152 | for (int i = 0; i < buffer.getNumSamples(); ++i) {
153 | float a = in1[i];
154 | float b = in2[i];
155 |
156 | float c = l2l * a + r2l * b;
157 | float d = r2r * b + l2r * a;
158 |
159 | out1[i] = c;
160 | out2[i] = d;
161 | }
162 | }
163 |
164 | juce::AudioProcessorEditor *MDAImageAudioProcessor::createEditor()
165 | {
166 | return new juce::GenericAudioProcessorEditor(*this);
167 | }
168 |
169 | void MDAImageAudioProcessor::getStateInformation(juce::MemoryBlock &destData)
170 | {
171 | copyXmlToBinary(*apvts.copyState().createXml(), destData);
172 | }
173 |
174 | void MDAImageAudioProcessor::setStateInformation(const void *data, int sizeInBytes)
175 | {
176 | std::unique_ptr xml(getXmlFromBinary(data, sizeInBytes));
177 | if (xml.get() != nullptr && xml->hasTagName(apvts.state.getType())) {
178 | apvts.replaceState(juce::ValueTree::fromXml(*xml));
179 | }
180 | }
181 |
182 | juce::AudioProcessorValueTreeState::ParameterLayout MDAImageAudioProcessor::createParameterLayout()
183 | {
184 | juce::AudioProcessorValueTreeState::ParameterLayout layout;
185 |
186 | layout.add(std::make_unique(
187 | juce::ParameterID("Mode", 1),
188 | "Mode",
189 | juce::StringArray { "SM->LR", "MS->LR", "LR->LR", "LR->MS" },
190 | 2));
191 |
192 | layout.add(std::make_unique(
193 | juce::ParameterID("S Width", 1),
194 | "S Width",
195 | juce::NormalisableRange(-200.0f, 200.0f, 0.01f),
196 | 100.0f,
197 | juce::AudioParameterFloatAttributes().withLabel("%")));
198 |
199 | layout.add(std::make_unique(
200 | juce::ParameterID("S Pan", 1),
201 | "S Pan",
202 | juce::NormalisableRange(-100.0f, 100.0f, 0.01f),
203 | 0.0f,
204 | juce::AudioParameterFloatAttributes().withLabel("L<->R")));
205 |
206 | layout.add(std::make_unique(
207 | juce::ParameterID("M Level", 1),
208 | "M Level",
209 | juce::NormalisableRange(-200.0f, 200.0f, 0.01f),
210 | 100.0f,
211 | juce::AudioParameterFloatAttributes().withLabel("%")));
212 |
213 | layout.add(std::make_unique(
214 | juce::ParameterID("M Pan", 1),
215 | "M Pan",
216 | juce::NormalisableRange(-100.0f, 100.0f, 0.01f),
217 | 0.0f,
218 | juce::AudioParameterFloatAttributes().withLabel("L<->R")));
219 |
220 | layout.add(std::make_unique(
221 | juce::ParameterID("Output", 1),
222 | "Output",
223 | juce::NormalisableRange(-20.0f, 20.0f, 0.01f),
224 | 0.0f,
225 | juce::AudioParameterFloatAttributes().withLabel("dB")));
226 |
227 | return layout;
228 | }
229 |
230 | juce::AudioProcessor *JUCE_CALLTYPE createPluginFilter()
231 | {
232 | return new MDAImageAudioProcessor();
233 | }
234 |
--------------------------------------------------------------------------------
/Image/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class MDAImageAudioProcessor : public juce::AudioProcessor
6 | {
7 | public:
8 | MDAImageAudioProcessor();
9 | ~MDAImageAudioProcessor() override;
10 |
11 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
12 | void releaseResources() override;
13 | void reset() override;
14 |
15 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
16 |
17 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
18 |
19 | juce::AudioProcessorEditor *createEditor() override;
20 | bool hasEditor() const override { return true; }
21 |
22 | const juce::String getName() const override;
23 |
24 | bool acceptsMidi() const override { return false; }
25 | bool producesMidi() const override { return false; }
26 | bool isMidiEffect() const override { return false; }
27 | double getTailLengthSeconds() const override { return 0.0; }
28 |
29 | int getNumPrograms() override;
30 | int getCurrentProgram() override;
31 | void setCurrentProgram(int index) override;
32 | const juce::String getProgramName(int index) override;
33 | void changeProgramName(int index, const juce::String &newName) override;
34 |
35 | void getStateInformation(juce::MemoryBlock &destData) override;
36 | void setStateInformation(const void *data, int sizeInBytes) override;
37 |
38 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
39 |
40 | private:
41 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
42 |
43 | void update();
44 | void resetState();
45 |
46 | float l2l, l2r, r2l, r2r;
47 |
48 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MDAImageAudioProcessor)
49 | };
50 |
--------------------------------------------------------------------------------
/JX10/JX10.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
10 |
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 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/JX10/README.markdown:
--------------------------------------------------------------------------------
1 | # JX10
2 |
3 | Simple 2-oscillator analog synthesizer. 8 voice polyphonic.
4 |
5 | > **TIP!** I cleaned up the code for this synth and [wrote a 350-page book about it](https://leanpub.com/synth-plugin). The book teaches the fundamentals of audio programming by showing you how to build this synth step-by-step.
6 |
7 | The plug-in is designed for high quality (lower aliasing than most soft synths) and low processor usage - this means that some features that would increase CPU load have been left out!
8 |
9 | Additional patch design by Stefan Andersson and Zeitfraktur, Sascha Kujawa.
10 |
11 | Please note that the mda JX10 is not related to the JX series of synths available from JXPlugins.
12 |
13 | | Parameter | Description |
14 | | --------- | ----------- |
15 | | OSC Mix | Level of second oscillator (both oscillators are sawtooth wave only - but see Vibrato below) |
16 | | OSC Tune | Tuning of second oscillator in semitones |
17 | | OSC Fine | Tuning of second oscillator in cents |
18 | | Glide Mode | POLY = 8-voice polyphonic, P-LEGATO = 8-voice polyphonic with pitch glide if a key is held, P-GLIDE = 8-voice polyphonic with pitch glide, MONO = monophonic, M-LEGATO = monophonic with pitch glide if a key is held, M-GLIDE = monophonic with pitch glide |
19 | | Glide Rate | Pitch glide rate |
20 | | Glide Bend | Initial pitch-glide offset, for pitch-envelope effects |
21 | | VCF Freq | Filter cutoff frequency |
22 | | VCF Reso | Filter resonance |
23 | | VCF Env | Cutoff modulation by VCF envelope |
24 | | VCF LFO | Cutoff modulation by LFO |
25 | | VCF Vel | Cutoff modulation by velocity (turn fully left to disable velocity control of cutoff and amplitude) |
26 | | VCF A,D,S,R | Attack, Decay, Sustain, Release envelope for filter cutoff |
27 | | ENV A,D,S,R | Attack, Decay, Sustain, Release envelope for amplitude |
28 | | LFO Rate | LFO rate (sine wave only) |
29 | | Vibrato | LFO modulation of pitch - turn to left for PWM effects |
30 | | Noise | White noise mix |
31 | | Octave | Master tuning in octaves |
32 | | Tuning | Master tuning in cents |
33 |
34 | When Vibrato is set to PWM, the two oscillators are phase-locked and will produce a square wave if set to the same pitch. Pitch modulation of one oscillator then causes Pulse Width Modulation (pitch modulation of both oscillators for vibrato is still available from the modulation wheel). Unlike other synths, in PWM mode the oscillators can still be detuned to give a wider range of PWM effects.
35 |
36 | | MIDI Control | |
37 | | --------- | ----------- |
38 | | Pitch Bend | +/- 2 semitones |
39 | | CC1 (Mod Wheel) | Vibrato |
40 | | Channel Pressure | Filter cutoff modulation by LFO |
41 | | CC2, CC74 | Increase filter cutoff |
42 | | CC3 | Decrease filter cutoff |
43 | | CC7 | Volume |
44 | | CC16, CC71 | Increase filter resonance |
45 | | Program Change | 1 - 64 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | mda VST plug-ins
2 |
3 | Copyright (c) 2008 Paul Kellett
4 | Copyright (c) 2021-2025 M.I. Hollemans (JUCE version)
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
7 |
8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9 |
10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11 |
--------------------------------------------------------------------------------
/Limiter/MDALimiter.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
9 |
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 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Limiter/README.markdown:
--------------------------------------------------------------------------------
1 | # Limiter
2 |
3 | Opto-electronic style limiter.
4 |
5 | | Parameter | Description |
6 | | --------- | ----------- |
7 | | Thresh | Threshold (this is not a brickwall limiter so this is only approximate) |
8 | | Output | Level trim |
9 | | Release | |
10 | | Attack | |
11 | | Knee | Select Hard or Soft (both can pump and distort when pushed hard - but that could be just what you want!) |
12 |
--------------------------------------------------------------------------------
/Limiter/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class MDALimiterAudioProcessor : public juce::AudioProcessor
6 | {
7 | public:
8 | MDALimiterAudioProcessor();
9 | ~MDALimiterAudioProcessor() override;
10 |
11 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
12 | void releaseResources() override;
13 | void reset() override;
14 |
15 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
16 |
17 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
18 |
19 | juce::AudioProcessorEditor *createEditor() override;
20 | bool hasEditor() const override { return true; }
21 |
22 | const juce::String getName() const override;
23 |
24 | bool acceptsMidi() const override { return false; }
25 | bool producesMidi() const override { return false; }
26 | bool isMidiEffect() const override { return false; }
27 | double getTailLengthSeconds() const override { return 0.0; }
28 |
29 | int getNumPrograms() override;
30 | int getCurrentProgram() override;
31 | void setCurrentProgram(int index) override;
32 | const juce::String getProgramName(int index) override;
33 | void changeProgramName(int index, const juce::String &newName) override;
34 |
35 | void getStateInformation(juce::MemoryBlock &destData) override;
36 | void setStateInformation(const void *data, int sizeInBytes) override;
37 |
38 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
39 |
40 | private:
41 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
42 |
43 | void update();
44 | void resetState();
45 |
46 | // The maximum amplitude you want the sound to have. Louder sounds will be
47 | // reduced to approximately this level. With a very slow attack it may take
48 | // a long time before the sound drops below the threshold level, if ever.
49 | // In soft knee mode, the threshold only indirectly represents the maximum
50 | // amplitude, but it still serves the same purpose.
51 | float _threshold;
52 |
53 | // The attack time determines how quickly the limiter responds when the sound
54 | // level approaches (in soft knee mode) or exceeds the threshold (hard knee).
55 | float _attack;
56 |
57 | // The release time determines how quickly the gain level resets itself after
58 | // the limiter no longer needs to be active.
59 | float _release;
60 |
61 | // Use this for boosting the output level when setting a low threshold.
62 | float _trim;
63 |
64 | // Choose between hard knee and soft knee modes.
65 | bool _softKnee;
66 |
67 | // The current gain level. When the audio signal exceeds or approaches the
68 | // threshold, the gain level is lowered to reduce the amplitude. The limiter
69 | // essentially calculates a gain signal over time that is used to prevent the
70 | // audio from becoming too loud. This is the gain signal's most recent value.
71 | float _gain;
72 |
73 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MDALimiterAudioProcessor)
74 | };
75 |
--------------------------------------------------------------------------------
/Loudness/MDALoudness.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
9 |
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 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Loudness/README.markdown:
--------------------------------------------------------------------------------
1 | # Loudness
2 |
3 | Equal loudness contours for bass EQ and mix correction.
4 |
5 | | Parameter | Description |
6 | | --------- | ----------- |
7 | | Loudness | Source level relative to listening level (based on a 100 dB SPL maximum level) |
8 | | Output | Level trim |
9 | | Link | Automatically adjusts Output to maintain a consistent tonal balance at all levels |
10 |
11 | The ear is less sensitive to low frequencies when listening at low volume. This plug-in is based on the Stevens-Davis equal loudness contours and allows the bass level to be adjusted to simulate or correct for this effect.
12 |
13 | Example uses:
14 |
15 | - If a mix was made with a very low or very high monitoring level, the amount of bass can sound wrong at a normal monitoring level. Use Loudness to adjust the bass content.
16 | - Check how a mix would sound at a much louder level by decreasing Loudness. (Although the non-linear behaviour of the ear at very high levels is not simulated by this plug-in.)
17 | - Fade out without the sound becoming "tinny" by activating Link and using Loudness to adjust the level without affecting the tonal balance.
18 |
--------------------------------------------------------------------------------
/Loudness/Source/PluginProcessor.cpp:
--------------------------------------------------------------------------------
1 | #include "PluginProcessor.h"
2 |
3 | // Lookup table of filter coefficients.
4 | static float loudness[14][3] =
5 | {
6 | {402.f, 0.0025f, 0.00f}, // -60 dB
7 | {334.f, 0.0121f, 0.00f},
8 | {256.f, 0.0353f, 0.00f},
9 | {192.f, 0.0900f, 0.00f},
10 | {150.f, 0.2116f, 0.00f},
11 | {150.f, 0.5185f, 0.00f},
12 | { 1.0f, 0.0f, 0.00f}, // 0 dB
13 | {33.7f, 5.5f, 1.00f},
14 | {92.0f, 8.7f, 0.62f},
15 | {63.7f, 18.4f, 0.44f},
16 | {42.9f, 48.2f, 0.30f},
17 | {37.6f, 116.2f, 0.18f},
18 | {22.9f, 428.7f, 0.09f}, // +60 dB
19 | { 0.0f, 0.0f, 0.00f}
20 | };
21 |
22 | MDALoudnessAudioProcessor::MDALoudnessAudioProcessor()
23 | : AudioProcessor(BusesProperties()
24 | .withInput ("Input", juce::AudioChannelSet::stereo(), true)
25 | .withOutput("Output", juce::AudioChannelSet::stereo(), true))
26 | {
27 | }
28 |
29 | MDALoudnessAudioProcessor::~MDALoudnessAudioProcessor()
30 | {
31 | }
32 |
33 | const juce::String MDALoudnessAudioProcessor::getName() const
34 | {
35 | return JucePlugin_Name;
36 | }
37 |
38 | int MDALoudnessAudioProcessor::getNumPrograms()
39 | {
40 | return 1;
41 | }
42 |
43 | int MDALoudnessAudioProcessor::getCurrentProgram()
44 | {
45 | return 0;
46 | }
47 |
48 | void MDALoudnessAudioProcessor::setCurrentProgram(int index)
49 | {
50 | }
51 |
52 | const juce::String MDALoudnessAudioProcessor::getProgramName(int index)
53 | {
54 | return {};
55 | }
56 |
57 | void MDALoudnessAudioProcessor::changeProgramName(int index, const juce::String &newName)
58 | {
59 | }
60 |
61 | void MDALoudnessAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock)
62 | {
63 | resetState();
64 | }
65 |
66 | void MDALoudnessAudioProcessor::releaseResources()
67 | {
68 | }
69 |
70 | void MDALoudnessAudioProcessor::reset()
71 | {
72 | resetState();
73 | }
74 |
75 | bool MDALoudnessAudioProcessor::isBusesLayoutSupported(const BusesLayout &layouts) const
76 | {
77 | return layouts.getMainOutputChannelSet() == juce::AudioChannelSet::stereo();
78 | }
79 |
80 | void MDALoudnessAudioProcessor::resetState()
81 | {
82 | z0 = z1 = z2 = z3 = 0.0f;
83 | }
84 |
85 | void MDALoudnessAudioProcessor::update()
86 | {
87 | float igain = apvts.getRawParameterValue("Loudness")->load();
88 | float ogain = apvts.getRawParameterValue("Output")->load();
89 |
90 | // Convert the decibel value to an index in the `loudness` table.
91 | float f = 0.1f * igain + 6.0f;
92 | int i = int(f); // coefficient index
93 | f -= float(i); // fractional part
94 |
95 | // Do a linear interpolation between the entries in the table.
96 | a0 = loudness[i][0] + f * (loudness[i + 1][0] - loudness[i][0]);
97 | a1 = loudness[i][1] + f * (loudness[i + 1][1] - loudness[i][1]);
98 | a2 = loudness[i][2] + f * (loudness[i + 1][2] - loudness[i][2]);
99 |
100 | // The first entry in the table is a frequency; convert it to a
101 | // low-pass filter coefficient.
102 | a0 = 1.0f - std::exp(-6.283153f * a0 / getSampleRate());
103 |
104 | // Cutting or boosting?
105 | mode = (igain > 0.0f);
106 |
107 | // Calculate the output gain, convert from dB to linear value.
108 | float tmp = ogain;
109 | if (apvts.getRawParameterValue("Link")->load()) { // linked gain
110 | tmp -= igain;
111 | if (tmp > 0.0f) { // limit max gain
112 | tmp = 0.0f;
113 | }
114 | }
115 | gain = std::pow(10.0f, 0.05f * tmp);
116 | }
117 |
118 | void MDALoudnessAudioProcessor::processBlock(juce::AudioBuffer &buffer, juce::MidiBuffer &midiMessages)
119 | {
120 | juce::ScopedNoDenormals noDenormals;
121 | auto totalNumInputChannels = getTotalNumInputChannels();
122 | auto totalNumOutputChannels = getTotalNumOutputChannels();
123 |
124 | // Clear any output channels that don't contain input data.
125 | for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i) {
126 | buffer.clear(i, 0, buffer.getNumSamples());
127 | }
128 |
129 | update();
130 |
131 | const float *in1 = buffer.getReadPointer(0);
132 | const float *in2 = buffer.getReadPointer(1);
133 | float *out1 = buffer.getWritePointer(0);
134 | float *out2 = buffer.getWritePointer(1);
135 |
136 | if (mode == 0) { // cut
137 | for (int i = 0; i < buffer.getNumSamples(); ++i) {
138 | float a = in1[i];
139 | float b = in2[i];
140 |
141 | // Filter for the left channel.
142 | z0 += a0 * (a - z0 + 0.3f * z1);
143 | a -= z0;
144 | z1 += a0 * (a - z1);
145 | a -= z1;
146 | a -= z0 * a1;
147 |
148 | // Filter for the right channel.
149 | z2 += a0 * (b - z2 + 0.3f * z1);
150 | b -= z2;
151 | z3 += a0 * (b - z3);
152 | b -= z3;
153 | b -= z2 * a1;
154 |
155 | out1[i] = a * gain;
156 | out2[i] = b * gain;
157 | }
158 | } else { // boost
159 | for (int i = 0; i < buffer.getNumSamples(); ++i) {
160 | float a = in1[i];
161 | float b = in2[i];
162 |
163 | // This is two one-pole low-pass filters in a row.
164 | z0 += a0 * (a - z0);
165 | z1 += a0 * (z0 - z1);
166 |
167 | // Add the low-pass filtered values to the input to boost it.
168 | a += a1 * (z1 - a2 * z0);
169 |
170 | // Same filtering but for the right channel.
171 | z2 += a0 * (b - z2);
172 | z3 += a0 * (z2 - z3);
173 | b += a1 * (z3 - a2 * z2);
174 |
175 | out1[i] = a * gain;
176 | out2[i] = b * gain;
177 | }
178 | }
179 | }
180 |
181 | juce::AudioProcessorEditor *MDALoudnessAudioProcessor::createEditor()
182 | {
183 | return new juce::GenericAudioProcessorEditor(*this);
184 | }
185 |
186 | void MDALoudnessAudioProcessor::getStateInformation(juce::MemoryBlock &destData)
187 | {
188 | copyXmlToBinary(*apvts.copyState().createXml(), destData);
189 | }
190 |
191 | void MDALoudnessAudioProcessor::setStateInformation(const void *data, int sizeInBytes)
192 | {
193 | std::unique_ptr xml(getXmlFromBinary(data, sizeInBytes));
194 | if (xml.get() != nullptr && xml->hasTagName(apvts.state.getType())) {
195 | apvts.replaceState(juce::ValueTree::fromXml(*xml));
196 | }
197 | }
198 |
199 | juce::AudioProcessorValueTreeState::ParameterLayout MDALoudnessAudioProcessor::createParameterLayout()
200 | {
201 | juce::AudioProcessorValueTreeState::ParameterLayout layout;
202 |
203 | layout.add(std::make_unique(
204 | juce::ParameterID("Loudness", 1),
205 | "Loudness",
206 | juce::NormalisableRange(-60.0f, 60.0f, 0.01f, 0.5f, true),
207 | 9.6f,
208 | juce::AudioParameterFloatAttributes().withLabel("dB")));
209 |
210 | layout.add(std::make_unique(
211 | juce::ParameterID("Output", 1),
212 | "Output",
213 | juce::NormalisableRange(-60.0f, 60.0f, 0.01f, 0.5f, true),
214 | 0.0f,
215 | juce::AudioParameterFloatAttributes().withLabel("dB")));
216 |
217 | layout.add(std::make_unique(
218 | juce::ParameterID("Link", 1),
219 | "Link",
220 | false));
221 |
222 | return layout;
223 | }
224 |
225 | juce::AudioProcessor *JUCE_CALLTYPE createPluginFilter()
226 | {
227 | return new MDALoudnessAudioProcessor();
228 | }
229 |
--------------------------------------------------------------------------------
/Loudness/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class MDALoudnessAudioProcessor : public juce::AudioProcessor
6 | {
7 | public:
8 | MDALoudnessAudioProcessor();
9 | ~MDALoudnessAudioProcessor() override;
10 |
11 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
12 | void releaseResources() override;
13 | void reset() override;
14 |
15 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
16 |
17 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
18 |
19 | juce::AudioProcessorEditor *createEditor() override;
20 | bool hasEditor() const override { return true; }
21 |
22 | const juce::String getName() const override;
23 |
24 | bool acceptsMidi() const override { return false; }
25 | bool producesMidi() const override { return false; }
26 | bool isMidiEffect() const override { return false; }
27 | double getTailLengthSeconds() const override { return 0.0; }
28 |
29 | int getNumPrograms() override;
30 | int getCurrentProgram() override;
31 | void setCurrentProgram(int index) override;
32 | const juce::String getProgramName(int index) override;
33 | void changeProgramName(int index, const juce::String &newName) override;
34 |
35 | void getStateInformation(juce::MemoryBlock &destData) override;
36 | void setStateInformation(const void *data, int sizeInBytes) override;
37 |
38 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
39 |
40 | private:
41 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
42 |
43 | void update();
44 | void resetState();
45 |
46 | float z0, z1, z2, z3; // filter delays (0+1 = left channel, 2+3 = right)
47 | float a0, a1, a2; // filter coefficients
48 | float gain; // output gain
49 | int mode; // 0 = cut, 1 = boost
50 |
51 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MDALoudnessAudioProcessor)
52 | };
53 |
--------------------------------------------------------------------------------
/Overdrive/MDAOverdrive.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
9 |
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 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Overdrive/README.markdown:
--------------------------------------------------------------------------------
1 | # Overdrive
2 |
3 | Soft distortion plug-in.
4 |
5 | Possible uses include adding body to drum loops, fuzz guitar, and that 'standing outside a nightclub' sound. This plug does not simulate valve distortion, and any attempt to process organ sounds through it will be extremely unrewarding!
6 |
7 | | Parameter | Description |
8 | | --------- | ----------- |
9 | | Drive | Amount of distortion |
10 | | Muffle | Gentle low-pass filter |
11 | | Output | Level trim |
12 |
--------------------------------------------------------------------------------
/Overdrive/Source/PluginProcessor.cpp:
--------------------------------------------------------------------------------
1 | #include "PluginProcessor.h"
2 |
3 | MDAOverdriveAudioProcessor::MDAOverdriveAudioProcessor()
4 | : AudioProcessor(BusesProperties()
5 | .withInput ("Input", juce::AudioChannelSet::stereo(), true)
6 | .withOutput("Output", juce::AudioChannelSet::stereo(), true))
7 | {
8 | }
9 |
10 | MDAOverdriveAudioProcessor::~MDAOverdriveAudioProcessor()
11 | {
12 | }
13 |
14 | const juce::String MDAOverdriveAudioProcessor::getName() const
15 | {
16 | return JucePlugin_Name;
17 | }
18 |
19 | int MDAOverdriveAudioProcessor::getNumPrograms()
20 | {
21 | return 1;
22 | }
23 |
24 | int MDAOverdriveAudioProcessor::getCurrentProgram()
25 | {
26 | return 0;
27 | }
28 |
29 | void MDAOverdriveAudioProcessor::setCurrentProgram(int index)
30 | {
31 | }
32 |
33 | const juce::String MDAOverdriveAudioProcessor::getProgramName(int index)
34 | {
35 | return {};
36 | }
37 |
38 | void MDAOverdriveAudioProcessor::changeProgramName(int index, const juce::String &newName)
39 | {
40 | }
41 |
42 | void MDAOverdriveAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock)
43 | {
44 | resetState();
45 | }
46 |
47 | void MDAOverdriveAudioProcessor::releaseResources()
48 | {
49 | }
50 |
51 | void MDAOverdriveAudioProcessor::reset()
52 | {
53 | resetState();
54 | }
55 |
56 | bool MDAOverdriveAudioProcessor::isBusesLayoutSupported(const BusesLayout &layouts) const
57 | {
58 | return layouts.getMainOutputChannelSet() == juce::AudioChannelSet::stereo();
59 | }
60 |
61 | void MDAOverdriveAudioProcessor::resetState()
62 | {
63 | // Set the filter delay units back to zero.
64 | _filtL = _filtR = 0.0f;
65 | }
66 |
67 | void MDAOverdriveAudioProcessor::update()
68 | {
69 | // The amount of drive is a percentage; divide by 100 to make it 0 - 1.
70 | _drive = apvts.getRawParameterValue("Drive")->load() / 100.0f;
71 |
72 | // The muffle parameter controls a low-pass filter. Muffle is a percentage;
73 | // convert it to a value between 1.0 and 0.025 that drops off exponentially.
74 | // 1.0 means the filter is disabled; the smaller the value, the lower the
75 | // cutoff frequency will be. At 100%, the cutoff is around 200 Hz somewhere.
76 | // Since it's a first-order filter, it has a gentle roll-off of 6 dB/octave.
77 | float muffle = apvts.getRawParameterValue("Muffle")->load();
78 | _filt = std::pow(10.0f, -1.6f * muffle / 100.0f);
79 |
80 | // The output level is between -20 dB and +20 dB. Convert to linear gain.
81 | float output = apvts.getRawParameterValue("Output")->load();
82 | _gain = juce::Decibels::decibelsToGain(output);
83 | }
84 |
85 | void MDAOverdriveAudioProcessor::processBlock(juce::AudioBuffer &buffer, juce::MidiBuffer &midiMessages)
86 | {
87 | juce::ScopedNoDenormals noDenormals;
88 | auto totalNumInputChannels = getTotalNumInputChannels();
89 | auto totalNumOutputChannels = getTotalNumOutputChannels();
90 |
91 | // Clear any output channels that don't contain input data.
92 | for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i) {
93 | buffer.clear(i, 0, buffer.getNumSamples());
94 | }
95 |
96 | update();
97 |
98 | const float *in1 = buffer.getReadPointer(0);
99 | const float *in2 = buffer.getReadPointer(1);
100 | float *out1 = buffer.getWritePointer(0);
101 | float *out2 = buffer.getWritePointer(1);
102 |
103 | const float drive = _drive;
104 | const float gain = _gain;
105 | const float f = _filt;
106 |
107 | float fa = _filtL, fb = _filtR;
108 |
109 | for (int i = 0; i < buffer.getNumSamples(); ++i) {
110 | float a = in1[i];
111 | float b = in2[i];
112 |
113 | // Overdrive: this applies a sqrt to slightly distort and boost the sound.
114 | float aa = (a > 0.0f) ? std::sqrt(a) : -std::sqrt(-a);
115 | float bb = (b > 0.0f) ? std::sqrt(b) : -std::sqrt(-b);
116 |
117 | // Filter: this is a simple exponentially weighted moving average filter.
118 | // The difference equation is: y(n) = f * x(n) + (1 - f) * y(n - 1).
119 | //
120 | // When f = 1, the filter is disabled as that makes (1 - f) equal to 0.
121 | // As you move the "muffle" slider to the right, f becomes exponentially
122 | // smaller and more smoothing is applied, making the filter cutoff lower.
123 | //
124 | // The input to the filter x(n) = drive * (aa - a) + a. This is simply
125 | // the linear interpolation between the original sample value and the
126 | // overdriven version, aa or sqrt(a). Rewriting the math shows that this
127 | // is the same as x(n) = drive * aa + (1 - drive) * a. The larger drive
128 | // is, the more we add the overdriven signal into the mix.
129 | //
130 | // fa is y(n - 1) for the left channel and fb is for the right channel.
131 | fa = fa + f * (drive * (aa - a) + a - fa);
132 | fb = fb + f * (drive * (bb - b) + b - fb);
133 |
134 | // Apply output gain and write to output buffer.
135 | out1[i] = fa * gain;
136 | out2[i] = fb * gain;
137 | }
138 |
139 | // Catch denormals
140 | if (std::abs(fa) > 1.0e-10f) _filtL = fa; else _filtL = 0.0f;
141 | if (std::abs(fb) > 1.0e-10f) _filtR = fb; else _filtR = 0.0f;
142 | }
143 |
144 | juce::AudioProcessorEditor *MDAOverdriveAudioProcessor::createEditor()
145 | {
146 | return new juce::GenericAudioProcessorEditor(*this);
147 | }
148 |
149 | void MDAOverdriveAudioProcessor::getStateInformation(juce::MemoryBlock &destData)
150 | {
151 | copyXmlToBinary(*apvts.copyState().createXml(), destData);
152 | }
153 |
154 | void MDAOverdriveAudioProcessor::setStateInformation(const void *data, int sizeInBytes)
155 | {
156 | std::unique_ptr xml(getXmlFromBinary(data, sizeInBytes));
157 | if (xml.get() != nullptr && xml->hasTagName(apvts.state.getType())) {
158 | apvts.replaceState(juce::ValueTree::fromXml(*xml));
159 | }
160 | }
161 |
162 | juce::AudioProcessorValueTreeState::ParameterLayout MDAOverdriveAudioProcessor::createParameterLayout()
163 | {
164 | juce::AudioProcessorValueTreeState::ParameterLayout layout;
165 |
166 | layout.add(std::make_unique(
167 | juce::ParameterID("Drive", 1),
168 | "Drive",
169 | juce::NormalisableRange(0.0f, 100.0f, 0.01f),
170 | 0.0f,
171 | juce::AudioParameterFloatAttributes().withLabel("%")));
172 |
173 | layout.add(std::make_unique(
174 | juce::ParameterID("Muffle", 1),
175 | "Muffle",
176 | juce::NormalisableRange(0.0f, 100.0f, 0.01f),
177 | 0.0f,
178 | juce::AudioParameterFloatAttributes().withLabel("%")));
179 |
180 | layout.add(std::make_unique(
181 | juce::ParameterID("Output", 1),
182 | "Output",
183 | juce::NormalisableRange(-20.0f, 20.0f, 0.01f),
184 | 0.0f,
185 | juce::AudioParameterFloatAttributes().withLabel("dB")));
186 |
187 | return layout;
188 | }
189 |
190 | juce::AudioProcessor *JUCE_CALLTYPE createPluginFilter()
191 | {
192 | return new MDAOverdriveAudioProcessor();
193 | }
194 |
--------------------------------------------------------------------------------
/Overdrive/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class MDAOverdriveAudioProcessor : public juce::AudioProcessor
6 | {
7 | public:
8 | MDAOverdriveAudioProcessor();
9 | ~MDAOverdriveAudioProcessor() override;
10 |
11 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
12 | void releaseResources() override;
13 | void reset() override;
14 |
15 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
16 |
17 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
18 |
19 | juce::AudioProcessorEditor *createEditor() override;
20 | bool hasEditor() const override { return true; }
21 |
22 | const juce::String getName() const override;
23 |
24 | bool acceptsMidi() const override { return false; }
25 | bool producesMidi() const override { return false; }
26 | bool isMidiEffect() const override { return false; }
27 | double getTailLengthSeconds() const override { return 0.0; }
28 |
29 | int getNumPrograms() override;
30 | int getCurrentProgram() override;
31 | void setCurrentProgram(int index) override;
32 | const juce::String getProgramName(int index) override;
33 | void changeProgramName(int index, const juce::String &newName) override;
34 |
35 | void getStateInformation(juce::MemoryBlock &destData) override;
36 | void setStateInformation(const void *data, int sizeInBytes) override;
37 |
38 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
39 |
40 | private:
41 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
42 |
43 | void update();
44 | void resetState();
45 |
46 | // Amount of overdrive, a value between 0 and 1. This controls the mix
47 | // between the original signal and the overdriven one.
48 | float _drive;
49 |
50 | // Filter coefficient, a value between 1 and 0.025.
51 | float _filt;
52 |
53 | // Output gain, a value between 0.1 (for -20 dB) and 10 (for +20 dB).
54 | float _gain;
55 |
56 | // Delay units for the left and right channel filters.
57 | float _filtL, _filtR;
58 |
59 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MDAOverdriveAudioProcessor)
60 | };
61 |
--------------------------------------------------------------------------------
/Piano/MDAPiano.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
12 |
14 |
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 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/Piano/README.markdown:
--------------------------------------------------------------------------------
1 | # Piano
2 |
3 | Acoustic piano instrument — this was quite a [popular free piano synth](https://www.kvraudio.com/product/piano-by-mda) back in the day.
4 |
5 | Not designed to be the best sounding piano in the world, but boasts extremely low CPU and memory usage.
6 |
7 | | Parameter | Description |
8 | | --------- | ----------- |
9 | | Decay | Envelope decay time |
10 | | Release | Envelope release time |
11 | | Stereo Width | Key to pan position, with additional stereo ambience at high settings |
12 | | Tuning | Controls for overall tuning, random tuning amount, and high frequency stretch tuning amount. Use Alt-click to reset sliders to their default positions |
13 | | Vel Sens | Velocity curve: Mid point is normal "square law" response |
14 | | Muffle | Gentle low pass filter. Use "V" slider to adjust velocity control |
15 | | Hardness | Adjusts sample keyranges up or down to change the "size" and brightness of the piano. Use "V" slider to adjust velocity control |
16 | | Polyphony | Adjustable from monophonic to 32 voices |
17 |
--------------------------------------------------------------------------------
/Piano/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | const int NPARAMS = 12; // number of parameters
6 | const int NPROGS = 8; // number of programs
7 | const int NVOICES = 32; // max polyphony
8 |
9 | const float SILENCE = 0.0001f; // voice choking
10 |
11 | // Describes a factory preset.
12 | struct MDAPianoProgram
13 | {
14 | MDAPianoProgram();
15 | MDAPianoProgram(const char *name,
16 | float p0, float p1, float p2, float p3,
17 | float p4, float p5, float p6, float p7,
18 | float p8, float p9, float p10, float p11);
19 | char name[24];
20 | float param[NPARAMS];
21 | };
22 |
23 | // A keygroup maps notes to waveforms. All the waveforms are stored inside one
24 | // big lookup table (see mdaPianoData.h). There are 15 keygroups, each covering
25 | // 4 semitones. That's 60 notes in total. A piano has 88 keys so very low notes
26 | // all share the same waveform; likewise for very high notes. The waveforms are
27 | // mono, 22050 Hz, and consist of an attack portion and a loop portion.
28 | struct Keygroup
29 | {
30 | int root; // MIDI root note (usually the note in the middle of the keygroup)
31 | int high; // highest note this waveform should be used for
32 | int pos; // index of the first sample in the lookup table
33 | int end; // index of the last sample in the lookup table
34 | int loop; // how far from end the first sample of the loop is
35 | };
36 |
37 | // State for an active voice.
38 | struct Voice
39 | {
40 | // What note triggered this voice, or SUSTAIN when the key is released
41 | // but the sustain pedal is held down.
42 | int note;
43 |
44 | // The increment for stepping through the waveform table. This is stored as
45 | // a fixed point value, where 65536 = 1.0. For example, a step size of 0.5
46 | // has a delta of 32768.
47 | int delta;
48 |
49 | // The fractional part of the current position in the waveform. This is
50 | // stored using 16 bits. The highest value it can have is 65535, which is
51 | // approximately 0.99999.
52 | int frac;
53 |
54 | // These are copied from the keygroup for this note. When we start playing
55 | // the note, pos is incremented by delta until it reaches end, and then it
56 | // wraps back to the loop index.
57 | int pos;
58 | int end;
59 | int loop;
60 |
61 | // The current envelope level and the exponential decay value that the
62 | // envelope is multiplied with on every step. Setting the decay to 0.99
63 | // will fade out the sound almost immediately (used for all notes off).
64 | float env;
65 | float decay;
66 |
67 | // "Muffling" filter. This is a first-order LPF.
68 | float f0; // delay for y(n - 1)
69 | float f1; // delay for x(n - 1)
70 | float ff; // filter coefficient
71 |
72 | // Panning volumes for the left and right channels.
73 | float outl;
74 | float outr;
75 | };
76 |
77 | class MDAPianoAudioProcessor : public juce::AudioProcessor
78 | {
79 | public:
80 | MDAPianoAudioProcessor();
81 | ~MDAPianoAudioProcessor() override;
82 |
83 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
84 | void releaseResources() override;
85 | void reset() override;
86 |
87 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
88 |
89 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
90 |
91 | juce::AudioProcessorEditor *createEditor() override;
92 | bool hasEditor() const override { return true; }
93 |
94 | const juce::String getName() const override;
95 |
96 | bool acceptsMidi() const override { return true; }
97 | bool producesMidi() const override { return false; }
98 | bool isMidiEffect() const override { return false; }
99 | double getTailLengthSeconds() const override { return 0.0; }
100 |
101 | int getNumPrograms() override;
102 | int getCurrentProgram() override;
103 | void setCurrentProgram(int index) override;
104 | const juce::String getProgramName(int index) override;
105 | void changeProgramName(int index, const juce::String &newName) override;
106 |
107 | void getStateInformation(juce::MemoryBlock &destData) override;
108 | void setStateInformation(const void *data, int sizeInBytes) override;
109 |
110 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
111 |
112 | private:
113 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
114 |
115 | void update();
116 | void resetState();
117 |
118 | void createPrograms();
119 | void processEvents(juce::MidiBuffer &midiMessages);
120 | void noteOn(int note, int velocity);
121 |
122 | // The factory presets.
123 | std::vector _programs;
124 |
125 | // Index of the active preset.
126 | int _currentProgram;
127 |
128 | // The current sample rate and 1 / sample rate.
129 | float _sampleRate, _inverseSampleRate;
130 |
131 | // MIDI note on / note off events for the current block. Each event is
132 | // described by 3 values: delta time, note number, velocity.
133 | static const int EVENTBUFFER = 120;
134 | int _notes[EVENTBUFFER + 8];
135 |
136 | // Special event code that marks the end of the MIDI events list.
137 | const int EVENTS_DONE = 99999999;
138 |
139 | // Special "note number" that says this voice is now kept alive by the
140 | // sustain pedal being pressed down. As soon as the pedal is released,
141 | // this voice will fade out.
142 | const int SUSTAIN = 128;
143 |
144 | // Big lookup table with waveforms containing the piano samples.
145 | short *_waves;
146 |
147 | // Maps the waveforms from the _waves lookup table to ranges of notes.
148 | Keygroup _keygroups[15];
149 |
150 | // List of the active voices.
151 | Voice _voices[NVOICES];
152 |
153 | // How many voices are currently in use.
154 | int _numActiveVoices;
155 |
156 | // Status of the damper pedal: 64 = pressed, 0 = released.
157 | int _sustain;
158 |
159 | // Output gain in linear units. Can be changed by MIDI CC 7.
160 | float _volume;
161 |
162 | // Max number of voices of polyphony.
163 | int _polyphony;
164 |
165 | // Envelope decay length (lower is shorter). Used when playing a new note.
166 | float _envDecay;
167 |
168 | // Value of the envelope release parameter, 0.0 - 1.0. This is used after a
169 | // note off event (if the sustain pedal is not pressed).
170 | float _envRelease;
171 |
172 | // Value of the muffling filter parameter, 0.0 - 1.0.
173 | float _mufflingFilter;
174 |
175 | // How sensitive the muffling filter is to note velocity, 0.0 - 5.0
176 | float _mufflingVelocity;
177 |
178 | // Adjusts the amount of filtering. This variable is changed when the mod
179 | // wheel or soft pedal is used. Default value = 160.
180 | float _muff;
181 |
182 | // These two settings change which waveform to use for a given note, by not
183 | // selecting the note's keygroup but one of its neighboring keygroups.
184 | int _hardnessOffset;
185 | float _hardnessVelocity;
186 |
187 | // Used to set the envelope level for new notes. Value between 0.25 and 3.0.
188 | float _velocitySensitivity;
189 |
190 | // Amount of fine-tuning, in semitones.
191 | float _fine;
192 |
193 | // Amount of random detuning.
194 | float _random;
195 |
196 | // Amount of stretch tuning.
197 | float _stretch;
198 |
199 | // For calculating the stereo width.
200 | float _width, _trim;
201 |
202 | // Delay line for comb filter. Used to enhance the stereo width.
203 | int _delayPos;
204 | int _delayMax;
205 | float _combDelay[256];
206 |
207 | // Amount of comb filtering. More means a wider stereo effect.
208 | float _comb;
209 |
210 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MDAPianoAudioProcessor)
211 | };
212 |
--------------------------------------------------------------------------------
/RezFilter/MDARezFilter.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
9 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
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 |
--------------------------------------------------------------------------------
/RezFilter/README.markdown:
--------------------------------------------------------------------------------
1 | # RezFilter
2 |
3 | Resonant filter with LFO and envelope follower
4 |
5 | | Parameter | Description |
6 | | --------- | ----------- |
7 | | Freq | Cut-off frequency |
8 | | Rez | Resonance |
9 | | Output | Level trim |
10 | | Env->VCF | Positive or negative (squelchy!) Envelope modulation of cut-off frequency |
11 | | Attack | |
12 | | Release | (use fast attack and release for "dirty" modulation) |
13 | | LFO->VCF | LFO modulation of cut-off frequency (turn to left for sample & hold LFO, right for sine) |
14 | | LFO Rate | LFO modulation speed |
15 | | Trigger | Envelope trigger level (normally set to minimum to acts as a free-running envelope follower) |
16 | | Max Freq | Limit maximum cut-off frequency for a mellower sound (the filter can sound "screechy" at high frequencies) |
17 |
--------------------------------------------------------------------------------
/RezFilter/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class MDARezFilterAudioProcessor : public juce::AudioProcessor
6 | {
7 | public:
8 | MDARezFilterAudioProcessor();
9 | ~MDARezFilterAudioProcessor() override;
10 |
11 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
12 | void releaseResources() override;
13 | void reset() override;
14 |
15 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
16 |
17 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
18 |
19 | juce::AudioProcessorEditor *createEditor() override;
20 | bool hasEditor() const override { return true; }
21 |
22 | const juce::String getName() const override;
23 |
24 | bool acceptsMidi() const override { return false; }
25 | bool producesMidi() const override { return false; }
26 | bool isMidiEffect() const override { return false; }
27 | double getTailLengthSeconds() const override { return 0.0; }
28 |
29 | int getNumPrograms() override;
30 | int getCurrentProgram() override;
31 | void setCurrentProgram(int index) override;
32 | const juce::String getProgramName(int index) override;
33 | void changeProgramName(int index, const juce::String &newName) override;
34 |
35 | void getStateInformation(juce::MemoryBlock &destData) override;
36 | void setStateInformation(const void *data, int sizeInBytes) override;
37 |
38 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
39 |
40 | private:
41 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
42 |
43 | void update();
44 | void resetState();
45 |
46 | float cutoff; // filter cutoff
47 | float q; // filter Q
48 | float gain; // output gain
49 | float filterMax; // maximum cutoff
50 |
51 | float envDepth; // envelope modulation amount
52 | float attack; // envelope attack coefficient
53 | float release; // envelope release coefficient
54 | float env; // current envelope level
55 |
56 | float lfo; // most recent LFO value
57 | float lfoPhase; // current LFO phase
58 | float lfoInc; // LFO rate
59 | float lfoDepth; // LFO modulation amount
60 | bool sampleHold; // 0 = sine, 1 = sample & hold
61 |
62 | float buf0, buf1; // filter delay units
63 |
64 | float threshold; // envelope trigger threshold
65 | float triggerEnv; // secondary envelope used when triggered
66 | bool triggered; // whether envelope exceeded threshold
67 | bool triggerAttack; // triggerEnv currently in attack mode
68 |
69 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MDARezFilterAudioProcessor)
70 | };
71 |
--------------------------------------------------------------------------------
/RingMod/MDARingMod.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
9 |
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 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/RingMod/README.markdown:
--------------------------------------------------------------------------------
1 | # RingMod
2 |
3 | This was the first "mda" effect, made way back in 1998. It is a simple ring modulator, multiplying the input signal by a sine wave, the frequency of which is set using the Frequency and Fine Tune controls. As if ring modulation wasn't harsh enough already, the Feedback parameter can add even more edge to the sound!
4 |
5 | Can be used as a high-frequency enhancer for drum sounds (when mixed with the original), adding dissonance to pitched material, and severe tremolo (at low frequency settings).
6 |
7 | | Parameter | Description |
8 | | --------- | ----------- |
9 | | Freq | Set oscillator frequency in 100Hz steps |
10 | | Fine | Oscillator frequency fine tune |
11 | | Feedback | Amount of feedback for "harsh" sound |
12 |
--------------------------------------------------------------------------------
/RingMod/Source/PluginProcessor.cpp:
--------------------------------------------------------------------------------
1 | #include "PluginProcessor.h"
2 |
3 | MDARingModAudioProcessor::MDARingModAudioProcessor()
4 | : AudioProcessor(BusesProperties()
5 | .withInput ("Input", juce::AudioChannelSet::stereo(), true)
6 | .withOutput("Output", juce::AudioChannelSet::stereo(), true))
7 | {
8 | }
9 |
10 | MDARingModAudioProcessor::~MDARingModAudioProcessor()
11 | {
12 | }
13 |
14 | const juce::String MDARingModAudioProcessor::getName() const
15 | {
16 | return JucePlugin_Name;
17 | }
18 |
19 | int MDARingModAudioProcessor::getNumPrograms()
20 | {
21 | return 1;
22 | }
23 |
24 | int MDARingModAudioProcessor::getCurrentProgram()
25 | {
26 | return 0;
27 | }
28 |
29 | void MDARingModAudioProcessor::setCurrentProgram(int index)
30 | {
31 | }
32 |
33 | const juce::String MDARingModAudioProcessor::getProgramName(int index)
34 | {
35 | return {};
36 | }
37 |
38 | void MDARingModAudioProcessor::changeProgramName(int index, const juce::String &newName)
39 | {
40 | }
41 |
42 | void MDARingModAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock)
43 | {
44 | resetState();
45 | }
46 |
47 | void MDARingModAudioProcessor::releaseResources()
48 | {
49 | }
50 |
51 | void MDARingModAudioProcessor::reset()
52 | {
53 | resetState();
54 | }
55 |
56 | bool MDARingModAudioProcessor::isBusesLayoutSupported(const BusesLayout &layouts) const
57 | {
58 | return layouts.getMainOutputChannelSet() == juce::AudioChannelSet::stereo();
59 | }
60 |
61 | void MDARingModAudioProcessor::resetState()
62 | {
63 | _phase = 0.0f;
64 | _prevL = 0.0f;
65 | _prevR = 0.0f;
66 | }
67 |
68 | void MDARingModAudioProcessor::update()
69 | {
70 | float freq = apvts.getRawParameterValue("Frequency")->load();
71 | float fine = apvts.getRawParameterValue("Fine-tune")->load();
72 |
73 | const auto twoPi = juce::MathConstants::twoPi;
74 |
75 | // The phase increment is 2*pi*freq/sampleRate. The frequency is between 0 Hz
76 | // and 16000 Hz, in steps of 100 Hz. The fine-tune amount is from 0 - 100 Hz.
77 | _phaseInc = twoPi * (fine + freq) / float(getSampleRate());
78 |
79 | // Feedback is a percentage from 0 to 95%.
80 | _feedbackAmount = apvts.getRawParameterValue("Feedback")->load() / 100.0f;
81 |
82 | // Convert from decibels to a linear gain value.
83 | float level = apvts.getRawParameterValue("Level")->load();
84 | _level = juce::Decibels::decibelsToGain(level);
85 | }
86 |
87 | void MDARingModAudioProcessor::processBlock(juce::AudioBuffer &buffer, juce::MidiBuffer &midiMessages)
88 | {
89 | juce::ScopedNoDenormals noDenormals;
90 | auto totalNumInputChannels = getTotalNumInputChannels();
91 | auto totalNumOutputChannels = getTotalNumOutputChannels();
92 |
93 | // Clear any output channels that don't contain input data.
94 | for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i) {
95 | buffer.clear(i, 0, buffer.getNumSamples());
96 | }
97 |
98 | update();
99 |
100 | const float *in1 = buffer.getReadPointer(0);
101 | const float *in2 = buffer.getReadPointer(1);
102 | float *out1 = buffer.getWritePointer(0);
103 | float *out2 = buffer.getWritePointer(1);
104 |
105 | const float level = _level;
106 | const float phaseInc = _phaseInc;
107 | const float feedback = _feedbackAmount;
108 |
109 | float phase = _phase;
110 | float prevL = _prevL;
111 | float prevR = _prevR;
112 |
113 | const auto twoPi = juce::MathConstants::twoPi;
114 |
115 | for (int i = 0; i < buffer.getNumSamples(); ++i) {
116 | // The value of the sine is the instantaneous gain.
117 | const float g = std::sin(phase);
118 |
119 | // Increment the phase and wrap at 2 pi.
120 | phase = std::fmod(phase + phaseInc, twoPi);
121 |
122 | // Add the previous output value to the new input sample, multiplied by
123 | // the feedback factor. Then multiply by sine wave for ring modulation.
124 | prevL = (feedback * prevL + in1[i]) * g;
125 | prevR = (feedback * prevR + in2[i]) * g;
126 |
127 | // Before putting the value into the output buffer, multiply it by the
128 | // output level in order to attenuate it, if necessary.
129 | out1[i] = prevL * level;
130 | out2[i] = prevR * level;
131 | }
132 |
133 | _phase = phase;
134 | _prevL = prevL;
135 | _prevR = prevR;
136 | }
137 |
138 | juce::AudioProcessorEditor *MDARingModAudioProcessor::createEditor()
139 | {
140 | return new juce::GenericAudioProcessorEditor(*this);
141 | }
142 |
143 | void MDARingModAudioProcessor::getStateInformation(juce::MemoryBlock &destData)
144 | {
145 | copyXmlToBinary(*apvts.copyState().createXml(), destData);
146 | }
147 |
148 | void MDARingModAudioProcessor::setStateInformation(const void *data, int sizeInBytes)
149 | {
150 | std::unique_ptr xml(getXmlFromBinary(data, sizeInBytes));
151 | if (xml.get() != nullptr && xml->hasTagName(apvts.state.getType())) {
152 | apvts.replaceState(juce::ValueTree::fromXml(*xml));
153 | }
154 | }
155 |
156 | juce::AudioProcessorValueTreeState::ParameterLayout MDARingModAudioProcessor::createParameterLayout()
157 | {
158 | juce::AudioProcessorValueTreeState::ParameterLayout layout;
159 |
160 | layout.add(std::make_unique(
161 | juce::ParameterID("Frequency", 1),
162 | "Frequency",
163 | juce::NormalisableRange(0.0f, 16000.0f, 100.0f, 0.5f),
164 | 1000.0f,
165 | juce::AudioParameterFloatAttributes().withLabel("Hz")));
166 |
167 | layout.add(std::make_unique(
168 | juce::ParameterID("Fine-tune", 1),
169 | "Fine-tune",
170 | juce::NormalisableRange(0.0f, 100.0f, 0.01f),
171 | 0.0f,
172 | juce::AudioParameterFloatAttributes().withLabel("Hz")));
173 |
174 | layout.add(std::make_unique(
175 | juce::ParameterID("Feedback", 1),
176 | "Feedback",
177 | juce::NormalisableRange(0.0f, 95.0f, 0.01f),
178 | 0.0f,
179 | juce::AudioParameterFloatAttributes().withLabel("%")));
180 |
181 | layout.add(std::make_unique(
182 | juce::ParameterID("Level", 1),
183 | "Level",
184 | juce::NormalisableRange(-30.0f, 0.0f, 0.01f),
185 | -6.0f,
186 | juce::AudioParameterFloatAttributes().withLabel("dB")));
187 |
188 | return layout;
189 | }
190 |
191 | juce::AudioProcessor *JUCE_CALLTYPE createPluginFilter()
192 | {
193 | return new MDARingModAudioProcessor();
194 | }
195 |
--------------------------------------------------------------------------------
/RingMod/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class MDARingModAudioProcessor : public juce::AudioProcessor
6 | {
7 | public:
8 | MDARingModAudioProcessor();
9 | ~MDARingModAudioProcessor() override;
10 |
11 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
12 | void releaseResources() override;
13 | void reset() override;
14 |
15 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
16 |
17 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
18 |
19 | juce::AudioProcessorEditor *createEditor() override;
20 | bool hasEditor() const override { return true; }
21 |
22 | const juce::String getName() const override;
23 |
24 | bool acceptsMidi() const override { return false; }
25 | bool producesMidi() const override { return false; }
26 | bool isMidiEffect() const override { return false; }
27 | double getTailLengthSeconds() const override { return 0.0; }
28 |
29 | int getNumPrograms() override;
30 | int getCurrentProgram() override;
31 | void setCurrentProgram(int index) override;
32 | const juce::String getProgramName(int index) override;
33 | void changeProgramName(int index, const juce::String &newName) override;
34 |
35 | void getStateInformation(juce::MemoryBlock &destData) override;
36 | void setStateInformation(const void *data, int sizeInBytes) override;
37 |
38 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
39 |
40 | private:
41 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
42 |
43 | void update();
44 | void resetState();
45 |
46 | // Output level. This was not in the original plug-in, but with a lot of
47 | // feedback it's useful to dial back the total volume to prevent clipping.
48 | float _level;
49 |
50 | // Phase increment for the sine wave.
51 | float _phaseInc;
52 |
53 | // Amount of feedback to add (value between 0 and 1).
54 | float _feedbackAmount;
55 |
56 | // Current phase for the sine wave.
57 | float _phase;
58 |
59 | // Previous output values for the left and right channels; used for feedback.
60 | float _prevL, _prevR;
61 |
62 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MDARingModAudioProcessor)
63 | };
64 |
--------------------------------------------------------------------------------
/Shepard/MDAShepard.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
9 |
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 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Shepard/README.markdown:
--------------------------------------------------------------------------------
1 | # Shepard
2 |
3 | Shepard tone generator
4 |
5 | This plug-in generates a continuously rising or falling tone. Or rather, that's what it sounds like but really new harmonics are always appearing at one end of the spectrum and disappearing at the other. (Using some EQ can improve the psychoacoustic effect, depending on your listening environment.)
6 |
7 | These continuous tones are actually called "Risset tones", developed from the earlier "Shepard tones" which change in series of discrete steps. The Mode control allows the input signal to be mixed or ring modulated with the tone - this works well as one element of a complex chain of effects.
8 |
9 | | Parameter | Description |
10 | | --------- | ----------- |
11 | | Mode| TONES = tones only, RING MOD = input ring modulated by tones, TONES+IN = tones mixed with input |
12 | | Rate | Speed of rising (right) or falling (left) |
13 | | Output | Level trim |
14 |
--------------------------------------------------------------------------------
/Shepard/Source/PluginProcessor.cpp:
--------------------------------------------------------------------------------
1 | #include "PluginProcessor.h"
2 |
3 | MDAShepardAudioProcessor::MDAShepardAudioProcessor()
4 | : AudioProcessor(BusesProperties()
5 | .withInput ("Input", juce::AudioChannelSet::stereo(), true)
6 | .withOutput("Output", juce::AudioChannelSet::stereo(), true))
7 | {
8 | const float twopi = 6.2831853f;
9 | const int max = bufferSize - 1;
10 |
11 | // Generate wavetables. We only need to do this once.
12 | for (int j = 0; j < max; ++j) {
13 | float pos = twopi * float(j) / float(max);
14 |
15 | // buf2 contains one period of a sine wave.
16 | _buf2[j] = std::sin(pos);
17 |
18 | // buf1 also contains higher octaves of this sine wave.
19 | float x = 0.0f;
20 | float a = 1.0f;
21 | for (int i = 0; i < 8; ++i) {
22 | x += a * std::sin(std::fmod(pos, twopi));
23 | a *= 0.5f;
24 | pos *= 2.0f;
25 | }
26 | _buf1[j] = x;
27 | }
28 |
29 | // Make last value the same as the first, for easier interpolation.
30 | _buf1[max] = 0.0f;
31 | _buf2[max] = 0.0f;
32 | }
33 |
34 | MDAShepardAudioProcessor::~MDAShepardAudioProcessor()
35 | {
36 | }
37 |
38 | const juce::String MDAShepardAudioProcessor::getName() const
39 | {
40 | return JucePlugin_Name;
41 | }
42 |
43 | int MDAShepardAudioProcessor::getNumPrograms()
44 | {
45 | return 1;
46 | }
47 |
48 | int MDAShepardAudioProcessor::getCurrentProgram()
49 | {
50 | return 0;
51 | }
52 |
53 | void MDAShepardAudioProcessor::setCurrentProgram(int index)
54 | {
55 | }
56 |
57 | const juce::String MDAShepardAudioProcessor::getProgramName(int index)
58 | {
59 | return {};
60 | }
61 |
62 | void MDAShepardAudioProcessor::changeProgramName(int index, const juce::String &newName)
63 | {
64 | }
65 |
66 | void MDAShepardAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock)
67 | {
68 | resetState();
69 | }
70 |
71 | void MDAShepardAudioProcessor::releaseResources()
72 | {
73 | }
74 |
75 | void MDAShepardAudioProcessor::reset()
76 | {
77 | resetState();
78 | }
79 |
80 | bool MDAShepardAudioProcessor::isBusesLayoutSupported(const BusesLayout &layouts) const
81 | {
82 | return layouts.getMainOutputChannelSet() == juce::AudioChannelSet::stereo();
83 | }
84 |
85 | void MDAShepardAudioProcessor::resetState()
86 | {
87 | _pos = 0.0f;
88 | _rate = 1.0f;
89 | }
90 |
91 | void MDAShepardAudioProcessor::update()
92 | {
93 | _mode = int(apvts.getRawParameterValue("Mode")->load());
94 |
95 | // The rate is a percentage from -100% to +100%. Convert this into a curve
96 | // that is 1.0 at 0% and goes gently downward to the left (to make a falling
97 | // sound) and upward to the right (for a rising sound).
98 | float fParam1 = int(apvts.getRawParameterValue("Rate")->load());
99 | fParam1 = (fParam1 + 100) / 200.0f;
100 | _delta = 1.0f + 10.0f * std::pow(fParam1 - 0.5f, 3.0f) / float(getSampleRate());
101 |
102 | // Convert the output level from decibels to a linear gain.
103 | float fParam2 = int(apvts.getRawParameterValue("Output")->load());
104 | _level = 0.4842f * juce::Decibels::decibelsToGain(fParam2);
105 | }
106 |
107 | void MDAShepardAudioProcessor::processBlock(juce::AudioBuffer &buffer, juce::MidiBuffer &midiMessages)
108 | {
109 | juce::ScopedNoDenormals noDenormals;
110 | auto totalNumInputChannels = getTotalNumInputChannels();
111 | auto totalNumOutputChannels = getTotalNumOutputChannels();
112 |
113 | // Clear any output channels that don't contain input data.
114 | for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i) {
115 | buffer.clear(i, 0, buffer.getNumSamples());
116 | }
117 |
118 | update();
119 |
120 | const float *in1 = buffer.getReadPointer(0);
121 | const float *in2 = buffer.getReadPointer(1);
122 | float *out1 = buffer.getWritePointer(0);
123 | float *out2 = buffer.getWritePointer(1);
124 |
125 | const float *buf1 = _buf1;
126 | const float *buf2 = _buf2;
127 | const float max = float(bufferSize - 1);
128 | const int mode = _mode;
129 | const float delta = _delta;
130 | const float level = _level;
131 |
132 | float rate = _rate;
133 | float pos = _pos;
134 |
135 | for (int i = 0; i < buffer.getNumSamples(); ++i) {
136 | // The illusion is a sound that appears to be rising (or falling) in pitch
137 | // forever. We make the pitch go up by stepping through the wavetable at an
138 | // increasing rate. The rate goes up from 1.0 to 2.0 and then wraps back to
139 | // 1.0. That wrap-around by itself would give a jarring effect. To hide
140 | // this, we don't just play a plain sine wave (buf2) but also 1, 2, 4, 8
141 | // octaves higher (buf1). As the pitch goes up, the higher notes fade out
142 | // while lower notes fade in. In the case of a falling tone, we do it the
143 | // other way around (the pitch goes down because the wavetable read pos is
144 | // incremented using a rate that becomes gradually smaller).
145 |
146 | rate *= delta;
147 | if (rate > 2.0f) { // rising tone
148 | rate *= 0.5f;
149 | pos *= 0.5f;
150 | } else if (rate < 1.0f) { // falling tone
151 | rate *= 2.0f;
152 | pos *= 2.0f;
153 | if (pos >= max) pos -= max;
154 | }
155 |
156 | // Increment the read position in the wavetables and wrap around when we
157 | // get to the end.
158 | pos += rate;
159 | if (pos > max) pos -= max;
160 |
161 | // Calculate position interpolation:
162 | int i1 = int(pos); // current sample
163 | int i2 = i1 + 1; // next sample
164 | float di = float(i2) - pos; // fractional part between the two
165 |
166 | // di and (1 - di) are used for interpolating between two successive
167 | // positions in the wavetable.
168 | // buf1 contains the sine waves in the higher octaves, with each higher
169 | // octave having half the amplitude as the previous octave.
170 | // buf2 contains a plain sine wave. We multiply this by (rate - 2) in
171 | // order to fade it in or out as the pitch changes.
172 | float b = di * (buf1[i1] + (rate - 2.0f) * buf2[i1])
173 | + (1.0f - di) * (buf1[i2] + (rate - 2.0f) * buf2[i2]);
174 |
175 | // Dividing by the rate means we fade out the sound as the pitch goes
176 | // up, or fade it in when the pitch goes down.
177 | b *= level / rate;
178 |
179 | // Do we need to combine the tone with incoming audio?
180 | if (mode > 0) {
181 | float a = in1[i] + in2[i]; // stereo to mono
182 | if (mode == 1) {
183 | b *= a; // ring modulation with input
184 | } else if (mode == 2) {
185 | b += 0.5f * a; // mix with input (at -6 dB)
186 | }
187 | }
188 |
189 | out1[i] = b;
190 | out2[i] = b;
191 | }
192 |
193 | _pos = pos;
194 | _rate = rate;
195 | }
196 |
197 | juce::AudioProcessorEditor *MDAShepardAudioProcessor::createEditor()
198 | {
199 | return new juce::GenericAudioProcessorEditor(*this);
200 | }
201 |
202 | void MDAShepardAudioProcessor::getStateInformation(juce::MemoryBlock &destData)
203 | {
204 | copyXmlToBinary(*apvts.copyState().createXml(), destData);
205 | }
206 |
207 | void MDAShepardAudioProcessor::setStateInformation(const void *data, int sizeInBytes)
208 | {
209 | std::unique_ptr xml(getXmlFromBinary(data, sizeInBytes));
210 | if (xml.get() != nullptr && xml->hasTagName(apvts.state.getType())) {
211 | apvts.replaceState(juce::ValueTree::fromXml(*xml));
212 | }
213 | }
214 |
215 | juce::AudioProcessorValueTreeState::ParameterLayout MDAShepardAudioProcessor::createParameterLayout()
216 | {
217 | juce::AudioProcessorValueTreeState::ParameterLayout layout;
218 |
219 | layout.add(std::make_unique(
220 | juce::ParameterID("Mode", 1),
221 | "Mode",
222 | juce::StringArray({ "TONES", "RING MOD", "TONES+IN" }),
223 | 0));
224 |
225 | layout.add(std::make_unique(
226 | juce::ParameterID("Rate", 1),
227 | "Rate",
228 | juce::NormalisableRange(-100.0f, 100.0f, 0.01f),
229 | 40.0f,
230 | juce::AudioParameterFloatAttributes().withLabel("%")));
231 |
232 | layout.add(std::make_unique(
233 | juce::ParameterID("Output", 1),
234 | "Output",
235 | juce::NormalisableRange(-20.0f, 20.0f, 0.01f),
236 | 0.0f,
237 | juce::AudioParameterFloatAttributes().withLabel("dB")));
238 |
239 | return layout;
240 | }
241 |
242 | juce::AudioProcessor *JUCE_CALLTYPE createPluginFilter()
243 | {
244 | return new MDAShepardAudioProcessor();
245 | }
246 |
--------------------------------------------------------------------------------
/Shepard/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class MDAShepardAudioProcessor : public juce::AudioProcessor
6 | {
7 | public:
8 | MDAShepardAudioProcessor();
9 | ~MDAShepardAudioProcessor() override;
10 |
11 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
12 | void releaseResources() override;
13 | void reset() override;
14 |
15 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
16 |
17 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
18 |
19 | juce::AudioProcessorEditor *createEditor() override;
20 | bool hasEditor() const override { return true; }
21 |
22 | const juce::String getName() const override;
23 |
24 | bool acceptsMidi() const override { return false; }
25 | bool producesMidi() const override { return false; }
26 | bool isMidiEffect() const override { return false; }
27 | double getTailLengthSeconds() const override { return 0.0; }
28 |
29 | int getNumPrograms() override;
30 | int getCurrentProgram() override;
31 | void setCurrentProgram(int index) override;
32 | const juce::String getProgramName(int index) override;
33 | void changeProgramName(int index, const juce::String &newName) override;
34 |
35 | void getStateInformation(juce::MemoryBlock &destData) override;
36 | void setStateInformation(const void *data, int sizeInBytes) override;
37 |
38 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
39 |
40 | private:
41 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
42 |
43 | void update();
44 | void resetState();
45 |
46 | // The currently selected mode.
47 | int _mode;
48 |
49 | // Output gain level.
50 | float _level;
51 |
52 | // The speed of rising or falling.
53 | float _delta;
54 |
55 | // Two wavetables containing sine waves.
56 | static const int bufferSize = 512;
57 | float _buf1[bufferSize];
58 | float _buf2[bufferSize];
59 |
60 | // Read position in the wavetables.
61 | float _pos;
62 |
63 | // Increment of read position. This is what determines the current pitch.
64 | float _rate;
65 |
66 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MDAShepardAudioProcessor)
67 | };
68 |
--------------------------------------------------------------------------------
/Splitter/MDASplitter.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
9 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
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 |
--------------------------------------------------------------------------------
/Splitter/README.markdown:
--------------------------------------------------------------------------------
1 | # Splitter
2 |
3 | 2-way signal splitter. Frequency / level crossover for setting up dynamic processing.
4 |
5 | | Parameter | Description |
6 | | --------- | ----------- |
7 | | Mode | see below |
8 | | Frequency | Crossover frequency |
9 | | Frequency SW | Select crossover output: **LOW** frequencies / **ALL** frequencies / **HIGH** frequencies |
10 | | Level | Gate threshold |
11 | | Level SW | Select gate output: **LOW** levels / **ALL** levels / **HIGH** levels |
12 | | Envelope | Gate envelope speed |
13 | | Output | Level trim |
14 |
15 | This plug-in can split a signal based on frequency or level, for example for producing dynamic effects where only loud drum hits are sent to a reverb. Other functions include a simple "spectral gate" in **INVERSE** mode and a conventional gate and filter for separating drum sounds in **NORMAL** mode.
16 |
17 | Modes:
18 |
19 | - NORMAL: Output as selected with **Frequency** and **Level** controls
20 | - INVERSE: Inverse of shown selection (e.g. everything except low frequencies at high level)
21 | - NORM INV: Left / Right split of above
22 | - INV NORM: Right / Left split of above
23 |
--------------------------------------------------------------------------------
/Splitter/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class MDASplitterAudioProcessor : public juce::AudioProcessor
6 | {
7 | public:
8 | MDASplitterAudioProcessor();
9 | ~MDASplitterAudioProcessor() override;
10 |
11 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
12 | void releaseResources() override;
13 | void reset() override;
14 |
15 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
16 |
17 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
18 |
19 | juce::AudioProcessorEditor *createEditor() override;
20 | bool hasEditor() const override { return true; }
21 |
22 | const juce::String getName() const override;
23 |
24 | bool acceptsMidi() const override { return false; }
25 | bool producesMidi() const override { return false; }
26 | bool isMidiEffect() const override { return false; }
27 | double getTailLengthSeconds() const override { return 0.0; }
28 |
29 | int getNumPrograms() override;
30 | int getCurrentProgram() override;
31 | void setCurrentProgram(int index) override;
32 | const juce::String getProgramName(int index) override;
33 | void changeProgramName(int index, const juce::String &newName) override;
34 |
35 | void getStateInformation(juce::MemoryBlock &destData) override;
36 | void setStateInformation(const void *data, int sizeInBytes) override;
37 |
38 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
39 |
40 | private:
41 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
42 |
43 | void update();
44 | void resetState();
45 |
46 | float freq; // filter coefficient
47 | float a0, a1, b0, b1; // filter states (a = left, b = right channel)
48 |
49 | float level; // gate threshold
50 | float env; // current envelope level
51 | float att, rel; // attack and release constants
52 |
53 | float ff, ll, pp; // routing: freq, level, polarity
54 | float i2l, i2r, o2l, o2r; // routing: gain for left/right dry&wet
55 |
56 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MDASplitterAudioProcessor)
57 | };
58 |
--------------------------------------------------------------------------------
/Stereo/MDAStereo.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
9 |
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 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Stereo/README.markdown:
--------------------------------------------------------------------------------
1 | # Stereo
2 |
3 | Stereo Simulator: Add artificial width to a mono signal. Haas delay and comb filtering.
4 |
5 | This plug converts a mono signal to a 'wide' signal using two techniques: Comb filtering where the signal is panned left and right alternately with increasing frequency, and Haas panning where a time delayed signal sounds appears to be at the same level as a quieter non-delayed version.
6 |
7 | Comb mode is mono compatible. Haas mode is not, but sounds fine on some signals such as backing vocals. This plug-in must be used in a stereo channel or bus!
8 |
9 | | Parameter | Description |
10 | | --------- | ----------- |
11 | | Width | Stereo width (turn to right for comb filter mode, left for Haas panning mode) |
12 | | Delay | Delay time - use higher values for more filter "combs" across the frequency spectrum |
13 | | Balance | Balance correction for Haas mode |
14 | | Mod | Amount of delay modulation (defaults to OFF to reduce processor usage) |
15 | | Rate | Modulation rate (note that modulation completely disappears in mono) |
16 |
--------------------------------------------------------------------------------
/Stereo/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class MDAStereoAudioProcessor : public juce::AudioProcessor
6 | {
7 | public:
8 | MDAStereoAudioProcessor();
9 | ~MDAStereoAudioProcessor() override;
10 |
11 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
12 | void releaseResources() override;
13 | void reset() override;
14 |
15 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
16 |
17 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
18 |
19 | juce::AudioProcessorEditor *createEditor() override;
20 | bool hasEditor() const override { return true; }
21 |
22 | const juce::String getName() const override;
23 |
24 | bool acceptsMidi() const override { return false; }
25 | bool producesMidi() const override { return false; }
26 | bool isMidiEffect() const override { return false; }
27 | double getTailLengthSeconds() const override { return 0.0; }
28 |
29 | int getNumPrograms() override;
30 | int getCurrentProgram() override;
31 | void setCurrentProgram(int index) override;
32 | const juce::String getProgramName(int index) override;
33 | void changeProgramName(int index, const juce::String &newName) override;
34 |
35 | void getStateInformation(juce::MemoryBlock &destData) override;
36 | void setStateInformation(const void *data, int sizeInBytes) override;
37 |
38 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
39 |
40 | private:
41 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
42 |
43 | void update();
44 | void resetState();
45 |
46 | // Used to calculate the release time in milliseconds in the UI.
47 | float _sampleRate;
48 |
49 | // This buffer stores the delayed samples (mono).
50 | std::vector _delayBuffer;
51 |
52 | // Maximum length of the delay buffer in samples.
53 | int _delayMax;
54 |
55 | // Where we will write the next new sample value in the delay buffer.
56 | int _writePos;
57 |
58 | // Delay time in samples.
59 | float _delayTime;
60 |
61 | // Amount of delay modulation (0.0 = off).
62 | float _mod;
63 |
64 | // Current phase and phase increment for the sine wave that is used to
65 | // modulate the read position in the delay buffer.
66 | float _phase, _phaseInc;
67 |
68 | // Filter coefficients for l=left, r=right, i=input, d=delayed sample.
69 | float _fli, _fld, _fri, _frd;
70 |
71 | // Output level.
72 | float _gain;
73 |
74 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MDAStereoAudioProcessor)
75 | };
76 |
--------------------------------------------------------------------------------
/SubSynth/MDASubSynth.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
9 |
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 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/SubSynth/README.markdown:
--------------------------------------------------------------------------------
1 | # SubSynth
2 |
3 | Sub-Bass Synthesizer: Several low frequency enhancement methods. More bass than you could ever need!
4 |
5 | Be aware that you may be adding low frequency content outside the range of your monitor speakers. To avoid clipping, follow with a limiter plug-in (this can also give some giant hip-hop drum sounds!).
6 |
7 | | Parameter | Description |
8 | | --------- | ----------- |
9 | | Type | see below |
10 | | Level | Amount of synthesized low frequencysignal to be added |
11 | | Tune | Maximum frequency - keep as low as possible to reduce distortion. In Key Osc mode sets the oscillator frequency |
12 | | Dry Mix | Reduces the level of the original signal |
13 | | Thresh | Increase to "gate" the low frequency effect and stop unwanted background rumbling |
14 | | Release | Decay time in Key Osc mode |
15 |
16 | Type can be:
17 |
18 | - **Distort**: Takes the existing low frequencies, clips them to produce harmonics at a constant level, then filters out the higher harmonics. Has a similar effect to compressing the low frequencies.
19 |
20 | - **Divide**: As above, but works at an octave below the input frequency, like an octave divider guitar pedal.
21 |
22 | - **Invert**: Flips the phase of the low frequency signal once per cycle to add a smooth sub-octave. A simplified version of the classic Sub-Harmonic Synthesizer.
23 |
24 | - **Key Osc.**: Adds a decaying "boom" - usually made with an oscillator before a noise gate keyed with the kick drum signal.
25 |
--------------------------------------------------------------------------------
/SubSynth/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class MDASubSynthAudioProcessor : public juce::AudioProcessor
6 | {
7 | public:
8 | MDASubSynthAudioProcessor();
9 | ~MDASubSynthAudioProcessor() override;
10 |
11 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
12 | void releaseResources() override;
13 | void reset() override;
14 |
15 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
16 |
17 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
18 |
19 | juce::AudioProcessorEditor *createEditor() override;
20 | bool hasEditor() const override { return true; }
21 |
22 | const juce::String getName() const override;
23 |
24 | bool acceptsMidi() const override { return false; }
25 | bool producesMidi() const override { return false; }
26 | bool isMidiEffect() const override { return false; }
27 | double getTailLengthSeconds() const override { return 0.0; }
28 |
29 | int getNumPrograms() override;
30 | int getCurrentProgram() override;
31 | void setCurrentProgram(int index) override;
32 | const juce::String getProgramName(int index) override;
33 | void changeProgramName(int index, const juce::String &newName) override;
34 |
35 | void getStateInformation(juce::MemoryBlock &destData) override;
36 | void setStateInformation(const void *data, int sizeInBytes) override;
37 |
38 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
39 |
40 | private:
41 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
42 |
43 | void update();
44 | void resetState();
45 |
46 | // Used to calculate the release time in milliseconds in the UI.
47 | float _sampleRate;
48 |
49 | // The kind of sub-bass sound to add.
50 | int _type;
51 |
52 | // Amount of synthesized low-frequency signal to be added.
53 | float _wet;
54 |
55 | // Reduces the level of the original signal.
56 | float _dry;
57 |
58 | // Threshold level. The lower this is, the more intense the effect.
59 | float _threshold;
60 |
61 | // Used to find the octave below the input frequency.
62 | float _sign, _phase;
63 |
64 | // Oscillator phase and phase increment, for "Key Osc" mode.
65 | float _oscPhase, _phaseInc;
66 |
67 | // Current envelope level for the oscillator.
68 | float _env;
69 |
70 | // Decay amount for "Key Osc" mode.
71 | float _decay;
72 |
73 | // Low-pass filter coefficients.
74 | float _filti, _filto;
75 |
76 | // Filter delays. We use the same filter four times.
77 | float _filt1, _filt2, _filt3, _filt4;
78 |
79 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MDASubSynthAudioProcessor)
80 | };
81 |
--------------------------------------------------------------------------------
/TestTone/MDATestTone.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
9 |
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 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/TestTone/README.markdown:
--------------------------------------------------------------------------------
1 | # TestTone
2 |
3 | Signal generator with pink and white noise, impulses and sweeps.
4 |
5 | Note: the AU version of this plug-in has a bunch of extra features and improvements that I didn't convert yet.
6 |
7 | | Parameter | Description |
8 | | --------- | ----------- |
9 | | Mode | see below |
10 | | Level | Peak output level |
11 | | Channel | Generate signals on left or right channel only |
12 | | F1 | Base frequency (not applicable to pink and white noise or impulses) |
13 | | F2 | Fine frequency control, or end frequency for sweep modes |
14 | | Sweep | Sweep duration for sweep modes (2 seconds silence is also added between sweeps). Sets repetition rate in inpulse mode |
15 | | Thru | Allow the input signal to pass through the plug-in |
16 | | 0 dB = | Calibrate output so indicated level is relative to, for example -0.01 dB FS or -18 dB FS |
17 |
18 | Possible modes:
19 |
20 | - MIDI #: sine waves at musical pitches (A3 = 69 = 440 Hz)
21 | - IMPULSE: single-sample impulse
22 | - WHITE: white noise
23 | - PINK: pink noise
24 | - SINE: ISO 1/3-octave frequencies
25 | - LOG SWP: logarithmic frequency sweep
26 | - LOG STEP: 1/3-octave steps
27 | - LIN SWP: linear frequency sweep
28 |
--------------------------------------------------------------------------------
/TestTone/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class MDATestToneAudioProcessor : public juce::AudioProcessor,
6 | private juce::ValueTree::Listener,
7 | private juce::AudioProcessorValueTreeState::Listener
8 | {
9 | public:
10 | MDATestToneAudioProcessor();
11 | ~MDATestToneAudioProcessor() override;
12 |
13 | void prepareToPlay(double sampleRate, int samplesPerBlock) override;
14 | void releaseResources() override;
15 | void reset() override;
16 |
17 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override;
18 |
19 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override;
20 |
21 | juce::AudioProcessorEditor *createEditor() override;
22 | bool hasEditor() const override { return true; }
23 |
24 | const juce::String getName() const override;
25 |
26 | bool acceptsMidi() const override { return false; }
27 | bool producesMidi() const override { return false; }
28 | bool isMidiEffect() const override { return false; }
29 | double getTailLengthSeconds() const override { return 0.0; }
30 |
31 | int getNumPrograms() override;
32 | int getCurrentProgram() override;
33 | void setCurrentProgram(int index) override;
34 | const juce::String getProgramName(int index) override;
35 | void changeProgramName(int index, const juce::String &newName) override;
36 |
37 | void getStateInformation(juce::MemoryBlock &destData) override;
38 | void setStateInformation(const void *data, int sizeInBytes) override;
39 |
40 | juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };
41 |
42 | private:
43 | juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
44 |
45 | void valueTreePropertyChanged(juce::ValueTree &, const juce::Identifier &) override
46 | {
47 | _parametersChanged.store(true);
48 | }
49 |
50 | std::atomic _parametersChanged { false };
51 |
52 | void parameterChanged(const juce::String &identifier, float value) override
53 | {
54 | // The following code triggers the UI to redraw F1 and F2 when the mode
55 | // changes, and the output level when the calibration setting changes.
56 | // Note that this doesn't work in AudioPluginHost's "Show all parameters"
57 | // but it does work with "Show plugin GUI". Not sure if this is the best
58 | // way to handle it in JUCE, but it seems to work. :-)
59 |
60 | if (identifier == "Mode") {
61 | auto f1Param = apvts.getParameter("F1");
62 | f1Param->beginChangeGesture();
63 | f1Param->setValueNotifyingHost(f1Param->getValue());
64 | f1Param->endChangeGesture();
65 |
66 | auto f2Param = apvts.getParameter("F2");
67 | f2Param->beginChangeGesture();
68 | f2Param->setValueNotifyingHost(f2Param->getValue());
69 | f2Param->endChangeGesture();
70 | }
71 | else if (identifier == "0dB =") {
72 | auto param = apvts.getParameter("Level");
73 | param->beginChangeGesture();
74 | param->setValueNotifyingHost(param->getValue());
75 | param->endChangeGesture();
76 | }
77 | }
78 |
79 | void update();
80 | void resetState();
81 |
82 | juce::String midi2string(float n);
83 | juce::String iso2string(float b);
84 |
85 | // The meaning of the F1 and F2 parameters changes based on the current mode.
86 | // What is displayed for the output level depends on the calibration setting.
87 | // These functions return the parameter value that is displayed to the user.
88 | juce::String stringFromValueF1(float value);
89 | juce::String stringFromValueF2(float value);
90 | juce::String stringFromValueOutputLevel(float value);
91 | juce::String stringFromValueCalibration(float value);
92 |
93 | // The currently selected mode.
94 | int _mode;
95 |
96 | // Gain for the left and right channels.
97 | float _left, _right;
98 |
99 | // Incoming audio is mixed into the generated sound at this gain level.
100 | float _thru;
101 |
102 | // Sweep time in seconds (1 - 32 sec).
103 | float _durationInSeconds;
104 |
105 | // Sweep time in number of samples.
106 | int _durationInSamples;
107 |
108 | // Remaining sweep time in number of samples.
109 | int _sweepRemaining;
110 |
111 | // Start and end frequencies for sweep.
112 | float _sweepStart, _sweepEnd;
113 |
114 | // Current sweep frequency.
115 | float _sweepFreq;
116 |
117 | // Step value for the frequency sweeps.
118 | float _sweepInc;
119 |
120 | // 2 pi / sample rate. Used for converting frequencies to radians.
121 | float _fscale;
122 |
123 | // Current phase and phase increment for sine wave oscillator.
124 | float _phase, _phaseInc;
125 |
126 | // Filter delay units for the pink noise filter.
127 | float _z0, _z1, _z2, _z3, _z4, _z5;
128 |
129 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MDATestToneAudioProcessor)
130 | };
131 |
--------------------------------------------------------------------------------