//////////////////////////////////////////////////////////////// // // // BEAT-DUINO // // AN ARDUINO 8-BIT BEAT BOX + BASS SYNTH // // // // version 0.1 // // // // Nicolas Besnard, Jan 2011 // // electronique-et-musique.blog4ever.com // // // // based on the following pieces of code: // // - "Arduino Beats", by little-scale, 06/04/08 // // http://little-scale.blogspot.com/2008/04/arduino-beats.html // // // - "Signal generator using Arduino and DDS, mouro, 16/05/09 // // http://mouro.info/signal-generator-using-arduino-and-dds // // // //////////////////////////////////////////////////////////////// #include // DECLARATIONS // Constants int pwmPin = 9; // Synth PWM output (OCR1A) int beatPin = 10; // Beat PWM output // User variables unsigned long durStep = 120; // Step duration int barLength = 16; // Nb of steps in a bar int sampleTime[] = { // Sample duration for each instr 0, 300, 220, 180, 120 }; int waveForm = 0; // 0: sine, 1: tri, 2: sqr // Beats byte beatPatterns[][16] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 1, 0, 1 }, { 1, 0, 0, 0, 2, 0, 1, 0, 0, 0, 1, 0, 2, 1, 0, 0 }, { 1, 0, 0, 0, 2, 0, 1, 0, 0, 0, 1, 0, 2, 1, 0, 1 }, { 1, 0, 3, 0, 2, 0, 1, 0, 0, 0, 1, 0, 2, 1, 3, 0 }, { 1, 0, 3, 0, 2, 0, 1, 0, 0, 0, 1, 0, 2, 1, 3, 1 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; byte beatSong[] = { 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, 4, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4, 5, 6, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, 4, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4, 5, 6, 0, 0, 0, 0, 0, 0, 0 }; // Synth line byte synthPatterns[][16] = { { 55, 0, 66, 0, 110, 0, 73, 0, 55, 0, 110, 0, 73, 73, 73, 0 }, { 55, 0, 66, 0, 110, 0, 73, 0, 37, 37, 37, 37, 41, 41, 41, 41 }, { 55, 55, 66, 66, 110,110, 73, 73, 55, 55, 110,110, 73, 73, 73, 73 }, { 55, 55, 66, 66, 110,110, 73, 73, 37, 37, 37, 37, 41, 41, 41, 41 }, { 55, 83, 66, 83, 110,110, 73, 73, 55, 83, 110, 83, 73, 83, 73, 73 }, { 55, 83, 66, 83, 110,110, 73, 73, 37, 37, 37, 37, 41, 41, 41, 41 } }; byte synthSong[] = { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0 }; // Program variables unsigned long time; // Current time unsigned long timeNextStep; // Time of next step int iStep; // Current step int iBar; // Current bar int iBeatPattern; // Current beat pattern int iSynthPattern; // Current synth pattern boolean isPlaying = true; // Samples byte kick[] = { 127, 80, 42, 5, 165, 242, 241, 233, 128, 73, 48, 22, 127, 69, 55, 113, 151, 183, 209, 217, 223, 228, 233, 215, 161, 117, 91, 76, 65, 49, 37, 31, 31, 48, 83, 120, 146, 166, 183, 198, 206, 210, 209, 199, 178, 145, 111, 88, 78, 73, 69, 67, 72, 80, 88, 97, 109, 124, 137, 150, 163, 171, 174, 172, 168, 160, 144, 125, 114, 110, 108, 104, 104, 106, 109, 110, 112, 117, 124, 129, 135, 142, 145, 145, 143, 140, 137, 132, 128, 125, 122, 119, 118, 119, 119, 119, 118, 118, 120, 124, 126, 129, 132, 135, 137, 137, 135, 132, 131, 130, 129, 128, 126, 126, 124, 123, 121, 120, 120, 122, 123, 124, 126, 128, 129, 130, 130, 131, 131, 131, 130, 130, 130, 129, 129, 128, 126, 125, 125, 124, 124, 124, 124, 125, 126, 126, 128, 128, 128, 129, 129, 129, 129, 129, 128, 128, 128, 128, 126, 126, 126, 126, 126, 126, 126, 126, 126, 128, 127, 126, 128, 128, 128, 128, 128, 128, 128, 128, 126, 126, 126, 126, 126, 126, 126, 126, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126 }; byte snare[] = { 127, 215, 65, 212, 56, 102, 135, 122, 51, 201, 220, 46, 175, 80, 152, 95, 123, 116, 184, 155, 59, 122, 100, 161, 143, 173, 101, 155, 97, 73, 112, 98, 176, 96, 140, 77, 134, 109, 132, 149, 112, 149, 97, 161, 98, 151, 98, 155, 149, 112, 157, 103, 133, 106, 167, 97, 166, 108, 129, 124, 136, 146, 124, 136, 129, 150, 94, 130, 105, 141, 146, 128, 129, 99, 150, 121, 141, 99, 142, 116, 131, 114, 118, 143, 127, 143, 115, 144, 120, 137, 109, 129, 131, 139, 129, 113, 144, 119, 145, 117, 135, 129, 134, 136, 124, 130, 130, 139, 121, 136, 121, 132, 128, 127, 126, 122, 130, 126, 138, 120, 136, 122, 131, 123, 130, 128, 127, 128, 118, 132, 125, 131, 122, 131, 125, 131, 122, 126, 128, 126, 129, 121, 129, 123, 132, 129, 127, 131, 123, 128, 125, 130, 123, 131, 123, 128, 131, 129, 128, 126, 125, 124, 131, 121, 124, 129, 130, 126, 124, 126, 127, 130, 125, 126, 128, 126, 128, 126, 126, 126, 126, 125, 128, 126, 126, 126, 126, 126, 126, 125, 128, 126, 126, 126, 126, 126, 126, 126, 126, 128, 128, 126, 128, 126, 127, 126, 128, 125, 127, 128, 128, 126, 126, 128, 126, 126, 128, 128, 128, 128, 128, 126, 128, 126, 126, 128, 128, 126, 126, 128, 128, 126, 126, 127, 126, 128, 126, 126, 128, 128, 128, 126, 126, 126, 128, 128, 126, 126, 126, 128, 128, 126, 128, 128, 126, 126 }; byte hat[] = { 127, 128, 225, 217, 99, 38, 61, 153, 152, 144, 133, 73, 122, 144, 65, 188, 87, 170, 164, 111, 122, 151, 114, 88, 174, 77, 140, 92, 122, 141, 156, 124, 121, 123, 126, 133, 132, 139, 119, 120, 127, 141, 130, 122, 129, 127, 132, 121, 139, 118, 130, 131, 129, 132, 130, 134, 126, 128, 130, 126, 122, 132, 129, 127, 131, 126, 128, 127, 126, 125, 127, 125, 128, 125, 128, 128, 127, 127, 126, 127, 128, 128, 128, 127, 127, 127, 127, 127, 128, 127, 127, 126, 127, 127, 128, 127, 128, 126, 127, 128, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 128, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 128, 128, 126, 126, 128, 127, 126, 127, 126, 127, 127, 126, 127, 126, 127, 127, 127, 127, 127, 126, 127, 127, 127, 126, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 126, 126, 126, 127, 127, 127, 126, 127, 127, 127, 126, 127, 127, 126, 127, 127, 127, 127, 127, 127, 126, 126, 126, 126, 126, 126, 126, 127, 127, 126, 127, 126, 126, 127, 126, 127, 126, 126, 126, 126, 126, 126, 126, 127, 127, 126, 127, 127, 127, 127, 126, 126, 127, 127, 127, 126, 127, 126, 127, 127, 127, 127, 127, 126, 126, 127, 127, 126, 127, 127, 127, 127, 126, 127, 127, 127, 127, 127, 127, 127, 127 }; byte crash[] = { 127, 128, 225, 217, 99, 38, 61, 153, 152, 144, 133, 73, 122, 144, 65, 188, 87, 170, 164, 111, 122, 151, 114, 88, 174, 77, 140, 92, 122, 141, 156, 124, 121, 123, 126, 133, 132, 139, 119, 120, 127, 141, 130, 122, 129, 127, 132, 121, 139, 118, 130, 131, 129, 132, 130, 134, 126, 128, 130, 126, 122, 132, 129, 127, 131, 126, 128, 127, 126, 125, 127, 125, 128, 125, 128, 128, 127, 127, 126, 127, 128, 128, 128, 127, 127, 127, 127, 127, 128, 127, 127, 126, 127, 127, 128, 127, 128, 126, 127, 128, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 128, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 128, 128, 126, 126, 128, 127, 126, 127, 126, 127, 127, 126, 127, 126, 127, 127, 127, 127, 127, 126, 127, 127, 127, 126, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 126, 126, 126, 127, 127, 127, 126, 127, 127, 127, 126, 127, 127, 126, 127, 127, 127, 127, 127, 127, 126, 126, 126, 126, 126, 126, 126, 127, 127, 126, 127, 126, 126, 127, 126, 127, 126, 126, 126, 126, 126, 126, 126, 127, 127, 126, 127, 127, 127, 127, 126, 126, 127, 127, 127, 126, 127, 126, 127, 127, 127, 127, 127, 126, 126, 127, 127, 126, 127, 127, 127, 127, 126, 127, 127, 127, 127, 127, 127, 127, 127 }; // Sinewave lookup table for waveform generation static const uint8_t sineTable[] PROGMEM = { 0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95, 0x98,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae, 0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4, 0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5,0xd8, 0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8, 0xea,0xec,0xed,0xef,0xf0,0xf2,0xf3,0xf5, 0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc, 0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe, 0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7, 0xf6,0xf5,0xf3,0xf2,0xf0,0xef,0xed,0xec, 0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0xde,0xdc, 0xda,0xd8,0xd5,0xd3,0xd1,0xce,0xcc,0xc9, 0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb3, 0xb0,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c, 0x98,0x95,0x92,0x8f,0x8c,0x89,0x86,0x83, 0x80,0x7c,0x79,0x76,0x73,0x70,0x6d,0x6a, 0x67,0x63,0x60,0x5d,0x5a,0x57,0x54,0x51, 0x4f,0x4c,0x49,0x46,0x43,0x40,0x3e,0x3b, 0x38,0x36,0x33,0x31,0x2e,0x2c,0x2a,0x27, 0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17, 0x15,0x13,0x12,0x10,0x0f,0x0d,0x0c,0x0a, 0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03, 0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01, 0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08, 0x09,0x0a,0x0c,0x0d,0x0f,0x10,0x12,0x13, 0x15,0x17,0x19,0x1b,0x1d,0x1f,0x21,0x23, 0x25,0x27,0x2a,0x2c,0x2e,0x31,0x33,0x36, 0x38,0x3b,0x3e,0x40,0x43,0x46,0x49,0x4c, 0x4f,0x51,0x54,0x57,0x5a,0x5d,0x60,0x63, 0x67,0x6a,0x6d,0x70,0x73,0x76,0x79,0x7c }; uint16_t phaseAccumulator = 0; // 16 bit accumulator uint16_t phaseIncrement = 0; // 16 bit delta const uint32_t resolution = 68719; // DDS resolution uint8_t index = 0; // wavetable lookup index // (upper 8 bits of the accumulator) uint16_t frequency = 440; // initial output frequency // SETUP ROUTINE void setup() { Serial.begin(38400); pinMode(beatPin, OUTPUT); pinMode(pwmPin, OUTPUT); pinMode(2, INPUT); pinMode(3, INPUT); digitalWrite(2, HIGH); // enable pullup resistor digitalWrite(3, HIGH); // enable pullup resistor // 8-bit Fast PWM - non inverted PWM TCCR1A= _BV(COM1A1) | _BV(WGM10); // Start timer without prescaler TCCR1B = _BV(CS10) | _BV(WGM12); // Enable overflow interrupt for OCR1A TIMSK1 = _BV(TOIE1); // Enable global interrupts sei(); } // MAIN LOOP void loop() { time = millis(); // Read the waveform switches if (digitalRead(2) == true){ waveForm = 1; } else if (digitalRead(3) == true){ waveForm = 2; } else waveForm = 0; // Step increment if (time >= timeNextStep && isPlaying){ if (digitalRead(13) == false){ digitalWrite(13, true); digitalWrite(12, true); } else { digitalWrite(13, false); digitalWrite(12, false); } // Increment step time timeNextStep = timeNextStep + durStep; iBeatPattern = beatSong[iBar]; iSynthPattern = synthSong[iBar]; // Play the synth note setFrequency(synthPatterns[iSynthPattern][iStep]); // Play the beat playBeat(beatPatterns[iBeatPattern][iStep]); // Increment step iStep++; if (iStep >= barLength) { iStep = 0; iBar++; if (iBar >= sizeof(beatSong)) { isPlaying = false; setFrequency(0); } } } } // TIMER INTERUPT FUNCTION ISR(TIMER1_OVF_vect) { // TIMER1 will overflow at a 62.5KHz(Sampling frequency). // Updates the OCR1A value and the accumulator. // Computes the next sample to be sent to the PWM. static uint8_t osc = 0; // Send oscillator output to PWM OCR1A = osc; // Update accumulator phaseAccumulator += phaseIncrement; index = phaseAccumulator >> 8; // Read oscillator value for next interrupt switch (waveForm){ case 0: // sine wave osc = pgm_read_byte( &sineTable[index] ); break; case 1: // saw wave osc = index; break; case 2: // square wave osc = sineTable[index]; break; } } // ROUTINES void playBeat(byte beat) { if(beat == 1) { playKick(); } else if(beat == 2) { playSnare(); } else if(beat == 3) { playHat(); } else if(beat == 4) { playCrash(); } } void playKick() { for(int i = 0; i < 256; i ++) { analogWrite(beatPin, kick[i]); delayMicroseconds(sampleTime[1]); } analogWrite(beatPin, 127); } void playSnare() { for(int i = 0; i < 256; i ++) { analogWrite(beatPin, snare[i]); delayMicroseconds(sampleTime[2]); } analogWrite(beatPin, 127); } void playHat() { for(int i = 0; i < 256; i ++) { analogWrite(beatPin, hat[i]); delayMicroseconds(sampleTime[3]); } analogWrite(beatPin, 127); } void playCrash() { for(int i = 0; i < 256; i ++) { analogWrite(beatPin, crash[i]); delayMicroseconds(sampleTime[4]); } analogWrite(beatPin, 127); } void setFrequency(uint32_t frequency){ // Translates the desired output frequency to a phase // increment to be used with the phase accumulator. // The 16 bit shift is required to remove the 2^16 // scale factor of the resolution. if (waveForm == 0) frequency = 2 * frequency; uint64_t phaseIncr64 = resolution * frequency; phaseIncrement = phaseIncr64 >> 16; }