1 /*                                                     -*- linux-c -*-
2     Copyright (C) 2004 Tom Szilagyi
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 
18     $Id: tap_pinknoise.c,v 1.2 2004/08/13 18:34:31 tszilagyi Exp $
19 */
20 
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <math.h>
26 #include <time.h>
27 
28 #include "ladspa.h"
29 #include "tap_utils.h"
30 
31 /* The Unique ID of the plugin: */
32 #define ID_MONO         2155
33 
34 
35 /* The port numbers for the plugin: */
36 #define HURST  0
37 #define SIGNAL 1
38 #define NOISE  2
39 #define INPUT  3
40 #define OUTPUT 4
41 
42 
43 /* Total number of ports */
44 #define PORTCOUNT_MONO   5
45 
46 
47 #define NOISE_LEN  1024
48 
49 
50 /* The structure used to hold port connection information and state */
51 typedef struct {
52 	LADSPA_Data * hurst;
53 	LADSPA_Data * signal;
54 	LADSPA_Data * noise;
55 	LADSPA_Data * input;
56 	LADSPA_Data * output;
57 
58 	LADSPA_Data * ring;
59 	unsigned long buflen;
60 	unsigned long pos;
61 
62 	unsigned long sample_rate;
63 	LADSPA_Data run_adding_gain;
64 } Pinknoise;
65 
66 
67 
68 /* generate fractal pattern using Midpoint Displacement Method
69  * v: buffer of floats to output fractal pattern to
70  * N: length of v, MUST be integer power of 2 (ie 128, 256, ...)
71  * H: Hurst constant, between 0 and 0.9999 (fractal dimension)
72  */
73 void
fractal(LADSPA_Data * v,int N,float H)74 fractal(LADSPA_Data * v, int N, float H) {
75 
76 	int l = N;
77 	int k;
78 	float r = 2.0f * H*H + 0.3f;
79 	int c;
80 
81 	v[0] = 0;
82 	while (l > 1) {
83 		k = N / l;
84 		for (c = 0; c < k; c++) {
85 			v[c*l + l/2] = (v[c*l] + v[((c+1) * l) % N]) / 2.0f +
86 				2.0f * r * (rand() - (float)RAND_MAX/2.0f) / (float)RAND_MAX;
87 			v[c*l + l/2] = LIMIT(v[c*l + l/2], -1.0f, 1.0f);
88 		}
89 		l /= 2;
90 		r /= powf(2, H);
91 	}
92 }
93 
94 
95 
96 /* Construct a new plugin instance. */
97 LADSPA_Handle
instantiate_Pinknoise(const LADSPA_Descriptor * Descriptor,unsigned long SampleRate)98 instantiate_Pinknoise(const LADSPA_Descriptor * Descriptor,
99 		      unsigned long             SampleRate) {
100 
101 	LADSPA_Handle * ptr;
102 
103 	if ((ptr = malloc(sizeof(Pinknoise))) != NULL) {
104 	        ((Pinknoise *)ptr)->sample_rate = SampleRate;
105 	        ((Pinknoise *)ptr)->run_adding_gain = 1.0;
106 
107                 if ((((Pinknoise *)ptr)->ring =
108                      calloc(NOISE_LEN, sizeof(LADSPA_Data))) == NULL)
109                         return NULL;
110                 ((Pinknoise *)ptr)->buflen = NOISE_LEN;
111                 ((Pinknoise *)ptr)->pos = 0;
112 
113 		return ptr;
114 	}
115 
116 	return NULL;
117 }
118 
119 
120 /* Connect a port to a data location. */
121 void
connect_port_Pinknoise(LADSPA_Handle Instance,unsigned long Port,LADSPA_Data * data)122 connect_port_Pinknoise(LADSPA_Handle Instance,
123 		       unsigned long Port,
124 		       LADSPA_Data * data) {
125 
126 	Pinknoise * ptr;
127 
128 	ptr = (Pinknoise *)Instance;
129 	switch (Port) {
130 	case HURST:
131 		ptr->hurst = data;
132 		break;
133 	case SIGNAL:
134 		ptr->signal = data;
135 		break;
136 	case NOISE:
137 		ptr->noise = data;
138 		break;
139 	case INPUT:
140 		ptr->input = data;
141 		break;
142 	case OUTPUT:
143 		ptr->output = data;
144 		break;
145 	}
146 }
147 
148 
149 
150 void
run_Pinknoise(LADSPA_Handle Instance,unsigned long SampleCount)151 run_Pinknoise(LADSPA_Handle Instance,
152 	      unsigned long SampleCount) {
153 
154 	Pinknoise * ptr = (Pinknoise *)Instance;
155 
156 	LADSPA_Data * input = ptr->input;
157 	LADSPA_Data * output = ptr->output;
158 	LADSPA_Data hurst = LIMIT(*(ptr->hurst), 0.0f, 1.0f);
159 	LADSPA_Data signal = db2lin(LIMIT(*(ptr->signal), -90.0f, 20.0f));
160 	LADSPA_Data noise = db2lin(LIMIT(*(ptr->noise), -90.0f, 20.0f));
161 	unsigned long sample_index;
162 
163   	for (sample_index = 0; sample_index < SampleCount; sample_index++) {
164 
165 		if (!ptr->pos)
166 			fractal(ptr->ring, NOISE_LEN, hurst);
167 
168 		*(output++) = signal * *(input++) +
169 			noise * push_buffer(0.0f, ptr->ring, ptr->buflen, &(ptr->pos));
170 	}
171 }
172 
173 
174 
175 void
set_run_adding_gain_Pinknoise(LADSPA_Handle Instance,LADSPA_Data gain)176 set_run_adding_gain_Pinknoise(LADSPA_Handle Instance, LADSPA_Data gain) {
177 
178 	Pinknoise * ptr;
179 
180 	ptr = (Pinknoise *)Instance;
181 
182 	ptr->run_adding_gain = gain;
183 }
184 
185 
186 
187 void
run_adding_Pinknoise(LADSPA_Handle Instance,unsigned long SampleCount)188 run_adding_Pinknoise(LADSPA_Handle Instance,
189 		   unsigned long SampleCount) {
190 
191 	Pinknoise * ptr = (Pinknoise *)Instance;
192 
193 	LADSPA_Data * input = ptr->input;
194 	LADSPA_Data * output = ptr->output;
195 	LADSPA_Data hurst = LIMIT(*(ptr->hurst), 0.0f, 1.0f);
196 	LADSPA_Data signal = db2lin(LIMIT(*(ptr->signal), -90.0f, 20.0f));
197 	LADSPA_Data noise = db2lin(LIMIT(*(ptr->noise), -90.0f, 20.0f));
198 	unsigned long sample_index;
199 
200   	for (sample_index = 0; sample_index < SampleCount; sample_index++) {
201 
202 		if (!ptr->pos)
203 			fractal(ptr->ring, NOISE_LEN, hurst);
204 
205 		*(output++) += ptr->run_adding_gain * (signal * *(input++) +
206 						       noise * push_buffer(0.0f, ptr->ring,
207 									   ptr->buflen, &(ptr->pos)));
208 	}
209 }
210 
211 
212 
213 
214 /* Throw away a Pinknoise effect instance. */
215 void
cleanup_Pinknoise(LADSPA_Handle Instance)216 cleanup_Pinknoise(LADSPA_Handle Instance) {
217         Pinknoise * ptr = (Pinknoise *)Instance;
218         free(ptr->ring);
219 	free(Instance);
220 }
221 
222 
223 
224 LADSPA_Descriptor * mono_descriptor = NULL;
225 
226 
227 
228 /* _init() is called automatically when the plugin library is first
229    loaded. */
230 void
_init()231 _init() {
232 
233 	char ** port_names;
234 	LADSPA_PortDescriptor * port_descriptors;
235 	LADSPA_PortRangeHint * port_range_hints;
236 
237 	if ((mono_descriptor =
238 	     (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL)
239 		exit(1);
240 
241 	/* initialize RNG */
242 	srand(time(0));
243 
244 	mono_descriptor->UniqueID = ID_MONO;
245 	mono_descriptor->Label = strdup("tap_pinknoise");
246 	mono_descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
247 	mono_descriptor->Name = strdup("TAP Pink/Fractal Noise");
248 	mono_descriptor->Maker = strdup("Tom Szilagyi");
249 	mono_descriptor->Copyright = strdup("GPL");
250 	mono_descriptor->PortCount = PORTCOUNT_MONO;
251 
252 	if ((port_descriptors =
253 	     (LADSPA_PortDescriptor *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortDescriptor))) == NULL)
254 		exit(1);
255 
256 	mono_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors;
257 	port_descriptors[HURST] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
258 	port_descriptors[SIGNAL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
259 	port_descriptors[NOISE] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
260 	port_descriptors[INPUT] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
261 	port_descriptors[OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
262 
263 	if ((port_names =
264 	     (char **)calloc(PORTCOUNT_MONO, sizeof(char *))) == NULL)
265 		exit(1);
266 
267 	mono_descriptor->PortNames = (const char **)port_names;
268 	port_names[HURST] = strdup("Fractal Dimension");
269 	port_names[SIGNAL] = strdup("Signal Level [dB]");
270 	port_names[NOISE] = strdup("Noise Level [dB]");
271 	port_names[INPUT] = strdup("Input");
272 	port_names[OUTPUT] = strdup("Output");
273 
274 	if ((port_range_hints =
275 	     ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortRangeHint)))) == NULL)
276 		exit(1);
277 
278 	mono_descriptor->PortRangeHints	= (const LADSPA_PortRangeHint *)port_range_hints;
279 	port_range_hints[HURST].HintDescriptor =
280 		(LADSPA_HINT_BOUNDED_BELOW |
281 		 LADSPA_HINT_BOUNDED_ABOVE |
282 		 LADSPA_HINT_DEFAULT_MIDDLE);
283 	port_range_hints[SIGNAL].HintDescriptor =
284 		(LADSPA_HINT_BOUNDED_BELOW |
285 		 LADSPA_HINT_BOUNDED_ABOVE |
286 		 LADSPA_HINT_DEFAULT_0);
287 	port_range_hints[NOISE].HintDescriptor =
288 		(LADSPA_HINT_BOUNDED_BELOW |
289 		 LADSPA_HINT_BOUNDED_ABOVE |
290 		 LADSPA_HINT_DEFAULT_MINIMUM);
291 	port_range_hints[HURST].LowerBound = 0.0f;
292 	port_range_hints[HURST].UpperBound = 1.0f;
293 	port_range_hints[SIGNAL].LowerBound = -90.0f;
294 	port_range_hints[SIGNAL].UpperBound = 20.0f;
295 	port_range_hints[NOISE].LowerBound = -90.0f;
296 	port_range_hints[NOISE].UpperBound = 20.0f;
297 	port_range_hints[INPUT].HintDescriptor = 0;
298 	port_range_hints[OUTPUT].HintDescriptor = 0;
299 	mono_descriptor->instantiate = instantiate_Pinknoise;
300 	mono_descriptor->connect_port = connect_port_Pinknoise;
301 	mono_descriptor->activate = NULL;
302 	mono_descriptor->run = run_Pinknoise;
303 	mono_descriptor->run_adding = run_adding_Pinknoise;
304 	mono_descriptor->set_run_adding_gain = set_run_adding_gain_Pinknoise;
305 	mono_descriptor->deactivate = NULL;
306 	mono_descriptor->cleanup = cleanup_Pinknoise;
307 }
308 
309 
310 void
delete_descriptor(LADSPA_Descriptor * descriptor)311 delete_descriptor(LADSPA_Descriptor * descriptor) {
312 	unsigned long index;
313 	if (descriptor) {
314 		free((char *)descriptor->Label);
315 		free((char *)descriptor->Name);
316 		free((char *)descriptor->Maker);
317 		free((char *)descriptor->Copyright);
318 		free((LADSPA_PortDescriptor *)descriptor->PortDescriptors);
319 		for (index = 0; index < descriptor->PortCount; index++)
320 			free((char *)(descriptor->PortNames[index]));
321 		free((char **)descriptor->PortNames);
322 		free((LADSPA_PortRangeHint *)descriptor->PortRangeHints);
323 		free(descriptor);
324 	}
325 }
326 
327 
328 /* _fini() is called automatically when the library is unloaded. */
329 void
_fini()330 _fini() {
331 	delete_descriptor(mono_descriptor);
332 }
333 
334 
335 /* Return a descriptor of the requested plugin type. */
336 const LADSPA_Descriptor *
ladspa_descriptor(unsigned long Index)337 ladspa_descriptor(unsigned long Index) {
338 
339 	switch (Index) {
340 	case 0:
341 		return mono_descriptor;
342 	default:
343 		return NULL;
344 	}
345 }
346