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