/*
"Tri-Shape", a wave shaping oscilatorfor Ginkosynthese's "grains" module.
By Kassen Oud
LICENSE:
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
DESCRIPION;
A triangle-based osclitator with wave-folding and hard-clipping features.
MANUAL;
Knob 1 / mod 1; Wave folding
Amplifies the base triangle wave, then once it hits the limits of the
range "folds" it back in the opposite direction. With enough
amplification this will happen again at the other side, creating a
rich spectrum.
Knob 2/ mod 2; Hard Cliping
Amplifies the signal (after the folding) and clips the result. This is
done asymetrically for a "deeper" and more "balsy" sound. Thanks to
Rob Bothof for that trick.
Knob 3: Base Tuning.
Sets the base pitch.
Mod 3; Pitch Modulation
This CV gets added to the value set by Knob 3.
*/
//the libraries we use
#include
#include
#include
//variables
uint16_t phase_accumulator; //keeps track of the phase
uint16_t phase_inc; //phase increase per sample
bool flip = false; //keeps track of the output's polarity
uint16_t wrap = 1; // amount of wave-folding
uint16_t drive = 32; //amount of clipping for positive signal
uint16_t top_drive = 32; //same for negative signal
uint16_t output = 127; //the value we write out
uint16_t last_out = 127; //last value we wrote out
// Map inputs
#define DRIVE_CONTROL (A1)
#define WRAP_CONTROL (A2)
#define PITCH_KNOB (A0)
#define PITCH_CV (A3)
// Changing these will also requires rewriting setup()
// Output is on pin 11
#define PWM_PIN 11
#define PWM_VALUE OCR2A
#define LED_PORT PORTB
#define LED_BIT 5
#define PWM_INTERRUPT TIMER2_OVF_vect
//maps cv to samples of phase increase each time we output a new value
//this might need tuning in the future
const uint16_t freqTable[] PROGMEM = {
69, 69, 69, 69, 70, 70, 70, 70, 70, 71, // 0 to 9
71, 71, 71, 72, 72, 72, 72, 73, 73, 73, //
73, 74, 74, 74, 74, 75, 75, 75, 75, 76, //
76, 76, 76, 77, 77, 77, 77, 78, 78, 78, //
78, 79, 79, 79, 79, 80, 80, 80, 81, 81, //
81, 81, 82, 82, 82, 82, 83, 83, 83, 84, //
84, 84, 84, 85, 85, 85, 86, 86, 86, 86, //
87, 87, 87, 88, 88, 88, 88, 89, 89, 89, //
90, 90, 90, 91, 91, 91, 91, 92, 92, 92, //
93, 93, 93, 94, 94, 94, 95, 95, 95, 96, //
96, 96, 97, 97, 97, 97, 98, 98, 98, 99, // 100 to 109
99, 99, 100, 100, 100, 101, 101, 101, 102, 102, //
102, 103, 103, 104, 104, 104, 105, 105, 105, 106, //
106, 106, 107, 107, 107, 108, 108, 109, 109, 109, //
110, 110, 110, 111, 111, 111, 112, 112, 113, 113, //
113, 114, 114, 114, 115, 115, 116, 116, 116, 117, //
117, 118, 118, 118, 119, 119, 120, 120, 120, 121, //
121, 122, 122, 122, 123, 123, 124, 124, 124, 125, //
125, 126, 126, 127, 127, 127, 128, 128, 129, 129, //
130, 130, 130, 131, 131, 132, 132, 133, 133, 134, //
134, 134, 135, 135, 136, 136, 137, 137, 138, 138, // 200 to 209
139, 139, 139, 140, 140, 141, 141, 142, 142, 143, //
143, 144, 144, 145, 145, 146, 146, 147, 147, 148, //
148, 149, 149, 150, 150, 151, 151, 152, 152, 153, //
153, 154, 154, 155, 155, 156, 156, 157, 157, 158, //
158, 159, 159, 160, 161, 161, 162, 162, 163, 163, //
164, 164, 165, 165, 166, 167, 167, 168, 168, 169, //
169, 170, 171, 171, 172, 172, 173, 173, 174, 175, //
175, 176, 176, 177, 178, 178, 179, 179, 180, 181, //
181, 182, 182, 183, 184, 184, 185, 185, 186, 187, //
187, 188, 189, 189, 190, 190, 191, 192, 192, 193, // 300 to 309
194, 194, 195, 196, 196, 197, 198, 198, 199, 200, //
200, 201, 202, 202, 203, 204, 204, 205, 206, 206, //
207, 208, 208, 209, 210, 211, 211, 212, 213, 213, //
214, 215, 216, 216, 217, 218, 218, 219, 220, 221, //
221, 222, 223, 224, 224, 225, 226, 227, 227, 228, //
229, 230, 231, 231, 232, 233, 234, 234, 235, 236, //
237, 238, 238, 239, 240, 241, 242, 242, 243, 244, //
245, 246, 246, 247, 248, 249, 250, 251, 251, 252, //
253, 254, 255, 256, 257, 257, 258, 259, 260, 261, //
262, 263, 264, 264, 265, 266, 267, 268, 269, 270, // 400 to 409
271, 272, 273, 273, 274, 275, 276, 277, 278, 279, //
280, 281, 282, 283, 284, 285, 286, 287, 288, 288, //
289, 290, 291, 292, 293, 294, 295, 296, 297, 298, //
299, 300, 301, 302, 303, 304, 305, 306, 307, 308, //
310, 311, 312, 313, 314, 315, 316, 317, 318, 319, //
320, 321, 322, 323, 324, 325, 327, 328, 329, 330, //
331, 332, 333, 334, 335, 337, 338, 339, 340, 341, //
342, 343, 345, 346, 347, 348, 349, 350, 352, 353, //
354, 355, 356, 357, 359, 360, 361, 362, 363, 365, //
366, 367, 368, 370, 371, 372, 373, 375, 376, 377, // 500 to 509
378, 380, 381, 382, 383, 385, 386, 387, 389, 390, //
391, 393, 394, 395, 397, 398, 399, 401, 402, 403, //
405, 406, 407, 409, 410, 411, 413, 414, 416, 417, //
418, 420, 421, 423, 424, 425, 427, 428, 430, 431, //
433, 434, 436, 437, 438, 440, 441, 443, 444, 446, //
447, 449, 450, 452, 453, 455, 456, 458, 460, 461, //
463, 464, 466, 467, 469, 470, 472, 474, 475, 477, //
478, 480, 482, 483, 485, 486, 488, 490, 491, 493, //
495, 496, 498, 500, 501, 503, 505, 506, 508, 510, //
511, 513, 515, 517, 518, 520, 522, 524, 525, 527, // 600 to 609
529, 531, 532, 534, 536, 538, 540, 541, 543, 545, //
547, 549, 551, 552, 554, 556, 558, 560, 562, 564, //
566, 567, 569, 571, 573, 575, 577, 579, 581, 583, //
585, 587, 589, 591, 593, 595, 597, 599, 601, 603, //
605, 607, 609, 611, 613, 615, 617, 619, 621, 623, //
625, 627, 630, 632, 634, 636, 638, 640, 642, 644, //
647, 649, 651, 653, 655, 658, 660, 662, 664, 666, //
669, 671, 673, 675, 678, 680, 682, 685, 687, 689, //
691, 694, 696, 698, 701, 703, 705, 708, 710, 713, //
715, 717, 720, 722, 725, 727, 729, 732, 734, 737, // 700 to 709
739, 742, 744, 747, 749, 752, 754, 757, 759, 762, //
764, 767, 770, 772, 775, 777, 780, 783, 785, 788, //
791, 793, 796, 799, 801, 804, 807, 809, 812, 815, //
817, 820, 823, 826, 828, 831, 834, 837, 840, 842, //
845, 848, 851, 854, 857, 860, 862, 865, 868, 871, //
874, 877, 880, 883, 886, 889, 892, 895, 898, 901, //
904, 907, 910, 913, 916, 919, 922, 925, 928, 932, //
935, 938, 941, 944, 947, 950, 954, 957, 960, 963, //
966, 970, 973, 976, 979, 983, 986, 989, 993, 996, //
999,1003,1006,1009,1013,1016,1020,1023,1027,1030, // 800 to 809
1033,1037,1040,1044,1047,1051,1054,1058,1061,1065, //
1069,1072,1076,1079,1083,1087,1090,1094,1098,1101, //
1105,1109,1112,1116,1120,1124,1127,1131,1135,1139, //
1143,1146,1150,1154,1158,1162,1166,1170,1174,1178, //
1182,1186,1189,1193,1197,1201,1206,1210,1214,1218, //
1222,1226,1230,1234,1238,1242,1247,1251,1255,1259, //
1263,1268,1272,1276,1280,1285,1289,1293,1298,1302, //
1306,1311,1315,1320,1324,1328,1333,1337,1342,1346, //
1351,1355,1360,1365,1369,1374,1378,1383,1388,1392, //
1397,1402,1406,1411,1416,1421,1425,1430,1435,1440, // 900 to 909
1444,1449,1454,1459,1464,1469,1474,1479,1484,1489, //
1494,1499,1504,1509,1514,1519,1524,1529,1534,1539, //
1545,1550,1555,1560,1565,1571,1576,1581,1587,1592, //
1597,1603,1608,1613,1619,1624,1630,1635,1641,1646, //
1652,1657,1663,1668,1674,1679,1685,1691,1696,1702, //
1708,1714,1719,1725,1731,1737,1742,1748,1754,1760, //
1766,1772,1778,1784,1790,1796,1802,1808,1814,1820, //
1826,1832,1838,1845,1851,1857,1863,1869,1876,1882, //
1888,1895,1901,1907,1914,1920,1927,1933,1940,1946, //
1953,1959,1966,1972,1979,1986,1992,1999,2006,2012, // 1000 to 1009
2019,2026,2033,2040,2046,2053,2060,2067,2074,2081, // 1010 to 1019
2088,2095,2102,2109 , // 1020 to 1023
};
uint16_t mapFreq(uint16_t input)
{
return pgm_read_word_near(freqTable + input);
}
//sets up pins and configures the samplerate and frequency of the PWM output
void setup()
{
TCCR2A = _BV(COM2A1) | _BV(WGM20);
TCCR2B = _BV(CS20);
TIMSK2 = _BV(TOIE2);
pinMode(PWM_PIN,OUTPUT);
PWM_VALUE = 127;
}
//reads modulation inputs
void loop()
{
//calculate the pitch
int pwmv = min( 1023, analogRead(PITCH_CV) + analogRead(PITCH_KNOB));
//look up the phase increase per sample
phase_inc = mapFreq(pwmv);
//read the control for wave-folding
wrap = min( 64 + (analogRead(WRAP_CONTROL) >> 1), 511);
//read the control for clipping and calculate the two amounts of overdrive
drive = min( 32 + (analogRead(DRIVE_CONTROL) >> 1), 511);
top_drive = max( 32, drive >>1);
}
//Actual sound generation happens here.
//This involves rather a lot of bitwise operations, if you're looking to get
//into writing code for the Grains I'd suggest not starting here; "PWM-Saw" is
//far more "friendly". That's a nice way of saying "Here be Dragons".
//I'm writing numbers out as literal trains of 0's and 1's because we make fair
//ampount of use of those. Also note that a lot of the structure for this is
//caused by avoiding signed integers, while we do want a symetrical signal.
//Hence; we treat it as a unipolar signal, keep track of the polarity it should
//be and apply that at the end.
//I drew the process out on graph paper using multicoloured fineliner.
//If you're serious about following all of this that might help.
SIGNAL(PWM_INTERRUPT)
{
//increase the phase
phase_accumulator += phase_inc;
//2nd half of the phase will be the negative part of the cycle
flip = phase_accumulator & 0b1000000000000000;
//turn the phase acumulator into 4 up-ramps
output = (phase_accumulator & 0b0011111111111111);
//get these into 7 bit range. "flip" will be the 8th bit of the output
output = output >> 7;
//invert the 2nd and 4th of our 4 up-ramps to create our triangle wave
if (phase_accumulator & 0b0100000000000000) output = (uint16_t)127 - output;
//amplify the signal for the wave-wrapping
output *= wrap;
output = output >> 6;
//detect whether folding will be more involved than inverting the range
//from 128 to 254
if (output & 0b1111111100000000)
{
//values between 255 and 511 fold back past the "0" line
if (output & 0b0000000100000000) flip = !flip;
//mask out bits beyond which the process just repeats
output &= 0b0000000011111111;
}
//actual folding
if (output > (uint16_t)127)
{
output = 127 - (output & 0b0000000001111111);
}
//apply the signal gain for asymetrical clipping
output *= flip?drive:top_drive;
output = output >> 5;
//clip
if (output > (uint16_t)127) output = (uint16_t)127;
//turn our 7bit unipolar value into a 8bit bipolar one
if ( flip ) output = (uint16_t)127 - output;
else output += (uint16_t)127;
//slight amount of smoothing
output = (output + last_out) >> 1;
last_out = output;
//write out the output
PWM_VALUE = output;
}