You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
131 lines
3.0 KiB
C++
131 lines
3.0 KiB
C++
/*
|
|
|
|
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]);
|
|
}
|
|
}
|