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 }