You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
210 lines
7.4 KiB
210 lines
7.4 KiB
/*
|
|
LUFA Library
|
|
Copyright (C) Dean Camera, 2010.
|
|
|
|
dean [at] fourwalledcubicle [dot] com
|
|
www.fourwalledcubicle.com
|
|
*/
|
|
|
|
/*
|
|
Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
|
|
Permission to use, copy, modify, distribute, and sell this
|
|
software and its documentation for any purpose is hereby granted
|
|
without fee, provided that the above copyright notice appear in
|
|
all copies and that both that the copyright notice and this
|
|
permission notice and warranty disclaimer appear in supporting
|
|
documentation, and that the name of the author not be used in
|
|
advertising or publicity pertaining to distribution of the
|
|
software without specific, written prior permission.
|
|
|
|
The author disclaim all warranties with regard to this
|
|
software, including all implied warranties of merchantability
|
|
and fitness. In no event shall the author be liable for any
|
|
special, indirect or consequential damages or any damages
|
|
whatsoever resulting from loss of use, data or profits, whether
|
|
in an action of contract, negligence or other tortious action,
|
|
arising out of or in connection with the use or performance of
|
|
this software.
|
|
*/
|
|
|
|
/** \file
|
|
*
|
|
* Main source file for the MIDI demo. This file contains the main tasks of
|
|
* the demo and is responsible for the initial application hardware configuration.
|
|
*/
|
|
|
|
#include "MIDIToneGenerator.h"
|
|
|
|
/** LUFA MIDI Class driver interface configuration and state information. This structure is
|
|
* passed to all MIDI Class driver functions, so that multiple instances of the same class
|
|
* within a device can be differentiated from one another.
|
|
*/
|
|
USB_ClassInfo_MIDI_Device_t Keyboard_MIDI_Interface =
|
|
{
|
|
.Config =
|
|
{
|
|
.StreamingInterfaceNumber = 1,
|
|
|
|
.DataINEndpointNumber = MIDI_STREAM_IN_EPNUM,
|
|
.DataINEndpointSize = MIDI_STREAM_EPSIZE,
|
|
.DataINEndpointDoubleBank = false,
|
|
|
|
.DataOUTEndpointNumber = MIDI_STREAM_OUT_EPNUM,
|
|
.DataOUTEndpointSize = MIDI_STREAM_EPSIZE,
|
|
.DataOUTEndpointDoubleBank = false,
|
|
},
|
|
};
|
|
|
|
const uint8_t SineTable[] PROGMEM =
|
|
{
|
|
0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x95, 0x98, 0x9c, 0x9f, 0xa2, 0xa5, 0xa8, 0xab, 0xae,
|
|
0xb0, 0xb3, 0xb6, 0xb9, 0xbc, 0xbf, 0xc1, 0xc4, 0xc7, 0xc9, 0xcc, 0xce, 0xd1, 0xd3, 0xd5, 0xd8,
|
|
0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xed, 0xef, 0xf0, 0xf2, 0xf3, 0xf5,
|
|
0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfc, 0xfd, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfd, 0xfc, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7,
|
|
0xf6, 0xf5, 0xf3, 0xf2, 0xf0, 0xef, 0xed, 0xec, 0xea, 0xe8, 0xe6, 0xe4, 0xe2, 0xe0, 0xde, 0xdc,
|
|
0xda, 0xd8, 0xd5, 0xd3, 0xd1, 0xce, 0xcc, 0xc9, 0xc7, 0xc4, 0xc1, 0xbf, 0xbc, 0xb9, 0xb6, 0xb3,
|
|
0xb0, 0xae, 0xab, 0xa8, 0xa5, 0xa2, 0x9f, 0x9c, 0x98, 0x95, 0x92, 0x8f, 0x8c, 0x89, 0x86, 0x83,
|
|
0x80, 0x7c, 0x79, 0x76, 0x73, 0x70, 0x6d, 0x6a, 0x67, 0x63, 0x60, 0x5d, 0x5a, 0x57, 0x54, 0x51,
|
|
0x4f, 0x4c, 0x49, 0x46, 0x43, 0x40, 0x3e, 0x3b, 0x38, 0x36, 0x33, 0x31, 0x2e, 0x2c, 0x2a, 0x27,
|
|
0x25, 0x23, 0x21, 0x1f, 0x1d, 0x1b, 0x19, 0x17, 0x15, 0x13, 0x12, 0x10, 0x0f, 0x0d, 0x0c, 0x0a,
|
|
0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
|
0x09, 0x0a, 0x0c, 0x0d, 0x0f, 0x10, 0x12, 0x13, 0x15, 0x17, 0x19, 0x1b, 0x1d, 0x1f, 0x21, 0x23,
|
|
0x25, 0x27, 0x2a, 0x2c, 0x2e, 0x31, 0x33, 0x36, 0x38, 0x3b, 0x3e, 0x40, 0x43, 0x46, 0x49, 0x4c,
|
|
0x4f, 0x51, 0x54, 0x57, 0x5a, 0x5d, 0x60, 0x63, 0x67, 0x6a, 0x6d, 0x70, 0x73, 0x76, 0x79, 0x7c
|
|
};
|
|
|
|
struct
|
|
{
|
|
uint8_t Pitch;
|
|
uint8_t Velocity;
|
|
|
|
uint8_t CurrentPos;
|
|
uint8_t ElapsedTicks;
|
|
} ChannelStates[10];
|
|
|
|
/** Main program entry point. This routine contains the overall program flow, including initial
|
|
* setup of all components and the main program loop.
|
|
*/
|
|
int main(void)
|
|
{
|
|
SetupHardware();
|
|
|
|
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
|
|
|
|
for (;;)
|
|
{
|
|
MIDI_EventPacket_t ReceivedMIDIEvent;
|
|
if (MIDI_Device_ReceiveEventPacket(&Keyboard_MIDI_Interface, &ReceivedMIDIEvent))
|
|
{
|
|
if (ReceivedMIDIEvent.Command == (MIDI_COMMAND_NOTE_ON >> 4))
|
|
{
|
|
ChannelStates[ReceivedMIDIEvent.Data1 & 0x0F].Pitch = ReceivedMIDIEvent.Data2;
|
|
ChannelStates[ReceivedMIDIEvent.Data1 & 0x0F].Velocity = ReceivedMIDIEvent.Data3;
|
|
|
|
LEDs_SetAllLEDs(LEDS_LED1);
|
|
}
|
|
else if (ReceivedMIDIEvent.Command == (MIDI_COMMAND_NOTE_OFF >> 4))
|
|
{
|
|
ChannelStates[ReceivedMIDIEvent.Data1 & 0x0F].Velocity = 0;
|
|
|
|
LEDs_SetAllLEDs(LEDS_NO_LEDS);
|
|
}
|
|
}
|
|
|
|
/* Check if the sample reload timer period has elapsed, and that the USB bus is ready for a new sample */
|
|
if (TIFR0 & (1 << OCF0A))
|
|
{
|
|
/* Clear the sample reload timer */
|
|
TIFR0 |= (1 << OCF0A);
|
|
|
|
uint8_t OutputSample = 0;
|
|
|
|
/* Loop through the channels (excluding percussion channel 10) and generate next sample */
|
|
for (uint8_t Channel = 0; Channel < 9; Channel++)
|
|
{
|
|
/* Channel only contributes if it is not muted */
|
|
if (ChannelStates[Channel].Velocity)
|
|
{
|
|
/* Fetch the current sample from the sine lookup table */
|
|
uint8_t TableValue = pgm_read_byte(&SineTable[ChannelStates[Channel].CurrentPos]);
|
|
|
|
/* Scale sample value by the velocity of the channel */
|
|
TableValue = ((uint16_t)TableValue << 6) / ChannelStates[Channel].Velocity;
|
|
|
|
/* Add the sample to the output waveform */
|
|
OutputSample += TableValue;
|
|
}
|
|
|
|
/* Calculate next sample table position for this channel */
|
|
ChannelStates[Channel].CurrentPos += ChannelStates[Channel].Pitch;
|
|
}
|
|
|
|
/* Output the sample to the PWM timer */
|
|
OCR3A = OutputSample;
|
|
}
|
|
|
|
MIDI_Device_USBTask(&Keyboard_MIDI_Interface);
|
|
USB_USBTask();
|
|
}
|
|
}
|
|
|
|
/** Configures the board hardware and chip peripherals for the demo's functionality. */
|
|
void SetupHardware(void)
|
|
{
|
|
/* Disable watchdog if enabled by bootloader/fuses */
|
|
MCUSR &= ~(1 << WDRF);
|
|
wdt_disable();
|
|
|
|
/* Disable clock division */
|
|
clock_prescale_set(clock_div_1);
|
|
|
|
/* Hardware Initialization */
|
|
LEDs_Init();
|
|
USB_Init();
|
|
|
|
/* Sample reload timer initialization */
|
|
OCR0A = (F_CPU / 8 / AUDIO_SAMPLE_FREQUENCY) - 1;
|
|
TCCR0A = (1 << WGM01); // CTC mode
|
|
TCCR0B = (1 << CS01); // Fcpu/8 speed
|
|
|
|
/* PWM speaker timer initialization */
|
|
TCCR3A = ((1 << WGM30) | (1 << COM3A1) | (1 << COM3A0)); // Set on match, clear on TOP
|
|
TCCR3B = ((1 << WGM32) | (1 << CS30)); // Fast 8-Bit PWM, Fcpu speed
|
|
}
|
|
|
|
/** Event handler for the library USB Connection event. */
|
|
void EVENT_USB_Device_Connect(void)
|
|
{
|
|
LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
|
|
|
|
/* Set speaker as output */
|
|
DDRC |= (1 << 6);
|
|
}
|
|
|
|
/** Event handler for the library USB Disconnection event. */
|
|
void EVENT_USB_Device_Disconnect(void)
|
|
{
|
|
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
|
|
|
|
/* Set speaker as input to reduce current draw */
|
|
DDRC &= ~(1 << 6);
|
|
}
|
|
|
|
/** Event handler for the library USB Configuration Changed event. */
|
|
void EVENT_USB_Device_ConfigurationChanged(void)
|
|
{
|
|
LEDs_SetAllLEDs(LEDMASK_USB_READY);
|
|
|
|
if (!(MIDI_Device_ConfigureEndpoints(&Keyboard_MIDI_Interface)))
|
|
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
|
}
|
|
|
|
/** Event handler for the library USB Unhandled Control Request event. */
|
|
void EVENT_USB_Device_UnhandledControlRequest(void)
|
|
{
|
|
MIDI_Device_ProcessControlRequest(&Keyboard_MIDI_Interface);
|
|
}
|