1 /* pink.cpp
2 
3    Interpolated pink noise plugins for use as control signals.
4 
5    (c) 2002 Nathaniel Virgo
6 
7    Computer Music Toolkit - a library of LADSPA plugins. Copyright (C)
8    2000-2002 Richard W.E. Furse. The author may be contacted at
9    richard@muse.demon.co.uk.
10 
11    This library is free software; you can redistribute it and/or
12    modify it under the terms of the GNU General Public Licence as
13    published by the Free Software Foundation; either version 2 of the
14    Licence, or (at your option) any later version.
15 
16    This library is distributed in the hope that it will be useful, but
17    WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19    General Public License for more details.
20 
21    You should have received a copy of the GNU General Public License
22    along with this library; if not, write to the Free Software
23    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24    02111-1307, USA. */
25 
26 /*****************************************************************************/
27 
28 #include <stdlib.h>
29 
30 /*****************************************************************************/
31 
32 #include "cmt.h"
33 
34 #include "pinknoise.h"
35 #include "utils.h"
36 
37 /*****************************************************************************/
38 
39 namespace pink {
40 
41     enum {
42 	port_frequency   = 0,
43 	port_output      = 1,
44 	n_ports          = 2
45     };
46 
47     /** This plugin generates a signal which approximates the effect of low-pass
48 	filtered pink noise, which makes for an interesting randomly changing
49 	control parameter.  It should probably use sinc interpolation, but in fact
50 	it uses third-order splines, which sound more-or-less okay to me. */
51     class Plugin : public CMT_PluginInstance {
52     private:
53 
54 	LADSPA_Data sample_rate;
55 
56 	PinkNoise noise_source;
57 	LADSPA_Data *data_points;
58 	int first_point;
59 	unsigned long counter;
60 	float multiplier;   // 1/(max counter value)
61 
62     public:
63 
Plugin(const LADSPA_Descriptor *,unsigned long s_rate)64         Plugin(const LADSPA_Descriptor *,
65 	       unsigned long s_rate) :
66 	    CMT_PluginInstance(n_ports),
67 	    sample_rate(s_rate) {
68 	    data_points = new LADSPA_Data[4];
69 	}
70 
~Plugin()71 	~Plugin() {
72 	    delete [] data_points;
73 	}
74 
75 	friend void activate(LADSPA_Handle instance);
76 
77 	friend void run_interpolated_audio(LADSPA_Handle instance,
78 					   unsigned long sample_count);
79 
80 	friend void run_interpolated_control(LADSPA_Handle instance,
81 					     unsigned long sample_count);
82 
83     };
84 
activate(LADSPA_Handle instance)85     void activate(LADSPA_Handle instance) {
86 	Plugin *pp = (Plugin *) instance;
87 	Plugin &p  = *pp;
88 
89 	p.noise_source.reset();
90 	for (int i=0; i<4; ++i)
91 	    p.data_points[i] = p.noise_source.getValue();
92 	p.first_point = 0;
93 	p.counter = 0;
94 	p.multiplier = 1;
95     }
96 
thirdInterp(const float & x,const float & L1,const float & L0,const float & H0,const float & H1)97     inline float thirdInterp(const float &x,
98 			     const float &L1,const float &L0,
99 			     const float &H0,const float &H1) {
100       return
101 	L0 +
102 	.5f*
103 	x*(H0-L1 +
104 	   x*(H0 + L0*(-2) + L1 +
105 	      x*( (H0 - L0)*9 + (L1 - H1)*3 +
106 		  x*((L0 - H0)*15 + (H1 - L1)*5 +
107 		     x*((H0 - L0)*6 + (L1 - H1)*2 )))));
108     }
109 
run_interpolated_audio(LADSPA_Handle instance,unsigned long sample_count)110     void run_interpolated_audio(LADSPA_Handle instance,
111 				unsigned long sample_count) {
112 
113 	Plugin *pp = (Plugin *) instance;
114 	Plugin &p  = *pp;
115 
116 	LADSPA_Data   frequency = *pp->m_ppfPorts[port_frequency];
117 	LADSPA_Data * out       =  pp->m_ppfPorts[port_output];
118 
119 	if (frequency<=0) {
120 	    LADSPA_Data value = thirdInterp( 1 - p.counter*p.multiplier,
121 					     p.data_points[  p.first_point        ],
122 					     p.data_points[ (p.first_point+1) % 4 ],
123 					     p.data_points[ (p.first_point+2) % 4 ],
124 					     p.data_points[ (p.first_point+3) % 4 ] );
125 	    for (unsigned long i=0; i<sample_count; ++i)
126 		*(out++) = value;
127 	} else {
128 	    frequency = BOUNDED_ABOVE(frequency, p.sample_rate);
129 	    unsigned long remain = sample_count;
130 	    while (remain) {
131 		unsigned long jump_samples = (remain<p.counter) ? remain : p.counter;
132 		for (unsigned long j=0; j<jump_samples; ++j) {
133 		    *(out++) = thirdInterp( 1 - p.counter*p.multiplier,
134 					    p.data_points[  p.first_point        ],
135 					    p.data_points[ (p.first_point+1) % 4 ],
136 					    p.data_points[ (p.first_point+2) % 4 ],
137 					    p.data_points[ (p.first_point+3) % 4 ] );
138 		    --p.counter;
139 		}
140 		remain -= jump_samples;
141 		if (p.counter == 0) {
142 		    p.data_points[p.first_point] = p.noise_source.getValue();
143 		    p.first_point = (p.first_point + 1) % 4;
144 		    p.multiplier = frequency/p.sample_rate;
145 		    p.counter = (unsigned long)(p.sample_rate/frequency);
146 		}
147 	    }
148 	}
149     }
150 
run_interpolated_control(LADSPA_Handle instance,unsigned long sample_count)151     void run_interpolated_control(LADSPA_Handle instance,
152 				  unsigned long sample_count) {
153 
154 	Plugin *pp = (Plugin *) instance;
155  	Plugin &p  = *pp;
156 
157 	LADSPA_Data   frequency = *pp->m_ppfPorts[port_frequency];
158 	LADSPA_Data * out       =  pp->m_ppfPorts[port_output];
159 
160 	float value = thirdInterp( 1 - p.counter*p.multiplier,
161 	                           p.data_points[  p.first_point        ],
162 				   p.data_points[ (p.first_point+1) % 4 ],
163 				   p.data_points[ (p.first_point+2) % 4 ],
164 				   p.data_points[ (p.first_point+3) % 4 ] );
165 	if (frequency>0) {
166 	    frequency = BOUNDED_ABOVE(frequency, p.sample_rate/sample_count);
167 	    while (p.counter <= sample_count) {
168 		p.data_points[ p.first_point ] = p.noise_source.getValue();
169 		p.first_point = (p.first_point + 1) % 4;
170 		p.multiplier = frequency/p.sample_rate;
171 		p.counter += (unsigned long)(p.sample_rate/frequency);
172 	    }
173 	    p.counter -= (p.counter < sample_count) ? p.counter : sample_count;
174 	}
175 	*(out)=value;
176     }
177 
initialise()178     void initialise() {
179 	CMT_Descriptor * d = new CMT_Descriptor
180 	    (1841,
181 	     "pink_interpolated_audio",
182 	     0,
183 	     "Pink Noise (Interpolated)",
184 	     CMT_MAKER("Nathaniel Virgo"),
185 	     CMT_COPYRIGHT("2002", "Nathaniel Virgo"),
186 	     NULL,
187 	     CMT_Instantiate<Plugin>,
188 	     activate,
189 	     run_interpolated_audio,
190 	     NULL,
191 	     NULL,
192 	     NULL);
193 	d->addPort
194 	    (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
195 	     "Highest frequency",
196 	     (LADSPA_HINT_BOUNDED_BELOW
197 	      | LADSPA_HINT_BOUNDED_ABOVE
198 	      | LADSPA_HINT_SAMPLE_RATE
199 	      | LADSPA_HINT_DEFAULT_1),
200 	     0,
201 	     1);
202 	d->addPort
203 	    (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
204 	     "Output");
205 	registerNewPluginDescriptor(d);
206 
207 	// the following has been commented out because I'm pretty sure that
208 	// control-rate outputs don't make sense for the vast majority of hosts.
209 	// (SSM being the notable exception)
210 	/*
211 	d = new CMT_Descriptor
212 	    (1842,
213 	     "pink_interpolated_control",
214 	     0,
215 	     "Pink Noise (Interpolated, control rate)",
216 	     CMT_MAKER("Nathaniel Virgo"),
217 	     CMT_COPYRIGHT("2002", "Nathaniel Virgo"),
218 	     NULL,
219 	     CMT_Instantiate<Plugin>,
220 	     activate,
221 	     run_interpolated_control,
222 	     NULL,
223 	     NULL,
224 	     NULL);
225 	d->addPort
226 	    (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
227 	     "Highest frequency",
228 	     (LADSPA_HINT_BOUNDED_BELOW
229 	      | LADSPA_HINT_BOUNDED_ABOVE
230 	      | LADSPA_HINT_SAMPLE_RATE
231 	      | LADSPA_HINT_DEFAULT_1),
232 	     0,
233 	     0.002);  // arbitrary low value (sensible for sample_count around 500)
234 	d->addPort
235 	    (LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL,
236 	     "Output");
237 	registerNewPluginDescriptor(d);
238 	*/
239     }
240 
241 } // end of namespace
242 
243 /*****************************************************************************/
244 
245 /* EOF */
246