Nsound  0.9.4
Generator.cc
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------
2 //
3 // $Id: Generator.cc 912 2015-07-26 00:50:29Z weegreenblobbie $
4 //
5 // Copyright (c) 2005-2006 Nick Hilton
6 //
7 // weegreenblobbie_yahoo_com (replace '_' with '@' and '.')
8 //
9 //-----------------------------------------------------------------------------
10 
11 //-----------------------------------------------------------------------------
12 //
13 // This program is free software; you can redistribute it and/or modify
14 // it under the terms of the GNU General Public License as published by
15 // the Free Software Foundation; either version 2 of the License, or
16 // (at your option) any later version.
17 //
18 // This program is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 // GNU Library General Public License for more details.
22 //
23 // You should have received a copy of the GNU General Public License
24 // along with this program; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 //
27 //-----------------------------------------------------------------------------
28 
29 #include <Nsound/Buffer.h>
30 #include <Nsound/Generator.h>
31 #include <Nsound/RngTausworthe.h>
32 
33 #include <iostream>
34 
35 //~#include <cmath>
36 #include <string.h>
37 
38 #include <math.h>
39 
40 using namespace Nsound;
41 
42 using std::cout;
43 using std::cerr;
44 using std::endl;
45 
46 #define M_2PI (2.0*M_PI)
47 
48 #define CERR_HEADER __FILE__ << ":" << __LINE__ << ": "
49 
50 // Constructor
53  :
54  last_frequency_(0.0),
55  position_(0.0),
56  sync_pos_(0.0),
57  sample_rate_(0.0),
58  sample_time_(0.0),
59  t_(0.0),
60  waveform_(NULL),
61  rng_(NULL),
62  buzz_max_harmonics_(0),
63  buzz_position_(),
64  chorus_is_on_(false),
65  chorus_n_voices_(0),
66  chorus_position_(),
67  chorus_factor_(),
68  sync_is_master_(false),
69  sync_is_slave_(false),
70  sync_count_(0),
71  sync_vector_(),
72  sync_slaves_()
73 {
74 };
75 
76 // Constructor
78 Generator(const float64 & sample_rate)
79  :
80  is_realtime_(false),
81  last_frequency_(0.0),
82  position_(0.0),
83  sync_pos_(0.0),
84  sample_rate_(0.0),
85  sample_time_(0.0),
86  t_(0.0),
87  waveform_(NULL),
88  rng_(NULL),
89  buzz_max_harmonics_(0),
90  buzz_position_(),
91  chorus_is_on_(false),
92  chorus_n_voices_(0),
93  chorus_position_(),
94  chorus_factor_(),
95  sync_is_master_(false),
96  sync_is_slave_(false),
97  sync_count_(0),
98  sync_vector_(),
99  sync_slaves_()
100 {
101  ctor(sample_rate);
102 }
103 
104 // Constructor
106 Generator(const std::string & wave_filename)
107  :
108  is_realtime_(false),
109  last_frequency_(0.0),
110  position_(0.0),
111  sync_pos_(0.0),
112  sample_rate_(0.0),
113  sample_time_(0.0),
114  t_(0.0),
115  waveform_(NULL),
116  rng_(NULL),
117  buzz_max_harmonics_(0),
118  buzz_position_(),
119  chorus_is_on_(false),
120  chorus_n_voices_(0),
121  chorus_position_(),
122  chorus_factor_(),
123  sync_is_master_(false),
124  sync_is_slave_(false),
125  sync_count_(0),
126  sync_vector_(),
127  sync_slaves_()
128 {
129  Buffer b(wave_filename);
130  ctor(b.getLength(), b);
131 }
132 
133 // Constructor
135 Generator(const float64 & sample_rate, const Buffer & waveform)
136  :
137  is_realtime_(false),
138  last_frequency_(0.0),
139  position_(0.0),
140  sync_pos_(0.0),
141  sample_rate_(0.0),
142  sample_time_(0.0),
143  t_(0.0),
144  waveform_(NULL),
145  rng_(NULL),
146  buzz_max_harmonics_(0),
147  buzz_position_(),
148  chorus_is_on_(false),
149  chorus_n_voices_(0),
150  chorus_position_(),
151  chorus_factor_(),
152  sync_is_master_(false),
153  sync_is_slave_(false),
154  sync_count_(0),
155  sync_vector_(),
156  sync_slaves_()
157 {
158  ctor(sample_rate, waveform);
159 }
160 
161 // Copy Constructor
163 Generator(const Generator & copy)
164  :
165  is_realtime_(false),
166  last_frequency_(0.0),
167  position_(0.0),
168  sync_pos_(0.0),
169  sample_rate_(0.0),
170  sample_time_(0.0),
171  t_(0.0),
172  waveform_(NULL),
173  rng_(NULL),
174  buzz_max_harmonics_(0),
175  buzz_position_(),
176  chorus_is_on_(false),
177  chorus_n_voices_(0),
178  chorus_position_(),
179  chorus_factor_(),
180  sync_is_master_(false),
181  sync_is_slave_(false),
182  sync_count_(0),
183  sync_vector_(),
184  sync_slaves_()
185 {
186  // Call operator=
187  *this = copy;
188 }
189 
190 // Destructor
193 {
194  delete waveform_;
195  delete rng_;
196 };
197 
198 // ctor
199 void
201 ctor(const float64 & sample_rate)
202 {
203  sample_rate_ = sample_rate;
204  sample_time_ = 1.0 / sample_rate_;
205  waveform_ = NULL;
206  rng_ = new RngTausworthe();
207 }
208 
209 // ctor
210 void
212 ctor(const float64 & sample_rate, const Buffer & waveform)
213 {
214  if(waveform.getLength() != sample_rate)
215  {
216  M_THROW("Generator::ctor(): waveform.getLength() != sample_rate ("
217  << waveform.getLength()
218  << " != "
219  << sample_rate
220  << ")");
221  ctor(sample_rate);
222  }
223  else
224  {
225  delete waveform_;
226  delete rng_;
227 
228  sample_rate_ = sample_rate;
229  sample_time_ = 1.0 / sample_rate_;
230  waveform_ = new Buffer(waveform);
231  rng_ = new RngTausworthe();
232  }
233 }
234 
235 void
238 {
239  sync_is_master_ = true;
240  slave.sync_is_slave_ = true;
241 
242  if(sync_slaves_.count(&slave) == 0)
243  {
244  sync_slaves_.insert(&slave);
245  }
246 
247  reset();
248 }
249 
250 void
252 buzzInit(const uint32 & max_harmonics)
253 {
254  buzz_max_harmonics_ = max_harmonics;
255  reset();
256 }
257 
258 float64
261  const float64 & frequency,
262  const float64 & n_harmonics,
263  const float64 & phase_offset)
264 {
265  // This function is based on the csound buzz opcode.
266 
267  float64 n = static_cast<int32>(n_harmonics);
268 
269  n = fabs(n);
270  if(n < 1.0) n = 1.0;
271 
272  float64 two_n_plus_1 = 2.0 * n + 1.0;
273  float64 scale = static_cast<float64>(0.5) / n;
274 
275  float64 sign = 1.0;
276  for(int i = 0; i < n; ++i) sign = -sign;
277 
278  float64 phase = fabs(phase_offset / static_cast<float64>(2.0));
279 
280  while(phase >= 0.5) phase -= 0.5;
281 
282  position_ += (phase - last_frequency_) * sample_rate_;
283 
284  last_frequency_ = phase;
285 
286  float64 y;
287 
289 
290  float64 denom = (*waveform_)[static_cast<int32>(position_ + 0.5)] * sign;
291 
292  if(fabs(denom) > 1e-12)
293  {
294  float64 up_phase = position_ * two_n_plus_1;
295  while(up_phase >= sample_rate_) up_phase -= sample_rate_;
296 
297  float64 num = (*waveform_)[static_cast<int32>(up_phase)];
298 
299  y = (num / denom - static_cast<float64>(1.0)) * scale;
300  }
301  else
302  {
303  y = 1.0; // this assumes cosine wave!
304  }
305 
306  position_ += 0.5*frequency;
307 
308  return y;
309 }
310 
311 Buffer
314  const float64 & duration,
315  const float64 & frequency,
316  const float64 & n_harmonics,
317  const float64 & phase_offset)
318 {
319  buzzInit(static_cast<uint32>(n_harmonics));
320 
321  int32 n_samples = static_cast<int32>(duration * sample_rate_);
322 
323  Buffer y(n_samples);
324 
325  for(int i = 0; i < n_samples; ++i)
326  {
327  y << buzz(frequency, n_harmonics, phase_offset+0.5);
328  }
329 
330  return y;
331 }
332 
333 Buffer
336  const float64 & duration,
337  const Buffer & frequencies,
338  const Buffer & n_harmonics,
339  const Buffer & phase_offset)
340 {
341  buzzInit(static_cast<uint32>(n_harmonics.getMax()));
342 
343  int32 n_samples = static_cast<int32>(duration * sample_rate_);
344 
345  Buffer::const_circular_iterator f = frequencies.cbegin();
346  Buffer::const_circular_iterator n = n_harmonics.cbegin();
347  Buffer::const_circular_iterator p = phase_offset.cbegin();
348 
349  Buffer y(n_samples);
350 
351  for(int32 i = 0; i < n_samples; ++i, ++f, ++n, ++p)
352  {
353  y << buzz(*f, *n, *p+0.5);
354  }
355 
356  return y;
357 }
358 
359 void
361 setChorus(const uint32 n_voices, const float64 & amount)
362 {
363  if(n_voices == 0)
364  {
365  chorus_is_on_ = false;
366  return;
367  }
368 
369  chorus_is_on_ = true;
370 
371  chorus_n_voices_ = n_voices;
372 
373  chorus_factor_.clear();
374  chorus_position_.clear();
375 
376  for(uint32 i = 0; i < chorus_n_voices_; ++i)
377  {
378  chorus_factor_.push_back(1.0 + rng_->get(-amount, amount));
379 
380  chorus_position_.push_back(0.0);
381  }
382 
383  reset();
384 }
385 
386 Buffer
388 drawDecay(const float64 & duration, const float64 & alpha) const
389 {
390  if(duration <= 0.0) return Buffer();
391 
392  Buffer t = drawLine(duration, 0.0, 1.0);
393 
394  t *= -alpha;
395 
396  t.exp();
397 
398  return t;
399 }
400 
401 Buffer
404  const float64 & duration,
405  const float64 & mu,
406  const float64 & sigma,
407  const boolean & normalize) const
408 {
409  if(duration <= 0.0) return Buffer();
410 
411  float64 variance = sigma * sigma;
412 
413  Buffer g = drawLine(duration, 0.0, duration);
414 
415  g -= mu;
416 
417  g *= g;
418 
419  g /= (2.0 * variance);
420 
421  g *= -1.0;
422 
423  g.exp();
424 
425  g /= ::sqrt(M_2PI * variance);
426 
427  if(normalize) g.normalize();
428 
429  return g;
430 }
431 
432 Buffer
435  const float64 & duration,
436  const float64 & pass_band_percent) const
437 {
438  M_ASSERT_VALUE(duration, >, 0.0);
439  M_ASSERT_VALUE(pass_band_percent, >, 0.0);
440  M_ASSERT_VALUE(pass_band_percent, <, 1.0);
441 
442  float64 pass_band_time = duration * pass_band_percent;
443 
444  float64 gauss_time = duration - pass_band_time;
445 
446  float64 h_gauss_time = gauss_time / 2.0;
447 
448  // Using a constant sigma ratio so the shape of the fat gaussian doesn't
449  // change given a duration.
450 
451  float64 sigma = 0.275 * h_gauss_time;
452 
453  Buffer y;
454 
455  y << drawGaussian(h_gauss_time, h_gauss_time, sigma)
456  << drawLine(pass_band_time, 1.0, 1.0)
457  << drawGaussian(h_gauss_time, 0.0, sigma);
458 
459  return y;
460 }
461 
462 Buffer
465  const float64 & duration,
466  const float64 & y1,
467  const float64 & y2) const
468 {
469  M_ASSERT_VALUE(duration, >, 0.0);
470 
471  Buffer buffer;
472 
473  float64 n_samples = duration * sample_rate_;
474 
475  float64 slope = (y2 - y1) / n_samples;
476 
477  float64 current_sample = y1;
478 
479  for(uint32 i = 0; i < static_cast<uint32>(n_samples+0.5); ++i)
480  {
481  buffer << current_sample;
482  current_sample += slope;
483  }
484 
485  return buffer;
486 }
487 
488 Buffer
491  const float64 & duration,
492  const float64 & y1,
493  const float64 & x2,
494  const float64 & y2,
495  const float64 & y3) const
496 {
497  M_ASSERT_VALUE(duration, >, 0.0);
498 
499  // In this discustion, amp = amplitude.
500  //
501  // The general equation for a parabola is:
502  //
503  // y = A*x^2 + B*x + C
504  //
505  // This alogorithm uses Gaussian elimination to solve for A,B,C.
506  //
507  // y1 = A * x1^2 + B * x1 + C (1)
508  //
509  // y2 = A * x2^2 + B * x2 + C (2)
510  //
511  // y3 = A * x3^2 + B * x3 + C (3)
512  //
513  // Solve for C using (1), with x1 = 0.0:
514  //
515  // C = y1
516  //
517  // Solve for A using (2) and substituting C:
518  //
519  // A = (y2 - y1 - B * x2) / (x2^2)
520  //
521  // Solve for B using (3) and substituting A,C, I used WolframAlpha, awesome!
522  //
523  // solve y_3 = (y_2 - y_1 - B*x_2) / (x_2 * x_2) * (x_3 * x_3) + B*(x_3) + y_1 for B
524  //
525  // B = [x2 * x2 * ( y3 - y1 ) + x3 * x3 * (y1 - y2)] / [x2 * x3 * (x2 - x3)]
526  //
527  M_ASSERT_VALUE(x2, <, duration);
528 
529  float64 x3 = duration;
530 
531  float64 C = y1;
532 
533  float64 B = ( x2*x2*(y3 - y1) + x3*x3*(y1 - y2) ) / ( x2*x3*(x2 - x3) );
534 
535  float64 A = (y2 - y1 - B*x2) / (x2*x2);
536 
537  Buffer t = drawLine(duration, 0.0, duration);
538 
539  return A*t*t + B*t + C;
540 }
541 
542 Buffer
545  const float64 & duration,
546  const float64 & frequency)
547 {
548  M_ASSERT_VALUE(duration, >, 0.0);
549 
550  t_ = 0.0;
551 
552  Buffer y;
553 
554  uint64 n_samples = static_cast<uint64>(duration * sample_rate_ + 0.5);
555 
556  for(uint64 i = 0; i < n_samples; ++i)
557  {
558  y << drawSine2(frequency, 0.0);
559  }
560 
561  return y;
562 }
563 
564 Buffer
567  const float64 & duration,
568  const Buffer & frequency)
569 {
570  M_ASSERT_VALUE(duration, >, 0.0);
571 
572  t_ = 0.0;
573 
574  Buffer y;
575 
576  uint64 n_samples = static_cast<uint64>(duration * sample_rate_ + 0.5);
577 
578  Buffer::const_circular_iterator f = frequency.cbegin();
579 
580  for(uint64 i = 0; i < n_samples; ++i)
581  {
582  y << drawSine2(*f, 0.0);
583  ++f;
584  }
585 
586  return y;
587 }
588 
589 Buffer
592  const float64 & duration,
593  const float64 & frequency,
594  const float64 & phase)
595 {
596  M_ASSERT_VALUE(duration, >, 0.0);
597 
598  t_ = 0.0;
599 
600  Buffer y;
601 
602  uint64 n_samples = static_cast<uint64>(duration * sample_rate_ + 0.5);
603 
604  for(uint64 i = 0; i < n_samples; ++i)
605  {
606  y << drawSine2(frequency, phase);
607  }
608 
609  return y;
610 }
611 
612 Buffer
615  const float64 & duration,
616  const Buffer & frequency,
617  const Buffer & phase)
618 {
619  M_ASSERT_VALUE(duration, >, 0.0);
620 
621  t_ = 0.0;
622 
623  Buffer y;
624 
625  uint64 n_samples = static_cast<uint64>(duration * sample_rate_ + 0.5);
626 
627  Buffer::const_circular_iterator f = frequency.cbegin();
629 
630  for(uint64 i = 0; i < n_samples; ++i)
631  {
632  y << drawSine2(*f, *p);
633  ++f;
634  ++p;
635  }
636 
637  return y;
638 }
639 
640 Buffer
643  const float64 & duration,
644  const Buffer & frequency,
645  const float64 & phase)
646 {
647  Buffer p(1);
648  p << phase;
649 
650  return drawSine2(duration, frequency, p);
651 }
652 
653 Buffer
656  const float64 & duration,
657  const float64 & frequency,
658  const Buffer & phase)
659 {
660  Buffer f(1);
661  f << frequency;
662 
663  return drawSine2(duration, f, phase);
664 }
665 
666 float64
668 drawSine2(const float64 & frequency, const float64 & phase)
669 {
670  float64 f = 0.0;
671  float64 sample = 0.0;
672 
673  if(chorus_is_on_)
674  {
675  for(uint32 i = 0; i < chorus_n_voices_; ++i)
676  {
677  f = M_2PI * chorus_position_[i] * sample_time_ + M_PI * phase;
678  sample += ::sin(f);
679  chorus_position_[i] += frequency * chorus_factor_[i];
680  }
681  sample /= static_cast<float64>(chorus_n_voices_);
682  }
683  else
684  {
685  sample = ::sin(M_2PI * t_ * sample_time_ + M_PI * phase);
686  t_ += frequency;
687  }
688 
689  return sample;
690 }
691 
692 float64
694 drawSine(const float64 & frequency)
695 {
696  return drawSine2(frequency, 0.0);
697 }
698 
699 
700 Buffer
702 drawWindow(const float64 & duration, WindowType type) const
703 {
704  switch(type)
705  {
706  case BARTLETT: return drawWindowBartlett(duration);
707  case BLACKMAN: return drawWindowBlackman(duration);
708  case BLACKMAN_HARRIS: return drawWindowBlackmanHarris(duration);
709  case GAUSSIAN: return drawGaussian(duration, duration/2.0, 1.0);
710  case GAUSSIAN_05: return drawFatGaussian(duration, 0.05);
711  case GAUSSIAN_10: return drawFatGaussian(duration, 0.10);
712  case GAUSSIAN_15: return drawFatGaussian(duration, 0.15);
713  case GAUSSIAN_20: return drawFatGaussian(duration, 0.20);
714  case GAUSSIAN_25: return drawFatGaussian(duration, 0.25);
715  case GAUSSIAN_30: return drawFatGaussian(duration, 0.30);
716  case GAUSSIAN_33: return drawFatGaussian(duration, 0.3333);
717  case GAUSSIAN_35: return drawFatGaussian(duration, 0.35);
718  case GAUSSIAN_40: return drawFatGaussian(duration, 0.40);
719  case GAUSSIAN_45: return drawFatGaussian(duration, 0.45);
720  case GAUSSIAN_50: return drawFatGaussian(duration, 0.50);
721  case GAUSSIAN_55: return drawFatGaussian(duration, 0.55);
722  case GAUSSIAN_60: return drawFatGaussian(duration, 0.60);
723  case GAUSSIAN_65: return drawFatGaussian(duration, 0.65);
724  case GAUSSIAN_66: return drawFatGaussian(duration, 0.6666);
725  case GAUSSIAN_70: return drawFatGaussian(duration, 0.70);
726  case GAUSSIAN_75: return drawFatGaussian(duration, 0.75);
727  case GAUSSIAN_80: return drawFatGaussian(duration, 0.80);
728  case GAUSSIAN_85: return drawFatGaussian(duration, 0.85);
729  case GAUSSIAN_90: return drawFatGaussian(duration, 0.90);
730  case GAUSSIAN_95: return drawFatGaussian(duration, 0.95);
731  case GAUSSIAN_99: return drawFatGaussian(duration, 0.9999);
732  case HAMMING: return drawWindowHamming(duration);
733  case HANNING: return drawWindowHanning(duration);
734  case KAISER: return drawWindowKaiser(duration);
735  case NUTTALL: return drawWindowNuttall(duration);
736  case PARZEN: return drawWindowParzen(duration);
737  case RECTANGULAR: return drawWindowRectangular(duration);
738  default: M_THROW("Unkown window type " << type);
739  }
740 
741  return drawWindowRectangular(duration);
742 }
743 
744 static
745 void
747  Buffer & win,
748  const float64 & a0,
749  const float64 & a1,
750  const float64 & a2,
751  const float64 & a3)
752 {
753  int32 n = win.getLength();
754  for(int32 i = 0; i < n; ++i)
755  {
756  win[i] *= a0
757  - a1 * ::cos(2.0 * M_PI * i / n)
758  + a2 * ::cos(4.0 * M_PI * i / n)
759  - a3 * ::cos(6.0 * M_PI * i / n);
760  }
761 }
762 
763 Buffer
765 drawWindowBartlett(const float64 & duration) const
766 {
767  Buffer window = drawLine(duration, 1.0, 1.0);
768 
769  int32 n = static_cast<int32>(duration * sample_rate_);
770 
771  float64 n_over_2 = static_cast<float64>(n / 2);
772 
773  for(int32 i = 0; i < n / 2; ++i)
774  {
775  float64 t = static_cast<float64>(i) / n_over_2;
776  window[i] *= t;
777  window[i + n/2] *= 1.0 - t;
778  }
779 
780  return window;
781 }
782 
783 Buffer
785 drawWindowBlackman(const float64 & duration) const
786 {
787  Buffer window = drawLine(duration, 1.0, 1.0);
788 
789  cosinewindow(window, 0.42, 0.50, 0.08, 0.00);
790 
791  return window;
792 }
793 
794 Buffer
796 drawWindowBlackmanHarris(const float64 & duration) const
797 {
798  Buffer window = drawLine(duration, 1.0, 1.0);
799 
800  cosinewindow(window, 0.35875, 0.48829, 0.14128, 0.01168);
801 
802  return window;
803 }
804 
805 
806 Buffer
808 drawWindowHamming(const float64 & duration) const
809 {
810  Buffer window = drawLine(duration, 1.0, 1.0);
811 
812  cosinewindow(window, 0.54, 0.46, 0.00, 0.00);
813 
814  return window;
815 }
816 
817 Buffer
819 drawWindowHanning(const float64 & duration) const
820 {
821  Buffer window = drawLine(duration, 1.0, 1.0);
822 
823  cosinewindow(window, 0.50, 0.50, 0.00, 0.00);
824 
825  return window;
826 }
827 
828 // Computation of the modified Bessel function I_0(x) for any real x.
829 //
830 // The algorithm is based on the article by Abramowitz and Stegun [1]
831 // as denoted in Numerical Recipes 2nd ed. on p. 230 (W.H.Press et al.).
832 //
833 // [1] M.Abramowitz and I.A.Stegun, Handbook of Mathematical Functions,
834 // Applied Mathematics Series vol. 55 (1964), Washington.
835 //
836 float64
837 bessel_i0(const float64 & x)
838 {
839  const float64 p1 = 1.0,
840  p2 = 3.5156229,
841  p3 = 3.0899424,
842  p4 = 1.2067492,
843  p5 = 0.2659732,
844  p6 = 3.60768e-2,
845  p7 = 4.5813e-3;
846 
847  const float64 q1 = 0.39894228,
848  q2 = 1.328592e-2,
849  q3 = 2.25319e-3,
850  q4 = -1.57565e-3,
851  q5 = 9.16281e-3,
852  q6 = -2.057706e-2,
853  q7 = 2.635537e-2,
854  q8 = -1.647633e-2,
855  q9 = 3.92377e-3;
856 
857  float64 ax = ::fabs(x);
858 
859  float64 y = 0.0,
860  result = 0.0;
861 
862  if (ax < 3.75)
863  {
864  y = ::pow(x / 3.75, 2);
865  result = p1+y*(p2+y*(p3+y*(p4+y*(p5+y*(p6+y*p7)))));
866  }
867  else
868  {
869  y = 3.75 / ax;
870  result = (::exp(ax) / ::sqrt(ax))
871  * (q1+y*(q2+y*(q3+y*(q4+y*(q5+y*(q6+y*(q7+y*(q8+y*q9))))))));
872  }
873  return result;
874 }
875 
876 
877 Buffer
879 drawWindowKaiser(const float64 & duration, const float64 & beta) const
880 {
881  Buffer window = drawLine(duration, 0.0, 0.0);
882 
883  int32 n_samples = window.getLength();
884  float64 f_n_samples = float64(n_samples);
885 
886  float64 b = ::fabs(beta);
887 
888  if(b < 1.0)
889  {
890  b = 1.0;
891  }
892 
893  // Calculate window coefficients
894  //
895  // alpha = n_samples / 2
896  //
897  // for n = 0 : n_samples -1
898  //
899  // w[n] = bessel_i0( beta * sqrt(1.0 - [(n - alpha)/alpha]^2)
900  // / bessel_i0(beta)
901  //
902  //
903 
904  float64 alpha = f_n_samples / 2.0;
905 
906  float64 denominator = bessel_i0(b);
907 
908  for(int32 i = 0 ; i < n_samples; ++i)
909  {
910  float64 temp = (float64(i) - alpha) / alpha;
911  temp *= temp;
912 
913  window[i] = bessel_i0( b * ::sqrt(1.0 - temp)) / denominator;
914  }
915 
916  return window;
917 }
918 
919 Buffer
921 drawWindowNuttall(const float64 & duration) const
922 {
923  Buffer window = drawLine(duration, 1.0, 1.0);
924 
925  cosinewindow(window, 0.3635819, 0.4891775, 0.1365995, 0.0106411);
926 
927  return window;
928 }
929 
930 Buffer
932 drawWindowParzen(const float64 & duration) const
933 {
934  Buffer window = drawLine(duration, 1.0, 1.0);
935 
936  int32 n = static_cast<int32>(duration * sample_rate_);
937 
938  int32 N = n -1;
939 
940  float64 Nf = static_cast<float64>(N);
941 
942  for(int32 i = 0; i < N / 4; ++i)
943  {
944  float64 m = 2 * pow(1.0 - (Nf / 2 - i) / (Nf / 2), 3.0);
945  window[i] *= m;
946  window[N - i] *= m;
947  }
948 
949  for(int32 i = N/4; i <= N/2; ++i)
950  {
951  int32 wn = i - N/2;
952  float64 m = 1.0
953  - 6.0 * pow(wn / (Nf/2),2.0)
954  * (1.0 - fabs(static_cast<float64>(wn)) / (Nf/2));
955 
956  window[i] *= m;
957  window[N-i] *= m;
958  }
959 
960  return window;
961 }
962 
963 Buffer
965 drawWindowRectangular(const float64 & duration) const
966 {
967  return drawLine(duration, 1.0, 1.0);
968 }
969 
970 float64
972 generate(const float64 & frequency)
973 {
974  return generate2(frequency, 0.0);
975 }
976 
977 float64
979 generate2(const float64 & frequency, const float64 & phase)
980 {
982 
983  ++sync_count_;
984 
985  if(sync_is_slave_ && !sync_vector_.empty())
986  {
987  uint32 sync_count = sync_vector_.front();
988 
989  if(sync_count_ == sync_count)
990  {
991  sync_vector_.erase(sync_vector_.begin());
992  position_ = 0;
993  sync_pos_ = 0;
994  }
995  }
996 
997  // Move with phase
998  float64 ph = (phase * sample_rate_ / 2.0);
999  float64 position2 = position_ + ph + 0.5;
1000 
1001  // Range checks
1002 
1003  while(position2 >= sample_rate_)
1004  {
1005  position2 -= sample_rate_;
1006  }
1007 
1008  while(position2 < 0.0)
1009  {
1010  position2 += sample_rate_;
1011  }
1012 
1013  float64 sample = 0.0;
1014 
1015  if(chorus_is_on_)
1016  {
1017  for(uint32 i = 0; i < chorus_n_voices_; ++i)
1018  {
1019  float64 pos = chorus_position_[i]
1020  + chorus_factor_[i] * frequency
1021  + ph
1022  + 0.5;
1023 
1024  // Range check
1025  while(pos >= sample_rate_) pos -= sample_rate_;
1026  while(pos < 0) pos += sample_rate_;
1027 
1028  sample += (*waveform_)[static_cast<uint32>(pos)];
1029 
1030  chorus_position_[i] += frequency * chorus_factor_[i];
1031  }
1032 
1033  sample /= static_cast<float64>(chorus_n_voices_);
1034  }
1035  else
1036  {
1037  sample = (*waveform_)[static_cast<uint32>(position2)];
1038  }
1039 
1040  position_ += frequency;
1041  sync_pos_ += frequency;
1042 
1043  // limit
1044  if(sync_pos_ > sample_rate_)
1045  {
1047 
1048  if(sync_is_master_)
1049  {
1050  std::set<Generator *>::iterator itor = sync_slaves_.begin();
1051 
1052  while(itor != sync_slaves_.end())
1053  {
1054  (*itor)->sync_vector_.push_back(sync_count_);
1055  ++itor;
1056  }
1057  }
1058  }
1059 
1060  return sample;
1061 }
1062 
1063 Buffer
1066  const float64 & duration,
1067  const float64 & frequency)
1068 {
1069  M_ASSERT_VALUE(duration, >, 0.0);
1070 
1071  if(!is_realtime_) reset();
1072 
1073  Buffer buffer;
1074 
1075  uint64 n_samples = static_cast<uint64>(std::ceil(duration * sample_rate_));
1076 
1077  for(uint64 i = 0; i < n_samples; ++i)
1078  {
1079  buffer << generate(frequency);
1080  }
1081 
1082  return buffer;
1083 }
1084 
1085 Buffer
1088  const float64 & duration,
1089  const float64 & frequency,
1090  const float64 & phase)
1091 {
1092  M_ASSERT_VALUE(duration, >, 0.0);
1093 
1094  if(!is_realtime_) reset();
1095 
1096  Buffer buffer;
1097 
1098  uint64 n_samples = static_cast<uint64>(std::ceil(duration * sample_rate_));
1099 
1100  for(uint64 i = 0; i < n_samples; ++i)
1101  {
1102  buffer << generate2(frequency, phase);
1103  }
1104 
1105  return buffer;
1106 }
1107 
1108 Buffer
1111  const float64 & duration,
1112  const Buffer & frequencies)
1113 {
1114  M_ASSERT_VALUE(duration, >, 0.0);
1115 
1116  if(!is_realtime_) reset();
1117 
1118  uint32 n_samples = static_cast<uint32>(std::ceil(duration * sample_rate_));
1119 
1120  Buffer y(n_samples);
1121 
1122  Buffer::const_circular_iterator freq = frequencies.cbegin();
1123 
1124  for(uint32 i = 0; i < n_samples; ++i, ++freq)
1125  {
1126  y << generate(*freq);
1127  }
1128 
1129  return y;
1130 }
1131 
1132 Buffer
1135  const float64 & duration,
1136  const float64 & frequency,
1137  const Buffer & phase)
1138 {
1139  M_ASSERT_VALUE(duration, >, 0.0);
1140 
1141  if(!is_realtime_) reset();
1142 
1143  uint32 n_samples = static_cast<uint32>(std::ceil(duration * sample_rate_));
1144 
1145  Buffer y(n_samples);
1146 
1148 
1149  for(uint32 i = 0; i < n_samples; ++i, ++p)
1150  {
1151  y << generate2(frequency,*p);
1152  }
1153 
1154  return y;
1155 }
1156 
1157 Buffer
1160  const float64 & duration,
1161  const Buffer & frequencies,
1162  const float64 & phase)
1163 {
1164  M_ASSERT_VALUE(duration, >, 0.0);
1165 
1166  if(!is_realtime_) reset();
1167 
1168  uint32 n_samples = static_cast<uint32>(std::ceil(duration * sample_rate_));
1169 
1170  Buffer y(n_samples);
1171 
1172  Buffer::const_circular_iterator f = frequencies.cbegin();
1173 
1174  for(uint32 i = 0; i < n_samples; ++i, ++f)
1175  {
1176  y << generate2(*f, phase);
1177  }
1178 
1179  return y;
1180 }
1181 
1182 Buffer
1185  const float64 & duration,
1186  const Buffer & frequencies,
1187  const Buffer & phase)
1188 {
1189  M_ASSERT_VALUE(duration, >, 0.0);
1190 
1191  if(!is_realtime_) reset();
1192 
1193  uint32 n_samples = static_cast<uint32>(std::ceil(duration * sample_rate_));
1194 
1195  Buffer y(n_samples);
1196 
1197  Buffer::const_circular_iterator f = frequencies.cbegin();
1199 
1200  for(uint32 i = 0; i < n_samples; ++i, ++f, ++p)
1201  {
1202  y << generate2(*f,*p);
1203  }
1204 
1205  return y;
1206 }
1207 
1208 Generator &
1210 operator=(const Generator & rhs)
1211 {
1212  // If this is the same object, return it.
1213  if(this == &rhs)
1214  {
1215  return *this;
1216  }
1217 
1219  position_ = rhs.position_;
1220  sample_rate_ = rhs.sample_rate_;
1221  sample_time_ = rhs.sample_time_;
1222  t_ = rhs.t_;
1223 
1224  if(waveform_ != NULL && rhs.waveform_ != NULL)
1225  {
1226  *waveform_ = *rhs.waveform_;
1227  }
1228  else if(waveform_ == NULL && rhs.waveform_ != NULL)
1229  {
1230  waveform_ = new Buffer(*rhs.waveform_);
1231  }
1232  else if(waveform_ != NULL && rhs.waveform_ == NULL)
1233  {
1234  delete waveform_;
1235  waveform_ = NULL;
1236  }
1237 
1238  *rng_ = *rhs.rng_;
1239 
1242 
1247 
1250  sync_count_ = rhs.sync_count_;
1251  sync_vector_ = rhs.sync_vector_;
1252  sync_slaves_ = rhs.sync_slaves_;
1253 
1254  return *this;
1255 }
1256 
1257 void
1260 {
1261  slave.sync_is_slave_ = false;
1262 
1263  if(sync_slaves_.count(&slave) == 0) return;
1264 
1265  sync_slaves_.erase(&slave);
1266 
1267  reset();
1268 }
1269 
1270 void
1273 {
1274  last_frequency_ = -1.0;
1275  position_ = 0.0;
1276  sync_count_ = 0;
1277  sync_pos_ = 0.0;
1278  t_ = 0.0;
1279 
1281 
1282  for(uint32 i = 0; i < buzz_max_harmonics_; ++i)
1283  {
1284  buzz_position_[i] = 0.0;
1285  }
1286 
1287  for(uint32 i = 0; i < chorus_n_voices_; ++i)
1288  {
1289  chorus_position_[i] = 0.0;
1290  }
1291 
1292  std::set<Generator *>::iterator itor = sync_slaves_.begin();
1293 
1294  while(itor != sync_slaves_.end())
1295  {
1296  (*itor)->sync_vector_.clear();
1297  ++itor;
1298  }
1299 }
1300 
1301 void
1303 setSeed(const uint32 seed)
1304 {
1305  rng_->setSeed(seed);
1306 }
1307 
1308 Buffer
1310 silence(const float64 & duration) const
1311 {
1312  return drawLine(duration,0.0,0.0);
1313 }
1314 
1315 float64
1317 tell() const
1318 {
1319  return position_ / sample_rate_;
1320 }
1321 
1322 
1323 Buffer
1325 whiteNoise(const float64 & duration) const
1326 {
1327  M_ASSERT_VALUE(duration, >, 0.0);
1328 
1329  Buffer buffer;
1330 
1331  uint64 n_samples = static_cast<uint64>(std::ceil(duration * sample_rate_));
1332 
1333  for(uint64 i = 0; i < n_samples; ++i)
1334  {
1335  buffer << rng_->get(-1.0f,1.0f);
1336  }
1337 
1338  return buffer;
1339 }
1340 
1341 Buffer
1344  const float64 & duration,
1345  const float64 & mu,
1346  const float64 & sigma) const
1347 {
1348  Buffer buffer;
1349 
1350  uint32 n_samples = static_cast<uint32>(std::ceil(duration * sample_rate_));
1351 
1352  M_ASSERT_VALUE(n_samples, >, 0);
1353 
1354  // The polar form of the Box-Muller transformation.
1355 
1356  uint32 i = 0;
1357  while(true)
1358  {
1359  float64 f = 0.0;
1360  float64 x1 = 0.0;
1361  float64 x2 = 0.0;
1362  float64 r2 = 0.0;
1363 
1364  while(r2 == 0.0 || r2 >= 1.0)
1365  {
1366  x1 = rng_->get(-1.0f, 1.0f);
1367  x2 = rng_->get(-1.0f, 1.0f);
1368  r2 = x1 * x1 + x2 * x2;
1369  }
1370 
1371  f = ::sqrt(-2.0 * ::log(r2) / r2);
1372 
1373  buffer << mu + sigma * f * x1;
1374 
1375  ++i;
1376 
1377  if(i >= n_samples)
1378  {
1379  break;
1380  }
1381 
1382  buffer << mu + sigma * f * x2;
1383 
1384  ++i;
1385 
1386  if(i >= n_samples)
1387  {
1388  break;
1389  }
1390  }
1391 
1392  return buffer;
1393 }
1394 
1395 Buffer
1397 tanh(const float64 & duration) const
1398 {
1399  M_ASSERT_VALUE(duration, >, 0.0);
1400 
1401  Buffer buffer;
1402 
1403  uint64 n_samples = static_cast<uint64>(std::ceil(duration * sample_rate_));
1404 
1405  float64 step = (2.0 * M_PI) / n_samples;
1406 
1407  float64 x = -1.0 * M_PI;
1408 
1409  for(uint64 i = 0; i < n_samples; ++i)
1410  {
1411  buffer << std::tanh(x);
1412  x += step;
1413  }
1414 
1415  return buffer;
1416 }
float64 sample_rate_
Used to determine when to create a sync sample.
Definition: Generator.h:616
boolean chorus_is_on_
Definition: Generator.h:628
unsigned int uint32
Definition: Nsound.h:153
RandomNumberGenerator * rng_
The waveform to ossicialate.
Definition: Generator.h:621
Buffer drawSine2(const float64 &duration, const float64 &frequency, const float64 &phase)
This method draws a static sine wave.
Definition: Generator.cc:591
float64 tell() const
Returns the current position pointer, values are between 0.0 to 1.0.
Definition: Generator.cc:1317
#define M_ASSERT_VALUE(a, op, value)
Definition: Macros.h:76
Buffer drawWindowKaiser(const float64 &duration, const float64 &beta=5.0) const
Draws a Kaiser window.
Definition: Generator.cc:879
Buffer drawWindowRectangular(const float64 &duration) const
Draws a rectangular window.
Definition: Generator.cc:965
Buffer drawFatGaussian(const float64 &duration, const float64 &pass_band_percent=0.01) const
This method draws a standard Gaussian curve over duration seconds, with a specified pass band...
Definition: Generator.cc:434
Nsound::Generator & operator=(const Nsound::Generator &rhs)
Assignment operator.
Definition: Generator.cc:1210
Buffer drawWindowBlackman(const float64 &duration) const
Draws a Blackman window.
Definition: Generator.cc:785
virtual void ctor(const float64 &sample_rate)
DOXME.
Definition: Generator.cc:201
std::vector< float64 > chorus_position_
Definition: Generator.h:630
#define M_PI
Definition: Nsound.h:121
uint32 buzz_max_harmonics_
The random number generator.
Definition: Generator.h:624
Generator()
DOXME.
Definition: Generator.cc:52
std::vector< float64 > buzz_position_
Definition: Generator.h:625
Buffer tanh(const float64 &duration) const
This method draws the tanh function accross duration samples.
Definition: Generator.cc:1397
#define M_CHECK_PTR(ptr)
Definition: Macros.h:64
std::set< Generator * > sync_slaves_
Stores sample counts when synced.
Definition: Generator.h:638
Buffer drawWindowHamming(const float64 &duration) const
Draws a Hamming window.
Definition: Generator.cc:808
Buffer drawGaussian(const float64 &duration, const float64 &mu, const float64 &sigma, const boolean &normalize=true) const
This method draws a Gaussian curve over duration seconds.
Definition: Generator.cc:403
float64 position_
Used for phase offset adjustment.
Definition: Generator.h:614
Buffer drawWindow(const float64 &duration, WindowType type) const
Draws a window of the specified type.
Definition: Generator.cc:702
Buffer drawWindowBartlett(const float64 &duration) const
Draws a Bartlett window.
Definition: Generator.cc:765
virtual void setSeed(uint32 seed)=0
Set the seed to use.
double float64
Definition: Nsound.h:146
circular_iterator cbegin()
Retruns the itreator at the start of the Buffer.
Definition: Buffer.h:318
float64 sync_pos_
The number of samples into the wavefrom.
Definition: Generator.h:615
Buffer drawSine(const float64 &duration, const float64 &frequency)
This method draws a static sine wave.
Definition: Generator.cc:544
virtual uint32 get()=0
Get a random number.
Buffer drawWindowHanning(const float64 &duration) const
Draws a Hanning window.
Definition: Generator.cc:819
Buffer drawParabola(const float64 &duration, const float64 &y1, const float64 &x2, const float64 &y2, const float64 &y3) const
This method draws a parabola between three points, intersecting the middle point. ...
Definition: Generator.cc:490
uint32 getLength() const
Returns the number of samples in the Buffer.
Definition: Buffer.h:587
void addSlaveSync(Generator &slave)
Adds a generator as a slave to this instance for syncing.
Definition: Generator.cc:237
Buffer silence(const float64 &duration) const
This method generates silence.
Definition: Generator.cc:1310
float64 t_
The time step between samples in seconds.
Definition: Generator.h:618
boolean sync_is_slave_
Indicates if this generator is the master.
Definition: Generator.h:635
void buzzInit(const uint32 &max_harmonics)
Initaializes Buzz settings for real-time calls.
Definition: Generator.cc:252
boolean sync_is_master_
Definition: Generator.h:634
Buffer drawWindowParzen(const float64 &duration) const
Draws a Parzen window.
Definition: Generator.cc:932
virtual float64 generate(const float64 &frequency)
This is a real-time method for the wavetable oscillator.
Definition: Generator.cc:972
Buffer drawDecay(const float64 &duration, const float64 &alpha=2.0 *M_PI) const
This method draws an exponential curve that decays from 1.0 to 0.0 over the duration.
Definition: Generator.cc:388
void setChorus(const uint32 n_voices, const float64 &sigma=0.02)
Chorus or Unison.
Definition: Generator.cc:361
Buffer * waveform_
The current time (for real time draw functions.)
Definition: Generator.h:619
float64 buzz(const float64 &frequency, const float64 &n_harmonics, const float64 &delay)
Returns sample from a set of harmonics. Based on the Csound buzz opcode.
Definition: Generator.cc:260
unsigned long long uint64
Definition: Nsound.h:154
void normalize()
Multiplies the Buffer by a constant gain so the peak sample has magnitude 1.0.
Definition: Buffer.cc:1064
float64 last_frequency_
Definition: Generator.h:613
float64 bessel_i0(const float64 &x)
Definition: Generator.cc:837
std::vector< float64 > chorus_factor_
Definition: Generator.h:631
#define M_THROW(message)
Definition: Macros.h:108
virtual ~Generator()
Deletes the baseclass part of the object.
Definition: Generator.cc:192
virtual void reset()
Resets the position pointer back to the begging of the waveform.
Definition: Generator.cc:1272
Buffer gaussianNoise(const float64 &duration, const float64 &mu, const float64 &sigma) const
This method generates noise from a Gaussian distribution.
Definition: Generator.cc:1343
void exp()
Each sample in the Buffer becomes the power e^x.
Definition: Buffer.cc:510
float64 sample_time_
The number of samples per second to generate.
Definition: Generator.h:617
Buffer drawWindowBlackmanHarris(const float64 &duration) const
Draws a Blackman-Harris window.
Definition: Generator.cc:796
A Buffer for storing audio samples.
Definition: Buffer.h:60
std::vector< uint32 > sync_vector_
Indicates the number of samples since reset.
Definition: Generator.h:637
Buffer whiteNoise(const float64 &duration) const
This method generates noise from a uniform distribution.
Definition: Generator.cc:1325
signed int int32
Definition: Nsound.h:142
#define M_2PI
Definition: Generator.cc:46
uint32 sync_count_
Indicates if this generator is a slave.
Definition: Generator.h:636
uint32 chorus_n_voices_
Definition: Generator.h:629
Buffer drawLine(const float64 &duration, const float64 &amplitude_start, const float64 &amplitude_finish) const
This method draws a linear line beteween 2 points.
Definition: Generator.cc:464
float64 getMax() const
Returns the maximum sample value in the Buffer.
Definition: Buffer.cc:951
Buffer drawWindowNuttall(const float64 &duration) const
Draws a Nuttall window.
Definition: Generator.cc:921
void setSeed(const uint32 seed)
Sets the seed for the Generator's random number generator (rng).
Definition: Generator.cc:1303
WindowType
Definition: WindowType.h:39
A class the provides draw utilities and a wavetable oscillator.
Definition: Generator.h:50
static void cosinewindow(Buffer &win, const float64 &a0, const float64 &a1, const float64 &a2, const float64 &a3)
Definition: Generator.cc:746
void removeSlaveSync(Generator &slave)
Removes the generator from the sync list.
Definition: Generator.cc:1259
virtual float64 generate2(const float64 &frequency, const float64 &phase)
This is a real-time method for the wavetable oscillator.
Definition: Generator.cc:979