-
Notifications
You must be signed in to change notification settings - Fork 2
/
demo_midiadapter.c
127 lines (109 loc) · 3.67 KB
/
demo_midiadapter.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
This file is part of TrinketMIDI. See README.md for licencing details.
TrinketMIDI is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
TrinketMIDI is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with TrinketMIDI. If not, see <http://www.gnu.org/licenses/>.
*/
#include <avr/power.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "usbconfig.h"
#include "usbdrv/usbdrv.h"
#include "vusbmidi.h" // V-USB MIDI definitions & routines
#include "trinketusb.h" // Trinket oscillator calibration & USB init
#include "usbmidi.h" // usbmidi*() functions
#ifndef PRO_TRINKET
#error "MIDI adapter demo only works with hardware USART in Pro Trinket!"
#endif
void USARTInit(unsigned int ubrr_value) {
cli();
//Set Baud rate
UBRR0H = (unsigned char)(ubrr_value >> 8);
UBRR0L = (unsigned char)(ubrr_value & 255);
// Make sure double speed is off! Maybe Trinket bootloader sets this?
UCSR0A &= ~(1 << U2X0);
// Frame Format: asynchronous 8-N-1
UCSR0C = (0 << USBS0) | (3 << UCSZ00);
//Enable the receiver
#ifdef DEBUG
UCSR0B = _BV(RXEN0) | _BV(TXEN0); // echo RX on TX
#else
UCSR0B = _BV(RXEN0);
#endif
sei();
}
int main(void) {
enum { NOTEON, NOTEOFF, CONTROL, OTHER } state = OTHER;
uchar msg, data[2], dp=0;
// Run MIDI at slightly higher clock rate, because ATmega
// seemed to drop bytes with exact 31250 baud rate
USARTInit(F_CPU/16/32150); // Exact: 12e6/16/31250 = 24
wdt_enable(WDTO_1S);
trinketUsbBegin();
#ifdef DEBUG
DDRB |= _BV(PB5); // LED as output
#endif
while(1) {
wdt_reset();
usbPoll();
usbmidiSend();
if(!(UCSR0A & (1<<RXC0))) continue; // no data waiting
// There are several limitations to the code below:
// 1. System real-time messages ignored
// 2. Only note on, off and control change handled
// 3. Channel number ignored
msg = UDR0;
#ifdef DEBUG
UDR0 = msg; // echo on TX for debugging
PINB |= _BV(PB5); // Toggle LED
#endif
if(msg & 0x80) { // MIDI status byte
switch(msg >> 4) { // Remove channel
case 0xB:
state = CONTROL;
dp = 0;
break;
case 0x8:
state = NOTEOFF;
dp = 0;
break;
case 0x9:
state = NOTEON;
dp = 0;
break;
default:
// Just forget everything else for now, including
// 0xF8 (time) and 0xFE (active sensing)
//state = OTHER;
break;
}
} else { // MIDI data byte
data[dp++] = msg;
if(dp >= 2) {
switch(state) {
case NOTEON:
usbmidiNoteOn(data[0], data[1]);
break;
case NOTEOFF:
usbmidiNoteOff(data[0], data[1]);
break;
case CONTROL:
usbmidiControlChange(data[0], data[1]);
break;
default: // ignore
break;
}
dp = 0; // ready for running status
}
}
}
return 0;
}