/* FRAMEN v2.0 by Robert Beenen MOD1: 1-15 -> amen slice 16 -> random sample MOD2: 0-50% -> play from start to 1-100% 51-100% -> loop starts at 0-99% to end KNOB3: 0-100% -> pitch -1 oct to +1 oct INPUT3: trigger input Just play around with it, it's pretty straight forward. */ #include "sample.h" #define MOD1_PIN A2 // KNOB1 / INPUT1 #define MOD2_PIN A1 // KNOB2 / INPUT2 #define KNOB3_PIN A0 // KNOB3 #define INPUT3_PIN A3 // INPUT3 #define OUT_PIN 11 #define SAMPLERATE 8000 #define UPDATERATE (F_CPU / SAMPLERATE) #define SILENCE 0x80 // inputs uint8_t mod1; uint16_t mod2; uint16_t knob3; uint8_t input3; // internal uint16_t offset; uint16_t length; uint16_t loop_start; uint16_t index; bool playing; bool triggered; bool looping; uint8_t seed = 1; void xorshift(void) { if(!seed) seed++; seed ^= (seed << 7); seed ^= (seed >> 5); seed ^= (seed << 3); } void setup() { pinMode(OUT_PIN, OUTPUT); // Setup Timer 2 to do pulse width modulation on the speaker pin ASSR &= ~(_BV(EXCLK) | _BV(AS2)); // use internal clock (datasheet p.160) TCCR2A |= _BV(WGM21) | _BV(WGM20); // set fast PWM mode (p.155) TCCR2B &= ~_BV(WGM22); TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0); // non-inverting PWM on OC2A (p.155) TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0)); // OC2A = OUT_PIN TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10); // no prescaler (p.158) OCR2A = SILENCE; // set initial output to silent // Setup Timer 1 to send a sample every interrupt. cli(); TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12); // CTC mode (p.133) TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10)); TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10); // no prescaler OCR1A = UPDATERATE; TIMSK1 |= _BV(OCIE1A); // enable interrupt when TCNT1 == OCR1A (p.136) sei(); } void loop() { mod1 = analogRead(MOD1_PIN) >> 6; // reduce to 4 bits mod2 = analogRead(MOD2_PIN); knob3 = analogRead(KNOB3_PIN); input3 = digitalRead(INPUT3_PIN); // using digital read on an analog input works if(mod1 == 0x0F) { mod1 = map(seed, 0, 255, 0, 14); // use the random value when mod1 is at max value } offset = slice_start[mod1]; if(mod2 & 0x200) { looping = true; length = slice_length[mod1]; mod2 ^= 0x3FF; loop_start = length - map(mod2, 0, 511, 4 * GRAINSIZE, length); } else { looping = false; length = map(mod2, 0, 511, 4 * GRAINSIZE, slice_length[mod1]); } OCR1A = map(analogRead(KNOB3_PIN), 0, 1023, 4000, 1000); } ISR(TIMER1_COMPA_vect) { if(input3 && !triggered) { xorshift(); // update to another random number on trigger index = 0; playing = true; triggered = true; } else if(!input3 && triggered) { triggered = false; } if(index >= length) { if(looping) { index = loop_start; } else { playing = false; OCR2A = SILENCE; } } else { index++; } if(playing) { OCR2A = pgm_read_byte(&sample_data[(offset + index) % SAMPLESIZE]); } }