Skip to content
Snippets Groups Projects
Commit 81a01f8e authored by Erik Strand's avatar Erik Strand
Browse files

Merge branch 'midi_output'

parents f35392e4 f736b4e0
Branches
No related tags found
No related merge requests found
//
// midi_test.c
// based on hello.ftdi.44.echo.c
//
// 115200 baud FTDI MIDI controller
//
// set lfuse to 0x5E for 20 MHz xtal
//
// Neil Gershenfeld
// 12/8/10
// Erik Strand
// 11/13/2018
//
// (c) Massachusetts Institute of Technology 2010
// This work may be reproduced, modified, distributed,
// performed, and displayed for any purpose. Copyright is
// retained and must be preserved. The work is provided
// as is; no warranty is provided, and users accept all
// liability.
//
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#define output(directions,pin) (directions |= pin) // set port direction for output
#define set(port,pin) (port |= pin) // set port pin
#define clear(port,pin) (port &= (~pin)) // clear port pin
#define pin_test(pins,pin) (pins & pin) // test for port pin
#define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set
#define bit_delay_time 8.4 // bit delay for 115200 with overhead
#define bit_delay() _delay_us(bit_delay_time) // RS232 bit delay
#define half_bit_delay() _delay_us(bit_delay_time/2) // RS232 half bit delay
#define char_delay() _delay_ms(10) // char delay
#define serial_port PORTA
#define serial_direction DDRA
#define serial_pins PINA
#define serial_pin_in (1 << PA0)
#define serial_pin_out (1 << PA1)
#define led_pin (1 << PB2)
#define note_on 144
#define note_off 128
void put_char(volatile unsigned char *port, unsigned char pin, uint8_t txchar) {
// send character in txchar on port pin
// assumes line driver (inverts bits)
//
// start bit
clear(*port,pin);
bit_delay();
// unrolled loop to write data bits
if bit_test(txchar,0)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
if bit_test(txchar,1)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
if bit_test(txchar,2)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
if bit_test(txchar,3)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
if bit_test(txchar,4)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
if bit_test(txchar,5)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
if bit_test(txchar,6)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
if bit_test(txchar,7)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
// stop bit
set(*port,pin);
bit_delay();
// char delay
char_delay();
}
struct MidiEvent {
uint16_t tick;
uint8_t status;
uint8_t note;
uint8_t velocity;
};
int main(void) {
// Set the clock prescaler to 1.
CLKPR = (1 << CLKPCE);
CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
// Set the 8 bit timer's prescaler to 1/1024.
TCCR0B |= 0b00000101;
// Initialize serial output pins
set(serial_port, serial_pin_out);
output(serial_direction, serial_pin_out);
// Configure led_pin as an output.
DDRB |= led_pin;
uint16_t current_tick = 0;
uint16_t max_tick = 960;
uint8_t event_index = 0;
// 120 ticks per quarter note
const struct MidiEvent events[] = {
// Bb major 7
{0, note_on, 58, 100},
{30, note_on, 62, 100},
{60, note_on, 65, 100},
{90, note_on, 69, 100},
{180, note_off, 69, 100},
{180, note_off, 65, 100},
{180, note_off, 62, 100},
{180, note_off, 58, 100},
// sentinel event
{65535, note_off, 50, 100},
};
while (1) {
if (TCNT0 >= 120) {
TCNT0 = 0;
++current_tick;
while (events[event_index].tick <= current_tick) {
put_char(&serial_port, serial_pin_out, events[event_index].status);
put_char(&serial_port, serial_pin_out, events[event_index].note);
put_char(&serial_port, serial_pin_out, events[event_index].velocity);
++event_index;
}
if (current_tick == max_tick) {
current_tick = 0;
event_index = 0;
PORTB ^= led_pin;
}
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment