File indexing completed on 2024-04-28 15:08:06

0001 /* miniSynth - A Simple Software Synthesizer
0002    SPDX-FileCopyrightText: 2015 Ville Räisänen <vsr at vsr.name>
0003 
0004    SPDX-License-Identifier: GPL-3.0-or-later
0005 */
0006 
0007 #include "waveform.h"
0008 #include <QCoreApplication>
0009 #include <QDebug>
0010 
0011 Waveform::Waveform(unsigned int mode, unsigned int size) {
0012     waveTable = new qreal[size];
0013     tableSize = size;
0014     this->mode = mode;
0015 
0016     for (unsigned int sample = 0; sample < tableSize; sample++) {
0017         qreal u = (2*M_PI * (qreal)sample) / ((qreal)tableSize);
0018 
0019         switch(mode) {
0020         case MODE_SIN:
0021             waveTable[sample] = waveSin(u);
0022             break;
0023         case MODE_SAW:
0024             waveTable[sample] = waveSaw(u);
0025             break;
0026         case MODE_SAW2:
0027             waveTable[sample] = waveSaw2(u);
0028             break;
0029         case MODE_SQU:
0030             waveTable[sample] = waveSqu(u);
0031             break;
0032         }
0033     }
0034 }
0035 
0036 Waveform::~Waveform() {
0037     delete [] waveTable;
0038     waveTable = nullptr;
0039 }
0040 
0041 qreal
0042 Waveform::waveSin(qreal t) {
0043     return qSin(t);
0044 }
0045 
0046 qreal
0047 Waveform::waveSaw(qreal t) {
0048     qreal tmod = (qreal)(fmod((double)t, 2*M_PI) - M_PI);
0049     return tmod / M_PI;
0050 }
0051 
0052 qreal
0053 Waveform::waveSaw2(qreal t) {
0054     qreal tmod = (qreal)(fmod((double)t, 2*M_PI) - M_PI);
0055     return 1 - 2 * qAbs(tmod) / M_PI;
0056 }
0057 
0058 qreal
0059 Waveform::waveSqu(qreal t) {
0060     qreal tmod = (qreal)fmod((double)t, 2*M_PI);
0061     if (tmod < M_PI) {
0062         return 1;
0063     }
0064     return -1;
0065 }
0066 
0067 
0068 qreal
0069 Waveform::eval(qreal t) {
0070     qreal tmod = fmod((double)t, 2*M_PI);
0071     if (tmod < 0) tmod += 2*M_PI;
0072 
0073     // Position indexed by a continuous variable does not generally fall on
0074     // integer-valued points. Here indF is the "continuous-valued position"
0075     // of the argument and is somewhere between the integers qFloor(indF) and
0076     // qCeil(indF). When indF is not an integer, we use linear interpolation
0077     // to obtain the appropriate value.
0078 
0079     qreal indF = ((qreal)tableSize) * tmod / (2*(qreal)M_PI);
0080     if (indF == (qreal)tableSize) indF = 0;
0081 
0082     Q_ASSERT(indF >= 0);
0083     Q_ASSERT(indF < (qreal)tableSize);
0084 
0085     unsigned int ind_min = (unsigned int) qFloor(indF);
0086     unsigned int ind_max = (unsigned int) qCeil(indF);
0087 
0088     Q_ASSERT(ind_min <= ind_max);
0089     Q_ASSERT(ind_max <= tableSize);
0090     Q_ASSERT(ind_min < tableSize);
0091 
0092     qreal indmod = indF - (qreal)ind_min;
0093     Q_ASSERT(indmod < 1 && indmod >= 0);
0094 
0095     qreal value_next;
0096     qreal value_prev;
0097 
0098     if (ind_min == ind_max) {
0099         return waveTable[ind_min];
0100     }
0101     if (ind_max == tableSize) {
0102         value_prev = waveTable[ind_min];
0103         value_next = waveTable[0];
0104         return indmod * value_next + (1-indmod) * value_prev;
0105     }
0106     if (ind_min < ind_max) {
0107         Q_ASSERT(ind_max < tableSize);
0108         value_prev = waveTable[ind_min];
0109         value_next = waveTable[ind_max];
0110         return indmod * value_next + (1-indmod) * value_prev;
0111     }
0112     // This shouldn't be reached;
0113     qCritical("Wave Table Interpolation Failed");
0114     QCoreApplication::exit(-1);
0115     return 0;
0116 }