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