Hi
I was hoping someone might be able to help me please
I'm working on a midi controlled polyphonic synth(not paraphonic) using 2 x teensy 3.1 and midi library 3.2 (4 voice for the moment).
what i'm trying to achieve is using one teensy to generate the oscillator voices Then each of the voices goes through analogue filters and processing then through a digitally controlled VCA.
The setup is as follows:
I have one teensy generating four oscillator voices using phase accumulation wavetables. it is also responsible for velocity. Then the individual oscillator voices are outputted to 4 channels
of MCP4922. DAC
At this point each voice will be then going through digitally controlled analogue filters and processing.(which is left out of the design at the moment while i try to work out the polyphonic side of things)
From there each voice passes through a MCP41010 which is controlled by a second midi controlled teensy, this implements an individual ADSR for each voice.
From there all voices are combined using a analogue mixer circuit
I've adapted the midi code side of things using this excellent https://forum.pjrc.com/archive/index.php/t-27896.html and both teensy are fed the same midi signal from a midi in circuit
The problem is with the Release stage of the ADSR and here is where i'm up to at the moment .
I have disabled the code inside the note Off that releases the voice to be used by the next key strike on teensy 1
Instead the second teensy is running an almost identical midi solution except the ISR runs a simple ADSR for each Digital Pot (at the moment).
When the envelope is triggered it takes pin D3 D4 D5 D6 HIGH and when the END of the release stage is finished i.e. the volume is at zero it takes D3 D4 D5 D6 LOW
These digital outs are connected to Teensy 1 with wires and pull down resistors to digital in pins D3 D4 D5 D6
On teensy one the pins D3 D4 D5 D6 are read with digital read from inside the ISR. I have check this setup and indeed it does read ok. (these are called MPC1 to MCP4.)
My initial thought was that when a key is struck D3 to D5 are read and if HIGH don't reset the voice but if are LOW and the release is finished allow the next part of the code Quote "try to find a free voice to play a note"
to use that voice. Obviously this doesn't work and i can't figure out why ?? I have spent the last week moving things around and am now getting so frustrated i could *4£-??`@%$ and i'm normally such a patient person.
I really really hoping someone might shed some light on a solution.
If you got this far thanks for reading
PS there is printStuff(); which displays the contents of the typedef struct.
In an ideal world…..if 4 keys are held down and you press a fifth note nothing will sound …if 4 keys are hit and the voices are in release then if another key is struck it would steal a voice .
This is how the roland Juno 106 works.
thanks again and here is the code for each teensy
CODE FOR TEENSY ONE
CODE FOR TEENSY TWO
I was hoping someone might be able to help me please
I'm working on a midi controlled polyphonic synth(not paraphonic) using 2 x teensy 3.1 and midi library 3.2 (4 voice for the moment).
what i'm trying to achieve is using one teensy to generate the oscillator voices Then each of the voices goes through analogue filters and processing then through a digitally controlled VCA.
The setup is as follows:
I have one teensy generating four oscillator voices using phase accumulation wavetables. it is also responsible for velocity. Then the individual oscillator voices are outputted to 4 channels
of MCP4922. DAC
At this point each voice will be then going through digitally controlled analogue filters and processing.(which is left out of the design at the moment while i try to work out the polyphonic side of things)
From there each voice passes through a MCP41010 which is controlled by a second midi controlled teensy, this implements an individual ADSR for each voice.
From there all voices are combined using a analogue mixer circuit
I've adapted the midi code side of things using this excellent https://forum.pjrc.com/archive/index.php/t-27896.html and both teensy are fed the same midi signal from a midi in circuit
The problem is with the Release stage of the ADSR and here is where i'm up to at the moment .
I have disabled the code inside the note Off that releases the voice to be used by the next key strike on teensy 1
Instead the second teensy is running an almost identical midi solution except the ISR runs a simple ADSR for each Digital Pot (at the moment).
When the envelope is triggered it takes pin D3 D4 D5 D6 HIGH and when the END of the release stage is finished i.e. the volume is at zero it takes D3 D4 D5 D6 LOW
These digital outs are connected to Teensy 1 with wires and pull down resistors to digital in pins D3 D4 D5 D6
On teensy one the pins D3 D4 D5 D6 are read with digital read from inside the ISR. I have check this setup and indeed it does read ok. (these are called MPC1 to MCP4.)
My initial thought was that when a key is struck D3 to D5 are read and if HIGH don't reset the voice but if are LOW and the release is finished allow the next part of the code Quote "try to find a free voice to play a note"
to use that voice. Obviously this doesn't work and i can't figure out why ?? I have spent the last week moving things around and am now getting so frustrated i could *4£-??`@%$ and i'm normally such a patient person.
I really really hoping someone might shed some light on a solution.
If you got this far thanks for reading
PS there is printStuff(); which displays the contents of the typedef struct.
In an ideal world…..if 4 keys are held down and you press a fifth note nothing will sound …if 4 keys are hit and the voices are in release then if another key is struck it would steal a voice .
This is how the roland Juno 106 works.
thanks again and here is the code for each teensy
CODE FOR TEENSY ONE
Code:
#include <TimerOne.h>
#include <MIDI.h>
#include <spi4teensy3.h> // include the SPI library:
// how many voices do we have?
#define VOICES 4
// note struct
// contains a pitch, a velocity, and a sequence number
typedef struct
{
uint8_t myPitch;
uint8_t myVelocity;
uint8_t mySequence;
uint8_t myOutput;//My addition
}
note;
// array of notes
// four notes since we have four voices
note notes[VOICES];
// array of frearduinoquencies corresponding to MIDI notes 0 to 128
const float noteFreqs[128] = {8.176, 8.662, 9.177, 9.723, 10.301, 10.913, 11.562, 12.25, 12.978, 13.75, 14.568, 15.434, 16.352, 17.324, 18.354, 19.445, 20.602, 21.827, 23.125, 24.5, 25.957, 27.5, 29.135, 30.868, 32.703, 34.648, 36.708, 38.891, 41.203, 43.654, 46.249, 48.999, 51.913, 55, 58.27, 61.735, 65.406, 69.296, 73.416, 77.782, 82.407, 87.307, 92.499, 97.999, 103.826, 110, 116.541, 123.471, 130.813, 138.591, 146.832, 155.563, 164.814, 174.614, 184.997, 195.998, 207.652, 220, 233.082, 246.942, 261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 391.995, 415.305, 440, 466.164, 493.883, 523.251, 554.365, 587.33, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880, 932.328, 987.767, 1046.502, 1108.731, 1174.659, 1244.508, 1318.51, 1396.913, 1479.978, 1567.982, 1661.219, 1760, 1864.655, 1975.533, 2093.005, 2217.461, 2349.318, 2489.016, 2637.02, 2793.826, 2959.955, 3135.963, 3322.438, 3520, 3729.31, 3951.066, 4186.009, 4434.922, 4698.636, 4978.032, 5274.041, 5587.652, 5919.911, 6271.927, 6644.875, 7040, 7458.62, 7902.133, 8372.018, 8869.844, 9397.273, 9956.063, 10548.08, 11175.3, 11839.82, 12543.85};
volatile float oscAFreq;
const int sine1024[1024] = {//SINE WAVE
0 , 0 , 0 , 0 , 0 , 1 , 1 , 2 , 2 , 3 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 12 , 13 , 14 , 16 , 18 , 19 , 21 , 23 , 25 , 27 , 29 , 31 , 33 , 35 , 38 , 40 , 43 , 45 , 48 , 51 , 53 , 56 , 59 , 62 , 66 , 69 , 72 , 75 , 79 , 82 , 86 , 89 , 93 , 97 , 101 , 105 , 109 , 113 , 117 , 121 , 125 , 130 , 134 , 139 , 143 , 148 , 153 , 158 , 162 , 167 , 172 , 177 , 183 , 188 , 193 , 199 , 204 , 209 , 215 , 221 , 226 , 232 , 238 , 244 , 250 , 256 , 262 , 268 , 275 , 281 , 287 , 294 , 300 , 307 , 313 , 320 , 327 , 334 , 341 , 348 , 355 , 362 , 369 , 376 , 384 , 391 , 398 , 406 , 413 , 421 , 429 , 436 , 444 , 452 , 460 , 468 , 476 , 484 , 492 , 500 , 509 , 517 , 525 , 534 , 542 , 551 , 559 , 568 , 577 , 585 , 594 , 603 , 612 , 621 , 630 , 639 , 648 , 658 , 667 , 676 , 686 , 695 , 704 , 714 , 724 , 733 , 743 , 753 , 762 , 772 , 782 , 792 , 802 , 812 , 822 , 832 , 842 , 852 , 863 , 873 , 883 , 893 , 904 , 914 , 925 , 935 , 946 , 957 , 967 , 978 , 989 , 999 , 1010 , 1021 , 1032 , 1043 , 1054 , 1065 , 1076 , 1087 , 1098 , 1109 , 1121 , 1132 , 1143 , 1154 , 1166 , 1177 , 1188 , 1200 , 1211 , 1223 , 1234 , 1246 , 1257 , 1269 , 1281 , 1292 , 1304 , 1316 , 1328 , 1339 , 1351 , 1363 , 1375 , 1387 , 1399 , 1411 , 1423 , 1434 , 1446 , 1459 , 1471 , 1483 , 1495 , 1507 , 1519 , 1531 , 1543 , 1556 , 1568 , 1580 , 1592 , 1604 , 1617 , 1629 , 1641 , 1654 , 1666 , 1678 , 1691 , 1703 , 1716 , 1728 , 1740 , 1753 , 1765 , 1778 , 1790 , 1803 , 1815 , 1828 , 1840 , 1853 , 1865 , 1878 , 1890 , 1903 , 1915 , 1928 , 1940 , 1953 , 1966 , 1978 , 1991 , 2003 , 2016 , 2028 , 2041 , 2054 , 2066 , 2079 , 2091 , 2104 , 2116 , 2129 , 2141 , 2154 , 2167 , 2179 , 2192 , 2204 , 2217 , 2229 , 2242 , 2254 , 2267 , 2279 , 2292 , 2304 , 2317 , 2329 , 2342 , 2354 , 2367 , 2379 , 2391 , 2404 , 2416 , 2428 , 2441 , 2453 , 2465 , 2478 , 2490 , 2502 , 2515 , 2527 , 2539 , 2551 , 2563 , 2575 , 2588 , 2600 , 2612 , 2624 , 2636 , 2648 , 2660 , 2672 , 2684 , 2696 , 2708 , 2720 , 2732 , 2743 , 2755 , 2767 , 2779 , 2790 , 2802 , 2814 , 2825 , 2837 , 2849 , 2860 , 2872 , 2883 , 2895 , 2906 , 2918 , 2929 , 2940 , 2952 , 2963 , 2974 , 2985 , 2996 , 3007 , 3019 , 3030 , 3041 , 3052 , 3063 , 3073 , 3084 , 3095 , 3106 , 3117 , 3127 , 3138 , 3149 , 3159 , 3170 , 3180 , 3191 , 3201 , 3211 , 3222 , 3232 , 3242 , 3252 , 3263 , 3273 , 3283 , 3293 , 3303 , 3313 , 3322 , 3332 , 3342 , 3352 , 3361 , 3371 , 3381 , 3390 , 3400 , 3409 , 3418 , 3428 , 3437 , 3446 , 3455 , 3464 , 3473 , 3482 , 3491 , 3500 , 3509 , 3518 , 3527 , 3535 , 3544 , 3552 , 3561 , 3569 , 3578 , 3586 , 3594 , 3603 , 3611 , 3619 , 3627 , 3635 , 3643 , 3651 , 3658 , 3666 , 3674 , 3681 , 3689 , 3696 , 3704 , 3711 , 3718 , 3726 , 3733 , 3740 , 3747 , 3754 , 3761 , 3768 , 3775 , 3781 , 3788 , 3795 , 3801 , 3808 , 3814 , 3820 , 3826 , 3833 , 3839 , 3845 , 3851 , 3857 , 3863 , 3868 , 3874 , 3880 , 3885 , 3891 , 3896 , 3902 , 3907 , 3912 , 3917 , 3922 , 3927 , 3932 , 3937 , 3942 , 3947 , 3951 , 3956 , 3961 , 3965 , 3969 , 3974 , 3978 , 3982 , 3986 , 3990 , 3994 , 3998 , 4002 , 4005 , 4009 , 4013 , 4016 , 4020 , 4023 , 4026 , 4029 , 4032 , 4036 , 4038 , 4041 , 4044 , 4047 , 4050 , 4052 , 4055 , 4057 , 4060 , 4062 , 4064 , 4066 , 4068 , 4070 , 4072 , 4074 , 4076 , 4077 , 4079 , 4081 , 4082 , 4083 , 4085 , 4086 , 4087 , 4088 , 4089 , 4090 , 4091 , 4092 , 4092 , 4093 , 4093 , 4094 , 4094 , 4095 , 4095 , 4095 , 4095 , 4095 , 4095 , 4095 , 4094 , 4094 , 4094 , 4093 , 4093 , 4092 , 4091 , 4091 , 4090 , 4089 , 4088 , 4087 , 4086 , 4084 , 4083 , 4082 , 4080 , 4079 , 4077 , 4075 , 4073 , 4072 , 4070 , 4068 , 4066 , 4063 , 4061 , 4059 , 4056 , 4054 , 4051 , 4049 , 4046 , 4043 , 4041 , 4038 , 4035 , 4032 , 4028 , 4025 , 4022 , 4019 , 4015 , 4012 , 4008 , 4004 , 4001 , 3997 , 3993 , 3989 , 3985 , 3981 , 3977 , 3972 , 3968 , 3964 , 3959 , 3955 , 3950 , 3945 , 3941 , 3936 , 3931 , 3926 , 3921 , 3916 , 3911 , 3905 , 3900 , 3895 , 3889 , 3884 , 3878 , 3872 , 3867 , 3861 , 3855 , 3849 , 3843 , 3837 , 3831 , 3825 , 3818 , 3812 , 3806 , 3799 , 3793 , 3786 , 3779 , 3773 , 3766 , 3759 , 3752 , 3745 , 3738 , 3731 , 3724 , 3716 , 3709 , 3702 , 3694 , 3687 , 3679 , 3671 , 3664 , 3656 , 3648 , 3640 , 3632 , 3624 , 3616 , 3608 , 3600 , 3592 , 3584 , 3575 , 3567 , 3558 , 3550 , 3541 , 3533 , 3524 , 3515 , 3507 , 3498 , 3489 , 3480 , 3471 , 3462 , 3453 , 3443 , 3434 , 3425 , 3416 , 3406 , 3397 , 3387 , 3378 , 3368 , 3359 , 3349 , 3339 , 3329 , 3320 , 3310 , 3300 , 3290 , 3280 , 3270 , 3260 , 3249 , 3239 , 3229 , 3219 , 3208 , 3198 , 3188 , 3177 , 3167 , 3156 , 3145 , 3135 , 3124 , 3113 , 3103 , 3092 , 3081 , 3070 , 3059 , 3048 , 3037 , 3026 , 3015 , 3004 , 2993 , 2982 , 2971 , 2959 , 2948 , 2937 , 2926 , 2914 , 2903 , 2891 , 2880 , 2868 , 2857 , 2845 , 2834 , 2822 , 2810 , 2799 , 2787 , 2775 , 2763 , 2752 , 2740 , 2728 , 2716 , 2704 , 2692 , 2680 , 2668 , 2656 , 2644 , 2632 , 2620 , 2608 , 2596 , 2584 , 2572 , 2560 , 2548 , 2535 , 2523 , 2511 , 2499 , 2486 , 2474 , 2462 , 2449 , 2437 , 2425 , 2412 , 2400 , 2388 , 2375 , 2363 , 2350 , 2338 , 2325 , 2313 , 2301 , 2288 , 2276 , 2263 , 2251 , 2238 , 2226 , 2213 , 2200 , 2188 , 2175 , 2163 , 2150 , 2138 , 2125 , 2113 , 2100 , 2087 , 2075 , 2062 , 2050 , 2037 , 2025 , 2012 , 1999 , 1987 , 1974 , 1962 , 1949 , 1937 , 1924 , 1912 , 1899 , 1887 , 1874 , 1861 , 1849 , 1836 , 1824 , 1811 , 1799 , 1786 , 1774 , 1762 , 1749 , 1737 , 1724 , 1712 , 1699 , 1687 , 1675 , 1662 , 1650 , 1638 , 1625 , 1613 , 1601 , 1589 , 1576 , 1564 , 1552 , 1540 , 1528 , 1515 , 1503 , 1491 , 1479 , 1467 , 1455 , 1443 , 1431 , 1419 , 1407 , 1395 , 1383 , 1371 , 1359 , 1348 , 1336 , 1324 , 1312 , 1301 , 1289 , 1277 , 1266 , 1254 , 1242 , 1231 , 1219 , 1208 , 1196 , 1185 , 1174 , 1162 , 1151 , 1140 , 1128 , 1117 , 1106 , 1095 , 1084 , 1073 , 1062 , 1051 , 1040 , 1029 , 1018 , 1007 , 996 , 985 , 975 , 964 , 953 , 943 , 932 , 922 , 911 , 901 , 890 , 880 , 870 , 859 , 849 , 839 , 829 , 819 , 809 , 799 , 789 , 779 , 769 , 759 , 750 , 740 , 730 , 721 , 711 , 702 , 692 , 683 , 673 , 664 , 655 , 646 , 637 , 627 , 618 , 609 , 601 , 592 , 583 , 574 , 565 , 557 , 548 , 540 , 531 , 523 , 514 , 506 , 498 , 490 , 482 , 473 , 465 , 457 , 450 , 442 , 434 , 426 , 419 , 411 , 404 , 396 , 389 , 381 , 374 , 367 , 360 , 353 , 346 , 339 , 332 , 325 , 318 , 311 , 305 , 298 , 292 , 285 , 279 , 273 , 266 , 260 , 254 , 248 , 242 , 236 , 230 , 225 , 219 , 213 , 208 , 202 , 197 , 192 , 186 , 181 , 176 , 171 , 166 , 161 , 156 , 151 , 147 , 142 , 137 , 133 , 129 , 124 , 120 , 116 , 112 , 108 , 104 , 100 , 96 , 92 , 88 , 85 , 81 , 78 , 74 , 71 , 68 , 65 , 61 , 58 , 56 , 53 , 50 , 47 , 44 , 42 , 39 , 37 , 35 , 32 , 30 , 28 , 26 , 24 , 22 , 20 , 19 , 17 , 15 , 14 , 13 , 11 , 10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 2 , 1 , 1 , 1 , 0 , 0 , 0 ,
};
volatile unsigned long delta;
//VARIABLES FOR ISR DAC
volatile unsigned long phaccu0;
volatile unsigned long phaccu1;
volatile unsigned long phaccu2;
volatile unsigned long phaccu3;
volatile unsigned long tword0;
volatile unsigned long tword1;
volatile unsigned long tword2;
volatile unsigned long tword3;
volatile int fromarray0;
volatile int fromarray1;
volatile int fromarray2;
volatile int fromarray3;
float dfreq0 = 2000;
float dfreq1 = 2000;
float dfreq2 = 2000;
float dfreq3 = 2000;
const double refclk = 43470.00;
//mcp4922
const int CS1 = 9; // chip Select MCP zero & one
const int CS2 = 10; // chip Select MCP two & three
int i = 0;
volatile byte myvoiceUsed;
float voice0Freq;
float voice1Freq;
float voice2Freq;
float voice3Freq;
float myFreq;
volatile unsigned long level0;
volatile unsigned long level1;
volatile unsigned long level2;
volatile unsigned long level3;
volatile int MCP0 = 0;
volatile int MCP1 = 0;
volatile int MCP2 = 0;
volatile int MCP3 = 0;
void setup() {
pinMode (CS1, OUTPUT);//mcp4922 ONE
pinMode (CS2, OUTPUT);//mcp4922 TWO
pinMode(3, INPUT);//From 2nd Teensy
pinMode(4, INPUT);
pinMode(5, INPUT);
pinMode(6, INPUT);
pinMode(13, OUTPUT);
Serial.begin(31250);
MIDI.begin(MIDI_CHANNEL_OMNI);
//MIDI.turnThruOff();
MIDI.setHandleNoteOn(HandleNoteOn);
//MIDI.setHandleNoteOff(HandleNoteOff);
analogWriteResolution(12);
analogReadRes(12);
analogReadAveraging (1);//maximum is 32 minimum is one
spi4teensy3::init(); // initialize SPI:
Timer1.initialize (23);// Timer1.setPeriod(38);//23 is working
Timer1.attachInterrupt(fourOSC);
}
void fourOSC() {//ISR
MCP0 = digitalRead(3);//Read from 2nd Teensy zero when release ends
MCP1 = digitalRead(4);//Read from 2nd Teensy zero when release ends
MCP2 = digitalRead(5);//Read from 2nd Teensy zero when release ends
MCP3 = digitalRead(6);//Read from 2nd Teensy zero when release ends
//Oscillator / Voice Zero
phaccu0 = phaccu0 + tword0;
int i0 = phaccu0 >> 22;
fromarray0 = ((sine1024[i0] * level0) / 1261);// to sort out -31
//Oscillator / Voice One
phaccu1 = phaccu1 + tword1;
int i1 = phaccu1 >> 22;
fromarray1 = ((sine1024[i1] * level1) / 1261);// to sort out -31
//Oscillator / Voice Tw0
phaccu2 = phaccu2 + tword2;
int i2 = phaccu2 >> 22;
fromarray2 = ((sine1024[i2] * level2) / 1261);// to sort out -31
//Oscillator / Voice Three
phaccu3 = phaccu3 + tword3;
int i3 = phaccu3 >> 22;
fromarray3 = ((sine1024[i3] * level3) / 1261);// to sort out -31
mcpZero(fromarray0); //OUT to DAC
mcpOne(fromarray1); //OUT to DAC
mcpTwo(fromarray2); //OUT to DAC
mcpThree(fromarray3); //OUT to DAC
} //EO four OSC
void HandleNoteOn(byte channel, byte pitch, byte velocity)
{
if (channel == 1) {
if (velocity > 0) { ///if its a real note
digitalWrite(13, HIGH);
// flag if a free voice was found
byte voicesFree = 0;
// the voice to be used
byte voiceUsed = 0;
// temporary variable for finding oldest note
uint8_t seqNo = 0;
int i;
//MY INITIAL IDEA MY INITIAL IDEA code repeated for each voice i've taken the other 3 out
//to keep the code size down for reading
/*
if (notes[0].myOutput == 100 && MCP0 == 0) {
int i = 0;
Serial.println(notes[i].myPitch);
notes[i].myPitch = 0;
notes[i].myVelocity = 0;
notes[i].mySequence = 0;
notes[i].myOutput = 0;
printStuff();
}
*/
//IS THIS THE PLACE TO RELEASE NOTE AFTER GETTING ZERO FROM DIGITAL READ
//**************************************************************************************************
// try to find a free voice to play the note
for (i = 0; i < VOICES; i++)
{
// if a free voice is found, use it
if (notes[i].mySequence == 0)
{
notes[i].myPitch = pitch;
notes[i].myVelocity = velocity;
// store the time
notes[i].mySequence = 1;
// flag it
voicesFree = 1;
// store the voice used so the right oscillators can be turned on
voiceUsed = i;
break;
}
// increment the sequence number if the note is being used
else {
notes[i].mySequence = notes[i].mySequence + 1;
}// eo else
}//eo for i = 0; i < VOICES; i++
// assign seqNo to mySequence
notes[voiceUsed].mySequence = 1;
// assign pitch and velocity to myPitch and myVelocity
notes[voiceUsed].myPitch = pitch;
notes[voiceUsed].myVelocity = velocity;
notes[voiceUsed].myOutput = i + 100;
if (voicesFree > -1) //this is for test printing to see whats going on
{
// printStuff();
}
// voiceUsed is now the voice that will play the note
oscAFreq = noteFreqs[pitch];
// start the appropriate waveforms
switch (voiceUsed)
{
case 0:
phaccu0 = 0;
myvoiceUsed = 0;
myFreq = oscAFreq;
level0 = velocity * 10;
// kill0 = 1;
break;
case 1:
phaccu1 = 0;
myvoiceUsed = 1;
myFreq = oscAFreq;
level1 = velocity * 10;
break;
case 2:
phaccu2 = 0;
myvoiceUsed = 2;
myFreq = oscAFreq;
level2 = velocity * 10;
break;
case 3:
phaccu3 = 0;
myvoiceUsed = 3;
myFreq = oscAFreq;
level3 = velocity * 10;
break;
}//eo case
}//eo if Its a Real Note
// **************************************************************
// END OF NOTE ON .. AND START OFF NOTE OFF USING ZERO VELOCITY
if (velocity == 0) //IF its a note with zero velocity ie a note off
{
printStuff();
// holds the voice playing the pitch
byte voiceUsedInRelease = 0;
// find the voice which is playing the note
for (int i = 0; i < VOICES; i++)
{
if (pitch == notes[i].myPitch)
{
voiceUsedInRelease = i;
// reset the voice values
// THIS IS THE SECTION I THINK NEEDS TO BE TRIGGERED BY DIGITAL READS FROM 2ND TEENSY
//notes[i].myPitch = 0;
// notes[i].myVelocity = 0;
// notes[i].mySequence = 0;
// notes[i].myOutput = 0;
}//eo if
}//eo for
// signal the EGs to go to release mode (NOT USED)
// but if used will kill voice after sustain
/*
switch (voiceUsedInRelease)
{
case 0:
level0 = 0;
break;
case 1:
level1 = 0;
break;
case 2:
level2 = 0;
break;
case 3:
level3 = 0;
break;
}//eo switch
*/
}// EO if velocity == 0
}// if channel == 1
}//eo void HandleNoteOn
void loop() {
MIDI.read();
if (myvoiceUsed == 0) {
dfreq0 = myFreq;
tword0 = 4294967296 * dfreq0 / refclk;
}
if (myvoiceUsed == 1) {
dfreq1 = myFreq;
tword1 = 4294967296 * dfreq1 / refclk;
}
if (myvoiceUsed == 2) {
dfreq2 = myFreq;
tword2 = 4294967296 * dfreq2 / refclk;
}
if (myvoiceUsed == 3) {
dfreq3 = myFreq;
tword3 = 4294967296 * dfreq3 / refclk;
}
/*
Serial.print(" MCP0 = "); Serial.print(MCP0);
Serial.print(" MCP1 = "); Serial.print(MCP1);
Serial.print(" MCP2 = "); Serial.print(MCP2);
Serial.print(" MCP3 = "); Serial.println(MCP3);delay(20);
*/
}//eo void loop
void mcpZero(int value) {
uint16_t out = (0 << 15) | (1 << 14) | (1 << 13) | (1 << 12) | ( value );
digitalWriteFast(CS1, LOW);
spi4teensy3::send(out >> 8);
spi4teensy3::send(out & 0xFF);
digitalWriteFast(CS1, HIGH);
}
void mcpOne(int value) {
uint16_t out = (1 << 15) | (1 << 14) | (1 << 13) | (1 << 12) | ( value );
digitalWriteFast(CS1, LOW);
spi4teensy3::send(out >> 8);
spi4teensy3::send(out & 0xFF);
digitalWriteFast(CS1, HIGH);
}
void mcpTwo(int value) {
uint16_t out = (0 << 15) | (1 << 14) | (1 << 13) | (1 << 12) | ( value );
digitalWriteFast(CS2, LOW);
spi4teensy3::send(out >> 8);
spi4teensy3::send(out & 0xFF);
digitalWriteFast(CS2, HIGH);
}
void mcpThree(int value) {
uint16_t out = (1 << 15) | (1 << 14) | (1 << 13) | (1 << 12) | ( value );
digitalWriteFast(CS2, LOW);
spi4teensy3::send(out >> 8);
spi4teensy3::send(out & 0xFF);
digitalWriteFast(CS2, HIGH);
}
void printStuff() {
int s0 = notes[0].mySequence;
int s1 = notes[1].mySequence;
int s2 = notes[2].mySequence;
int s3 = notes[3].mySequence;
int p0 = notes[0].myPitch;
int p1 = notes[1].myPitch;
int p2 = notes[2].myPitch;
int p3 = notes[3].myPitch;
int v0 = notes[0].myVelocity;
int v1 = notes[1].myVelocity;
int v2 = notes[2].myVelocity;
int v3 = notes[3].myVelocity;
int o0 = notes[0].myOutput;
int o1 = notes[1].myOutput;
int o2 = notes[2].myOutput;
int o3 = notes[3].myOutput;
Serial.print("index = ");
Serial.print("\t");
Serial.print("0");
Serial.print("\t");
Serial.print("1");
Serial.print("\t");
Serial.print("2");
Serial.print("\t");
Serial.println("3");
Serial.print("mySequence = ");
Serial.print("\t");
Serial.print(s0);
Serial.print("\t");
Serial.print(s1);
Serial.print("\t");
Serial.print(s2);
Serial.print("\t");
Serial.println(s3);
Serial.print("myPitch = ");
Serial.print("\t");
Serial.print(p0);
Serial.print("\t");
Serial.print(p1);
Serial.print("\t");
Serial.print(p2);
Serial.print("\t");
Serial.println(p3);
Serial.print("myVelocity = ");
Serial.print("\t");
Serial.print(v0);
Serial.print("\t");
Serial.print(v1);
Serial.print("\t");
Serial.print(v2);
Serial.print("\t");
Serial.println(v3);
Serial.print("myOutput = ");
Serial.print("\t");
Serial.print(o0);
Serial.print("\t");
Serial.print(o1);
Serial.print("\t");
Serial.print(o2);
Serial.print("\t");
Serial.println(o3);
Serial.println("___________________________________________");
}
CODE FOR TEENSY TWO
Code:
#include <TimerOne.h>
#include <MIDI.h>
#include <SPI.h> //for MCP41
byte address = 0x11; //for MCP41
// how many voices do we have?
#define VOICES 4
// note struct contains a pitch, a velocity, and a sequence number
volatile typedef struct
{
uint8_t myPitch;
uint8_t myVelocity;
uint8_t mySequence;
}
note;
// array of notes four notes since we have four voices
note notes[VOICES];
volatile unsigned long delta;
//VARIABLES FOR ISR ADSR
volatile unsigned long phaccu0;
volatile unsigned long phaccu1;
volatile unsigned long phaccu2;
volatile unsigned long phaccu3;
volatile unsigned long tword0;
volatile unsigned long tword1;
volatile unsigned long tword2;
volatile unsigned long tword3;
const double refclk = 43470.00; //////was 43470
int i = 0;
volatile int i0;//value for MCP41100 0
volatile int i1;//value for MCP41100 1
volatile int i2;//value for MCP41100 2
volatile int i3;//value for MCP41100 2
volatile float speed0 = 2;
volatile float speed1 = 2;
volatile float speed2 = 2;
volatile float speed3 = 2;
volatile byte flag0 = 0;
volatile byte flag1 = 0;
volatile byte flag2 = 0;
volatile byte flag3 = 0;
volatile byte trigger0 = 0;
volatile byte trigger1 = 0;
volatile byte trigger2 = 0;
volatile byte trigger3 = 0;
void setup() {
pinMode (7, OUTPUT);//chip Select MCP0
pinMode (8, OUTPUT);//chip Select MCP1
pinMode (9, OUTPUT);//chip Select MCP2
pinMode (10, OUTPUT);//chip Select MCP3
pinMode(3, OUTPUT); //release
pinMode(4, OUTPUT); //release
pinMode(5, OUTPUT); //release
pinMode(6, OUTPUT); //release
pinMode(17, OUTPUT); //release LED just for testing
pinMode(18, OUTPUT); //release LED just for testing
pinMode(19, OUTPUT); //release LED just for testing
pinMode(20, OUTPUT); //release LED just for testing
pinMode(13, OUTPUT);
Serial.begin(31250);
MIDI.begin(MIDI_CHANNEL_OMNI);
// MIDI.turnThruOff();
MIDI.setHandleNoteOn(HandleNoteOn);
// MIDI.setHandleNoteOff(HandleNoteOff);
analogWriteResolution(12);
analogReadRes(12);
analogReadAveraging (1);//maximum is 32 minimum is one
SPI.begin();//for MCP41
MCP0(0x00); MCP0(0x80); MCP0(0xFF); //for MCP0
MCP1(0x00); MCP1(0x80); MCP1(0xFF); //for MCP1
MCP2(0x00); MCP2(0x80); MCP2(0xFF); //for MCP2
MCP3(0x00); MCP3(0x80); MCP3(0xFF); //for MCP3
Timer1.initialize (100);
Timer1.attachInterrupt(VCAISR);
}//eo setup
void VCAISR() {
ADSR0();
ADSR1();
ADSR2();
ADSR3();
} //EO VCAISR
void ADSR0() {
//ATTACK
if (trigger0 == 1 && flag0 == 1) {
speed0 = 1;
phaccu0 = phaccu0 + tword0;
i0 = phaccu0 >> 24;
if (i0 > 200) {
flag0 = 2;
}
if (trigger0 == 2) {
flag0 = 3;
}
}//eo attack
//DECAY AND SUSTAIN
if (trigger0 == 1 && flag0 == 2) {
speed0 = 9;
phaccu0 = phaccu0 - tword0;
i0 = phaccu0 >> 24;
if (i0 < 60) {
flag0 = 3;
}
if (trigger0 == 2) {
flag0 = 3;
}
}//eo decay sustain
//RELEASE
if (trigger0 == 2 && flag0 == 3) {
speed0 = 0.01;
phaccu0 = phaccu0 - tword0;
i0 = phaccu0 >> 24;
if (i0 < 1) {
digitalWrite(3, LOW); //out to Teensy 1
digitalWrite(17, LOW);
flag0 = 0;
}
}//eo release
MCP0(i0);//Write value to MCP41010
}//EO void ADSR0
void ADSR1() {
//ATTACK
if (trigger1 == 1 && flag1 == 1) {
speed1 = 1;
phaccu1 = phaccu1 + tword1;
i1 = phaccu1 >> 24;
if (i1 > 200) {
flag1 = 2;
}
if (trigger1 == 2) {
flag1 = 3;
}
}//eo attack
//DECAY AND SUSTAIN
if (trigger1 == 1 && flag1 == 2) {
speed1 = 9;
phaccu1 = phaccu1 - tword1;
i1 = phaccu1 >> 24;
if (i1 < 60) {
flag1 = 3;
}
if (trigger1 == 2) {
flag1 = 3;
}
}//eo decay sustain
//RELEASE
if (trigger1 == 2 && flag1 == 3) {
speed1 = 0.01;
phaccu1 = phaccu1 - tword1;
i1 = phaccu1 >> 24;
if (i1 < 1) {
digitalWrite(4, LOW); //out to Teensy 1
digitalWrite(18, LOW);
flag1 = 0;
}
}//eo release
MCP1(i1);//Write value to MCP41010
}//eo void ADSR1
void ADSR2() {
//ATTACK
if (trigger2 == 1 && flag2 == 1) {
speed2 = 1;
phaccu2 = phaccu2 + tword2;
i2 = phaccu2 >> 24;
if (i2 > 200) {
flag2 = 2;
}
if (trigger2 == 2) {
flag2 = 3;
}
}//eo attack
//DECAY AND SUSTAIN
if (trigger2 == 1 && flag2 == 2) {
speed2 = 9;
phaccu2 = phaccu2 - tword2;
i2 = phaccu2 >> 24;
if (i2 < 60) {
flag2 = 3;
}
if (trigger2 == 2) {
flag2 = 3;
}
}//eo decay sustain
//RELEASE
if (trigger2 == 2 && flag2 == 3) {
speed2 = 0.01;
phaccu2 = phaccu2 - tword2;
i2 = phaccu2 >> 24;
if (i2 < 1) {
digitalWrite(5, LOW); //out to Teensy 1
digitalWrite(19, LOW);
flag2 = 0;
}
}//eo release
MCP2(i2);//Write value to MCP41010
}//eo void ADSR2
void ADSR3(){
//ATTACK
if (trigger3 == 1 && flag3 == 1) {
speed3 = 1;
phaccu3 = phaccu3 + tword3;
i3 = phaccu3 >> 24;
if (i3 > 200) {
flag3 = 2;
}
if (trigger3 == 2) {
flag3 = 3;
}
}//eo attack
//DECAY AND SUSTAIN
if (trigger3 == 1 && flag3 == 2) {
speed3 = 9;
phaccu3 = phaccu3 - tword3;
i3 = phaccu3 >> 24;
if (i3 < 60) {
flag3 = 3;
}
if (trigger3 == 2) {
flag3 = 3;
}
}//eo decay sustain
//RELEASE
if (trigger3 == 2 && flag3 == 3) {
speed3 = 0.01;
phaccu3 = phaccu3 - tword3;
i3 = phaccu3 >> 24;
if (i3 < 1) {
digitalWrite(6, LOW); //out to Teensy 1
digitalWrite(20, LOW);
flag3 = 0;
}
}//eo release
MCP3(i3); //Write value to MCP41010
}//eo void ADSR3
void HandleNoteOn(byte channel, byte pitch, byte velocity)
{
if (channel == 1) {
if (velocity > 0) { ///if its a real note
digitalWrite(13, HIGH);
// flag if a free voice was found
byte voicesFree = 0;
// the voice to be used
byte voiceUsed = 0;
// temporary variable for finding oldest note
uint8_t seqNo = 0;
int i;
//**************************************************************************************************
// try to find a free voice to play the note
for (i = 0; i < VOICES; i++)
{
// if a free voice is found, use it
if (notes[i].mySequence == 0)
{
notes[i].myPitch = pitch;
notes[i].myVelocity = velocity;
// store the time
notes[i].mySequence = 1;
// flag it
voicesFree = 1;
// store the voice used so the right ADSR's can be turned on
voiceUsed = i;
break;
}
// increment the sequence number if the note is being used
else
{
notes[i].mySequence = notes[i].mySequence + 1;
}// eo else
}//eo for i = 0; i < VOICES; i++
// voiceUsed is now the voice that will trigger the ADSR so start the appropriate ADSR
switch (voiceUsed)
{
case 0:
phaccu0 = 0;
trigger0 = 1;
flag0 = 1;
digitalWrite(3, HIGH);//out to Teensy 1
digitalWrite(17, HIGH);
break;
case 1:
phaccu1 = 0;
trigger1 = 1;
flag1 = 1;
digitalWrite(4, HIGH);//out to Teensy 1
digitalWrite(18, HIGH);
break;
case 2:
phaccu2 = 0;
trigger2 = 1;
flag2 = 1;
digitalWrite(5, HIGH);//out to Teensy 1
digitalWrite(19, HIGH);
break;
case 3:
phaccu3 = 0;
trigger3 = 1;
flag3 = 1;
digitalWrite(6, HIGH);//out to Teensy 1
digitalWrite(20, HIGH);
break;
}//eo SWITCH CASE
}//eo if Its a Real Note
// **************************************************************
// END OF NOTE ON .. AND START OFF NOTE OFF USING ZERO VELOCITY
if (velocity == 0) { //IF its a note with zero velocity ie a note off
digitalWrite(13, LOW);
// holds the voice playing the pitch
byte voiceUsed = 0;
// find the voice which is playing the note
for (int i = 0; i < VOICES; i++)
{
// Serial.println(notes[i].myPitch);
if (pitch == notes[i].myPitch)
{
voiceUsed = i;
// reset the voice values
notes[i].myPitch = 0;
notes[i].myVelocity = 0;
notes[i].mySequence = 0;
}
}//eo for
// signal the EGs to go to release mode
switch (voiceUsed)
{
case 0:
speed0 = 0.001;
trigger0 = 2;
flag0 = 3;
break;
case 1:
speed1 = 0.001;
trigger1 = 2;
flag1 = 3;
break;
case 2:
speed2 = 0.001;
trigger2 = 2;
flag2 = 3;
break;
case 3:
speed3 = 0.001;
trigger3 = 2;
flag3 = 3;
break;
}//eo switch
}// EO if velocity == 0
}// if channel == 1
}//eo void HandleNoteOn
void loop() {
MIDI.read();
if (trigger0 == 1) {
tword0 = 4294967296 * speed0 / refclk;
}
if (trigger1 == 1) {
tword1 = 4294967296 * speed1 / refclk;
}
if (trigger2 == 1) {
tword2 = 4294967296 * speed2 / refclk;
}
if (trigger3 == 1) {
tword3 = 4294967296 * speed3 / refclk;
}
}//eo void loop
//MCP41100
void MCP0(int value) {
digitalWrite(7, LOW);
SPI.transfer(address);
SPI.transfer(value);
digitalWrite(7, HIGH);
}
void MCP1(int value) {
digitalWrite(8, LOW);
SPI.transfer(address);
SPI.transfer(value);
digitalWrite(8, HIGH);
}
void MCP2(int value) {
digitalWrite(9, LOW);
SPI.transfer(address);
SPI.transfer(value);
digitalWrite(9, HIGH);
}
void MCP3(int value) {
digitalWrite(10, LOW);
SPI.transfer(address);
SPI.transfer(value);
digitalWrite(10, HIGH);
}