andrewm@0
|
1 /*
|
andrewm@0
|
2 This code accompanies the textbook:
|
andrewm@0
|
3
|
andrewm@0
|
4 Digital Audio Effects: Theory, Implementation and Application
|
andrewm@0
|
5 Joshua D. Reiss and Andrew P. McPherson
|
andrewm@0
|
6
|
andrewm@0
|
7 ---
|
andrewm@0
|
8
|
andrewm@0
|
9 Empty: template for an effect; passes input to output unmodified
|
andrewm@0
|
10 See textbook Chapter 13: Building Audio Effect Plug-Ins
|
andrewm@0
|
11
|
andrewm@0
|
12 Code by Andrew McPherson, Brecht De Man and Joshua Reiss
|
andrewm@0
|
13
|
andrewm@0
|
14 ---
|
andrewm@0
|
15
|
andrewm@0
|
16 This program is free software: you can redistribute it and/or modify
|
andrewm@0
|
17 it under the terms of the GNU General Public License as published by
|
andrewm@0
|
18 the Free Software Foundation, either version 3 of the License, or
|
andrewm@0
|
19 (at your option) any later version.
|
andrewm@0
|
20
|
andrewm@0
|
21 This program is distributed in the hope that it will be useful,
|
andrewm@0
|
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
andrewm@0
|
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
andrewm@0
|
24 GNU General Public License for more details.
|
andrewm@0
|
25
|
andrewm@0
|
26 You should have received a copy of the GNU General Public License
|
andrewm@0
|
27 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
andrewm@0
|
28 */
|
andrewm@0
|
29
|
andrewm@0
|
30 #include "PluginProcessor.h"
|
andrewm@0
|
31 #include "PluginEditor.h"
|
andrewm@0
|
32
|
andrewm@0
|
33
|
andrewm@0
|
34 //==============================================================================
|
andrewm@0
|
35 EmptyAudioProcessor::EmptyAudioProcessor()
|
andrewm@0
|
36 {
|
andrewm@0
|
37 // Set default values:
|
andrewm@0
|
38
|
andrewm@0
|
39 volume_ = 1.0;
|
andrewm@0
|
40 lastUIWidth_ = 170;
|
andrewm@0
|
41 lastUIHeight_ = 100;
|
andrewm@0
|
42 }
|
andrewm@0
|
43
|
andrewm@0
|
44 EmptyAudioProcessor::~EmptyAudioProcessor()
|
andrewm@0
|
45 {
|
andrewm@0
|
46 }
|
andrewm@0
|
47
|
andrewm@0
|
48 //==============================================================================
|
andrewm@0
|
49 const String EmptyAudioProcessor::getName() const
|
andrewm@0
|
50 {
|
andrewm@0
|
51 return JucePlugin_Name;
|
andrewm@0
|
52 }
|
andrewm@0
|
53
|
andrewm@0
|
54 int EmptyAudioProcessor::getNumParameters()
|
andrewm@0
|
55 {
|
andrewm@0
|
56 return kNumParameters;
|
andrewm@0
|
57 }
|
andrewm@0
|
58
|
andrewm@0
|
59 float EmptyAudioProcessor::getParameter (int index)
|
andrewm@0
|
60 {
|
andrewm@0
|
61 // This method will be called by the host, probably on the audio thread, so
|
andrewm@0
|
62 // it's absolutely time-critical. Don't use critical sections or anything
|
andrewm@0
|
63 // UI-related, or anything at all that may block in any way!
|
andrewm@0
|
64 switch (index)
|
andrewm@0
|
65 {
|
andrewm@0
|
66 case kVolumeParam: return volume_;
|
andrewm@0
|
67 default: return 0.0f;
|
andrewm@0
|
68 }
|
andrewm@0
|
69 }
|
andrewm@0
|
70
|
andrewm@0
|
71 void EmptyAudioProcessor::setParameter (int index, float newValue)
|
andrewm@0
|
72 {
|
andrewm@0
|
73 // This method will be called by the host, probably on the audio thread, so
|
andrewm@0
|
74 // it's absolutely time-critical. Don't use critical sections or anything
|
andrewm@0
|
75 // UI-related, or anything at all that may block in any way!
|
andrewm@0
|
76 switch (index)
|
andrewm@0
|
77 {
|
andrewm@0
|
78 case kVolumeParam:
|
andrewm@0
|
79 volume_ = newValue;
|
andrewm@0
|
80 break;
|
andrewm@0
|
81 default:
|
andrewm@0
|
82 break;
|
andrewm@0
|
83 }
|
andrewm@0
|
84 }
|
andrewm@0
|
85
|
andrewm@0
|
86 const String EmptyAudioProcessor::getParameterName (int index)
|
andrewm@0
|
87 {
|
andrewm@0
|
88 switch (index)
|
andrewm@0
|
89 {
|
andrewm@0
|
90 case kVolumeParam: return "volume";
|
andrewm@0
|
91 default: break;
|
andrewm@0
|
92 }
|
andrewm@0
|
93
|
andrewm@0
|
94 return String::empty;
|
andrewm@0
|
95 }
|
andrewm@0
|
96
|
andrewm@0
|
97 const String EmptyAudioProcessor::getParameterText (int index)
|
andrewm@0
|
98 {
|
andrewm@0
|
99 return String (getParameter (index), 2);
|
andrewm@0
|
100 }
|
andrewm@0
|
101
|
andrewm@0
|
102 const String EmptyAudioProcessor::getInputChannelName (int channelIndex) const
|
andrewm@0
|
103 {
|
andrewm@0
|
104 return String (channelIndex + 1);
|
andrewm@0
|
105 }
|
andrewm@0
|
106
|
andrewm@0
|
107 const String EmptyAudioProcessor::getOutputChannelName (int channelIndex) const
|
andrewm@0
|
108 {
|
andrewm@0
|
109 return String (channelIndex + 1);
|
andrewm@0
|
110 }
|
andrewm@0
|
111
|
andrewm@0
|
112 bool EmptyAudioProcessor::isInputChannelStereoPair (int index) const
|
andrewm@0
|
113 {
|
andrewm@0
|
114 return true;
|
andrewm@0
|
115 }
|
andrewm@0
|
116
|
andrewm@0
|
117 bool EmptyAudioProcessor::isOutputChannelStereoPair (int index) const
|
andrewm@0
|
118 {
|
andrewm@0
|
119 return true;
|
andrewm@0
|
120 }
|
andrewm@0
|
121
|
andrewm@0
|
122 bool EmptyAudioProcessor::silenceInProducesSilenceOut() const
|
andrewm@0
|
123 {
|
andrewm@0
|
124 #if JucePlugin_SilenceInProducesSilenceOut
|
andrewm@0
|
125 return true;
|
andrewm@0
|
126 #else
|
andrewm@0
|
127 return false;
|
andrewm@0
|
128 #endif
|
andrewm@0
|
129 }
|
andrewm@0
|
130
|
andrewm@0
|
131 double EmptyAudioProcessor::getTailLengthSeconds() const
|
andrewm@0
|
132 {
|
andrewm@0
|
133 return 0.0;
|
andrewm@0
|
134 }
|
andrewm@0
|
135
|
andrewm@0
|
136 bool EmptyAudioProcessor::acceptsMidi() const
|
andrewm@0
|
137 {
|
andrewm@0
|
138 #if JucePlugin_WantsMidiInput
|
andrewm@0
|
139 return true;
|
andrewm@0
|
140 #else
|
andrewm@0
|
141 return false;
|
andrewm@0
|
142 #endif
|
andrewm@0
|
143 }
|
andrewm@0
|
144
|
andrewm@0
|
145 bool EmptyAudioProcessor::producesMidi() const
|
andrewm@0
|
146 {
|
andrewm@0
|
147 #if JucePlugin_ProducesMidiOutput
|
andrewm@0
|
148 return true;
|
andrewm@0
|
149 #else
|
andrewm@0
|
150 return false;
|
andrewm@0
|
151 #endif
|
andrewm@0
|
152 }
|
andrewm@0
|
153
|
andrewm@0
|
154 int EmptyAudioProcessor::getNumPrograms()
|
andrewm@0
|
155 {
|
andrewm@0
|
156 return 0;
|
andrewm@0
|
157 }
|
andrewm@0
|
158
|
andrewm@0
|
159 int EmptyAudioProcessor::getCurrentProgram()
|
andrewm@0
|
160 {
|
andrewm@0
|
161 return 0;
|
andrewm@0
|
162 }
|
andrewm@0
|
163
|
andrewm@0
|
164 void EmptyAudioProcessor::setCurrentProgram (int index)
|
andrewm@0
|
165 {
|
andrewm@0
|
166 }
|
andrewm@0
|
167
|
andrewm@0
|
168 const String EmptyAudioProcessor::getProgramName (int index)
|
andrewm@0
|
169 {
|
andrewm@0
|
170 return String::empty;
|
andrewm@0
|
171 }
|
andrewm@0
|
172
|
andrewm@0
|
173 void EmptyAudioProcessor::changeProgramName (int index, const String& newName)
|
andrewm@0
|
174 {
|
andrewm@0
|
175 }
|
andrewm@0
|
176
|
andrewm@0
|
177 //==============================================================================
|
andrewm@0
|
178 void EmptyAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
|
andrewm@0
|
179 {
|
andrewm@0
|
180 // Use this method as the place to do any pre-playback
|
andrewm@0
|
181 // initialisation that you need..
|
andrewm@0
|
182 }
|
andrewm@0
|
183
|
andrewm@0
|
184 void EmptyAudioProcessor::releaseResources()
|
andrewm@0
|
185 {
|
andrewm@0
|
186 // When playback stops, you can use this as an opportunity to free up any
|
andrewm@0
|
187 // spare memory, etc.
|
andrewm@0
|
188 }
|
andrewm@0
|
189
|
andrewm@0
|
190 void EmptyAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
|
andrewm@0
|
191 {
|
andrewm@0
|
192 // Helpful information about this block of samples:
|
andrewm@0
|
193 const int numInputChannels = getNumInputChannels(); // How many input channels for our effect?
|
andrewm@0
|
194 const int numOutputChannels = getNumOutputChannels(); // How many output channels for our effect?
|
andrewm@0
|
195 const int numSamples = buffer.getNumSamples(); // How many samples in the buffer for this block?
|
andrewm@0
|
196
|
andrewm@0
|
197 // Go through each channel of audio that's passed in
|
andrewm@0
|
198
|
andrewm@0
|
199 for (int channel = 0; channel < numInputChannels; ++channel)
|
andrewm@0
|
200 {
|
andrewm@0
|
201 // channelData is an array of length numSamples which contains the audio for one channel
|
b@1
|
202 float* channelData = buffer.getWritePointer(channel);
|
andrewm@0
|
203
|
andrewm@0
|
204 for (int i = 0; i < numSamples; ++i)
|
andrewm@0
|
205 {
|
andrewm@0
|
206 const float in = channelData[i];
|
andrewm@0
|
207
|
andrewm@0
|
208 // Store the output sample back in the buffer
|
andrewm@0
|
209 channelData[i] = in * volume_;
|
andrewm@0
|
210 }
|
andrewm@0
|
211 }
|
andrewm@0
|
212
|
andrewm@0
|
213 // In case we have more outputs than inputs, we'll clear any output
|
andrewm@0
|
214 // channels that didn't contain input data, (because these aren't
|
andrewm@0
|
215 // guaranteed to be empty - they may contain garbage).
|
andrewm@0
|
216 for (int i = numInputChannels; i < numOutputChannels; ++i)
|
andrewm@0
|
217 {
|
andrewm@0
|
218 buffer.clear (i, 0, buffer.getNumSamples());
|
andrewm@0
|
219 }
|
andrewm@0
|
220 }
|
andrewm@0
|
221
|
andrewm@0
|
222 //==============================================================================
|
andrewm@0
|
223 bool EmptyAudioProcessor::hasEditor() const
|
andrewm@0
|
224 {
|
andrewm@0
|
225 return true; // (change this to false if you choose to not supply an editor)
|
andrewm@0
|
226 }
|
andrewm@0
|
227
|
andrewm@0
|
228 AudioProcessorEditor* EmptyAudioProcessor::createEditor()
|
andrewm@0
|
229 {
|
andrewm@0
|
230 return new EmptyAudioProcessorEditor (this);
|
andrewm@0
|
231 }
|
andrewm@0
|
232
|
andrewm@0
|
233 //==============================================================================
|
andrewm@0
|
234 void EmptyAudioProcessor::getStateInformation (MemoryBlock& destData)
|
andrewm@0
|
235 {
|
andrewm@0
|
236 // You should use this method to store your parameters in the memory block.
|
andrewm@0
|
237 // You could do that either as raw data, or use the XML or ValueTree classes
|
andrewm@0
|
238 // as intermediaries to make it easy to save and load complex data.
|
andrewm@0
|
239
|
andrewm@0
|
240 // Create an outer XML element..
|
andrewm@0
|
241 XmlElement xml("C4DMPLUGINSETTINGS");
|
andrewm@0
|
242
|
andrewm@0
|
243 // add some attributes to it..
|
andrewm@0
|
244 xml.setAttribute("uiWidth", lastUIWidth_);
|
andrewm@0
|
245 xml.setAttribute("uiHeight", lastUIHeight_);
|
andrewm@0
|
246 xml.setAttribute("volume", volume_);
|
andrewm@0
|
247
|
andrewm@0
|
248 // then use this helper function to stuff it into the binary blob and return it..
|
andrewm@0
|
249 copyXmlToBinary(xml, destData);
|
andrewm@0
|
250 }
|
andrewm@0
|
251
|
andrewm@0
|
252 void EmptyAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
|
andrewm@0
|
253 {
|
andrewm@0
|
254 // You should use this method to restore your parameters from this memory block,
|
andrewm@0
|
255 // whose contents will have been created by the getStateInformation() call.
|
andrewm@0
|
256
|
andrewm@0
|
257 // This getXmlFromBinary() helper function retrieves our XML from the binary blob..
|
andrewm@0
|
258 ScopedPointer<XmlElement> xmlState (getXmlFromBinary (data, sizeInBytes));
|
andrewm@0
|
259
|
andrewm@0
|
260 if(xmlState != 0)
|
andrewm@0
|
261 {
|
andrewm@0
|
262 // make sure that it's actually our type of XML object..
|
andrewm@0
|
263 if(xmlState->hasTagName("C4DMPLUGINSETTINGS"))
|
andrewm@0
|
264 {
|
andrewm@0
|
265 // ok, now pull out our parameters..
|
andrewm@0
|
266 lastUIWidth_ = xmlState->getIntAttribute("uiWidth", lastUIWidth_);
|
andrewm@0
|
267 lastUIHeight_ = xmlState->getIntAttribute("uiHeight", lastUIHeight_);
|
andrewm@0
|
268
|
andrewm@0
|
269 volume_ = (float)xmlState->getDoubleAttribute("volume", volume_);
|
andrewm@0
|
270 }
|
andrewm@0
|
271 }
|
andrewm@0
|
272 }
|
andrewm@0
|
273
|
andrewm@0
|
274 //==============================================================================
|
andrewm@0
|
275 // This creates new instances of the plugin..
|
andrewm@0
|
276 AudioProcessor* JUCE_CALLTYPE createPluginFilter()
|
andrewm@0
|
277 {
|
andrewm@0
|
278 return new EmptyAudioProcessor();
|
andrewm@0
|
279 }
|