#include #include #include #include #include #include "sample.h" #define LED_PIN 13 #define SPEAKER_PIN 11 #define KNOB_1 (0) #define KNOB_2 (1) #define KNOB_3 (2) #define INPUT_3 (3) volatile uint16_t sample; volatile uint16_t loop_start; volatile uint16_t loop_length; volatile uint16_t index_bounds; volatile uint16_t loop_overflow; volatile boolean gate; volatile boolean gate_prev; byte lastSample; CapacitiveSensor cs_4_2 = CapacitiveSensor(4,2); // 10M resistor between pins 4 & 2, pin 2 is sensor pin, add a wire and or foil if desired CapacitiveSensor cs_4_3 = CapacitiveSensor(4,3); // 10M resistor between pins 4 & 6, pin 6 is sensor pin, add a wire and or foil CapacitiveSensor cs_4_5 = CapacitiveSensor(4,5); // 10M resistor between pins 4 & 8, pin 8 is sensor pin, add a wire and or foil void startPlayback() { pinMode(SPEAKER_PIN, OUTPUT); // Set up Timer 2 to do pulse width modulation on the speaker pin. // Use internal clock (datasheet p.160) ASSR &= ~(_BV(EXCLK) | _BV(AS2)); // Set fast PWM mode (p.157) TCCR2A |= _BV(WGM21) | _BV(WGM20); TCCR2B &= ~_BV(WGM22); // Do non-inverting PWM on pin OC2A (p.155) // On the Arduino this is pin 11. TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0); TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0)); // No prescaler (p.158) TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10); // Set initial pulse width to the first sample. OCR2A = pgm_read_byte(&sound_data[0]); // Set up Timer 1 to send a sample every interrupt. cli(); // Set CTC mode (Clear Timer on Compare Match) (p.133) // Have to set OCR1A *after*, otherwise it gets reset to 0! TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12); TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10)); // No prescaler (p.134) TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10); // Set the compare register (OCR1A). // OCR1A is a 16-bit register, so we have to do this with // interrupts disabled to be safe. OCR1A = F_CPU / SAMPLE_RATE; // 16e6 / 8000 = 2000 // Enable interrupt when TCNT1 == OCR1A (p.136) TIMSK1 |= _BV(OCIE1A); lastSample = pgm_read_byte(&sound_data[sound_length - 1]); sample = 0; sei(); } void stopPlayback() { TIMSK1 &= ~_BV(OCIE1A); // Disable playback per-sample interrupt. TCCR1B &= ~_BV(CS10); // Disable the per-sample timer completely. TCCR2B &= ~_BV(CS10); // Disable the PWM timer. digitalWrite(SPEAKER_PIN, LOW); } void setup() { pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, HIGH); startPlayback(); loop_start = 0; loop_length = sound_length; gate = false; gate_prev = false; } // This is called at 8000 Hz to load the next sample. ISR(TIMER1_COMPA_vect) { if(sample >= index_bounds) { sample = loop_start; } else if((sample < loop_start) && (sample >= loop_overflow)) { sample = loop_start; } else if((gate == true) && (gate_prev == false)) { sample = loop_start; } else { OCR2A = pgm_read_byte(&sound_data[sample % sound_length]); } gate_prev = gate; sample++; } void loop() { long start = millis(); long total1 = cs_4_2.capacitiveSensor(30); long valCons1 = constrain(total1, 10000, 225000); long mappedVal1 = map(valCons1, 10000, 225000, 0, 1024); long total2 = cs_4_3.capacitiveSensor(30); long valCons2 = constrain(total2, 10000, 225000); long mappedVal2 = map(valCons2, 10000, 225000, 0, 1024); long total3 = cs_4_5.capacitiveSensor(30); long valCons3 = constrain(total3, 10000, 225000); long mappedVal3 = map(valCons3, 10000, 225000, 0, 1024); loop_start = mappedVal3 / 1024.0 * sound_length; loop_length = (mappedVal2 + 1) / 1024.0 * sound_length; OCR1A = (512.0 / (mappedVal1 + 1)) * (F_CPU / SAMPLE_RATE); gate = analogRead(3) >> 9; // 10 bits in. gate < 512 == off, gate >= 512 == on // can be up to 2x sound length. the more you know. index_bounds = loop_start + loop_length; // this will set the overflow length. take the loop overflow into account when checking the loop boundaries if(index_bounds > sound_length) { loop_overflow = index_bounds - sound_length; } else { loop_overflow = 0; } }