Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

executable file 5449 lines (4568 sloc) 194.665 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448
;-------------------------------------------------------------------------------------------------------------------
; _ _ _
; | | | |(_)
; ____ _____ _____| |__ | | _ ____ ___ _____
; | \| ___ | ___ | _ \| || | _ \ /___) ___ |
; | | | | ____| ____| |_) ) || | |_| | |___ | ____|
; |_|_|_|_____)_____)____/ \_)_| __/ (___/|_____)
; |_|
;
; meeblip se micro - the hackable digital synthesiser
;
; For meeblip micro hardware
;
;-------------------------------------------------------------------------------------------------------------------
;
; Changelog
;
;V2.04 2012.01.05 - Added maximum resonance table
; - Envelopes no longer restart on note off release if they're stopped
; - Replace MUL8X8S routine with hardware multiply
; - Updated LPM calls throughout code
; - Implement 2 byte offsets for all table lookups
; - New bandlimited waveforms with matched average amplitude (Axel Werner)
; - New 32x16 bit multiply, 32 bit load (AW)
; - Use signed multiply in DCA (AW)
; - New oscillator mix routine (AW)
; - New TAB_VCF, TAB_VCA and TIMETORATE tables (AW)
; - Fix envelope decay bug (AW)
;V2.03 2011.12.20 - Added MIDI Velocity to VCF Envelope Modulation
; - Changed maximum resonance and resonance scaling limits
; - Updated oscillator mix levels because of mix clipping
;V2.02 2011.12.12 - Corrected code to save pre-filtered waveform
;V2.01 2011.12.01 - Added inverse sawtooth waveform
; - Fixed wavetable overflow in variable pulse calculation
; - Assign individual switches instead of switch matrix
; - Synthesis engine defaults to MIDI channel 1
; - Enable patch load/save and MIDI save functions (careful with V1 hardware - you have to use the DIP switches)
; - Increase Portamento rate
; - Debugged MIDI CC switch loading routine
; - Removed unnecessary opcodes throughout code
;V2.00 2011.11.23 - Bandlimited pulse and PWM wave built from out-of-phase ramps
; - Bandlimited square, saw and triangle oscillators
; - Patch state engine (independent of front panel controls)
; - New knob scan routine (scans only the most recently converted analog channel)
; - Dual ADSD envelopes
; - PWM sweep switch and PWM rate knob (limited between 0-50% pulse duty cycle)
; - Filter envelop amount knob added
; - MIDI control of all parameters
; - Reorganized front panel
; - MIDI knob and switch CC control
; - DCA gate, LFO sync, modulation wheel and filter key track now always on
; - LFO enable switch added
; - anti-alias switch added - off uses bandlimited wave 0, on uses bandlimited wavetable 0..11, based on note
; - Added variable names for switches instead of using bit ops - allows easier reorganization of panel
; - FM switch - off or 100%
; - New sample rate - 36363.63636 Hz, approximately 440 instructions per sample
;V1.05 2011.02.04 - Save dual parameter knob values to eeprom and reload on power up.
;V1.04 2011.01.19 - MIDI CC RAM table added.
; - PWM waveform with dedicated fixed sweep LFO
; - 8-bit multiplies optimized in main loop
; - LFO Sync switch now retriggers LFO on each keypress
; - Initialize FM Depth to zero on power up
;V1.03 - VCA and VCF level tables extended to reduce stairstepping
;V1.02 - Flip DAC write line high immediately after outputting sample
;V1.01 - Optimized DCOA+DCOB summer, outputs signed value
;V1.00 - Power/MIDI status LED remains on unless receiving MIDI
; - Sustain level of ADSR envelope is exponentially scaled
; - Non-resonant highpass filter implemented
; - Filter Q level compensation moved outside audio sample calc interrupt
; - Filter calculations increased to 16x8-bit to reduce noise floor
; - DCA output level calculations are rounded
; - Mod wheel no longer overrides LFO level knob when less than knob value
;V0.90 - Initial release
;
;-------------------------------------------------------------------------------------------------------------------
;
; MeeBlip Contributors
;
; Jarek Ziembicki - Created the original AVRsynth, upon which this project is based.
; Laurie Biddulph - Worked with Jarek to translate his comments into English, ported to Atmega16
; Daniel Kruszyna - Extended AVRsynth (several of his ideas are incorporated in MeeBlip)
; Julian Schmidt - Original filter algorithm
; Axel Werner - Code optimization, bug fixes and bandlimited waveforms
; James Grahame - Ported and extended the AVRsynth code to MeeBlip hardware.
;
;-------------------------------------------------------------------------------------------------------------------
;
; Port Mapping
;
; PA0..7 8 potentiometers
; PB0-PB4 Control Panel Switches - ROWS
; PB5-PB7 ISP programming header
; PB7 DAC LDAC signal (load both DAC ports synchronously)
; PC0-PC7 DATA port for DAC
; PD0 RxD (MIDI IN)
; PD1 Power ON/MIDI LED
; PD2 Select DAC port A or B
; PD3 DAC Write line
; PD4-PD7 Control Panel Switches - COLUMNS
;
; Timers
;
; Timer0 not used
; Timer1 Time counter: CK/400 --> TCNT1
; Timer2 Sample timer: (CK/8) / 32 --> 36363.63636 Hz
;
;-------------------------------------------------------------------------------------------------------------------

                    .NOLIST
                   ; .INCLUDE "m32def.inc"
                    .LIST
                    .LISTMAC

                    .SET cpu_frequency = 16000000
                    .SET baud_rate = 31250
.SET KBDSCAN = 6250
;
;-------------------------------------------------------------------------------------------------------------------
; V A R I A B L E S & D E F I N I T I O N S
;-------------------------------------------------------------------------------------------------------------------
;registers:

;current phase of DCO A:
.DEF PHASEA_0 = r2
.DEF PHASEA_1 = r3
.DEF PHASEA_2 = r4

;current phase of DCO B:
.DEF PHASEB_0 = r5
.DEF PHASEB_1 = r6
.DEF PHASEB_2 = r7

.DEF ZERO = r8

;DCF:

.def a_L = r9
.def a_H = r10
.def temp_SREG = r11
.def z_L = r18
.def z_H = r19
.def temp = r30
.def temp2 = r31

.DEF OSC_OUT_L = r14 ; pre-filter audio
.DEF OSC_OUT_H = r15

.def LDAC = r16
.def HDAC = r17

;RAM (0060h...025Fh):

                    .DSEG
;MIDI:
MIDIPHASE: .BYTE 1
MIDICHANNEL: .BYTE 1
MIDIDATA0: .BYTE 1
MIDIVELOCITY: .BYTE 1
MIDINOTE: .BYTE 1
MIDINOTEPREV: .BYTE 1 ; buffer for MIDI note
MIDIPBEND_L: .BYTE 1 ;\
MIDIPBEND_H: .BYTE 1 ;/ -32768..+32766

;current sound parameters:
LFOLEVEL: .BYTE 1 ; 0..255
KNOB_SHIFT: .BYTE 1 ; 0= unchanged 255= changed state
POWER_UP: .BYTE 1 ; 255 = Synth just turned on, 0 = normal operation
KNOB0_STATUS: .BYTE 1 ; Each byte corresponds to a panel knob.
KNOB1_STATUS: .BYTE 1 ; 0 = pot not updated since Knob Shift switch change
KNOB2_STATUS: .BYTE 1 ; 1 = pot has been updated.
KNOB3_STATUS: .BYTE 1
KNOB4_STATUS: .BYTE 1
KNOB5_STATUS: .BYTE 1
KNOB6_STATUS: .BYTE 1
KNOB7_STATUS: .BYTE 1

SWITCH1: .BYTE 1
SWITCH2: .BYTE 1
OLD_SWITCH1: .BYTE 1 ; Previous switch values (used to flag switch changes)
OLD_SWITCH2: .BYTE 1


; Switch value currently used (from front panel, MIDI or last loaded patch)
PATCH_SWITCH1: .BYTE 1
  .equ SW_KNOB_SHIFT = 0
  .equ SW_OSC_FM = 1
  .equ SW_LFO_RANDOM = 2
  .equ SW_LFO_WAVE = 3
  .equ SW_FILTER_MODE = 4
  .equ SW_DISTORTION = 5
  .equ SW_LFO_ENABLE = 6
  .equ SW_LFO_DEST = 7

PATCH_SWITCH2: .BYTE 1
  .equ SW_ANTI_ALIAS = 0
  .equ SW_OSCB_OCT = 1
  .equ SW_OSCB_ENABLE = 2
  .equ SW_OSCB_WAVE = 3
  .equ SW_SUSTAIN = 4
  .equ SW_OSCA_NOISE = 5
  .equ SW_PWM_SWEEP = 6
  .equ SW_OSCA_WAVE = 7


SWITCH3: .BYTE 1 ; b0: MIDI SWITCH 1
; b1: MIDI SWITCH 2
; b2: MIDI SWITCH 3
; b3: MIDI SWITCH 4

SETMIDICHANNEL: .BYTE 1 ; selected MIDI channel: 0 for OMNI or 1..15
DETUNEB_FRAC: .BYTE 1 ;\
DETUNEB_INTG: .BYTE 1 ;/ -128,000..+127,996
ATTACKTIME: .BYTE 1 ; 0..255
DECAYTIME: .BYTE 1 ; 0..255
SUSTAINLEVEL: .BYTE 1 ; 0/255
RELEASETIME: .BYTE 1 ; 0..255
ATTACKTIME2: .BYTE 1 ; 0..255
DECAYTIME2: .BYTE 1 ; 0..255
SUSTAINLEVEL2: .BYTE 1 ; 0/255
RELEASETIME2: .BYTE 1 ; 0..255
NOTE_L: .BYTE 1
NOTE_H: .BYTE 1
NOTE_INTG: .BYTE 1
PORTACNT: .BYTE 1 ; 2 / 1 / 0
LPF_I: .BYTE 1
HPF_I: .BYTE 1
LEVEL: .BYTE 1 ; 0..255
PITCH: .BYTE 1 ; 0..96
ADC_CHAN: .BYTE 1 ; 0..7
PREV_ADC_CHAN: .BYTE 1 ; 0..7
ADC_0: .BYTE 1 ; Panel knob values.
ADC_1: .BYTE 1
ADC_2: .BYTE 1
ADC_3: .BYTE 1
ADC_4: .BYTE 1
ADC_5: .BYTE 1
ADC_6: .BYTE 1
ADC_7: .BYTE 1
OLD_ADC_0: .BYTE 1 ; Previous panel knob value
OLD_ADC_1: .BYTE 1
OLD_ADC_2: .BYTE 1
OLD_ADC_3: .BYTE 1
OLD_ADC_4: .BYTE 1
OLD_ADC_5: .BYTE 1
OLD_ADC_6: .BYTE 1
OLD_ADC_7: .BYTE 1
GATE: .BYTE 1 ; 0 / 1
GATEEDGE: .BYTE 1 ; 0 / 1
TPREV_KBD_L: .BYTE 1
TPREV_KBD_H: .BYTE 1
TPREV_L: .BYTE 1
TPREV_H: .BYTE 1
DELTAT_L: .BYTE 1 ;\ Time from former course
DELTAT_H: .BYTE 1 ;/ of the main loop (1 bit = 32 µs)
ENVPHASE: .BYTE 1 ; 0=stop 1=attack 2=decay 3=sustain 4=release
ENV_FRAC_L: .BYTE 1
ENV_FRAC_H: .BYTE 1
ENV_INTEGR: .BYTE 1
ENVPHASE2: .BYTE 1 ; 0=stop 1=attack 2=decay 3=sustain 4=release
ENV_FRAC_L2: .BYTE 1
ENV_FRAC_H2: .BYTE 1
ENV_INTEGR2: .BYTE 1
VELOCITY_ENVMOD: .BYTE 1

LFOPHASE: .BYTE 1 ; 0=up 1=down
LFO_FRAC_L: .BYTE 1 ;\
LFO_FRAC_H: .BYTE 1 ; > -128,000..+127,999
LFO_INTEGR: .BYTE 1 ;/
LFOVALUE: .BYTE 1 ; -128..+127
LFO2PHASE: .BYTE 1 ; 0=up 1=down
LFO2_FRAC_L: .BYTE 1 ;\
LFO2_FRAC_H: .BYTE 1 ; > -128,000..+127,999
LFO2_INTEGR: .BYTE 1 ;/
LFO2VALUE: .BYTE 1 ; -128..+127
OLDWAVEA: .BYTE 1
OLDWAVEB: .BYTE 1
SHIFTREG_0: .BYTE 1 ;\
SHIFTREG_1: .BYTE 1 ; > shift register for
SHIFTREG_2: .BYTE 1 ;/ pseudo-random generator
LFOBOTTOM_0: .BYTE 1 ;\
LFOBOTTOM_1: .BYTE 1 ; > bottom level of LFO
LFOBOTTOM_2: .BYTE 1 ;/
LFOTOP_0: .BYTE 1 ;\
LFOTOP_1: .BYTE 1 ; > top level of LFO
LFOTOP_2: .BYTE 1 ;/
LFO2BOTTOM_0: .BYTE 1 ;\
LFO2BOTTOM_1: .BYTE 1 ; > bottom level of LFO2
LFO2BOTTOM_2: .BYTE 1 ;/
LFO2TOP_0: .BYTE 1 ;\
LFO2TOP_1: .BYTE 1 ; > top level of LFO2
LFO2TOP_2: .BYTE 1 ;/
DCOA_LEVEL: .BYTE 1
DCOB_LEVEL: .BYTE 1
KNOB_DEADZONE: .BYTE 1

; increase phase for DCO A
DELTAA_0: .byte 1
DELTAA_1: .byte 1
DELTAA_2: .byte 1

; increase phase for DCO B
DELTAB_0: .byte 1
DELTAB_1: .byte 1
DELTAB_2: .byte 1

; Wavetable select
WAVETABLE_A: .byte 1 ; Bandlimited wavetable 0..11
WAVETABLE_B: .byte 1 ; Bandlimited wavetable 0..11

; oscillator pulse width
PULSE_WIDTH: .byte 1
PULSE_KNOB_LIMITED: .byte 1

; fm
WAVEB: .byte 1
FMDEPTH: .byte 1

; eeprom
WRITE_MODE: .byte 1
WRITE_OFFSET: .byte 1 ; byte 0..15 of the patch
WRITE_PATCH_OFFSET: .byte 1 ; start of patch in eeprom

; filter
SCALED_RESONANCE: .byte 1
b_L: .byte 1
b_H: .byte 1
VCF_STATUS: .byte 1 ; 0 indicates VCF off, 1 = on

;-------------------------------------------------------------------------------------------------------------------
; MIDI Control Change parameter table
;-------------------------------------------------------------------------------------------------------------------
;
; MIDI CC parameters with an offset from MIDICC. They are automatically
; stored for use, just use the variable name to access their value.
 

MIDICC: .byte $80
  .equ MIDIMODWHEEL = MIDICC + $01

    ; Unshifted knobs (potentiometer 0 through 7)
  .equ RESONANCE = MIDICC + $30
  .equ CUTOFF = MIDICC + $31
  .equ LFOFREQ = MIDICC + $32
  .equ PANEL_LFOLEVEL = MIDICC + $33
  .equ VCFENVMOD = MIDICC + $34
  .equ PORTAMENTO = MIDICC + $35
  .equ PULSE_KNOB = MIDICC + $36
  .equ OSC_DETUNE = MIDICC + $37

  ; Shifted knobs (potentiometer 0 through 7)
  ;.equ X = MIDICC + $38
  ;.equ X = MIDICC + $39
  .equ KNOB_DCF_DECAY = MIDICC + $3A
  .equ KNOB_DCF_ATTACK = MIDICC + $3B
  .equ KNOB_AMP_DECAY = MIDICC + $3C
  .equ KNOB_AMP_ATTACK = MIDICC + $3D
  .equ SW1 = MIDICC + $3E ; Reserved
  .equ SW2 = MIDICC + $3F ; Reserved

  ; Panel switches 0..15
  ; Switches 2
  .equ S_KNOB_SHIFT = MIDICC + $40
  .equ S_OSC_FM = MIDICC + $41
  .equ S_LFO_RANDOM = MIDICC + $42
  .equ S_LFO_WAVE = MIDICC + $43
  .equ S_FILTER_MODE = MIDICC + $44
  .equ S_DISTORTION = MIDICC + $45
  .equ S_LFO_ENABLE = MIDICC + $46
  .equ S_LFO_DEST = MIDICC + $47
  ; Switches 1
  .equ S_ANTI_ALIAS = MIDICC + $48
  .equ S_OSCB_OCT = MIDICC + $49
  .equ S_OSCB_ENABLE = MIDICC + $4A
  .equ S_OSCB_WAVE = MIDICC + $4B
  .equ S_SUSTAIN = MIDICC + $4C
  .equ S_OSCA_NOISE = MIDICC + $4D
  .equ S_PWM_SWEEP = MIDICC + $4E
  .equ S_OSCA_WAVE = MIDICC + $4F

  
; Patch save/load and MIDI channel set
LED_STATUS: .byte 1 ; off/on status of front panel LED
LED_TIMER: .byte 1 ; number of blinks before reset
BUTTON_STATUS: .byte 1 ; MIDI=1, SAVE=3, LOAD=7, CLEAR=0
CONTROL_SWITCH: .byte 1 ; Last panel switch moved: 1..16, where zero indicates no movement.

;-------------------------------------------------------------------------------------------------------------------



;stack: 0x0A3..0x25F
            .ESEG

;-------------------------------------------------------------------------------------------------------------------
; V E C T O R T A B L E
;-------------------------------------------------------------------------------------------------------------------
            .CSEG

jmp RESET ; RESET

jmp IRQ_NONE ; INT0
jmp IRQ_NONE ; INT1
jmp IRQ_NONE ; INT2

jmp TIM2_CMP ; TIMEr2 COMP
jmp IRQ_NONE ; TIMEr2 OVF

jmp IRQ_NONE ; TIMEr1 CAPT
jmp IRQ_NONE ; TIMEr1 COMPA
jmp IRQ_NONE ; TIMEr1 COMPB
     jmp IRQ_NONE ; TIMEr1 OVF

jmp IRQ_NONE ; TIMEr0 COMPA
jmp IRQ_NONE ; TIMEr0 OVF

jmp IRQ_NONE ; SPI,STC

jmp UART_RXC ; UART, RX COMPLETE
jmp IRQ_NONE ; UART,UDRE
jmp IRQ_NONE ; UART, TX COMPLETE

jmp IRQ_NONE ; ADC CONVERSION COMPLETE

jmp IRQ_NONE ; EEPROM READY

jmp IRQ_NONE ; ANALOG COMPARATOR

            jmp IRQ_NONE ; 2-Wire Serial Interface

            jmp IRQ_NONE ; STORE PROGRAM MEMORY READY

IRQ_NONE:
            reti
;-------------------------------------------------------------------------------------------------------------------
; R O M T A B L E S
;-------------------------------------------------------------------------------------------------------------------
;
; Phase Deltas at 36363.63636 Hz sample rate
;
; NOTE PHASE DELTA = 2 ^ 24 * Freq / SamplingFreq
; So... Note zero calc: 2 ^ 24 * 8.175799 / 36363.63636 = 3772.09651 (stored as 00 0E BC.19)
;
;-------------------------------------------------------------------------------------------------------------------

DELTA_C:
            .DW 0xBC19 ;\
.DW 0x000E ;/ note 0 ( 8.175799 Hz)
DELTA_CIS:
            .DW 0x9C66 ;\
.DW 0x000F ;/ note 1 ( 8.661957 Hz)
DELTA_D:
            .DW 0x8A09 ;\
.DW 0x0010 ;/ note 2 ( 9.177024 Hz)
DELTA_DIS:
            .DW 0x85CE ;\
.DW 0x0011 ;/ note 3 ( 9.722718 Hz)
DELTA_E:
            .DW 0x908B ;\
.DW 0x0012 ;/ note 4 (10.300861 Hz)
DELTA_F:
            .DW 0xAB25 ;\
.DW 0x0013 ;/ note 5 (10.913382 Hz)
DELTA_FIS:
            .DW 0xD68D ;\
.DW 0x0014 ;/ note 6 (11.562326 Hz)
DELTA_G:
            .DW 0x13C2 ;\
.DW 0x0016 ;/ note 7 (12.249857 Hz)
DELTA_GIS:
            .DW 0x63D4 ;\
.DW 0x0017 ;/ note 8 (12.978272 Hz)
DELTA_A:
            .DW 0xC7E3 ;\
.DW 0x0018 ;/ note 9 (13.750000 Hz)
DELTA_AIS:
            .DW 0x411D ;\
.DW 0x001A ;/ note 10 (14.567618 Hz)
DELTA_H:
            .DW 0xD0C5 ;\
.DW 0x001B ;/ note 11 (15.433853 Hz)
DELTA_C1:
            .DW 0x7831 ;\
.DW 0x001D ;/ note 12 (16.351598 Hz)

;-----------------------------------------------------------------------------
;
; Lookup Tables
;
; VCF filter cutoff - 128 bytes
; Time to Rate table for calculating amplitude envelopes - 64 bytes
; VCA non-linear level conversion - 256 bytes
;
;-----------------------------------------------------------------------------
; VCF Filter Cutoff
;
; value = (16th root of 2)**(index+1)
;
TAB_VCF:
.db 1, 1, 1, 1, 1, 1, 1, 1 ; 0
.db 1, 1, 1, 1, 1, 1, 1, 2 ; 8
.db 2, 2, 2, 2, 2, 2, 2, 2 ; 16
.db 2, 3, 3, 3, 3, 3, 3, 3 ; 24
.db 4, 4, 4, 4, 4, 5, 5, 5 ; 32
.db 5, 6, 6, 6, 7, 7, 7, 7 ; 40
.db 8, 8, 9, 9, 9, 10, 10, 11 ; 48
.db 11, 12, 12, 13, 14, 14, 15, 16 ; 56
.db 16, 17, 18, 19, 19, 20, 21, 22 ; 64
.db 23, 24, 25, 26, 28, 29, 30, 31 ; 72
.db 33, 34, 36, 38, 39, 41, 43, 45 ; 80
.db 47, 49, 51, 53, 56, 58, 61, 63 ; 88
.db 66, 69, 72, 76, 79, 82, 86, 90 ; 96
.db 94, 98, 103, 107, 112, 117, 122, 127 ; 104
.db 133, 139, 145, 152, 158, 165, 173, 181 ; 112
.db 189, 197, 206, 215, 224, 234, 245, 255 ; 120

;-----------------------------------------------------------------------------
;Time to Rate conversion table for envelope timing.
; lfo:
; update values for 32us update rate
; LFO_INTEGR overflows all 256*32us = 8.192 ms
;
; formula Tof = 256*32us*2^16/N
; LFOfreq = 1/Tof

; Rate value = Rmin * Q^i with Q = (Rmax/Rmin)^(1/31) = 1,286111766

TIMETORATE:
.DW 50957 ; 10.54 mS fast lfo, attack/rise time
.DW 39621 ; 13.55 mS
.DW 30807 ; 17.43 mS
.DW 23953 ; 22.41 mS
.DW 18625 ; 28.83 mS
.DW 14481 ; 37.07 mS
.DW 11260 ; 47.68 mS
.DW 8755 ; 61.32 mS
.DW 6807 ; 78.87 mS
.DW 5293 ; 101.4 mS
.DW 4115 ; 130.5 mS
.DW 3200 ; 167.8 mS
.DW 2488 ; 215.8 mS
.DW 1935 ; 277.5 mS
.DW 1504 ; 356.9 mS
.DW 1170 ; 459.0 mS
.DW 909 ; 590.4 mS
.DW 707 ; 759.3 mS
.DW 550 ; 976.5 mS
.DW 427 ; 1.256 S
.DW 332 ; 1.615 S
.DW 258 ; 2.077 S
.DW 201 ; 2.672 S
.DW 156 ; 3.436 S
.DW 121 ; 4.419 S
.DW 94 ; 5.684 S
.DW 73 ; 7.310 S
.DW 57 ; 9.401 S
.DW 44 ; 12.09 S
.DW 35 ; 15.55 S
.DW 27 ; 20.00 S
.DW 19 ; 28.26 S slow lfo, attack/rise time

;-----------------------------------------------------------------------------
;
; VCA non-linear level conversion
;
; Amplitude level lookup table. Envelopes levels are calculated as linear
; and then converted to approximate an exponential saturation curve.
;
; polynomial y = a + bx + cx2 + dx3
; with coefficients…
; a 0
; b 0.210841569
; c 0.000177823
; d 1.14E-05

TAB_VCA:
.db 0, 0, 0, 1, 1, 1, 1, 1 ; 0
.db 2, 2, 2, 2, 3, 3, 3, 3 ; 8
.db 3, 4, 4, 4, 4, 5, 5, 5 ; 16
.db 5, 6, 6, 6, 6, 7, 7, 7 ; 24
.db 7, 8, 8, 8, 8, 9, 9, 9 ; 32
.db 9, 10, 10, 10, 11, 11, 11, 11 ; 40
.db 12, 12, 12, 13, 13, 13, 14, 14 ; 48
.db 14, 15, 15, 15, 16, 16, 16, 17 ; 56
.db 17, 18, 18, 18, 19, 19, 20, 20 ; 64
.db 20, 21, 21, 22, 22, 23, 23, 23 ; 72
.db 24, 24, 25, 25, 26, 26, 27, 27 ; 80
.db 28, 28, 29, 29, 30, 30, 31, 31 ; 88
.db 32, 33, 33, 34, 34, 35, 35, 36 ; 96
.db 37, 37, 38, 39, 39, 40, 41, 41 ; 104
.db 42, 43, 43, 44, 45, 45, 46, 47 ; 112
.db 48, 48, 49, 50, 51, 51, 52, 53 ; 120

.db 54, 55, 56, 56, 57, 58, 59, 60 ; 128
.db 61, 62, 63, 63, 64, 65, 66, 67 ; 136
.db 68, 69, 70, 71, 72, 73, 74, 75 ; 144
.db 76, 77, 78, 80, 81, 82, 83, 84 ; 152
.db 85, 86, 87, 89, 90, 91, 92, 93 ; 160
.db 95, 96, 97, 98, 100, 101, 102, 104 ; 168
.db 105, 106, 108, 109, 110, 112, 113, 115 ; 176
.db 116, 118, 119, 120, 122, 123, 125, 126 ; 184
.db 128, 130, 131, 133, 134, 136, 138, 139 ; 192
.db 141, 142, 144, 146, 148, 149, 151, 153 ; 200
.db 154, 156, 158, 160, 162, 164, 165, 167 ; 208
.db 169, 171, 173, 175, 177, 179, 181, 183 ; 216
.db 185, 187, 189, 191, 193, 195, 197, 199 ; 224
.db 201, 203, 206, 208, 210, 212, 214, 217 ; 232
.db 219, 221, 224, 226, 228, 231, 233, 235 ; 240
.db 238, 240, 243, 245, 247, 250, 252, 255 ; 248

;-----------------------------------------------------------------------------
;
; Limit maximum resonance when filter cutoff is extremely low
;

TAB_REZ:
.db 224, 224, 224, 224, 224, 224, 224, 224 ; 0 - Low value of DE
.db 224, 228, 232, 236, 240, 244, 248, 252 ; 8 - High value of FC

;-------------------------------------------------------------------------------------------------------------------
; I N T E R R U P T S U B R O U T I N E S
;-------------------------------------------------------------------------------------------------------------------
; Timer 2 compare interrupt (sampling)
;
; This is where sound is generated. This interrupt is called 36,363 times per second
; to calculate a single 16-bit value for audio output. There are ~440 instruction cycles
; (16MHZ/36,363) between samples, and these have to be shared between this routine and the
; main program loop that scans controls, receives MIDI commands and calculates envelope,
; LFO, and DCA/DCF levels.
;
; If you use too many clock cycles here there won't be sufficient time left over for
; general housekeeping tasks. The result will be sluggish and lost notes, weird timing and sadness.
;-------------------------------------------------------------------------------------------------------------------

; Push contents of registers onto the stack
;
TIM2_CMP:
push r16
in r16, SREG ;\
     push r16 ;/ push SREG
push r17
push r18
push r19
push r20
push r21
push r22
push r23
push r30
push r31
   push r0
   push r1

lds r21, PATCH_SWITCH1 ; Load the mode flag settings so we can check the selected waveform,
lds r23, PATCH_SWITCH2 ; noise and distortion settings.


;-------------------------------------------------------------------------------------------------------------------
;
; Oscillator A & B
;
; This design uses direct frequency synthesis to generate a ramp wave. A three-byte counter (= phase) is being
; incremented by a value which is proportional to the sound frequency (= phase delta). The
; increment takes place every sampling period. The most significant byte of the counter is a sawtooth ramp.
; This is either used as a pointer to a 256 byte wavetable or for direct waveform synthesis.
; Each oscillator has its own phase and phase delta registers. The contents of each phase delta
; register depends on the frequency being generated:
;
; PHASE DELTA = 2 ^ 24 * Freq / SamplingFreq
;
; where:
; SamplingFreq = 40000 Hz
; Freq = 440 * 2 ^ ((n - 69 + d) / 12)
; where in turn:
; n = MIDI note number. Range limited to 36 to 96 (5 octaves)
; d = transpose/detune (in halftones)
;
;-------------------------------------------------------------------------------------------------------------------


;Calculate DCO A
; If Noise switch is on, use pseudo-random shift register value
sbrs r23, SW_OSCA_NOISE ; Use noise if bit set, otherwise jump to calculate DCO.
rjmp CALC_DCOA
lds r17, SHIFTREG_2
   sbrc PHASEA_2,3
com r17
sbrc PHASEA_2,4
com r17
sbrc PHASEA_2,6
com r17
sbrc PHASEA_2,7
com r17
lsl r17
rjmp CALC_DCOB ; skip sample calc for DCO A if noise bit set


CALC_DCOA:
mov r17, PHASEA_2 ; sawtooth ramp for OSCA
sbrs r23, SW_OSCA_WAVE ; 0/1 (DCO A = saw/pwm)
rjmp DCOA_SAW

;Pulse wave generated by subtracting two bandlimited sawtooths, between 0 and 180 degrees out of phase

sbrs r23, SW_PWM_SWEEP
lds r20, PULSE_KNOB_LIMITED ; PWM Sweep switch is off, so load the knob value as PWM width
sbrc r23, SW_PWM_SWEEP
lds r20, PULSE_WIDTH ; PWM Sweep switch is on, load pulse width from LF02
sbrs r23, SW_ANTI_ALIAS
rjmp RAW_PULSE ; Calculate raw pulse/PWM when anti-alias switch is off

lds r22, WAVETABLE_A ; Offset to the correct wavetable, based on note number (0..15)

; r17 phase
; r20 pulse width
; r22 wavetable
; get sample a into r17
ldi ZL, low (2*INV_SAW0) ; Load low part of byte address into ZL
ldi ZH, high(2*INV_SAW0) ; Load high part of byte address into ZH
add ZL, r17 ; Offset the wavetable by the ramp phase (i)
adc ZH, r22 ; Wavetable 0..15
lpm ; Load wave(i) into r0

; get sample b out of phase into r18
mov r16, r20 ; Grab a copy of the pulse width
add r16, r17 ; Add phase offset for second table (pulse width + original sample)
mov r17, r0 ; store previous sample in r17
ldi ZL, low (2*INV_SAW0) ; Load low part of byte address into ZL
ldi ZH, high(2*INV_SAW0) ; Load high part of byte address into ZH
add ZL, r16 ; Add phase offset for second table.
adc ZH, r22 ; Wavetable 0..15
lpm ; Load wave(i) into r0

; subtract wave a-b
; first part b > a, second part b < a
clr r16
sub r17, r0
sbc r16, ZERO
add r17, r20 ; add offset (pulse width)
adc r16, ZERO
brge PULSE_BOUND_CHECK ; non-negative result, so no need to limit the value
ldi r17, 0
ldi r16, 0 ; value was negative, so force to zero
PULSE_BOUND_CHECK:
tst r16 ; Check if we're larger than 255
breq PWM_EXIT ; no need to limit upper bound
ldi r17, $FF
PWM_EXIT:
subi r17, $80 ; sign the result
rjmp CALC_DCOB

; Raw Pulse wave generated on the fly. Aliases like crazy (calc'd only when anti-alias switch is OFF)
RAW_PULSE:
cp r17, r20
brlo PULSE_ZERO
ldi r17, 255
subi r17, $80 ; Sign the sample
rjmp CALC_DCOB
PULSE_ZERO:
ldi r17, 0
subi r17, $80 ; Sign the sample
rjmp CALC_DCOB

; Calculate DCOA sawtooth
DCOA_SAW:
mov r17, PHASEA_2
sbrs r23, SW_ANTI_ALIAS
rjmp DCOA_SAW_SIGN
lds r22, WAVETABLE_A ; Offset to the correct wavetable, based on note number (0..15)
ldi ZL, low (2*INV_SAW0) ; Load low part of byte address into ZL
ldi ZH, high(2*INV_SAW0) ; Load high part of byte address into ZH
add ZL, r17 ; Offset the wavetable by the ramp phase (i)
adc ZH, r22 ; Wavetable 0..15
lpm ; Load wave(i) into r0
mov r17, r0 ; Copy into DCO B
DCOA_SAW_SIGN:
subi r17, $80 ; -127..127 Sign oscillator

;Calculate DCO B
CALC_DCOB:
lds r22, WAVETABLE_B ; Offset to the correct wavetable, based on note number (0..15)
sbrs r23, SW_ANTI_ALIAS
ldi r22, 0 ; Use wavetable 0 when anti-alias switch off

mov r16, PHASEB_2 ; Use ramp value as offset when scanning wavetable
sbrs r23, SW_OSCB_WAVE ; 0/1 (DCO B = saw/squ)
rjmp LIMITED_TRIB

LIMITED_SQB: ; Square wave lookup
ldi ZL, low(2*SQ_LIMIT0) ; Load low part of byte address into ZL
ldi ZH, high(2*SQ_LIMIT0) ; Load high part of byte address into ZH
add ZL, r16 ; Offset the wavetable by the ramp phase (i)
adc ZH, r22 ; Wavetable 0..15
lpm ; Load wave(i) into r0
mov r16, r0 ; Copy into DCO B
rjmp CALC_DIST

LIMITED_TRIB: ; Triangle wave lookup
ldi ZL, low(2*TRI_LIMIT0) ; Load low part of byte address into ZL
ldi ZH, high(2*TRI_LIMIT0) ; Load high part of byte address into ZH
add ZL, r16 ; Offset the wavetable by the ramp phase (i)
adc ZH, r22 ; Wavetable 0..15
lpm ; Load wave(i) into r0
mov r16, r0 ; Copy into DCO B

CALC_DIST:
subi r16, $80 ; -127..127 Sign Oscillator B waveform

sbrc r21, SW_DISTORTION ; 0/1 (OSC DIST = off/on)
     eor r17, r16

; Turn off OSCB if not enabled
;sbrs r23, SW_OSCB_ENABLE
;ldi r16, $00 ; Zero OSCB. Oscillator is signed


;-------------------------------------------------------------------------------------------------------------------
; Sum Oscillators
;
; Combines DCOA (in r17) and DCOB (in r16) waves to produce a 16-bit signed result in HDAC:LDAC (r17:r16)
;
sts WAVEB,r16 ; store signed DCO B wave for fm

; Mixer out = (A*x + B*(1-x))/4 x=0..1
ldi r22, $7F ; Set maximum oscillator level to 127 for each oscillator
mulsu r17, r22 ; signed DCO A wave * level
movw r30, r0 ; store value in temp register
sbrs r23, SW_OSCB_ENABLE ; if OSC B disabled add OSC A twice
mov r16, r17 ; (A*x + A*(1-x))/4 x=0..1
mulsu r16, r22 ; signed DCO B wave * level
add r30, r0
adc r31, r1 ; sum scaled waves
movw r16, r30 ; place signed output in HDAC:LDAC

; rotate right a couple of times to make a couple of bits of headroom for resonance.

            asr r17 ;\
ror r16 ;/ r17:r16 = r17:r16 asr 1
asr r17 ;\
ror r16 ;/ r17:r16 = r17:r16 asr 1

movw OSC_OUT_L, r16 ; keep a copy for highpass filter

;DCF:

;-------------------------------------------------------------------------------------------------------------------
; Digitally Controlled Filter
;
; A 2-pole resonant low pass filter:
;
; a += f * ((in - a) + q * (a - b));
; b += f * (a - b);
;
; Input 16-Bit signed HDAC:LDAC (r17:r16), already scaled to minimize clipping (reduced to 25% of full code).
;-------------------------------------------------------------------------------------------------------------------

                             ;calc (in - a) ; both signed
sub LDAC, a_L
        sbc HDAC, a_H
                             ;check for overflow / do hard clipping
        brvc OVERFLOW_1 ;if overflow bit is clear jump to OVERFLOW_1

         ;sub overflow happened -> set to min
                             ;b1000.0000 b0000.0001 -> min
                             ;0b0111.1111 0b1111.1111 -> max

        ldi LDAC, 0b00000001
        ldi HDAC, 0b10000000

OVERFLOW_1: ;when overflow is clear

         ;(in-a) is now in HDAC:LDAC as signed
         ;now calc q*(a-b)

        ; Scale resonance based on filter cutoff
lds r22, SCALED_RESONANCE
lds r20, LPF_I ;load 'F' value
        ldi r21, 0xff

        sub r21, r20 ; 1-F
        lsr r21
ldi r18, 0x08 ; changed (4 was original value in V1)
        add r21, r18

        sub r22, r21 ; Q-(1-f)
        brcc OVERFLOW_2 ; if no overflow occured
        ldi r22, 0x00 ;0x00 because of unsigned
        

OVERFLOW_2:
        
        mov r20, a_L ;\
        mov r21, a_H ;/ load 'a' , signed

        lds z_H, b_H ;\
        lds z_L, b_L ;/ load 'b', signed

        sub r20, z_L ;\
        sbc r21, z_H ;/ (a-b) signed

        brvc OVERFLOW_3 ;if overflow is clear jump to OVERFLOW_3
        
         ;b1000.0000 b0000.0001 -> min
         ;0b0111.1111 0b1111.1111 -> max

        ldi r20, 0b00000001
        ldi r21, 0b10000000

OVERFLOW_3:
        
lds r18, PATCH_SWITCH1 ; Check Low Pass/High Pass panel switch.
sbrs r18, SW_FILTER_MODE
rjmp CALC_LOWPASS

SKIP_REZ:
movw z_L, r20 ; High Pass selected, so just load r21:r20 into z_H:z_L to disable Q
rjmp DCF_ADD ; Skip lowpass calc

CALC_LOWPASS:

; skip resonance calculation if VCF is turned off (value of 0)
lds r18, VCF_STATUS
tst r18
breq SKIP_REZ
; mul signed:unsigned -> (a-b) * Q
; 16x8 into 16-bit
; r19:r18 = r21:r20 (ah:al) * r22 (b)

mulsu r21, r22 ; (signed)ah * b
movw r18, r0
mul r20, r22 ; al * b
add r18, r1
adc r19, ZERO
rol r0 ; r0.7 --> Cy
brcc NO_ROUND ; LSByte < $80, so don't round up
inc r18
NO_ROUND:
        clc
        lsl r18
        rol r19
        clc
        lsl r18
        rol r19
movw z_L,r18 ;Q*(a-b) in z_H:z_L as signed

        ;add both
        ;both signed
        ;((in-a)+q*(a-b))
        ;=> HDAC:LDAC + z_H:z_L
 
 DCF_ADD:
                
        add LDAC, z_L
        adc HDAC, z_H

        brvc OVERFLOW_4 ;if overflow is clear
         ;b1000.0000 b0000.0001 -> min
;0b0111.1111 0b1111.1111 -> max

        ldi LDAC, 0b11111111
        ldi HDAC, 0b01111111

OVERFLOW_4:

         ;Result is a signed value in HDAC:LDAC
         ;calc * f
         ;((in-a)+q*(a-b))*f

        lds r20, LPF_I ;load lowpass 'F' value
lds r18, PATCH_SWITCH1
sbrc r18, SW_FILTER_MODE ; Check LP/HP switch.
lds r20, HPF_I ; Switch set, so load 'F' for HP

; mul signed unsigned HDAC*F
; 16x8 into 16-bit
; r19:r18 = HDAC:LDAC (ah:al) * r20 (b)

mulsu HDAC, r20 ; (signed)ah * b
movw r18, r0
mul LDAC, r20 ; al * b
add r18, r1 ; signed result in r19:r18
adc r19, ZERO
rol r0 ; r0.7 --> Cy
brcc NO_ROUND2 ; LSByte < $80, so don't round up
inc r18
NO_ROUND2:
         ;Add result to 'a'
         ;a+=f*((in-a)+q*(a-b))

        add a_L, r18
        adc a_H, r19
        brvc OVERFLOW_5 ;if overflow is clear
                                 ;b1000.0000 b0000.0001 -> min
                                 ;0b0111.1111 0b1111.1111 -> max

ldi z_L, 0b11111111
ldi z_H, 0b01111111
mov a_L, z_L
mov a_H, z_H

OVERFLOW_5:

         ;calculated a+=f*((in-a)+q*(a-b)) as signed value and saved in a_H:a_L
         ;calc 'b'
         ;b += f * (a*0.5 - b);

mov z_H, a_H ;\
        mov z_L, a_L ;/ load 'a' as signed

        lds temp, b_L ;\
        lds temp2, b_H ;/ load b as signed

        sub z_L, temp ;\
        sbc z_H, temp2 ;/ (a - b) signed

        brvc OVERFLOW_6 ;if overflow is clear
                          ;b1000.0000 b0000.0001 -> min
;0b0111.1111 0b1111.1111 -> max

        ldi z_L, 0b00000001
        ldi z_H, 0b10000000

OVERFLOW_6:

        lds r20, LPF_I ;load lowpass 'F' value
lds r18, PATCH_SWITCH1
sbrc r18, SW_FILTER_MODE ; Check LP/HP switch.
lds r20, HPF_I ; Switch set to HP, so load 'F' for HP

;mulsu z_H, r20 ;mul signed unsigned (a-b) * F

; mul signed unsigned (a-b) * F
; 16x8 into 16-bit
; r19:r18 = z_H:z_L (ah:al) * r20 (b)
mulsu z_H, r20 ; (signed)ah * b
movw r18, r0
mul z_L, r20 ; al * b
add r18, r1 ; signed result in r19:r18
adc r19, ZERO
                                 
        
        add temp, r18 ;\ add result to 'b' , signed
        adc temp2, r19 ;/ b +=(a-b)*f

        brvc OVERFLOW_7 ;if overflow is clear
                
;b1000.0000 b0000.0001 -> min
;0b0111.1111 0b1111.1111 -> max

        ldi temp, 0b11111111
        ldi temp2, 0b01111111

OVERFLOW_7:

sts b_L, temp ;\
        sts b_H, temp2 ;/ save value of 'b'


        mov LDAC, temp ;B now contains the filtered signal in HDAC:LDAC
        mov HDAC, temp2


; If in HP filter mode, just use (filter input - filter output)

lds r18, PATCH_SWITCH1 ; Check if LP or HP filter
sbrs r18, SW_FILTER_MODE
rjmp DCA ; LP, so jump to DCA
sub OSC_OUT_L, LDAC ; HP filter, so output = filter input - output
sbc OSC_OUT_H, HDAC
movw LDAC, OSC_OUT_L


;-------------------------------------------------------------------------------------------------------------------
; Digitally Controlled Amplifier
;
; Multiply the output waveform by the 8-bit value in LEVEL.
; r17:r16 - output from filter 16b signed
; r18 - output from DCA envelope generator
;-------------------------------------------------------------------------------------------------------------------
;
DCA:
movw r30, r16
lds r18, LEVEL
cpi r18, 255
breq T2_AEXIT ; don't multiply when LEVEL==255, use
mulsu r17, r18 ; multiply samples high byte
movw r30, r0
mul r16, r18 ; multipliy samples low byte
add r30, r1
adc r31, ZERO
T2_AEXIT:

;-------------------------------------------------------------------------------------------------------------------
; Output Sample
;
; Write the 16-bit signed output of the DCA to the DAC.
;-------------------------------------------------------------------------------------------------------------------
;


;write sample (r31:r30) to DAC:

sbi PORTD, 3 ; Set WR high
subi r31, 128 ; U2 --> PB
cbi PORTD, 2 ; Select DAC port A
out PORTC, r31 ; output most significant byte
cbi PORTD, 3 ; Pull WR low to load buffer A
sbi PORTD, 3 ; Set WR high
sbi PORTD, 2 ; Select DAC port B
out PORTC, r30 ; output least significant byte
cbi PORTD, 3 ; Pull WR low to load buffer B
sbi PORTD, 3 ; Set WR high again

; Increment Oscillator A & B phase

   ldi r30, low(DELTAA_0)
   ldi r31, high(DELTAA_0)
   ld r16, z+
   add PHASEA_0, r16
   ld r16,z+
   adc PHASEA_1, r16
   ld r16,z+
   adc PHASEA_2, r16
   ld r16,z+
   add PHASEB_0, r16
   ld r16,z+
   adc PHASEB_1, r16
   ld r16, z+
   adc PHASEB_2,r16

;-------------------------------------------------------------------------------------------------------------------
; Frequency Modulation
;-------------------------------------------------------------------------------------------------------------------
;

dco_fm:

lds r30, PATCH_SWITCH2
sbrc r30, SW_OSCA_NOISE ;
rjmp END_SAMPLE_LOOP ; If DCOA waveform is set to Noise, skip FM
sbrs r30, SW_OSCB_ENABLE ; Skip FM is OSCB is turned off
rjmp END_SAMPLE_LOOP

lds r30, PATCH_SWITCH1 ; Get FM switch value
sbrs r30, SW_OSC_FM
ldi r17, 0 ; Set FM depth to 0 if switch is off
sbrc r30, SW_OSC_FM
ldi r17, 255 ; Set FM depth to 255 if switch is on

; mod * depth
tst r17 ; skip if FM depth is zero
breq END_SAMPLE_LOOP
lds r16, WAVEB

mulsu r16, r17
movw r18, r0

; delta * mod * depth
lds r16, DELTAA_0
clr r17
mulsu r19, r16
sbc r17, r17
add PHASEA_0, r1
adc PHASEA_1, r17
adc PHASEA_2, r17

lds r16, DELTAA_1
mulsu r19, r16
add PHASEA_0, r0
adc PHASEA_1, r1
adc PHASEA_2, r17

lds r16, DELTAA_2
mulsu r19, r16
add PHASEA_1, r0
adc PHASEA_2, r1

;-------------------------------------------------------------------------------------------------------------------
; End of Sample Interrupt
;
; Pop register values off stack and return to our regularly scheduled programming.
;-------------------------------------------------------------------------------------------------------------------
;

END_SAMPLE_LOOP:

pop r1
   pop r0
pop r31
pop r30
pop r23
pop r22
pop r21
pop r20
pop r19
pop r18
pop r17
pop r16 ;\
out SREG, r16 ;/ pop SREG
pop r16
reti

;------------------------
; UART receiver (MIDI IN)
;------------------------
UART_RXC:

            push r16
in r16, SREG ;\
push r16 ;/ push SREG

in r16, UDR ; read received byte in r16
cbi UCR, 7 ; RXCIE=0 (disable UART interrupts)
sei ; enable other interrupts
push r17

tst r16 ;\ jump when
brpl INTRX_DATA ;/ r16.7 == 0 (MIDI data byte)

;MIDI status byte (1xxxxxxx):
mov r17, r16
andi r17, 0xF0
cpi r17, 0x80
breq INTRX_ACCEPT ; 8x note off
cpi r17, 0x90
breq INTRX_ACCEPT ; 9x note on
cpi r17, 0xB0
breq INTRX_ACCEPT ; Bx control change
cpi r17, 0xE0
breq INTRX_ACCEPT ; Ex pitch bend
ldi r17, 0 ;\
sts MIDIPHASE, r17 ;/ MIDIPHASE = 0
rjmp INTRX_EXIT ; Ax polyphonic aftertouch
; Cx program change
; Dx channel aftertouch
; Fx system

INTRX_ACCEPT:
            sts MIDIPHASE, r17 ; phase = 80 90 B0 E0
andi r16, 0x0F ;\
inc r16 ; > store MIDI channel 1..16
sts MIDICHANNEL, r16 ;/
lds r17, SETMIDICHANNEL ;0 for OMNI or 1..15
tst r17
breq INTRX_ACPT_X ; end when OMNI
cp r17, r16 ; compare set channel to the incoming channel
breq INTRX_ACPT_X ; end when right channel
ldi r17, 0 ;\ otherwise:
sts MIDIPHASE, r17 ;/ MIDIPHASE = 0 (no data service)

INTRX_ACPT_X:
            rjmp INTRX_EXIT

;MIDI data byte (0xxxxxxx):
INTRX_DATA:
            lds r17, MIDIPHASE
cpi r17, 0x80 ;\
breq INTRX_NOFF1 ; \
cpi r17, 0x81 ; / note off
breq INTRX_NOFF2 ;/
rjmp INTRX_NOTEON

INTRX_NOFF1:
            inc r17 ;\
sts MIDIPHASE, r17 ;/ MIDIPHASE = 0x81
sts MIDIDATA0, r16 ; MIDIDATA0 = d
rjmp INTRX_EXIT

INTRX_NOFF2:
            dec r17 ;\
sts MIDIPHASE, r17 ;/ MIDIPHASE = 0x80
rjmp INTRXNON2_OFF

;9x note on:
INTRX_NOTEON:
            cpi r17, 0x90 ;\
breq INTRX_NON1 ; \
cpi r17, 0x91 ; / note on
breq INTRX_NON2 ;/
rjmp INTRX_CTRL

INTRX_NON1:
            inc r17 ;\
sts MIDIPHASE, r17 ;/ MIDIPHASE = 0x91
sts MIDIDATA0, r16 ; MIDIDATA0 = d
rjmp INTRX_EXIT

INTRX_NON2:
            dec r17 ;\
sts MIDIPHASE, r17 ;/ MIDIPHASE = 0x90
tst r16 ;\
brne INTRXNON2_ON ;/ jump when velocity != 0

;turn note off:
INTRXNON2_OFF:
            lds r16, MIDIDATA0
lds r17, MIDINOTEPREV
cp r16, r17
brne INTRXNON2_OFF1
ldi r17, 255 ;\ remove previous note
sts MIDINOTEPREV, r17 ;/ from buffer

INTRXNON2_OFF1:
            lds r17, MIDINOTE
cp r16, r17 ;\
brne INTRXNON2_OFF3 ;/ exit when not the same note
lds r17, MIDINOTEPREV
cpi r17, 255
breq INTRXNON2_OFF2
sts MIDINOTE, r17 ; previous note is valid
ldi r17, 255 ;\ remove previous note
sts MIDINOTEPREV, r17 ;/ from buffer

INTRXNON2_OFF3:
            rjmp INTRX_EXIT

INTRXNON2_OFF2:
            ldi r17, 255 ;\ remove last note
sts MIDINOTE, r17 ;/
ldi r17, 0 ;\
sts GATE, r17 ;/ GATE = 0


sbi PORTD, 1 ; LED on
rjmp INTRX_EXIT

;turn note on:
INTRXNON2_ON:
            sts MIDIVELOCITY, r16 ; store velocity
lds r17, MIDINOTE ;\ move previous note
sts MIDINOTEPREV, r17 ;/ into buffer
lds r17, MIDIDATA0 ;\
sts MIDINOTE, r17 ;/ MIDINOTE = note#
ldi r17, 1
sts GATE, r17 ; GATE = 1
sts GATEEDGE, r17 ; GATEEDGE = 1

cbi PORTD, 1 ; LED off
rjmp INTRX_EXIT

;Bx control change:
INTRX_CTRL:
            cpi r17, 0xB0 ;\
breq INTRX_CC1 ; \
cpi r17, 0xB1 ; / control change
breq INTRX_CC2 ;/
rjmp INTRX_PBEND

INTRX_CC1:
            inc r17 ;\
sts MIDIPHASE, r17 ;/ MIDIPHASE = 0xB1
sts MIDIDATA0, r16 ; MIDIDATA0 = controller#
rjmp INTRX_EXIT

INTRX_CC2:
            dec r17 ;\
sts MIDIPHASE, r17 ;/ MIDIPHASE = 0xB0
lds r17, MIDIDATA0

;Store MIDI CC in table
push r26 ; store contents of r27 and r26 on stack
push r27

cpi r17, $30 ; Just save a controller # < $30
brlo INTRX_GOSAVE

cpi r17, $40 ; save, update old knob value and status
brlo INTRX_KNOB

cpi r17, $50 ; save, update old switch value and status
brlo INTRX_SW

INTRX_GOSAVE:
rjmp INTRX_SAVE ; Save all other controller # > $50

INTRX_KNOB:
; save the value in the MIDI table
ldi r26,low(MIDICC)
   ldi r27,high(MIDICC)
   add r26,r17
   adc r27,zero
   lsl r16 ; shift MIDI data to 0..254 to match knob value
   st x,r16 ; store in MIDI CC table

; Get ADC_X and write it into OLD_ADC_X
subi r17, $30 ; reduce to 0..15
cbr r17, $f8 ; Clear highest 5 bits, leaving knob 0..7

ldi r26,low(ADC_0)
   ldi r27,high(ADC_0)
   add r26,r17
   adc r27,zero
ld r16, x ; Fetch ADC_X into r16

ldi r26,low(OLD_ADC_0)
   ldi r27,high(OLD_ADC_0)
   add r26,r17
   adc r27,zero
st x, r16 ; Store ADC_X in OLD_ADC_X

; Clear KNOBX_STATUS (knob not moved)
ldi r26,low(KNOB0_STATUS)
   ldi r27,high(KNOB0_STATUS)
   add r26,r17
   adc r27,zero
ldi r17, 0
st x, r17 ; Clear KNOBX_STATUS
rjmp INTRX_CCEND

INTRX_SW:
subi r17, $40 ; MIDI CC # --> switch offset 0..15

cpi r17, $08
BRLO INTRX_SWITCH1 ; Jump to Switch 1 if switch 0..7 selected.

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

INTRX_SWITCH2:

cbr r17, $f8 ; Clear highest 5 bits, leaving switch 0..7
lds r26, PATCH_SWITCH2
bst r16, 6 ; load MSB of MIDI CC value into SREG T bit

cpi r17, 0
brne INTRX_S1
bld r26, 0 ; Set bit in PATCH_SWITCH2
rjmp INTRX_SEXIT
INTRX_S1:
cpi r17, 1
brne INTRX_S2
bld r26, 1 ; Set bit in PATCH_SWITCH2
rjmp INTRX_SEXIT
INTRX_S2:
cpi r17, 2
brne INTRX_S3
bld r26, 2 ; Set bit in PATCH_SWITCH2
rjmp INTRX_SEXIT
INTRX_S3:
cpi r17, 3
brne INTRX_S4
bld r26, 3 ; Set bit in PATCH_SWITCH2
rjmp INTRX_SEXIT
INTRX_S4:
cpi r17, 4
brne INTRX_S5
bld r26, 4 ; Set bit in PATCH_SWITCH2
rjmp INTRX_SEXIT
INTRX_S5:
cpi r17, 5
brne INTRX_S6
bld r26, 5 ; Set bit in PATCH_SWITCH2
rjmp INTRX_SEXIT
INTRX_S6:
cpi r17, 6
brne INTRX_S7
bld r26, 6 ; Set bit in PATCH_SWITCH2
rjmp INTRX_SEXIT
INTRX_S7:
bld r26, 7 ; Set bit in PATCH_SWITCH2

INTRX_SEXIT: ; Finished switch scan, store updated switch bytes
sts PATCH_SWITCH2, r26
rjmp INTRX_CCEND

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

INTRX_SWITCH1:

cbr r17, $f8 ; Clear highest 5 bits, leaving switch 0..7
lds r26, PATCH_SWITCH1
bst r16, 6 ; load MSB of MIDI CC value into SREG T bit

cpi r17, 0
brne INTRX_SW1
bld r26, 0 ; Set bit in PATCH_SWITCH1
rjmp INTRX_SWEXIT
INTRX_SW1:
cpi r17, 1
brne INTRX_SW2
bld r26, 1 ; Set bit in PATCH_SWITCH1
rjmp INTRX_SWEXIT
INTRX_SW2:
cpi r17, 2
brne INTRX_SW3
bld r26, 2 ; Set bit in PATCH_SWITCH1
rjmp INTRX_SWEXIT
INTRX_SW3:
cpi r17, 3
brne INTRX_SW4
bld r26, 3 ; Set bit in PATCH_SWITCH1
rjmp INTRX_SWEXIT
INTRX_SW4:
cpi r17, 4
brne INTRX_SW5
bld r26, 4 ; Set bit in PATCH_SWITCH1
rjmp INTRX_SWEXIT
INTRX_SW5:
cpi r17, 5
brne INTRX_SW6
bld r26, 5 ; Set bit in PATCH_SWITCH1
rjmp INTRX_SWEXIT
INTRX_SW6:
cpi r17, 6
brne INTRX_SW7
bld r26, 6 ; Set bit in PATCH_SWITCH1
rjmp INTRX_SWEXIT
INTRX_SW7:
bld r26, 7 ; Set bit in PATCH_SWITCH1

INTRX_SWEXIT: ; Finished switch scan, store updated switch bytes
sts PATCH_SWITCH1, r26
rjmp INTRX_CCEND

INTRX_SAVE:
ldi r26,low(MIDICC)
   ldi r27,high(MIDICC)
   add r26,r17
   adc r27,zero
   lsl r16 ; shift MIDI data to 0..254 to match knob value
   st x,r16 ; store in MIDI CC table

INTRX_CCEND:
pop r27 ; reload old contents of r27 and r 26
pop r26
rjmp INTRX_EXIT

;Ex pitch bender:
INTRX_PBEND:
            cpi r17, 0xE0 ;\
breq INTRX_PB1 ; \
cpi r17, 0xE1 ; / pitch bend
breq INTRX_PB2 ;/
rjmp INTRX_EXIT

INTRX_PB1:
            inc r17 ;\
sts MIDIPHASE, r17 ;/ MIDIPHASE = 0xE1
sts MIDIDATA0, r16 ; MIDIDATA0 = dFine 0..127
rjmp INTRX_EXIT

INTRX_PB2:
            dec r17 ;\
sts MIDIPHASE, r17 ;/ MIDIPHASE = 0xE0
lds r17,MIDIDATA0 ;\
lsl r17 ;/ r17 = dFine*2 0..254
lsl r17 ;\ r16,r17 = P.B.data
rol r16 ;/ 0..255,996
subi r16, 128 ; r16,r17 = -128,000..+127,996
sts MIDIPBEND_L, r17 ;\
sts MIDIPBEND_H, r16 ;/ store P.BEND value
rjmp INTRX_EXIT

INTRX_EXIT:
            pop r17
pop r16 ;\
out SREG, r16 ;/ pop SREG
pop r16
sbi UCR, 7 ; RXCIE=1
reti

;-------------------------------------------------------------------------------------------------------------------
; M A I N L E V E L S U B R O U T I N E S
;-------------------------------------------------------------------------------------------------------------------

;=============================================================================
; Delay subroutines
;=============================================================================

WAIT_10US:
            push r16 ; 3+2
ldi r16, 50 ; 1

W10U_LOOP:
            dec r16 ; 1\
brne W10U_LOOP ; 2/1 / 49*3 + 2
pop r16 ; 2
ret ; 4

;=============================================================================
; I/O subroutines
;=============================================================================

;-----------------------------------------------------------------------------
;A/D conversion (start)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;In: r18 = channel # 0..7
;Out: -
;Used: -
;-----------------------------------------------------------------------------
ADC_START:
            out ADMUX, r18 ; set multiplexer
sbi ADCSRA, 6 ; ADSC=1
ret

;-----------------------------------------------------------------------------
;A/D conversion (end)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;In: -
;Out: r16 = result 0..255
;Used: SREG,r17
;-----------------------------------------------------------------------------
ADC_END:
ADCE_LOOP:
            sbis ADCSRA, 4 ;\
rjmp ADCE_LOOP ;/ wait for ADIF==1
sbi ADCSRA, 4 ; clear ADIF
in r16, ADCL ;\
in r17, ADCH ;/ r17:r16 = 000000Dd:dddddddd
lsr r17 ;\
ror r16 ;/ r17:r16 = 0000000D:dddddddd
lsr r17 ;\
ror r16 ;/ r16 = Dddddddd
ret

;=============================================================================
; arithmetic subroutines
;=============================================================================

;-----------------------------------------------------------------------------
; 16 bit arithmetical shift right (division by 2^n)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;In: r17:r16 = x
; r18 = n (shift count) 0..16
;Out: r17:r16 = x asr n
;Used: SREG
;-----------------------------------------------------------------------------
ASr16:
            tst r18
breq ASr16_EXIT
push r18

ASr16_LOOP:
            asr r17 ;\
ror r16 ;/ r17,r16 = r17,r16 asr 1
dec r18
brne ASr16_LOOP
pop r18

ASr16_EXIT:
            ret

;-----------------------------------------------------------------------------
; 32 bit logical shift right
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;In: r19:r18:r17:r16 = x
; r20 = n (shift count)
;Out: r19:r18:r17:r16 = x >> n
;Used: SREG
;-----------------------------------------------------------------------------
SHr32:
            tst r20
breq SHr32_EXIT
push r20

SHr32_LOOP:
            lsr r19
ror r18
ror r17
ror r16
dec r20
brne SHr32_LOOP
pop r20

SHr32_EXIT:
            ret

;-----------------------------------------------------------------------------
; 32 bit logical shift left
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;In: r19:r18:r17:r16 = x
; r20 = n (shift count)
;Out: r19:r18:r17:r16 = x << n
;Used: SREG
;-----------------------------------------------------------------------------
SHL32:
            tst r20
breq SHL32_EXIT
push r20

SHL32_LOOP:
            lsl r16
rol r17
rol r18
rol r19
dec r20
brne SHL32_LOOP
pop r20

SHL32_EXIT:
            ret

;-----------------------------------------------------------------------------
;8 bit x 8 bit multiplication (unsigned)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;In: r16 = x 0..255
; r17 = y 0,000..0,996
;Out: r17,r16 = x * y 0,000..254,004
;Used: SREG,r18-r20
;-----------------------------------------------------------------------------
MUL8X8U:

MUL r16, r17
movw r16,r0
ret

;-----------------------------------------------------------------------------
;32 bit x 16 bit multiplication (unsigned)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;In: r19:r18:r17:r16 = x 0..2^32-1
; r23:r22 = y 0,yyyyyyyyyyyyyyyy 0..0,9999847
;Out: r19:r18:r17:r16 = x * y 0..2^32-1
;Used: SREG,r20-r29
;-----------------------------------------------------------------------------
MUL32X16:

; multiply with high multiplier x
mul r19, r23 ; ax
movw r29:r28, r1:r0
mul r18, r23 ; bx
movw r21:r20, r1:r0
mul r17, r23 ; cx
movw r27:r26, r1:r0
mul r16, r23 ; dx
mov r25, r0
add r26, r1
adc r27, r20
adc r28, r21
adc r29, ZERO
; multiply with low multiplier y
mul r19, r22 ; ay
movw r21:r20, r1:r0
mul r17, r22 ; cy
add r25, r0
adc r26, r1
adc r27, r20
adc r28, r21
adc r29, ZERO
mul r18, r22 ; by
movw r21:r20, r1:r0
mul r16, r22 ; dy
mov r24, r0
add r25, r1
adc r26, r20
adc r27, r21
adc r28, ZERO
adc r29, ZERO

mov r16,r26 ;\
mov r17,r27 ; \
mov r18,r28 ; / x * y
mov r19,r29 ;/

ret

;-----------------------------------------------------------------------------
; Load 32 bit phase value from ROM
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;In: r30 = index
;Out: r19:r18:r17:r16 = value
;Used: SREG,r0,r30,r31
;-----------------------------------------------------------------------------
LOAD_32BIT:
            lsl r30 ; r30 *= 2
ldi r31, 0
adiw r30, DELTA_C ; Z = ROM address
add r30, r30
     adc r31, r31
lpm r16, z+
lpm r17, z+
lpm r18, z+
lpm r19, z+
ret

;-----------------------------------------------------------------------------
; Load phase delta from ROM
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;In: r23,r22 = indexs = 0,0..12,0 = n,octave
;Out: r19:r18:r17:r16 = delta
;Used: SREG,r0,r21,r24-r31
;-----------------------------------------------------------------------------
LOAD_DELTA:
            push r22
push r23
mov r30, r23
     rcall LOAD_32BIT
mov r24, r16
mov r25, r17
mov r26, r18
mov r27, r19 ; r27-r24 = delta[n]
mov r30, r23
inc r30
rcall LOAD_32BIT
sub r16, r24
sbc r17, r25
sbc r18, r26
sbc r19, r27
push r24
push r25
push r26
push r27
mov r23, r22
ldi r22, 0
push r20
rcall MUL32X16
pop r20
pop r27
pop r26
pop r25
pop r24
     add r16, r24
adc r17, r25
     adc r18, r26
adc r19, r27
pop r23
pop r22
ret

;-----------------------------------------------------------------------------
;note number recalculation
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;In: r23 = n 0..139 = m12 + 12*n12
;Out: r23 = m12 0..11
; r20 = n12 0..11
;Used: SREG
;-----------------------------------------------------------------------------
NOTERECALC:
            ldi r20,0 ; n12 = 0
rjmp NRC_2

NRC_1:
            subi r23, 12 ; m12 -= 12
inc r20 ; n12++

NRC_2:
            cpi r23, 12
brsh NRC_1 ; repeat while m12 >= 12
ret

;-----------------------------------------------------------------------------
;read a byte from a table
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;In: r16 = i 0..255
; r31:r30 = &Tab
;Out: r0 = Tab[i] 0..255
;Used: SREG,r30,r31
;-----------------------------------------------------------------------------
TAB_BYTE:
            add r30, r30 ;\
adc r31, r31 ;/ Z = 2 * &Tab
add r30, r16
adc r31, ZERO
lpm r16, z
ret

;-----------------------------------------------------------------------------
;read a word from a table
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;In: r16 = i 0..255
; r31:r30 = &Tab
;Out: r19:r18 = Tab[i] 0..65535
;Used: SREG,r0,r30,r31
;-----------------------------------------------------------------------------
TAB_WORD:
            add r30, r16
adc r31, ZERO
add r30, r30 ;\
adc r31, r31 ;/ Z = 2 * &Tab
lpm r18, z+ ; LSByte
lpm r19, z ; MSByte
ret

;-----------------------------------------------------------------------------
;"time" --> "rate" conversion
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;In: r16 = time 0..255
;Out: r19:r18:r17:r16 = rate 0x001B0000..0xFFFF0000
;Used: SREG,r0,r30,r31
;-----------------------------------------------------------------------------
ADCTORATE:
            lsr r16
lsr r16
lsr r16 ;0..31
ldi r30, low( TIMETORATE)
ldi r31, high(TIMETORATE)
rcall TAB_WORD ;r19:r18 = rate
clr r16
clr r17
ret

;-----------------------------------------------------------------------------
;conversion of the "detune B" potentiometer function
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;In: r16 = x 0..255
;Out: r17,r16 = y 0,000..255,996
;Used: SREG,r18-r30
;-----------------------------------------------------------------------------
NONLINPOT:
            ldi r22, 0
mov r23, r16
     cpi r23, 112
brlo NLP_I
cpi r23, 144
brlo NLP_II
rjmp NLP_III

NLP_I:
            ldi r16, 0 ;\ r18,r17:r16 = m =
ldi r17, 32 ; > = 126/112 =
ldi r18, 1 ;/ = 1,125
     ldi r30, 0 ;\ r31,r30 = n =
ldi r31, 0 ;/ = 0,0
rjmp NLP_CONT

NLP_II:
            ldi r16, 8 ;\ r18,r17:r16 = m =
ldi r17, 33 ; > = (130-126)/(143-112) =
     ldi r18, 0 ;/ = 0,129032258
ldi r30, 140 ;\ r31,r30 = n =
ldi r31, 111 ;/ = 126 - m*112 = 111,5483871
rjmp NLP_CONT

NLP_III:
            ldi r16, 183 ;\ r18,r17:r16 = m =
ldi r17, 29 ; > = (255-130)/(255-143) =
ldi r18, 1 ;/ = 1,116071429
     ldi r30, 103 ;\ r31,r30 = n =
ldi r31, 226 ;/ 255 - m*255 = -29,59821429

NLP_CONT:
            ldi r19, 0
rcall MUL32X16
add r16, r30
adc r17, r31
ret

;-----------------------------------------------------------------------------
; Write byte to eeprom memory
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;In: r16 = value 0..255
; r18:r17 = eeprom memory address
;Used: r16, r17, r18
;-----------------------------------------------------------------------------
EEPROM_write:
; Wait for completion of previous write
sbic EECR,EEWE
rjmp EEPROM_write
in temp_SREG, SREG ; save SREG
cli ; disable interrupts during timed eeprom sequence
out EEARH, r18
out EEARL, r17 ; single byte offset from WRITE_OFFSET
out EEDR, r16 ; Write data (r16) to data register
sbi EECR,EEMWE ; Write logical one to EEMWE
sbi EECR,EEWE ; Start eeprom write by setting EEWE
out SREG, temp_SREG ; restore SREG (restarts interrupts if enabled)
ret

;-----------------------------------------------------------------------------
; Read byte from eeprom memory
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;In: r18:r17 = eeprom memory address
;Out: r16 = value 0..255
;Used: r16, r17, r18
;-----------------------------------------------------------------------------
EEPROM_read:

sbic EECR,EEWE ; Wait for completion of previous write
rjmp EEPROM_read
in temp_SREG, SREG ; save SREG
cli ; disable interrupts during timed eeprom sequence
out EEARH, r18 ; Set up address (r18:r17) in address register
out EEARL, r17
sbi EECR, EERE ; Start eeprom read by writing EERE
in r16, EEDR ; Read data from data register
out SREG, temp_SREG ; restore SREG (restarts interrupts if enabled)
ret

;-----------------------------------------------------------------------------
; Clear knob status
; Set knob status to 'unmoved' and save current knob positions
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;In: --
;Out: --
;Used: r16
;-----------------------------------------------------------------------------

CLEAR_KNOB_STATUS: ; set knob status to 'unmoved' and save current knob positions
clr r16
sts KNOB0_STATUS, r16 ;
sts KNOB1_STATUS, r16 ;
sts KNOB2_STATUS, r16 ;
sts KNOB3_STATUS, r16 ;
sts KNOB4_STATUS, r16 ;
sts KNOB5_STATUS, r16 ;
sts KNOB6_STATUS, r16 ;
sts KNOB7_STATUS, r16 ;
lds r16, ADC_0 ; Save current pot positions for future comparison
sts OLD_ADC_0,r16
lds r16, ADC_1
sts OLD_ADC_1,r16
lds r16, ADC_2
sts OLD_ADC_2,r16
lds r16, ADC_3
sts OLD_ADC_3,r16
lds r16, ADC_4
sts OLD_ADC_4,r16
lds r16, ADC_5
sts OLD_ADC_5,r16
lds r16, ADC_6
sts OLD_ADC_6,r16
lds r16, ADC_7
sts OLD_ADC_7,r16
ret

;-----------------------------------------------------------------------------
; Load patch
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;In: r16 = patch number
;Out: Loads 16 byte patch into MIDI CC table
;Used: r16-r19, r28, r29
;-----------------------------------------------------------------------------

LOAD_PATCH:
; Enter with patch number in r16
lsl r16
lsl r16
lsl r16
lsl r16 ; multiply patch number by 16 to get starting address of patch in eeprom
mov r17, r16 ; Low byte of eeprom address
ldi r18, 0 ; High byte of eeprom address
ldi r19, $30 ; MIDI CC table offset

; Get byte from eeprom
PATCH_LOOP:
rcall EEPROM_READ ; Returns patch(i) in r16

ldi r28, low (MIDICC)
   ldi r29, high(MIDICC)
   add r28, r19
   adc r29, zero
   st Y, r16 ; store in MIDI CC table

inc r17
inc r19
cpi r19, $40 ; are we finished loading 16 bytes?
brne PATCH_LOOP

; copy switch bytes from MIDI table to current patch
lds r16, SW1
sts PATCH_SWITCH1, r16
lds r16, SW2
sts PATCH_SWITCH2, r16
lds r16, SWITCH1
sts OLD_SWITCH1, r16
lds r16, SWITCH2
sts OLD_SWITCH2, r16

; flag knobs as not moved
rcall CLEAR_KNOB_STATUS
ret


;-----------------------------------------------------------------------------
; Scan a pot and update its value if it has been moved
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; In: r16 - the new pot value
; r20 - the current conversion channel (0..7)
; Out: r17 - 1 if the pot has changed, 0 otherwise
; Used: r16-r20, r28, r29, SREG
;-----------------------------------------------------------------------------
POT_SCAN:
ldi r28, low(KNOB0_STATUS)
ldi r29, high(KNOB0_STATUS)
add r28, r20
adc r29, ZERO
ld r18, Y ; load KNOBN_STATUS value into r18

sbrc r18, 0 ; Check bit 0
rjmp LOAD_ADC ; KNOBN_STATUS is set, so just update parameter
mov r19, r16

ldi r28, low(OLD_ADC_0)
ldi r29, high(OLD_ADC_0)
add r28, r20
adc r29, ZERO
ld r17, Y ; load OLD_ADC_N value into r17
sub r19, r17
brpl DEAD_CHECK
neg r19
DEAD_CHECK:
cpi r19, 5
brlo NO_CHANGE ; Skip ahead if pot change is < the deadzone limit
sbr r18,1 ; Update knob status bit and continue -- pot moved
ldi r28, low(KNOB0_STATUS)
ldi r29, high(KNOB0_STATUS)
add r28, r20 ;
adc r29, ZERO
st Y, r18 ; save updated KNOBN_STATUS
rjmp LOAD_ADC ;

NO_CHANGE:
ldi r17, 0 ; flag pot unchanged
ret

LOAD_ADC:
ldi r17, 1 ; flag pot changed
ret

;-------------------------------------------------------------------------------------------------------------------
; M A I N P R O G R A M
;-------------------------------------------------------------------------------------------------------------------
RESET:
            cli ; disable interrupts

;JTAG Disable - Set JTD in MCSCSR
            lds r16, MCUCSR ; Read MCUCSR
            sbr r16, 1 << JTD ; Set jtag disable flag
            out MCUCSR, r16 ; Write MCUCSR
            out MCUCSR, r16 ; and again as per datasheet

;initialize stack:
   ldi r16, low(RAMEND)
ldi r17, high(RAMEND)
out SPL, r16
out SPH, r17

;initialize variables:
clr ZERO
clr PHASEA_0
     clr PHASEA_1
clr PHASEA_2
clr PHASEB_0
clr PHASEB_1
clr PHASEB_2
clr a_L ; clear DCF registers
clr a_H ;
clr z_L ;
clr z_H ;
clr temp ;
clr temp2 ;
ldi r16, 5
sts KNOB_DEADZONE, r16
ldi r16, 0
sts LED_STATUS, r16 ; LED status = off
sts LED_TIMER, r16 ;
sts BUTTON_STATUS, r16 ; no buttons pressed
sts CONTROL_SWITCH, r16 ; no switches flipped
sts SETMIDICHANNEL, r16 ; Default MIDI channel to zero (omni)
sts SWITCH3, r16 ; MIDI/Save/Load switch hasn't been scanned yet, so clear it
sts FMDEPTH, r16 ; FM Depth = 0
sts GATE, r16 ; GATE = 0
sts GATEEDGE, r16 ; GATEEDGE = 0
sts LEVEL, r16 ; LEVEL = 0
sts ENV_FRAC_L, r16 ;\
sts ENV_FRAC_H, r16 ; > ENV = 0
sts ENV_INTEGR, r16 ;/
sts ADC_CHAN, r16 ;ADC_CHAN = 0
sts NOTE_L, r16 ;\
sts NOTE_H, r16 ; >
sts NOTE_INTG, r16 ;/
sts MIDIPBEND_L, r16 ;\
sts MIDIPBEND_H, r16 ;/ P.BEND = 0
sts MIDIMODWHEEL, r16 ; MOD.WHEEL = 0
sts KNOB_SHIFT, r16 ; Initialize panel shift switch = 0 (unshifted)
sts VCF_STATUS, r16 ; Flag VCF as off (0)
ldi r16, 2
sts PORTACNT, r16 ; PORTACNT = 2
ldi r16, 255
sts POWER_UP, r16 ; Set power_up flag to 255 to force first initialization of panel switches
sts LPF_I, r16 ; no DCF
sts HPF_I, r16
sts MIDINOTE, r16 ; note# = 255
sts MIDINOTEPREV, r16 ; note# = 255
ldi r16, 0x5E ;\
ldi r17, 0xB4 ; \
ldi r18, 0x76 ; \ initialising of
sts SHIFTREG_0, r16 ; / shift register
sts SHIFTREG_1, r17 ; /
sts SHIFTREG_2, r18 ;/
ldi r16, 0 ;\
     ldi r17, 0 ; > Amin = 0
ldi r18, 0 ;/
sts LFOBOTTOM_0, r16 ;\
sts LFOBOTTOM_1, r17 ; > store Amin for LFO
sts LFOBOTTOM_2, r18 ;/
ldi r16, 255 ;\
ldi r17, 255 ; > Amax = 255,999
ldi r18, 255 ;/
sts LFOTOP_0, r16 ;\
sts LFOTOP_1, r17 ; > store Amax for LFO
sts LFOTOP_2, r18 ;/
ldi r18, 20
sts LFO2BOTTOM_0, r16 ;\
sts LFO2BOTTOM_1, r17 ; > store Amin for LFO2
sts LFO2BOTTOM_2, r18 ;/
ldi r18, 100
sts LFO2TOP_0, r16 ;\
sts LFO2TOP_1, r17 ; > store Amax for LFO2
sts LFO2TOP_2, r18 ;/


;initialize sound parameters:
clr r16
sts LFOPHASE, r16 ;
sts LFO2PHASE, r16 ;
sts ENVPHASE, r16 ;
sts DETUNEB_FRAC, r16 ;\
sts DETUNEB_INTG, r16 ;/ detune = 0
sts LFOLEVEL, r16 ;

;initialize port A:
ldi r16, 0x00 ;\
out DDRA, r16 ;/ PA = iiiiiiii all inputs (panel pots)
ldi r16, 0xFF ; enable internal pull-ups, even though we're using analog inputs
out PORTA, r16 ;/ PA = pppppppp

;initialize port B:
ldi r16, 0x00 ;\
out DDRB, r16 ;/ PB = iiiiiiii all inputs, pull-ups enabled
ldi r16, 0xff ;\
out PORTB, r16 ;/ PB = pppppppp

;initialize port C:
     ldi r16, 0xFF ;\
out DDRC, r16 ;/ PC = oooooooo all outputs (DAC)
ldi r16, 0x00 ;\
out PORTC, r16 ;/ PC = 00000000

;initialize port D:
ldi r16, 0x0E ; PD = iiiioooi
out DDRD, r16 ;/ PD0 (MIDI-IN)
ldi r16, 0xFC ;\
out PORTD, r16 ;/ PD = 1111110z


; Turn Power/MIDI LED on at power up

sbi PORTD, 1 ; LED on

; initialize DAC port pins

sbi PORTD, 3 ; Set WR high
cbi PORTD, 2 ; Pull DAC AB port select low


;initialize Timer0:
ldi r16, 0x00 ;\
out TCCr0, r16 ;/ stop Timer 0

;initialize Timer1:
ldi r16, 0x04 ;\ prescaler = CK/256
out TCCr1B, r16 ;/ (clock = 32µs)

;initialize Timer2:
            ldi r16, 54 ;\
            out OCr2, r16 ;/ OCr2 = 54 gives 36363.63636 Hz sample rate at ~440 cycles per sample loop.
            ldi r16, 0x0A ;\ clear timer on compare,
            out TCCr2, r16 ;/ set prescaler = CK/8

;initialize UART:
ldi r16, high((cpu_frequency / (baud_rate * 16)) - 1)
out UBRRH, r16
     ldi r16, low((cpu_frequency / (baud_rate * 16)) - 1)
            out UBRRL, r16

; enable receiver and receiver interrupt
     ldi r16, (1<<RXCIE)|(1<<RXEN) ;\
out UCR, r16 ;/ RXCIE=1, RXEN=1

;initialize ADC:
ldi r16, 0x86 ;\
out ADCSRA, r16 ;/ ADEN=1, clk = 125 kHz

;initialize interrupts:
ldi r16, 0x80 ;\
out TIMSK, r16 ;/ OCIE2=1

     sei ; Interrupt Enable

;start conversion of the first A/D channel:
lds r18, ADC_CHAN
rcall ADC_START

;store initial pot positions as OLD_ADC values to avoid snapping to new value unless knob has been moved.

; Store value of Pot ADC0
ldi r28, low(ADC_0)
ldi r29, high(ADC_0)
add r28, r18
adc r29, ZERO
rcall ADC_END ; r16 = AD(i)
st Y, r16 ; AD(i) --> ADC_i

inc r18 ; Now do ADC1
rcall ADC_START ; start conversion of next channel
inc r28
rcall ADC_END ; r16 = AD(i)
st Y, r16 ; AD(i) --> ADC_i

inc r18 ; Now do ADC2
rcall ADC_START ; start conversion of next channel
inc r28
rcall ADC_END ; r16 = AD(i)
st Y, r16 ; AD(i) --> ADC_i

inc r18 ; Now do ADC3
rcall ADC_START ; start conversion of next channel
inc r28
rcall ADC_END ; r16 = AD(i)
st Y, r16 ; AD(i) --> ADC_i

inc r18 ; Now do ADC4
rcall ADC_START ; start conversion of next channel
inc r28
rcall ADC_END ; r16 = AD(i)
st Y, r16 ; AD(i) --> ADC_i

inc r18 ; Now do ADC5
rcall ADC_START ; start conversion of next channel
inc r28
rcall ADC_END ; r16 = AD(i)
st Y, r16 ; AD(i) --> ADC_i

inc r18 ; Now do ADC6
rcall ADC_START ; start conversion of next channel
inc r28
rcall ADC_END ; r16 = AD(i)
st Y, r16 ; AD(i) --> ADC_i

inc r18 ; Now do ADC7
rcall ADC_START ; start conversion of next channel
inc r28
rcall ADC_END ; r16 = AD(i)
st Y, r16 ; AD(i) --> ADC_i

ldi r18, 0
sts ADC_CHAN,r18
rcall ADC_START ; start conversion of ADC0 for main loop

; Load current patch from eeprom
 
ldi r18, $03
ldi r17, $FE ; Set eeprom address to $03FE (second last byte)
rcall EEPROM_READ ; load current patch number into r16
rcall LOAD_PATCH ; load patch into synthesis engine

; Load MIDI channel from eeprom

ldi r18, $03
ldi r17, $FF ; Set eeprom address to $03FF (last byte)
rcall EEPROM_READ ; load MIDI CHANNEL into r16
sts SETMIDICHANNEL, r16

;initialize the keyboard scan time
in r16, TCNT1L ;\
in r17, TCNT1H ;/ r17:r16 = TCNT1 = t
sts TPREV_KBD_L, r16
sts TPREV_KBD_H, r17

;-------------------------------------------------------------------------------------------------------------------
; Main Program Loop
;
; This is where everything but sound generation happens. This loop is interrupted 36,636 times per second by the
; sample interrupt routine. When it's actually allowed to get down to work, it scans the panel switches every 100ms,
; scans the knobs a lot more than that, calculates envelopes, processes the LFO and parses MIDI input.
;
; In its spare time, Main Program Loop likes to go for long walks, listen to classical music and perform
; existential bit flipping.
;-------------------------------------------------------------------------------------------------------------------
;


MAINLOOP:
            ;---------------------
            ; scan panel switches:
            ;---------------------
;begin:

in r16, TCNT1L ;\
in r17, TCNT1H ;/ r17:r16 = t
lds r18, TPREV_KBD_L ;\
lds r19, TPREV_KBD_H ;/ r19:r18 = t0
sub r16, r18 ;\
sbc r17, r19 ;/ r17:r16 = t - t0
subi r16, LOW(KBDSCAN) ;\
sbci r17, HIGH(KBDSCAN) ;/ r17:r16 = (t-t0) - 100ms
brsh MLP_SCAN ;\
rjmp MLP_WRITE ;/ skip scanning if (t-t0) < 100ms

MLP_SCAN:

; blink LED if LED/save/load button has been pressed
lds r16, SWITCH3
tst r16
breq CONTROL_EXIT ; Set button status: 1=MIDI, 2=SAVE, 4=LOAD
sts BUTTON_STATUS, r16 ; Set control status to MIDI, turn on control timer
ldi r16, 63
sts LED_TIMER, r16
control_exit:
lds r16, BUTTON_STATUS
tst r16
breq MLP_LED_END ; button hasn't been pressed, so skip

; flip panel LED state until button timer is finished
lds r16, LED_STATUS
ldi r17, 64
add r16, r17
cpi r16, $80
brlo MLP_LED_OFF
lds r17, LED_TIMER
dec r17
breq MLP_LED_RESET
sbi PORTD, 1 ; LED on
rjmp MLP_LED_EXIT
MLP_LED_OFF:
lds r17, LED_TIMER
dec r17
breq MLP_LED_RESET
cbi PORTD, 1 ; LED off
rjmp MLP_LED_EXIT
MLP_LED_RESET:
sbi PORTD, 1 ; Clear everything
ldi r16, 0
sts BUTTON_STATUS, r16
MLP_LED_EXIT:
sts LED_STATUS, r16
sts LED_TIMER, r17
MLP_LED_END:

            in r16, TCNT1L
in r17, TCNT1H
sts TPREV_KBD_L, r16 ;\
sts TPREV_KBD_H, r17 ;/ t0 = t


; Read the digital inputs. See below for mapping to SE parameters
;
;
; Micro switches are mapped to PB0-4, PD4-6
in r16, PINB
cbr r16, 0b11100000 ; Clear the highest three bits
in r17, PIND
cbr r17, 0b00001111 ; Clear lowest four bits
lsl r17 ; shift PD4-6 into bits 5-7
add r16, r17 ; Combine values into a single byte

ldi r19, 0x00 ; bits of SWITCH1
ldi r20, 0x00 ; bits of SWITCH2
ldi r21, 0x00 ; bits of SWITCH3

bst r16, 0
bld r20, SW_OSCA_WAVE ; Copy bit 0 into SW_OSCA_WAVE
bst r16, 1
bld r20, SW_OSCB_WAVE ; Copy bit 1 into SW_OSCB_WAVE
bst r16, 2
bld r20, SW_PWM_SWEEP ; Copy bit 2 into SW_PWM_SWEEP
bst r16, 3
bld r20, SW_OSCB_OCT ; Copy bit 3 into SW_OSCB_OCT
bst r16, 4
bld r20, SW_SUSTAIN ; Copy bit 4 into SW_SUSTAIN
bst r16, 5
bld r19, SW_LFO_ENABLE ; Copy bit 5 into SW_LFO_ENABLE
bst r16, 6
bld r19, SW_LFO_WAVE ; Copy bit 6 into SW_LFO_WAVE
bst r16, 7
bld r19, SW_KNOB_SHIFT ; Copy bit 7 into SW_KNOB_SHIFT

sts SWITCH1, r19
sts SWITCH2, r20
     sts SWITCH3, r21 ; Store switch settings


; capture switch values on power up

lds r17, POWER_UP ; Is this the first time through this code since synth was turned on?
sbrs r17, 0
rjmp MLP_SWITCH
sts OLD_SWITCH1, r19 ; Yes: make OLD_SWITCHx = SWITCHx (so we know when they've been flipped)
sts OLD_SWITCH2, r20
clr r17
sts POWER_UP, r17 ; Clear the POWER_UP flag so we don't reinitialize

;service:
MLP_SWITCH:
; Compare SWITCH1 to OLD_SWITCH1. Skip if unchanged.

lds r16, SWITCH1
lds r17, OLD_SWITCH1
cp r16, r17
breq MLP_SWITCH2 ; Switch 1 unchanged, so leave as is.
lds r18, PATCH_SWITCH1

; Compare bits in OLD_SWITCH1 and SWITCH1. If different, copy SWITCH1 bit to PATCH_SWITCH1 bit.
clr r30 ; Register used to indicate which switch 1..16 has been flipped
; Perform an exclusive OR on r17 and r16. Changed bits are flagged as 1's.
eor r17, r16
sbrs r17, 0
rjmp MLP_BIT1 ; Exit if bit is not set
bst r16, 0
bld r18, 0 ; copy bit from SWITCH1 to PATCH_SWITCH1
; Flag dual parameter knobs unmoved because this is the KNOB_SHIFT switch
push r16
rcall CLEAR_KNOB_STATUS
pop r16
ldi r30, 16 ; Flag switch 16 moved
MLP_BIT1:
sbrs r17, 1
rjmp MLP_BIT2
bst r16, 1
bld r18, 1
ldi r30, 15 ; Flag switch 15 moved
MLP_BIT2:
sbrs r17, 2
rjmp MLP_BIT3
bst r16, 2
bld r18, 2
ldi r30, 14 ; Flag switch 14 moved
MLP_BIT3:
sbrs r17, 3
rjmp MLP_BIT4
bst r16, 3
bld r18, 3
ldi r30, 13 ; Flag switch 13 moved
MLP_BIT4:
sbrs r17, 4
rjmp MLP_BIT5
bst r16, 4
bld r18, 4
ldi r30, 8 ; Flag switch 8 moved
MLP_BIT5:
sbrs r17, 5
rjmp MLP_BIT6
bst r16, 5
bld r18, 5
ldi r30, 7 ; Flag switch 7 moved
MLP_BIT6:
sbrs r17, 6
rjmp MLP_BIT7
bst r16, 6
bld r18, 6
ldi r30, 6 ; Flag switch 6 moved
MLP_BIT7:
sbrs r17, 7
rjmp MLP_PATCH1SAVE
bst r16, 7
bld r18, 7
ldi r30, 5 ; Flag switch 5 moved

MLP_PATCH1SAVE:
sts CONTROL_SWITCH, r30 ; Number of last switch flipped: 1..16, where zero indicates none flipped
; DON'T save changes to PATCH_SWITCH1 if BUTTON_STATUS is SAVE (2) because we're about to write the patch that has just been changed by flipping the switch.
lds r17, BUTTON_STATUS
cpi r17, 2
breq MLP_SKIP_PATCH1
sts PATCH_SWITCH1, r18 ; Store changes to patch
MLP_SKIP_PATCH1:
sts OLD_SWITCH1, r16 ; Keep a copy of panel switches so we know if things change next time

MLP_SWITCH2:
; Compare SWITCH2 to OLD_SWITCH2. Skip if unchanged.

lds r16, SWITCH2
lds r17, OLD_SWITCH2
cp r16, r17
breq MLP_SW_EXIT ; Switch 2 unchanged, so leave as is.
lds r18, PATCH_SWITCH2

; Compare bits in OLD_SWITCH2 and SWITCH2. If different, copy SWITCH2 bit to PATCH_SWITCH2 bit.
clr r30 ; Register used to indicate which switch 1..16 has been flipped

; Perform an exclusive OR on r17 and r16. Changed bits are flagged as 1's.
eor r17, r16
sbrs r17, 0
rjmp MLP_BIT1A ; Exit if bit is not set
bst r16, 0
bld r18, 0 ; copy bit from SWITCH2 to PATCH_SWITCH2
ldi r30, 12 ; Flag switch 12 moved
MLP_BIT1A:
sbrs r17, 1
rjmp MLP_BIT2A
bst r16, 1
bld r18, 1
ldi r30, 11 ; Flag switch 11 moved
MLP_BIT2A:
sbrs r17, 2
rjmp MLP_BIT3A
bst r16, 2
bld r18, 2
ldi r30, 10 ; Flag switch 10 moved
MLP_BIT3A:
sbrs r17, 3
rjmp MLP_BIT4A
bst r16, 3
bld r18, 3
ldi r30, 9 ; Flag switch 9 moved
MLP_BIT4A:
sbrs r17, 4
rjmp MLP_BIT5A
bst r16, 4
bld r18, 4
ldi r30, 4 ; Flag switch 4 moved
MLP_BIT5A:
sbrs r17, 5
rjmp MLP_BIT6A
bst r16, 5
bld r18, 5
ldi r30, 3 ; Flag switch 3 moved
MLP_BIT6A:
sbrs r17, 6
rjmp MLP_BIT7A
bst r16, 6
bld r18, 6
ldi r30, 2 ; Flag switch 2 moved
MLP_BIT7A:
sbrs r17, 7
rjmp MLP_PATCH2SAVE
bst r16, 7
bld r18, 7
ldi r30, 1 ; Flag switch 1 moved

MLP_PATCH2SAVE:
sts CONTROL_SWITCH, r30 ; Number of last switch flipped: 1..16, where zero indicates none flipped

; DON'T save changes to PATCH_SWITCH2 if BUTTON_STATUS is SAVE (2) because we're about to write the patch that has just been changed by flipping the switch.
lds r17, BUTTON_STATUS
cpi r17, 2
breq MLP_SKIP_PATCH2
sts PATCH_SWITCH2, r18 ; Store changes to patch
MLP_SKIP_PATCH2:
sts OLD_SWITCH2, r16 ; Keep a copy of panel switches so we know if things change next time

MLP_SW_EXIT:

; Set MIDI channel based on panel switches:
lds r17, BUTTON_STATUS
tst r17
breq SKIP_CONTROL_SET
lds r16, CONTROL_SWITCH
tst r16
breq SKIP_CONTROL_SET ; continue only if a switch was moved
cpi r17, 1
breq SET_MIDI_CH
cpi r17, 2
breq MLP_SAVE
MLP_LOAD:
dec r16 ; Shift patch offset to 0..16
ldi r18, $03
ldi r17, $FE ; Set eeprom address to $03FE (second last byte in memory)
rcall EEPROM_WRITE ; Write current patch # to memory so it will be loaded at power up
rcall LOAD_PATCH ; Fetches the patch correspondng to the control switch number stored in r16
rjmp END_CONTROL_SET ; reset control button
MLP_SAVE:
lds r17, WRITE_MODE
tst r17
breq END_CONTROL_SET ; Skip if we're already in write mode
dec r16 ; Shift patch offset to 0..16
ldi r18, $03
ldi r17, $FE ; Set eeprom address to $03FE (second last byte in memory)
rcall EEPROM_WRITE ; Write current patch # to memory so it will be loaded at power up
ldi r17, 0
sts WRITE_MODE, r17 ; Set knob status to 'unmoved' and save current knob positions
sts WRITE_OFFSET, r17
lsl r16
lsl r16
lsl r16
lsl r16 ; multiply patch number by 16 to get starting address of patch in eeprom
sts WRITE_PATCH_OFFSET, r16 ; switch # 0..16
lds r16, PATCH_SWITCH1
sts SW1, r16
lds r16, PATCH_SWITCH2
sts SW2, r16 ; Copy the patch switches into the MIDI CC table
rcall CLEAR_KNOB_STATUS
rjmp END_CONTROL_SET ; reset control button
SET_MIDI_CH:
; Set MIDI channel - adjust the panel switches so that channel 16 sets the synth in omni mode
inc r16 ; Shift value to 2..17 to make room for omni
cpi r16, 17
brne NOT_OMNI
ldi r16, 1 ; If it was channel 16, force it to channel 1
NOT_OMNI:
dec r16 ; subtract 1 from channel numbers
sts SETMIDICHANNEL, r16 ; 0 for OMNI or channel 1..15
ldi r18, $03
ldi r17, $FF ; Set eeprom address to $03FF (last byte in memory)
rcall EEPROM_WRITE ; Write r16 to eeprom
END_CONTROL_SET:
sbi PORTD, 1 ; Clear control button parameters and leave the LED on
ldi r16, 0 ;
sts BUTTON_STATUS, r16 ;
sts LED_STATUS, r16 ;
sts LED_TIMER, r16 ;
sts CONTROL_SWITCH, r16 ;

SKIP_CONTROL_SET:

; ------------------------------------------------------------------------------------------------------------------------
; Asynchronous EEPROM write
;
; Because EEPROM writes are slow, MeeBlip executes the main program and audio interrupts while eeprom writes happen in the
; background. A new byte is only written if the eeprom hardware flags that it's finished the previous write.
; ------------------------------------------------------------------------------------------------------------------------

MLP_WRITE:
lds r16, WRITE_MODE
sbrc r16,7
rjmp MLP_SKIPSCAN ; Nothing to write, so skip

sbic EECR,EEWE
rjmp MLP_SKIPSCAN ; Skip if we're not finished the last write

; Get the parameter value from MIDI CC table
lds r18, WRITE_OFFSET ; r18 contains the byte offset in the patch
ldi r17, $30
add r17, r18 ; Add the byte offset in the MIDI CC table
ldi r28, low (MIDICC)
   ldi r29, high(MIDICC)
   add r28, r17
   adc r29, zero
   ld r17, Y ; Patch parameter(i) stored in r17

lds r16, WRITE_PATCH_OFFSET
add r16, r18 ; r16 contains the eeprom address of the byte to write, parameter is in r17

; ------------------------------------------------------------------------------------------------------------------------
; Store a single parameter value to eeprom. r16 is the offset, r17 is the data
; ------------------------------------------------------------------------------------------------------------------------
;

WRITE_BYTE:
ldi r19, 0
out EEARH, r19
out EEARL, r16 ; single byte offset from WRITE_OFFSET
out EEDR,r17 ; Write data (r17) to data register
in temp_SREG, SREG ; store SREG value
cli ; Disable global interrupts during timed write
sbi EECR,EEMWE ; Write logical one to EEMWE
sbi EECR,EEWE ; Start eeprom write by setting EEWE
out SREG, temp_SREG ; restore SREG value (I-bit - restarts global interrupts)
cpi r18, 15 ; If eeprom write offset is at the end patch (byte 15)
breq CLEAR_WRITE
inc r18
sts WRITE_OFFSET, r18 ; increment and store eeprom offset for next parameter
rjmp MLP_SKIPSCAN

CLEAR_WRITE:
ldi r17, 255
sts WRITE_MODE, r17 ; Set write mode to 255 (off)

; ------------------------------------------------------------------------------------------------------------------------
; Read potentiometer values
; ------------------------------------------------------------------------------------------------------------------------
;

MLP_SKIPSCAN:

            ;--------------------
            ;read potentiometers:
            ;--------------------


rcall ADC_END ; r16 = AD(i)
lds r18, ADC_CHAN ;\
sts PREV_ADC_CHAN, r18 ; keep track of which ADC channel we're processing.
ldi r28, low(ADC_0)
ldi r29, high(ADC_0)
add r28, r18
adc r29, ZERO
st Y, r16 ; AD(i) --> ADC_i

;next channel:
inc r18
andi r18, 0x07
sts ADC_CHAN,r18
rcall ADC_START ; start conversion of next channel


;-------------------------------------------------------------------------------------------------------------------
; Store knob values based on KNOB SHIFT switch setting
;
; Pots 2-5 have two parameters with the KNOB SHIFT
; switch used to select knob bank 0 or 1.
;
; To make things more challenging, the ADC value read from each pot might fluctuate
; through several values. This will cause the synth to think the pot has been moved and update
; the parameter value. To avoid this, require the pot to be moved a level of at least
; X before updating (deadzone check). To reduce processing time, a knob status byte
; tracks whether the pots have been moved since the KNOB SHIFT switch was updated.
; If the status bit is set, we can just skip the deadzone check and update.
;-------------------------------------------------------------------------------------------------------------------
;
; First process the unshifted pots (0, 1, 6, 7)
;

lds r20, PREV_ADC_CHAN ; Only process the most recently scanned pot, store ADC channel 0..7 in r20

CHECK_0:
cpi r20, 0 ; Update knob 0 - filter resonance?
brne CHECK_1
rcall POT_SCAN ; If so, check if parameter should be updated with pot value in r16
tst r17
breq EXIT_CHECK_0 ; Skip update if pot hasn't been updated
sts RESONANCE, r16
EXIT_CHECK_0:
lds r16, RESONANCE ; Limit resonance
cpi r16, 252 ;\
BRLO LOAD_REZ ; | Limit maximum knob resonance to 252
ldi r16, 252 ;/
LOAD_REZ:
sts RESONANCE,r16
rjmp DONE_KNOBS

CHECK_1:
cpi r20, 1 ; Update knob 1 - filter cutoff?
brne CHECK_6
rcall POT_SCAN ; If so, check if parameter should be updated with pot value in r16
tst r17
breq EXIT_KNOBA ; Skip update if pot hasn't been updated
sts CUTOFF,r16
rjmp DONE_KNOBS

CHECK_6:
cpi r20, 6 ; Update knob 6, PWM?
brne CHECK_7
rcall POT_SCAN ; If so, check if parameter should be updated with pot value in r16
tst r17
breq EXIT_CHECK_6 ; Skip update if pot hasn't been updated
sts PULSE_KNOB, r16
EXIT_CHECK_6:
; Store limited PULSE_WIDTH values
lds r16, PULSE_KNOB ; grab the patch value, just in case it hasn't been updated
lsr r16 ; Divide it by two (we only need 0-50% pulse)
subi r16, 18
brcc LIMIT_PWM1
ldi r16, 4 ; restrict PULSE_KNOB_LIMITED to 4-115 (avoid 0% and 50% pulse)
rjmp LIMIT_PWM3
LIMIT_PWM1:
cpi r16, 4
brlo LIMIT_PWM2
rjmp LIMIT_PWM3
LIMIT_PWM2:
ldi r16, 4
LIMIT_PWM3:
sts PULSE_KNOB_LIMITED, r16
rjmp DONE_KNOBS

CHECK_7:
cpi r20, 7 ; Update knob 7, OSC Detune?
brne KNOB_SHIFT_CHECK
rcall POT_SCAN ; If so, check if parameter should be updated with pot value in r16
tst r17
breq EXIT_CHECK7 ; Skip update if pot hasn't been updated
sts OSC_DETUNE, r16
EXIT_CHECK7:
lds r16, OSC_DETUNE ; grab the patch value, just in case it hasn't been updated
rcall NONLINPOT ; AD6.1 --> DCO B detune with non-linear knob (center is tuned)
subi r17, 128
sts DETUNEB_FRAC, r16 ; Value -128.000..+127.996
sts DETUNEB_INTG, r17
EXIT_KNOBA:
rjmp DONE_KNOBS


KNOB_SHIFT_CHECK:

; Now process the shifted pots ( 2, 3, 4, 5)
; Check which bank of knob parameters we're updating.

lds r19, PATCH_SWITCH1
sbrc r19, SW_KNOB_SHIFT ; If knob Shift bit set, jump to process bank 1
jmp KNOB_BANK_1

;-------------------------------------------------------------------------------------------------------------------
; KNOB BANK 0 - unshifted ( glide, filter envelope amount, LFO depth, LFO rate)
;-------------------------------------------------------------------------------------------------------------------

CHECK_2:
cpi r20, 2 ; Update knob 2, LFO rate?
brne CHECK_3
rcall POT_SCAN ; If so, check if parameter should be updated with pot value in r16
tst r17
breq EXIT_CHECK2A ; Skip update if pot not updated, post-process DCF_DECAY
sts LFOFREQ,r16
rjmp EXIT_CHECK2A

CHECK_3: cpi r20, 3 ; Update knob 3, LFO depth?
brne CHECK_4
rcall POT_SCAN ; If so, check if parameter should be updated with pot value in r16
tst r17
breq EXIT_KNOBB ; Skip update if pot hasn't been updated
sts LFOLEVEL,r16
sts PANEL_LFOLEVEL, r16
rjmp DONE_KNOBS

CHECK_4: cpi r20, 4 ; Update knob 4, Filter envelope amount?
brne CHECK_5
rcall POT_SCAN ; If so, check if parameter should be updated with pot value in r16
tst r17
breq EXIT_CHECK4A ; Skip update if pot hasn't been updated (post process AMP_DECAY parameters)
sts VCFENVMOD, r16
rjmp EXIT_CHECK4A

CHECK_5: cpi r20, 5 ; Update knob 5, Glide/Portamento?
brne EXIT_KNOBB
rcall POT_SCAN ; If so, check if parameter should be updated with pot value in r16
tst r17
breq EXIT_KNOBB ; Skip update if pot hasn't been updated
lsr r16 ; 50% of original value +
mov r17, r16
lsr r17 ; 25% of original =
add r16, r17 ; 75% of original
sts PORTAMENTO,r16

EXIT_KNOBB:
rjmp DONE_KNOBS
;-------------------------------------------------------------------------------------------------------------------
; KNOB BANK 1
;-------------------------------------------------------------------------------------------------------------------
KNOB_BANK_1:

CHECK_2A:
cpi r20, 2 ; Update knob 2^, Filter decay?
brne CHECK_3A
rcall POT_SCAN ; If so, check if parameter should be updated with pot value in r16
tst r17
breq EXIT_CHECK2A ; Skip update if pot hasn't been updated
sts KNOB_DCF_DECAY, r16
EXIT_CHECK2A:
lds r16, KNOB_DCF_DECAY ; Grab knob patch value just in case it hasn't been changed
lds r19, PATCH_SWITCH2
sbrs r19, SW_SUSTAIN
rjmp SUSTAIN_OFF ; skip if sustain switch is off
ldi r19, 255 ; Sustain is on, so...
sts SUSTAINLEVEL2, r19 ; Set sustain to maximum
sts DECAYTIME2, r19 ; Set decay to maximum
sts RELEASETIME2, r16 ; Set release time to value of decay knob
rjmp DONE_KNOBS
SUSTAIN_OFF:
ldi r19, 0 ; Sustain is off, so...
sts SUSTAINLEVEL2, r19 ; Set sustain to minimum
sts DECAYTIME2, r16 ; Set decay time to value of decay knob
sts RELEASETIME2, r16 ; Set release time to value of decay knob
rjmp DONE_KNOBS

CHECK_3A: cpi r20, 3 ; Update knob 3^, Filter attack?
brne CHECK_4A
rcall POT_SCAN ; If so, check if parameter should be updated with pot value in r16
tst r17
breq DONE_KNOBS ; Skip update if pot hasn't been updated
sts KNOB_DCF_ATTACK, r16
rjmp DONE_KNOBS

CHECK_4A: cpi r20, 4 ; Update knob 4^, Amplitude decay?
brne CHECK_5A
rcall POT_SCAN ; If so, check if parameter should be updated with pot value in r16
tst r17
breq EXIT_CHECK4A ; Skip update if pot hasn't been updated
sts KNOB_AMP_DECAY, r16
EXIT_CHECK4A:
lds r16, KNOB_AMP_DECAY ; Grab knob patch value just in case it hasn't been changed
lds r19, PATCH_SWITCH2
sbrs r19, SW_SUSTAIN
rjmp DCF_SUSTAIN_OFF ; Skip if sustain is off...
ldi r19, 255 ; Sustain is on, so...
sts SUSTAINLEVEL, r19 ; Set sustain to maximum
sts DECAYTIME, r19 ; Set decay to maximum
sts RELEASETIME, r16 ; Set release time to value of decay knob
rjmp DONE_KNOBS
DCF_SUSTAIN_OFF:
ldi r19, 0 ; Sustain is off, so...
sts SUSTAINLEVEL, r19 ; Set sustain to minimum
sts DECAYTIME, r16 ; Set decay time to value of decay knob
sts RELEASETIME, r16 ; Set release time to value of decay knob
rjmp DONE_KNOBS

CHECK_5A: cpi r20, 5 ; Update knob 5^, Amplitude attack?
brne DONE_KNOBS
rcall POT_SCAN ; If so, check if parameter should be updated with pot value in r16
tst r17
breq DONE_KNOBS ; Skip update if pot hasn't been updated
sts KNOB_AMP_ATTACK, r16

DONE_KNOBS:


;-------------------------------------------------------------------------------------------------------------------
; Add MIDI velocity code here
;-------------------------------------------------------------------------------------------------------------------

MIDI_VELOCITY:

; Add velocity control of filter

lds R16, MIDIVELOCITY ; Value is 0..127
lsl R16
lds r17, VCFENVMOD
mul r16, r17
sts VELOCITY_ENVMOD, r1

;-------------------------------------------------------------------------------------------------------------------


            ;-------------
            ;calculate dT:
            ;-------------
in r22, TCNT1L ;\
in r23, TCNT1H ;/ r23:r22 = TCNT1 = t
mov r18, r22 ;\
     mov r19, r23 ;/ r19:r18 = t
lds r16, TPREV_L ;\
lds r17, TPREV_H ;/ r17:r16 = t0
sub r22, r16 ;\ r23:r22 = t - t0 = dt
sbc r23, r17 ;/ (1 bit = 32 µs)
sts TPREV_L, r18 ;\
sts TPREV_H, r19 ;/ t0 = t
     sts DELTAT_L, r22 ;\
sts DELTAT_H, r23 ;/ r23:r22 = dT

            ;----
            ;LFO:
            ;----

;calculate dA:
lds r16, LFOFREQ ;\
com r16 ;/ r16 = 255 - ADC0
rcall ADCTORATE ; r19:r18:r17:r16 = rate of rise/fall
lds r22, DELTAT_L ;\
     lds r23, DELTAT_H ;/ r23:r22 = dT
rcall MUL32X16 ; r18:r17:r16 = dA
lds r19, LFO_FRAC_L
lds r20, LFO_FRAC_H
     lds r21, LFO_INTEGR
subi r21, 128
ldi r31, 0 ; flag = 0
lds r30, LFOPHASE
tst r30
brne MLP_LFOFALL

;rising phase:

MLP_LFORISE:
            lds r22, LFOTOP_0 ;\
lds r23, LFOTOP_1 ; > r24:r23:r22 = Amax
lds r24, LFOTOP_2 ;/
add r19, r16 ;\
     adc r20, r17 ; > A += dA
adc r21, r18 ;/
brcs MLP_LFOTOP
cp r19, r22 ;\
cpc r20, r23 ; > A - Amax
cpc r21, r24 ;/
brlo MLP_LFOX ; skip when A < Amax

;A reached top limit:

MLP_LFOTOP:
            mov r19, r22 ;\
mov r20, r23 ; > A = Amax
mov r21, r24 ;/
ldi r30, 1 ; begin of falling
ldi r31, 1 ; flag = 1
rjmp MLP_LFOX

;falling phase:

MLP_LFOFALL:
            lds r22, LFOBOTTOM_0 ;\
lds r23, LFOBOTTOM_1 ; > r24:r23:r22 = Amin
lds r24, LFOBOTTOM_2 ;/
     sub r19, r16 ;\
sbc r20, r17 ; > A -= dA
sbc r21, r18 ;/
brcs MLP_LFOBOTTOM
cp r22, r19 ;\
cpc r23, r20 ; > Amin - A
cpc r24, r21 ;/
brlo MLP_LFOX ; skip when A > Amin

;A reached bottom limit:

MLP_LFOBOTTOM:
            mov r19, r22 ;\
mov r20, r23 ; > A = Amin
mov r21, r24 ;/
ldi r30, 0 ; begin of rising
ldi r31, 1 ; flag = 1

MLP_LFOX:
            sts LFOPHASE, r30
subi r21, 128 ; r21,r20:r19 = LFO tri wave
sts LFO_FRAC_L, r19 ;\
sts LFO_FRAC_H, r20 ; > store LFO value
     sts LFO_INTEGR, r21 ;/

;switch norm/rand:

;determine Amin i Amax:
ldi r16, 0 ;\
ldi r17, 0 ; > Amin when not LFO==tri
     ldi r18, 0 ;/ and not LFO==rand
lds r30, PATCH_SWITCH1
sbrs r30, SW_LFO_RANDOM ; LFO random if switch is set
     RJMP MLP_LFOAWR
tst r31
     breq MLP_LFOAX
lds r16, SHIFTREG_0 ;\
lds r17, SHIFTREG_1 ; \ Amin = pseudo-random number
lds r18, SHIFTREG_2 ; / 0,000..127,999
andi r18, 0x7F ;/

MLP_LFOAWR:
            sts LFOBOTTOM_0, r16 ;\
sts LFOBOTTOM_1, r17 ; > store Amin
sts LFOBOTTOM_2, r18 ;/
com r16 ;\
com r17 ; > Amax = 255,999 - Amin
com r18 ;/ 128,000..255,999
sts LFOTOP_0, r16 ;\
sts LFOTOP_1, r17 ; > store Amax
sts LFOTOP_2, r18 ;/

MLP_LFOAX:
lds r16, PATCH_SWITCH1
sbrs r16, SW_LFO_RANDOM
rjmp MLP_LFONORM
tst r31 ; flag == 1 ?
breq MLP_LFONWR ; jump when not
lds r21, SHIFTREG_2
rjmp MLP_LFOWR

MLP_LFONORM:

;switch tri/squ:
lds r16, PATCH_SWITCH1 ;\ Z=0: triangle
sbrs r16, SW_LFO_WAVE ;/ Z=1: square
     rjmp MLP_LFOWR
lsl r21 ; Cy = (LFO < 0)
ldi r21, 127 ;\
adc r21, ZERO ;/ r21 = -128 or +127

MLP_LFOWR:
            sts LFOVALUE, r21

; Modulation wheel: Use highest value (Front panel or MIDI)
MLP_LFONWR:
lds r16, PANEL_LFOLEVEL
lds r17,MIDIMODWHEEL
cp r16, r17
     brsh MLP_LFOLWR
mov r16, r17 ; MOD.WHEEL is greater

MLP_LFOLWR:
            sts LFOLEVEL, r16

MLP_LFOMWX:

            ;----
            ;LFO2 (Used to sweep PWM waveform)
            ;----

;calculate dA:
lds r16, PULSE_KNOB ; Use PULSE_KNOB as PWM Sweep rate.
lsr r16
lsr r16 ; Limit PWM sweep rate to 0..63 to avoid PWM aliasing
com r16 ;/ r16 = 255 - ADC0
rcall ADCTORATE ; r19:r18:r17:r16 = rate of rise/fall
lds r22, DELTAT_L ;\
     lds r23, DELTAT_H ;/ r23:r22 = dT
rcall MUL32X16 ; r18:r17:r16 = dA
lds r19, LFO2_FRAC_L
lds r20, LFO2_FRAC_H
     lds r21, LFO2_INTEGR
subi r21, 128
ldi r31, 0 ; flag = 0
lds r30, LFO2PHASE
tst r30
brne MLP_LFO2FALL

;rising phase:

MLP_LFO2RISE:
            lds r22, LFO2TOP_0 ;\
lds r23, LFO2TOP_1 ; > r24:r23:r22 = Amax
lds r24, LFO2TOP_2 ;/
add r19, r16 ;\
     adc r20, r17 ; > A += dA
adc r21, r18 ;/
brcs MLP_LFO2TOP
cp r19, r22 ;\
cpc r20, r23 ; > A - Amax
cpc r21, r24 ;/
brlo MLP_LFO2X ; skip when A < Amax

;A reached top limit:

MLP_LFO2TOP:
            mov r19, r22 ;\
mov r20, r23 ; > A = Amax
mov r21, r24 ;/
ldi r30, 1 ; begin of falling
ldi r31, 1 ; flag = 1
rjmp MLP_LFO2X

;falling phase:

MLP_LFO2FALL:
            lds r22, LFO2BOTTOM_0 ;\
lds r23, LFO2BOTTOM_1 ; > r24:r23:r22 = Amin
lds r24, LFO2BOTTOM_2 ;/
     sub r19, r16 ;\
sbc r20, r17 ; > A -= dA
sbc r21, r18 ;/
brcs MLP_LFO2BOTTOM
cp r22, r19 ;\
cpc r23, r20 ; > Amin - A
cpc r24, r21 ;/
brlo MLP_LFO2X ; skip when A > Amin

;A reached bottom limit:

MLP_LFO2BOTTOM:
            mov r19, r22 ;\
mov r20, r23 ; > A = Amin
mov r21, r24 ;/
ldi r30, 0 ; begin of rising
ldi r31, 1 ; flag = 1

MLP_LFO2X:
            sts LFO2PHASE, r30
subi r21, 128 ; r21,r20:r19 = LFO2 tri wave
sts LFO2_FRAC_L, r19 ;\
sts LFO2_FRAC_H, r20 ; > store LFO2 value
     sts LFO2_INTEGR, r21 ;/

subi r21, $80 ; remove sign
            sts PULSE_WIDTH, r21 ; Update pulse width value


;----
            ;ENV:
            ;----
;check envelope phase:
lds r17, ENVPHASE
lds r16, KNOB_AMP_ATTACK
;cpi r17, 5 ; If we're in pre-attack mode, zero the envelope and start attack, otherwise continue
;brne MLP_PHASE
;ldi r17, 0
;sts ENV_FRAC_L, r17 ;\
;sts ENV_FRAC_H, r17 ; > Set envelope to zero
;sts ENV_INTEGR, r17 ;/
;ldi r17, 1
;sts ENVPHASE, r17 ; store new phase (attack)


MLP_PHASE: cpi r17, 1
breq MLP_ENVAR ; when "attack"
lds r16, DECAYTIME
cpi r17, 2
breq MLP_ENVAR ; when "decay"
lds r16, RELEASETIME
cpi r17, 4
breq MLP_ENVAR ; when "release"
lds r22, SUSTAINLEVEL
cpi r17, 3 ; when sustain
breq MLP_ESUSTAIN
rjmp MLP_EEXIT ; when "stop" or "sustain"

;calculate dL:

MLP_ENVAR:
            rcall ADCTORATE ; r19:r18:r17:r16 = rate of rise/fall
lds r22, DELTAT_L ;\
lds r23, DELTAT_H ;/ r23:r22 = dT
rcall MUL32X16 ; r18:r17:r16 = dL

;add/subtract dL to/from L:
lds r19, ENV_FRAC_L ;\
lds r20, ENV_FRAC_H ; > r21:r20:r19 = L
     lds r21, ENV_INTEGR ;/
lds r22, ENVPHASE
cpi r22, 4
breq MLP_ERELEASE

MLP_EATTACK:
cpi r22, 2
breq MLP_EDECAY
add r19, r16 ;\
adc r20, r17 ; > r21:r20:r19 = L + dL
adc r21, r18 ;/
brcc MLP_ESTORE

;L reached top limit:
ldi r19, 255 ;\
ldi r20, 255 ; > L = Lmax
ldi r21, 255 ;/
ldi r16, 2 ; now decay
rjmp MLP_ESTOREP

MLP_EDECAY:
            sub r19, r16 ;\
sbc r20, r17 ; > r21:r20:r19 = L - dL
sbc r21, r18 ;/
brcs MLP_BOTTOM ; Exit if we went past bottom level
lds r22, SUSTAINLEVEL
cp r22, r21
brlo MLP_ESTORE ; Keep going if we haven't hit sustain level
ldi r16, 3 ; now sustain
sts ENVPHASE, r16 ; store phase
MLP_ESUSTAIN:
clr r19 ; correct sustain level after decay is done
clr r20
mov r21, r22
rjmp MLP_ESTORE

MLP_ERELEASE:
            sub r19, r16 ;\
sbc r20, r17 ; > r21:r20:r19 = L - dL
sbc r21, r18 ;/
brcc MLP_ESTORE

;L reached bottom limit:
MLP_BOTTOM:
ldi r19, 0 ;\
ldi r20, 0 ; > L = 0
ldi r21, 0 ;/
ldi r16, 0 ; stop

MLP_ESTOREP:
            sts ENVPHASE, r16 ; store phase

MLP_ESTORE:
            sts ENV_FRAC_L, r19 ;\
sts ENV_FRAC_H, r20 ; > store L
sts ENV_INTEGR, r21 ;/

MLP_EEXIT:



;----
            ;ENV 2 (VCF):
            ;----
;check envelope phase:
lds r17, ENVPHASE2
lds r16, KNOB_DCF_ATTACK
;cpi r17, 5 ; If we're in pre-attack mode, zero the envelope and start attack, otherwise continue
;brne MLP_PHASE2
;ldi r17, 0
;sts ENV_FRAC_L2, r17 ;\
;sts ENV_FRAC_H2, r17 ; > Set envelope to zero
;sts ENV_INTEGr2, r17 ;/
;ldi r17, 1
;sts ENVPHASE2, r17 ; store new phase (attack)

MLP_PHASE2:
cpi r17, 1
breq MLP_ENVAR2 ; when "attack"
lds r16, DECAYTIME2
cpi r17, 2
breq MLP_ENVAR2 ; when "decay"
lds r16, RELEASETIME2
cpi r17, 4
breq MLP_ENVAR2 ; when "release"
lds r22, SUSTAINLEVEL2
cpi r17, 3 ; when sustain
breq MLP_ESUSTAIN2
rjmp MLP_EEXIT2 ; when "stop" or "sustain"

;calculate dL:

MLP_ENVAr2:
            rcall ADCTORATE ; r19:r18:r17:r16 = rate of rise/fall
lds r22, DELTAT_L ;\
lds r23, DELTAT_H ;/ r23:r22 = dT
rcall MUL32X16 ; r18:r17:r16 = dL

;add/subtract dL to/from L:
lds r19, ENV_FRAC_L2 ;\
lds r20, ENV_FRAC_H2 ; > r21:r20:r19 = L
     lds r21, ENV_INTEGr2 ;/
lds r22, ENVPHASE2
cpi r22, 4
breq MLP_ERELEASE2

MLP_EATTACK2:
cpi r22, 2
breq MLP_EDECAY2
add r19, r16 ;\
adc r20, r17 ; > r21:r20:r19 = L + dL
adc r21, r18 ;/
brcc MLP_ESTORE2

;L reached top limit:
ldi r19, 255 ;\
ldi r20, 255 ; > L = Lmax
ldi r21, 255 ;/
ldi r16, 2 ; now decay
rjmp MLP_ESTOREP2

MLP_EDECAY2:
            sub r19, r16 ;\
sbc r20, r17 ; > r21:r20:r19 = L - dL
sbc r21, r18 ;/
brcs MLP_BOTTOM2 ; Exit if we went past bottom level
lds r22, SUSTAINLEVEL2
cp r22, r21
brlo MLP_ESTORE2 ; Keep going if we haven't hit sustain level
ldi r16, 3 ; now sustain
sts ENVPHASE2, r16 ; store phase
MLP_ESUSTAIN2:
clr r19 ; correct sustain level after decay is done
clr r20
mov r21, r22
rjmp MLP_ESTORE2

MLP_ERELEASE2:
            sub r19, r16 ;\
sbc r20, r17 ; > r21:r20:r19 = L - dL
sbc r21, r18 ;/
brcc MLP_ESTORE2

;L reached bottom limit:
MLP_BOTTOM2:
ldi r19, 0 ;\
ldi r20, 0 ; > L = 0
ldi r21, 0 ;/
ldi r16, 0 ; stop
sts VCF_STATUS, r16 ; Flag VCF as off when we hit the bottom limit.

MLP_ESTOREP2:
            sts ENVPHASE2, r16 ; store phase

MLP_ESTORE2:
            sts ENV_FRAC_L2, r19 ;\
sts ENV_FRAC_H2, r20 ; > store L
sts ENV_INTEGr2, r21 ;/

; End of Envelope 2

MLP_EEXIT2:
            ;-----
            ;GATE:
            ;-----
lds r16, GATE
tst r16 ; check GATE
brne MLP_KEYON

;no key is pressed:

MLP_KEYOFF:
            ldi r16,4 ;\

; don't restart envelope 1 for release if it's already stopped.
lds r17, ENVPHASE
tst r17
breq MLP_NOTEON ; Don't put envelope 1 in release mode if it is already stopped

sts ENVPHASE, r16 ; "release"

; don't restart envelope 2 for release if it's already stopped.
lds r17, ENVPHASE2
tst r17
breq MLP_NOTEON ; Don't put envelope 2 in release mode if it is already stopped
;

sts ENVPHASE2, r16 ; "release" for envelope 2
rjmp MLP_NOTEON

;key is pressed:

MLP_KEYON:
            lds r16, GATEEDGE
tst r16 ; Z=0 when key has just been pressed
breq MLP_NOTEON

;key has just been pressed:
ldi r16, 0 ;\
sts GATEEDGE, r16 ;/ GATEEDGE = 0
lds r16, PORTACNT ;\
tst r16 ; \
breq MLP_KEYON1 ; > if ( PORTACNT != 0 )
dec r16 ; / PORTACNT--
sts PORTACNT, r16 ;/

MLP_KEYON1:

;envelope starts:
ldi r16, 1
sts ENVPHASE, r16 ; attack
sts ENVPHASE2, r16 ; attack for envelope 2
sts VCF_STATUS, r16 ; Flag VCF as on

; LFO starts when note triggered:
ldi r16, 255 ;\
ldi r17, 255 ; > A = Amax
ldi r18, 127 ;/
sts LFO_FRAC_L, r16 ;\
sts LFO_FRAC_H, r17 ; > store A
sts LFO_INTEGR, r18 ;/
ldi r16, 1 ;\
sts LFOPHASE, r16 ;/ begin of falling

MLP_NOTEON:
            ;-------------
            ;DCO A, DCO B:
            ;-------------
ldi r25, 0 ;\
ldi r22, 0 ; > r23,r22:r25 = note# 0..127
lds r23, MIDINOTE ;/
cpi r23, 255
brne MLP_NLIM2
rjmp MLP_VCOX

;note# limited to 36..96:

MLP_NLIM1:
            subi r23, 12

MLP_NLIM2:
            cpi r23, 97
brsh MLP_NLIM1
rjmp MLP_NLIM4

MLP_NLIM3:
            subi r23, 244

MLP_NLIM4:
            cpi r23, 36
brlo MLP_NLIM3

;transpose 1 octave down:
subi r23, 12 ; n -= 12 Note range limited to 24..84

;portamento:
lds r25, NOTE_L ;\
lds r26, NOTE_H ; > r27,r26:r25 = nCurr
lds r27, NOTE_INTG ;/
lds r16, PORTACNT ;\
     tst r16 ; > jump when it's the first note
brne MLP_PORTAWR ;/ (PORTACNT != 0)
lds r16, PORTAMENTO
     rcall ADCTORATE
push r22
push r23
mov r22, r18 ;\ r23:r22 = portamento rate
mov r23, r19 ;/ 65535..27
ldi r16, 0
ldi r17, 0
lds r18, DELTAT_L
lds r19, DELTAT_H
ldi r20, 3
rcall SHr32
rcall MUL32X16 ; r18,r17:r16 = nDelta
pop r23
pop r22
mov r19, r16 ;\
mov r20, r17 ; > r21,r20:r19 = nDelta
mov r21, r18 ;/
lds r25, NOTE_L ;\
lds r26, NOTE_H ; > r27,r26:r25 = nCurr
lds r27, NOTE_INTG ;/
cp r22, r26 ;\ nEnd - nCurr
cpc r23, r27 ;/ Cy = (nEnd < nCurr)
brsh MLP_PORTAADD

MLP_PORTAMIN:
            sub r25, r19 ;\
sbc r26, r20 ; > nCurr -= nDelta
sbc r27, r21 ;/
cp r22, r26 ;\ nEnd - nCurr;
cpc r23, r27 ;/ Cy = (nEnd < nCurr)
brlo MLP_PORTA1
rjmp MLP_PORTAEND

MLP_PORTAADD:
            add r25, r19 ;\
adc r26, r20 ; > nCurr += nDelta
adc r27, r21 ;/
cp r22, r26 ;\ nEnd - nCurr;
cpc r23, r27 ;/ Cy = (nEnd < nCurr)
brsh MLP_PORTA1

MLP_PORTAEND:
            ldi r25, 0 ;\
mov r26, r22 ; > nCurr = nEnd
     mov r27, r23 ;/

MLP_PORTA1:
            mov r22, r26
mov r23, r27

MLP_PORTAWR:
         sts NOTE_L, r25
sts NOTE_H, r22
sts NOTE_INTG, r23

;pitch bender (-12..+12):
lds r16, MIDIPBEND_L ;\ r17,r16 = P.BEND
     lds r17, MIDIPBEND_H ;/ -128,000..+127,996
ldi r18, 5 ;\ r17,r16 = P.BEND/32
rcall ASr16 ;/ -4,000..+3,999
mov r18, r16 ;\ r19,r18 = P.BEND/32
mov r19, r17 ;/ -4,000..+3,999
add r16, r18 ;\ r17,r16 = 2/32*P.BEND
adc r17, r19 ;/ -8,000..+7,999
add r16, r18 ;\ r17,r16 = 3/32*P.BEND
adc r17, r19 ;/ -12,000..+11,999
add r22, r16 ;\
adc r23, r17 ;/ add P.BEND

MLP_PBX:
;for "DCF KBD TRACK":
sts PITCH, r23 ; n = 0..108


;LFO modulation:
lds r16, PATCH_SWITCH1 ; Check LFO destination bit.
sbrs r16, SW_LFO_DEST ; DCF is 0, DCO is 1
jmp MLP_VCOLFOX ; exit when LFO=DCF
lds r16, LFOVALUE ; r16 = LFO -128..+127
     lds r17, LFOLEVEL ; r17 = LFO level 0..255

lds r18, PATCH_SWITCH1 ; Is the LFO enabled?
sbrs r18, SW_LFO_ENABLE
ldi r17, 0 ; Set LFO level to zero if switch is off

;nonlinear potentiometer function:
mov r18, r17 ; r18 = LL
lsr r17 ; r17 = LL/2
cpi r18, 128
brlo MLP_OM1 ; skip if LL = 0..127
subi r17, 128 ; r17 = 0,5*LL-128 -64..-1
add r17, r18 ; r17 = 1,5*LL-128 +64..254

MLP_OM1:
mulsu r16, r17 ; LFOVALUE*LFOLEVEL
movw r16, r0
ldi r18, 4 ;\
rcall ASr16 ;/ r17,r16 = LFO*mod / 16
add r22, r16 ;\
adc r23, r17 ;/ add LFO to note #

;limiting to 0..108
tst r23
brpl MLP_VCOLFO1
ldi r22, 0
ldi r23, 0
rjmp MLP_VCOLFOX

MLP_VCOLFO1:
            cpi r23, 109
brlo MLP_VCOLFOX
ldi r22, 0
ldi r23, 108

MLP_VCOLFOX:
            push r22 ;\ note# = 0..108
push r23 ;/ store for phase delta B

; determine the wavetable for osc A: note = 0..108

; Track which wavetable to use:
mov r25, r23 ; Store a copy of the note number in r25
subi r25, 13 ; 13..108
brcc WTA_NOUFL
clr r25
WTA_NOUFL:
lsr r25
lsr r25 ; (108-12-1)/8 = 11
lsr r25 ; 0..11
sts WAVETABLE_A, r25 ; Save wavetable 0..11 for lookup when generating oscillator

;phase delta A:
;octave A:
rcall NOTERECALC ; r23,r22 = m12 (0,0..11,996),
; r20 = n12 (0..11)
rcall LOAD_DELTA ; r19:r18:r17:r16 = delta
rcall SHL32 ; r19:r18:r17:r16 = delta*(2^exp)

; store delta
   sts DELTAA_0,r17
   sts DELTAA_1,r18
   sts DELTAA_2,r19

;phase delta B:
pop r23 ;\
pop r22 ;/ n

;detune B:
lds r16, DETUNEB_FRAC ;\ r17,r16 = detuneB
lds r17, DETUNEB_INTG ;/ -128,000..+127,996
ldi r18, 4 ;\ r17,r16 = detuneB / 16
     rcall ASr16 ;/ -8,0000..+7,9998
add r22, r16 ;\
adc r23, r17 ;/

;octave B:
            lds r16, PATCH_SWITCH2 ; b7 = octave B: 0=down, 1=up
sbrc r16, SW_OSCB_OCT
subi r23, 244 ; n += 12

; determine the wavetable for osc B; r23: note = 0..108,
; Track which wavetable to use:
mov r25, r23 ; Store a copy of the note number in r25
subi r25, 13 ; 13..108
brcc WTB_NOUFL
clr r25
WTB_NOUFL:
lsr r25
lsr r25 ; (108-12-1)/8 = 11
lsr r25 ; 0..11
sts WAVETABLE_B, r25 ; Save wavetable 0..15 for lookup when generating oscillator

rcall NOTERECALC ; r23,r22 = m12 (0,0..11,996),
; r20 = n12 (0..11)
rcall LOAD_DELTA ; r19:r18:r17:r16 = delta
rcall SHL32 ; r19:r18:r17:r16 = delta*(2^exp)

sts DELTAB_0,r17
   sts DELTAB_1,r18
   sts DELTAB_2,r19
 

MLP_VCOX:
            ;----
            ;DCF:
            ;----
;LFO mod:
ldi r30, 0 ;\
ldi r31, 0 ;/ sum = 0

lds r16, PATCH_SWITCH1 ; Check LFO destination bit.
sbrc r16, SW_LFO_DEST ; DCF is 0, DCO is 1
jmp MLP_DCF0 ; exit when LFO=DCO
lds r16, LFOVALUE ; r16 = LFO -128..+127
lds r17, LFOLEVEL ; r17 = DCF LFO MOD 0..255
lds r18, PATCH_SWITCH1 ; Is the LFO enabled?
sbrs r18, SW_LFO_ENABLE
ldi r17, 0 ; Set LFO level to zero if switch is off
mulsu r16, r17
mov r30, r1
ldi r31, 0
rol r1 ; r1.7 --> Cy (sign)
sbc r31, r31 ; sign extension to r31

MLP_DCF0:

;ENV mod:
            lds r16, ENV_INTEGr2 ; Get the integer part of the filter envelope
lds r17, VELOCITY_ENVMOD ; Use MIDI velocity * envmod
mul r16, r17
movw r16,r0 ; r17,r16 = FILTER ENV * ENVMOD
     rol r16 ; Cy = r16.7 (for rounding)
adc r30, r17
adc r31, ZERO

;KBD TRACK:
lds r16, PITCH ; r16 = n (12/octave) 0..96
lsl r16 ; r16 = 2*n (24/octave) 0..192
subi r16, 96 ; r16 = 2*(n-48) (24/octave) -96..+96
ldi r17, 171

mulsu r16, r17
movw r16, r0
ldi r18, 0 ;\
sbrc r17, 7 ; > r18 = sign extension
ldi r18, 255 ;/ of r17
add r30, r17
adc r31, r18

MLP_DCF3:
;CUTOFF:
lds r16, CUTOFF
clr r17
add r16, r30
     adc r17, r31
tst r17
brpl MLP_DCF1
ldi r16, 0
rjmp MLP_DCF2

MLP_DCF1:
            breq MLP_DCF2
ldi r16, 255

MLP_DCF2:
lsr r16 ; 0..127
ldi r30, low( TAB_VCF) ;\
ldi r31, high( TAB_VCF) ;/ Z = &Tab
rcall TAB_BYTE ; r0 = 1.. 255
sts LPF_I, r16 ; Store Lowpass F value
subi r16, 10 ; Offset HP knob value
brcc STORE_HPF
ldi r16, 0x00 ; Limit HP to min of 0
STORE_HPF:
sts HPF_I, r16

; Limit resonance at low filter cutoff settings
lds r17, RESONANCE
lds r16, LPF_I
cpi r16, 16
brlo LIMIT_REZ ; Only limit resonance if LPF_I is 0..15
mov r16, r17
rjmp EXIT_LIMIT_REZ
LIMIT_REZ:
ldi r30, low( TAB_REZ) ;\
ldi r31, high( TAB_REZ) ;/ Z = &Tab
rcall TAB_BYTE ; r16 = 0..15 ; r16 holds maximum allow resonance
cp r16, r17
brlo EXIT_LIMIT_REZ
mov r16, r17
EXIT_LIMIT_REZ:
sts SCALED_RESONANCE, r16 ; Store scaled resonance

            ;---------------
            ;sound level:
            ;---------------

MLP_VCAENV:
            lds r16,ENV_INTEGR ;
ldi r30, low( TAB_VCA) ;\
ldi r31, high( TAB_VCA) ;/ Z = &Tab
rcall TAB_BYTE ; r0 = 2..255
MLP_VCAOK:
            sts LEVEL,r16
            ;-----------------------------------
            ;pseudo-random shift register:
            ;-----------------------------------
;BIT = SHIFTREG.23 xor SHIFTREG.18
;SHIFTREG = (SHIFTREG << 1) + BIT
lds r16, SHIFTREG_0
lds r17, SHIFTREG_1
lds r18, SHIFTREG_2
     bst r18, 7 ;\
bld r19, 0 ;/ r19.0 = SHIFTREG.23
bst r18, 2 ;\
bld r20, 0 ;/ r20.0 = SHIFTREG.18
eor r19, r20 ;r19.0 = BIT
lsr r19 ; Cy = BIT
rol r16 ;\
rol r17 ; > r18:r17:r16 =
rol r18 ;/ = (SHIFTREG << 1) + BIT
sts SHIFTREG_0, r16
sts SHIFTREG_1, r17
sts SHIFTREG_2, r18


            ;------------------------
            ;back to the main loop:
            ;------------------------
rjmp MAINLOOP

;-----------------------------------------------------------------------------
;
;*** Bandlimited sawtooth wavetables (each table is 256 bytes long, unsigned integer)

INV_SAW0:
; base freqency: 25.96 Hz, discrets: 701, rms: 7.95, min: -0.87, max: 0.87

.db 128, 18, 17, 21, 22, 22, 22, 24
.db 25, 25, 26, 27, 28, 29, 30, 31
.db 32, 32, 33, 34, 35, 36, 37, 38
.db 39, 39, 40, 41, 42, 43, 44, 45

.db 45, 46, 47, 48, 49, 50, 51, 52
.db 52, 53, 54, 55, 56, 57, 58, 58
.db 59, 60, 61, 62, 63, 64, 65, 65
.db 66, 67, 68, 69, 70, 71, 71, 72

.db 73, 74, 75, 76, 77, 77, 78, 79
.db 80, 81, 82, 83, 83, 84, 85, 86
.db 87, 88, 89, 89, 90, 91, 92, 93
.db 94, 95, 96, 96, 97, 98, 99, 100

.db 101, 102, 102, 103, 104, 105, 106, 107
.db 108, 109, 109, 110, 111, 112, 113, 114
.db 115, 115, 116, 117, 118, 119, 120, 121
.db 122, 122, 123, 124, 125, 126, 127, 128

.db 128, 128, 129, 130, 131, 132, 133, 134
.db 134, 135, 136, 137, 138, 139, 140, 141
.db 141, 142, 143, 144, 145, 146, 147, 147
.db 148, 149, 150, 151, 152, 153, 154, 154

.db 155, 156, 157, 158, 159, 160, 160, 161
.db 162, 163, 164, 165, 166, 167, 167, 168
.db 169, 170, 171, 172, 173, 173, 174, 175
.db 176, 177, 178, 179, 179, 180, 181, 182

.db 183, 184, 185, 185, 186, 187, 188, 189
.db 190, 191, 191, 192, 193, 194, 195, 196
.db 197, 198, 198, 199, 200, 201, 202, 203
.db 204, 204, 205, 206, 207, 208, 209, 210

.db 211, 211, 212, 213, 214, 215, 216, 217
.db 217, 218, 219, 220, 221, 222, 223, 224
.db 224, 225, 226, 227, 228, 229, 230, 231
.db 231, 232, 234, 234, 234, 235, 239, 238


INV_SAW1:
; base freqency: 41.20 Hz, discrets: 442, rms: 7.95, min: -0.88, max: 0.88

.db 128, 17, 16, 21, 23, 21, 22, 25
.db 25, 25, 26, 28, 28, 29, 30, 31
.db 31, 32, 34, 34, 35, 36, 37, 38
.db 38, 39, 40, 41, 42, 43, 44, 44

.db 45, 46, 47, 48, 49, 50, 51, 51
.db 52, 53, 54, 55, 56, 57, 57, 58
.db 59, 60, 61, 62, 63, 64, 64, 65
.db 66, 67, 68, 69, 70, 70, 71, 72

.db 73, 74, 75, 76, 76, 77, 78, 79
.db 80, 81, 82, 83, 83, 84, 85, 86
.db 87, 88, 89, 89, 90, 91, 92, 93
.db 94, 95, 96, 96, 97, 98, 99, 100

.db 101, 102, 102, 103, 104, 105, 106, 107
.db 108, 109, 109, 110, 111, 112, 113, 114
.db 115, 115, 116, 117, 118, 119, 120, 121
.db 122, 122, 123, 124, 125, 126, 127, 128

.db 128, 128, 129, 130, 131, 132, 133, 134
.db 134, 135, 136, 137, 138, 139, 140, 141
.db 141, 142, 143, 144, 145, 146, 147, 147
.db 148, 149, 150, 151, 152, 153, 154, 154

.db 155, 156, 157, 158, 159, 160, 160, 161
.db 162, 163, 164, 165, 166, 167, 167, 168
.db 169, 170, 171, 172, 173, 173, 174, 175
.db 176, 177, 178, 179, 180, 180, 181, 182

.db 183, 184, 185, 186, 186, 187, 188, 189
.db 190, 191, 192, 192, 193, 194, 195, 196
.db 197, 198, 199, 199, 200, 201, 202, 203
.db 204, 205, 205, 206, 207, 208, 209, 210

.db 211, 212, 212, 213, 214, 215, 216, 217
.db 218, 218, 219, 220, 221, 222, 222, 224
.db 225, 225, 226, 227, 228, 228, 230, 231
.db 231, 231, 234, 235, 233, 235, 240, 239


INV_SAW2:
; base freqency: 65.41 Hz, discrets: 278, rms: 7.95, min: -0.85, max: 0.85

.db 128, 28, 22, 20, 20, 20, 21, 22
.db 24, 26, 27, 28, 29, 29, 30, 30
.db 31, 32, 33, 34, 35, 36, 37, 38
.db 39, 39, 40, 41, 41, 42, 43, 44

.db 45, 46, 47, 48, 49, 50, 50, 51
.db 52, 53, 54, 55, 56, 57, 58, 58
.db 59, 60, 61, 62, 62, 63, 64, 65
.db 66, 67, 68, 69, 70, 70, 71, 72

.db 73, 74, 75, 76, 77, 77, 78, 79
.db 80, 81, 82, 82, 83, 84, 85, 86
.db 87, 88, 89, 89, 90, 91, 92, 93
.db 94, 95, 96, 97, 97, 98, 99, 100

.db 101, 101, 102, 103, 104, 105, 106, 107
.db 108, 109, 109, 110, 111, 112, 113, 114
.db 115, 116, 116, 117, 118, 119, 120, 121
.db 121, 122, 123, 124, 125, 126, 127, 128

.db 128, 128, 129, 130, 131, 132, 133, 134
.db 135, 135, 136, 137, 138, 139, 140, 140
.db 141, 142, 143, 144, 145, 146, 147, 147
.db 148, 149, 150, 151, 152, 153, 154, 155

.db 155, 156, 157, 158, 159, 159, 160, 161
.db 162, 163, 164, 165, 166, 167, 167, 168
.db 169, 170, 171, 172, 173, 174, 174, 175
.db 176, 177, 178, 179, 179, 180, 181, 182

.db 183, 184, 185, 186, 186, 187, 188, 189
.db 190, 191, 192, 193, 194, 194, 195, 196
.db 197, 198, 198, 199, 200, 201, 202, 203
.db 204, 205, 206, 206, 207, 208, 209, 210

.db 211, 212, 213, 214, 215, 215, 216, 217
.db 217, 218, 219, 220, 221, 222, 223, 224
.db 225, 226, 226, 227, 227, 228, 229, 230
.db 232, 234, 235, 236, 236, 236, 234, 228


INV_SAW3:
; base freqency: 103.83 Hz, discrets: 176, rms: 7.95, min: -0.92, max: 0.92

.db 128, 10, 15, 26, 21, 19, 25, 25
.db 23, 26, 28, 26, 28, 30, 29, 30
.db 33, 32, 33, 35, 35, 35, 37, 38
.db 38, 40, 41, 41, 42, 44, 44, 44

.db 46, 46, 47, 48, 49, 49, 51, 52
.db 52, 53, 55, 55, 56, 57, 58, 58
.db 60, 60, 61, 62, 63, 63, 65, 66
.db 66, 67, 68, 69, 70, 71, 71, 72

.db 73, 74, 75, 76, 77, 77, 78, 80
.db 80, 81, 82, 83, 83, 85, 85, 86
.db 87, 88, 89, 90, 91, 91, 92, 93
.db 94, 95, 96, 97, 97, 98, 99, 100

.db 101, 102, 102, 103, 105, 105, 106, 107
.db 108, 108, 110, 110, 111, 112, 113, 114
.db 115, 116, 116, 117, 118, 119, 120, 121
.db 122, 122, 123, 124, 125, 126, 127, 127

.db 128, 129, 129, 130, 131, 132, 133, 134
.db 134, 135, 136, 137, 138, 139, 140, 140
.db 141, 142, 143, 144, 145, 146, 146, 148
.db 148, 149, 150, 151, 151, 153, 154, 154

.db 155, 156, 157, 158, 159, 159, 160, 161
.db 162, 163, 164, 165, 165, 166, 167, 168
.db 169, 170, 171, 171, 173, 173, 174, 175
.db 176, 176, 178, 179, 179, 180, 181, 182

.db 183, 184, 185, 185, 186, 187, 188, 189
.db 190, 190, 191, 193, 193, 194, 195, 196
.db 196, 198, 198, 199, 200, 201, 201, 203
.db 204, 204, 205, 207, 207, 208, 209, 210

.db 210, 212, 212, 212, 214, 215, 215, 216
.db 218, 218, 219, 221, 221, 221, 223, 224
.db 223, 226, 227, 226, 228, 230, 228, 230
.db 233, 231, 231, 237, 235, 230, 241, 246


INV_SAW4:
; base freqency: 164.81 Hz, discrets: 111, rms: 7.95, min: -1.00, max: 1.00

.db 128, 1, 27, 19, 21, 25, 20, 28
.db 22, 28, 25, 28, 29, 28, 32, 29
.db 33, 31, 34, 34, 35, 37, 36, 39
.db 38, 40, 40, 41, 43, 42, 45, 44

.db 46, 46, 48, 48, 49, 50, 50, 52
.db 52, 54, 54, 55, 56, 56, 58, 58
.db 60, 60, 61, 62, 63, 64, 64, 66
.db 66, 67, 68, 69, 70, 70, 72, 72

.db 74, 74, 75, 76, 76, 78, 78, 80
.db 80, 81, 82, 83, 84, 84, 86, 86
.db 87, 88, 89, 90, 90, 92, 92, 93
.db 94, 95, 96, 96, 98, 98, 99, 100

.db 101, 102, 102, 104, 104, 106, 106, 107
.db 108, 109, 110, 110, 112, 112, 113, 114
.db 115, 116, 116, 118, 118, 119, 120, 121
.db 122, 122, 124, 124, 125, 126, 127, 128

.db 128, 128, 129, 130, 131, 132, 132, 134
.db 134, 135, 136, 137, 138, 138, 140, 140
.db 141, 142, 143, 144, 144, 146, 146, 147
.db 148, 149, 150, 150, 152, 152, 154, 154

.db 155, 156, 157, 158, 158, 160, 160, 161
.db 162, 163, 164, 164, 166, 166, 167, 168
.db 169, 170, 170, 172, 172, 173, 174, 175
.db 176, 176, 178, 178, 180, 180, 181, 182

.db 182, 184, 184, 186, 186, 187, 188, 189
.db 190, 190, 192, 192, 193, 194, 195, 196
.db 196, 198, 198, 200, 200, 201, 202, 202
.db 204, 204, 206, 206, 207, 208, 208, 210

.db 210, 212, 211, 214, 213, 215, 216, 216
.db 218, 217, 220, 219, 221, 222, 222, 225
.db 223, 227, 224, 228, 227, 228, 231, 228
.db 234, 228, 236, 231, 235, 237, 229, 255


INV_SAW5:
; base freqency: 261.62 Hz, discrets: 70, rms: 7.95, min: -1.00, max: 1.00

.db 128, 26, 1, 24, 30, 17, 19, 29
.db 27, 21, 26, 31, 27, 26, 32, 33
.db 30, 31, 36, 35, 33, 36, 39, 37
.db 37, 41, 41, 40, 42, 44, 44, 43

.db 46, 47, 46, 47, 50, 50, 50, 51
.db 53, 53, 53, 56, 57, 56, 57, 59
.db 60, 59, 61, 63, 62, 63, 65, 66
.db 66, 67, 69, 69, 69, 71, 72, 72

.db 73, 75, 75, 75, 77, 78, 78, 79
.db 80, 81, 81, 82, 84, 85, 85, 86
.db 88, 88, 88, 90, 91, 91, 92, 94
.db 94, 94, 96, 97, 97, 98, 100, 100

.db 100, 102, 103, 103, 104, 105, 106, 107
.db 107, 109, 110, 110, 111, 113, 113, 113
.db 115, 116, 116, 117, 119, 119, 119, 121
.db 122, 122, 123, 125, 125, 125, 127, 128

.db 128, 128, 129, 131, 131, 131, 133, 134
.db 134, 135, 137, 137, 137, 139, 140, 140
.db 141, 143, 143, 143, 145, 146, 146, 147
.db 149, 149, 150, 151, 152, 153, 153, 154

.db 156, 156, 156, 158, 159, 159, 160, 162
.db 162, 162, 164, 165, 165, 166, 168, 168
.db 168, 170, 171, 171, 172, 174, 175, 175
.db 176, 177, 178, 178, 179, 181, 181, 181

.db 183, 184, 184, 185, 187, 187, 187, 189
.db 190, 190, 191, 193, 194, 193, 195, 197
.db 196, 197, 199, 200, 199, 200, 203, 203
.db 203, 205, 206, 206, 206, 209, 210, 209

.db 210, 213, 212, 212, 214, 216, 215, 215
.db 219, 219, 217, 220, 223, 221, 220, 225
.db 226, 223, 224, 230, 229, 225, 230, 235
.db 229, 227, 237, 239, 226, 232, 255, 230


INV_SAW6:
; base freqency: 415.30 Hz, discrets: 44, rms: 7.95, min: -1.00, max: 1.00

.db 128, 57, 11, 0, 13, 29, 33, 27
.db 19, 19, 25, 32, 33, 29, 26, 27
.db 32, 36, 36, 33, 32, 34, 38, 40
.db 40, 38, 38, 40, 43, 45, 44, 43

.db 43, 46, 49, 50, 49, 48, 49, 52
.db 54, 54, 53, 53, 55, 57, 59, 59
.db 58, 59, 60, 63, 64, 64, 63, 64
.db 66, 68, 69, 69, 69, 69, 71, 73

.db 74, 74, 74, 75, 77, 78, 79, 79
.db 79, 80, 82, 84, 84, 84, 84, 86
.db 88, 89, 89, 89, 90, 91, 93, 94
.db 94, 94, 95, 97, 98, 99, 99, 99

.db 100, 102, 103, 104, 104, 104, 106, 108
.db 108, 109, 109, 110, 111, 113, 113, 114
.db 114, 115, 117, 118, 119, 119, 119, 120
.db 122, 123, 124, 124, 124, 126, 127, 128

.db 128, 128, 129, 130, 132, 132, 132, 133
.db 134, 136, 137, 137, 137, 138, 139, 141
.db 142, 142, 143, 143, 145, 146, 147, 147
.db 148, 148, 150, 152, 152, 152, 153, 154

.db 156, 157, 157, 157, 158, 159, 161, 162
.db 162, 162, 163, 165, 166, 167, 167, 167
.db 168, 170, 172, 172, 172, 172, 174, 176
.db 177, 177, 177, 178, 179, 181, 182, 182

.db 182, 183, 185, 187, 187, 187, 187, 188
.db 190, 192, 193, 192, 192, 193, 196, 197
.db 198, 197, 197, 199, 201, 203, 203, 202
.db 202, 204, 207, 208, 207, 206, 207, 210

.db 213, 213, 212, 211, 213, 216, 218, 218
.db 216, 216, 218, 222, 224, 223, 220, 220
.db 224, 229, 230, 227, 223, 224, 231, 237
.db 237, 229, 223, 227, 243, 255, 245, 199


INV_SAW7:
; base freqency: 659.25 Hz, discrets: 28, rms: 7.95, min: -0.99, max: 0.99

.db 128, 81, 41, 14, 2, 3, 12, 23
.db 32, 36, 34, 29, 24, 21, 22, 26
.db 32, 36, 38, 38, 36, 33, 32, 33
.db 36, 40, 43, 44, 44, 43, 42, 41

.db 42, 44, 47, 50, 51, 51, 51, 50
.db 49, 50, 52, 55, 57, 59, 59, 58
.db 58, 58, 59, 61, 63, 65, 66, 66
.db 66, 66, 66, 67, 69, 71, 73, 74

.db 74, 74, 74, 74, 75, 76, 78, 80
.db 81, 82, 82, 81, 82, 83, 84, 86
.db 88, 89, 90, 89, 89, 90, 91, 92
.db 94, 96, 97, 97, 97, 97, 98, 99

.db 100, 102, 104, 105, 105, 105, 105, 105
.db 106, 108, 110, 111, 112, 113, 113, 113
.db 113, 114, 116, 118, 119, 120, 121, 121
.db 121, 121, 122, 124, 125, 127, 128, 128

.db 128, 128, 128, 129, 131, 132, 134, 135
.db 135, 135, 135, 136, 137, 138, 140, 142
.db 143, 143, 143, 143, 144, 145, 146, 148
.db 150, 151, 151, 151, 151, 151, 152, 154

.db 156, 157, 158, 159, 159, 159, 159, 160
.db 162, 164, 165, 166, 167, 167, 166, 167
.db 168, 170, 172, 173, 174, 175, 174, 174
.db 175, 176, 178, 180, 181, 182, 182, 182

.db 182, 182, 183, 185, 187, 189, 190, 190
.db 190, 190, 190, 191, 193, 195, 197, 198
.db 198, 198, 197, 197, 199, 201, 204, 206
.db 207, 206, 205, 205, 205, 206, 209, 212

.db 214, 215, 214, 213, 212, 212, 213, 216
.db 220, 223, 224, 223, 220, 218, 218, 220
.db 224, 230, 234, 235, 232, 227, 222, 220
.db 224, 233, 244, 253, 254, 242, 215, 175


INV_SAW8:
; base freqency: 1046.50 Hz, discrets: 18, rms: 7.95, min: -0.98, max: 0.98

.db 128, 97, 68, 43, 24, 11, 4, 3
.db 6, 12, 20, 28, 34, 38, 40, 39
.db 37, 34, 30, 28, 27, 27, 29, 33
.db 36, 40, 43, 46, 47, 47, 46, 44

.db 43, 42, 42, 43, 44, 47, 49, 52
.db 54, 56, 57, 57, 57, 56, 55, 55
.db 55, 56, 58, 60, 62, 64, 66, 68
.db 68, 69, 68, 68, 68, 68, 68, 69

.db 71, 72, 74, 76, 78, 79, 80, 80
.db 80, 80, 80, 80, 81, 82, 83, 85
.db 87, 89, 90, 91, 92, 92, 92, 92
.db 92, 92, 93, 94, 96, 97, 99, 101

.db 102, 103, 104, 104, 104, 104, 104, 105
.db 105, 107, 108, 110, 112, 113, 115, 116
.db 116, 116, 116, 116, 117, 117, 118, 119
.db 121, 122, 124, 126, 127, 128, 128, 128

.db 128, 128, 128, 128, 129, 130, 132, 134
.db 135, 137, 138, 139, 139, 140, 140, 140
.db 140, 140, 141, 143, 144, 146, 148, 149
.db 151, 151, 152, 152, 152, 152, 152, 153

.db 154, 155, 157, 159, 160, 162, 163, 164
.db 164, 164, 164, 164, 164, 165, 166, 167
.db 169, 171, 173, 174, 175, 176, 176, 176
.db 176, 176, 176, 177, 178, 180, 182, 184

.db 185, 187, 188, 188, 188, 188, 188, 187
.db 188, 188, 190, 192, 194, 196, 198, 200
.db 201, 201, 201, 200, 199, 199, 199, 200
.db 202, 204, 207, 209, 212, 213, 214, 214

.db 213, 212, 210, 209, 209, 210, 213, 216
.db 220, 223, 227, 229, 229, 228, 226, 222
.db 219, 217, 216, 218, 222, 228, 236, 244
.db 250, 253, 252, 245, 232, 213, 188, 159


INV_SAW9:
; base freqency: 1661.21 Hz, discrets: 11, rms: 7.95, min: -0.97, max: 0.97

.db 128, 109, 90, 73, 56, 42, 30, 20
.db 12, 8, 5, 5, 6, 9, 13, 18
.db 24, 29, 34, 38, 42, 44, 46, 47
.db 46, 45, 44, 42, 41, 39, 38, 37

.db 36, 37, 38, 39, 41, 44, 47, 49
.db 52, 55, 57, 59, 60, 61, 61, 61
.db 61, 61, 60, 59, 59, 59, 59, 59
.db 60, 61, 63, 65, 67, 69, 71, 73

.db 75, 77, 78, 79, 79, 80, 80, 80
.db 80, 79, 79, 79, 79, 80, 80, 82
.db 83, 84, 86, 88, 90, 92, 94, 95
.db 96, 98, 98, 99, 99, 99, 99, 99

.db 99, 99, 99, 100, 100, 101, 103, 104
.db 106, 107, 109, 111, 113, 114, 116, 117
.db 117, 118, 118, 119, 119, 119, 119, 119
.db 119, 119, 120, 121, 122, 123, 125, 127

.db 128, 129, 131, 133, 134, 135, 136, 137
.db 137, 137, 137, 137, 137, 137, 138, 138
.db 139, 139, 140, 142, 143, 145, 147, 149
.db 150, 152, 153, 155, 156, 156, 157, 157

.db 157, 157, 157, 157, 157, 157, 158, 158
.db 160, 161, 162, 164, 166, 168, 170, 172
.db 173, 174, 176, 176, 177, 177, 177, 177
.db 176, 176, 176, 176, 177, 177, 178, 179

.db 181, 183, 185, 187, 189, 191, 193, 195
.db 196, 197, 197, 197, 197, 197, 196, 195
.db 195, 195, 195, 195, 196, 197, 199, 201
.db 204, 207, 209, 212, 215, 217, 218, 219

.db 220, 219, 218, 217, 215, 214, 212, 211
.db 210, 209, 210, 212, 214, 218, 222, 227
.db 232, 238, 243, 247, 250, 251, 251, 248
.db 244, 236, 226, 214, 200, 183, 166, 147


INV_SAW10:
; base freqency: 2637.01 Hz, discrets: 7, rms: 7.95, min: -0.94, max: 0.94

.db 128, 116, 104, 91, 80, 69, 58, 49
.db 40, 32, 26, 20, 15, 12, 10, 8
.db 8, 8, 9, 11, 14, 17, 20, 24
.db 28, 32, 35, 39, 42, 46, 48, 51

.db 53, 54, 56, 56, 57, 57, 56, 56
.db 55, 54, 54, 53, 52, 51, 50, 50
.db 50, 50, 51, 51, 52, 53, 55, 57
.db 59, 61, 63, 65, 67, 69, 72, 74

.db 76, 77, 79, 80, 81, 82, 83, 83
.db 83, 83, 83, 83, 83, 83, 83, 82
.db 82, 82, 83, 83, 84, 84, 85, 86
.db 88, 89, 91, 92, 94, 96, 98, 100

.db 102, 103, 105, 107, 108, 109, 110, 111
.db 112, 112, 113, 113, 113, 113, 113, 113
.db 113, 113, 113, 114, 114, 114, 115, 116
.db 116, 118, 119, 120, 122, 123, 125, 127

.db 128, 129, 131, 133, 134, 136, 137, 138
.db 140, 140, 141, 142, 142, 142, 143, 143
.db 143, 143, 143, 143, 143, 143, 143, 144
.db 144, 145, 146, 147, 148, 149, 151, 153

.db 154, 156, 158, 160, 162, 164, 165, 167
.db 168, 170, 171, 172, 172, 173, 173, 174
.db 174, 174, 173, 173, 173, 173, 173, 173
.db 173, 173, 173, 174, 175, 176, 177, 179

.db 180, 182, 184, 187, 189, 191, 193, 195
.db 197, 199, 201, 203, 204, 205, 205, 206
.db 206, 206, 206, 205, 204, 203, 202, 202
.db 201, 200, 200, 199, 199, 200, 200, 202

.db 203, 205, 208, 210, 214, 217, 221, 224
.db 228, 232, 236, 239, 242, 245, 247, 248
.db 248, 248, 246, 244, 241, 236, 230, 224
.db 216, 207, 198, 187, 176, 165, 152, 140


INV_SAW11:
; base freqency: 4185.98 Hz, discrets: 5, rms: 7.95, min: -0.92, max: 0.92

.db 128, 119, 110, 101, 93, 84, 76, 68
.db 60, 53, 47, 41, 35, 30, 26, 22
.db 19, 16, 14, 12, 11, 11, 11, 11
.db 12, 14, 16, 18, 20, 23, 26, 29

.db 32, 35, 38, 41, 44, 47, 50, 53
.db 55, 58, 60, 61, 63, 64, 66, 67
.db 67, 68, 68, 68, 68, 68, 68, 67
.db 67, 66, 66, 65, 65, 65, 64, 64

.db 64, 64, 64, 65, 65, 66, 67, 68
.db 69, 70, 72, 73, 75, 77, 79, 81
.db 83, 85, 87, 89, 91, 92, 94, 96
.db 98, 99, 101, 102, 103, 104, 105, 105

.db 106, 107, 107, 107, 107, 107, 108, 108
.db 107, 107, 107, 107, 107, 108, 108, 108
.db 108, 109, 109, 110, 111, 112, 113, 114
.db 115, 117, 118, 120, 121, 123, 125, 127

.db 128, 129, 131, 133, 135, 136, 138, 139
.db 141, 142, 143, 144, 145, 146, 147, 147
.db 148, 148, 148, 148, 149, 149, 149, 149
.db 149, 148, 148, 149, 149, 149, 149, 149

.db 150, 151, 151, 152, 153, 154, 155, 157
.db 158, 160, 162, 164, 165, 167, 169, 171
.db 173, 175, 177, 179, 181, 183, 184, 186
.db 187, 188, 189, 190, 191, 191, 192, 192

.db 192, 192, 192, 191, 191, 191, 190, 190
.db 189, 189, 188, 188, 188, 188, 188, 188
.db 189, 189, 190, 192, 193, 195, 196, 198
.db 201, 203, 206, 209, 212, 215, 218, 221

.db 224, 227, 230, 233, 236, 238, 240, 242
.db 244, 245, 245, 245, 245, 244, 242, 240
.db 237, 234, 230, 226, 221, 215, 209, 203
.db 196, 188, 180, 172, 163, 155, 146, 137



;-----------------------------------------------------------------------------
;
;*** Bandlimited square wavetables (each table is 256 bytes long, unsigned integer)
SQ_LIMIT0:
; base freqency: 25.96 Hz, discrets: 350, rms: 12.65, min: -0.81, max: 0.81

.db 128, 230, 231, 229, 228, 229, 230, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229

.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229

.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229

.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 230, 229, 228, 229, 231, 230

.db 128, 26, 25, 27, 28, 27, 26, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27

.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27

.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27

.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 26, 27, 28, 27, 25, 26


SQ_LIMIT1:
; base freqency: 41.20 Hz, discrets: 221, rms: 12.65, min: -0.82, max: 0.82

.db 128, 230, 232, 228, 228, 230, 230, 228
.db 229, 230, 229, 228, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229

.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229

.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229

.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 228, 229, 230
.db 229, 228, 230, 230, 228, 228, 232, 230

.db 128, 26, 24, 28, 28, 26, 26, 28
.db 27, 26, 27, 28, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27

.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27

.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27

.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 28, 27, 26
.db 27, 28, 26, 26, 28, 28, 24, 26


SQ_LIMIT2:
; base freqency: 65.41 Hz, discrets: 139, rms: 12.65, min: -0.81, max: 0.81

.db 128, 221, 227, 229, 230, 231, 231, 230
.db 230, 229, 229, 228, 228, 229, 229, 229
.db 230, 230, 230, 230, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 230, 229, 229

.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229

.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229

.db 229, 229, 229, 230, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 230, 230, 230
.db 230, 229, 229, 229, 228, 228, 229, 229
.db 230, 230, 231, 231, 230, 229, 227, 221

.db 128, 35, 29, 27, 26, 25, 25, 26
.db 26, 27, 27, 28, 28, 27, 27, 27
.db 26, 26, 26, 26, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 26, 27, 27

.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27

.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27

.db 27, 27, 27, 26, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 26, 26, 26
.db 26, 27, 27, 27, 28, 28, 27, 27
.db 26, 26, 25, 25, 26, 27, 29, 35


SQ_LIMIT3:
; base freqency: 103.83 Hz, discrets: 88, rms: 12.65, min: -0.85, max: 0.85

.db 128, 237, 234, 224, 229, 232, 227, 228
.db 231, 228, 228, 230, 229, 228, 230, 229
.db 228, 229, 230, 228, 229, 230, 228, 229
.db 230, 229, 229, 229, 229, 228, 229, 229

.db 228, 229, 229, 228, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229

.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 229, 229, 229
.db 229, 229, 229, 229, 229, 228, 229, 229

.db 228, 229, 229, 228, 229, 229, 229, 229
.db 230, 229, 228, 230, 229, 228, 230, 229
.db 228, 229, 230, 228, 229, 230, 228, 228
.db 231, 228, 227, 232, 229, 224, 234, 237

.db 128, 19, 22, 32, 27, 24, 29, 28
.db 25, 28, 28, 26, 27, 28, 26, 27
.db 28, 27, 26, 28, 27, 26, 28, 27
.db 26, 27, 27, 27, 27, 28, 27, 27

.db 28, 27, 27, 28, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27

.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 27, 27, 27
.db 27, 27, 27, 27, 27, 28, 27, 27

.db 28, 27, 27, 28, 27, 27, 27, 27
.db 26, 27, 28, 26, 27, 28, 26, 27
.db 28, 27, 26, 28, 27, 26, 28, 28
.db 25, 28, 29, 24, 27, 32, 22, 19


SQ_LIMIT4:
; base freqency: 164.81 Hz, discrets: 55, rms: 12.65, min: -0.92, max: 0.92

.db 128, 245, 223, 230, 231, 226, 232, 225
.db 232, 227, 229, 229, 228, 231, 227, 230
.db 228, 229, 229, 228, 230, 228, 230, 228
.db 229, 229, 228, 230, 228, 230, 228, 229

.db 229, 229, 229, 228, 230, 228, 229, 229
.db 229, 229, 228, 230, 228, 229, 229, 229
.db 229, 228, 229, 228, 229, 229, 229, 229
.db 228, 229, 228, 229, 229, 229, 229, 228

.db 229, 228, 229, 229, 229, 229, 228, 229
.db 228, 229, 229, 229, 229, 228, 229, 228
.db 229, 229, 229, 229, 228, 230, 228, 229
.db 229, 229, 229, 228, 230, 228, 229, 229

.db 229, 229, 228, 230, 228, 230, 228, 229
.db 229, 228, 230, 228, 230, 228, 229, 229
.db 228, 230, 227, 231, 228, 229, 229, 227
.db 232, 225, 232, 226, 231, 230, 223, 245

.db 128, 11, 33, 26, 25, 30, 24, 31
.db 24, 29, 27, 27, 28, 25, 29, 26
.db 28, 27, 27, 28, 26, 28, 26, 28
.db 27, 27, 28, 26, 28, 26, 28, 27

.db 27, 27, 27, 28, 26, 28, 27, 27
.db 27, 27, 28, 26, 28, 27, 27, 27
.db 27, 28, 27, 28, 27, 27, 27, 27
.db 28, 27, 28, 27, 27, 27, 27, 28

.db 27, 28, 27, 27, 27, 27, 28, 27
.db 28, 27, 27, 27, 27, 28, 27, 28
.db 27, 27, 27, 27, 28, 26, 28, 27
.db 27, 27, 27, 28, 26, 28, 27, 27

.db 27, 27, 28, 26, 28,