2 #include <avr/interrupt.h>
3 #include <avr/eeprom.h>
10 #define MIDI_SYSEX_MAX_LEN 64
11 volatile uint8_t sysex_buf_len
= 0;
12 volatile uint8_t sysex_buf
[MIDI_SYSEX_MAX_LEN
];
14 volatile uint8_t sysex_read
= false;
15 volatile int16_t midisync_clocked
= 0;
17 #define IN_MIDI_Q_SIZE 32
18 #define OUT_MIDI_Q_SIZE 32
20 volatile uint8_t in_midi_q
[IN_MIDI_Q_SIZE
]; // cyclic queue for midi msgs
21 volatile static uint8_t in_head_idx
= 0;
22 volatile static uint8_t in_tail_idx
= 0;
23 volatile uint8_t out_midi_q
[OUT_MIDI_Q_SIZE
];// cyclic queue for midi msgs
24 volatile static uint8_t out_head_idx
= 0;
25 volatile static uint8_t out_tail_idx
= 0;
27 #define MIDI_BAUDRATE 31250UL // the MIDI spec baudrate
29 uint8_t EEMEM ee_midi_channel
= 0;
31 void midi_handle_sysex(void);
33 // interrupt on receive char
34 ISR(SIG_USART0_RECV
) {
37 if( c
== MD_SYSEX_START
) {
40 } else if( c
== MD_SYSEX_END
) {
46 sysex_buf
[ sysex_buf_len
++ ] = c
;
48 in_midi_q
[in_tail_idx
++] = c
; // place at end of q
49 in_tail_idx
%= IN_MIDI_Q_SIZE
;
51 if( in_tail_idx
== in_head_idx
) {
52 // i.e. there are too many msgs in the q
53 // drop the oldest msg?
55 in_head_idx
%= IN_MIDI_Q_SIZE
;
60 ISR(SIG_USART0_DATA
) {
61 if( out_tail_idx
!= out_head_idx
) {
62 UDR0
= out_midi_q
[out_tail_idx
++];
63 out_tail_idx
%= OUT_MIDI_Q_SIZE
;
65 // output buffer empty
66 if( out_tail_idx
== out_head_idx
)
67 UCSR0B
&= ~_BV(UDRIE0
);
71 ISR(SIG_USART0_TRANS
) {
75 void midi_init(void) {
76 // read and write, interrupt on recv.
77 UCSR0B
|= (1<<RXEN0
) | (1<<TXEN0
)| (1<<RXCIE0
) | (1<<TXCIE0
);
79 /* setup the MIDI UART */
80 uint16_t ubbr
= (F_CPU
/ (16 * MIDI_BAUDRATE
)) - 1; // formula in datasheet
81 UBRR0L
= (uint8_t)ubbr
; // set baudrate
82 UBRR0H
= (uint8_t)(ubbr
>>8);
85 int midi_putchar(uint8_t c
) {
86 while( (out_head_idx
+1)%OUT_MIDI_Q_SIZE
== out_tail_idx
);
90 // Add it to the queue
91 out_midi_q
[out_head_idx
++] = c
;
92 out_head_idx
%= OUT_MIDI_Q_SIZE
;
94 UCSR0B
|= _BV(UDRIE0
);
100 int midi_getch(void) { // checks if there is a character waiting!
101 if( in_head_idx
!= in_tail_idx
)
106 int midi_getchar(void) {
109 while( in_head_idx
== in_tail_idx
);
113 c
= in_midi_q
[in_head_idx
++];
114 in_head_idx
%= IN_MIDI_Q_SIZE
;
121 void midi_send(uint8_t status
, uint8_t chan
, uint8_t data
, uint8_t data2
) {
122 midi_putchar( (status
& 0xF0)|(chan
& 0x0F) );
123 midi_putchar( data
& 0x7F );
124 midi_putchar( data2
& 0x7F );
127 static uint8_t SYSEX_snd_checksum
;
128 void sysex_start(uint8_t command
) {
130 SYSEX_snd_checksum
= 0;
132 // Send SYSEX start, manufacturer ID, model number and command
133 midi_putchar(MD_SYSEX_START
);
134 midi_putchar(MD_MF_ID_1
);
135 midi_putchar(MD_MF_ID_2
);
136 midi_putchar(MD_MF_ID_3
);
137 midi_putchar(MD_SYNTH_ID
);
138 midi_putchar(command
);
141 void sysex_data(uint8_t data
) {
142 // split one byte of data in two
143 uint8_t msb
= data
>> 7;
144 uint8_t lsb
= data
& 0x7f;
148 SYSEX_snd_checksum
= (SYSEX_snd_checksum
+ msb
+ lsb
) & 0x7F;
151 void sysex_end(void) {
153 midi_putchar(SYSEX_snd_checksum
);
156 midi_putchar(MD_SYSEX_END
);
159 uint8_t calcCRC(void) {
161 for(i
= 0; i
< sysex_buf_len
; ++i
)
162 crc
= (crc
+ sysex_buf
[i
]) & 0x7F;
166 void midi_handle_sysex(void) {
167 uint8_t crc
= sysex_buf
[ sysex_buf_len
-1];
171 if( crc
!= calcCRC() ) {
176 if( (sysex_buf_len
< 5) ||
177 sysex_buf
[0] != MD_MF_ID_1
||
178 sysex_buf
[1] != MD_MF_ID_2
||
179 sysex_buf
[2] != MD_MF_ID_3
||
180 sysex_buf
[3] != MD_SYNTH_ID
) {
185 //handle_sysex(sysex_buf+4, sysex_buf_len);
188 uint8_t midi_readchannel(void) {
189 return eeprom_read_byte( &ee_midi_channel
);