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