Introduction: Arduino Chiptunes

I am not a big fan of programming. I may like it, but I try to keep it down to a 555 timer, like in this ible. However, when it comes to synthesizers, I kinda NEED programming. One day, while exploring Synthesizers, I came across something known as chiptunes.

I decided to listen and found the music really awesome. So I tried to make it with Arduino. Didn't work. The code was not in the Arduino language. Some browsing of the internet forums led me to find that an Arduino forum user by the name of Stimmer had ported Linus Åkesson's Hardware Chiptune Project to the Arduino.

And now, here is that project.

Step 1: Gains and Losses.

You will gain:

A machine capable of playing a tune every time you push a button to activate it.


You will lose: (Materials)

An Arduino
A speaker+possibly an amp
2 jumper wires (If your speaker doesn't already have them)

Step 2: What Type of Speakers Should I Use?

There are many speakers available on the market these days.

Some have 3.5 mm jacks and amplifiers. Too bad you probably want to save them for your phone.

Some have wire, coils and a magnet - exposed.

Heck, you could even use headphones - assuming that it isn't haphazardly held together by Sugru or some other similar substance.

Step 3: Programming.

Start by copying the code from below.

Then, copy and paste the code into the Arduino editor.

Compile. Upload.

You're done with the software.


<pre>#include <avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>

#define TRACKLEN 32
#define MAXTRACK 0x92
#define SONGLEN  0x37

#include <avr/pgmspace.h>

extern "C" {
 
typedef unsigned char u8;
typedef unsigned short u16;
typedef char s8;
typedef short s16;
typedef unsigned long u32;

const byte songdata[] PROGMEM = {
  0x77, 0x00, 0x2a, 0x84, 0x05, 0xbb, 0x90, 0x18, 0x40, 0xc3, 0x6c, 0x50,
    0x0e, 0xd1, 0x41, 0x3e, 0x4c, 0x08, 0x1a, 0xb1, 0x24, 0xa4, 0x44, 0x99,
    0x30, 0x13, 0x67, 0x82, 0x50, 0x60, 0x0a, 0x53, 0x11, 0x2c, 0x9e, 0x45,
    0xbe, 0xe8, 0x18, 0x2b, 0xe3, 0x68, 0x9c, 0x8d, 0xc2, 0xd1, 0x39, 0x60,
    0xc7, 0xf5, 0xe0, 0x1f, 0x1c, 0x64, 0x88, 0x84, 0x11, 0x3c, 0xb2, 0x48,
    0x4e, 0x49, 0x2d, 0x89, 0x26, 0xe8, 0x84, 0x9f, 0x38, 0x94, 0x8e, 0x92,
    0x53, 0x9e, 0x4a, 0x57, 0xb1, 0x2b, 0x8d, 0x45, 0xb5, 0x14, 0x97, 0xe9,
    0x32, 0x5e, 0xe8, 0x0b, 0x83, 0x29, 0x31, 0x40, 0xc6, 0xcc, 0x28, 0x9a,
    0x51, 0x63, 0x6c, 0xaa, 0xcd, 0xb8, 0xe1, 0x37, 0x10, 0x27, 0xe5, 0x54,
    0x1d, 0xb9, 0x73, 0x7a, 0x72, 0x4f, 0xf2, 0xc9, 0x3e, 0x03, 0x08, 0x00,
    0x00, 0x1b, 0x00, 0x00, 0xa8, 0xb5, 0x00, 0x80, 0x9b, 0x2b, 0x00, 0x00,
    0x00, 0x02, 0x00, 0x00, 0x20, 0x90, 0x18, 0x00, 0x02, 0x09, 0x00, 0x20,
    0x90, 0x00, 0x4c, 0x02, 0x09, 0x00, 0x25, 0x90, 0x00, 0x54, 0x0e, 0x09,
    0xc0, 0x24, 0x90, 0x00, 0x4c, 0x02, 0x09, 0x00, 0x25, 0x90, 0x00, 0x54,
    0x02, 0x09, 0xc2, 0x24, 0x90, 0x50, 0x4c, 0x02, 0x89, 0x05, 0x25, 0x90,
    0x60, 0x54, 0x02, 0x89, 0xc6, 0x24, 0x90, 0x70, 0x4c, 0x02, 0x89, 0x07,
    0x25, 0x90, 0x90, 0x5c, 0x0e, 0x89, 0xc6, 0x44, 0x60, 0xc2, 0x7c, 0x04,
    0xa7, 0x0c, 0x48, 0x80, 0xd2, 0x84, 0x04, 0xa9, 0x8d, 0x48, 0x88, 0x3e,
    0xce, 0x48, 0xa0, 0xea, 0x90, 0x04, 0x2c, 0x4f, 0xe9, 0xb0, 0x1a, 0x10,
    0x02, 0x89, 0xd7, 0x24, 0x90, 0x80, 0x51, 0x02, 0x89, 0x58, 0x25, 0x90,
    0x90, 0x4d, 0x02, 0x89, 0xd9, 0x24, 0x90, 0xa0, 0x51, 0x02, 0x89, 0xd8,
    0xe5, 0x90, 0x90, 0x4d, 0x82, 0xef, 0x74, 0xe6, 0x34, 0x82, 0xf0, 0x7c,
    0x26, 0x35, 0x84, 0xf1, 0x64, 0x66, 0x35, 0x82, 0xf2, 0x6c, 0xe6, 0x34,
    0x82, 0xc9, 0x84, 0xe6, 0x34, 0x82, 0xc9, 0x84, 0x26, 0x35, 0x84, 0xc9,
    0x8c, 0x66, 0x35, 0x8e, 0xc9, 0x8c, 0xe6, 0x34, 0x8c, 0xf8, 0xcc, 0xe7,
    0x34, 0x8c, 0xf8, 0xcc, 0x27, 0x35, 0x8c, 0xf8, 0xcc, 0x67, 0x35, 0x8c,
    0xf8, 0xcc, 0xe7, 0x34, 0x8c, 0xf8, 0xcc, 0xe7, 0x34, 0x8c, 0xf8, 0xcc,
    0x27, 0x35, 0x88, 0xed, 0xcc, 0xe7, 0x35, 0x90, 0xee, 0x28, 0x5a, 0x03,
    0x09, 0x03, 0x08, 0xff, 0x07, 0x01, 0x09, 0x02, 0x01, 0x90, 0x0b, 0x31,
    0x05, 0xa0, 0x02, 0xf0, 0x00, 0x08, 0xff, 0x09, 0x03, 0x07, 0x02, 0x09,
    0x02, 0x0b, 0x31, 0x01, 0x70, 0x05, 0xd0, 0x07, 0x02, 0x02, 0xf8, 0x04,
    0x01, 0x00, 0x09, 0x02, 0x06, 0x05, 0x0b, 0x31, 0x08, 0xff, 0x02, 0xf0,
    0x07, 0x06, 0x02, 0x00, 0x07, 0x16, 0x0a, 0x25, 0x00, 0x09, 0x03, 0x08,
    0xff, 0x07, 0x01, 0x09, 0x00, 0x06, 0x05, 0x0b, 0x3d, 0x02, 0xf0, 0x07,
    0x06, 0x02, 0x00, 0x07, 0x20, 0x02, 0xf0, 0x00, 0x09, 0x03, 0x08, 0xff,
    0x07, 0x01, 0x09, 0x02, 0x01, 0x50, 0x06, 0x01, 0x0b, 0x31, 0x07, 0x05,
    0x02, 0xfe, 0x00, 0x09, 0x02, 0x01, 0x80, 0x0b, 0x3d, 0x08, 0xc0, 0x02,
    0x08, 0x07, 0x02, 0x02, 0xf0, 0x07, 0x02, 0x02, 0x00, 0x07, 0x16, 0x0a,
    0x34, 0x00, 0x09, 0x03, 0x08, 0xff, 0x02, 0xfc, 0x00, 0x03, 0x00, 0x09,
    0x03, 0x08, 0xff, 0x07, 0x01, 0x09, 0x02, 0x06, 0x05, 0x02, 0xff, 0x0b,
    0x3d, 0x07, 0x03, 0x0b, 0x38, 0x07, 0x03, 0x0b, 0x34, 0x07, 0x03, 0x0b,
    0x31, 0x07, 0x03, 0x04, 0x07, 0x00, 0x03, 0x00, 0x09, 0x03, 0x08, 0xff,
    0x07, 0x01, 0x09, 0x02, 0x06, 0x05, 0x02, 0xff, 0x0b, 0x3d, 0x07, 0x03,
    0x0b, 0x38, 0x07, 0x03, 0x0b, 0x35, 0x07, 0x03, 0x0b, 0x31, 0x07, 0x03,
    0x04, 0x07, 0x00, 0x03, 0x00, 0x09, 0x03, 0x08, 0xff, 0x07, 0x01, 0x09,
    0x02, 0x06, 0x05, 0x02, 0xff, 0x0b, 0x3d, 0x07, 0x03, 0x0b, 0x38, 0x07,
    0x03, 0x0b, 0x36, 0x07, 0x03, 0x0b, 0x31, 0x07, 0x03, 0x04, 0x07, 0x00,
    0x09, 0x03, 0x08, 0xff, 0x07, 0x01, 0x09, 0x00, 0x06, 0x05, 0x0b, 0x3d,
    0x02, 0xf0, 0x07, 0x06, 0x02, 0x00, 0x07, 0x06, 0x0a, 0x25, 0x00, 0x09,
    0x03, 0x08, 0xff, 0x02, 0xf0, 0x00, 0x08, 0xc4, 0x09, 0x00, 0x06, 0x05,
    0x0b, 0x3d, 0x02, 0xf0, 0x07, 0x06, 0x02, 0x00, 0x07, 0x06, 0x0a, 0x25,
    0x00, 0x00, 0x00, 0x6b, 0x04, 0x00, 0x20, 0x0d, 0x2c, 0x23, 0x58, 0x23,
    0x00, 0xb4, 0x81, 0x80, 0x44, 0xc0, 0x34, 0x90, 0x06, 0xd2, 0xc0, 0x32,
    0x02, 0x60, 0x8d, 0x40, 0x1a, 0x00, 0x11, 0x00, 0x6b, 0x04, 0xd2, 0x00,
    0x00, 0x2c, 0x23, 0x00, 0x80, 0x35, 0x02, 0x00, 0x90, 0x06, 0x80, 0x65,
    0x04, 0x00, 0x00, 0x00, 0x94, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x8b, 0x45, 0x62,
    0x89, 0x25, 0x96, 0x18, 0x12, 0x03, 0x90, 0x18, 0xc2, 0x42, 0x58, 0x00,
    0xc2, 0x42, 0x4a, 0x48, 0x09, 0x01, 0x21, 0x20, 0x00, 0x2b, 0x1d, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcb,
    0x08, 0x11, 0x6a, 0x8d, 0x48, 0x23, 0x0d, 0xa4, 0x81, 0x65, 0x84, 0x08,
    0xd0, 0x0c, 0x42, 0x11, 0x01, 0xd6, 0x08, 0xa4, 0x81, 0x65, 0x84, 0x08,
    0xb5, 0x46, 0x20, 0x0d, 0xa4, 0x81, 0x65, 0x84, 0x08, 0xb5, 0x46, 0x20,
    0x8d, 0x34, 0xd2, 0x48, 0x03, 0x6b, 0x04, 0x00, 0x20, 0x0d, 0x2c, 0x23,
    0x44, 0x80, 0x35, 0x02, 0x40, 0x1b, 0x08, 0x98, 0xc6, 0x32, 0x42, 0x04,
    0x58, 0x23, 0x90, 0x06, 0xd2, 0xc0, 0x32, 0x82, 0x35, 0x02, 0xcb, 0x08,
    0x11, 0x20, 0x19, 0x22, 0x00, 0x6b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0xd1, 0x00, 0x20, 0x25,
    0x84, 0x86, 0xcc, 0x90, 0x12, 0x12, 0x43, 0x6c, 0xc8, 0x0c, 0xa1, 0x21,
    0x25, 0x84, 0x86, 0xcc, 0x90, 0x12, 0x12, 0x43, 0x66, 0xc8, 0x0b, 0xc7,
    0xcd, 0x00, 0x00, 0x44, 0x60, 0x00, 0x48, 0x0c, 0x20, 0x02, 0x03, 0x40,
    0x70, 0x44, 0x20, 0x22, 0x00, 0x82, 0x23, 0x02, 0x24, 0x07, 0x10, 0x01,
    0x62, 0x23, 0x02, 0xa4, 0x87, 0xdc, 0x00, 0xc3, 0x0d, 0x40, 0x04, 0x06,
    0x80, 0xc4, 0x00, 0x22, 0x30, 0x00, 0x04, 0x87, 0xd8, 0x10, 0x1a, 0x11,
    0x20, 0x31, 0x80, 0x08, 0x10, 0x1a, 0x11, 0x20, 0xb8, 0xe4, 0xb2, 0x4b,
    0x0f, 0x03, 0x0e, 0x80, 0x00, 0x91, 0x1e, 0x80, 0xe4, 0x10, 0x21, 0x02,
    0x44, 0x7e, 0x08, 0x10, 0x11, 0x22, 0x3b, 0x00, 0xc1, 0x21, 0x33, 0xc4,
    0x06, 0x03, 0x0e, 0xf2, 0x03, 0x11, 0x00, 0xe9, 0x01, 0x00, 0x00, 0x00,
    0x00, 0x28, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x0d, 0x11, 0x20,
    0x33, 0x22, 0x30, 0x10, 0x1a, 0x88, 0x00, 0x48, 0x8c, 0x08, 0x1c, 0x1b,
    0x11, 0x20, 0x31, 0x22, 0x40, 0x70, 0xb1, 0x85, 0x86, 0xe0, 0x88, 0x00,
    0xb1, 0x21, 0x34, 0x22, 0x40, 0x66, 0x44, 0x80, 0xc4, 0x00, 0x00, 0x63,
    0x0d, 0xe7, 0x3f, 0x25, 0x24, 0x86, 0x94, 0x10, 0x16, 0x52, 0x42, 0x62,
    0x1c, 0x80, 0x94, 0x10, 0x5a, 0x66, 0x89, 0x85, 0x15, 0x55, 0x50, 0x29,
    0x05, 0x14, 0x4e, 0x3c, 0xf9, 0x04, 0x94, 0x52, 0x5a, 0x89, 0x05, 0x07,
    0x2b, 0x0d, 0xe7, 0x3f, 0x19, 0x24, 0x83, 0xa0, 0x90, 0x0c, 0x52, 0x42,
    0x58, 0xc8, 0x08, 0x29, 0x21, 0x19, 0x24, 0x83, 0xa0, 0x90, 0x17, 0xc2,
    0xe2, 0x00, 0xa4, 0x94, 0x53, 0x50, 0x61, 0x01, 0x63, 0x0d, 0xe7, 0x3f,
    0x31, 0x24, 0x83, 0xb0, 0x90, 0x12, 0x92, 0x41, 0x58, 0x44, 0x80, 0xc6,
    0x06, 0x80, 0x08, 0x90, 0x0c, 0xe7, 0x3f, 0x2c, 0xa4, 0x84, 0x64, 0x90,
    0x12, 0x92, 0xe1, 0x00, 0x84, 0x45, 0x04, 0xc8, 0x8b, 0x08, 0x00, 0xa3,
    0x0d, 0x11, 0x20, 0x36, 0x00, 0xc1, 0x11, 0x01, 0x81, 0xd0, 0x90, 0x5d,
    0x72, 0xc1, 0x21, 0x3b, 0xa4, 0x87, 0xfc, 0x88, 0x00, 0x11, 0x02, 0x08,
    0x0e, 0x99, 0x21, 0x36, 0x00, 0x6b, 0x14, 0x12, 0x00, 0x00, 0x80, 0x08,
    0x00, 0xc4, 0x10, 0x44, 0x16, 0x48, 0x03, 0x09, 0x20, 0x01, 0x00, 0x20,
    0x02, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x46, 0x01, 0x44, 0x40, 0x20, 0x0d,
    0x10, 0x01, 0x90, 0x06, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b,
    0x14, 0x00, 0x20, 0x15, 0x10, 0x01, 0x10, 0x08, 0x92, 0x40, 0x0c, 0xc8,
    0x02, 0x59, 0x00, 0x44, 0x80, 0x20, 0x88, 0xc0, 0x40, 0x06, 0x44, 0x60,
    0x20, 0x08, 0x00, 0x0b, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x14, 0x00, 0x20, 0x15, 0x10, 0x01,
    0x10, 0x08, 0x92, 0x40, 0x0c, 0x08, 0x02, 0x41, 0x00, 0x44, 0x80, 0x20,
    0x88, 0xc0, 0x40, 0x06, 0x44, 0x60, 0x20, 0x08, 0x00, 0x43, 0x19, 0x00,
    0x00, 0x00, 0x80, 0x8c, 0x40, 0x04, 0x40, 0x56, 0x00, 0x40, 0x04, 0x88,
    0x0a, 0x00, 0x88, 0x00, 0x41, 0x01, 0x44, 0x00, 0x3b, 0x19, 0x00, 0x10,
    0x01, 0x82, 0x22, 0x02, 0x44, 0x05, 0x00, 0x00, 0x00, 0x4a, 0x3f, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x23, 0x19, 0x00, 0x00, 0x00, 0x80, 0x98, 0x00,
    0x04, 0x05, 0x00, 0x00, 0x42, 0x02, 0x58, 0xf8, 0x00, 0x00, 0x1b, 0x19,
    0x00, 0x00, 0xa0, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x3b, 0x19, 0x80, 0x9c, 0x10, 0x14, 0x80, 0xa0, 0x10, 0x15, 0x00,
    0x0a, 0x3e, 0x80, 0xb4, 0x00, 0xa4, 0x85, 0xa8, 0x88, 0x00, 0x21, 0x11,
    0x01, 0x32, 0x22, 0x02, 0x00, 0x43, 0x19, 0x00, 0x0a, 0x3f, 0x80, 0xac,
    0x00, 0x50, 0xf8, 0x01, 0x44, 0x05, 0x80, 0xc2, 0x0f, 0x20, 0x26, 0xb0,
    0x06, 0x00, 0x00, 0x43, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x14, 0x80, 0x10, 0x10, 0x08, 0x80,
    0x2c, 0x10, 0x07, 0xf2, 0x40, 0x08, 0x00, 0x42, 0x40, 0x20, 0x00, 0xb2,
    0x40, 0x20, 0x81, 0x64, 0x11, 0x02, 0x5b, 0x14, 0x80, 0x2c, 0x90, 0x0b,
    0x80, 0x18, 0x90, 0x04, 0xa2, 0x40, 0x16, 0x00, 0xd2, 0x00, 0x10, 0x07,
    0x80, 0x3c, 0x58, 0xe0, 0x00, 0x63, 0x14, 0xc2, 0x00, 0x11, 0x00, 0x39,
    0x20, 0x0a, 0x84, 0x01, 0x22, 0x00, 0xa2, 0x40, 0x18, 0x08, 0x03, 0x44,
    0x00, 0xe4, 0x80, 0x3c, 0x10, 0x07, 0xc2, 0x40, 0x0a, 0x00, 0x3b, 0x14,
    0x72, 0x00, 0x90, 0x09, 0x80, 0x40, 0x10, 0x07, 0xb2, 0x40, 0x12, 0x39,
    0xe4, 0x92, 0x4a, 0x26, 0x81, 0xc4, 0x91, 0x44, 0x0e, 0x00, 0x92, 0x00,
    0x00, 0x5b, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x63, 0x14, 0x00, 0x00, 0x00, 0x80, 0x30, 0x00, 0xc4,
    0x01, 0x00, 0x00, 0x00, 0x20, 0x0e, 0x00, 0x83, 0x14, 0x00, 0x20, 0x10,
    0x10, 0x01, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x2b, 0x1d, 0x00, 0x00, 0x00, 0x86, 0x42, 0x00, 0x41, 0x11, 0x01, 0x82,
    0x02, 0x00, 0x84, 0x46, 0x04, 0x04, 0x42, 0x23, 0x02, 0x04, 0x05, 0x00,
    0x1b, 0x25, 0x00, 0x10, 0x01, 0xf2, 0x22, 0x02, 0x02, 0x19, 0x01, 0xc8,
    0x88, 0x08, 0x90, 0x17, 0x80, 0x8c, 0x00, 0x64, 0x84, 0xbc, 0x90, 0x11,
    0x00, 0x23, 0x25, 0x00, 0x10, 0x01, 0x02, 0x23, 0x02, 0x02, 0x21, 0x01,
    0x08, 0x89, 0x08, 0x10, 0x12, 0x00, 0x20, 0x30, 0x22, 0x20, 0x10, 0x18,
    0x11, 0x20, 0x24, 0x00, 0x5b, 0x25, 0x11, 0x20, 0x1f, 0x80, 0x08, 0x90,
    0x15, 0x11, 0x20, 0x2b, 0x22, 0x40, 0x3e, 0x00, 0x11, 0x20, 0x2b, 0x22,
    0x40, 0x56, 0x44, 0x80, 0x7c, 0x00, 0x22, 0x40, 0x3e, 0x00, 0xb2, 0x22,
    0x02, 0x02, 0xf9, 0x10, 0x01, 0x00, 0x23, 0x25, 0x80, 0x90, 0x88, 0x00,
    0x81, 0x81, 0x08, 0x80, 0xc0, 0x88, 0x00, 0x21, 0x01, 0x88, 0x09, 0x44,
    0x00, 0xc4, 0x44, 0x04, 0x88, 0x0c, 0x20, 0x02, 0x44, 0x46, 0x04, 0x88,
    0x89, 0x08, 0x10, 0x19, 0x11, 0x00, 0xa3, 0x25, 0x42, 0x0b, 0x2d, 0x34,
    0x22, 0x40, 0x50, 0x20, 0x02, 0x20, 0x28, 0x22, 0x40, 0x50, 0x08, 0x0d,
    0x41, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0x29, 0x42, 0x0b, 0x2a,
    0x34, 0x22, 0x40, 0x50, 0x20, 0x02, 0x20, 0x28, 0x22, 0x40, 0x50, 0x00,
    0x42, 0x43, 0x68, 0xa1, 0x85, 0x46, 0x04, 0x08, 0x0a, 0x44, 0x00, 0x04,
    0x45, 0x04, 0x08, 0x0a, 0xa1, 0x01, 0x0b, 0x25, 0x00, 0x00, 0x00, 0x00,
    0x00, 0xc8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x21, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b,
    0x1d, 0x00, 0x00, 0x18, 0x6b, 0x91, 0x12, 0x80, 0xb0, 0x90, 0x18, 0xc2,
    0x42, 0x4a, 0x08, 0x8d, 0x02, 0x90, 0x19, 0xc2, 0x42, 0x4a, 0x88, 0x0d,
    0xc3, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x0c,
    0xa1, 0xc5, 0x96, 0x5b, 0x70, 0xd9, 0xa5, 0x07, 0x03, 0x2e, 0x00, 0x00,
    0x48, 0x0f, 0x40, 0x80, 0x00, 0xf2, 0x23, 0x02, 0x64, 0x07, 0x22, 0x00,
    0x82, 0x03, 0x10, 0x1c, 0x11, 0x20, 0x3f, 0x64, 0x07, 0x03, 0x6e, 0x7e,
    0xe9, 0x05, 0x17, 0x5a, 0x66, 0xb1, 0x65, 0x16, 0x5a, 0x66, 0x89, 0x85,
    0x95, 0x57, 0x54, 0x99, 0xe5, 0x95, 0x18, 0x11, 0x20, 0x31, 0x22, 0x40,
    0x62, 0x44, 0x80, 0xc4, 0x00, 0x22, 0x40, 0x62, 0x44, 0x80, 0xf4, 0x88,
    0x00, 0x89, 0x11, 0x01, 0x00, 0x03, 0x2e, 0x12, 0x43, 0x62, 0x48, 0x0f,
    0x89, 0x21, 0x3d, 0x44, 0x18, 0x60, 0x7e, 0x08, 0x10, 0x89, 0x21, 0x31,
    0xa4, 0x87, 0xc4, 0x90, 0x1e, 0x22, 0x0c, 0x30, 0x3f, 0x00, 0xfb, 0x2d,
    0x02, 0x24, 0x02, 0x84, 0x48, 0x04, 0x48, 0x6f, 0xc4, 0x9e, 0x70, 0xd7,
    0xeb, 0xc5, 0x76, 0xc2, 0x1e, 0x70, 0x17, 0xeb, 0xe1, 0x76, 0xc0, 0xde,
    0x6f, 0xd7, 0xeb, 0xc5, 0x76, 0xbf, 0xde, 0x6e, 0x17, 0xeb, 0xe1, 0x76,
    0xbb, 0x1e, 0x6e, 0x87, 0xeb, 0xc5, 0x76, 0xc4, 0xde, 0x6e, 0x17, 0xeb,
    0xf5, 0x36, 0x3f, 0xa3, 0x0d, 0x00, 0x00, 0x48, 0x0c, 0x40, 0x68, 0x00,
    0x32, 0x03, 0x00, 0x00, 0x89, 0x01, 0xc8, 0x0b, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xbd, 0x26, 0xb1, 0xcc,
    0x00, 0x7f, 0x4d, 0x41, 0x00, 0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x21, 0x11, 0x20, 0x25, 0x80, 0x08,
    0x90, 0x58, 0x62, 0x29, 0x11, 0x01, 0x52, 0x22, 0x02, 0x00, 0x29, 0x11,
    0x01, 0x56, 0x52, 0x22, 0x00, 0x90, 0x12, 0x11, 0x60, 0x25, 0x24, 0x02,
    0x00, 0x29, 0x11, 0x01, 0x52, 0x22, 0x02, 0xa4, 0x44, 0x04, 0x00, 0xcf,
    0xcc, 0xc0, 0x11, 0x01, 0x52, 0x22, 0x02, 0xa4, 0x44, 0x04, 0x48, 0x86,
    0x08, 0x90, 0x12, 0x11, 0x20, 0x19, 0x22, 0x40, 0x4a, 0x44, 0x80, 0x94,
    0x88, 0x00, 0xc9, 0x10, 0x01, 0x52, 0x22, 0x02, 0xa4, 0x44, 0x04, 0x48,
    0x86, 0x08, 0x90, 0x12, 0x11, 0xa0, 0x99, 0x01, 0x68, 0x46, 0x80, 0x53,
    0x22, 0x02, 0xa4, 0x44, 0x04
};

volatile u8 callbackwait;
volatile u8 lastsample;

volatile u8 timetoplay;

volatile u8 test;
volatile u8 testwait;

u8 trackwait;
u8 trackpos;
u8 playsong;
u8 songpos;

u32 noiseseed = 1;

u8 light[2];

/*const u16 freqtable[] = {
0x010b, 0x011b, 0x012c, 0x013e, 0x0151, 0x0165, 0x017a, 0x0191, 0x01a9,
0x01c2, 0x01dd, 0x01f9, 0x0217, 0x0237, 0x0259, 0x027d, 0x02a3, 0x02cb,
0x02f5, 0x0322, 0x0352, 0x0385, 0x03ba, 0x03f3, 0x042f, 0x046f, 0x04b2,
0x04fa, 0x0546, 0x0596, 0x05eb, 0x0645, 0x06a5, 0x070a, 0x0775, 0x07e6,
0x085f, 0x08de, 0x0965, 0x09f4, 0x0a8c, 0x0b2c, 0x0bd6, 0x0c8b, 0x0d4a,
0x0e14, 0x0eea, 0x0fcd, 0x10be, 0x11bd, 0x12cb, 0x13e9, 0x1518, 0x1659,
0x17ad, 0x1916, 0x1a94, 0x1c28, 0x1dd5, 0x1f9b, 0x217c, 0x237a, 0x2596,
0x27d3, 0x2a31, 0x2cb3, 0x2f5b, 0x322c, 0x3528, 0x3851, 0x3bab, 0x3f37,
0x42f9, 0x46f5, 0x4b2d, 0x4fa6, 0x5462, 0x5967, 0x5eb7, 0x6459, 0x6a51,
0x70a3, 0x7756, 0x7e6f
};*/

const u16 freqtable[] = {
0x0085, 0x008d, 0x0096, 0x009f, 0x00a8, 0x00b2, 0x00bd, 0x00c8, 0x00d4,
0x00e1, 0x00ee, 0x00fc, 0x010b, 0x011b, 0x012c, 0x013e, 0x0151, 0x0165,
0x017a, 0x0191, 0x01a9, 0x01c2, 0x01dd, 0x01f9, 0x0217, 0x0237, 0x0259,
0x027d, 0x02a3, 0x02cb, 0x02f5, 0x0322, 0x0352, 0x0385, 0x03ba, 0x03f3,
0x042f, 0x046f, 0x04b2, 0x04fa, 0x0546, 0x0596, 0x05eb, 0x0645, 0x06a5,
0x070a, 0x0775, 0x07e6, 0x085f, 0x08de, 0x0965, 0x09f4, 0x0a8c, 0x0b2c,
0x0bd6, 0x0c8b, 0x0d4a, 0x0e14, 0x0eea, 0x0fcd, 0x10be, 0x11bd, 0x12cb,
0x13e9, 0x1518, 0x1659, 0x17ad, 0x1916, 0x1a94, 0x1c28, 0x1dd5, 0x1f9b,
0x217c, 0x237a, 0x2596, 0x27d3, 0x2a31, 0x2cb3, 0x2f5b, 0x322c, 0x3528,
0x3851, 0x3bab, 0x3f37
};

const s8 sinetable[] = {
0, 12, 25, 37, 49, 60, 71, 81, 90, 98, 106, 112, 117, 122, 125, 126,
127, 126, 125, 122, 117, 112, 106, 98, 90, 81, 71, 60, 49, 37, 25, 12,
0, -12, -25, -37, -49, -60, -71, -81, -90, -98, -106, -112, -117, -122,
-125, -126, -127, -126, -125, -122, -117, -112, -106, -98, -90, -81,
-71, -60, -49, -37, -25, -12
};

const u8 validcmds[] = "0dfijlmtvw~+=";

enum {
WF_TRI,
WF_SAW,
WF_PUL,
WF_NOI
};

volatile struct oscillator {
u16 freq;
u16 phase;
u16 duty;
u8 waveform;
u8 volume; // 0-255
} osc[4];

struct trackline {
u8 note;
u8 instr;
u8 cmd[2];
u8 param[2];
};

struct track {
struct trackline line[TRACKLEN];
};

struct unpacker {
u16 nextbyte;
u8 buffer;
u8 bits;
};

struct channel {
struct unpacker  trackup;
u8   tnum;
s8   transp;
u8   tnote;
u8   lastinstr;
u8   inum;
u16   iptr;
u8   iwait;
u8   inote;
s8   bendd;
s16   bend;
s8   volumed;
s16   dutyd;
u8   vdepth;
u8   vrate;
u8   vpos;
s16   inertia;
u16   slur;
} channel[4];

u16 resources[16 + MAXTRACK];

struct unpacker songup;

byte readsongbyte(u16 offset)
{
 
   return pgm_read_byte_near(&songdata[0] + offset);
}

void watchdogoff()
{
 
}

void initup(struct unpacker *up, u16 offset) {
up->nextbyte = offset;
up->bits = 0;
}

u8 readbit(struct unpacker *up) {
u8 val;

if(!up->bits) {
  up->buffer = readsongbyte(up->nextbyte++);
  up->bits = 8;
}

up->bits--;
val = up->buffer & 1;
up->buffer >>= 1;

return val;
}

u16 readchunk(struct unpacker *up, u8 n) {
u16 val = 0;
u8 i;

for(i = 0; i < n; i++) {
  if(readbit(up)) {
   val |= (1 << i);
  }
}

return val;
}

void readinstr(byte num, byte pos, byte *dest) {
dest[0] = readsongbyte(resources[num] + 2 * pos + 0);
dest[1] = readsongbyte(resources[num] + 2 * pos + 1);
}

void runcmd(u8 ch, u8 cmd, u8 param) {
switch(validcmds[cmd]) {
  case '0':
   channel[ch].inum = 0;
   break;
  case 'd':
   osc[ch].duty = param << 8;
   break;
  case 'f':
   channel[ch].volumed = param;
   break;
  case 'i':
   channel[ch].inertia = param << 1;
   break;
  case 'j':
   channel[ch].iptr = param;
   break;
  case 'l':
   channel[ch].bendd = param;
   break;
  case 'm':
   channel[ch].dutyd = param << 6;
   break;
  case 't':
   channel[ch].iwait = param;
   break;
  case 'v':
   osc[ch].volume = param;
   break;
  case 'w':
   osc[ch].waveform = param;
   break;
  case '+':
   channel[ch].inote = param + channel[ch].tnote - 12 * 4;
   break;
  case '=':
   channel[ch].inote = param;
   break;
  case '~':
   if(channel[ch].vdepth != (param >> 4)) {
    channel[ch].vpos = 0;
   }
   channel[ch].vdepth = param >> 4;
   channel[ch].vrate = param & 15;
   break;
}
}

void playroutine() {   // called at 50 Hz
u8 ch;
u8 lights;

if(playsong) {
  if(trackwait) {
   trackwait--;
  } else {
   trackwait = 4;

   if(!trackpos) {
    if(playsong) {
     if(songpos >= SONGLEN) {
      playsong = 0;
     } else {
      for(ch = 0; ch < 4; ch++) {
       u8 gottransp;
       u8 transp;

       gottransp = readchunk(&songup, 1);
       channel[ch].tnum = readchunk(&songup, 6);
       if(gottransp) {
        transp = readchunk(&songup, 4);
        if(transp & 0x8) transp |= 0xf0;
       } else {
        transp = 0;
       }
       channel[ch].transp = (s8) transp;
       if(channel[ch].tnum) {
        initup(&channel[ch].trackup, resources[16 + channel[ch].tnum - 1]);
       }
      }
      songpos++;
     }
    }
   }

   if(playsong) {
    for(ch = 0; ch < 4; ch++) {
     if(channel[ch].tnum) {
      u8 note, instr, cmd, param;
      u8 fields;

      fields = readchunk(&channel[ch].trackup, 3);
      note = 0;
      instr = 0;
      cmd = 0;
      param = 0;
      if(fields & 1) note = readchunk(&channel[ch].trackup, 7);
      if(fields & 2) instr = readchunk(&channel[ch].trackup, 4);
      if(fields & 4) {
       cmd = readchunk(&channel[ch].trackup, 4);
       param = readchunk(&channel[ch].trackup, 8);
      }
      if(note) {
       channel[ch].tnote = note + channel[ch].transp;
       if(!instr) instr = channel[ch].lastinstr;
      }
      if(instr) {
       if(instr == 2) light[1] = 5;
       if(instr == 1) {
        light[0] = 5;
        if(channel[ch].tnum == 4) {
         light[0] = light[1] = 3;
        }
       }
       if(instr == 7) {
        light[0] = light[1] = 30;
       }
       channel[ch].lastinstr = instr;
       channel[ch].inum = instr;
       channel[ch].iptr = 0;
       channel[ch].iwait = 0;
       channel[ch].bend = 0;
       channel[ch].bendd = 0;
       channel[ch].volumed = 0;
       channel[ch].dutyd = 0;
       channel[ch].vdepth = 0;
      }
      if(cmd) runcmd(ch, cmd, param);
     }
    }

    trackpos++;
    trackpos &= 31;
   }
  }
}

for(ch = 0; ch < 4; ch++) {
  s16 vol;
  u16 duty;
  u16 slur;

  while(channel[ch].inum && !channel[ch].iwait) {
   u8 il[2];

   readinstr(channel[ch].inum, channel[ch].iptr, il);
   channel[ch].iptr++;

   runcmd(ch, il[0], il[1]);
  }
  if(channel[ch].iwait) channel[ch].iwait--;

  if(channel[ch].inertia) {
   s16 diff;

   slur = channel[ch].slur;
   diff = freqtable[channel[ch].inote] - slur;
   //diff >>= channel[ch].inertia;
   if(diff > 0) {
    if(diff > channel[ch].inertia) diff = channel[ch].inertia;
   } else if(diff < 0) {
    if(diff < -channel[ch].inertia) diff = -channel[ch].inertia;
   }
   slur += diff;
   channel[ch].slur = slur;
  } else {
   slur = freqtable[channel[ch].inote];
  }
  osc[ch].freq =
   slur +
   channel[ch].bend +
   ((channel[ch].vdepth * sinetable[channel[ch].vpos & 63]) >> 2);
  channel[ch].bend += channel[ch].bendd;
  vol = osc[ch].volume + channel[ch].volumed;
  if(vol < 0) vol = 0;
  if(vol > 255) vol = 255;
  osc[ch].volume = vol;

  duty = osc[ch].duty + channel[ch].dutyd;
  if(duty > 0xe000) duty = 0x2000;
  if(duty < 0x2000) duty = 0xe000;
  osc[ch].duty = duty;

  channel[ch].vpos += channel[ch].vrate;
}

lights = 0;
if(light[0]) {
  light[0]--;
  lights |= 0x04;
}
if(light[1]) {
  light[1]--;
  lights |= 0x10;
}
PORTB = lights;
}

void initresources() {
u8 i;
struct unpacker up;

initup(&up, 0);
for(i = 0; i < 16 + MAXTRACK; i++) {
  resources[i] = readchunk(&up, 13);
}

initup(&songup, resources[0]);
}

int main() {
asm("cli");
watchdogoff();
CLKPR = 0x80;
CLKPR = 0x80;

DDRC = 0x12;
DDRD = 0xff;

//PORTC = 0;

        pinMode(10,OUTPUT);
        pinMode(12,OUTPUT);

         timetoplay = 0;
trackwait = 0;
trackpos = 0;
playsong = 1;
songpos = 0;

osc[0].volume = 0;
channel[0].inum = 0;
osc[1].volume = 0;
channel[1].inum = 0;
osc[2].volume = 0;
channel[2].inum = 0;
osc[3].volume = 0;
channel[3].inum = 0;

initresources();

TCCR0A = 0x02;
TCCR0B = 0x02; // clkIO/8, so 1/8 MHz
OCR0A = 125;//125; // 8 KHz

        TCCR2A=0b10100011;
        TCCR2B=0b00000001;

TIMSK0 = 0x02;

asm("sei");
for(;;) {
  while(!timetoplay);

  timetoplay--;
  playroutine();
}
}


ISR(TIMER0_COMPA_vect)  // called at 8 KHz
{
u8 i;
s16 acc;
u8 newbit;

OCR2B = lastsample;

newbit = 0;
if(noiseseed & 0x80000000L) newbit ^= 1;
if(noiseseed & 0x01000000L) newbit ^= 1;
if(noiseseed & 0x00000040L) newbit ^= 1;
if(noiseseed & 0x00000200L) newbit ^= 1;
noiseseed = (noiseseed << 1) | newbit;

if(callbackwait) {
  callbackwait--;
} else {
  timetoplay++;
  callbackwait = 180 - 1;
}

acc = 0;
for(i = 0; i < 4; i++) {
  s8 value; // [-32,31]

  switch(osc[i].waveform) {
   case WF_TRI:
    if(osc[i].phase < 0x8000) {
     value = -32 + (osc[i].phase >> 9);
    } else {
     value = 31 - ((osc[i].phase - 0x8000) >> 9);
    }
    break;
   case WF_SAW:
    value = -32 + (osc[i].phase >> 10);
    break;
   case WF_PUL:
    value = (osc[i].phase > osc[i].duty)? -32 : 31;
    break;
   case WF_NOI:
    value = (noiseseed & 63) - 32;
    break;
   default:
    value = 0;
    break;
  }
  osc[i].phase += osc[i].freq;

  acc += value * osc[i].volume; // rhs = [-8160,7905]
}
// acc [-32640,31620]
lastsample = 128 + (acc >> 8); // [1,251]
}

}

Step 4: Assembly.

You may be done with the software, but the hardware is not finished.

Take one of your speaker wires, and then plug it into pin 3. Then, plug the other end into ground...or 5 volts, your choice.

You should hear music playing.

Now, hit the reset button to here it from the beginning.

Step 5: Done.

Now listen to it play the tune.

Step 6: Adding a Jack.

Keep you eyes peeled for updates...

Step 7: Modulate It!

Connect an LED from pin 3 to ground.

Then, listen to it with the Light Listener.

Have fun!

Step 8: Make It Beatbox.

Here's the beatbox code:

#include 
#include 
#include 

#define TRACKLEN 32
#define MAXTRACK	0x92
#define SONGLEN		0x37

#include 

extern "C" {
  
typedef unsigned char u8;
typedef unsigned short u16;
typedef char s8;
typedef short s16;
typedef unsigned long u32;

byte songdata[] PROGMEM = {
   0x34,0x80,0x0d,0xe4,0x01,0x41,0x30,0x09,0x34,0x41,0x2c,0xd0,0x05,0xc3,0x80,0x18,
0x14,0x03,0x63,0x70,0x0c,0x90,0x41,0x32,0x50,0x06,0xcb,0xe0,0x1b,0xcc,0x83,0x83,
0xb0,0x11,0x5e,0x42,0x51,0xd8,0x0a,0x6f,0x61,0x30,0x5c,0x86,0xd5,0x40,0x1c,0xbc,
0xc3,0x7d,0x80,0x10,0x02,0x08,0x06,0x40,0x90,0x60,0x00,0x06,0x08,0x06,0x80,0x90,
0x60,0x00,0x0a,0x08,0x06,0xc0,0xb0,0x60,0x00,0x0a,0x08,0x06,0xe0,0xa0,0x68,0x40,
0x02,0x08,0x86,0x43,0x90,0x60,0x00,0x06,0x08,0xc6,0x83,0x90,0x60,0x00,0x0a,0x08,
0x86,0xc3,0xb0,0x60,0x00,0x0a,0x08,0x86,0xe3,0xa0,0x68,0x40,0x09,0x02,0x08,0xa0,
0x01,0x80,0x0b,0x19,0x07,0x04,0x02,0xe8,0x00,0x09,0x00,0x08,0xff,0x0b,0x25,0x02,
0xf0,0x00,0x09,0x03,0x08,0xff,0x07,0x01,0x09,0x02,0x01,0x90,0x0b,0x31,0x05,0xa0,
0x02,0xf0,0x00,0x09,0x03,0x08,0x80,0x02,0xe0,0x00,0x09,0x03,0x08,0xff,0x07,0x01,
0x09,0x02,0x01,0x90,0x0b,0x31,0x05,0xa0,0x07,0x02,0x09,0x03,0x08,0x80,0x02,0xf0,
0x00,0x09,0x01,0x08,0x60,0x0b,0x31,0x02,0xf8,0x00,0x09,0x01,0x08,0xc0,0x0b,0x31,
0x02,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xeb,0x04,0x80,0xa4,0x00,
0xa4,0x03,0x20,0x29,0x00,0xe9,0x00,0x48,0x0a,0x40,0x3a,0x00,0x92,0x02,0x00,0xeb,
0x04,0x80,0xa4,0x00,0xa4,0x03,0x20,0x29,0x00,0xe9,0x00,0x48,0x0a,0x40,0x3e,0x00,
0xb2,0x02,0x00,0x03,0x05,0x80,0xb0,0x00,0x04,0x04,0x20,0x2c,0x00,0x01,0x01,0x08,
0x0b,0x40,0x40,0x00,0xc2,0x02,0x00,0x03,0x05,0x80,0xb0,0x00,0x04,0x04,0x20,0x2c,
0x00,0x01,0x01,0x08,0x0b,0x40,0x44,0x00,0xe2,0x02,0x00,0x23,0x05,0x80,0xc0,0x00,
0x84,0x04,0x20,0x30,0x00,0x21,0x01,0x08,0x0c,0x40,0x48,0x00,0x02,0x03,0x00,0x23,
0x05,0x80,0xc0,0x00,0x84,0x04,0x20,0x30,0x00,0x21,0x01,0x08,0x09,0x81,0x21,0x22,
0x00,0x71,0x21,0x22,0x00,0x23,0x05,0x80,0xc0,0x00,0x84,0x04,0x20,0x30,0x00,0xd9,
0x00,0xc8,0x09,0x40,0x36,0xc8,0x06,0x39,0x21,0x27,0x00,0xab,0x09,0x80,0xc0,0x00,
0x64,0x06,0x20,0x35,0x00,0xa9,0x01,0x08,0x0c,0x40,0x66,0x00,0x52,0x03,0x00,0xab,
0x09,0x80,0xc0,0x00,0x64,0x06,0x20,0x35,0x00,0xa9,0x01,0x08,0x0e,0x40,0x6e,0x00,
0x52,0x03,0x00,0xab,0x09,0x80,0xc0,0x00,0x64,0x06,0x20,0x30,0x00,0xc1,0x01,0xc8,
0x0d,0x40,0x6a,0x00,0x32,0x03,0x00,0xab,0x09,0x80,0xc0,0x00,0x64,0x06,0x20,0x35,
0x00,0xa9,0x01,0x08,0x0c,0x40,0x66,0x00,0x02,0x03,0x00,0xcb,0x0c,0x80,0x95,0x08,
0x29,0x61,0x99,0x02,0xb0,0x12,0x01,0x58,0x66,0xb0,0x12,0x21,0x25,0x00,0xcb,0x14,
0x80,0x95,0x08,0x00,0xcb,0x0c,0x80,0x95,0x08,0x29,0x61,0x99,0x02,0xb0,0x12,0x01,
0x58,0x66,0x90,0x0c,0x80,0x64,0xb0,0x4c,0x21,0x19,0x2c,0x33,0x00,0x00,0x83,0x1d,
0x80,0xc1,0x0c,0x4b,0x1d,0x80,0x9c,0x90,0x14,0x76,0x32,0x0c,0x76,0x00,0x06,0x33,
0x2c,0x75,0x00,0x96,0x32,0x00,0x00,0x63,0x1d,0x80,0xb1,0x0c,0x73,0x1d,0x80,0xc4,
0x10,0x18,0x76,0x32,0x8c,0x75,0x00,0x06,0x33,0xcc,0x75,0x00,0xe6,0x32,0x00,0x00,
0x00,0x00,0x00,0x00,0x30,0xd8,0x01,0x88,0x0b,0x40,0x58,0x00,0x72,0x42,0x52,0x58,
0xca,0x00,
};

volatile u8 callbackwait;
volatile u8 lastsample;

volatile u8 timetoplay;

volatile u8 test;
volatile u8 testwait;

u8 trackwait;
u8 trackpos;
u8 playsong;
u8 songpos;

u32 noiseseed = 1;

u8 light[2];

/*const u16 freqtable[] = {
	0x010b, 0x011b, 0x012c, 0x013e, 0x0151, 0x0165, 0x017a, 0x0191, 0x01a9,
	0x01c2, 0x01dd, 0x01f9, 0x0217, 0x0237, 0x0259, 0x027d, 0x02a3, 0x02cb,
	0x02f5, 0x0322, 0x0352, 0x0385, 0x03ba, 0x03f3, 0x042f, 0x046f, 0x04b2,
	0x04fa, 0x0546, 0x0596, 0x05eb, 0x0645, 0x06a5, 0x070a, 0x0775, 0x07e6,
	0x085f, 0x08de, 0x0965, 0x09f4, 0x0a8c, 0x0b2c, 0x0bd6, 0x0c8b, 0x0d4a,
	0x0e14, 0x0eea, 0x0fcd, 0x10be, 0x11bd, 0x12cb, 0x13e9, 0x1518, 0x1659,
	0x17ad, 0x1916, 0x1a94, 0x1c28, 0x1dd5, 0x1f9b, 0x217c, 0x237a, 0x2596,
	0x27d3, 0x2a31, 0x2cb3, 0x2f5b, 0x322c, 0x3528, 0x3851, 0x3bab, 0x3f37,
	0x42f9, 0x46f5, 0x4b2d, 0x4fa6, 0x5462, 0x5967, 0x5eb7, 0x6459, 0x6a51,
	0x70a3, 0x7756, 0x7e6f
};*/

const u16 freqtable[] = {
	0x0085, 0x008d, 0x0096, 0x009f, 0x00a8, 0x00b2, 0x00bd, 0x00c8, 0x00d4,
	0x00e1, 0x00ee, 0x00fc, 0x010b, 0x011b, 0x012c, 0x013e, 0x0151, 0x0165,
	0x017a, 0x0191, 0x01a9, 0x01c2, 0x01dd, 0x01f9, 0x0217, 0x0237, 0x0259,
	0x027d, 0x02a3, 0x02cb, 0x02f5, 0x0322, 0x0352, 0x0385, 0x03ba, 0x03f3,
	0x042f, 0x046f, 0x04b2, 0x04fa, 0x0546, 0x0596, 0x05eb, 0x0645, 0x06a5,
	0x070a, 0x0775, 0x07e6, 0x085f, 0x08de, 0x0965, 0x09f4, 0x0a8c, 0x0b2c,
	0x0bd6, 0x0c8b, 0x0d4a, 0x0e14, 0x0eea, 0x0fcd, 0x10be, 0x11bd, 0x12cb,
	0x13e9, 0x1518, 0x1659, 0x17ad, 0x1916, 0x1a94, 0x1c28, 0x1dd5, 0x1f9b,
	0x217c, 0x237a, 0x2596, 0x27d3, 0x2a31, 0x2cb3, 0x2f5b, 0x322c, 0x3528,
	0x3851, 0x3bab, 0x3f37
};

const s8 sinetable[] = {
	0, 12, 25, 37, 49, 60, 71, 81, 90, 98, 106, 112, 117, 122, 125, 126,
	127, 126, 125, 122, 117, 112, 106, 98, 90, 81, 71, 60, 49, 37, 25, 12,
	0, -12, -25, -37, -49, -60, -71, -81, -90, -98, -106, -112, -117, -122,
	-125, -126, -127, -126, -125, -122, -117, -112, -106, -98, -90, -81,
	-71, -60, -49, -37, -25, -12
};

const u8 validcmds[] = "0dfijlmtvw~+=";

enum {
	WF_TRI,
	WF_SAW,
	WF_PUL,
	WF_NOI
};

volatile struct oscillator {
	u16	freq;
	u16	phase;
	u16	duty;
	u8	waveform;
	u8	volume;	// 0-255
} osc[4];

struct trackline {
	u8	note;
	u8	instr;
	u8	cmd[2];
	u8	param[2];
	};

struct track {
	struct trackline	line[TRACKLEN];
};

struct unpacker {
	u16	nextbyte;
	u8	buffer;
	u8	bits;
};

struct channel {
	struct unpacker		trackup;
	u8			tnum;
	s8			transp;
	u8			tnote;
	u8			lastinstr;
	u8			inum;
	u16			iptr;
	u8			iwait;
	u8			inote;
	s8			bendd;
	s16			bend;
	s8			volumed;
	s16			dutyd;
	u8			vdepth;
	u8			vrate;
	u8			vpos;
	s16			inertia;
	u16			slur;
} channel[4];

u16 resources[16 + MAXTRACK];

struct unpacker songup;

byte readsongbyte(u16 offset)
{
  
   return pgm_read_byte_near(&songdata[0] + offset); 
}

void watchdogoff()
{
  
}

void initup(struct unpacker *up, u16 offset) {
	up->nextbyte = offset;
	up->bits = 0;
}

u8 readbit(struct unpacker *up) {
	u8 val;

	if(!up->bits) {
		up->buffer = readsongbyte(up->nextbyte++);
		up->bits = 8;
	}

	up->bits--;
	val = up->buffer & 1;
	up->buffer >>= 1;

	return val;
}

u16 readchunk(struct unpacker *up, u8 n) {
	u16 val = 0;
	u8 i;

	for(i = 0; i < n; i++) {
		if(readbit(up)) {
			val |= (1 << i);
		}
	}

	return val;
}

void readinstr(byte num, byte pos, byte *dest) {
	dest[0] = readsongbyte(resources[num] + 2 * pos + 0);
	dest[1] = readsongbyte(resources[num] + 2 * pos + 1);
}

void runcmd(u8 ch, u8 cmd, u8 param) {
	switch(validcmds[cmd]) {
		case '0':
			channel[ch].inum = 0;
			break;
		case 'd':
			osc[ch].duty = param << 8;
			break;
		case 'f':
			channel[ch].volumed = param;
			break;
		case 'i':
			channel[ch].inertia = param << 1;
			break;
		case 'j':
			channel[ch].iptr = param;
			break;
		case 'l':
			channel[ch].bendd = param;
			break;
		case 'm':
			channel[ch].dutyd = param << 6;
			break;
		case 't':
			channel[ch].iwait = param;
			break;
		case 'v':
			osc[ch].volume = param;
			break;
		case 'w':
			osc[ch].waveform = param;
			break;
		case '+':
			channel[ch].inote = param + channel[ch].tnote - 12 * 4;
			break;
		case '=':
			channel[ch].inote = param;
			break;
		case '~':
			if(channel[ch].vdepth != (param >> 4)) {
				channel[ch].vpos = 0;
			}
			channel[ch].vdepth = param >> 4;
			channel[ch].vrate = param & 15;
			break;
	}
}

void initresources() {
	u8 i;
	struct unpacker up;

	initup(&up, 0);
	for(i = 0; i < 16 + MAXTRACK; i++) {
		resources[i] = readchunk(&up, 13);
	}

	initup(&songup, resources[0]);
}

void playroutine() {			// called at 50 Hz
	u8 ch;
	u8 lights;

	if(playsong) {
		if(trackwait) {
			trackwait--;
		} else {
			trackwait = 4;

			if(!trackpos) {
				if(playsong) {
					if(songpos >= SONGLEN) {
						//playsong = 0;
                                                songpos=0;
                                                trackpos=0;
                                                initresources();
					} else {
						for(ch = 0; ch < 4; ch++) {
							u8 gottransp;
							u8 transp;

							gottransp = readchunk(&songup, 1);
							channel[ch].tnum = readchunk(&songup, 6);
							if(gottransp) {
								transp = readchunk(&songup, 4);
								if(transp & 0x8) transp |= 0xf0;
							} else {
								transp = 0;
							}
							channel[ch].transp = (s8) transp;
							if(channel[ch].tnum) {
								initup(&channel[ch].trackup, resources[16 + channel[ch].tnum - 1]);
							}
						}
						songpos++;
					}
				}
			}

			if(playsong) {
				for(ch = 0; ch < 4; ch++) {
					if(channel[ch].tnum) {
						u8 note, instr, cmd, param;
						u8 fields;

						fields = readchunk(&channel[ch].trackup, 3);
						note = 0;
						instr = 0;
						cmd = 0;
						param = 0;
						if(fields & 1) note = readchunk(&channel[ch].trackup, 7);
						if(fields & 2) instr = readchunk(&channel[ch].trackup, 4);
						if(fields & 4) {
							cmd = readchunk(&channel[ch].trackup, 4);
							param = readchunk(&channel[ch].trackup, 8);
						}
						if(note) {
							channel[ch].tnote = note + channel[ch].transp;
							if(!instr) instr = channel[ch].lastinstr;
						}
						if(instr) {
							if(instr == 2) light[1] = 5;
							if(instr == 1) {
								light[0] = 5;
								if(channel[ch].tnum == 4) {
									light[0] = light[1] = 3;
								}
							}
							if(instr == 7) {
								light[0] = light[1] = 30;
							}
							channel[ch].lastinstr = instr;
							channel[ch].inum = instr;
							channel[ch].iptr = 0;
							channel[ch].iwait = 0;
							channel[ch].bend = 0;
							channel[ch].bendd = 0;
							channel[ch].volumed = 0;
							channel[ch].dutyd = 0;
							channel[ch].vdepth = 0;
						}
						if(cmd) runcmd(ch, cmd, param);
					}
				}

				trackpos++;
				trackpos &= 31;
			}
		}
	}

	for(ch = 0; ch < 4; ch++) {
		s16 vol;
		u16 duty;
		u16 slur;

		while(channel[ch].inum && !channel[ch].iwait) {
			u8 il[2];

			readinstr(channel[ch].inum, channel[ch].iptr, il);
			channel[ch].iptr++;

			runcmd(ch, il[0], il[1]);
		}
		if(channel[ch].iwait) channel[ch].iwait--;

		if(channel[ch].inertia) {
			s16 diff;

			slur = channel[ch].slur;
			diff = freqtable[channel[ch].inote] - slur;
			//diff >>= channel[ch].inertia;
			if(diff > 0) {
				if(diff > channel[ch].inertia) diff = channel[ch].inertia;
			} else if(diff < 0) {
				if(diff < -channel[ch].inertia) diff = -channel[ch].inertia;
			}
			slur += diff;
			channel[ch].slur = slur;
		} else {
			slur = freqtable[channel[ch].inote];
		}
		osc[ch].freq =
			slur +
			channel[ch].bend +
			((channel[ch].vdepth * sinetable[channel[ch].vpos & 63]) >> 2);
		channel[ch].bend += channel[ch].bendd;
		vol = osc[ch].volume + channel[ch].volumed;
		if(vol < 0) vol = 0;
		if(vol > 255) vol = 255;
		osc[ch].volume = vol;

		duty = osc[ch].duty + channel[ch].dutyd;
		if(duty > 0xe000) duty = 0x2000;
		if(duty < 0x2000) duty = 0xe000;
		osc[ch].duty = duty;

		channel[ch].vpos += channel[ch].vrate;
	}

	lights = 0;
	if(light[0]) {
		light[0]--;
		lights |= 0x04;
	}
	if(light[1]) {
		light[1]--;
		lights |= 0x10;
	}
	PORTB = lights;
}



int main() {
	asm("cli");
	watchdogoff();
	CLKPR = 0x80;
	CLKPR = 0x80;

	DDRC = 0x12;
	DDRD = 0xff;

	//PORTC = 0;

        pinMode(10,OUTPUT);
        pinMode(12,OUTPUT);
	
         timetoplay = 0;
	trackwait = 0;
	trackpos = 0;
	playsong = 1;
	songpos = 0;

	osc[0].volume = 0;
	channel[0].inum = 0;
	osc[1].volume = 0;
	channel[1].inum = 0;
	osc[2].volume = 0;
	channel[2].inum = 0;
	osc[3].volume = 0;
	channel[3].inum = 0;

	initresources();

	TCCR0A = 0x02;
	TCCR0B = 0x02;	// clkIO/8, so 1/8 MHz
	OCR0A = 125;//125; // 8 KHz

        TCCR2A=0b10100011;
        TCCR2B=0b00000001;

	TIMSK0 = 0x02;

	asm("sei");
	for(;;) {
		while(!timetoplay);

		timetoplay--;
		playroutine();
	}
}


ISR(TIMER0_COMPA_vect)		// called at 8 KHz
{
	u8 i;
	s16 acc;
	u8 newbit;

	OCR2B = lastsample;

	newbit = 0;
	if(noiseseed & 0x80000000L) newbit ^= 1;
	if(noiseseed & 0x01000000L) newbit ^= 1;
	if(noiseseed & 0x00000040L) newbit ^= 1;
	if(noiseseed & 0x00000200L) newbit ^= 1;
	noiseseed = (noiseseed << 1) | newbit;

	if(callbackwait) {
		callbackwait--;
	} else {
		timetoplay++;
		callbackwait = 180 - 1;
	}

	acc = 0;
	for(i = 0; i < 4; i++) {
		s8 value; // [-32,31]

		switch(osc[i].waveform) {
			case WF_TRI:
				if(osc[i].phase < 0x8000) {
					value = -32 + (osc[i].phase >> 9);
				} else {
					value = 31 - ((osc[i].phase - 0x8000) >> 9);
				}
				break;
			case WF_SAW:
				value = -32 + (osc[i].phase >> 10);
				break;
			case WF_PUL:
				value = (osc[i].phase > osc[i].duty)? -32 : 31;
				break;
			case WF_NOI:
				value = (noiseseed & 63) - 32;
				break;
			default:
				value = 0;
				break;
		}
		osc[i].phase += osc[i].freq;

		acc += value * osc[i].volume; // rhs = [-8160,7905]
	}
	// acc [-32640,31620]
	lastsample = 128 + (acc >> 8);	// [1,251]
}

}

Comments

author
eseixa made it! (author)2017-06-01

Hi all!

For everyone that need, here another code:

http://aliencrack.ucoz.ru/Files/articles/AHCP/Hard...

enjoy.

author
eseixa made it! (author)eseixa2017-06-01

PS: Need put "const" at the beginning at 36 st line, before "byte"

Like this:

const byte songdata[] PROGMEM = {

author
joostvanpoppel made it! (author)2016-05-22

Stumbled on this project today, didn't know it was possible to do this :-)

These questions arise quickly:

- Are there other tunes available?

- Is there an easy way to add songs?

Thx,

Joost

author
blinkyblinky made it! (author)blinkyblinky2016-05-22

In terms of making a tune or adding songs, you have to "compose" them yourself. You need to be able to use something called a tracker. Once you know how to use them, there is a tutorial with a link to the software to generate the array here. So if you were looking for a very quick way to load songs on this, no it's not very possible. I may upload an 'ible soon discussing a thing that can play more easily loadable songs, but as of right now I am super busy.

author
alaafprojs made it! (author)alaafprojs2017-01-01

I tried that but...

it seems that the software is for linux, I have windows.

is there a alternative?

thanks :-)

author
jʎɐɹ-ɾ made it! (author)jʎɐɹ-ɾ2016-08-18

okay, settle down

author
blinkyblinky made it! (author)blinkyblinky2016-05-22

In terms of making a tune or adding songs, you have to "compose" them yourself. You need to be able to use something called a tracker. Once you know how to use them, there is a tutorial with a link to the software to generate the array here. So if you were looking for a very quick way to load songs on this, no it's not very possible. I may upload an 'ible soon discussing a thing that can play more easily loadable songs, but as of right now I am super busy.

author
blinkyblinky made it! (author)blinkyblinky2016-05-22

In terms of making a tune or adding songs, you have to "compose" them yourself. You need to be able to use something called a tracker. Once you know how to use them, there is a tutorial with a link to the software to generate the array here. So if you were looking for a very quick way to load songs on this, no it's not very possible. I may upload an 'ible soon discussing a thing that can play more easily loadable songs, but as of right now I am super busy.

author
blinkyblinky made it! (author)blinkyblinky2016-05-22

In terms of making a tune or adding songs, you have to "compose" them yourself. You need to be able to use something called a tracker. Once you know how to use them, there is a tutorial with a link to the software to generate the array here. So if you were looking for a very quick way to load songs on this, no it's not very possible. I may upload an 'ible soon discussing a thing that can play more easily loadable songs, but as of right now I am super busy.

author
blinkyblinky made it! (author)blinkyblinky2016-05-22

In terms of making a tune or adding songs, you have to "compose" them yourself. You need to be able to use something called a tracker. Once you know how to use them, there is a tutorial with a link to the software to generate the array here. So if you were looking for a very quick way to load songs on this, no it's not very possible. I may upload an 'ible soon discussing a thing that can play more easily loadable songs, but as of right now I am super busy.

author
blinkyblinky made it! (author)blinkyblinky2016-05-22

In terms of making a tune or adding songs, you have to "compose" them yourself. You need to be able to use something called a tracker. Once you know how to use them, there is a tutorial with a link to the software to generate the array here. So if you were looking for a very quick way to load songs on this, no it's not very possible. I may upload an 'ible soon discussing a thing that can play more easily loadable songs, but as of right now I am super busy.

author
blinkyblinky made it! (author)blinkyblinky2016-05-22

In terms of making a tune or adding songs, you have to "compose" them yourself. You need to be able to use something called a tracker. Once you know how to use them, there is a tutorial with a link to the software to generate the array here. So if you were looking for a very quick way to load songs on this, no it's not very possible. I may upload an 'ible soon discussing a thing that can play more easily loadable songs, but as of right now I am super busy.

author
blinkyblinky made it! (author)blinkyblinky2016-05-22

In terms of making a tune or adding songs, you have to "compose" them yourself. You need to be able to use something called a tracker. Once you know how to use them, there is a tutorial with a link to the software to generate the array here. So if you were looking for a very quick way to load songs on this, no it's not very possible. I may upload an 'ible soon discussing a thing that can play more easily loadable songs, but as of right now I am super busy.

author
Raphango made it! (author)2016-09-08

Awesome! :D

author
Raphango made it! (author)Raphango2016-09-08

Nice song btw!

author
kd8bxp made it! (author)2016-09-06

Very much the same as the instructable -I used a old Dell amplified speaker out of a old desktop computer - they work very well for this project. But take one extra wire :-)

2016-09-06 15.50.59.jpg2016-09-06 15.51.02.jpg
author
Strx made it! (author)2016-07-15

Nice , l liked it!. I love these kinds of project where you can create something satisfying with few components. Took me 5 minutes from start to finding and connecting a speaker. Also my first (and certainly not my last) project with a speaker.

DSC_1403.JPG
author
R Jordan Kreindler made it! (author)2016-07-11

Very interesting.

author
duBtrotterS made it! (author)2016-06-03

Could someone please explain adding LEDs and creating a loop as well. thanks

author
NekoBeMe made it! (author)NekoBeMe2016-06-19

Step one: Visit Arduino website.

Step two: Rejoice

author
duBtrotterS made it! (author)2016-06-10

Very cool project! This was my first project to utilize a speaker...

IMG_20160610_175540.jpg
author
alaafprojs made it! (author)2016-06-02

I like it!

Photo on 2016-06-02 at 12.40.jpg
author
Neiljams made it! (author)2016-05-19

Super freakn awesome!

20160519_105159.jpg
author
JamesZ16 made it! (author)2016-04-15

thanks super easy and fun. need some mega man 2 up in here!!

20160415_120958.jpg
author
RA productions made it! (author)2016-03-01

blinkyblinky, is there any way that i can play a previously recorded sound? Instead of the song, its awesome by the way.

author
ArduinoUshiroma made it! (author)2016-02-14

can I get all this as pdf?

author
ArduinoUshiroma made it! (author)ArduinoUshiroma2016-02-22

Don't see it. Maybe its cuz I'm using mobile

author
blinkyblinky made it! (author)blinkyblinky2016-02-14

There is a download as PDF function right below the title.

author
koubis made it! (author)2016-01-12

This is soo funny. Would you post please more info on coding and a link to some basic description how those sound are generated? Just frequency and timing?

author
blinkyblinky made it! (author)blinkyblinky2016-02-14

Sorry for the late response. The songdata is really the most vital part of the code, as well as these three lines:

#define TRACKLEN 32

#define MAXTRACK 0x92

#define SONGLEN 0x37

In order to generate your own tunes (which is not that easy) you need to know how to use a tracker, if you already know it, here is a guide to generating your own music. This tracker operates in the Linux terminal (or a Windows program that is not the command line and can run Linux files), so you will likely need to know your way around the Linux terminal as well.

author
deepak_paryani made it! (author)2016-02-06

Cool! I liked the music!

just songdata[] has to be const

Snapshot_20160206.JPG
author
Marethno made it! (author)2015-12-10

I love Chiptune Music - so i made this project - Thanks very nice

DSC_0383.JPG
author
ankur sharma made it! (author)2015-11-21

sir can I have a downloadable file for second code

author
ankur sharma made it! (author)2015-11-21

sir can I have a downloadable file for second code

author
sluis made it! (author)2015-11-18

It sounds like the mid of giana sisters ;-) A game on commodore C-64!!

author
KomeylD made it! (author)2015-07-12

i'm new to arduino.

i received this error in compiling:

Arduino: 1.6.5 (Windows 8.1), Board: "Arduino Uno"

In file included from ChiptunesLightsLinus.ino:9:0:
ChiptunesLightsLinus:19: error: variable 'songdata' must be const in order to be put into read-only section by means of '__attribute__((progmem))'
variable 'songdata' must be const in order to be put into read-only section by means of '__attribute__((progmem))'

This report would have more information with
"Show verbose output during compilation"
enabled in File > Preferences.

author
ChrisC54 made it! (author)ChrisC542015-07-16

I got the same error, and got it to compile by adding the keyword "const" at the beginning of the line so it looks like this: const byte songdata[] PROGMEM = {

I have to hunt down a speaker, though, so I don't know if the code actually works, just that it compiles.

author
leon.bed.3 made it! (author)leon.bed.32015-11-17

That worked for me!

Thanks!

author
El Mutante made it! (author)2015-11-04

A wee bit quiet through the tiny speaker I used. Works thanks to that code correction. The beat box code only seems to produce a few glitchy noises and a high pitched whine though.

Photo0426.jpg
author
benediktsamson made it! (author)2015-09-23

author
YuriSantosTeixeira made it! (author)2015-09-11

Used an earphone and a small speaker, both with an amplifier. Nice sound and easily done.

20150912_000132.jpg
author
Rodrigomecanica made it! (author)2015-07-07

It's so funny

temp_-66944201.jpg
author
_Ry_ made it! (author)2015-05-13

Thank you, blinkyblinky

On 1.6.4 I changed "byte songdata[] PROGMEM = {"

to "const PROGMEM byte songdata[] = {"

and it compiled for me.

http://www.arduino.cc/en/Reference/PROGMEM

author
ChrisF17 made it! (author)ChrisF172015-06-06

Making this change allowed it to compile on mine, but the code seems to do absolutely nothing.

author
SteelTurtle made it! (author)2015-05-06

First of all, thank you very much for guide.

Is there a way to add a loop, so that the music repeats itself when it's over?

Thanks

author
Magitor made it! (author)2015-04-05

i got:
In file included from chiptune.ino:10:0:

chiptune.ino:20:17: error: variable 'songdata' must be const in order to be put into read-only section by means of '__attribute__((progmem))'

author
krispykreme.mcdonald.5 made it! (author)2015-03-19

Error compiling is what my arduino says

author
blinkyblinky made it! (author)blinkyblinky2015-03-31

Arduino 1.6.0 and beyond has problems with older code because some variable declarations have changed; revert back to Arduino 1.0.6 or something older and it should work but not before arduino 1.0 though.

Just the other day I was trying to compile some other code and found out that instead of just byte [variable name] I have to declare byte PROGMEM [variable name] in order to make it work; something similar may have happened with the Octosynth code so try an older build of Arduino such as Arduino 1.0.6 or prior.

author
hoàng huyđ made it! (author)2015-03-15

How i can do it with LEONARDO?????
Can you help me in Code?

author
blinkyblinky made it! (author)blinkyblinky2015-03-31

It should work without problems. If so, try an older version of Arduino such as 1.0.6 as I have been finding out that Arduino 1.6.1 has some issues with older code.

About This Instructable

75,368views

329favorites

License:

Bio: I love building things and taking pictures. If you want me to build something...I'm open to ideas. My motto? "If you want something ... More »
More by blinkyblinky:Keeping Up Appearances with ChindoguA Complete Beginner's Guide to Raw Files And Raw ProcessingHypercard - An Impossible Paper Object
Add instructable to: