catdogmouse tvout

master
Slayr 5 years ago
commit 8f306b1bda

@ -0,0 +1,137 @@
/*
* good old starfield
*
* The way this one works is by first filling the screen with pixels at
* random coordinates. Then at each frame we calculate the new position of
* each pixel as if it was going away from the center of the screen. When a
* pixel is going off screen, it is reassigned at a new random position.
* To simulate a bit of depth, some pixels move twice as fast.
*
* Limitations: all the pixels/stars coordinates are stored in float arrays.
* Each float is 4 bytes in size (32 bits) and the Nano has 2 KB of SRAM.
* For each pixel/star we need to store 4 floats: x, y, vx, vy. That's
* 16 bytes per pixel/star, so we should be able to store quite few.
* However, the SRAM is already used by other parts of the code, and TVout.
* In practice with the current implementation, there's just enough free
* memory left for 25 pixels/stars :(
*
* See starfield51 for a modification that allows to have 51 stars :)
*/
#include <TVout.h>
TVout TV;
#define STARS 25
float x[STARS]; // x coordinates of all the stars
float y[STARS]; // y coordinates of all the stars
float vx[STARS]; // vx and vy are the increments that we add to x
float vy[STARS]; // and y at each frame to get the x,y position
/*
* new_star(i) generates the x, y, vx, and vy values for star i
* x is generated at random x-axis position around the centre
* y is generated at random y-axis position around the centre
* we calculate the distances dx and dy from the screen center ox,oy
* (we cheat a bit to make sure no 0 are left in a division later on)
* we use dx and dy to calculte the distance vl between the star
* and the center, ie the magnitude of the vector (center, star)
* we use the magnitude to normalize the vector, namely calculating
* the normalized components vx and vy
*/
void
new_star(uint8_t i)
{
uint8_t ox = 60;
uint8_t oy = 48;
float dx, dy, vl;
x[i] = 30 + random(60);
y[i] = 24 + random(48);
dx = x[i] - ox;
dy = y[i] - oy;
switch(int(dx))
case 0: dx = 1; // CHEAT
vl = sqrt(dx*dx + dy*dy);
vx[i] = dx / vl;
vy[i] = dy / vl;
}
/*
* new_stars() creates as many stars as set by the STARS constant
*/
void
new_stars()
{
for (uint8_t i = 0; i < STARS; i++)
new_star(i);
}
/*
* Nothing exciting here, we initialize the PRNG with some noise,
* configure TV out, and generate coordinates for all stars.
*/
void
setup()
{
randomSeed(analogRead(6)); // effective?
TV.begin(NTSC,120,96);
new_stars();
}
/*
* update_stars() goes through all the x and y values and update
* them in such a way that:
* new x = current x + vx
* new y = current y + vy
* we also test if the new coordinates of the star are still in the
* visible part of the screen, and if not, we call new_star() to
* generate new x, y, vx, vy all over again
* Note: fancy effect, the first 20 stars are updated with regular
* vx and vy values, while the last 5 are a updated with 2 times vx and vy,
* which means that these 5 last stars will move twice the speed.
*/
void
update_stars()
{
for (uint8_t i = 0; i < 20; i++) {
x[i] = x[i] + vx[i];
y[i] = y[i] + vy[i];
if (x[i] > 120 || x[i] < 0 || y[i] < 0 || y[i] > 96)
new_star(i);
}
for (uint8_t i = 20; i < STARS; i++) {
x[i] = x[i] + vx[i] * 2;
y[i] = y[i] + vy[i] * 2;
if (x[i] > 120 || x[i] < 0 || y[i] < 0 || y[i] > 96)
new_star(i);
}
}
/*
* draw_stars() walks through the x and y coordinates arrays and
* uses the value to draw a pixel for each star
*/
void
draw_stars()
{
for (uint8_t i = 0; i < STARS; i++)
TV.set_pixel(x[i], y[i], 1);
}
/*
* loop() is stuck doing the same stuff forever because it dared to trick
* the gods...
*/
void
loop()
{
TV.delay_frame(1);
update_stars();
TV.clear_screen();
draw_stars();
}

@ -0,0 +1,107 @@
/*
* good old starfield - PASTIS 51 EDITION + CAPTAIN MOD
*
* Same as starfield51 but this time we can control the origin with POT 1 and
* POT2, which affects all the newly created stars, allowing for deep space
* travel.
*
* Really not optimised in current state, even though I tried to simplify things.
* But it starts to push the chip beyond its capacity, so it feels a bit sluggish now.
* More changes would start to make the thing even less readable so...
*/
#include <TVout.h>
TVout TV;
#define STARS 51
#define POT_1 0
#define POT_2 1
#define POT_1_MOD 11 // 120/1024 ish int(0.1171875 * 100)
#define POT_2_MOD 9 // 96/1024 ish
#define RND_1_MOD 5 // 60/1024 ish
#define RND_2_MOD 4 // 48/1024 ish
int x[STARS];
int y[STARS];
int vx[STARS];
int vy[STARS];
uint8_t ox;
uint8_t oy;
void
setup()
{
randomSeed(analogRead(6)); // effective?
TV.begin(NTSC,120,96);
new_stars();
}
void
new_star(uint8_t i)
{
uint8_t x_tmp, y_tmp;
int dx, dy, pot1, pot2;
float vl;
pot1 = analogRead(POT_1);
pot2 = analogRead(POT_2);
ox = pot1 * POT_1_MOD / 100 ;
oy = pot2 * POT_2_MOD / 100 ;
x_tmp = pot1 * RND_1_MOD / 100 + random(60);
y_tmp = pot2 * RND_2_MOD / 100 + random(48);
dx = x_tmp - ox;
dy = y_tmp - oy;
switch(dx)
case 0: dx = 1; // CHEAT
vl = 1 / sqrt(dx*dx + dy*dy);
vx[i] = int(dx * vl * 100);
vy[i] = int(dy * vl * 100);
x[i] = x_tmp * 100;
y[i] = y_tmp * 100;
}
void
new_stars()
{
for (uint8_t i = 0; i < STARS; i++)
new_star(i);
}
void
update_stars()
{
for (uint8_t i = 0; i < 40; i++) {
x[i] = x[i] + vx[i];
y[i] = y[i] + vy[i];
if (x[i] > 12000 || x[i] < 0 || y[i] < 0 || y[i] > 9600)
new_star(i);
}
for (uint8_t i = 40; i < STARS; i++) {
x[i] = x[i] + (vx[i] << 1);
y[i] = y[i] + (vy[i] << 1);
if (x[i] > 12000 || x[i] < 0 || y[i] < 0 || y[i] > 9600)
new_star(i);
}
}
void
draw_stars()
{
for (uint8_t i = 0; i < STARS; i++)
TV.set_pixel(x[i]/100, y[i]/100, 1);
}
void
loop()
{
TV.delay_frame(1);
update_stars();
TV.clear_screen();
draw_stars();
}

@ -0,0 +1,112 @@
/*
* good old starfield - PASTIS 51 EDITION
*
* See starfield25 for context and more comments, otherwise it may not make much
* sense...
*
* So basically the trick used to get more stars here, is not to free memory,
* because that's not possible, but instead it's to make the stars use less memory.
* To do that we change the type from float (4 bytes) to int (2 bytes).
* The tradeoff is of course that now we have integers and not floating point numbers,
* and that prevents us to have any meaningful results when we calculate vector related
* stuff. But there's a workaround to this!
* The workaround is very simple, we use int as floats without floating points, which
* means that everytime we read from the array we convert the int to float and divide
* it by an arbitrary precision value (here we use 100), and when we want to store a
* float we multiply it by the same precision value and convert to int.
* We loose in accuray, but that does not matter here at all.
*
* ex: we want to store 12,345678
* 12,3456 * 100 = 1234,56
* int(1234,56) = 1234
* and converted back
* float(1234 / 100) = 12,34
* in the process with this trick we lost 0,005678 (who cares?)
*
* Note: most of the changes are in new_star(). There are some minor changes elsewhere,
* mostly to try optimise things cheaply, ignore.
*/
#include <TVout.h>
TVout TV;
#define STARS 51
int x[STARS];
int y[STARS];
int vx[STARS];
int vy[STARS];
void
setup()
{
randomSeed(analogRead(6)); // effective?
TV.begin(NTSC,120,96);
new_stars();
}
void
new_star(uint8_t i)
{
uint8_t x_tmp, y_tmp;
uint8_t ox = 60;
uint8_t oy = 48;
int dx, dy;
float vl;
x_tmp = 30 + random(60);
y_tmp = 24 + random(48);
dx = x_tmp - ox;
dy = y_tmp - oy;
switch(dx)
case 0: dx = 1; // CHEAT
vl = 1 / sqrt(dx*dx + dy*dy);
vx[i] = int(dx * vl * 100);
vy[i] = int(dy * vl * 100);
x[i] = x_tmp * 100;
y[i] = y_tmp * 100;
}
void
new_stars()
{
for (uint8_t i = 0; i < STARS; i++)
new_star(i);
}
void
update_stars()
{
for (uint8_t i = 0; i < 40; i++) {
x[i] = x[i] + vx[i];
y[i] = y[i] + vy[i];
if (x[i] > 12000 || x[i] < 0 || y[i] < 0 || y[i] > 9600)
new_star(i);
}
for (uint8_t i = 40; i < STARS; i++) {
x[i] = x[i] + (vx[i] << 1);
y[i] = y[i] + (vy[i] << 1);
if (x[i] > 12000 || x[i] < 0 || y[i] < 0 || y[i] > 9600)
new_star(i);
}
}
void
draw_stars()
{
for (uint8_t i = 0; i < STARS; i++)
TV.set_pixel(x[i]/100, y[i]/100, 1);
}
void
loop()
{
TV.delay_frame(1);
update_stars();
TV.clear_screen();
draw_stars();
}

@ -12,7 +12,10 @@
bool triggered; // logic: trigered, yes or no bool triggered; // logic: trigered, yes or no
<<<<<<< HEAD
=======
>>>>>>> 90939591a6ad3754ea764cdcf2a32970a3156486
long randNumber; //variable to store random number long randNumber; //variable to store random number
int pwmPin = 11; //define output pin, Meergranen output pin is 11 int pwmPin = 11; //define output pin, Meergranen output pin is 11
@ -34,17 +37,25 @@ void loop() {
delayMicroseconds(randNumber); //wait for randomNumber (10-100 Mircroseconds (0.00001-0.0001 seconds)) delayMicroseconds(randNumber); //wait for randomNumber (10-100 Mircroseconds (0.00001-0.0001 seconds))
} }
int input3 = digitalRead(A3); // read analog pin 3 // int input3 = digitalRead(A3); // read analog pin 3
int input3 = true;
// trigger // trigger
if(input3 && !triggered) { //if there is a reading on input3 and the bool condition triggered is not true do if(input3 && !triggered) { //if there is a reading on input3 and the bool condition triggered is not true do
Serial.println("I hear a trigger!"); Serial.println("I hear a trigger!");
// DO SOMETHING ON TRIGGER HERE // DO SOMETHING ON TRIGGER HERE
for(int i=0; i<100; i++){
randNumber = random(10, 1000000); //generate random number between 10 and 100
digitalWrite(pwmPin, LOW); //set output pin to LOW (0v)
delayMicroseconds(randNumber);//wait for randomNumber (10-100 Mircroseconds (0.00001-0.0001 seconds))
digitalWrite(pwmPin, HIGH); //set output pin to HIGH (5v)
delayMicroseconds(randNumber); //wait for randomNumber (10-100 Mircroseconds (0.00001-0.0001 seconds))
triggered = true; triggered = true;
}
} }
else if(!input3 && triggered) { //if there is no reading on input3 and condition triggered is true (aka sound is playing), set triggered to false, aka stop playing else if(!input3 && triggered) { //if there is no reading on input3 and condition triggered is true (aka sound is playing), set triggered to false, aka stop playing
// STOP WHEN NO TRIGGER IS PRESENT (or do something else ;) // STOP WHEN NO TRIGGER IS PRESENT (or do something else ;)
triggered = false; triggered = true;
} }
} }

@ -31,6 +31,7 @@ void loop() {
//ATTACK //ATTACK
for(int i=0;i<10;i++){ // i = DELAY+SUSTAIN+RELEASE of ATTACK for(int i=0;i<10;i++){ // i = DELAY+SUSTAIN+RELEASE of ATTACK
analogWrite(11,0); analogWrite(11,0);
tone(11,440,40);
delayMicroseconds(analogRead(A2)*i); // lower the pitch over time delayMicroseconds(analogRead(A2)*i); // lower the pitch over time
analogWrite(11,255); analogWrite(11,255);
delayMicroseconds(analogRead(A2)*i); // lower the pitch over time delayMicroseconds(analogRead(A2)*i); // lower the pitch over time

@ -0,0 +1,21 @@
void setup() {
//int counter = 0;
Serial.begin(9600);
Serial.println("---------------");
//Serial.println(counter);
for(int counter = 0; counter < 10; counter++){
//counter++; [same as counter = counter + 1]
// counter += 1; [same as counter = counter + 1]
Serial.println('a', DEC); // get ascii decimal number value for -- a
Serial.println('HATE');
Serial.println(counter);
}
}
void loop() {
// put your main code here, to run repeatedly:
}

@ -1,265 +0,0 @@
/*
"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 <http://www.gnu.org/licenses/>.
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 <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
//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;
}
Loading…
Cancel
Save