Created
July 10, 2016 23:54
-
-
Save connornishijima/82add47400d60945bbe30205b907b9b1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const byte score [] PROGMEM = { | |
// YOUR BYTE STREAM GOES HERE! | |
}; | |
const byte voicePins[] PROGMEM = {2, 3, 4, 5, 6, 7}; | |
byte voiceEnabled[6]; | |
byte voiceType[6]; | |
byte states[6]; | |
byte noiseCount[6]; | |
unsigned long start[6]; | |
unsigned int periods[6]; | |
unsigned long nextFlip[6]; | |
byte noise = 0; | |
unsigned long t = 0; | |
byte tFlip = 0; | |
unsigned long nextCommandTime = 0; | |
bool songPlaying = false; | |
const unsigned int frequencies[89] PROGMEM = { | |
0, 27, 29, 30, | |
33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 58, 62, | |
65, 69, 73, 78, 82, 87, 92, 98, 104, 110, 116, 123, | |
131, 138, 147, 155, 165, 175, 185, 196, 208, 220, 233, 247, | |
262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, | |
523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, | |
1046, 1109, 1175, 1244, 1318, 1397, 1480, 1568, 1661, 1760, 1865, 1975, | |
2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, | |
4186, | |
}; | |
unsigned int index = sizeof(score); | |
void setup() { | |
songPlay(); | |
songWait(); | |
} | |
void songWait() { | |
while (songPlaying) { | |
delay(1); | |
} | |
} | |
void songStop() { | |
songPlaying = false; | |
index = sizeof(score); | |
for (byte i = 0; i < 6; i++) { | |
voiceEnabled[i] = 0; | |
voiceType[i] = 0; | |
start[i] = 0; | |
states[i] = 0; | |
periods[i] = 0; | |
nextFlip[i] = 0; | |
} | |
} | |
void songPlay() { | |
index = 0; | |
songPlaying = true; | |
for (byte i = 0; i < 6; i++) { | |
byte p = pgm_read_byte (voicePins + i); | |
pinMode(p, INPUT_PULLUP); | |
} | |
// TIMER 0 for interrupt frequency 1000 Hz: | |
cli(); // stop interrupts | |
TCCR0A = 0; // set entire TCCR0A register to 0 | |
TCCR0B = 0; // same for TCCR0B | |
TCNT0 = 0; // initialize counter value to 0 | |
// set compare match register for 1000 Hz increments | |
OCR0A = 249; // = 16000000 / (64 * 1000) - 1 (must be <256) | |
// turn on CTC mode | |
TCCR0B |= (1 << WGM01); | |
// Set CS02, CS01 and CS00 bits for 64 prescaler | |
TCCR0B |= (0 << CS02) | (1 << CS01) | (1 << CS00); | |
// enable timer compare interrupt | |
TIMSK0 |= (1 << OCIE0A); | |
sei(); // allow interrupts | |
// TIMER 1 for interrupt frequency 22050 Hz: | |
cli(); // stop interrupts | |
TCCR1A = 0; // set entire TCCR1A register to 0 | |
TCCR1B = 0; // same for TCCR1B | |
TCNT1 = 0; // initialize counter value to 0 | |
// set compare match register for 25000 Hz increments | |
OCR1A = 750; // = 16000000 / (1 * 22050) - 1 (must be <65536) | |
// turn on CTC mode | |
TCCR1B |= (1 << WGM12); | |
// Set CS12, CS11 and CS10 bits for 1 prescaler | |
TCCR1B |= (0 << CS12) | (0 << CS11) | (1 << CS10); | |
// enable timer compare interrupt | |
TIMSK1 |= (1 << OCIE1A); | |
sei(); // allow interrupts | |
} | |
byte rng() { | |
static unsigned int y = 0; | |
y += t; // seeded with changing number | |
y ^= y >> 7; | |
y ^= y << 7; | |
return (y); | |
} | |
void startVoice(byte voice, unsigned int frequency) { | |
byte p = pgm_read_byte (voicePins + voice); | |
pinMode(p, OUTPUT); | |
if (frequency < 27) { // off piano, must be percussion | |
voiceType[voice] = 1 + frequency; | |
Serial.println(voiceType[voice]); | |
voiceEnabled[voice] = 1; | |
periods[voice] = 1; | |
start[voice] = t; | |
} | |
else { | |
periods[voice] = 1000000 / frequency / 2; | |
nextFlip[voice] = t + periods[voice]; | |
voiceEnabled[voice] = 1; | |
voiceType[voice] = 0; | |
} | |
} | |
ISR(TIMER0_COMPA_vect) { | |
if (t >= nextCommandTime) { | |
if (index < sizeof(score)) { | |
byte command = pgm_read_byte (score + index); | |
byte type = bitRead(command, 7); | |
byte val1 = 0; | |
for (byte i = 0; i < 4; i++) { | |
bitWrite(val1, i, bitRead(command, i + 4)); | |
} | |
byte val2 = 0; | |
for (byte i = 0; i < 4; i++) { | |
bitWrite(val2, i, bitRead(command, i)); | |
} | |
type = bitRead(command, 7); | |
if (type == 1) { | |
if (val1 == 0x9) { | |
byte note = pgm_read_byte (score + index + 1); | |
byte voice = val2; | |
unsigned int freq = 0; | |
if (note > 108) { // IF HIGHER THAN PIANO RANGE, USE PERCUSSION | |
freq = 127 - note; // FREQUENCY NOW DECIDES PERCUSSION TYPE | |
} | |
else { // If we're in piano range, produce the corresponding frequency | |
freq = pgm_read_word(frequencies + note - 20); | |
} | |
startVoice(voice, freq); | |
index += 2; | |
} | |
if (val1 == 0x8) { | |
byte voice = val2; | |
voiceEnabled[voice] = 0; | |
byte p = pgm_read_byte (voicePins + voice); | |
pinMode(p, INPUT_PULLUP); | |
index += 1; | |
} | |
if (val1 == 0xF) { | |
songStop(); | |
} | |
if (val1 == 0xE) { | |
index = 0; | |
} | |
} | |
else if (type == 0) { | |
byte next = pgm_read_byte (score + index + 1); | |
unsigned long wait = 0; | |
for (byte i = 0; i < 7; i++) { | |
bitWrite(wait, i + 8, bitRead(command, i)); | |
} | |
for (byte i = 0; i < 8; i++) { | |
bitWrite(wait, i, bitRead(next, i)); | |
} | |
nextCommandTime = t + (wait * 965); // not an exact ms value, tuned faster to make up for some slow code | |
index += 2; | |
} | |
} | |
} | |
//limit hh closed and kick durations | |
for (byte i = 0; i < 6; i++) { | |
if (voiceType[i] == 1 || voiceType[i] == 2 || voiceType[i] == 3) { | |
if (t - start[i] >= 30000) { | |
voiceEnabled[i] = 0; | |
voiceType[i] = 0; | |
start[i] = 0; | |
byte p = pgm_read_byte (voicePins + i); | |
pinMode(p, INPUT_PULLUP); | |
} | |
} | |
// limit fast snare durations | |
if (voiceType[i] == 4) { | |
if (t - start[i] >= 80000) { | |
voiceEnabled[i] = 0; | |
voiceType[i] = 0; | |
start[i] = 0; | |
byte p = pgm_read_byte (voicePins + i); | |
pinMode(p, INPUT_PULLUP); | |
} | |
} | |
} | |
} | |
ISR(TIMER1_COMPA_vect) { | |
t = micros(); | |
bool newNoise = false; | |
for (byte i = 0; i < 6; i++) { | |
if (voiceEnabled[i] == 1) { | |
byte p = pgm_read_byte (voicePins + i); | |
byte state = 0; | |
if (voiceType[i] == 0) { | |
if (t > nextFlip[i]) { | |
nextFlip[i] += periods[i]; | |
states[i] = !states[i]; | |
digitalWrite(p, states[i]); | |
} | |
} | |
else if (voiceType[i] == 1 || voiceType[i] == 4) { | |
if (newNoise == false) { | |
newNoise = true; | |
noise = bitRead(rng(), 0); | |
} | |
digitalWrite(p, noise); | |
} | |
else if (voiceType[i] == 2) { | |
if (noiseCount[i] == 2) { | |
noiseCount[i] = 0; | |
if (newNoise == false) { | |
newNoise = true; | |
noise = bitRead(rng(), 0); | |
} | |
digitalWrite(p, noise); | |
} | |
else { | |
noiseCount[i]++; | |
} | |
} | |
else if (voiceType[i] == 3) { | |
if (noiseCount[i] == 3) { | |
noiseCount[i] = 0; | |
if (newNoise == false) { | |
newNoise = true; | |
noise = bitRead(rng(), 0); | |
} | |
digitalWrite(p, noise); | |
} | |
else { | |
noiseCount[i]++; | |
} | |
} | |
} | |
} | |
} | |
void loop() { | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment