#include #include #include #include #include "midi.h" #include "midi.c" void clearAllDisp(); void clearBars(); void clearBeats(); void clearNotes(); void clearSRs(); void refreshDisplay(); void edit(); void stop(); void play(); void play_note(int); void tick(); void sbeat(); // sixteenth_beat void qbeat(); // quarter_beat void hbeat(); // half_beat void nextbeat(); // one beat, 1/16 note void readInputs(); void setDispStatus(); void barLed(int, int); void noteLed(int, int); void greenLed(int); void setDispNum(int); void digit(int, char); void led(int, int); void srclk(int); void rclk(int); void read_kbd(); void encoder_cw(); void encoder_ccw(); #define MIDI_CLOCK_RATE 15 #define C1 13 #define C2 25 #define C3 37 #define c 0 #define db 1 #define d 2 #define eb 3 #define e 4 #define f 5 #define gb 6 #define g 7 #define hb 8 #define h 9 #define ab 10 #define a 11 #define b 12 #define pause -1 volatile int state; // 0 = stop, 1 = play, 2 = edit volatile int tempo; volatile int ticks; volatile int current_beat; volatile int nbrbeats; volatile int nbrbars; volatile int current_octave; volatile int bh_current; volatile int buttonHistory[] = {0,0,0,0,0}; volatile int rh_current; volatile int rotaryHistory[] = {0,0,0,0,0}; volatile unsigned char dispdata[9]; unsigned int notes[] = { c, c, g, g, a, a, g, pause, f, f, e, e, d, d, c, pause, g, g, f, f, e, e, d, pause, g, g, f, f, e, e, d, pause, c, c, g, g, a, a, g, pause, f, f, e, e, d, d, c, pause }; /* PortA: pa0: kbd pa1: kbd pa2: kbd pa3: kbd pa4: kbd pa5: - pa6: - pa7: - PortB: pb0: usart clock pb1: Display data out pb2: Encoder interrupt, INT2 pb3: - pb4: spi pb5: spi pb6: spi pb7: spi PortC: JTAG PortD: pd0: MIDI In pd1: MIDI Out pd2: kbd interrupt, INT0 pd3: Encoder interrupt, INT1 pd4: Shift clock pd5: Storage clock pd6: Shift registers output enable pd7: Shift registers clear */ int main(void) { DDRA = 0x00; // All pins for input DDRB = 0x02; // Set PINB1 for disp data output, rest input DDRD = 0xF0; // Set PIND4-7 for disp control, rest input PORTA = 0x00; // Disable pullups PORTB = 0x04; // Disable pullups, except INT2 PORTD = 0x08; // Disable pullups, except INT1 // Init timer, compare A TIMSK |= 0x10; TCCR1B |= 0x04; clearSRs(); // Clear shift registers clearAllDisp(); // Init dispdata PORTD |= 0x80; // Enable output /* MCUCR |= 0x0F; // Set trigger conditions for INT0 and INT1 MCUCSR |= 0x40; // Enable trigger for INT2 GICR |= 0xE0; // Enable external interrupts 0, 1 and 2 */ sei(); // globally enable interrupts midiInit(MIDI_CLOCK_RATE, true, false); // Initialize midi // State info state = 0; ticks = 0; // Init input histories bh_current = 0; rh_current = 0; current_octave = 3; // Beat config and init tempo = 120; nbrbeats = 16; nbrbars = 8; current_beat = 0; // Set timer compare to 29296/tempo // 29296 is the amount of clock ticks for one beat per minute OCR1A = 0x00+(7324/tempo); while(1) { readInputs(); if(state == 1){ TCCR1B |= 0x04; } else TCCR1B &= ~0x04; setDispStatus(); refreshDisplay(); } return 0; } void readInputs() { } /* Start of beat handling */ void tick() { ticks++; if(ticks%16 == 0) { nextbeat(); ticks = 0; } else if (ticks%8) { hbeat(); } else if (ticks%4) { qbeat(); } else if (ticks%2) { sbeat(); } } void sbeat() { } void qbeat() { } void hbeat() { } void nextbeat() { current_beat++; if(current_beat >= (nbrbars*nbrbeats)) current_beat = 0; } void prevbeat() { current_beat--; if(current_beat < 0) current_beat = (nbrbars*nbrbeats); } /* End of beat handling */ /* Start of LED-lighting routines */ /* 0-19 = beats 20-29 = bars 30-37 = digit1 39-45 = digit2 47-53 = digit3 54-55 = UNUSED 56-68 = notes 69-70 = UNUSED 71 = power */ void setDispStatus() { if(state == 1) greenLed(1); else greenLed(0); clearBars(); barLed( (current_beat/nbrbeats)%nbrbars , 1); clearBeats(); led(current_beat%nbrbeats, 1); if(state == 0) { digit(1, 'o'); digit(2, 'f'); digit(3, 'f'); } else if (state == 1) { digit(1, 'p'); digit(2, 'l'); digit(3, 'A'); } else if (state == 2) { digit(1, 'e'); digit(2, 'd'); digit(3, 'i'); } } // Higher level routine for toggling bar leds. 0 is first. void barLed(int nbr, int on) { led(nbr+20, on); } // Higher level routine for toggling note leds. 0 is first. void noteLed(int nbr, int on) { led(nbr+56, on); } // Higher level routine for toggling the green led. void greenLed(int on) { led(72, on); } void led(int nbr, int on) { int graph = (int)((nbr)/8); if(on){ dispdata[graph] |= 1 << (7-(nbr%8)); } else{ dispdata[graph] &= ~(1 << (7-(nbr%8))); } } /* End of LED-lighting routines */ /* Start of routines for handling 7seg displays */ // Higher-level routine for setting the three 7seg displays to a positive int value <1000 void setDispNum(int i) { int d1 = i/100; int d2 = (i-d1*100)/10; int d3 = i-d1*100-d2*10; digit(1, (char)('0'+d1)); digit(2, (char)('0'+d2)); digit(3, (char)('0'+d3)); } void digit(int digit, char letter) { unsigned char mask; switch (letter) { //TODO: Skriv om till enum, snabbare och mindre kod case '0': mask = 0b10111110; break; case '1': mask = 0b00100010; break; case '2': mask = 0b01011110; break; case '3': mask = 0b01110110; break; case '4': mask = 0b11100010; break; case '5': mask = 0b11110100; break; case '6': mask = 0b11111100; break; case '7': mask = 0b00100110; break; case '8': mask = 0b11111110; break; case '9': mask = 0b11110110; break; case 'a': case 'A': mask = 0b11101110; break; case 'b': case 'B': mask = 0b11111000; break; case 'C': mask = 0b10011100; break; case 'c': mask = 0b01011000; break; case 'd': case 'D': mask = 0b01111010; break; case 'e': case 'E': mask = 0b11011100; break; case 'f': case 'F': mask = 0b11001100; break; case 'H': mask = 0b11101010; break; case 'h': mask = 0b11101000; break; case 'i': case 'I': mask = 0b00100011; break; case 'j': case 'J': mask = 0b00111010; break; case 'l': case 'L': mask = 0b10011000; break; case 'o': case 'O': mask = 0b10111111; break; case 'p': case 'P': mask = 0b11001110; break; case 's': case 'S': mask = 0b11110101; break; case 'U': mask = 0b10111010; break; case 'u': mask = 0b00111000; break; default: mask = 0x00; } dispdata[digit+2] &= 0b11111100; dispdata[digit+2] |= mask >> 6; dispdata[digit+3] &= 0b00000011; dispdata[digit+3] |= mask << 2; } /* End of routines for handling 7seg displays */ // Outputs all dispdata into shift registers void refreshDisplay() { rclk(0); for(int i = 8; i>=0; i--) { for(int j = 0; j<8; j++) { srclk(0); if( (dispdata[i] & (1 << j)) == (1 << j)) PORTB |= 0x02; //Put 1 on PB1 else PORTB &= ~0x02; //Put 0 on PB1 srclk(1); } } rclk(1); // Toggle storage of shifts } /* Start of routines for clearing diplays */ void clearAllDisp() { dispdata[0] = 0x00; dispdata[1] = 0x00; dispdata[2] = 0x00; dispdata[3] = 0x00; dispdata[4] = 0x00; dispdata[5] = 0x00; dispdata[6] = 0x00; dispdata[7] = 0x00; dispdata[8] = 0x00; } void clearBars() { dispdata[2] &= 0xF0; dispdata[3] &= 0x03; } void clearBeats() { dispdata[0] = 0x00; dispdata[1] = 0x00; dispdata[2] &= 0x0F; } void clearNotes() { dispdata[7] = 0x00; dispdata[8] &= 0x01; } // Inits all shift registers void clearSRs() { PORTD = 0x08; // Disable pullups, except INT1 srclk(0); srclk(1); rclk(0); rclk(1); } /* End of routines for clearing displays */ /* Clocking routines */ void srclk(int i) { if(i == 1) PORTD |= 0x10; else PORTD &= ~0x10; } void rclk(int i) { if(i == 1) PORTD |= 0x20; else PORTD &= ~0x20; } /* End of clocking routines */ /* Start of input decoding routines */ void encoder_cw() { if(state == 2) nextbeat(); else current_octave++; } void encoder_ccw() { if(state == 2) prevbeat(); else current_octave--; } void read_kbd() { unsigned int button; unsigned char kbdData = (PINA & 0x1F); switch(kbdData) { case 0b00000111: button = 0; break; case 0x00: button = 1; break; case 0b00000100: button = 2; break; case 0b00001000: button = 3; break; case 0b00000001: button = 4; break; case 0b00000101: button = 5; break; case 0b00001001: button = 6; break; case 0b00000010: button = 7; break; case 0b00000110: button = 8; break; case 0b00001010: button = 9; break; case 0b00000011: button = 10;break; // * case 0b00001011: button = 11;break; // # case 0b00001100: button = 12;break; // b1 case 0b00001101: button = 13;break; // b2 case 0b00001110: button = 14;break; // b3 case 0b00001111: button = 15;break; // b4 case 0b00010000: button = 16;break; // b5 default: button = 99;break; } switch(button) { case 0: play_note(10); break; case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: play_note(button-1); break; case 11: play_note(11); break; case 12: play(); break; case 13: stop(); break; case 14: break; case 15: break; case 16: edit(); break; case 99: break; } } /* End of input decoding routines */ void edit() { state = 2; } void play() { if(state == 1) { // already playing } else { state = 1; current_beat = 0; } } void stop() { state = 0; } void play_note(int i) { midiSendNoteOn(0, current_octave*12+i, 127); } /* Start of interrupt routines */ // Keyboard data available ISR(INT0_vect) { read_kbd(); } // Rotary encoder, pinA ISR(INT1_vect) { if(PIND & 0x08){ if(!(PINB & 0x04)){ encoder_cw(); } else{ encoder_ccw(); } } else { if(PINB & 0x04){ encoder_cw(); } else { encoder_ccw(); } } } // Rotary encoder, pinB ISR(INT2_vect) { if(PINB & 0x04){ if(PIND & 0x08){ encoder_cw(); } else { encoder_ccw(); } } else { if(!(PIND & 0x08)){ encoder_cw(); } else { encoder_ccw(); } } } ISR(TIMER1_COMPA_vect) { tick(); TCNT1 = 0x0000; } /* End of interrupt routines */