Here is the code as it is now.
It has only one single pattern but will compile and perform as in the video.
/*
* Arduino Nano Groove, The smallest groovebox in the world.
*
* Plays 8-bit PCM Drums on pin 11 using pulse-width modulation (PWM).
* For Arduino with Atmega328 at 16 MHz.
*
* Uses two timers. The first changes the sample value 8000 times a second.
* The second holds pin 11 high for 0-255 ticks out of a 256-tick cycle,
* depending on sample value. The second timer repeats 62500 times per second
* (16000000 / 256), much faster than the playback rate (8000 Hz).
* Based on code from Michael Smith.
*
* The The bassline synth is a true analog SAW synthesizer with its own audio output
* The waveform is built on digitalpin2 and digitalpin3 mixed with a 10K resistor on each pin.
* Two freerunning phaseaccumulators are used creating a phaseincrement.
* The result is a real SAW-wave that is mixed with the PCM drumpart.
* Hardware for this comes from Roland synthesizers, mainly the Juno 106 and ideas from Duane B, rcarduino.blogspot.com
* Thanks for the inspiration.
*/
#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#define SAMPLE_RATE 8000
// Define various ADC prescaler
const unsigned char PS_16 = (1 << ADPS2);
const unsigned char PS_32 = (1 << ADPS2) | (1 << ADPS0);
const unsigned char PS_64 = (1 << ADPS2) | (1 << ADPS1);
const unsigned char PS_128 = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
#include "sounddata.h"
int ledPin = 13;
int GRNledPin = 10;
int YELledPin = 12;
int speakerPin = 11; // Can be either 3 or 11, two PWM outputs connected to Timer 2
volatile uint16_t sample;
byte lastSample;
int sound_stop;
int BPM;
int BEAT;
int Tick;
int sixteen;
byte pat;
int mute;
int nextmute;
int bassgate;
int button;
int variation;
//float chromatic = 1.059463094359;
//float scale[] = { 1 , 1.059463094359 , 1.122462048308747 , 1.189207115001727 , 1.259921049893469 , 1.334839854168174 , 1.41421356237073 , 1.498307076873759 , 1.58740105196466 , 1.681792830503211 , 1.781797436275713 , 1.8877486253576 };
long scale[] = { 10000 , 10594 , 11224 , 11892 , 12599 , 13348 , 14142 , 14983 , 15874 , 16817 , 17817 , 18877 };
int pattern[] = { 1 , 0 , 4 , 0 , 3 , 0 , 4 , 0 , 1 , 0 , 4 , 0 , 3 , 0 , 4 , 8 , 1 , 0 , 4 , 4 , 1 , 0 , 5 , 4 , 1 , 0 , 5 , 5 , 3 , 0 , 3 , 6 };
int basspattern[] = { 0 , 0 , 2 , 1 , 0 , 0 , 1 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 3 , 4 };
//SAW Synth
long phacc1;
long phacc2;
int pitch1;
int pitch2;
int osc1;
int osc2;
void stopPlayback()
{
// Disable playback per-sample interrupt.
TIMSK1 &= ~_BV(OCIE1A);
// Disable the per-sample timer completely.
TCCR1B &= ~_BV(CS10);
// Disable the PWM timer.
TCCR2B &= ~_BV(CS10);
digitalWrite(speakerPin, LOW);
}
// This is called at 8000 Hz to load the next sample.
ISR(TIMER1_COMPA_vect) {
if (sample >= sound_stop) {
sample = sound_stop;
}
else {
OCR2A = pgm_read_byte(&sounddata_data[sample]);
}
//The BassSynth
phacc1 = phacc1 + pitch1;
phacc2 = phacc2 + pitch2;
osc1 = (phacc1 ) / 8192;
osc2 = (phacc2 ) / 4096;
// Output the SAW-wave to D2 and D3 without using digitalwrite because its to slow in a ISR.
if (bassgate==1) {
PORTD = PORTD & B11110011 | (osc1 | osc2 & 12); //Outputs the SAW Wave
}
++sample;
++Tick;
}
void startPlayback()
{
pinMode(speakerPin, 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(&sounddata_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(&sounddata_data[sounddata_length-1]);
sample = 0;
sei();
digitalWrite(GRNledPin, LOW);
digitalWrite(YELledPin, HIGH);
Tick = 0;
sixteen = 0;
BEAT = 0;
}
void setup()
{
pinMode(ledPin, OUTPUT);
pinMode(GRNledPin, OUTPUT);
pinMode(YELledPin, OUTPUT);
digitalWrite(ledPin, HIGH);
digitalWrite(GRNledPin, LOW);
digitalWrite(YELledPin, LOW);
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
startPlayback();
// set up the ADC
ADCSRA &= ~PS_128; // remove bits set by Arduino library
// you can choose a prescaler from above.
// PS_16, PS_32, PS_64 or PS_128
ADCSRA |= PS_32; // set our own prescaler to 32
}
void loop()
{
// calculate the tempo
BPM = (analogRead(0) / 10) + 60;
sixteen = 2000 - (BPM * 7);
if (Tick >= sixteen) {
Tick = 0;
//Button 1 511
//Button 2 339
//Button 3 245
//Button 4 203
//Button 5 168
button = analogRead(1);
if (button > 150 and button <180) {
variation = 1;
}
if (button > 195) {
nextmute = 8;
}
if (button > 215) {
nextmute = 4;
}
if (button > 260) {
nextmute = 2;
}
if (button > 415) {
nextmute = 1;
}
++BEAT;
// Calculate the next bass sound
pitch1 = int(analogRead(2) * scale[basspattern[BEAT] - 1] / 10000);
pitch2 = int(analogRead(3) * scale[basspattern[BEAT] - 1] / 10000);
bassgate = 0;
if (basspattern[BEAT] > 0) {
bassgate = 1;
}
if (BEAT >= 16) {
BEAT = 0;
mute = mute ^ nextmute;
nextmute = 0;
variation = 0;
}
// Calculate the next drumsound
sample = (pattern[BEAT + (variation * 16)] & mute) * 1024;
sound_stop = sample + 1023;
// Turn on the BPM flash LED
switch (BEAT) {
case 0:
digitalWrite(YELledPin, HIGH);
break;
case 4:
digitalWrite(GRNledPin, HIGH);
break;
case 8:
digitalWrite(GRNledPin, HIGH);
break;
case 12:
digitalWrite(GRNledPin, HIGH);
break;
}
}
// Turn off the BPM flash LED
if (Tick >= 10) {
digitalWrite(GRNledPin, LOW);
}
if (Tick >= 750) {
digitalWrite(YELledPin, LOW);
}
}
And the sounddata.h required. It's not complete because it contains 16384 samples and would not fit here.
// sounddata sound made by wav2c
// (wav2c modified to use unsigned samples)
/* const int sounddata_sampleRate=8000; */
const int sounddata_length=1024;
const unsigned char sounddata_data[] PROGMEM = { 128 , 128 ..... };
So I have attached it.
sounddata.h (95.5 KB)