1 /*
2  * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/>
3  *           (C) 2020 Stefano Tronci <stefano.tronci@protonmail.com>
4  *
5  * This file is part of lsp-plugins
6  * Created on: 20 Mar 2017
7  *
8  * lsp-plugins is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * any later version.
12  *
13  * lsp-plugins is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <dsp/dsp.h>
23 #include <core/debug.h>
24 #include <core/util/Oscillator.h>
25 
26 #define PROCESS_BUF_LIMIT_SIZE  (12 * 1024) // Multiple of 3, 4 and 8
27 
28 namespace lsp
29 {
Oscillator()30     Oscillator::Oscillator()
31     {
32         enFunction                  = FG_SINE;
33         fAmplitude                  = 1.0f;
34         fFrequency                  = 0.0f;
35         fDCOffset                   = 0.0f;
36         enDCReference               = DC_WAVEDC;
37         fReferencedDC               = 0.0f;
38         fInitPhase                  = 0.0f;
39 
40         nSampleRate                 = -1;
41         nPhaseAcc                   = 0;
42         nPhaseAccBits               = sizeof(phacc_t) * 8;
43         nPhaseAccMaxBits            = sizeof(phacc_t) * 8;
44         nPhaseAccMask               = 0;
45         fAcc2Phase                  = 0.0f;
46 
47         nFreqCtrlWord               = 0;
48         nInitPhaseWord              = 0;
49 
50         sSquaredSinusoid.bInvert    = false;
51         sSquaredSinusoid.fAmplitude = 0.0f;
52         sSquaredSinusoid.fWaveDC    = 0.0f;
53 
54         sRectangular.fDutyRatio     = 0.5f;
55         sRectangular.nDutyWord      = 0;
56         sRectangular.fWaveDC        = 0.0f;
57         sRectangular.fBLPeakAtten   = 0.0f;
58 
59         sSawtooth.fWidth            = 1.0f;
60         sSawtooth.nWidthWord        = 0;
61         sSawtooth.fCoeffs[0]        = 0.0f;
62         sSawtooth.fCoeffs[1]        = 0.0f;
63         sSawtooth.fCoeffs[2]        = 0.0f;
64         sSawtooth.fCoeffs[3]        = 0.0f;
65         sSawtooth.fWaveDC           = 0.0f;
66         sSawtooth.fBLPeakAtten      = 0.0f;
67 
68         sTrapezoid.fRaiseRatio      = 0.25f;
69         sTrapezoid.fFallRatio       = 0.25f;
70         sTrapezoid.nPoints[0]       = 0;
71         sTrapezoid.nPoints[1]       = 0;
72         sTrapezoid.nPoints[2]       = 0;
73         sTrapezoid.nPoints[3]       = 0;
74         sTrapezoid.fCoeffs[0]       = 0.0f;
75         sTrapezoid.fCoeffs[1]       = 0.0f;
76         sTrapezoid.fCoeffs[2]       = 0.0f;
77         sTrapezoid.fCoeffs[3]       = 0.0f;
78         sTrapezoid.fWaveDC          = 0.0f;
79         sTrapezoid.fBLPeakAtten     = 0.0f;
80 
81         sPulse.fPosWidthRatio       = 0.0f;
82         sPulse.fNegWidthRatio       = 0.0f;
83         sPulse.nTrainPoints[0]      = 0;
84         sPulse.nTrainPoints[1]      = 0;
85         sPulse.nTrainPoints[2]      = 0;
86         sPulse.fWaveDC              = 0.0f;
87         sPulse.fBLPeakAtten         = 0.0f;
88 
89         sParabolic.bInvert          = false;
90         sParabolic.fAmplitude       = 1.0f;
91         sParabolic.fWidth           = 0.0f;
92         sParabolic.nWidthWord       = 0;
93         sParabolic.fWaveDC          = 0.0f;
94         sParabolic.fBLPeakAtten     = 0.0f;
95 
96         nOversampling               = 0;
97         enOverMode                  = OM_NONE;
98         vProcessBuffer              = NULL;
99         vSynthBuffer                = NULL;
100         pData                       = NULL;
101 
102         nFreqCtrlWord_Over          = 0;
103 
104         bSync                       = true;
105     }
106 
~Oscillator()107     Oscillator::~Oscillator()
108     {
109     }
110 
init()111     bool Oscillator::init()
112     {
113         size_t samples      = PROCESS_BUF_LIMIT_SIZE + PROCESS_BUF_LIMIT_SIZE;
114         pData               = new uint8_t[samples * sizeof(float) + DEFAULT_ALIGN];
115 
116         uint8_t *ptr        = ALIGN_PTR(pData, DEFAULT_ALIGN);
117         vProcessBuffer      = reinterpret_cast<float *>(ptr);
118         ptr                += PROCESS_BUF_LIMIT_SIZE * sizeof(float);
119         vSynthBuffer        = reinterpret_cast<float *>(ptr);
120         ptr                += PROCESS_BUF_LIMIT_SIZE * sizeof(float);
121 
122         lsp_assert(ptr <= &pData[samples * sizeof(float) + DEFAULT_ALIGN]);
123 
124         bool sOverInitialized           = sOver.init();
125         bool sOverGetPeriodsInitialized = sOverGetPeriods.init();
126 
127         return sOverInitialized && sOverGetPeriodsInitialized;
128     }
129 
destroy()130     void Oscillator::destroy()
131     {
132         sOver.destroy();
133         sOverGetPeriods.destroy();
134 
135         if (pData != NULL)
136         {
137             delete [] pData;
138             pData = NULL;
139         }
140         vProcessBuffer = NULL;
141         vSynthBuffer   = NULL;
142     }
143 
update_settings()144     void Oscillator::update_settings()
145     {
146         if (!bSync)
147             return;
148 
149         if (nPhaseAccBits == nPhaseAccMaxBits)
150             nPhaseAccMask    = phacc_t(-1);
151         else
152             nPhaseAccMask    = (phacc_t(1) << nPhaseAccBits) - phacc_t(1);
153 
154         fAcc2Phase       = 2.0 * M_PI * (1.0 / (nPhaseAccMask + 1.0));
155         nFreqCtrlWord    = ((nPhaseAccMask + 1.0) * fFrequency) / nSampleRate;
156 
157         nPhaseAcc        = (nPhaseAcc - nInitPhaseWord) & nPhaseAccMask;
158         nInitPhaseWord   = (nPhaseAccMask + 1.0) * 0.5 * M_1_PI * (fInitPhase - 2.0 * M_PI * floor(fInitPhase * 0.5 * M_1_PI));
159         nPhaseAcc        = (nPhaseAcc + nInitPhaseWord) & nPhaseAccMask;
160 
161         switch (enFunction)
162         {
163             case FG_SINE:
164             case FG_COSINE:
165             case FG_MAX:
166                 fReferencedDC = fDCOffset;
167                 break;
168             case FG_SQUARED_SINE:
169             case FG_SQUARED_COSINE:
170             {
171                 if (sSquaredSinusoid.bInvert)
172                     sSquaredSinusoid.fAmplitude = -fAmplitude;
173                 else
174                     sSquaredSinusoid.fAmplitude = fAmplitude;
175 
176                 sSquaredSinusoid.fWaveDC = 0.5f * sSquaredSinusoid.fAmplitude;
177 
178                 switch (enDCReference)
179                 {
180                     case DC_ZERO:
181                         fReferencedDC = fDCOffset - sSquaredSinusoid.fWaveDC;
182                         break;
183                     case DC_WAVEDC:
184                     default:
185                         fReferencedDC = fDCOffset;
186                         break;
187                 }
188             }
189             break;
190 
191             case FG_RECTANGULAR:
192             case FG_BL_RECTANGULAR:
193             {
194                 if (sRectangular.fDutyRatio == 1.0f)
195                     sRectangular.nDutyWord  = nPhaseAccMask;
196                 else
197                     sRectangular.nDutyWord  = sRectangular.fDutyRatio * (nPhaseAccMask + 1.0f);
198 
199                 sRectangular.fWaveDC        = fAmplitude * (2.0f * sRectangular.fDutyRatio - 1.0f);
200 
201                 switch (enDCReference)
202                 {
203                     case DC_ZERO:
204                         fReferencedDC = fDCOffset - sRectangular.fWaveDC;
205                         break;
206                     case DC_WAVEDC:
207                     default:
208                         fReferencedDC = fDCOffset;
209                         break;
210                 }
211 
212                 sRectangular.fBLPeakAtten = 0.6f;
213             }
214             break;
215 
216             case FG_SAWTOOTH:
217             case FG_BL_SAWTOOTH:
218             {
219                 if (sSawtooth.fWidth == 1.0f) // Prevent overflow
220                     sSawtooth.nWidthWord = nPhaseAccMask;
221                 else
222                     sSawtooth.nWidthWord       = sSawtooth.fWidth * (nPhaseAccMask + 1.0f);
223 
224                 sSawtooth.fCoeffs[0] = 2.0f * fAmplitude / sSawtooth.nWidthWord;
225                 sSawtooth.fCoeffs[1] = -fAmplitude;
226                 sSawtooth.fCoeffs[2] = (-2.0f * fAmplitude) / (nPhaseAccMask + 1.0f - sSawtooth.nWidthWord);
227                 sSawtooth.fCoeffs[3] = fAmplitude * (nPhaseAccMask + 1.0f + sSawtooth.nWidthWord) / (nPhaseAccMask + 1.0f - sSawtooth.nWidthWord);
228                 sSawtooth.fWaveDC    = 0.0f;
229 
230                 switch (enDCReference)
231                 {
232                     case DC_ZERO:
233                         fReferencedDC = fDCOffset; //sSawtooth.fWaveDC == 0.0f
234                         break;
235                     case DC_WAVEDC:
236                     default:
237                         fReferencedDC = fDCOffset;
238                         break;
239                 }
240 
241                 // Gibbs starts being noticeable at 6% or 94% with, so we drop
242                 // linearly the amplitude.
243                 if (sSawtooth.fWidth > 0.60f)
244                     sSawtooth.fBLPeakAtten = 0.64f / 0.4f -sSawtooth.fWidth;
245                 else if (sSawtooth.fWidth < 0.40f)
246                     sSawtooth.fBLPeakAtten =  sSawtooth.fWidth + 0.6f;
247                 else
248                     sSawtooth.fBLPeakAtten = 1.0f;
249             }
250             break;
251 
252             case FG_TRAPEZOID:
253             case FG_BL_TRAPEZOID:
254             {
255                 sTrapezoid.nPoints[0]     = sTrapezoid.fRaiseRatio * 0.5f * (nPhaseAccMask + 1.0f);
256                 sTrapezoid.nPoints[1]     = (1.0f - sTrapezoid.fFallRatio) * 0.5f * (nPhaseAccMask + 1.0f);
257 
258                 if (sTrapezoid.fFallRatio < 1.0f) // Prevent overflow
259                     sTrapezoid.nPoints[2]     = (1.0f + sTrapezoid.fFallRatio) * 0.5f * (nPhaseAccMask + 1.0f);
260                 else
261                     sTrapezoid.nPoints[2]       = nPhaseAccMask;
262 
263                 if (sTrapezoid.fRaiseRatio > 0.0f) // Prevent overflow
264                     sTrapezoid.nPoints[3] = (2.0f - sTrapezoid.fRaiseRatio) * 0.5f * (nPhaseAccMask + 1.0f);
265                 else
266                     sTrapezoid.nPoints[3] = nPhaseAccMask;
267 
268                 sTrapezoid.fCoeffs[0]     = fAmplitude / sTrapezoid.nPoints[0];
269                 sTrapezoid.fCoeffs[1]     = -2.0f * fAmplitude / (sTrapezoid.nPoints[2] - sTrapezoid.nPoints[1]);
270                 sTrapezoid.fCoeffs[2]     = fAmplitude / sTrapezoid.fFallRatio;
271                 sTrapezoid.fCoeffs[3]     = -2.0f * fAmplitude / sTrapezoid.fRaiseRatio;
272                 sTrapezoid.fWaveDC        = 0.0f;
273 
274                 switch (enDCReference)
275                 {
276                     case DC_ZERO:
277                         fReferencedDC = fDCOffset; //sTrapezoid.fWaveDC == 0.0f
278                         break;
279                     case DC_WAVEDC:
280                     default:
281                         fReferencedDC = fDCOffset;
282                         break;
283                 }
284 
285                 // Gibbs starts being noticeable at 6% or 94% with, so we drop
286                 // linearly the amplitude.
287                 float minRatio = (sTrapezoid.fRaiseRatio < sTrapezoid.fFallRatio) ? sTrapezoid.fRaiseRatio : sTrapezoid.fFallRatio;
288 
289                 if (minRatio < 0.40f)
290                     sTrapezoid.fBLPeakAtten = minRatio + 0.6f;
291                 else
292                     sTrapezoid.fBLPeakAtten = 1.0f;
293             }
294             break;
295 
296             case FG_PULSETRAIN:
297             case FG_BL_PULSETRAIN:
298             {
299                 sPulse.nTrainPoints[0]    = sPulse.fPosWidthRatio * 0.5f * (nPhaseAccMask + 1.0f);
300                 sPulse.nTrainPoints[1]    = 0.5f * (nPhaseAccMask + 1.0f);
301                 if (sPulse.fNegWidthRatio == 1.0f) // Prevent overflow
302                     sPulse.nTrainPoints[2]  = nPhaseAccMask;
303                 else
304                     sPulse.nTrainPoints[2]  = (1.0f + sPulse.fNegWidthRatio) * 0.5f * (nPhaseAccMask + 1.0f);
305 
306                 sPulse.fWaveDC              = 0.5f * fAmplitude * (sPulse.fPosWidthRatio - sPulse.fNegWidthRatio);
307 
308                 switch (enDCReference)
309                 {
310                     case DC_ZERO:
311                         fReferencedDC = fDCOffset - sPulse.fWaveDC;
312                         break;
313                     case DC_WAVEDC:
314                     default:
315                         fReferencedDC = fDCOffset;
316                         break;
317                 }
318 
319                 float maxRatio = (sPulse.fNegWidthRatio > sPulse.fPosWidthRatio) ? sPulse.fNegWidthRatio : sPulse.fPosWidthRatio;
320 
321                 if (maxRatio > 0.5f)
322                     sPulse.fBLPeakAtten = 0.6f;
323                 else
324                     sPulse.fBLPeakAtten = M_SQRT1_2;
325             }
326             break;
327 
328             case FG_PARABOLIC:
329             case FG_BL_PARABOLIC:
330             {
331                 if (sParabolic.bInvert)
332                     sParabolic.fAmplitude = -fAmplitude;
333                 else
334                     sParabolic.fAmplitude = fAmplitude;
335 
336                 if (sParabolic.fWidth == 1) // Prevent overflow
337                     sParabolic.nWidthWord       = nPhaseAccMask;
338                 else
339                     sParabolic.nWidthWord       = sParabolic.fWidth * (nPhaseAccMask + 1.0f);
340 
341                 sParabolic.fWaveDC              = 2.0f * sParabolic.fAmplitude * sParabolic.fWidth / 3.0f;
342 
343                 switch (enDCReference)
344                 {
345                     case DC_ZERO:
346                         fReferencedDC = fDCOffset - sParabolic.fWaveDC;
347                         break;
348                     case DC_WAVEDC:
349                     default:
350                         fReferencedDC = fDCOffset;
351                         break;
352                 }
353 
354                 sParabolic.fBLPeakAtten = 1.0f;
355             }
356             break;
357 
358         }
359 
360         // Oversamplers stuff:
361         sOver.set_sample_rate(nSampleRate);
362         sOver.set_mode(enOverMode);
363         if (sOver.modified())
364             sOver.update_settings();
365 
366         sOverGetPeriods.set_sample_rate(nSampleRate);
367         sOverGetPeriods.set_mode(enOverMode);
368         if (sOverGetPeriods.modified())
369             sOverGetPeriods.update_settings();
370 
371         nOversampling       = sOver.get_oversampling();
372         nFreqCtrlWord_Over  = nFreqCtrlWord / nOversampling;
373 
374         bSync               = false;
375     }
376 
do_process(Oversampler * os,float * dst,size_t count)377     void Oscillator::do_process(Oversampler *os, float *dst, size_t count)
378     {
379         // Prevent overwrite of vProcessBuffer when the size of processed data is smaller
380         // or equal the size of the original data (before oversampling) by imposing
381         // dst != vProcessBuffer
382         if (dst == vProcessBuffer)
383             return;
384 
385         switch (enFunction)
386         {
387             case FG_SINE:
388                 while (count--)
389                 {
390                     *(dst++)    = fAmplitude * sin(fAcc2Phase * nPhaseAcc) + fReferencedDC;
391                     nPhaseAcc   = (nPhaseAcc + nFreqCtrlWord) & nPhaseAccMask;
392                 }
393                 break;
394 
395             case FG_COSINE:
396                 while (count--)
397                 {
398                     *(dst++)    = fAmplitude * cos(fAcc2Phase * nPhaseAcc) + fReferencedDC;
399                     nPhaseAcc   = (nPhaseAcc + nFreqCtrlWord) & nPhaseAccMask;
400                 }
401                 break;
402 
403             case FG_SQUARED_SINE:
404                 while (count--)
405                 {
406                     // We put a 0.5 as simple squaring sinusoids will double the
407                     // fundamental frequency with respect fFrequency.
408                     float x     = sin(0.5f * fAcc2Phase * nPhaseAcc);
409                     *(dst++)    = sSquaredSinusoid.fAmplitude * x * x + fReferencedDC;
410                     nPhaseAcc   = (nPhaseAcc + nFreqCtrlWord) & nPhaseAccMask;
411                 }
412                 break;
413 
414             case FG_SQUARED_COSINE:
415                 while (count--)
416                 {
417                     // We put a 0.5 as simple squaring sinusoids will double the
418                     // fundamental frequency with respect fFrequency.
419                     float x     = cos(0.5f * fAcc2Phase * nPhaseAcc);
420                     *(dst++)    = sSquaredSinusoid.fAmplitude * x * x + fReferencedDC;
421                     nPhaseAcc   = (nPhaseAcc + nFreqCtrlWord) & nPhaseAccMask;
422                 }
423                 break;
424 
425             case FG_RECTANGULAR:
426                 while (count--)
427                 {
428                     *(dst++)    = ((nPhaseAcc < sRectangular.nDutyWord) ? fAmplitude : -fAmplitude) + fReferencedDC;
429                     nPhaseAcc   = (nPhaseAcc + nFreqCtrlWord) & nPhaseAccMask;
430                 }
431                 break;
432 
433             case FG_SAWTOOTH:
434                 while (count--)
435                 {
436                     if (nPhaseAcc < sSawtooth.nWidthWord)
437                         *(dst++)    = sSawtooth.fCoeffs[0] * nPhaseAcc + sSawtooth.fCoeffs[1] + fReferencedDC;
438                     else
439                         *(dst++)    = sSawtooth.fCoeffs[2] * nPhaseAcc + sSawtooth.fCoeffs[3] + fReferencedDC;
440 
441                     nPhaseAcc       = (nPhaseAcc + nFreqCtrlWord) & nPhaseAccMask;
442                 }
443                 break;
444 
445             case FG_TRAPEZOID:
446                 while (count--)
447                 {
448                     if (nPhaseAcc < sTrapezoid.nPoints[0])
449                         *(dst++)    = sTrapezoid.fCoeffs[0] * nPhaseAcc + fReferencedDC;
450 
451                     if ((nPhaseAcc >= sTrapezoid.nPoints[0]) && (nPhaseAcc <= sTrapezoid.nPoints[1]))
452                         *(dst++)    = fAmplitude + fReferencedDC;
453 
454                     if ((nPhaseAcc > sTrapezoid.nPoints[1]) && (nPhaseAcc < sTrapezoid.nPoints[2]))
455                         *(dst++)    = sTrapezoid.fCoeffs[1] * nPhaseAcc + sTrapezoid.fCoeffs[2] + fReferencedDC;
456 
457                     if ((nPhaseAcc >= sTrapezoid.nPoints[2]) && (nPhaseAcc <= sTrapezoid.nPoints[3]))
458                         *(dst++)    = fReferencedDC - fAmplitude;
459 
460                     if (nPhaseAcc > sTrapezoid.nPoints[3])
461                         *(dst++)    = sTrapezoid.fCoeffs[0] * nPhaseAcc + sTrapezoid.fCoeffs[3] + fReferencedDC;
462 
463                     nPhaseAcc       = (nPhaseAcc + nFreqCtrlWord) & nPhaseAccMask;
464 
465                 }
466                 break;
467 
468             case FG_PULSETRAIN:
469                 while (count--)
470                 {
471                     if (nPhaseAcc <= sPulse.nTrainPoints[0])
472                         *(dst++)    = fAmplitude + fReferencedDC;
473                     else if ((nPhaseAcc >= sPulse.nTrainPoints[1]) && (nPhaseAcc <= sPulse.nTrainPoints[2]))
474                         *(dst++)    = fReferencedDC - fAmplitude;
475                     else
476                         *(dst++)    = 0.0f + fReferencedDC;
477 
478                     nPhaseAcc       = (nPhaseAcc + nFreqCtrlWord) & nPhaseAccMask;
479                 }
480                 break;
481 
482             case FG_PARABOLIC:
483                 while (count--)
484                 {
485                     if (nPhaseAcc < sParabolic.nWidthWord)
486                     {
487                         float x     = (2.0f / sParabolic.nWidthWord) * nPhaseAcc - 1.0f;
488                         *(dst++)    = sParabolic.fAmplitude * (1.0f - x*x) + fReferencedDC;
489                     }
490                     else
491                         *(dst++)    = 0.0f + fReferencedDC;
492 
493                     nPhaseAcc       = (nPhaseAcc + nFreqCtrlWord) & nPhaseAccMask;
494                 }
495                 break;
496 
497             case FG_BL_RECTANGULAR:
498             {
499                 size_t buf_size     = PROCESS_BUF_LIMIT_SIZE / nOversampling;
500 
501                 while (count > 0)
502                 {
503                     size_t to_do        = (count > buf_size) ? buf_size : count;
504                     size_t synthCount   = nOversampling * to_do;
505 
506                     for (size_t n = 0; n < synthCount; ++n)
507                     {
508                         vProcessBuffer[n]   = sRectangular.fBLPeakAtten * (((nPhaseAcc < sRectangular.nDutyWord) ? fAmplitude : -fAmplitude) + fReferencedDC);
509                         nPhaseAcc           = (nPhaseAcc + nFreqCtrlWord_Over) & nPhaseAccMask;
510                     }
511 
512                     os->downsample(dst, vProcessBuffer, to_do);
513 
514                     dst             += to_do;
515                     count           -= to_do;
516                 }
517 
518             }
519             break;
520 
521             case FG_BL_SAWTOOTH:
522             {
523                 size_t buf_size     = PROCESS_BUF_LIMIT_SIZE / nOversampling;
524 
525                 while (count > 0)
526                 {
527                     size_t to_do        = (count > buf_size) ? buf_size : count;
528                     size_t synthCount   = nOversampling * to_do;
529 
530                     for (size_t n = 0; n < synthCount; ++n)
531                     {
532                         if (nPhaseAcc < sSawtooth.nWidthWord)
533                             vProcessBuffer[n]    = sSawtooth.fBLPeakAtten * (sSawtooth.fCoeffs[0] * nPhaseAcc + sSawtooth.fCoeffs[1] + fReferencedDC);
534                         else
535                             vProcessBuffer[n]    = sSawtooth.fBLPeakAtten * (sSawtooth.fCoeffs[2] * nPhaseAcc + sSawtooth.fCoeffs[3] + fReferencedDC);
536 
537                         nPhaseAcc           = (nPhaseAcc + nFreqCtrlWord_Over) & nPhaseAccMask;
538                     }
539 
540                     os->downsample(dst, vProcessBuffer, to_do);
541 
542                     dst             += to_do;
543                     count           -= to_do;
544                 }
545 
546             }
547             break;
548 
549             case FG_BL_TRAPEZOID:
550             {
551                 size_t buf_size     = PROCESS_BUF_LIMIT_SIZE / nOversampling;
552 
553                 while (count > 0)
554                 {
555                     size_t to_do        = (count > buf_size) ? buf_size : count;
556                     size_t synthCount   = nOversampling * to_do;
557 
558                     for (size_t n = 0; n < synthCount; ++n)
559                     {
560                         if (nPhaseAcc < sTrapezoid.nPoints[0])
561                             vProcessBuffer[n]    = sTrapezoid.fBLPeakAtten * (sTrapezoid.fCoeffs[0] * nPhaseAcc + fReferencedDC);
562 
563                         if ((nPhaseAcc >= sTrapezoid.nPoints[0]) && (nPhaseAcc <= sTrapezoid.nPoints[1]))
564                             vProcessBuffer[n]    = sTrapezoid.fBLPeakAtten * (fAmplitude + fReferencedDC);
565 
566                         if ((nPhaseAcc > sTrapezoid.nPoints[1]) && (nPhaseAcc < sTrapezoid.nPoints[2]))
567                             vProcessBuffer[n]    = sTrapezoid.fBLPeakAtten * (sTrapezoid.fCoeffs[1] * nPhaseAcc + sTrapezoid.fCoeffs[2] + fReferencedDC);
568 
569                         if ((nPhaseAcc >= sTrapezoid.nPoints[2]) && (nPhaseAcc <= sTrapezoid.nPoints[3]))
570                             vProcessBuffer[n]    = sTrapezoid.fBLPeakAtten * (fReferencedDC - fAmplitude);
571 
572                         if (nPhaseAcc > sTrapezoid.nPoints[3])
573                             vProcessBuffer[n]    = sTrapezoid.fBLPeakAtten * (sTrapezoid.fCoeffs[0] * nPhaseAcc + sTrapezoid.fCoeffs[3] + fReferencedDC);
574 
575                         nPhaseAcc           = (nPhaseAcc + nFreqCtrlWord_Over) & nPhaseAccMask;
576                     }
577 
578                     os->downsample(dst, vProcessBuffer, to_do);
579 
580                     dst             += to_do;
581                     count           -= to_do;
582                 }
583 
584             }
585             break;
586 
587             case FG_BL_PULSETRAIN:
588             {
589                 size_t buf_size     = PROCESS_BUF_LIMIT_SIZE / nOversampling;
590 
591                 while (count > 0)
592                 {
593                     size_t to_do        = (count > buf_size) ? buf_size : count;
594                     size_t synthCount   = nOversampling * to_do;
595 
596                     for (size_t n = 0; n < synthCount; ++n)
597                     {
598                         if (nPhaseAcc <= sPulse.nTrainPoints[0])
599                             vProcessBuffer[n]    = sPulse.fBLPeakAtten * (fAmplitude + fReferencedDC);
600                         else if ((nPhaseAcc >= sPulse.nTrainPoints[1]) && (nPhaseAcc <= sPulse.nTrainPoints[2]))
601                             vProcessBuffer[n]    = sPulse.fBLPeakAtten * (fReferencedDC - fAmplitude);
602                         else
603                             vProcessBuffer[n]    = 0.0f + fReferencedDC;
604 
605                         nPhaseAcc           = (nPhaseAcc + nFreqCtrlWord_Over) & nPhaseAccMask;
606                     }
607 
608                     os->downsample(dst, vProcessBuffer, to_do);
609 
610                     dst             += to_do;
611                     count           -= to_do;
612                 }
613 
614             }
615             break;
616 
617             case FG_BL_PARABOLIC:
618             {
619                 size_t buf_size     = PROCESS_BUF_LIMIT_SIZE / nOversampling;
620 
621                 while (count > 0)
622                 {
623                     size_t to_do        = (count > buf_size) ? buf_size : count;
624                     size_t synthCount   = nOversampling * to_do;
625 
626                     for (size_t n = 0; n < synthCount; ++n)
627                     {
628                         if (nPhaseAcc < sParabolic.nWidthWord)
629                         {
630                             float x             = (2.0f / sParabolic.nWidthWord) * nPhaseAcc - 1.0f;
631                             vProcessBuffer[n]   = sParabolic.fBLPeakAtten * (sParabolic.fAmplitude * (1.0f - x*x) + fReferencedDC); // Do not use pow(x, 2). Simple x*x multiplication is faster
632                         }
633                         else
634                             vProcessBuffer[n]    = 0.0f + fReferencedDC;
635 
636                         nPhaseAcc           = (nPhaseAcc + nFreqCtrlWord_Over) & nPhaseAccMask;
637                     }
638 
639                     os->downsample(dst, vProcessBuffer, to_do);
640 
641                     dst             += to_do;
642                     count           -= to_do;
643                 }
644 
645             }
646             break;
647 
648             default:
649                 break;
650         }
651     }
652 
get_periods(float * dst,size_t periods,size_t periodsSkip,size_t samples)653     void Oscillator::get_periods(float *dst, size_t periods, size_t periodsSkip, size_t samples)
654     {
655         phacc_t nPhaseAcc_Backup    = nPhaseAcc;
656         nPhaseAcc                   = nInitPhaseWord;
657 
658         float periodDuration        = float(nSampleRate) / fFrequency; /* samples / period */
659         float out_samples           = periodDuration * float(periods);
660         float skip_samples          = periodDuration * float(periodsSkip);
661         float decimationStep        = out_samples / float(samples);
662 
663         // Create and assign the samples of the periods to return.
664         ssize_t buf_size            = 0;
665 
666         // Create the samples of the first periods to skip
667         while (skip_samples > 0.0f)
668         {
669             // Request new buffer
670             size_t to_do    = ceil(out_samples + skip_samples + decimationStep);
671             if (to_do > PROCESS_BUF_LIMIT_SIZE)
672                 to_do           = PROCESS_BUF_LIMIT_SIZE;
673 
674             do_process(&sOverGetPeriods, vSynthBuffer, to_do);
675 
676             buf_size        = to_do;
677             skip_samples   -= to_do;
678         }
679 
680         float t                 = buf_size + skip_samples; // t points to the beginning of first period
681 
682         while (samples > 0)
683         {
684             if (t < buf_size)
685             {
686                 *(dst++)        = vSynthBuffer[size_t(t)];
687                 t              += decimationStep;
688                 samples        --;
689             }
690             else
691             {
692                 // Request new buffer
693                 size_t to_do    = ceil(out_samples + decimationStep);
694                 if (to_do > PROCESS_BUF_LIMIT_SIZE)
695                     to_do           = PROCESS_BUF_LIMIT_SIZE;
696 
697                 do_process(&sOverGetPeriods, vSynthBuffer, to_do);
698 
699                 // Update counters
700                 out_samples    -= to_do;
701                 buf_size        = PROCESS_BUF_LIMIT_SIZE;
702                 t              -= buf_size;
703             }
704         }
705 
706         nPhaseAcc = nPhaseAcc_Backup;
707     }
708 
process_add(float * dst,const float * src,size_t count)709     void Oscillator::process_add(float *dst, const float *src, size_t count)
710     {
711         update_settings();
712 
713         if (src != NULL)
714             dsp::copy(dst, src, count);
715         else
716             dsp::fill_zero(dst, count);
717 
718         while (count > 0)
719         {
720             size_t to_do = (count > PROCESS_BUF_LIMIT_SIZE) ? PROCESS_BUF_LIMIT_SIZE : count;
721 
722             do_process(&sOver, vSynthBuffer, to_do);
723             dsp::add2(dst, vSynthBuffer, to_do);
724 
725             dst     += to_do;
726             count   -= to_do;
727         }
728     }
729 
process_mul(float * dst,const float * src,size_t count)730     void Oscillator::process_mul(float *dst, const float *src, size_t count)
731     {
732         update_settings();
733 
734         if (src != NULL)
735             dsp::copy(dst, src, count);
736         else
737             dsp::fill_zero(dst, count);
738 
739         while (count > 0)
740         {
741             size_t to_do = (count > PROCESS_BUF_LIMIT_SIZE) ? PROCESS_BUF_LIMIT_SIZE : count;
742 
743             do_process(&sOver, vSynthBuffer, to_do);
744             dsp::mul2(dst, vSynthBuffer, to_do);
745 
746             dst     += to_do;
747             count   -= to_do;
748         }
749     }
750 
process_overwrite(float * dst,size_t count)751     void Oscillator::process_overwrite(float *dst, size_t count)
752     {
753         update_settings();
754 
755         while (count > 0)
756         {
757             size_t to_do = (count > PROCESS_BUF_LIMIT_SIZE) ? PROCESS_BUF_LIMIT_SIZE : count;
758 
759             do_process(&sOver, vSynthBuffer, to_do);
760             dsp::copy(dst, vSynthBuffer, to_do);
761 
762             dst     += to_do;
763             count   -= to_do;
764         }
765     }
766 
dump(IStateDumper * v) const767     void Oscillator::dump(IStateDumper *v) const
768     {
769         v->write("enFunction", enFunction);
770         v->write("fAmplitude", fAmplitude);
771         v->write("fFrequency", fFrequency);
772         v->write("fDCOffset", fDCOffset);
773         v->write("enDCReference", enDCReference);
774         v->write("fReferencedDC", fReferencedDC);
775         v->write("fInitPhase", fInitPhase);
776 
777         v->write("nSampleRate", nSampleRate);
778         v->write("nPhaseAcc", nPhaseAcc);
779         v->write("nPhaseAccBits", nPhaseAccBits);
780         v->write("nPhaseAccMaxBits", nPhaseAccMaxBits);
781         v->write("nPhaseAccMask", nPhaseAccMask);
782         v->write("fAcc2Phase", fAcc2Phase);
783 
784         v->write("nFreqCtrlWord", nFreqCtrlWord);
785         v->write("nInitPhaseWord", nInitPhaseWord);
786 
787         v->begin_object("sSquaredSinusoid", &sSquaredSinusoid, sizeof(sSquaredSinusoid));
788         {
789             v->write("bInvert", sSquaredSinusoid.bInvert);
790             v->write("fAmplitude", sSquaredSinusoid.fAmplitude);
791             v->write("fWaveDC", sSquaredSinusoid.fWaveDC);
792         }
793         v->end_object();
794 
795         v->begin_object("sRectangular", &sRectangular, sizeof(sRectangular));
796         {
797             v->write("fDutyRatio", sRectangular.fDutyRatio);
798             v->write("nDutyWord", sRectangular.nDutyWord);
799             v->write("fWaveDC", sRectangular.fWaveDC);
800             v->write("fBLPeakAtten", sRectangular.fBLPeakAtten);
801         }
802         v->end_object();
803 
804         v->begin_object("sSawtooth", &sSawtooth, sizeof(sSawtooth));
805         {
806             v->write("fWidth", sSawtooth.fWidth);
807             v->write("nWidthWord", sSawtooth.nWidthWord);
808             v->writev("fCoeffs", sSawtooth.fCoeffs, 4);
809             v->write("fWaveDC", sSawtooth.fWaveDC);
810             v->write("fBLPeakAtten", sSawtooth.fBLPeakAtten);
811         }
812         v->end_object();
813 
814         v->begin_object("sTrapezoid", &sTrapezoid, sizeof(sTrapezoid));
815         {
816             v->write("fRaiseRatio", sTrapezoid.fRaiseRatio);
817             v->write("fFallRatio", sTrapezoid.fFallRatio);
818             v->writev("nPoints", sTrapezoid.nPoints, 4);
819             v->writev("fCoeffs", sTrapezoid.fCoeffs, 4);
820             v->write("fWaveDC", sTrapezoid.fWaveDC);
821             v->write("fBLPeakAtten", sTrapezoid.fBLPeakAtten);
822         }
823         v->end_object();
824 
825         v->begin_object("sPulse", &sPulse, sizeof(sPulse));
826         {
827             v->write("fPosWidthRatio", sPulse.fPosWidthRatio);
828             v->write("fNegWidthRatio", sPulse.fNegWidthRatio);
829             v->writev("nTrainPoints", sPulse.nTrainPoints, 3);
830             v->write("fWaveDC", sPulse.fWaveDC);
831             v->write("fBLPeakAtten", sPulse.fBLPeakAtten);
832         }
833         v->end_object();
834 
835         v->begin_object("sParabolic", &sParabolic, sizeof(sParabolic));
836         {
837             v->write("bInvert", sParabolic.bInvert);
838             v->write("fAmplitude", sParabolic.fAmplitude);
839             v->write("fWidth", sParabolic.fWidth);
840             v->write("nWidthWord", sParabolic.nWidthWord);
841             v->write("fWaveDC", sParabolic.fWaveDC);
842             v->write("fBLPeakAtten", sParabolic.fBLPeakAtten);
843 
844         }
845         v->end_object();
846 
847         v->write("vProcessBuffer", vProcessBuffer);
848         v->write("vSynthBuffer", vSynthBuffer);
849         v->write("pData", pData);
850 
851         v->write_object("sOver", &sOver);
852         v->write_object("sOverGetPeriods", &sOverGetPeriods);
853 
854         v->write("nOversampling", nOversampling);
855         v->write("enOverMode", enOverMode);
856         v->write("nFreqCtrlWord_Over", nFreqCtrlWord_Over);
857         v->write("bSync", bSync);
858     }
859 
860 }
861