Band limited waveformsdds
#include <stdint.h> | |||||
// band limited step function, 17kHz limit for 44.1kSPS. | |||||
// step goes from -BASE_AMPLITUDE to +BASE_AMPLITUDE nominally | |||||
// [ only store the first half of the table due to its odd symmetry ] | |||||
// the extra first entry allows for the interpolation code not to overrun on reflected table, | |||||
// the last extra entry allows for interpolation not to overrun when non-reflected | |||||
const int16_t step_table [258] = // size is N/2+2 where N = SUPPORT * SCALE * 2 | |||||
{ | |||||
-24576, | |||||
-24551, -24550, -24549, -24548, -24546, -24544, -24542, -24540, -24538, -24537, -24537, -24537, -24539, -24543, -24547, -24553, | |||||
-24560, -24569, -24579, -24590, -24602, -24614, -24627, -24639, -24651, -24663, -24673, -24682, -24689, -24693, -24695, -24694, | |||||
-24691, -24684, -24674, -24661, -24646, -24627, -24607, -24585, -24561, -24536, -24511, -24486, -24463, -24441, -24421, -24403, | |||||
-24390, -24380, -24374, -24373, -24377, -24386, -24400, -24418, -24441, -24469, -24499, -24533, -24569, -24607, -24645, -24683, | |||||
-24720, -24755, -24786, -24814, -24836, -24854, -24865, -24870, -24867, -24858, -24842, -24819, -24789, -24753, -24712, -24666, | |||||
-24617, -24566, -24513, -24460, -24408, -24359, -24314, -24274, -24239, -24212, -24193, -24182, -24181, -24189, -24206, -24233, | |||||
-24268, -24312, -24364, -24422, -24485, -24552, -24621, -24691, -24760, -24826, -24889, -24945, -24994, -25034, -25064, -25084, | |||||
-25091, -25087, -25070, -25041, -25000, -24948, -24886, -24815, -24736, -24652, -24564, -24473, -24383, -24296, -24213, -24136, | |||||
-24068, -24011, -23965, -23934, -23916, -23914, -23928, -23958, -24003, -24064, -24137, -24224, -24320, -24426, -24537, -24653, | |||||
-24769, -24884, -24994, -25097, -25190, -25271, -25337, -25387, -25418, -25430, -25422, -25394, -25345, -25276, -25188, -25084, | |||||
-24964, -24832, -24691, -24542, -24391, -24240, -24092, -23953, -23824, -23710, -23613, -23537, -23484, -23456, -23454, -23478, | |||||
-23531, -23610, -23714, -23843, -23993, -24162, -24347, -24542, -24745, -24950, -25153, -25348, -25531, -25697, -25841, -25960, | |||||
-26048, -26104, -26125, -26108, -26054, -25961, -25831, -25665, -25466, -25238, -24984, -24710, -24422, -24125, -23828, -23535, | |||||
-23256, -22998, -22766, -22570, -22414, -22304, -22246, -22244, -22300, -22417, -22594, -22831, -23126, -23475, -23872, -24311, | |||||
-24785, -25283, -25795, -26311, -26816, -27300, -27747, -28143, -28476, -28731, -28894, -28953, -28896, -28711, -28390, -27923, | |||||
-27305, -26530, -25596, -24501, -23246, -21836, -20274, -18569, -16729, -14766, -12691, -10521, -8269, -5953, -3591, -1200, | |||||
1200 | |||||
}; | |||||
/* // this version is for SCALE = 64, but with interpolation isn't really needed | |||||
int16_t edge_table [1026] = // size is N/2+2 where N = SUPPORT * SCALE * 2 | |||||
{ | |||||
-24576, | |||||
-24551, -24551, -24551, -24551, -24551, -24550, -24550, -24550, -24550, -24549, -24549, -24549, -24548, -24548, -24547, -24547, | |||||
-24547, -24546, -24546, -24545, -24544, -24544, -24543, -24543, -24542, -24542, -24541, -24541, -24540, -24540, -24539, -24539, | |||||
-24539, -24538, -24538, -24538, -24537, -24537, -24537, -24537, -24537, -24537, -24537, -24537, -24537, -24537, -24538, -24538, | |||||
-24539, -24539, -24540, -24540, -24541, -24542, -24543, -24544, -24545, -24546, -24548, -24549, -24551, -24552, -24554, -24556, | |||||
-24557, -24559, -24561, -24563, -24566, -24568, -24570, -24573, -24575, -24578, -24580, -24583, -24586, -24588, -24591, -24594, | |||||
-24597, -24600, -24603, -24606, -24609, -24612, -24616, -24619, -24622, -24625, -24628, -24631, -24635, -24638, -24641, -24644, | |||||
-24647, -24650, -24653, -24656, -24659, -24661, -24664, -24667, -24669, -24672, -24674, -24677, -24679, -24681, -24683, -24685, | |||||
-24686, -24688, -24689, -24690, -24692, -24693, -24693, -24694, -24695, -24695, -24695, -24695, -24695, -24694, -24694, -24693, | |||||
-24692, -24691, -24690, -24688, -24687, -24685, -24683, -24680, -24678, -24675, -24672, -24669, -24666, -24663, -24659, -24656, | |||||
-24652, -24648, -24643, -24639, -24634, -24630, -24625, -24620, -24615, -24609, -24604, -24599, -24593, -24587, -24582, -24576, | |||||
-24570, -24564, -24558, -24552, -24545, -24539, -24533, -24527, -24520, -24514, -24508, -24502, -24496, -24489, -24483, -24477, | |||||
-24471, -24466, -24460, -24454, -24449, -24443, -24438, -24433, -24428, -24423, -24418, -24414, -24410, -24406, -24402, -24398, | |||||
-24395, -24391, -24388, -24386, -24383, -24381, -24379, -24377, -24376, -24375, -24374, -24374, -24373, -24373, -24374, -24374, | |||||
-24375, -24377, -24378, -24380, -24382, -24385, -24388, -24391, -24394, -24398, -24402, -24406, -24411, -24416, -24421, -24427, | |||||
-24432, -24438, -24445, -24451, -24458, -24465, -24472, -24480, -24488, -24496, -24504, -24512, -24520, -24529, -24538, -24547, | |||||
-24556, -24565, -24574, -24583, -24593, -24602, -24612, -24621, -24631, -24641, -24650, -24660, -24669, -24679, -24688, -24697, | |||||
-24706, -24715, -24724, -24733, -24742, -24750, -24759, -24767, -24775, -24782, -24790, -24797, -24804, -24810, -24817, -24823, | |||||
-24828, -24834, -24839, -24843, -24848, -24852, -24855, -24858, -24861, -24864, -24866, -24867, -24868, -24869, -24869, -24869, | |||||
-24869, -24868, -24866, -24864, -24862, -24859, -24856, -24852, -24848, -24844, -24839, -24834, -24828, -24822, -24815, -24808, | |||||
-24800, -24793, -24784, -24776, -24767, -24758, -24748, -24738, -24728, -24717, -24706, -24695, -24684, -24672, -24660, -24648, | |||||
-24636, -24623, -24611, -24598, -24585, -24572, -24559, -24546, -24533, -24520, -24506, -24493, -24480, -24467, -24454, -24441, | |||||
-24428, -24415, -24402, -24390, -24377, -24365, -24354, -24342, -24331, -24320, -24309, -24298, -24288, -24279, -24269, -24260, | |||||
-24252, -24243, -24236, -24228, -24222, -24215, -24210, -24204, -24199, -24195, -24191, -24188, -24186, -24183, -24182, -24181, | |||||
-24181, -24181, -24182, -24183, -24185, -24188, -24191, -24194, -24199, -24204, -24209, -24215, -24222, -24229, -24237, -24245, | |||||
-24254, -24264, -24274, -24284, -24295, -24307, -24319, -24331, -24344, -24357, -24371, -24385, -24399, -24414, -24429, -24445, | |||||
-24461, -24477, -24493, -24510, -24526, -24543, -24560, -24577, -24595, -24612, -24630, -24647, -24665, -24682, -24700, -24717, | |||||
-24734, -24751, -24768, -24785, -24802, -24818, -24834, -24850, -24866, -24881, -24896, -24910, -24924, -24938, -24951, -24964, | |||||
-24976, -24988, -24999, -25010, -25020, -25029, -25038, -25046, -25054, -25061, -25067, -25072, -25077, -25081, -25085, -25087, | |||||
-25089, -25091, -25091, -25091, -25090, -25088, -25085, -25082, -25077, -25073, -25067, -25060, -25053, -25045, -25036, -25027, | |||||
-25017, -25006, -24994, -24982, -24969, -24955, -24941, -24926, -24910, -24894, -24878, -24860, -24842, -24824, -24805, -24786, | |||||
-24766, -24746, -24726, -24705, -24684, -24663, -24641, -24619, -24597, -24575, -24552, -24530, -24507, -24485, -24462, -24440, | |||||
-24417, -24395, -24372, -24350, -24328, -24307, -24285, -24264, -24243, -24223, -24203, -24183, -24164, -24145, -24127, -24110, | |||||
-24093, -24076, -24061, -24046, -24031, -24018, -24005, -23993, -23981, -23971, -23961, -23952, -23944, -23937, -23931, -23926, | |||||
-23922, -23918, -23916, -23914, -23914, -23914, -23916, -23918, -23922, -23926, -23932, -23938, -23946, -23954, -23964, -23974, | |||||
-23985, -23997, -24011, -24025, -24040, -24056, -24073, -24090, -24109, -24128, -24148, -24169, -24190, -24213, -24236, -24259, | |||||
-24283, -24308, -24334, -24359, -24386, -24413, -24440, -24467, -24495, -24523, -24552, -24581, -24609, -24638, -24667, -24697, | |||||
-24726, -24755, -24784, -24813, -24841, -24870, -24898, -24926, -24953, -24980, -25007, -25034, -25059, -25084, -25109, -25133, | |||||
-25156, -25179, -25201, -25222, -25242, -25261, -25280, -25297, -25314, -25329, -25344, -25357, -25370, -25381, -25391, -25400, | |||||
-25408, -25415, -25420, -25425, -25428, -25429, -25430, -25429, -25427, -25424, -25419, -25413, -25406, -25398, -25388, -25377, | |||||
-25365, -25351, -25336, -25320, -25303, -25285, -25265, -25244, -25223, -25200, -25176, -25150, -25124, -25097, -25069, -25040, | |||||
-25010, -24980, -24948, -24916, -24883, -24849, -24815, -24780, -24745, -24709, -24672, -24635, -24598, -24561, -24523, -24486, | |||||
-24448, -24410, -24372, -24334, -24296, -24258, -24221, -24184, -24147, -24111, -24075, -24039, -24004, -23970, -23936, -23903, | |||||
-23871, -23840, -23809, -23780, -23751, -23724, -23697, -23672, -23648, -23625, -23603, -23583, -23564, -23546, -23530, -23515, | |||||
-23502, -23490, -23480, -23471, -23464, -23459, -23455, -23453, -23452, -23453, -23456, -23461, -23467, -23475, -23485, -23496, | |||||
-23509, -23524, -23540, -23558, -23578, -23599, -23622, -23647, -23673, -23701, -23730, -23761, -23793, -23826, -23861, -23898, | |||||
-23935, -23974, -24014, -24055, -24098, -24141, -24185, -24230, -24277, -24323, -24371, -24419, -24468, -24518, -24568, -24618, | |||||
-24669, -24720, -24771, -24822, -24873, -24925, -24976, -25027, -25077, -25128, -25178, -25227, -25276, -25324, -25371, -25418, | |||||
-25464, -25509, -25552, -25595, -25636, -25677, -25715, -25753, -25789, -25824, -25856, -25888, -25917, -25945, -25971, -25995, | |||||
-26017, -26038, -26056, -26072, -26086, -26098, -26107, -26115, -26120, -26123, -26123, -26121, -26117, -26111, -26102, -26091, | |||||
-26077, -26061, -26043, -26022, -25999, -25973, -25945, -25915, -25883, -25848, -25811, -25772, -25730, -25687, -25641, -25593, | |||||
-25543, -25492, -25438, -25383, -25326, -25267, -25207, -25145, -25081, -25016, -24950, -24883, -24815, -24745, -24675, -24603, | |||||
-24531, -24458, -24385, -24311, -24237, -24163, -24088, -24014, -23939, -23865, -23791, -23717, -23644, -23572, -23500, -23429, | |||||
-23360, -23291, -23224, -23157, -23093, -23030, -22968, -22908, -22851, -22795, -22741, -22690, -22640, -22594, -22549, -22508, | |||||
-22469, -22432, -22399, -22369, -22341, -22317, -22296, -22278, -22264, -22253, -22245, -22241, -22240, -22243, -22250, -22261, | |||||
-22275, -22292, -22314, -22339, -22368, -22401, -22438, -22479, -22523, -22571, -22623, -22678, -22738, -22801, -22867, -22938, | |||||
-23011, -23088, -23169, -23253, -23340, -23430, -23524, -23620, -23719, -23822, -23926, -24034, -24144, -24256, -24370, -24487, | |||||
-24605, -24725, -24847, -24970, -25094, -25220, -25347, -25474, -25602, -25731, -25860, -25989, -26118, -26246, -26374, -26502, | |||||
-26628, -26753, -26877, -27000, -27121, -27240, -27356, -27471, -27582, -27691, -27797, -27900, -27999, -28095, -28186, -28274, | |||||
-28357, -28436, -28509, -28578, -28642, -28700, -28753, -28800, -28841, -28875, -28903, -28925, -28940, -28947, -28948, -28941, | |||||
-28927, -28905, -28875, -28837, -28791, -28737, -28674, -28602, -28522, -28432, -28334, -28227, -28110, -27984, -27849, -27704, | |||||
-27549, -27385, -27211, -27027, -26833, -26629, -26416, -26192, -25959, -25715, -25461, -25198, -24924, -24640, -24346, -24043, | |||||
-23729, -23406, -23073, -22730, -22377, -22015, -21643, -21262, -20872, -20472, -20063, -19646, -19220, -18785, -18341, -17889, | |||||
-17429, -16961, -16486, -16002, -15511, -15013, -14508, -13996, -13477, -12953, -12421, -11884, -11342, -10794, -10240, -9682, | |||||
-9119, -8552, -7980, -7405, -6826, -6243, -5658, -5070, -4479, -3887, -3292, -2696, -2098, -1499, -900, -300, | |||||
300 | |||||
} ; | |||||
*/ |
WAVEFORM_SAWTOOTH_REVERSE LITERAL1 | WAVEFORM_SAWTOOTH_REVERSE LITERAL1 | ||||
WAVEFORM_SAMPLE_HOLD LITERAL1 | WAVEFORM_SAMPLE_HOLD LITERAL1 | ||||
WAVEFORM_TRIANGLE_VARIABLE LITERAL1 | WAVEFORM_TRIANGLE_VARIABLE LITERAL1 | ||||
WAVEFORM_BANDLIMIT_SAWTOOTH LITERAL1 | |||||
WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE LITERAL1 | |||||
WAVEFORM_BANDLIMIT_SQUARE LITERAL1 | |||||
WAVEFORM_BANDLIMIT_PULSE LITERAL1 | |||||
AUDIO_MEMORY_23LC1024 LITERAL1 | AUDIO_MEMORY_23LC1024 LITERAL1 | ||||
AUDIO_MEMORY_MEMORYBOARD LITERAL1 | AUDIO_MEMORY_MEMORYBOARD LITERAL1 |
// uncomment for more accurate but more computationally expensive frequency modulation | // uncomment for more accurate but more computationally expensive frequency modulation | ||||
//#define IMPROVE_EXPONENTIAL_ACCURACY | //#define IMPROVE_EXPONENTIAL_ACCURACY | ||||
#define BASE_AMPLITUDE 0x6000 // 0x7fff won't work due to Gibb's phenomenon, so use 3/4 of full range. | |||||
void AudioSynthWaveform::update(void) | void AudioSynthWaveform::update(void) | ||||
} | } | ||||
break; | break; | ||||
case WAVEFORM_BANDLIMIT_SQUARE: | |||||
for (int i = 0 ; i < AUDIO_BLOCK_SAMPLES ; i++) | |||||
{ | |||||
uint32_t new_ph = ph + inc ; | |||||
int16_t val = band_limit_waveform.generate_square (new_ph, i) ; | |||||
*bp++ = (val * magnitude) >> 16 ; | |||||
ph = new_ph ; | |||||
} | |||||
break; | |||||
case WAVEFORM_SAWTOOTH: | case WAVEFORM_SAWTOOTH: | ||||
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | ||||
*bp++ = signed_multiply_32x16t(magnitude, ph); | *bp++ = signed_multiply_32x16t(magnitude, ph); | ||||
} | } | ||||
break; | break; | ||||
case WAVEFORM_BANDLIMIT_SAWTOOTH: | |||||
case WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE: | |||||
for (i = 0 ; i < AUDIO_BLOCK_SAMPLES; i++) | |||||
{ | |||||
uint32_t new_ph = ph + inc ; | |||||
int16_t val = band_limit_waveform.generate_sawtooth (new_ph, i) ; | |||||
if (tone_type == WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE) | |||||
*bp++ = (val * -magnitude) >> 16 ; | |||||
else | |||||
*bp++ = (val * magnitude) >> 16 ; | |||||
ph = new_ph ; | |||||
} | |||||
break; | |||||
case WAVEFORM_TRIANGLE: | case WAVEFORM_TRIANGLE: | ||||
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | ||||
uint32_t phtop = ph >> 30; | uint32_t phtop = ph >> 30; | ||||
} | } | ||||
break; | break; | ||||
case WAVEFORM_BANDLIMIT_PULSE: | |||||
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) | |||||
{ | |||||
int32_t new_ph = ph + inc ; | |||||
int32_t val = band_limit_waveform.generate_pulse (new_ph, pulse_width, i) ; | |||||
*bp++ = (int16_t) ((val * magnitude) >> 16) ; | |||||
ph = new_ph ; | |||||
} | |||||
break; | |||||
case WAVEFORM_SAMPLE_HOLD: | case WAVEFORM_SAMPLE_HOLD: | ||||
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | ||||
*bp++ = sample; | *bp++ = sample; | ||||
// exp2 algorithm by Laurent de Soras | // exp2 algorithm by Laurent de Soras | ||||
// https://www.musicdsp.org/en/latest/Other/106-fast-exp2-approximation.html | // https://www.musicdsp.org/en/latest/Other/106-fast-exp2-approximation.html | ||||
n = (n + 134217728) << 3; | n = (n + 134217728) << 3; | ||||
n = multiply_32x32_rshift32_rounded(n, n); | n = multiply_32x32_rshift32_rounded(n, n); | ||||
n = multiply_32x32_rshift32_rounded(n, 715827883) << 3; | n = multiply_32x32_rshift32_rounded(n, 715827883) << 3; | ||||
n = n + 715827882; | n = n + 715827882; | ||||
} | } | ||||
break; | break; | ||||
case WAVEFORM_BANDLIMIT_PULSE: | |||||
if (shapedata) | |||||
{ | |||||
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) | |||||
{ | |||||
uint32_t width = ((shapedata->data[i] + 0x8000) & 0xFFFF) << 16; | |||||
int32_t val = band_limit_waveform.generate_pulse (phasedata[i], width, i) ; | |||||
*bp++ = (int16_t) ((val * magnitude) >> 16) ; | |||||
} | |||||
break; | |||||
} // else fall through to orginary square without shape modulation | |||||
case WAVEFORM_BANDLIMIT_SQUARE: | |||||
for (i = 0 ; i < AUDIO_BLOCK_SAMPLES ; i++) | |||||
{ | |||||
int32_t val = band_limit_waveform.generate_square (phasedata[i], i) ; | |||||
*bp++ = (int16_t) ((val * magnitude) >> 16) ; | |||||
} | |||||
break; | |||||
case WAVEFORM_SAWTOOTH: | case WAVEFORM_SAWTOOTH: | ||||
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | ||||
*bp++ = signed_multiply_32x16t(magnitude, phasedata[i]); | *bp++ = signed_multiply_32x16t(magnitude, phasedata[i]); | ||||
} | } | ||||
break; | break; | ||||
case WAVEFORM_BANDLIMIT_SAWTOOTH: | |||||
case WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE: | |||||
for (i = 0 ; i < AUDIO_BLOCK_SAMPLES ; i++) | |||||
{ | |||||
int16_t val = band_limit_waveform.generate_sawtooth (phasedata[i], i) ; | |||||
val = (int16_t) ((val * magnitude) >> 16) ; | |||||
*bp++ = tone_type == WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE ? (int16_t) -val : (int16_t) +val ; | |||||
} | |||||
break; | |||||
case WAVEFORM_TRIANGLE_VARIABLE: | case WAVEFORM_TRIANGLE_VARIABLE: | ||||
if (shapedata) { | if (shapedata) { | ||||
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | ||||
} | } | ||||
// BandLimitedWaveform | |||||
#define SUPPORT_SHIFT 4 | |||||
#define SUPPORT (1 << SUPPORT_SHIFT) | |||||
#define PTRMASK ((2 << SUPPORT_SHIFT) - 1) | |||||
#define SCALE 16 | |||||
#define SCALE_MASK (SCALE-1) | |||||
#define N (SCALE * SUPPORT * 2) | |||||
#define GUARD_BITS 8 | |||||
#define GUARD (1 << GUARD_BITS) | |||||
#define HALF_GUARD (1 << (GUARD_BITS-1)) | |||||
#define DEG180 0x80000000u | |||||
#define PHASE_SCALE (0x100000000L / (2 * BASE_AMPLITUDE)) | |||||
extern "C" | |||||
{ | |||||
extern const int16_t step_table [258] ; | |||||
} | |||||
int32_t BandLimitedWaveform::lookup (int offset) | |||||
{ | |||||
int off = offset >> GUARD_BITS ; | |||||
int frac = offset & (GUARD-1) ; | |||||
int32_t a, b ; | |||||
if (off < N/2) // handle odd symmetry by reflecting table | |||||
{ | |||||
a = step_table [off+1] ; | |||||
b = step_table [off+2] ; | |||||
} | |||||
else | |||||
{ | |||||
a = - step_table [N-off] ; | |||||
b = - step_table [N-off-1] ; | |||||
} | |||||
return BASE_AMPLITUDE + ((frac * b + (GUARD - frac) * a + HALF_GUARD) >> GUARD_BITS) ; // interpolated | |||||
} | |||||
// create a new step, apply its past waveform into the cyclic sample buffer | |||||
// and add a step_state object into active list so it can be added for the future samples | |||||
void BandLimitedWaveform::insert_step (int offset, bool rising, int i) | |||||
{ | |||||
while (offset <= (N/2-SCALE)<<GUARD_BITS) | |||||
{ | |||||
if (offset >= 0) | |||||
cyclic [i & 15] += rising ? lookup (offset) : -lookup (offset) ; | |||||
offset += SCALE<<GUARD_BITS ; | |||||
i ++ ; | |||||
} | |||||
states[newptr].offset = offset ; | |||||
states[newptr].positive = rising ; | |||||
newptr = (newptr+1) & PTRMASK ; | |||||
} | |||||
// generate value for current sample from one active step, checking for the | |||||
// dc_offset adjustment at the end of the table. | |||||
int32_t BandLimitedWaveform::process_step (int i) | |||||
{ | |||||
int off = states[i].offset ; | |||||
bool positive = states[i].positive ; | |||||
int32_t entry = lookup (off) ; | |||||
off += SCALE<<GUARD_BITS ; | |||||
states[i].offset = off ; // update offset in table for next sample | |||||
if (off >= N<<GUARD_BITS) // at end of step table we alter dc_offset to extend the step into future | |||||
dc_offset += positive ? 2*BASE_AMPLITUDE : -2*BASE_AMPLITUDE ; | |||||
return positive ? entry : -entry ; | |||||
} | |||||
// process all active steps for current sample, basically generating the waveform portion | |||||
// due only to steps | |||||
// square waves use this directly. | |||||
int32_t BandLimitedWaveform::process_active_steps (uint32_t new_phase) | |||||
{ | |||||
int32_t sample = dc_offset ; | |||||
int step_count = (newptr - delptr) & PTRMASK ; | |||||
if (step_count > 0) // for any steps in-flight we sum in table entry and update its state | |||||
{ | |||||
int i = newptr ; | |||||
do | |||||
{ | |||||
i = (i-1) & PTRMASK ; | |||||
sample += process_step (i) ; | |||||
} while (i != delptr) ; | |||||
if (states[delptr].offset >= N<<GUARD_BITS) // remove any finished entries from the buffer. | |||||
{ | |||||
delptr = (delptr+1) & PTRMASK ; | |||||
// can be upto two steps per sample now for pulses | |||||
if (newptr != delptr && states[delptr].offset >= N<<GUARD_BITS) | |||||
delptr = (delptr+1) & PTRMASK ; | |||||
} | |||||
} | |||||
return sample ; | |||||
} | |||||
// for sawtooth need to add in the slope and compensate for all the steps being one way | |||||
int32_t BandLimitedWaveform::process_active_steps_saw (uint32_t new_phase) | |||||
{ | |||||
int32_t sample = process_active_steps (new_phase) ; | |||||
sample += (int16_t) ((((uint64_t)phase_word * (2*BASE_AMPLITUDE)) >> 32) - BASE_AMPLITUDE) ; // generate the sloped part of the wave | |||||
if (new_phase < DEG180 && phase_word >= DEG180) // detect wrap around, correct dc offset | |||||
dc_offset += 2*BASE_AMPLITUDE ; | |||||
return sample ; | |||||
} | |||||
// for pulse need to adjust the baseline according to the pulse width to cancel the DC component. | |||||
int32_t BandLimitedWaveform::process_active_steps_pulse (uint32_t new_phase, uint32_t pulse_width) | |||||
{ | |||||
int32_t sample = process_active_steps (new_phase) ; | |||||
return sample + BASE_AMPLITUDE/2 - pulse_width / (0x80000000u / BASE_AMPLITUDE) ; // correct DC offset for duty cycle | |||||
} | |||||
// Check for new steps using the phase update for the current sample for a square wave | |||||
void BandLimitedWaveform::new_step_check_square (uint32_t new_phase, int i) | |||||
{ | |||||
if (new_phase >= DEG180 && phase_word < DEG180) // detect falling step | |||||
{ | |||||
int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (sampled_width - phase_word) / (new_phase - phase_word)) ; | |||||
if (offset == SCALE<<GUARD_BITS) | |||||
offset -- ; | |||||
if (pulse_state) // guard against two falling steps in a row (if pulse width changing for instance) | |||||
{ | |||||
insert_step (- offset, false, i) ; | |||||
pulse_state = false ; | |||||
} | |||||
} | |||||
else if (new_phase < DEG180 && phase_word >= DEG180) // detect wrap around, rising step | |||||
{ | |||||
int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (- phase_word) / (new_phase - phase_word)) ; | |||||
if (offset == SCALE<<GUARD_BITS) | |||||
offset -- ; | |||||
if (!pulse_state) // guard against two rising steps in a row (if pulse width changing for instance) | |||||
{ | |||||
insert_step (- offset, true, i) ; | |||||
pulse_state = true ; | |||||
} | |||||
} | |||||
} | |||||
// Checking for new steps for pulse waveform has to deal with changing frequency and pulse width and | |||||
// not letting a pulse glitch out of existence as these change across a single period of the waveform | |||||
// now we detect the rising edge just like for a square wave and use that to sample the pulse width | |||||
// parameter, which then has to be checked against the instantaneous frequency every sample. | |||||
void BandLimitedWaveform::new_step_check_pulse (uint32_t new_phase, uint32_t pulse_width, int i) | |||||
{ | |||||
if (pulse_state && phase_word < sampled_width && (new_phase >= sampled_width || new_phase < phase_word)) // falling edge | |||||
{ | |||||
int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (sampled_width - phase_word) / (new_phase - phase_word)) ; | |||||
if (offset == SCALE<<GUARD_BITS) | |||||
offset -- ; | |||||
insert_step (- offset, false, i) ; | |||||
pulse_state = false ; | |||||
} | |||||
if ((!pulse_state) && phase_word >= DEG180 && new_phase < DEG180) // detect wrap around, rising step | |||||
{ | |||||
// sample the pulse width value so its not changing under our feet later in cycle due to modulation | |||||
sampled_width = pulse_width ; | |||||
int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (- phase_word) / (new_phase - phase_word)) ; | |||||
if (offset == SCALE<<GUARD_BITS) | |||||
offset -- ; | |||||
insert_step (- offset, true, i) ; | |||||
pulse_state = true ; | |||||
if (pulse_state && new_phase >= sampled_width) // detect falling step directly after a rising edge | |||||
//if (new_phase - sampled_width < DEG180) // detect falling step directly after a rising edge | |||||
{ | |||||
int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (sampled_width - phase_word) / (new_phase - phase_word)) ; | |||||
if (offset == SCALE<<GUARD_BITS) | |||||
offset -- ; | |||||
insert_step (- offset, false, i) ; | |||||
pulse_state = false ; | |||||
} | |||||
} | |||||
} | |||||
// new steps for sawtooth are at 180 degree point, always falling. | |||||
void BandLimitedWaveform::new_step_check_saw (uint32_t new_phase, int i) | |||||
{ | |||||
if (new_phase >= DEG180 && phase_word < DEG180) // detect falling step | |||||
{ | |||||
int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (DEG180 - phase_word) / (new_phase - phase_word)) ; | |||||
if (offset == SCALE<<GUARD_BITS) | |||||
offset -- ; | |||||
insert_step (- offset, false, i) ; | |||||
} | |||||
} | |||||
// the generation function pushd new sample into cyclic buffer, having taken out the oldest entry | |||||
// to return. The output is thus 16 samples behind, which allows the non-casual step function to | |||||
// work in real time. | |||||
int16_t BandLimitedWaveform::generate_sawtooth (uint32_t new_phase, int i) | |||||
{ | |||||
new_step_check_saw (new_phase, i) ; | |||||
int32_t val = process_active_steps_saw (new_phase) ; | |||||
int16_t sample = (int16_t) cyclic [i&15] ; | |||||
cyclic [i&15] = val ; | |||||
phase_word = new_phase ; | |||||
return sample ; | |||||
} | |||||
int16_t BandLimitedWaveform::generate_square (uint32_t new_phase, int i) | |||||
{ | |||||
new_step_check_square (new_phase, i) ; | |||||
int32_t val = process_active_steps (new_phase) ; | |||||
int16_t sample = (int16_t) cyclic [i&15] ; | |||||
cyclic [i&15] = val ; | |||||
phase_word = new_phase ; | |||||
return sample ; | |||||
} | |||||
int16_t BandLimitedWaveform::generate_pulse (uint32_t new_phase, uint32_t pulse_width, int i) | |||||
{ | |||||
new_step_check_pulse (new_phase, pulse_width, i) ; | |||||
int32_t val = process_active_steps_pulse (new_phase, pulse_width) ; | |||||
int32_t sample = cyclic [i&15] ; | |||||
cyclic [i&15] = val ; | |||||
phase_word = new_phase ; | |||||
return (int16_t) ((sample >> 1) - (sample >> 5)) ; // scale down to avoid overflow on narrow pulses, where the DC shift is big | |||||
} | |||||
void BandLimitedWaveform::init_sawtooth (uint32_t freq_word) | |||||
{ | |||||
phase_word = 0 ; | |||||
newptr = 0 ; | |||||
delptr = 0 ; | |||||
for (int i = 0 ; i < 2*SUPPORT ; i++) | |||||
phase_word -= freq_word ; | |||||
dc_offset = phase_word < DEG180 ? BASE_AMPLITUDE : -BASE_AMPLITUDE ; | |||||
for (int i = 0 ; i < 2*SUPPORT ; i++) | |||||
{ | |||||
uint32_t new_phase = phase_word + freq_word ; | |||||
new_step_check_saw (new_phase, i) ; | |||||
cyclic [i & 15] = (int16_t) process_active_steps_saw (new_phase) ; | |||||
phase_word = new_phase ; | |||||
} | |||||
} | |||||
void BandLimitedWaveform::init_square (uint32_t freq_word) | |||||
{ | |||||
init_pulse (freq_word, DEG180) ; | |||||
} | |||||
void BandLimitedWaveform::init_pulse (uint32_t freq_word, uint32_t pulse_width) | |||||
{ | |||||
phase_word = 0 ; | |||||
sampled_width = pulse_width ; | |||||
newptr = 0 ; | |||||
delptr = 0 ; | |||||
for (int i = 0 ; i < 2*SUPPORT ; i++) | |||||
phase_word -= freq_word ; | |||||
if (phase_word < pulse_width) | |||||
{ | |||||
dc_offset = BASE_AMPLITUDE ; | |||||
pulse_state = true ; | |||||
} | |||||
else | |||||
{ | |||||
dc_offset = -BASE_AMPLITUDE ; | |||||
pulse_state = false ; | |||||
} | |||||
for (int i = 0 ; i < 2*SUPPORT ; i++) | |||||
{ | |||||
uint32_t new_phase = phase_word + freq_word ; | |||||
new_step_check_pulse (new_phase, pulse_width, i) ; | |||||
cyclic [i & 15] = (int16_t) process_active_steps_pulse (new_phase, pulse_width) ; | |||||
phase_word = new_phase ; | |||||
} | |||||
} | |||||
BandLimitedWaveform::BandLimitedWaveform() | |||||
{ | |||||
newptr = 0 ; | |||||
delptr = 0 ; | |||||
dc_offset = BASE_AMPLITUDE ; | |||||
phase_word = 0 ; | |||||
} |
#define WAVEFORM_SAWTOOTH_REVERSE 6 | #define WAVEFORM_SAWTOOTH_REVERSE 6 | ||||
#define WAVEFORM_SAMPLE_HOLD 7 | #define WAVEFORM_SAMPLE_HOLD 7 | ||||
#define WAVEFORM_TRIANGLE_VARIABLE 8 | #define WAVEFORM_TRIANGLE_VARIABLE 8 | ||||
#define WAVEFORM_BANDLIMIT_SAWTOOTH 9 | |||||
#define WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE 10 | |||||
#define WAVEFORM_BANDLIMIT_SQUARE 11 | |||||
#define WAVEFORM_BANDLIMIT_PULSE 12 | |||||
typedef struct step_state | |||||
{ | |||||
int offset ; | |||||
bool positive ; | |||||
} step_state ; | |||||
class BandLimitedWaveform | |||||
{ | |||||
public: | |||||
BandLimitedWaveform (void) ; | |||||
int16_t generate_sawtooth (uint32_t new_phase, int i) ; | |||||
int16_t generate_square (uint32_t new_phase, int i) ; | |||||
int16_t generate_pulse (uint32_t new_phase, uint32_t pulse_width, int i) ; | |||||
void init_sawtooth (uint32_t freq_word) ; | |||||
void init_square (uint32_t freq_word) ; | |||||
void init_pulse (uint32_t freq_word, uint32_t pulse_width) ; | |||||
private: | |||||
int32_t lookup (int offset) ; | |||||
void insert_step (int offset, bool rising, int i) ; | |||||
int32_t process_step (int i) ; | |||||
int32_t process_active_steps (uint32_t new_phase) ; | |||||
int32_t process_active_steps_saw (uint32_t new_phase) ; | |||||
int32_t process_active_steps_pulse (uint32_t new_phase, uint32_t pulse_width) ; | |||||
void new_step_check_square (uint32_t new_phase, int i) ; | |||||
void new_step_check_pulse (uint32_t new_phase, uint32_t pulse_width, int i) ; | |||||
void new_step_check_saw (uint32_t new_phase, int i) ; | |||||
uint32_t phase_word ; | |||||
int32_t dc_offset ; | |||||
step_state states [32] ; // circular buffer of active steps | |||||
int newptr ; // buffer pointers into states, AND'd with PTRMASK to keep in buffer range. | |||||
int delptr ; | |||||
int32_t cyclic[16] ; // circular buffer of output samples | |||||
bool pulse_state ; | |||||
uint32_t sampled_width ; // pulse width is sampled once per waveform | |||||
}; | |||||
class AudioSynthWaveform : public AudioStream | class AudioSynthWaveform : public AudioStream | ||||
{ | { | ||||
void begin(short t_type) { | void begin(short t_type) { | ||||
phase_offset = 0; | phase_offset = 0; | ||||
tone_type = t_type; | tone_type = t_type; | ||||
if (t_type == WAVEFORM_BANDLIMIT_SQUARE) | |||||
band_limit_waveform.init_square (phase_increment) ; | |||||
else if (t_type == WAVEFORM_BANDLIMIT_PULSE) | |||||
band_limit_waveform.init_pulse (phase_increment, pulse_width) ; | |||||
else if (t_type == WAVEFORM_BANDLIMIT_SAWTOOTH || t_type == WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE) | |||||
band_limit_waveform.init_sawtooth (phase_increment) ; | |||||
} | } | ||||
void begin(float t_amp, float t_freq, short t_type) { | void begin(float t_amp, float t_freq, short t_type) { | ||||
amplitude(t_amp); | amplitude(t_amp); | ||||
frequency(t_freq); | frequency(t_freq); | ||||
phase_offset = 0; | phase_offset = 0; | ||||
tone_type = t_type; | |||||
begin (t_type); | |||||
} | } | ||||
void arbitraryWaveform(const int16_t *data, float maxFreq) { | void arbitraryWaveform(const int16_t *data, float maxFreq) { | ||||
arbdata = data; | arbdata = data; | ||||
int16_t sample; // for WAVEFORM_SAMPLE_HOLD | int16_t sample; // for WAVEFORM_SAMPLE_HOLD | ||||
short tone_type; | short tone_type; | ||||
int16_t tone_offset; | int16_t tone_offset; | ||||
BandLimitedWaveform band_limit_waveform ; | |||||
}; | }; | ||||
} | } | ||||
void begin(short t_type) { | void begin(short t_type) { | ||||
tone_type = t_type; | tone_type = t_type; | ||||
if (t_type == WAVEFORM_BANDLIMIT_SQUARE) | |||||
band_limit_waveform.init_square (phase_increment) ; | |||||
else if (t_type == WAVEFORM_BANDLIMIT_PULSE) | |||||
band_limit_waveform.init_pulse (phase_increment, 0x80000000u) ; | |||||
else if (t_type == WAVEFORM_BANDLIMIT_SAWTOOTH || t_type == WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE) | |||||
band_limit_waveform.init_sawtooth (phase_increment) ; | |||||
} | } | ||||
void begin(float t_amp, float t_freq, short t_type) { | void begin(float t_amp, float t_freq, short t_type) { | ||||
amplitude(t_amp); | amplitude(t_amp); | ||||
frequency(t_freq); | frequency(t_freq); | ||||
tone_type = t_type; | |||||
begin (t_type) ; | |||||
} | } | ||||
void arbitraryWaveform(const int16_t *data, float maxFreq) { | void arbitraryWaveform(const int16_t *data, float maxFreq) { | ||||
arbdata = data; | arbdata = data; | ||||
int16_t tone_offset; | int16_t tone_offset; | ||||
uint8_t tone_type; | uint8_t tone_type; | ||||
uint8_t modulation_type; | uint8_t modulation_type; | ||||
BandLimitedWaveform band_limit_waveform ; | |||||
}; | }; | ||||