157 lines
4.3 KiB
Plaintext
157 lines
4.3 KiB
Plaintext
#include <SPI.h>
|
|
#include <GD.h>
|
|
|
|
#include "instruments.h"
|
|
|
|
// midi frequency table
|
|
static PROGMEM prog_uint16_t midifreq[128] = {
|
|
32,34,36,38,41,43,46,48,51,55,58,61,65,69,73,77,82,87,92,97,103,110,116,123,130,138,146,155,164,174,184,195,207,220,233,246,261,277,293,311,329,349,369,391,415,440,466,493,523,554,587,622,659,698,739,783,830,880,932,987,1046,1108,1174,1244,1318,1396,1479,1567,1661,1760,1864,1975,2093,2217,2349,2489,2637,2793,2959,3135,3322,3520,3729,3951,4186,4434,4698,4978,5274,5587,5919,6271,6644,7040,7458,7902,8372,8869,9397,9956,10548,11175,11839,12543,13289,14080,14917,15804,16744,17739,18794,19912,21096,22350,23679,25087,26579,28160,29834,31608,33488,35479,37589,39824,42192,44701,47359,50175
|
|
};
|
|
|
|
class player {
|
|
public:
|
|
byte voices, duration;
|
|
prog_uchar *amps;
|
|
byte fv;
|
|
player() {
|
|
duration = 0;
|
|
}
|
|
void begin(PROGMEM prog_uchar *instr, byte note, byte firstvoice) {
|
|
voices = pgm_read_byte(instr++);
|
|
duration = pgm_read_byte(instr++);
|
|
uint16_t midi = pgm_read_word(midifreq + note);
|
|
fv = firstvoice;
|
|
for (byte i = 0; i < voices; i++) {
|
|
uint16_t w = pgm_read_word(instr);
|
|
GD.voice(fv + i, 0, (long(w) * midi) >> 10, 0, 0);
|
|
instr += 2;
|
|
}
|
|
amps = instr;
|
|
}
|
|
void update() {
|
|
for (byte j = 0; j < voices; j++) {
|
|
byte v = pgm_read_byte(amps++) >> 2;
|
|
GD.wr(VOICES + 4 * (fv + j) + 2, v);
|
|
GD.wr(VOICES + 4 * (fv + j) + 3, v);
|
|
}
|
|
duration--;
|
|
}
|
|
byte available() {
|
|
return duration != 0;
|
|
}
|
|
};
|
|
|
|
static struct {
|
|
byte t, note;
|
|
} pacman[] = {
|
|
{ 0, 71 },
|
|
{ 2, 83 },
|
|
{ 4, 78 },
|
|
{ 6, 75 },
|
|
{ 8, 83 },
|
|
{ 9, 78 },
|
|
{ 12, 75 },
|
|
{ 16, 72 },
|
|
{ 18, 84 },
|
|
{ 20, 79 },
|
|
{ 22, 76 },
|
|
{ 24, 84 },
|
|
{ 25, 79 },
|
|
{ 28, 76 },
|
|
{ 32, 71 },
|
|
{ 34, 83 },
|
|
{ 36, 78 },
|
|
{ 38, 75 },
|
|
{ 40, 83 },
|
|
{ 41, 78 },
|
|
{ 44, 75 },
|
|
{ 48, 75 },
|
|
{ 49, 76 },
|
|
{ 50, 77 },
|
|
{ 52, 77 },
|
|
{ 53, 78 },
|
|
{ 54, 79 },
|
|
{ 56, 79 },
|
|
{ 57, 80 },
|
|
{ 58, 81 },
|
|
{ 60, 83 }
|
|
};
|
|
|
|
static void pickinstrument(prog_uchar* &instdata, byte &pitchdrop, byte n)
|
|
{
|
|
char* name = "";
|
|
switch (n) {
|
|
case 0: name = "chimebar"; instdata = chimebar; pitchdrop = 0; break;
|
|
case 1: name = "piano"; instdata = piano; pitchdrop = 4; break;
|
|
case 2: name = "flute"; instdata = flute; pitchdrop = 0; break;
|
|
case 3: name = "harp"; instdata = harp; pitchdrop = 1; break;
|
|
case 4: name = "glock"; instdata = glock; pitchdrop = 5; break;
|
|
case 5: name = "nylon"; instdata = nylon; pitchdrop = 2; break;
|
|
case 6: name = "bass"; instdata = bass; pitchdrop = 4; break;
|
|
case 7: name = "clarinet"; instdata = clarinet; pitchdrop = 1; break;
|
|
case 8: name = "recorder"; instdata = recorder; pitchdrop = 1; break;
|
|
case 9: name = "musicbox"; instdata = musicbox; pitchdrop = 0; break;
|
|
case 10: name = "guitar"; instdata = guitar; pitchdrop = 3; break;
|
|
case 11: name = "oboe"; instdata = oboe; pitchdrop = 2; break;
|
|
case 12: name = "organ"; instdata = organ; pitchdrop = 2; break;
|
|
}
|
|
GD.fill(64, ' ', 128);
|
|
GD.putstr(0, 2, name);
|
|
}
|
|
|
|
#include "showvoices.h"
|
|
#include "sphere.h"
|
|
|
|
void setup()
|
|
{
|
|
GD.begin();
|
|
GD.ascii();
|
|
|
|
GD.copy(RAM_SPRIMG, sphere_img, sizeof(sphere_img));
|
|
GD.copy(RAM_SPRPAL, sphere_pal, sizeof(sphere_pal));
|
|
for (byte i = 0; i < 64; i++)
|
|
GD.sprite(i, 100, 284 * i / 64, 0, 0);
|
|
GD.microcode(showvoices_code, sizeof(showvoices_code));
|
|
|
|
GD.putstr(0, 0, "Synthesized instruments");
|
|
}
|
|
|
|
void loop()
|
|
{
|
|
player p[4];
|
|
byte nextv = 0;
|
|
byte v;
|
|
for (byte inst = 0; inst < 13; inst++) {
|
|
prog_uchar* instdata;
|
|
byte pitchdrop;
|
|
pickinstrument(instdata, pitchdrop, inst);
|
|
byte t = 0;
|
|
byte i = 0;
|
|
while (i < sizeof(pacman) / sizeof(pacman[0])) {
|
|
if (t == pacman[i].t) {
|
|
p[nextv].begin(instdata, pacman[i].note - 12 * pitchdrop, 16 * nextv);
|
|
nextv = (nextv + 1) & 3;
|
|
i++;
|
|
}
|
|
for (int d = 4; d; d--) {
|
|
for (v = 0; v < 4; v++)
|
|
if (p[v].available())
|
|
p[v].update();
|
|
GD.waitvblank();
|
|
}
|
|
t++;
|
|
}
|
|
byte anyplaying;
|
|
do {
|
|
anyplaying = 0;
|
|
for (v = 0; v < 4; v++) {
|
|
byte playing = p[v].available();
|
|
anyplaying |= playing;
|
|
if (playing)
|
|
p[v].update();
|
|
}
|
|
GD.waitvblank();
|
|
} while (anyplaying);
|
|
}
|
|
}
|