├── AdditiveWavetableCreator.py ├── COLLATZ └── CollatzArpeggiatorTest │ └── CollatzArpeggiatorTest.ino ├── DRONE SYNTH ├── Display_ControlV1 │ └── Display_ControlV1.ino ├── DroneSynth_Cheapo_FINAL │ └── DroneSynth_Cheapo_FINAL.ino └── DroneSynth_WaveformChoiceV5 │ └── DroneSynth_WaveformChoiceV5.ino ├── Drone Synth -- Test 1.mp3 ├── Drone Synth -- Test 2.mp3 ├── DroneSynth_WaveformChoiceV5 └── DroneSynth_WaveformChoiceV5.ino ├── JohnSynth_V6 └── JohnSynth_V6.ino ├── LFO └── LFO.ino ├── MODMIX_BASS_SYNTH └── MODMIX_BASS_SYNTH.ino ├── MOZZI_BASS_SYNTH_V3 └── MOZZI_BASS_SYNTH_V3.ino ├── PERCUSSION_MOZZI_SYNTH_V4 └── PERCUSSION_MOZZI_SYNTH_V4.ino └── README.md /AdditiveWavetableCreator.py: -------------------------------------------------------------------------------- 1 | import math 2 | import matplotlib.pyplot as plt 3 | import numpy as np 4 | 5 | 6 | def sine(resolution, length, harmonic): 7 | wave = [] 8 | step_size = math.pi / length 9 | for x in range(length): 10 | y = math.sin(x*step_size*harmonic) * (resolution/2) 11 | wave.append(y) 12 | return wave 13 | 14 | 15 | def square(resolution, length, harmonic): 16 | wave = [] 17 | for x in range(length): 18 | if (x*harmonic)%length < length/2: y = 0 19 | else: y = resolution 20 | wave.append(y) 21 | return wave 22 | 23 | 24 | 25 | def saw(resolution, length, harmonic): 26 | wave = [] 27 | slope = resolution / (length / harmonic) 28 | for x in range(length): 29 | y = ((x*harmonic)%length)*slope 30 | wave.append(y) 31 | return wave 32 | 33 | 34 | 35 | def triangle(resolution, length, harmonic): 36 | wave = [] 37 | slope = resolution / (length / harmonic) 38 | for x in range(length): 39 | if (x*harmonic)%length < length/2: y = ((x*harmonic)%length)*slope 40 | else: y = ((x*harmonic)%length)*(-1*slope) 41 | wave.append(y) 42 | return wave 43 | 44 | 45 | 46 | def tangent(resolution, length, harmonic): 47 | wave = [] 48 | step_size = math.pi / length 49 | for x in range(length): 50 | y = math.tan(x*step_size*harmonic) * (resolution/2) 51 | wave.append(y) 52 | return wave 53 | 54 | 55 | 56 | def hyperbolic_tangent(resolution, length, harmonic): 57 | wave = [] 58 | step_size = math.pi / length 59 | for x in range(length): 60 | y = math.tanh(x*step_size*harmonic) * (resolution/2) 61 | wave.append(y) 62 | return wave 63 | 64 | 65 | 66 | def rounded_square(resolution, length, harmonic): 67 | wave = [] 68 | for x in range(length): 69 | if (x*harmonic)%length < length/2: y = y = math.tanh(x*harmonic) * (resolution/2) 70 | else: y = math.tanh((length - x)*harmonic) * (resolution/2) 71 | wave.append(y) 72 | return wave 73 | 74 | 75 | 76 | 77 | 78 | '''##################''' 79 | '''####TEST TIME!####''' 80 | '''##################''' 81 | resolution = int(1024) 82 | length = 2**13 83 | waves = [sine(resolution/3, length, 2), 84 | sine(resolution/6, length, 4), 85 | sine(resolution/6, length, 6), 86 | sine(resolution/6, length, 8), 87 | sine(resolution/12, length, 10), 88 | sine(resolution/12, length, 12), 89 | sine(resolution/12, length, 14)] 90 | table_y = np.zeros(length) 91 | table_x = np.zeros(length) 92 | wavetable = [] 93 | for i in range(length): 94 | table_x[i] += i 95 | for wave in waves: 96 | table_y[i] += math.floor(wave[i]) 97 | wavetable.append(table_y[i]) 98 | 99 | print(wavetable) 100 | print(len(wavetable), max(wavetable), min(wavetable)) 101 | 102 | 103 | plt.plot(table_x, table_y, label='Waveform') 104 | plt.xlabel('Wavetable Index') 105 | plt.ylabel('Value') 106 | plt.title('Waveform Plot') 107 | plt.show() 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /COLLATZ/CollatzArpeggiatorTest/CollatzArpeggiatorTest.ino: -------------------------------------------------------------------------------- 1 | //necessary Mozzi functions 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | 9 | 10 | /*########################### 11 | * WAVETABLES AND MOZZI STUFF 12 | ############################ */ 13 | //wavetables (all same size for switching function) 14 | #include 15 | 16 | //Oscillator objects 17 | Oscil aCarrier_1(SIN2048_DATA); 18 | 19 | //tone table 20 | int tone_table[38] = {123, 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, 21 | 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, 22 | 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, 1046}; 23 | 24 | 25 | 26 | 27 | /*#################################### 28 | * PINS, INPUTS, AND CONTROL VARIABLES 29 | ####################################*/ 30 | //pushbuttons 31 | const int numOfButtons = 8; 32 | const int DIGITAL_PINS[numOfButtons] = {2, 3, 4, 5, 6, 7, 8, 11}; 33 | 34 | //tempo control potentiometer 35 | const int TEMPO_PIN = 0; 36 | int bpm, noteChange; 37 | int counter = 0; 38 | 39 | //note range control and mode control 40 | const int RANGE_PIN = 1; 41 | const int START_PIN = 2; 42 | const int MODE_PIN = 12; 43 | byte noteRange, noteStart; 44 | 45 | //for Collatz Sequence 46 | byte increase, toAdd; 47 | int index = 0; 48 | long current_number = 1; 49 | long new_number; 50 | 51 | 52 | 53 | 54 | 55 | void setup() { 56 | Serial.begin(9600); 57 | startMozzi(); 58 | } 59 | 60 | 61 | void updateControl(){ 62 | //#### READ INPUTS #### 63 | //PUSHBUTTONS 64 | toAdd = 0; 65 | for (int i=0; i> 5; 76 | noteStart = 2 + (12 * (mozziAnalogRead(START_PIN) >> 7)); 77 | 78 | 79 | //#### CHECK MODE PIN! DO STUFF! #### 80 | //COLLATZ! 81 | /* 82 | * If counter is greater than noteChange, it's time to move to the next note. 83 | * If current number is 1, then the end of the collatz sequence has been reached and it's time to get a new number 84 | * If the current number isn't 1, then find the next number in the collatz sequence. 85 | * Then use the current number to get the index for which tone to play 86 | */ 87 | if (digitalRead(MODE_PIN) == LOW) { 88 | if (counter > noteChange) { 89 | if (current_number == 1) {current_number += toAdd;} 90 | else { 91 | if (current_number % 2 == 0) { 92 | int new_number = current_number / 2; 93 | current_number = new_number; 94 | } 95 | else { 96 | int new_number = current_number * 3; 97 | new_number++; 98 | current_number = new_number; 99 | } 100 | } 101 | index = current_number % 38; 102 | 103 | aCarrier_1.setFreq(tone_table[index]); 104 | Serial.print("Current Number: "); 105 | Serial.println(current_number); 106 | Serial.print("To Add: "); 107 | Serial.println(toAdd); 108 | Serial.print("Tone: "); 109 | Serial.println(tone_table[index]); 110 | 111 | counter = 0; 112 | } 113 | } 114 | 115 | //ARPEGGIATE! 116 | 117 | //increment counter and restart the loop 118 | counter++; 119 | } 120 | 121 | 122 | 123 | int updateAudio(){ 124 | return aCarrier_1.next() << 4; 125 | } 126 | 127 | 128 | void loop() { 129 | audioHook(); 130 | } 131 | -------------------------------------------------------------------------------- /DRONE SYNTH/Display_ControlV1/Display_ControlV1.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #define LED_PIN 12 3 | #define LED_COUNT 6 4 | Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800); 5 | 6 | 7 | 8 | //PIN assignment variables 9 | const int NUM = 8; 10 | const int BUTTONS[NUM] = {2, 3, 4, 5, 6, 7, 9, 10}; 11 | const int CHOICES = 6; 12 | 13 | //State variable -- incs on button push 14 | int states[NUM] = {0, 0, 0, 0, 0, 0, 0, 0}; 15 | 16 | //Variables for button debounce 17 | unsigned long t = 250; 18 | unsigned long now; 19 | unsigned long delta; 20 | const int threshold = 210; 21 | 22 | 23 | 24 | void setup() { 25 | strip.begin(); 26 | strip.show(); 27 | Serial.begin(9600); 28 | } 29 | 30 | void loop() { 31 | //Calculate delta 32 | now = millis(); 33 | delta = now - t; 34 | 35 | //Read button inputs and inc state variables 36 | for (byte i=0; i threshold) { 38 | if (states[i] >= 5) {states[i] = 0;} 39 | else {states[i]++;} 40 | Serial.print(states[i]); 41 | t = millis(); 42 | } 43 | } 44 | 45 | for (int i=2; i 16 | #include 17 | #include 18 | #include 19 | //wavetables (all same size for switching function) 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | 30 | // desired carrier frequency max and min, for AutoMap 31 | const int MIN_CARRIER_FREQ = 0; 32 | const int MAX_CARRIER_FREQ = 440; 33 | 34 | // desired intensity max and min, for AutoMap, note they're inverted for reverse dynamics 35 | const int MIN_INTENSITY = 700; 36 | const int MAX_INTENSITY = 1; 37 | 38 | // desired mod speed max and min, for AutoMap, note they're inverted for reverse dynamics 39 | const int MIN_MOD_SPEED = 10000; 40 | const int MAX_MOD_SPEED = 0; 41 | 42 | //automap functions to more quickly map ADC inputs to desired values 43 | AutoMap kMapCarrierFreq(0,1023,MIN_CARRIER_FREQ,MAX_CARRIER_FREQ); 44 | AutoMap kMapIntensity(0,1023,MIN_INTENSITY,MAX_INTENSITY); 45 | AutoMap kMapModSpeed(0,1023,MIN_MOD_SPEED,MAX_MOD_SPEED); 46 | 47 | //PINS! 48 | const byte CARRIER_PIN_1 = 0; 49 | const byte MODULATOR_PIN_1 = 1; 50 | const byte INTENSITY_PIN_1 = 2; 51 | const byte CARRIER_PIN_2 = 3; 52 | const byte MODULATOR_PIN_2 = 4; 53 | const byte INTENSITY_PIN_2 = 5; 54 | const byte WF_PIN_1A = 8; //aCarrier_1 55 | const byte WF_PIN_1B = 7; //aCarrier_1 56 | const byte WF_PIN_2A = 6; //aCarrier_2 57 | const byte WF_PIN_2B = 5; //aCarrier_2 58 | const byte WF_PIN_3A = 4; //aMod_1 59 | const byte WF_PIN_4A = 3; //aMod_2 60 | const byte ON_OFF_1 = 11; //voice 1 toggle 61 | const byte ON_OFF_2 = 12; //voice 2 toggle 62 | const byte ASSIGN_SETTINGS = 2; 63 | const byte CHANNEL_SELECT = 21; 64 | const byte CHANNEL_TOGGLE = 20; 65 | 66 | //Oscillator objects 67 | Oscil<512, AUDIO_RATE> aCarrier_1; 68 | Oscil<512, AUDIO_RATE> aModulator_1; 69 | Oscil<512, CONTROL_RATE> kIntensityMod_1; 70 | Oscil<512, AUDIO_RATE> aCarrier_2; 71 | Oscil<512, AUDIO_RATE> aModulator_2; 72 | Oscil<512, CONTROL_RATE> kIntensityMod_2; 73 | 74 | //for toggle 75 | boolean channel_1 = HIGH; //0 = OFF, 1 = ON 76 | boolean channel_2 = HIGH; //0 = OFF, 1 = ON 77 | int channel_1_debounce = 0; 78 | int channel_2_debounce = 0; 79 | 80 | // for controlling table swaps 81 | boolean D1; 82 | boolean D2; 83 | boolean D3; 84 | boolean D4; 85 | boolean D5; 86 | boolean D6; 87 | int wfc_1 = 0; 88 | int wfc_2 = 0; 89 | int wfc_3 = 0; 90 | int wfc_4 = 0; 91 | int wfc_5 = 0; 92 | int wfc_6 = 0; 93 | int count1 = 0; 94 | int count2 = 0; 95 | int count3 = 0; 96 | int count4 = 0; 97 | int count5 = 0; 98 | int count6 = 0; 99 | unsigned long debounce1 = 0; 100 | unsigned long debounce2 = 0; 101 | unsigned long debounce3 = 0; 102 | unsigned long debounce4 = 0; 103 | unsigned long debounce5 = 0; 104 | unsigned long debounce6 = 0; 105 | int debounce_time = 13; 106 | int ch1[6] = {0, 0, 0, 0, 0, 0}; 107 | int ch2[6] = {0, 0, 0, 0, 0, 0}; 108 | 109 | 110 | 111 | int mod_ratio = 5; // brightness (harmonics) 112 | long fm_intensity_1; // carries control info from updateControl to updateAudio 113 | long fm_intensity_2; 114 | 115 | 116 | float smoothness = 0.95f; 117 | Smooth aSmoothIntensity(smoothness); 118 | 119 | 120 | void setup() { 121 | startMozzi(); 122 | } 123 | 124 | 125 | void updateControl(){ 126 | //inc debounce values 127 | debounce1++; 128 | debounce2++; 129 | debounce3++; 130 | debounce4++; 131 | debounce5++; 132 | debounce6++; 133 | channel_1_debounce++; 134 | channel_2_debounce++; 135 | //read digital inputs to set wavetables 136 | D1 = digitalRead(WF_PIN_1A); //aCarrier_1 137 | D2 = digitalRead(WF_PIN_1B); //aCarrier_1 138 | D3 = digitalRead(WF_PIN_2A); //aCarrier_2 139 | D4 = digitalRead(WF_PIN_2B); //aCarrier_2 140 | D5 = digitalRead(WF_PIN_3A); //aMod_1 141 | D6 = digitalRead(WF_PIN_4A); //aMod_2 142 | //aCarrier_1 143 | if (D1 == HIGH and debounce1 > debounce_time) { 144 | count1++; 145 | wfc_1 = count1%8; 146 | debounce1 = 0; 147 | } 148 | switch (wfc_1) { 149 | case 0: 150 | aCarrier_1.setTable(SIN512_DATA); 151 | break; 152 | case 1: 153 | aCarrier_1.setTable(SAW512_DATA); 154 | break; 155 | case 2: 156 | aCarrier_1.setTable(SQUARE_NO_ALIAS512_DATA); 157 | break; 158 | case 3: 159 | aCarrier_1.setTable(TRIANGLE512_DATA); 160 | break; 161 | case 4: 162 | aCarrier_1.setTable(HANDMADE_1_512_DATA); 163 | break; 164 | case 5: 165 | aCarrier_1.setTable(HANDMADE_2_512_DATA); 166 | break; 167 | case 6: 168 | aCarrier_1.setTable(HANDMADE_5_512_DATA); 169 | break; 170 | case 7: 171 | aCarrier_1.setTable(HANDMADE_4_512_DATA); 172 | break; 173 | } 174 | 175 | //aModulator_1 176 | if (D2 == HIGH and debounce2 > debounce_time) { 177 | count2++; 178 | wfc_2 = count2%8; 179 | debounce2 = 0; 180 | } 181 | switch (wfc_2) { 182 | case 0: 183 | aModulator_1.setTable(SIN512_DATA); 184 | break; 185 | case 1: 186 | aModulator_1.setTable(SAW512_DATA); 187 | break; 188 | case 2: 189 | aModulator_1.setTable(SQUARE_NO_ALIAS512_DATA); 190 | break; 191 | case 3: 192 | aModulator_1.setTable(TRIANGLE512_DATA); 193 | break; 194 | case 4: 195 | aModulator_1.setTable(HANDMADE_1_512_DATA); 196 | break; 197 | case 5: 198 | aModulator_1.setTable(HANDMADE_2_512_DATA); 199 | break; 200 | case 6: 201 | aModulator_1.setTable(HANDMADE_5_512_DATA); 202 | break; 203 | case 7: 204 | aModulator_1.setTable(HANDMADE_4_512_DATA); 205 | break; 206 | } 207 | //kIntensityMod_1 208 | if (D3 == HIGH and debounce3 > debounce_time) { 209 | count3++; 210 | wfc_3 = count3 % 8; 211 | debounce3 = 0; 212 | } 213 | switch (wfc_3) { 214 | case 0: 215 | kIntensityMod_1.setTable(SIN512_DATA); 216 | break; 217 | case 1: 218 | kIntensityMod_1.setTable(SAW512_DATA); 219 | break; 220 | case 2: 221 | kIntensityMod_1.setTable(SQUARE_NO_ALIAS512_DATA); 222 | break; 223 | case 3: 224 | kIntensityMod_1.setTable(TRIANGLE512_DATA); 225 | break; 226 | case 4: 227 | kIntensityMod_1.setTable(HANDMADE_1_512_DATA); 228 | break; 229 | case 5: 230 | kIntensityMod_1.setTable(HANDMADE_2_512_DATA); 231 | break; 232 | case 6: 233 | kIntensityMod_1.setTable(HANDMADE_5_512_DATA); 234 | break; 235 | case 7: 236 | kIntensityMod_1.setTable(HANDMADE_4_512_DATA); 237 | break; 238 | } 239 | //aCarrier_2 240 | if (D4 == HIGH and debounce4 > debounce_time) { 241 | count4++; 242 | wfc_4 = count4 % 8; 243 | debounce4 = 0; 244 | } 245 | switch (wfc_4) { 246 | case 0: 247 | aCarrier_2.setTable(SIN512_DATA); 248 | break; 249 | case 1: 250 | aCarrier_2.setTable(SAW512_DATA); 251 | break; 252 | case 2: 253 | aCarrier_2.setTable(SQUARE_NO_ALIAS512_DATA); 254 | break; 255 | case 3: 256 | aCarrier_2.setTable(TRIANGLE512_DATA); 257 | break; 258 | case 4: 259 | aCarrier_2.setTable(HANDMADE_1_512_DATA); 260 | break; 261 | case 5: 262 | aCarrier_2.setTable(HANDMADE_2_512_DATA); 263 | break; 264 | case 6: 265 | aCarrier_2.setTable(HANDMADE_5_512_DATA); 266 | break; 267 | case 7: 268 | aCarrier_2.setTable(HANDMADE_4_512_DATA); 269 | break; 270 | } 271 | 272 | //aModulator_2 273 | if (D5 == HIGH and debounce5 > debounce_time) { 274 | count5++; 275 | wfc_5 = count5 % 8; 276 | debounce5 = 0; 277 | } 278 | switch (wfc_5) { 279 | case 0: 280 | aModulator_2.setTable(SIN512_DATA); 281 | break; 282 | case 1: 283 | aModulator_2.setTable(SAW512_DATA); 284 | break; 285 | case 2: 286 | aModulator_2.setTable(SQUARE_NO_ALIAS512_DATA); 287 | break; 288 | case 3: 289 | aModulator_2.setTable(TRIANGLE512_DATA); 290 | break; 291 | case 4: 292 | aModulator_2.setTable(HANDMADE_1_512_DATA); 293 | break; 294 | case 5: 295 | aModulator_2.setTable(HANDMADE_2_512_DATA); 296 | break; 297 | case 6: 298 | aModulator_2.setTable(HANDMADE_5_512_DATA); 299 | break; 300 | case 7: 301 | aModulator_2.setTable(HANDMADE_4_512_DATA); 302 | break; 303 | } 304 | //kIntensity_2 305 | if (D6 == HIGH and debounce6 > debounce_time) { 306 | count6++; 307 | wfc_6 = count6 % 8; 308 | debounce6 = 0; 309 | } 310 | switch (wfc_6) { 311 | case 0: 312 | kIntensityMod_2.setTable(SIN512_DATA); 313 | break; 314 | case 1: 315 | kIntensityMod_2.setTable(SAW512_DATA); 316 | break; 317 | case 2: 318 | kIntensityMod_2.setTable(SQUARE_NO_ALIAS512_DATA); 319 | break; 320 | case 3: 321 | kIntensityMod_2.setTable(TRIANGLE512_DATA); 322 | break; 323 | case 4: 324 | kIntensityMod_2.setTable(HANDMADE_1_512_DATA); 325 | break; 326 | case 5: 327 | kIntensityMod_2.setTable(HANDMADE_2_512_DATA); 328 | break; 329 | case 6: 330 | kIntensityMod_2.setTable(HANDMADE_5_512_DATA); 331 | break; 332 | case 7: 333 | kIntensityMod_2.setTable(HANDMADE_4_512_DATA); 334 | break; 335 | } 336 | 337 | if (digitalRead(ON_OFF_1) == HIGH and channel_1_debounce > debounce_time) { 338 | if (channel_1 == HIGH) {channel_1 = LOW;} 339 | else if (channel_1 == LOW) {channel_1 = HIGH;} 340 | channel_1_debounce = 0; 341 | } 342 | if (digitalRead(ON_OFF_2) == HIGH and channel_2_debounce > debounce_time) { 343 | if (channel_2 == HIGH) {channel_2 = LOW;} 344 | else if (channel_2 == LOW) {channel_2 = HIGH;} 345 | channel_2_debounce = 0; 346 | } 347 | //Read analog inputs for oscillator objects if channel is on, otehrwise, set all to OFF values. 348 | int carrier_value_1, intensity_value_1, modulator_value_1; 349 | int carrier_value_2, intensity_value_2, modulator_value_2; 350 | if (channel_1 == LOW) { 351 | carrier_value_1 = 0; 352 | intensity_value_1 = 1024; 353 | modulator_value_1 = 1024; 354 | } 355 | else { 356 | carrier_value_1 = mozziAnalogRead(CARRIER_PIN_1); 357 | intensity_value_1= mozziAnalogRead(INTENSITY_PIN_1); 358 | modulator_value_1 = mozziAnalogRead(MODULATOR_PIN_1); 359 | } 360 | if (channel_2 == LOW) { 361 | carrier_value_2 = 0; 362 | intensity_value_2 = 1024; 363 | modulator_value_2 = 1024; 364 | } 365 | else { 366 | carrier_value_2 = mozziAnalogRead(CARRIER_PIN_2); 367 | intensity_value_2= mozziAnalogRead(INTENSITY_PIN_2); 368 | modulator_value_2 = mozziAnalogRead(MODULATOR_PIN_2); 369 | } 370 | 371 | //calculate values for updateAudio function for each channel 372 | int carrier_freq_1 = kMapCarrierFreq(carrier_value_1); 373 | int mod_freq_1 = carrier_freq_1 * mod_ratio; 374 | int intensity_calibrated_1 = kMapIntensity(intensity_value_1); 375 | fm_intensity_1 = ((long)intensity_calibrated_1 * (kIntensityMod_1.next()+128))>>8; 376 | float mod_speed_1 = (float)kMapModSpeed(modulator_value_1)/1000; 377 | 378 | int carrier_freq_2 = kMapCarrierFreq(carrier_value_2); 379 | int mod_freq_2 = carrier_freq_2 * mod_ratio; 380 | int intensity_calibrated_2 = kMapIntensity(intensity_value_2); 381 | fm_intensity_2 = ((long)intensity_calibrated_2 * (kIntensityMod_2.next()+128))>>8; 382 | float mod_speed_2 = (float)kMapModSpeed(modulator_value_2)/1000; 383 | 384 | //saved channel settings inputs 385 | if (digitalRead(ASSIGN_SETTINGS) == HIGH) { 386 | if (digitalRead(CHANNEL_SELECT) == LOW) { 387 | ch1[0] = carrier_freq_1; 388 | ch1[1] = mod_freq_1; 389 | ch1[2] = mod_speed_1; 390 | ch1[3] = carrier_freq_2; 391 | ch1[4] = mod_freq_2; 392 | ch1[5] = mod_speed_2; 393 | } 394 | else if (digitalRead(CHANNEL_SELECT) == HIGH) { 395 | ch2[0] = carrier_freq_1; 396 | ch2[1] = mod_freq_1; 397 | ch2[2] = mod_speed_1; 398 | ch2[3] = carrier_freq_2; 399 | ch2[4] = mod_freq_2; 400 | ch2[5] = mod_speed_2; 401 | } 402 | } 403 | 404 | 405 | //assign oscillator object frequencies 406 | if (digitalRead(CHANNEL_TOGGLE) == LOW) { 407 | aCarrier_1.setFreq(carrier_freq_1); 408 | aModulator_1.setFreq(mod_freq_1); 409 | kIntensityMod_1.setFreq(mod_speed_1); 410 | aCarrier_2.setFreq(carrier_freq_2); 411 | aModulator_2.setFreq(mod_freq_2); 412 | kIntensityMod_2.setFreq(mod_speed_2); 413 | } 414 | else if (digitalRead(CHANNEL_TOGGLE) == HIGH) { 415 | if (digitalRead(CHANNEL_SELECT) == LOW) { 416 | aCarrier_1.setFreq(ch1[0]); 417 | aModulator_1.setFreq(ch1[1]); 418 | kIntensityMod_1.setFreq(ch1[2]); 419 | aCarrier_2.setFreq(ch1[3]); 420 | aModulator_2.setFreq(ch1[4]); 421 | kIntensityMod_2.setFreq(ch1[5]); 422 | } 423 | if (digitalRead(CHANNEL_SELECT) == HIGH) { 424 | aCarrier_1.setFreq(ch2[0]); 425 | aModulator_1.setFreq(ch2[1]); 426 | kIntensityMod_1.setFreq(ch2[2]); 427 | aCarrier_2.setFreq(ch2[3]); 428 | aModulator_2.setFreq(ch2[4]); 429 | kIntensityMod_2.setFreq(ch2[5]); 430 | } 431 | } 432 | /* 433 | * cycle debounce variables so they don't overflow -- 434 | * only needs to happen VERY infrequently. 435 | */ 436 | if (debounce1 > 4000000000) {debounce1 = debounce_time + 1;} 437 | if (debounce2 > 4000000000) {debounce2 = debounce_time + 1;} 438 | if (debounce3 > 4000000000) {debounce3 = debounce_time + 1;} 439 | if (debounce4 > 4000000000) {debounce4 = debounce_time + 1;} 440 | if (debounce5 > 4000000000) {debounce5 = debounce_time + 1;} 441 | if (debounce6 > 4000000000) {debounce6 = debounce_time + 1;} 442 | } 443 | 444 | 445 | int updateAudio(){ 446 | long modulation_1 = aSmoothIntensity.next(fm_intensity_1) * aModulator_1.next(); 447 | long modulation_2 = aSmoothIntensity.next(fm_intensity_2) * aModulator_2.next(); 448 | return (aCarrier_1.phMod(modulation_1) + aCarrier_2.phMod(modulation_2)) << 5; //V4 CHANGE FOR HIFI MODE 449 | } 450 | 451 | 452 | void loop() { 453 | audioHook(); 454 | } 455 | -------------------------------------------------------------------------------- /DRONE SYNTH/DroneSynth_WaveformChoiceV5/DroneSynth_WaveformChoiceV5.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * DRONE SYNTH!!! 3 | * V1: 2 voices with modulation with waveform swapping 4 | * V2: changes waveform swapping function to increase options, also improves debounce 5 | * V3: adds toggles to turn oscillators ON/OFF 6 | * V4: bit shifts output to accomodate HIFI output mode. More changes to come to take full advantage of the HIFI goodness. 7 | * also changed debounce variables from int to unsigned long, and added a variable reset in code so they don't overflow. 8 | * 9 | *IT'S DONE!!!!!!!!!!!!!!! 10 | *This will be the cheapo version. Moving on to upgraded version using a teensy3.2 board. 11 | * 12 | *V5: Psych! Wasn't done. Version 5 increases the size of the wavetables from 512 to 1024. 13 | * It also swaps the handmade waveforms for newer, more interesting versions. 14 | */ 15 | 16 | 17 | //necessary Mozzi functions 18 | #include 19 | #include 20 | #include 21 | #include 22 | //wavetables (all same size for switching function) 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | 32 | // desired carrier frequency max and min, for AutoMap 33 | const int MIN_CARRIER_FREQ = 0; 34 | const int MAX_CARRIER_FREQ = 440; 35 | 36 | // desired intensity max and min, for AutoMap, note they're inverted for reverse dynamics 37 | const int MIN_INTENSITY = 700; 38 | const int MAX_INTENSITY = 1; 39 | 40 | // desired mod speed max and min, for AutoMap, note they're inverted for reverse dynamics 41 | const int MIN_MOD_SPEED = 10000; 42 | const int MAX_MOD_SPEED = 0; 43 | 44 | //automap functions to more quickly map ADC inputs to desired values 45 | AutoMap kMapCarrierFreq(0,1023,MIN_CARRIER_FREQ,MAX_CARRIER_FREQ); 46 | AutoMap kMapIntensity(0,1023,MIN_INTENSITY,MAX_INTENSITY); 47 | AutoMap kMapModSpeed(0,1023,MIN_MOD_SPEED,MAX_MOD_SPEED); 48 | 49 | //PINS! 50 | const byte CARRIER_PIN_1 = 0; 51 | const byte MODULATOR_PIN_1 = 1; 52 | const byte INTENSITY_PIN_1 = 2; 53 | const byte CARRIER_PIN_2 = 3; 54 | const byte MODULATOR_PIN_2 = 4; 55 | const byte INTENSITY_PIN_2 = 5; 56 | const byte WF_PIN_1A = 8; //aCarrier_1 57 | const byte WF_PIN_1B = 7; //aCarrier_1 58 | const byte WF_PIN_2A = 6; //aCarrier_2 59 | const byte WF_PIN_2B = 5; //aCarrier_2 60 | const byte WF_PIN_3A = 4; //aMod_1 61 | const byte WF_PIN_4A = 3; //aMod_2 62 | const byte ON_OFF_1 = 12; //voice 1 toggle 63 | const byte ON_OFF_2 = 11; //voice 2 toggle 64 | 65 | //Oscillator objects 66 | Oscil<1024, AUDIO_RATE> aCarrier_1; 67 | Oscil<1024, AUDIO_RATE> aModulator_1; 68 | Oscil<1024, CONTROL_RATE> kIntensityMod_1; 69 | Oscil<1024, AUDIO_RATE> aCarrier_2; 70 | Oscil<1024, AUDIO_RATE> aModulator_2; 71 | Oscil<1024, CONTROL_RATE> kIntensityMod_2; 72 | 73 | //for toggle 74 | boolean channel_1 = HIGH; //0 = OFF, 1 = ON 75 | boolean channel_2 = HIGH; //0 = OFF, 1 = ON 76 | int channel_1_debounce = 0; 77 | int channel_2_debounce = 0; 78 | 79 | // for controlling table swaps 80 | boolean D1; 81 | boolean D2; 82 | boolean D3; 83 | boolean D4; 84 | boolean D5; 85 | boolean D6; 86 | int wfc_1 = 0; 87 | int wfc_2 = 0; 88 | int wfc_3 = 0; 89 | int wfc_4 = 0; 90 | int wfc_5 = 0; 91 | int wfc_6 = 0; 92 | int count1 = 0; 93 | int count2 = 0; 94 | int count3 = 0; 95 | int count4 = 0; 96 | int count5 = 0; 97 | int count6 = 0; 98 | unsigned long debounce1 = 0; 99 | unsigned long debounce2 = 0; 100 | unsigned long debounce3 = 0; 101 | unsigned long debounce4 = 0; 102 | unsigned long debounce5 = 0; 103 | unsigned long debounce6 = 0; 104 | int debounce_time = 13; 105 | 106 | 107 | int mod_ratio = 5; // brightness (harmonics) 108 | long fm_intensity_1; // carries control info from updateControl to updateAudio 109 | long fm_intensity_2; 110 | 111 | 112 | float smoothness = 0.95f; 113 | Smooth aSmoothIntensity(smoothness); 114 | 115 | 116 | void setup() { 117 | 118 | startMozzi(); 119 | } 120 | 121 | 122 | void updateControl(){ 123 | //inc debounce values 124 | debounce1++; 125 | debounce2++; 126 | debounce3++; 127 | debounce4++; 128 | debounce5++; 129 | debounce6++; 130 | channel_1_debounce++; 131 | channel_2_debounce++; 132 | //read digital inputs to set wavetables 133 | D1 = digitalRead(WF_PIN_1A); //aCarrier_1 134 | D2 = digitalRead(WF_PIN_1B); //aCarrier_1 135 | D3 = digitalRead(WF_PIN_2A); //aCarrier_2 136 | D4 = digitalRead(WF_PIN_2B); //aCarrier_2 137 | D5 = digitalRead(WF_PIN_3A); //aMod_1 138 | D6 = digitalRead(WF_PIN_4A); //aMod_2 139 | //aCarrier_1 140 | if (D1 == HIGH and debounce1 > debounce_time) { 141 | count1++; 142 | wfc_1 = count1%7; 143 | debounce1 = 0; 144 | } 145 | switch (wfc_1) { 146 | case 0: 147 | aCarrier_1.setTable(SIN1024_DATA); 148 | break; 149 | case 1: 150 | aCarrier_1.setTable(SAW1024_DATA); 151 | break; 152 | case 2: 153 | aCarrier_1.setTable(SQUARE_NO_ALIAS1024_DATA); 154 | break; 155 | case 3: 156 | aCarrier_1.setTable(TRIANGLE1024_DATA); 157 | break; 158 | case 4: 159 | aCarrier_1.setTable(SAWSIN1024_DATA); 160 | break; 161 | case 5: 162 | aCarrier_1.setTable(SQUARESIN1024_DATA); 163 | break; 164 | case 6: 165 | aCarrier_1.setTable(WHATAMESS1024_DATA); 166 | break; 167 | } 168 | 169 | //aModulator_1 170 | if (D2 == HIGH and debounce2 > debounce_time) { 171 | count2++; 172 | wfc_2 = count2%7; 173 | debounce2 = 0; 174 | } 175 | switch (wfc_2) { 176 | case 0: 177 | aCarrier_1.setTable(SIN1024_DATA); 178 | break; 179 | case 1: 180 | aCarrier_1.setTable(SAW1024_DATA); 181 | break; 182 | case 2: 183 | aCarrier_1.setTable(SQUARE_NO_ALIAS1024_DATA); 184 | break; 185 | case 3: 186 | aCarrier_1.setTable(TRIANGLE1024_DATA); 187 | break; 188 | case 4: 189 | aCarrier_1.setTable(SAWSIN1024_DATA); 190 | break; 191 | case 5: 192 | aCarrier_1.setTable(SQUARESIN1024_DATA); 193 | break; 194 | case 6: 195 | aCarrier_1.setTable(WHATAMESS1024_DATA); 196 | break; 197 | } 198 | //kIntensityMod_1 199 | if (D3 == HIGH and debounce3 > debounce_time) { 200 | count3++; 201 | wfc_3 = count3 % 7; 202 | debounce3 = 0; 203 | } 204 | switch (wfc_3) { 205 | case 0: 206 | aCarrier_1.setTable(SIN1024_DATA); 207 | break; 208 | case 1: 209 | aCarrier_1.setTable(SAW1024_DATA); 210 | break; 211 | case 2: 212 | aCarrier_1.setTable(SQUARE_NO_ALIAS1024_DATA); 213 | break; 214 | case 3: 215 | aCarrier_1.setTable(TRIANGLE1024_DATA); 216 | break; 217 | case 4: 218 | aCarrier_1.setTable(SAWSIN1024_DATA); 219 | break; 220 | case 5: 221 | aCarrier_1.setTable(SQUARESIN1024_DATA); 222 | break; 223 | case 6: 224 | aCarrier_1.setTable(WHATAMESS1024_DATA); 225 | break; 226 | } 227 | //aCarrier_2 228 | if (D4 == HIGH and debounce4 > debounce_time) { 229 | count4++; 230 | wfc_4 = count4 % 7; 231 | debounce4 = 0; 232 | } 233 | switch (wfc_4) { 234 | case 0: 235 | aCarrier_1.setTable(SIN1024_DATA); 236 | break; 237 | case 1: 238 | aCarrier_1.setTable(SAW1024_DATA); 239 | break; 240 | case 2: 241 | aCarrier_1.setTable(SQUARE_NO_ALIAS1024_DATA); 242 | break; 243 | case 3: 244 | aCarrier_1.setTable(TRIANGLE1024_DATA); 245 | break; 246 | case 4: 247 | aCarrier_1.setTable(SAWSIN1024_DATA); 248 | break; 249 | case 5: 250 | aCarrier_1.setTable(SQUARESIN1024_DATA); 251 | break; 252 | case 6: 253 | aCarrier_1.setTable(WHATAMESS1024_DATA); 254 | break; 255 | } 256 | 257 | //aModulator_2 258 | if (D5 == HIGH and debounce5 > debounce_time) { 259 | count5++; 260 | wfc_5 = count5 % 7; 261 | debounce5 = 0; 262 | } 263 | switch (wfc_5) { 264 | case 0: 265 | aCarrier_1.setTable(SIN1024_DATA); 266 | break; 267 | case 1: 268 | aCarrier_1.setTable(SAW1024_DATA); 269 | break; 270 | case 2: 271 | aCarrier_1.setTable(SQUARE_NO_ALIAS1024_DATA); 272 | break; 273 | case 3: 274 | aCarrier_1.setTable(TRIANGLE1024_DATA); 275 | break; 276 | case 4: 277 | aCarrier_1.setTable(SAWSIN1024_DATA); 278 | break; 279 | case 5: 280 | aCarrier_1.setTable(SQUARESIN1024_DATA); 281 | break; 282 | case 6: 283 | aCarrier_1.setTable(WHATAMESS1024_DATA); 284 | break; 285 | } 286 | //kIntensity_2 287 | if (D6 == HIGH and debounce6 > debounce_time) { 288 | count6++; 289 | wfc_6 = count6 % 7; 290 | debounce6 = 0; 291 | } 292 | switch (wfc_6) { 293 | case 0: 294 | aCarrier_1.setTable(SIN1024_DATA); 295 | break; 296 | case 1: 297 | aCarrier_1.setTable(SAW1024_DATA); 298 | break; 299 | case 2: 300 | aCarrier_1.setTable(SQUARE_NO_ALIAS1024_DATA); 301 | break; 302 | case 3: 303 | aCarrier_1.setTable(TRIANGLE1024_DATA); 304 | break; 305 | case 4: 306 | aCarrier_1.setTable(SAWSIN1024_DATA); 307 | break; 308 | case 5: 309 | aCarrier_1.setTable(SQUARESIN1024_DATA); 310 | break; 311 | case 6: 312 | aCarrier_1.setTable(WHATAMESS1024_DATA); 313 | break; 314 | } 315 | 316 | if (digitalRead(ON_OFF_1) == HIGH and channel_1_debounce > debounce_time) { 317 | if (channel_1 == HIGH) {channel_1 = LOW;} 318 | else if (channel_1 == LOW) {channel_1 = HIGH;} 319 | channel_1_debounce = 0; 320 | } 321 | if (digitalRead(ON_OFF_2) == HIGH and channel_2_debounce > debounce_time) { 322 | if (channel_2 == HIGH) {channel_2 = LOW;} 323 | else if (channel_2 == LOW) {channel_2 = HIGH;} 324 | channel_2_debounce = 0; 325 | } 326 | 327 | int carrier_value_1, intensity_value_1, modulator_value_1; 328 | int carrier_value_2, intensity_value_2, modulator_value_2; 329 | if (channel_1 == LOW) { 330 | carrier_value_1 = 0; 331 | intensity_value_1 = 1024; 332 | modulator_value_1 = 1024; 333 | } 334 | else { 335 | carrier_value_1 = mozziAnalogRead(CARRIER_PIN_1); 336 | intensity_value_1= mozziAnalogRead(INTENSITY_PIN_1); 337 | modulator_value_1 = mozziAnalogRead(MODULATOR_PIN_1); 338 | } 339 | int carrier_freq_1 = kMapCarrierFreq(carrier_value_1); 340 | int mod_freq_1 = carrier_freq_1 * mod_ratio; 341 | aCarrier_1.setFreq(carrier_freq_1); 342 | aModulator_1.setFreq(mod_freq_1); 343 | int intensity_calibrated_1 = kMapIntensity(intensity_value_1); 344 | fm_intensity_1 = ((long)intensity_calibrated_1 * (kIntensityMod_1.next()+128))>>8; 345 | float mod_speed_1 = (float)kMapModSpeed(modulator_value_1)/1000; 346 | aCarrier_1.setFreq(carrier_freq_1); 347 | aModulator_1.setFreq(mod_freq_1); 348 | kIntensityMod_1.setFreq(mod_speed_1); 349 | 350 | 351 | if (channel_2 == LOW) { 352 | carrier_value_2 = 0; 353 | intensity_value_2 = 1024; 354 | modulator_value_2 = 1024; 355 | } 356 | else { 357 | carrier_value_2 = mozziAnalogRead(CARRIER_PIN_2); 358 | intensity_value_2= mozziAnalogRead(INTENSITY_PIN_2); 359 | modulator_value_2 = mozziAnalogRead(MODULATOR_PIN_2); 360 | } 361 | int carrier_freq_2 = kMapCarrierFreq(carrier_value_2); 362 | int mod_freq_2 = carrier_freq_2 * mod_ratio; 363 | aCarrier_2.setFreq(carrier_freq_2); 364 | aModulator_2.setFreq(mod_freq_2); 365 | int intensity_calibrated_2 = kMapIntensity(intensity_value_2); 366 | fm_intensity_2 = ((long)intensity_calibrated_2 * (kIntensityMod_2.next()+128))>>8; 367 | float mod_speed_2 = (float)kMapModSpeed(modulator_value_2)/1000; 368 | kIntensityMod_2.setFreq(mod_speed_2); 369 | 370 | /* 371 | * cycle debounce variables so they don't overflow -- 372 | * only needs to happen VERY infrequently. 373 | */ 374 | if (debounce1 > 4000000000) {debounce1 = debounce_time + 1;} 375 | if (debounce2 > 4000000000) {debounce2 = debounce_time + 1;} 376 | if (debounce3 > 4000000000) {debounce3 = debounce_time + 1;} 377 | if (debounce4 > 4000000000) {debounce4 = debounce_time + 1;} 378 | if (debounce5 > 4000000000) {debounce5 = debounce_time + 1;} 379 | if (debounce6 > 4000000000) {debounce6 = debounce_time + 1;} 380 | } 381 | 382 | 383 | int updateAudio(){ 384 | long modulation_1 = aSmoothIntensity.next(fm_intensity_1) * aModulator_1.next(); 385 | long modulation_2 = aSmoothIntensity.next(fm_intensity_2) * aModulator_2.next(); 386 | return (aCarrier_1.phMod(modulation_1) + aCarrier_2.phMod(modulation_2)) << 5; //V4 CHANGE FOR HIFI MODE 387 | } 388 | 389 | 390 | void loop() { 391 | audioHook(); 392 | } 393 | -------------------------------------------------------------------------------- /Drone Synth -- Test 1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danielsinderson/Arduino-Synthesizers/5d747810476d041a9f1231e7247c48f876460330/Drone Synth -- Test 1.mp3 -------------------------------------------------------------------------------- /Drone Synth -- Test 2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danielsinderson/Arduino-Synthesizers/5d747810476d041a9f1231e7247c48f876460330/Drone Synth -- Test 2.mp3 -------------------------------------------------------------------------------- /DroneSynth_WaveformChoiceV5/DroneSynth_WaveformChoiceV5.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * DRONE SYNTH!!! 3 | * V1: 2 voices with modulation with waveform swapping 4 | * V2: changes waveform swapping function to increase options, also improves debounce 5 | * V3: adds toggles to turn oscillators ON/OFF 6 | * V4: bit shifts output to accomodate HIFI output mode. More changes to come to take full advantage of the HIFI goodness. 7 | * also changed debounce variables from int to unsigned long, and added a variable reset in code so they don't overflow. 8 | * 9 | *IT'S DONE!!!!!!!!!!!!!!! 10 | *This will be the cheapo version. Moving on to upgraded version using a teensy3.2 board. 11 | * 12 | *V5: Psych! Wasn't done. Version 5 increases the size of the wavetables from 512 to 1024. 13 | * It also swaps the handmade waveforms for newer, more interesting versions. 14 | */ 15 | 16 | 17 | //necessary Mozzi functions 18 | #include 19 | #include 20 | #include 21 | #include 22 | //wavetables (all same size for switching function) 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | 32 | // desired carrier frequency max and min, for AutoMap 33 | const int MIN_CARRIER_FREQ = 0; 34 | const int MAX_CARRIER_FREQ = 440; 35 | 36 | // desired intensity max and min, for AutoMap, note they're inverted for reverse dynamics 37 | const int MIN_INTENSITY = 700; 38 | const int MAX_INTENSITY = 1; 39 | 40 | // desired mod speed max and min, for AutoMap, note they're inverted for reverse dynamics 41 | const int MIN_MOD_SPEED = 10000; 42 | const int MAX_MOD_SPEED = 0; 43 | 44 | //automap functions to more quickly map ADC inputs to desired values 45 | AutoMap kMapCarrierFreq(0,1023,MIN_CARRIER_FREQ,MAX_CARRIER_FREQ); 46 | AutoMap kMapIntensity(0,1023,MIN_INTENSITY,MAX_INTENSITY); 47 | AutoMap kMapModSpeed(0,1023,MIN_MOD_SPEED,MAX_MOD_SPEED); 48 | 49 | //PINS! 50 | const byte CARRIER_PIN_1 = 0; 51 | const byte MODULATOR_PIN_1 = 1; 52 | const byte INTENSITY_PIN_1 = 2; 53 | const byte CARRIER_PIN_2 = 3; 54 | const byte MODULATOR_PIN_2 = 4; 55 | const byte INTENSITY_PIN_2 = 5; 56 | const byte WF_PIN_1A = 8; //aCarrier_1 57 | const byte WF_PIN_1B = 7; //aCarrier_1 58 | const byte WF_PIN_2A = 6; //aCarrier_2 59 | const byte WF_PIN_2B = 5; //aCarrier_2 60 | const byte WF_PIN_3A = 4; //aMod_1 61 | const byte WF_PIN_4A = 3; //aMod_2 62 | const byte ON_OFF_1 = 12; //voice 1 toggle 63 | const byte ON_OFF_2 = 11; //voice 2 toggle 64 | 65 | //Oscillator objects 66 | Oscil<1024, AUDIO_RATE> aCarrier_1; 67 | Oscil<1024, AUDIO_RATE> aModulator_1; 68 | Oscil<1024, CONTROL_RATE> kIntensityMod_1; 69 | Oscil<1024, AUDIO_RATE> aCarrier_2; 70 | Oscil<1024, AUDIO_RATE> aModulator_2; 71 | Oscil<1024, CONTROL_RATE> kIntensityMod_2; 72 | 73 | //for toggle 74 | boolean channel_1 = HIGH; //0 = OFF, 1 = ON 75 | boolean channel_2 = HIGH; //0 = OFF, 1 = ON 76 | int channel_1_debounce = 0; 77 | int channel_2_debounce = 0; 78 | 79 | // for controlling table swaps 80 | boolean D1; 81 | boolean D2; 82 | boolean D3; 83 | boolean D4; 84 | boolean D5; 85 | boolean D6; 86 | int wfc_1 = 0; 87 | int wfc_2 = 0; 88 | int wfc_3 = 0; 89 | int wfc_4 = 0; 90 | int wfc_5 = 0; 91 | int wfc_6 = 0; 92 | int count1 = 0; 93 | int count2 = 0; 94 | int count3 = 0; 95 | int count4 = 0; 96 | int count5 = 0; 97 | int count6 = 0; 98 | unsigned long debounce1 = 0; 99 | unsigned long debounce2 = 0; 100 | unsigned long debounce3 = 0; 101 | unsigned long debounce4 = 0; 102 | unsigned long debounce5 = 0; 103 | unsigned long debounce6 = 0; 104 | int debounce_time = 13; 105 | 106 | 107 | int mod_ratio = 5; // brightness (harmonics) 108 | long fm_intensity_1; // carries control info from updateControl to updateAudio 109 | long fm_intensity_2; 110 | 111 | 112 | float smoothness = 0.95f; 113 | Smooth aSmoothIntensity(smoothness); 114 | 115 | 116 | void setup() { 117 | 118 | startMozzi(); 119 | } 120 | 121 | 122 | void updateControl(){ 123 | //inc debounce values 124 | debounce1++; 125 | debounce2++; 126 | debounce3++; 127 | debounce4++; 128 | debounce5++; 129 | debounce6++; 130 | channel_1_debounce++; 131 | channel_2_debounce++; 132 | //read digital inputs to set wavetables 133 | D1 = digitalRead(WF_PIN_1A); //aCarrier_1 134 | D2 = digitalRead(WF_PIN_1B); //aCarrier_1 135 | D3 = digitalRead(WF_PIN_2A); //aCarrier_2 136 | D4 = digitalRead(WF_PIN_2B); //aCarrier_2 137 | D5 = digitalRead(WF_PIN_3A); //aMod_1 138 | D6 = digitalRead(WF_PIN_4A); //aMod_2 139 | //aCarrier_1 140 | if (D1 == HIGH and debounce1 > debounce_time) { 141 | count1++; 142 | wfc_1 = count1%7; 143 | debounce1 = 0; 144 | } 145 | switch (wfc_1) { 146 | case 0: 147 | aCarrier_1.setTable(SIN1024_DATA); 148 | break; 149 | case 1: 150 | aCarrier_1.setTable(SAW1024_DATA); 151 | break; 152 | case 2: 153 | aCarrier_1.setTable(SQUARE_NO_ALIAS1024_DATA); 154 | break; 155 | case 3: 156 | aCarrier_1.setTable(TRIANGLE1024_DATA); 157 | break; 158 | case 4: 159 | aCarrier_1.setTable(SAWSIN1024_DATA); 160 | break; 161 | case 5: 162 | aCarrier_1.setTable(SQUARESIN1024_DATA); 163 | break; 164 | case 6: 165 | aCarrier_1.setTable(WHATAMESS1024_DATA); 166 | break; 167 | } 168 | 169 | //aModulator_1 170 | if (D2 == HIGH and debounce2 > debounce_time) { 171 | count2++; 172 | wfc_2 = count2%7; 173 | debounce2 = 0; 174 | } 175 | switch (wfc_2) { 176 | case 0: 177 | aCarrier_1.setTable(SIN1024_DATA); 178 | break; 179 | case 1: 180 | aCarrier_1.setTable(SAW1024_DATA); 181 | break; 182 | case 2: 183 | aCarrier_1.setTable(SQUARE_NO_ALIAS1024_DATA); 184 | break; 185 | case 3: 186 | aCarrier_1.setTable(TRIANGLE1024_DATA); 187 | break; 188 | case 4: 189 | aCarrier_1.setTable(SAWSIN1024_DATA); 190 | break; 191 | case 5: 192 | aCarrier_1.setTable(SQUARESIN1024_DATA); 193 | break; 194 | case 6: 195 | aCarrier_1.setTable(WHATAMESS1024_DATA); 196 | break; 197 | } 198 | //kIntensityMod_1 199 | if (D3 == HIGH and debounce3 > debounce_time) { 200 | count3++; 201 | wfc_3 = count3 % 7; 202 | debounce3 = 0; 203 | } 204 | switch (wfc_3) { 205 | case 0: 206 | aCarrier_1.setTable(SIN1024_DATA); 207 | break; 208 | case 1: 209 | aCarrier_1.setTable(SAW1024_DATA); 210 | break; 211 | case 2: 212 | aCarrier_1.setTable(SQUARE_NO_ALIAS1024_DATA); 213 | break; 214 | case 3: 215 | aCarrier_1.setTable(TRIANGLE1024_DATA); 216 | break; 217 | case 4: 218 | aCarrier_1.setTable(SAWSIN1024_DATA); 219 | break; 220 | case 5: 221 | aCarrier_1.setTable(SQUARESIN1024_DATA); 222 | break; 223 | case 6: 224 | aCarrier_1.setTable(WHATAMESS1024_DATA); 225 | break; 226 | } 227 | //aCarrier_2 228 | if (D4 == HIGH and debounce4 > debounce_time) { 229 | count4++; 230 | wfc_4 = count4 % 7; 231 | debounce4 = 0; 232 | } 233 | switch (wfc_4) { 234 | case 0: 235 | aCarrier_1.setTable(SIN1024_DATA); 236 | break; 237 | case 1: 238 | aCarrier_1.setTable(SAW1024_DATA); 239 | break; 240 | case 2: 241 | aCarrier_1.setTable(SQUARE_NO_ALIAS1024_DATA); 242 | break; 243 | case 3: 244 | aCarrier_1.setTable(TRIANGLE1024_DATA); 245 | break; 246 | case 4: 247 | aCarrier_1.setTable(SAWSIN1024_DATA); 248 | break; 249 | case 5: 250 | aCarrier_1.setTable(SQUARESIN1024_DATA); 251 | break; 252 | case 6: 253 | aCarrier_1.setTable(WHATAMESS1024_DATA); 254 | break; 255 | } 256 | 257 | //aModulator_2 258 | if (D5 == HIGH and debounce5 > debounce_time) { 259 | count5++; 260 | wfc_5 = count5 % 7; 261 | debounce5 = 0; 262 | } 263 | switch (wfc_5) { 264 | case 0: 265 | aCarrier_1.setTable(SIN1024_DATA); 266 | break; 267 | case 1: 268 | aCarrier_1.setTable(SAW1024_DATA); 269 | break; 270 | case 2: 271 | aCarrier_1.setTable(SQUARE_NO_ALIAS1024_DATA); 272 | break; 273 | case 3: 274 | aCarrier_1.setTable(TRIANGLE1024_DATA); 275 | break; 276 | case 4: 277 | aCarrier_1.setTable(SAWSIN1024_DATA); 278 | break; 279 | case 5: 280 | aCarrier_1.setTable(SQUARESIN1024_DATA); 281 | break; 282 | case 6: 283 | aCarrier_1.setTable(WHATAMESS1024_DATA); 284 | break; 285 | } 286 | //kIntensity_2 287 | if (D6 == HIGH and debounce6 > debounce_time) { 288 | count6++; 289 | wfc_6 = count6 % 7; 290 | debounce6 = 0; 291 | } 292 | switch (wfc_6) { 293 | case 0: 294 | aCarrier_1.setTable(SIN1024_DATA); 295 | break; 296 | case 1: 297 | aCarrier_1.setTable(SAW1024_DATA); 298 | break; 299 | case 2: 300 | aCarrier_1.setTable(SQUARE_NO_ALIAS1024_DATA); 301 | break; 302 | case 3: 303 | aCarrier_1.setTable(TRIANGLE1024_DATA); 304 | break; 305 | case 4: 306 | aCarrier_1.setTable(SAWSIN1024_DATA); 307 | break; 308 | case 5: 309 | aCarrier_1.setTable(SQUARESIN1024_DATA); 310 | break; 311 | case 6: 312 | aCarrier_1.setTable(WHATAMESS1024_DATA); 313 | break; 314 | } 315 | 316 | if (digitalRead(ON_OFF_1) == HIGH and channel_1_debounce > debounce_time) { 317 | if (channel_1 == HIGH) {channel_1 = LOW;} 318 | else if (channel_1 == LOW) {channel_1 = HIGH;} 319 | channel_1_debounce = 0; 320 | } 321 | if (digitalRead(ON_OFF_2) == HIGH and channel_2_debounce > debounce_time) { 322 | if (channel_2 == HIGH) {channel_2 = LOW;} 323 | else if (channel_2 == LOW) {channel_2 = HIGH;} 324 | channel_2_debounce = 0; 325 | } 326 | 327 | int carrier_value_1, intensity_value_1, modulator_value_1; 328 | int carrier_value_2, intensity_value_2, modulator_value_2; 329 | if (channel_1 == LOW) { 330 | carrier_value_1 = 0; 331 | intensity_value_1 = 1024; 332 | modulator_value_1 = 1024; 333 | } 334 | else { 335 | carrier_value_1 = mozziAnalogRead(CARRIER_PIN_1); 336 | intensity_value_1= mozziAnalogRead(INTENSITY_PIN_1); 337 | modulator_value_1 = mozziAnalogRead(MODULATOR_PIN_1); 338 | } 339 | int carrier_freq_1 = kMapCarrierFreq(carrier_value_1); 340 | int mod_freq_1 = carrier_freq_1 * mod_ratio; 341 | aCarrier_1.setFreq(carrier_freq_1); 342 | aModulator_1.setFreq(mod_freq_1); 343 | int intensity_calibrated_1 = kMapIntensity(intensity_value_1); 344 | fm_intensity_1 = ((long)intensity_calibrated_1 * (kIntensityMod_1.next()+128))>>8; 345 | float mod_speed_1 = (float)kMapModSpeed(modulator_value_1)/1000; 346 | aCarrier_1.setFreq(carrier_freq_1); 347 | aModulator_1.setFreq(mod_freq_1); 348 | kIntensityMod_1.setFreq(mod_speed_1); 349 | 350 | 351 | if (channel_2 == LOW) { 352 | carrier_value_2 = 0; 353 | intensity_value_2 = 1024; 354 | modulator_value_2 = 1024; 355 | } 356 | else { 357 | carrier_value_2 = mozziAnalogRead(CARRIER_PIN_2); 358 | intensity_value_2= mozziAnalogRead(INTENSITY_PIN_2); 359 | modulator_value_2 = mozziAnalogRead(MODULATOR_PIN_2); 360 | } 361 | int carrier_freq_2 = kMapCarrierFreq(carrier_value_2); 362 | int mod_freq_2 = carrier_freq_2 * mod_ratio; 363 | aCarrier_2.setFreq(carrier_freq_2); 364 | aModulator_2.setFreq(mod_freq_2); 365 | int intensity_calibrated_2 = kMapIntensity(intensity_value_2); 366 | fm_intensity_2 = ((long)intensity_calibrated_2 * (kIntensityMod_2.next()+128))>>8; 367 | float mod_speed_2 = (float)kMapModSpeed(modulator_value_2)/1000; 368 | kIntensityMod_2.setFreq(mod_speed_2); 369 | 370 | /* 371 | * cycle debounce variables so they don't overflow -- 372 | * only needs to happen VERY infrequently. 373 | */ 374 | if (debounce1 > 4000000000) {debounce1 = debounce_time + 1;} 375 | if (debounce2 > 4000000000) {debounce2 = debounce_time + 1;} 376 | if (debounce3 > 4000000000) {debounce3 = debounce_time + 1;} 377 | if (debounce4 > 4000000000) {debounce4 = debounce_time + 1;} 378 | if (debounce5 > 4000000000) {debounce5 = debounce_time + 1;} 379 | if (debounce6 > 4000000000) {debounce6 = debounce_time + 1;} 380 | } 381 | 382 | 383 | int updateAudio(){ 384 | long modulation_1 = aSmoothIntensity.next(fm_intensity_1) * aModulator_1.next(); 385 | long modulation_2 = aSmoothIntensity.next(fm_intensity_2) * aModulator_2.next(); 386 | return (aCarrier_1.phMod(modulation_1) + aCarrier_2.phMod(modulation_2)) << 5; //V4 CHANGE FOR HIFI MODE 387 | } 388 | 389 | 390 | void loop() { 391 | audioHook(); 392 | } 393 | -------------------------------------------------------------------------------- /JohnSynth_V6/JohnSynth_V6.ino: -------------------------------------------------------------------------------- 1 | /* CHANGES 2 | - adding fine-grained control over both synth blocks: all frequencies and all waveform selects have their own control knob 3 | - this requires adding MUX control lines and changing how frequencies and waveforms are set 4 | - adding mode control over each synth block: requires changes to I/O and changes to updateAudio 5 | - shorteniing wavetable sizes and adding more of them now that each oscillator's waveform can be easily and finely controlled 6 | 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | //#include 22 | //#include 23 | //#include 24 | 25 | 26 | 27 | // VARIABLES 28 | AutoMap kMapCarrierFreq(0,1023,20,440); 29 | AutoMap kMapIntensity(0,1023,700,1); 30 | AutoMap kMapModSpeed(0,1023,10000,0); 31 | AutoMap kMapEnvelopeTimes(0, 1023, 20, 500); 32 | 33 | Oscil <256, AUDIO_RATE> carrier; 34 | Oscil <256, AUDIO_RATE> modulator; 35 | Oscil <256, CONTROL_RATE> modDepth; 36 | 37 | ADSR envelope; 38 | 39 | int attack = 20; 40 | int decay = 20; 41 | bool mode = 0; 42 | bool noteTrigger = 0; 43 | 44 | int freqs[3]; 45 | byte wfs[3]; 46 | 47 | int mod_ratio = 5; // brightness (harmonics) 48 | long fm_intensity; // carries control info from updateControl to updateAudio 49 | 50 | float smoothness = 0.95f; 51 | Smooth aSmoothIntensity(smoothness); 52 | 53 | 54 | // FUNCTIONS 55 | void setWavetables() { 56 | if (wfs[0]==0) {carrier.setTable(SIN256_DATA);} 57 | else if (wfs[0]==1) {carrier.setTable(HALFSIN256_DATA);} 58 | else if (wfs[0]==2) {carrier.setTable(SAW256_DATA);} 59 | else if (wfs[0]==3) {carrier.setTable(WAVESHAPE1_SOFTCLIP_DATA);} 60 | 61 | if (wfs[1]==0) {modulator.setTable(SIN256_DATA);} 62 | else if (wfs[1]==1) {modulator.setTable(HALFSIN256_DATA);} 63 | else if (wfs[1]==2) {modulator.setTable(SAW256_DATA);} 64 | else if (wfs[1]==3) {modulator.setTable(WAVESHAPE1_SOFTCLIP_DATA);} 65 | 66 | if (wfs[2]==0) {modDepth.setTable(SIN256_DATA);} 67 | else if (wfs[2]==1) {modDepth.setTable(HALFSIN256_DATA);} 68 | else if (wfs[2]==2) {modDepth.setTable(SAW256_DATA);} 69 | else if (wfs[2]==3) {modDepth.setTable(WAVESHAPE1_SOFTCLIP_DATA);} 70 | } 71 | 72 | void readPins() { 73 | freqs[0] = mozziAnalogRead(A0); 74 | freqs[1] = mozziAnalogRead(A1); 75 | freqs[2] = mozziAnalogRead(A2); 76 | 77 | wfs[0] = mozziAnalogRead(A3) >> 8; 78 | wfs[1] = mozziAnalogRead(A4) >> 8; 79 | wfs[2] = mozziAnalogRead(A5) >> 8; 80 | 81 | mod_ratio = (mozziAnalogRead(A6) >> 7) + 1; 82 | //attack = mozziAnalogRead(A6); 83 | decay = mozziAnalogRead(A7); 84 | 85 | mode = digitalRead(2); 86 | noteTrigger = digitalRead(3) or not digitalRead(4); 87 | } 88 | 89 | void setFrequencies() { 90 | int carrier_freq = kMapCarrierFreq(freqs[0]); 91 | int mod_freq = carrier_freq * mod_ratio; 92 | 93 | int intensity_calibrated = kMapIntensity(freqs[2]); 94 | fm_intensity = ((long)intensity_calibrated * (modDepth.next()+128))>>8; 95 | 96 | float mod_speed = (float)kMapModSpeed(freqs[1])/1000; 97 | 98 | carrier.setFreq(carrier_freq); 99 | modulator.setFreq(mod_freq); 100 | modDepth.setFreq(mod_speed); 101 | } 102 | 103 | void setAD() { 104 | //envelope.setAttackTime(kMapEnvelopeTimes(attack)); 105 | envelope.setReleaseTime(kMapEnvelopeTimes(decay)); 106 | } 107 | 108 | 109 | 110 | // ################### THE GOODS! ##################### 111 | 112 | void setup() { 113 | pinMode(4, INPUT_PULLUP); 114 | pinMode(2, INPUT); 115 | startMozzi(); 116 | envelope.setLevels(255, 250, 250, 0); 117 | envelope.setTimes(20, 20, 5000, 20); 118 | } 119 | 120 | void updateControl() { 121 | readPins(); 122 | setWavetables(); 123 | setFrequencies(); 124 | setAD(); 125 | 126 | if (noteTrigger == 0) { envelope.noteOn(); } 127 | else { envelope.noteOff(); } 128 | } 129 | 130 | int updateAudio() { 131 | int audio; 132 | 133 | if (mode == 0) { 134 | long mod = aSmoothIntensity.next(fm_intensity) * modulator.next(); 135 | audio = carrier.phMod(mod); 136 | } 137 | else { 138 | envelope.update(); 139 | long mod = aSmoothIntensity.next(fm_intensity) * modulator.next(); 140 | audio = ((carrier.phMod(mod) * envelope.next()) >> 8); 141 | } 142 | return audio << 6; // 14-bit number for HI-FI mode 143 | } 144 | 145 | void loop() { 146 | audioHook(); 147 | } 148 | -------------------------------------------------------------------------------- /LFO/LFO.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Brief Sketch for an 12-channel Relative Tempo LFO 3 | */ 4 | 5 | const int pin = 0; 6 | byte output, output2; 7 | int period, period2, pin_value; 8 | long t_zero, t_one, delta_t, t_off_zero, t_off_one; 9 | 10 | 11 | void setup() { 12 | for (int i=0;i<13;i++) { 13 | pinMode(i, OUTPUT); 14 | } 15 | t_zero = millis(); 16 | t_off_zero = millis(); 17 | output = 0; 18 | output2 = 0; 19 | } 20 | 21 | void loop() { 22 | pin_value = analogRead(pin); 23 | period = pin_value >> 1; 24 | period2 = (3 * period) / 2; //2 * ((3 * period) / 4)), times 3/4 to map to off beat and times 8 to slow down since PORTB is only 5 bits instead of 8 25 | t_one = millis(); 26 | delta_t = t_one - t_zero; 27 | if (delta_t >= period) { 28 | if (output == 255) {output = 0;} 29 | else {output++;} 30 | PORTD = output; 31 | t_zero = t_one; 32 | } 33 | t_off_one = millis(); 34 | delta_t = t_off_one - t_off_zero; 35 | if (delta_t >= period2) { 36 | if (output2 == 64) {output2 = 0;} 37 | else {output2++;} 38 | PORTB = output2; 39 | t_off_zero = t_off_one; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /MODMIX_BASS_SYNTH/MODMIX_BASS_SYNTH.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * ModMix Bass Synth 3 | */ 4 | 5 | 6 | /*PINS!*/ 7 | const byte FREQ_PIN = 14; 8 | const byte AMP_PIN = 15; 9 | const byte WF_PIN = 16; 10 | const byte CHANNEL_PIN = 17; 11 | const byte TOGGLE_PIN = 18; 12 | const byte BITCRUSH_TOGGLE_PIN = 19; 13 | const byte BITCRUSH_VALUE_PIN = 20; 14 | const byte REVERB_TOGGLE_PIN = 21; 15 | const byte REVERB_VALUE_PIN = 22; 16 | const byte OUTPUT_FREQ_PIN = 23; 17 | 18 | 19 | const byte MUX_SELECT_1 = 2; 20 | const byte MUX_SELECT_2 = 3; 21 | const byte MUX_SELECT_3 = 4; 22 | 23 | const byte OUTPUT_PIN = 5; 24 | 25 | 26 | /*GLOBAL VARIABLES!*/ 27 | #define PI 3.14159 28 | 29 | bool update_settings_flag = 0; 30 | 31 | 32 | bool operator_toggles[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 33 | uint32_t operator_waveform[8]; 34 | uint32_t operator_frequency[8]; 35 | uint32_t operator_amplitude[8]; 36 | uint32_t operator_channel[8]; 37 | 38 | #define wavetable_size 256 39 | uint8_t wavetable_size_log = 8; 40 | uint16_t wavetable[wavetable_size]; 41 | 42 | bool bitcrush_toggle = 0; 43 | uint32_t bitcrush_value = 0; 44 | 45 | bool reverb_toggle = 0; 46 | uint32_t reverb_value = 0; 47 | 48 | uint32_t output_frequency; 49 | uint32_t playback_counter = 0; 50 | uint32_t playback_rate = 20000; 51 | uint32_t playback_index = 0; 52 | 53 | uint32_t mod_mix_value = 0; 54 | uint32_t output_value = 0; 55 | 56 | float frequency_table[64] = {23.12, 24.50, 25.96, 27.50, 29.14, 30.87, 57 | 32.70, 34.65, 36.71, 38.89, 41.20, 43.65, 46.25, 49.00, 51.91, 55.00, 58.27, 61.74, 58 | 65.41, 69.30, 73.42, 77.78, 82.41, 87.31, 92.50, 98.00, 103.8, 110.0, 116.5, 123.5, 59 | 130.8, 138.6, 146.8, 155.6, 164.8, 174.6, 185.0, 196.0, 207.7, 220.0, 233.1, 246.9, 60 | 261.6, 277.2, 293.7, 311.1, 329.6, 349.2, 370.0, 392.0, 415.3, 440.0, 466.2, 493.9, 61 | 523.3, 554.4, 587.3, 622.3, 659.3, 698.5, 740.0, 784.0, 830.6, 880.0}; 62 | uint32_t playback_rates[128]; 63 | 64 | 65 | 66 | /*TIMERS!*/ 67 | IntervalTimer settingsUpdate; 68 | IntervalTimer audioUpdate; 69 | 70 | void set_update_flag() { 71 | update_settings_flag = 1; 72 | } 73 | 74 | void inc_playback_index() { 75 | playback_counter++; 76 | } 77 | 78 | 79 | /*FUNCTIONS!*/ 80 | uint8_t sine(uint32_t wavetable_position, uint32_t frequency, uint32_t amplitude){ 81 | uint32_t t = 2*frequency*wavetable_position; 82 | uint32_t x = (PI*t); 83 | x = x >> wavetable_size_log; 84 | uint32_t value = (sin(x)+1) * 255; 85 | uint8_t result = value >> amplitude; 86 | return result; 87 | } 88 | 89 | uint8_t triangle(uint32_t wavetable_position, uint32_t frequency, uint32_t amplitude){ 90 | uint8_t result; 91 | uint32_t slope = (256 / wavetable_size) / frequency; 92 | uint32_t waveform_position = (wavetable_position * frequency) % wavetable_size; 93 | if (waveform_position < (wavetable_size >> 1)){ 94 | result = slope * waveform_position; 95 | } 96 | else{ 97 | result = (1/slope) * waveform_position; 98 | } 99 | result = result >> amplitude; 100 | return result; 101 | } 102 | 103 | uint8_t square(uint32_t wavetable_position, uint32_t frequency, uint32_t amplitude){ 104 | uint8_t result; 105 | double x = (wavetable_position*frequency) % wavetable_size; 106 | if (x < (wavetable_size >> 1)) {result = 0;} 107 | else {result = 255;} 108 | result = result >> amplitude; 109 | return result; 110 | } 111 | 112 | uint8_t saw(uint32_t wavetable_position, uint32_t frequency, uint32_t amplitude){ 113 | uint8_t result; 114 | uint32_t slope = (256 / wavetable_size) / frequency; 115 | uint32_t waveform_position = (wavetable_position * frequency) % wavetable_size; 116 | result = slope * waveform_position; 117 | result = result >> amplitude; 118 | return result; 119 | } 120 | 121 | uint8_t get_waveform_value(uint32_t waveform, uint32_t wavetable_position, uint32_t frequency, uint32_t amplitude){ 122 | uint8_t result; 123 | if (waveform == 0) { result = sine(wavetable_position, frequency, amplitude); } 124 | else if (waveform == 1) { result = triangle(wavetable_position, frequency, amplitude); } 125 | else if (waveform == 2) { result = square(wavetable_position, frequency, amplitude); } 126 | else if (waveform == 3) { result = saw(wavetable_position, frequency, amplitude); } 127 | return result; 128 | } 129 | 130 | uint32_t mod_mix_block(uint32_t index){ //returns 16-bit value 131 | //block to iterate through operators and sum up values for each channel at the current playback index (which is the position in the waveform) 132 | uint32_t channel_waveforms[8]; 133 | for (int i=0; i<8; i++){ 134 | if (operator_toggles[i] == 1) { 135 | bool bitshift; 136 | if (channel_waveforms[operator_channel[i]] != 0) {bitshift = 1;} 137 | channel_waveforms[operator_channel[i]] += get_waveform_value(operator_waveform[i], playback_index, operator_frequency[i], operator_amplitude[i]);; 138 | if (bitshift == 1) { channel_waveforms[operator_channel[i]] = channel_waveforms[operator_channel[i]] >> 1; } 139 | } 140 | } 141 | 142 | //block to iterate through channel waveforms and multiply them together for final audio output value, skipping channels with no operators on them (value 0) 143 | uint64_t value = 1; 144 | int bitshifts = -12; 145 | for (int i=0; i<8; i++){ 146 | if (channel_waveforms[i] != 0) { 147 | value *= channel_waveforms[i]; 148 | bitshifts += 8; 149 | } 150 | } 151 | return value >> bitshifts; 152 | } 153 | 154 | uint32_t fx_block(uint32_t input_value){ 155 | uint32_t result = input_value; 156 | if (bitcrush_toggle == 1) { 157 | result = result >> bitcrush_value; 158 | result = result << bitcrush_value; 159 | } 160 | if (reverb_toggle == 1){ 161 | uint32_t samples_per_millisecond = 2.048 * output_frequency; 162 | uint32_t samples_of_delay = (reverb_value * samples_per_millisecond) % wavetable_size; 163 | uint32_t samples_to_add = wavetable_size - samples_of_delay; 164 | uint32_t reverb_index = (playback_index + samples_to_add) % wavetable_size; 165 | uint32_t wet_signal = mod_mix_block(reverb_index); 166 | result += wet_signal; 167 | result = result >> 1; 168 | } 169 | return result; 170 | } 171 | 172 | void set_mux_select_lines(char line_number){ //set MUX select lines based on desired line number (0 to 7) 173 | bool select3 = line_number / 4; //returns 1 if line_number is >=4, setting the MSB of the select lines 174 | bool select2 = (line_number-4*select3) / 2; //returns 1 if line_number is 2, 3, 6, or 7 175 | bool select1 = line_number % 2; //returns 1 if line number is odd 176 | digitalWrite(MUX_SELECT_3, select3); 177 | digitalWrite(MUX_SELECT_2, select2); 178 | digitalWrite(MUX_SELECT_1, select1); 179 | } 180 | 181 | void update_operator_settings(void){ //set MUX select lines and read operator settings from associated pin for each of the 8 operators 182 | for (int i=0; i<8; i++){ 183 | set_mux_select_lines(i); 184 | operator_toggles[i] = digitalRead(TOGGLE_PIN); 185 | operator_waveform[i] = analogRead(WF_PIN) >> 7; //values between 0 and 7 186 | operator_frequency[i] = analogRead(FREQ_PIN) >> 5; //values between 0 and 31 187 | operator_amplitude[i] = analogRead(AMP_PIN) >> 7; //values between 0 and 7 188 | operator_channel[i] = analogRead(CHANNEL_PIN) >> 7; //values between 0 and 7 189 | } 190 | } 191 | 192 | void update_fx_and_playback_settings(void){ 193 | bitcrush_toggle = digitalRead(BITCRUSH_TOGGLE_PIN); 194 | reverb_toggle = digitalRead(REVERB_TOGGLE_PIN); 195 | bitcrush_value = analogRead(BITCRUSH_VALUE_PIN) >> 7; //values between 0 and 7 196 | reverb_value = analogRead(REVERB_VALUE_PIN) >> 4; //values between 0 and 63 197 | output_frequency = analogRead(OUTPUT_FREQ_PIN) >> 3; //values between 0 and 127 198 | playback_rate = playback_rates[output_frequency]; 199 | } 200 | 201 | void update_user_settings(void){ 202 | update_operator_settings(); 203 | update_fx_and_playback_settings(); 204 | } 205 | 206 | 207 | void setup() { 208 | for (int i=0;i<63;i++){ 209 | float freq = frequency_table[i]; 210 | playback_rates[2*i] = 976563 / (wavetable_size * freq); 211 | freq = (frequency_table[i] + frequency_table[i+1]) / 2; 212 | playback_rates[(2*i)+1] = 976563 / (wavetable_size * freq); 213 | } 214 | playback_rates[126] = 976563 / (wavetable_size * frequency_table[63]); 215 | playback_rates[127] = 976563 / (wavetable_size * frequency_table[63]); 216 | 217 | update_user_settings(); 218 | 219 | settingsUpdate.begin(set_update_flag, 5000); 220 | audioUpdate.begin(inc_playback_index, 9.6); 221 | } 222 | 223 | void loop() { 224 | if (update_settings_flag == 1){ 225 | update_user_settings(); 226 | update_settings_flag = 0; 227 | } 228 | if (playback_counter >= playback_rate){ 229 | playback_index++; 230 | if (playback_index == wavetable_size) { playback_index = 0; } 231 | playback_counter = 0; 232 | mod_mix_value = mod_mix_block(playback_index); 233 | output_value = fx_block(mod_mix_value); 234 | } 235 | digitalWrite(OUTPUT_PIN, output_value); 236 | } 237 | -------------------------------------------------------------------------------- /MOZZI_BASS_SYNTH_V3/MOZZI_BASS_SYNTH_V3.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * BASS SYNTH: 3 | * Duophony bass synth with ADSR envelopes for each voice, waveform choices, and bitwise distortion 4 | * still needs: 5 | * - frequency tables 6 | * - frequency mapping 7 | * - updateAudio stuff 8 | * - waveform setting and waveform includes 9 | */ 10 | 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | 23 | 24 | //PINS 25 | const byte ANALOG_PINS[8] = {A0, A1, A2, A3, A4, A5, A6, A7}; 26 | const byte TRIGGER_PINS[2] = {2, 3}; 27 | const byte MODE_PIN = 4; 28 | 29 | 30 | //GLOBAL VARIABLES 31 | bool triggers[2] = {0, 0}; 32 | byte waveform_choice = 0; 33 | byte scale = 0; 34 | Oscil <2048, AUDIO_RATE> oscils[2]; 35 | ADSR envelopes[2]; 36 | 37 | float note_freq[41] = {20.60, 21.83, 23.12, 24.50, 25.96, 27.50, 29.14, 30.87, 38 | 32.70, 34.65, 36.71, 38.89, 41.20, 43.65, 46.25, 49.00, 39 | 51.91, 55.00, 58.27, 61.74, 69.30, 73.42, 77.78, 82.41, 40 | 87.31, 92.50, 98.00, 103.83, 110.00, 116.54, 123.47, 130.81, 41 | 138.59, 146.83, 155.56, 164.81, 174.61, 185.00, 196.00, 207.65, 220.00}; 42 | 43 | //FUNCTION DECLARATIONS 44 | void read_trigger(byte n) { 45 | if (digitalRead(TRIGGER_PINS[n]) == HIGH and triggers[n] == LOW) { 46 | envelopes[n].noteOn(); 47 | triggers[n] = HIGH; 48 | } 49 | else if (digitalRead(TRIGGER_PINS[n]) == LOW and triggers[n] == HIGH) { 50 | envelopes[n].noteOff(); 51 | triggers[n] = LOW; 52 | } 53 | } 54 | 55 | 56 | void setup() { 57 | startMozzi(); 58 | for (int i;i<8;i++) { pinMode(ANALOG_PINS[i], INPUT); } 59 | for (int i;i<2;i++) { pinMode(TRIGGER_PINS[i], INPUT); } 60 | pinMode(MODE_PIN, INPUT); 61 | envelopes[0].setLevels(255, 150, 150, 0); 62 | envelopes[1].setLevels(255, 150, 150, 0); 63 | envelopes[0].setTimes(20, 20, 4000, 20); 64 | envelopes[1].setTimes(20, 20, 4000, 20); 65 | } 66 | 67 | 68 | void updateControl() { 69 | read_trigger(0); 70 | read_trigger(1); 71 | 72 | int x; 73 | x = mozziAnalogRead(ANALOG_PINS[0]) >> 1; 74 | envelopes[0].setAttackTime(x + 20); 75 | envelopes[1].setAttackTime(x + 20); 76 | 77 | x = mozziAnalogRead(ANALOG_PINS[1]) >> 1; 78 | envelopes[0].setDecayTime(x + 20); 79 | envelopes[1].setDecayTime(x + 20); 80 | 81 | x = mozziAnalogRead(ANALOG_PINS[2]) >> 2; 82 | envelopes[0].setSustainLevel(x); 83 | envelopes[1].setSustainLevel(x); 84 | envelopes[0].setDecayLevel(x); 85 | envelopes[1].setDecayLevel(x); 86 | 87 | x = mozziAnalogRead(ANALOG_PINS[3]) >> 1; 88 | envelopes[0].setReleaseTime(x + 20); 89 | envelopes[1].setReleaseTime(x + 20); 90 | 91 | x = mozziAnalogRead(ANALOG_PINS[4]) >> 8; 92 | if (x==0) { 93 | oscils[0].setTable(SIN2048_DATA); 94 | oscils[1].setTable(SIN2048_DATA); 95 | } 96 | else if (x==1) { 97 | oscils[0].setTable(SQUARE_NO_ALIAS_2048_DATA); 98 | oscils[1].setTable(SQUARE_NO_ALIAS_2048_DATA); 99 | } 100 | else if (x==2) { 101 | oscils[0].setTable(HALFSIN2048_DATA); 102 | oscils[1].setTable(HALFSIN2048_DATA); 103 | } 104 | else if (x==3) { 105 | oscils[0].setTable(SAW2048_DATA); 106 | oscils[1].setTable(SAW2048_DATA); 107 | } 108 | 109 | x = mozziAnalogRead(ANALOG_PINS[6]) >> 5; 110 | oscils[0].setFreq(note_freq[x + 9] * 2); 111 | 112 | x = mozziAnalogRead(ANALOG_PINS[5]) >> 5; 113 | oscils[1].setFreq(note_freq[x + 9] * 2); 114 | } 115 | 116 | 117 | int updateAudio() { 118 | int voice1, voice2, audio1, audio2, combined; 119 | envelopes[0].update(); 120 | envelopes[1].update(); 121 | 122 | /* 123 | voice1 = oscils[0].next(); 124 | audio1 = (voice1 * envelopes[0].next()) >> 2; 125 | 126 | voice2 = oscils[1].next(); 127 | audio2 = (voice2 * envelopes[1].next()) >> 2; 128 | 129 | combined = (audio1 + audio2) >> 1; 130 | return combined;*/ 131 | return (((oscils[0].next() * oscils[1].next()) >> 8) * envelopes[0].next()) >> 2; 132 | } 133 | 134 | 135 | void loop() { 136 | audioHook(); 137 | } 138 | -------------------------------------------------------------------------------- /PERCUSSION_MOZZI_SYNTH_V4/PERCUSSION_MOZZI_SYNTH_V4.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * VERSION 1: Uses the chum9 wavetable and passes it through a low pass filter with adjustable cutoff and resonance, also has an ADSR envelop with adjustable release 3 | * VERSION 2: Want to add different modes: 4 | * 1) first mode is identical to version 1 except with adjustable reverb: freq, cutoff, release, reverb 5 | * 2) second mode will be an improved and intentional version of the laserbeam distortion that was happening with the sawtooth wavetable and high cutoff frequency values: freq, attack, release, cutoff 6 | * 3) third mode will be an FM synth using the cosine wavetables: carrier freq, mod freq, mod depth, release 7 | * 4) fourth mode is white noise: attack, release, reverb delay, reverb feedback 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | 21 | 22 | //PINS 23 | const byte KNOB_PINS[2][2] = { 24 | {A0, A1}, 25 | {A2, A3} 26 | }; 27 | const byte TRIGGER_PINS[2] = {2, 3}; 28 | const byte MODE_PINS[2] = {8, 7}; 29 | 30 | 31 | 32 | //GLOBAL VARIABLES 33 | bool triggers[2] = {0, 0}; 34 | 35 | byte modes[2][3] = { // { mode, debounce value, counter value } 36 | {0, 40, 0}, 37 | {0, 40, 0} 38 | }; 39 | 40 | byte pink_to_white_ratio = 0; 41 | int counter = 0; 42 | int print_stats = 100; 43 | 44 | Oscil <2048, AUDIO_RATE> carriers[2]; 45 | Oscil <2048, AUDIO_RATE> modulators[2]; 46 | Oscil <2048, AUDIO_RATE> lasers[2]; 47 | Oscil <8192, AUDIO_RATE> whitenoise(WHITENOISE8192_DATA); 48 | Oscil <8192, AUDIO_RATE> pinknoise(PINKNOISE8192_DATA); 49 | 50 | ADSR envelopes[2]; 51 | LowPassFilter lpfs[2]; 52 | 53 | 54 | 55 | //FUNCTION DECLARATIONS 56 | void read_trigger(byte n) { 57 | if (digitalRead(TRIGGER_PINS[n]) == HIGH and triggers[n] == LOW) { 58 | envelopes[n].noteOn(); 59 | triggers[n] = HIGH; 60 | } 61 | else if (digitalRead(TRIGGER_PINS[n]) == LOW and triggers[n] == HIGH) { 62 | envelopes[n].noteOff(); 63 | triggers[n] = LOW; 64 | } 65 | } 66 | 67 | void read_mode(byte n) { 68 | if (digitalRead(MODE_PINS[n]) == HIGH and modes[n][2] > modes[n][1]) { 69 | modes[n][0]++; 70 | modes[n][0] %= 3; 71 | modes[n][2] = 0; 72 | } 73 | else { 74 | modes[n][2]++; 75 | } 76 | } 77 | 78 | void update_voice_control(byte n, byte m) { 79 | int x; 80 | int y; 81 | x = mozziAnalogRead(KNOB_PINS[n][1]) >> 1; 82 | envelopes[n].setDecayTime(20 + x); 83 | x = mozziAnalogRead(KNOB_PINS[n][0]) >> 2; 84 | 85 | carriers[n].setFreq(x); 86 | y = (x%12) + 1; 87 | modulators[n].setFreq((y*x) >> 2); 88 | 89 | pink_to_white_ratio = x; 90 | 91 | lpfs[n].setCutoffFreq(x); 92 | } 93 | 94 | int update_voice_audio(byte n, byte m) { 95 | envelopes[n].update(); 96 | int synth; 97 | if (m==0) { 98 | synth = (carriers[n].next() * modulators[n].next()) >> 8; 99 | } 100 | else if (m==1) { 101 | synth = (((whitenoise.next() * (255-pink_to_white_ratio)) >> 8) + ((pinknoise.next() * pink_to_white_ratio) >> 8)) >> 1; 102 | } 103 | else if (m==2){ 104 | synth = lpfs[n].next(lasers[n].next()); 105 | } 106 | return (synth * envelopes[n].next()) >> 2; 107 | } 108 | 109 | 110 | void setup(){ 111 | //Serial.begin(115200); 112 | startMozzi(); 113 | pinMode(KNOB_PINS[0][0], INPUT); 114 | pinMode(KNOB_PINS[0][1], INPUT); 115 | pinMode(KNOB_PINS[1][0], INPUT); 116 | pinMode(KNOB_PINS[1][1], INPUT); 117 | pinMode(TRIGGER_PINS[0], INPUT); 118 | pinMode(TRIGGER_PINS[1], INPUT); 119 | pinMode(MODE_PINS[0], INPUT); 120 | pinMode(MODE_PINS[1], INPUT); 121 | 122 | whitenoise.setFreq(55); 123 | pinknoise.setFreq(55); 124 | modulators[0].setTable(COS2048_DATA); 125 | modulators[1].setTable(COS2048_DATA); 126 | carriers[0].setTable(COS2048_DATA); 127 | carriers[1].setTable(COS2048_DATA); 128 | lasers[0].setTable(SAW2048_DATA); 129 | lasers[1].setTable(SAW2048_DATA); 130 | lasers[0].setFreq(100); 131 | lasers[1].setFreq(100); 132 | envelopes[0].setLevels(255, 0, 0, 0); 133 | envelopes[0].setTimes(20, 20, 20, 20); 134 | envelopes[1].setLevels(255, 0, 0, 0); 135 | envelopes[1].setTimes(20, 20, 20, 20); 136 | lpfs[0].setResonance(200); 137 | lpfs[1].setResonance(200); 138 | } 139 | 140 | void updateControl(){ 141 | read_trigger(0); 142 | read_trigger(1); 143 | 144 | read_mode(0); 145 | read_mode(1); 146 | 147 | update_voice_control(0, modes[0][0]); 148 | update_voice_control(1, modes[1][0]); 149 | /* 150 | if (counter >= print_stats) { 151 | Serial.print("Mode 1:" ); 152 | Serial.println(modes[0][0]); 153 | Serial.print("Mode 2:" ); 154 | Serial.println(modes[1][0]); 155 | Serial.println(); 156 | counter = 0; 157 | } 158 | counter++; 159 | */ 160 | } 161 | 162 | int updateAudio(){ 163 | int audio_1, audio_2; 164 | audio_1 = update_voice_audio(0, modes[0][0]); 165 | audio_2 = update_voice_audio(1, modes[1][0]); 166 | 167 | return (audio_1 + audio_2) >> 1; 168 | } 169 | 170 | void loop(){ 171 | audioHook(); 172 | } 173 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a collection of synth experiments I've created. More information can be found for the "John Synth" on Hackster [here](https://www.hackster.io/danielsinderson/phasemod-drone-synth-w-arduino-nano-mozzi-7ab2ff). 2 | 3 | --------------------------------------------------------------------------------