1 /* grain.cpp
2
3 Computer Music Toolkit - a library of LADSPA plugins. Copyright (C)
4 2000-2002 Richard W.E. Furse. The author may be contacted at
5 richard@muse.demon.co.uk.
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public Licence as
9 published by the Free Software Foundation; either version 2 of the
10 Licence, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this library; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307, USA. */
21
22 /*****************************************************************************/
23
24 #include <stdlib.h>
25 #include <string.h>
26
27 /*****************************************************************************/
28
29 #include "cmt.h"
30 #include "utils.h"
31
32 /*****************************************************************************/
33
34 /** Period (in seconds) from which grains are selected. */
35 #define GRAIN_MAXIMUM_HISTORY 6
36 #define GRAIN_MAXIMUM_BLOCK 1 /* (seconds) */
37
38 #define GRAIN_MAXIMUM_SCATTER (GRAIN_MAXIMUM_HISTORY - GRAIN_MAXIMUM_BLOCK)
39 #define GRAIN_MAXIMUM_LENGTH (GRAIN_MAXIMUM_HISTORY - GRAIN_MAXIMUM_BLOCK)
40
41 /** What quality should we require when sampling the normal
42 distribution to generate grain counts? */
43 #define GRAIN_NORMAL_RV_QUALITY 16
44
45 /*****************************************************************************/
46
47 /** Pointers to this can be used as linked list of grains. */
48 class Grain {
49 private:
50
51 long m_lReadPointer;
52 long m_lGrainLength;
53 long m_lAttackTime;
54
55 long m_lRunTime;
56
57 bool m_bFinished;
58
59 LADSPA_Data m_fAttackSlope;
60 LADSPA_Data m_fDecaySlope;
61
62 public:
63
Grain(const long lReadPointer,const long lGrainLength,const long lAttackTime)64 Grain(const long lReadPointer,
65 const long lGrainLength,
66 const long lAttackTime)
67 : m_lReadPointer(lReadPointer),
68 m_lGrainLength(lGrainLength),
69 m_lAttackTime(lAttackTime),
70 m_lRunTime(0),
71 m_bFinished(false) {
72 if (lAttackTime <= 0) {
73 m_fAttackSlope = 0;
74 m_fDecaySlope = LADSPA_Data(1.0 / lGrainLength);
75 }
76 else {
77 m_fAttackSlope = LADSPA_Data(1.0 / lAttackTime);
78 if (lAttackTime >= lGrainLength)
79 m_fDecaySlope = 0;
80 else
81 m_fDecaySlope = LADSPA_Data(1.0 / (lGrainLength - lAttackTime));
82 }
83 }
84
isFinished() const85 bool isFinished() const {
86 return m_bFinished;
87 }
88
89 /** NULL if end of grain list. */
90 Grain * m_poNextGrain;
91
run(const unsigned long lSampleCount,float * pfOutput,const float * pfHistoryBuffer,const unsigned long lHistoryBufferSize)92 void run(const unsigned long lSampleCount,
93 float * pfOutput,
94 const float * pfHistoryBuffer,
95 const unsigned long lHistoryBufferSize) {
96
97 LADSPA_Data fAmp;
98 if (m_lRunTime < m_lAttackTime)
99 fAmp = m_fAttackSlope * m_lRunTime;
100 else
101 fAmp = m_fDecaySlope * (m_lGrainLength - m_lRunTime);
102
103 for (unsigned long lSampleIndex = 0;
104 lSampleIndex < lSampleCount;
105 lSampleIndex++) {
106
107 if (fAmp < 0) {
108 m_bFinished = true;
109 break;
110 }
111
112 *(pfOutput++) += fAmp * pfHistoryBuffer[m_lReadPointer];
113
114 m_lReadPointer = (m_lReadPointer + 1) & (lHistoryBufferSize - 1);
115
116 if (m_lRunTime < m_lAttackTime)
117 fAmp += m_fAttackSlope;
118 else
119 fAmp -= m_fDecaySlope;
120
121 m_lRunTime++;
122 }
123 }
124 };
125
126 /*****************************************************************************/
127
128 #define GRN_INPUT 0
129 #define GRN_OUTPUT 1
130 #define GRN_DENSITY 2
131 #define GRN_SCATTER 3
132 #define GRN_GRAIN_LENGTH 4
133 #define GRN_GRAIN_ATTACK 5
134
135 /** This plugin cuts an audio stream up and uses it to generate a
136 granular texture. */
137 class GrainScatter : public CMT_PluginInstance {
138 private:
139
140 Grain * m_poCurrentGrains;
141
142 long m_lSampleRate;
143
144 LADSPA_Data * m_pfBuffer;
145
146 /** Buffer size, a power of two. */
147 unsigned long m_lBufferSize;
148
149 /** Write pointer in buffer. */
150 unsigned long m_lWritePointer;
151
152 public:
153
GrainScatter(const LADSPA_Descriptor *,unsigned long lSampleRate)154 GrainScatter(const LADSPA_Descriptor *,
155 unsigned long lSampleRate)
156 : CMT_PluginInstance(6),
157 m_poCurrentGrains(NULL),
158 m_lSampleRate(lSampleRate) {
159 /* Buffer size is a power of two bigger than max delay time. */
160 unsigned long lMinimumBufferSize
161 = (unsigned long)((LADSPA_Data)lSampleRate * GRAIN_MAXIMUM_HISTORY);
162 m_lBufferSize = 1;
163 while (m_lBufferSize < lMinimumBufferSize)
164 m_lBufferSize <<= 1;
165 m_pfBuffer = new LADSPA_Data[m_lBufferSize];
166 }
167
~GrainScatter()168 ~GrainScatter() {
169 delete [] m_pfBuffer;
170 }
171
172 friend void activateGrainScatter(LADSPA_Handle Instance);
173 friend void runGrainScatter(LADSPA_Handle Instance,
174 unsigned long SampleCount);
175
176 };
177
178 /*****************************************************************************/
179
180 /** Initialise and activate a plugin instance. */
181 void
activateGrainScatter(LADSPA_Handle Instance)182 activateGrainScatter(LADSPA_Handle Instance) {
183
184 GrainScatter * poGrainScatter = (GrainScatter *)Instance;
185
186 /* Need to reset the delay history in this function rather than
187 instantiate() in case deactivate() followed by activate() have
188 been called to reinitialise a delay line. */
189 memset(poGrainScatter->m_pfBuffer,
190 0,
191 sizeof(LADSPA_Data) * poGrainScatter->m_lBufferSize);
192
193 poGrainScatter->m_lWritePointer = 0;
194 }
195
196 /*****************************************************************************/
197
198 void
runGrainScatter(LADSPA_Handle Instance,unsigned long SampleCount)199 runGrainScatter(LADSPA_Handle Instance,
200 unsigned long SampleCount) {
201
202 GrainScatter * poGrainScatter = (GrainScatter *)Instance;
203
204 LADSPA_Data * pfInput = poGrainScatter->m_ppfPorts[GRN_INPUT];
205 LADSPA_Data * pfOutput = poGrainScatter->m_ppfPorts[GRN_OUTPUT];
206
207 unsigned long lMaximumSampleCount
208 = (unsigned long)(poGrainScatter->m_lSampleRate
209 * GRAIN_MAXIMUM_BLOCK);
210
211 if (SampleCount > lMaximumSampleCount) {
212
213 /* We're beyond our capabilities. We're going to run out of delay
214 line for a large grain. Divide and conquer. */
215
216 runGrainScatter(Instance, lMaximumSampleCount);
217
218 poGrainScatter->m_ppfPorts[GRN_INPUT] += lMaximumSampleCount;
219 poGrainScatter->m_ppfPorts[GRN_OUTPUT] += lMaximumSampleCount;
220 runGrainScatter(Instance, SampleCount - lMaximumSampleCount);
221 poGrainScatter->m_ppfPorts[GRN_INPUT] = pfInput;
222 poGrainScatter->m_ppfPorts[GRN_OUTPUT] = pfOutput;
223
224 }
225 else {
226
227 /* Move the delay line along. */
228 if (poGrainScatter->m_lWritePointer
229 + SampleCount
230 > poGrainScatter->m_lBufferSize) {
231 memcpy(poGrainScatter->m_pfBuffer + poGrainScatter->m_lWritePointer,
232 pfInput,
233 sizeof(LADSPA_Data) * (poGrainScatter->m_lBufferSize
234 - poGrainScatter->m_lWritePointer));
235 memcpy(poGrainScatter->m_pfBuffer,
236 pfInput + (poGrainScatter->m_lBufferSize
237 - poGrainScatter->m_lWritePointer),
238 sizeof(LADSPA_Data) * (SampleCount
239 - (poGrainScatter->m_lBufferSize
240 - poGrainScatter->m_lWritePointer)));
241 }
242 else {
243 memcpy(poGrainScatter->m_pfBuffer + poGrainScatter->m_lWritePointer,
244 pfInput,
245 sizeof(LADSPA_Data) * SampleCount);
246 }
247 poGrainScatter->m_lWritePointer
248 = ((poGrainScatter->m_lWritePointer + SampleCount)
249 & (poGrainScatter->m_lBufferSize - 1));
250
251 /* Empty the output buffer. */
252 memset(pfOutput, 0, SampleCount * sizeof(LADSPA_Data));
253
254 /* Process current grains. */
255 Grain ** ppoGrainReference = &(poGrainScatter->m_poCurrentGrains);
256 while (*ppoGrainReference != NULL) {
257 (*ppoGrainReference)->run(SampleCount,
258 pfOutput,
259 poGrainScatter->m_pfBuffer,
260 poGrainScatter->m_lBufferSize);
261 if ((*ppoGrainReference)->isFinished()) {
262 Grain *poNextGrain = (*ppoGrainReference)->m_poNextGrain;
263 delete *ppoGrainReference;
264 *ppoGrainReference = poNextGrain;
265 }
266 else {
267 ppoGrainReference = &((*ppoGrainReference)->m_poNextGrain);
268 }
269 }
270
271 LADSPA_Data fSampleRate = LADSPA_Data(poGrainScatter->m_lSampleRate);
272 LADSPA_Data fDensity
273 = BOUNDED_BELOW(*(poGrainScatter->m_ppfPorts[GRN_DENSITY]),
274 0);
275
276 /* We want to average fDensity new grains per second. We need to
277 use a RNG to generate a new grain count from the fraction of a
278 second we are dealing with. Use a normal distribution and
279 choose standard deviation also to be fDensity. This could be
280 separately parameterised but any guarantees could be confusing
281 given that individual grains are uniformly distributed within
282 the block. Note that fDensity isn't quite grains/sec as we
283 discard negative samples from the RV. */
284 double dGrainCountRV_Mean = fDensity * SampleCount / fSampleRate;
285 double dGrainCountRV_SD = dGrainCountRV_Mean;
286 double dGrainCountRV = sampleNormalDistribution(dGrainCountRV_Mean,
287 dGrainCountRV_SD,
288 GRAIN_NORMAL_RV_QUALITY);
289 unsigned long lNewGrainCount = 0;
290 if (dGrainCountRV > 0)
291 lNewGrainCount = (unsigned long)(0.5 + dGrainCountRV);
292 if (lNewGrainCount > 0) {
293
294 LADSPA_Data fScatter
295 = BOUNDED(*(poGrainScatter->m_ppfPorts[GRN_SCATTER]),
296 0,
297 GRAIN_MAXIMUM_SCATTER);
298 LADSPA_Data fGrainLength
299 = BOUNDED_BELOW(*(poGrainScatter->m_ppfPorts[GRN_GRAIN_LENGTH]),
300 0);
301 LADSPA_Data fAttack
302 = BOUNDED_BELOW(*(poGrainScatter->m_ppfPorts[GRN_GRAIN_ATTACK]),
303 0);
304
305 long lScatterSampleWidth
306 = long(fSampleRate * fScatter) + 1;
307 long lGrainLength
308 = long(fSampleRate * fGrainLength);
309 long lAttackTime
310 = long(fSampleRate * fAttack);
311
312 for (unsigned long lIndex = 0; lIndex < lNewGrainCount; lIndex++) {
313
314 long lOffset = rand() % SampleCount;
315
316 long lGrainReadPointer
317 = (poGrainScatter->m_lWritePointer
318 - SampleCount
319 + lOffset
320 - (rand() % lScatterSampleWidth));
321 while (lGrainReadPointer < 0)
322 lGrainReadPointer += poGrainScatter->m_lBufferSize;
323 lGrainReadPointer &= (poGrainScatter->m_lBufferSize - 1);
324
325 Grain * poNewGrain = new Grain(lGrainReadPointer,
326 lGrainLength,
327 lAttackTime);
328
329 poNewGrain->m_poNextGrain = poGrainScatter->m_poCurrentGrains;
330 poGrainScatter->m_poCurrentGrains = poNewGrain;
331
332 poNewGrain->run(SampleCount - lOffset,
333 pfOutput + lOffset,
334 poGrainScatter->m_pfBuffer,
335 poGrainScatter->m_lBufferSize);
336 }
337 }
338 }
339 }
340
341 /*****************************************************************************/
342
343 void
initialise_grain()344 initialise_grain() {
345
346 CMT_Descriptor * psDescriptor = new CMT_Descriptor
347 (1096,
348 "grain_scatter",
349 0,
350 "Granular Scatter Processor",
351 CMT_MAKER("Richard W.E. Furse"),
352 CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"),
353 NULL,
354 CMT_Instantiate<GrainScatter>,
355 activateGrainScatter,
356 runGrainScatter,
357 NULL,
358 NULL,
359 NULL);
360 psDescriptor->addPort
361 (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
362 "Input");
363 psDescriptor->addPort
364 (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
365 "Output");
366 psDescriptor->addPort
367 (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
368 "Density (Grains/s)",
369 (LADSPA_HINT_BOUNDED_BELOW
370 | LADSPA_HINT_DEFAULT_MAXIMUM),
371 0,
372 10);
373 psDescriptor->addPort
374 (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
375 "Scatter (s)",
376 (LADSPA_HINT_BOUNDED_BELOW
377 | LADSPA_HINT_BOUNDED_ABOVE
378 | LADSPA_HINT_DEFAULT_MIDDLE),
379 0,
380 GRAIN_MAXIMUM_SCATTER);
381 psDescriptor->addPort
382 (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
383 "Grain Length (s)",
384 (LADSPA_HINT_BOUNDED_BELOW
385 | LADSPA_HINT_DEFAULT_MAXIMUM),
386 0,
387 0.2);
388 psDescriptor->addPort
389 (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
390 "Grain Attack (s)",
391 (LADSPA_HINT_BOUNDED_BELOW
392 | LADSPA_HINT_DEFAULT_MAXIMUM),
393 0,
394 0.05);
395
396 registerNewPluginDescriptor(psDescriptor);
397 }
398
399 /*****************************************************************************/
400
401 /* EOF */
402