Arduino Chiptunes (8 / 8 steg)
Steg 8: Gör det Beatbox.
Här är beatbox koden:
#include
#include
#include
#define TRACKLEN 32
#define MAXTRACK 0x92
#define SONGLEN 0x37
#include
extern "C" {
TypeDef unsigned char u8;
TypeDef unsigned kort u16;
TypeDef char s8;
TypeDef kort 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,
};
flyktiga u8 callbackwait;
flyktiga u8 lastsample;
flyktiga u8 timetoplay;
flyktiga u8 test;
flyktiga u8 testwait;
U8 trackwait;
U8 trackpos;
U8 playsong;
U8 songpos;
U32 noiseseed = 1;
U8 ljus [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 ~ +=";
fasttexttypen {
WF_TRI,
WF_SAW,
WF_PUL,
WF_NOI
};
flyktiga struct oscillator {
U16 freq;
U16 fas;
U16 tull.
U8 vågform;
U8 volym; 0-255
} osc [4].
struct trackline {
U8 Obs;
U8 instr;
U8 cmd [2].
U8 param [2].
};
struct spår {
struct trackline linje [TRACKLEN];
};
struct unpacker {
U16 nextbyte;
U8 buffert;
U8 bitar;
};
struct kanal {
struct unpacker trackup;
U8 tnum;
S8 transp;
U8 tnote;
U8 lastinstr;
U8 inum;
U16 iptr;
U8 iwait;
U8 inote;
S8 bendd;
S16 krök;
S8 volumed;
S16 dutyd;
U8 vdepth;
U8 vrate;
U8 vpos;
S16 tröghet;
U16 förtal;
} kanal [4];
U16 resurser [16 + MAXTRACK];
struct unpacker songup;
byte readsongbyte (u16 offset)
{
återgå pgm_read_byte_near (& songdata [0] + offset);
}
void watchdogoff()
{
}
void initup (struct unpacker * upp, u16 offset) {
upp -> nextbyte = offset;
upp -> bitar = 0;
}
U8 readbit (struct unpacker * up) {
U8 val;
om (!-upp > bitar) {
upp -> buffert = readsongbyte (upp -> nextbyte ++).
upp -> bitar = 8.
}
upp -> bitar--;
Val = upp -> buffert & 1.
upp -> buffert >> = 1;
returnera val;
}
U16 readchunk (struct unpacker * upp, u8 n) {
U16 val = 0;
U8 i.
för (jag = 0; jag < n; i ++) {
IF(readbit(up)) {
val | = (1 << jag);
}
}
returnera val;
}
void readinstr (byte num, byte pos, byte * dest) {
dest [0] = readsongbyte (resurser [num] + 2 * pos + 0);
dest [1] = readsongbyte (resurser [num] + 2 * pos + 1);
}
void runcmd (u8 ch, u8 cmd, u8 param) {
Switch(validcmds[cmd]) {
fallet "0":
kanalen [ch] .inum = 0;
bryta;
fall skulle ":
osc [ch] .duty = param << 8.
bryta;
fallet "f":
kanalen [ch] .volumed = param;
bryta;
fallet "i":
kanalen [ch] .inertia = param << 1.
bryta;
fallet "j":
kanalen [ch] .iptr = param;
bryta;
fallet "l":
kanalen [ch] .bendd = param;
bryta;
fallet är ":
kanalen [ch] .dutyd = param << 6.
bryta;
't i mål ":
kanalen [ch] .iwait = param;
bryta;
fallet "v":
osc [ch] .volume = param;
bryta;
fallet "w":
osc [ch] .waveform = param;
bryta;
fallet "+":
kanalen [ch] .inote = param + kanal [ch] .tnote - 12 * 4.
bryta;
ärende '=':
kanalen [ch] .inote = param;
bryta;
fallet "~":
om (kanal [ch] .vdepth! = (param >> 4)) {
kanalen [ch] .vpos = 0;
}
kanalen [ch] .vdepth = param >> 4.
kanalen [ch] .vrate = param & 15.
bryta;
}
}
void initresources() {
U8 i.
struct unpacker upp;
initup (& upp, 0);
för (jag = 0; jag < 16 + MAXTRACK; i ++) {
resurser [i] = readchunk (& upp, 13);
}
initup (& songup, resources[0]);
}
void playroutine() {/ / kallas vid 50 Hz
U8 ch;
U8 lampor;
IF(playsong) {
IF(trackwait) {
trackwait--;
} annat {
trackwait = 4;
IF(!trackpos) {
IF(playsong) {
om (songpos > = SONGLEN) {
playsong = 0;
songpos = 0;
trackpos = 0;
initresources();
} annat {
för (ch = 0; ch < 4; ch ++) {
U8 gottransp;
U8 transp;
gottransp = readchunk (& songup, 1);
kanalen [ch] .tnum = readchunk (& songup, 6);
IF(gottransp) {
transp = readchunk (& songup, 4);
IF(transp & 0x8) transp | = 0xf0;
} annat {
transp = 0;
}
kanalen [ch] .transp = (s8) transp;
IF(Channel[ch].tnum) {
initup (& kanal [ch] .trackup, resurser [16 + kanal [ch] .tnum - 1]);
}
}
songpos ++;
}
}
}
IF(playsong) {
för (ch = 0; ch < 4; ch ++) {
IF(Channel[ch].tnum) {
U8 Obs, instr, cmd, param;
U8 fält;
fält = readchunk (& kanal [ch] .trackup, 3);
Obs = 0;
instr = 0;
CMD = 0;
param = 0;
IF(Fields & 1) OBS = readchunk (& kanal [ch] .trackup, 7);
IF(Fields & 2) instr = readchunk (& kanal [ch] .trackup, 4);
IF(Fields & 4) {
CMD = readchunk (& kanal [ch] .trackup, 4);
param = readchunk (& kanal [ch] .trackup, 8);
}
IF(Note) {
kanalen [ch] .tnote = Obs + kanal [ch] .transp;
IF(!instr) instr = kanal [ch] .lastinstr;
}
IF(instr) {
IF(instr == 2) ljus [1] = 5;
IF(instr == 1) {
ljus [0] = 5;
om (kanal [ch] .tnum == 4) {
ljus [0] = ljus [1] = 3;
}
}
IF(instr == 7) {
ljus [0] = ljus [1] = 30.
}
kanalen [ch] .lastinstr = instr;
kanalen [ch] .inum = instr;
kanalen [ch] .iptr = 0;
kanalen [ch] .iwait = 0;
kanalen [ch] .bend = 0;
kanalen [ch] .bendd = 0;
kanalen [ch] .volumed = 0;
kanalen [ch] .dutyd = 0;
kanalen [ch] .vdepth = 0;
}
IF(CMD) runcmd (ch, cmd, param);
}
}
trackpos ++;
trackpos & = 31;
}
}
}
för (ch = 0; ch < 4; ch ++) {
S16 volymprocent;
U16 tull.
U16 förtal;
medan (kanal [ch] .inum & &! channel[ch].iwait) {
U8 il [2].
readinstr (kanal [ch] .inum, kanal [ch] .iptr, il);
kanalisera [ch] .iptr ++;
runcmd (ch, il [0], il[1]);
}
IF(Channel[ch].iwait) kanal [ch] .iwait--;
IF(Channel[ch].Inertia) {
S16 diff;
sluddra = kanal [ch] .slur;
diff = freqtable [kanal [ch] .inote] - förtal;
diff >> = kanal [ch] .inertia;
om (diff > 0) {
om (diff > channel[ch].inertia) diff = kanal [ch] .inertia;
} else om (diff < 0) {
om (diff <-channel[ch].inertia) diff = - kanal [ch] .inertia;
}
sluddra += diff;
kanalen [ch] .slur = förtal;
} annat {
sluddra = freqtable [kanal [ch] .inote];
}
osc [ch] .freq =
sluddra +
kanalen [ch] .bend +
((kanal [ch] .vdepth * sinetable [kanal [ch] .vpos & 63]) >> 2);
kanalisera [ch] .bend += kanal [ch] .bendd;
Vol = osc [ch] .volume + kanal [ch] .volumed;
om (vol < 0) vol = 0;
om (vol > 255) vol = 255;
osc [ch] .volume = vol;
skyldighet = osc [ch] .duty + kanal [ch] .dutyd;
om (duty > 0xe000) tull = 0x2000;
om (duty < 0x2000) tull = 0xe000;
osc [ch] .duty = tull.
kanalisera [ch] .vpos += kanal [ch] .vrate;
}
ljus = 0;
IF(Light[0]) {
ljus [0]--;
Lights | = 0x04;
}
IF(Light[1]) {
ljus [1]--;
Lights | = 0x10;
}
PORTB = ljus;
}
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;
kanalen [0] .inum = 0;
osc [1] .volume = 0;
kanalisera [1] .inum = 0;
osc [2] .volume = 0;
kanalen [2] .inum = 0;
osc [3] .volume = 0;
kanalen [3] .inum = 0;
initresources();
TCCR0A = 0X02;
TCCR0B = 0X02; clkIO/8, så 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) / / kallas på 8 KHz
{
U8 i.
S16 acc;
U8 newbit;
OCR2B = lastsample;
newbit = 0;
om (noiseseed & 0x80000000L) newbit ^ = 1;
om (noiseseed & 0x01000000L) newbit ^ = 1;
om (noiseseed & 0x00000040L) newbit ^ = 1;
om (noiseseed & 0x00000200L) newbit ^ = 1;
noiseseed = (noiseseed << 1) | newbit;
IF(callbackwait) {
callbackwait--;
} annat {
timetoplay ++;
callbackwait = 180-1;
}
ACC = 0;
för (jag = 0; jag < 4; i ++) {
S8 värde; [-32,31]
Switch(osc[i].Waveform) {
fall WF_TRI:
om (osc [i] .phase < 0x8000) {
värde = -32 + (osc [i] .phase >> 9);
} annat {
värde = 31 - ((osc [i] .phase - 0x8000) >> 9);
}
bryta;
fall WF_SAW:
värde = -32 + (osc [i] .phase >> 10);
bryta;
fall WF_PUL:
värde = (osc [i] .phase > osc[i].duty)? -32: 31;
bryta;
fall WF_NOI:
värde = (noiseseed & 63) - 32.
bryta;
standard:
värde = 0;
bryta;
}
osc [i] .phase += osc [i] .freq;
ACC += värdet * osc [i] .volume; RHS = [-8160,7905]
}
ACC [-32640,31620]
lastsample = 128 + (acc >> 8); 1 [251]
}
}