aboutsummaryrefslogtreecommitdiffstats
path: root/Projects/Incomplete
diff options
context:
space:
mode:
authorDean Camera <dean@fourwalledcubicle.com>2010-11-25 02:46:35 +0000
committerDean Camera <dean@fourwalledcubicle.com>2010-11-25 02:46:35 +0000
commitfd77bf5c9459360b8d3ae1679dfab71169d4a982 (patch)
treeb11da5c16536cbee1ae974cb15eabda5f7bc9640 /Projects/Incomplete
parent857a82674f1e15b3a8394a61ea3592e4d5e9afe5 (diff)
downloadlufa-fd77bf5c9459360b8d3ae1679dfab71169d4a982.tar.gz
lufa-fd77bf5c9459360b8d3ae1679dfab71169d4a982.tar.bz2
lufa-fd77bf5c9459360b8d3ae1679dfab71169d4a982.zip
Make the incomplete MIDIToneGenerator project work with up to three notes, using a LRU (Least Recently Used) algorithm to discard the oldest set note when the note table becomes full.
Diffstat (limited to 'Projects/Incomplete')
-rw-r--r--Projects/Incomplete/MIDIToneGenerator/MIDIToneGenerator.c52
-rw-r--r--Projects/Incomplete/MIDIToneGenerator/MIDIToneGenerator.h36
2 files changed, 61 insertions, 27 deletions
diff --git a/Projects/Incomplete/MIDIToneGenerator/MIDIToneGenerator.c b/Projects/Incomplete/MIDIToneGenerator/MIDIToneGenerator.c
index 7c5fc9a62..c8e06bed4 100644
--- a/Projects/Incomplete/MIDIToneGenerator/MIDIToneGenerator.c
+++ b/Projects/Incomplete/MIDIToneGenerator/MIDIToneGenerator.c
@@ -78,14 +78,7 @@ const uint8_t SineTable[256] =
};
/** Array of structures describing each note being generated */
-struct
-{
- uint8_t Pitch;
- uint32_t TableIncrement;
- uint32_t TablePosition;
-} NoteData[3];
-
-uint8_t PhaseCounter;
+DDSNoteData NoteData[MAX_SIMULTANEOUS_NOTES];
/** Main program entry point. This routine contains the overall program flow, including initial
* setup of all components and the main program loop.
@@ -104,19 +97,34 @@ int main(void)
{
if ((ReceivedMIDIEvent.Command == (MIDI_COMMAND_NOTE_ON >> 4)) && ((ReceivedMIDIEvent.Data1 & 0x0F) == 0))
{
+ DDSNoteData* LRUNoteStruct = &NoteData[0];
+
/* Find a free entry in the note table to use for the note being turned on */
for (uint8_t i = 0; i < MAX_SIMULTANEOUS_NOTES; i++)
{
+ /* Check if the note is unused */
if (!(NoteData[i].Pitch))
{
- NoteData[i].Pitch = ReceivedMIDIEvent.Data2;
- NoteData[i].TableIncrement = (uint32_t)(BASE_INCREMENT * SCALE_FACTOR) +
- ((uint32_t)(BASE_INCREMENT * NOTE_OCTIVE_RATIO * SCALE_FACTOR) *
- (ReceivedMIDIEvent.Data2 - BASE_PITCH_INDEX));
- NoteData[i].TablePosition = 0;
+ /* If a note is unused, it's age is essentially infinite - always prefer unused not entries */
+ LRUNoteStruct = &NoteData[i];
break;
}
+ else if (NoteData[i].LRUAge > LRUNoteStruct->LRUAge)
+ {
+ /* If an older entry that the current entry has been found, prefer overwriting that one */
+ LRUNoteStruct = &NoteData[i];
+ }
+
+ NoteData[i].LRUAge++;
}
+
+ /* Update the oldest note entry with the new note data and reset its age */
+ LRUNoteStruct->Pitch = ReceivedMIDIEvent.Data2;
+ LRUNoteStruct->TableIncrement = (uint32_t)(BASE_INCREMENT * SCALE_FACTOR) +
+ ((uint32_t)(BASE_INCREMENT * NOTE_OCTIVE_RATIO * SCALE_FACTOR) *
+ (ReceivedMIDIEvent.Data2 - BASE_PITCH_INDEX));
+ LRUNoteStruct->TablePosition = 0;
+ LRUNoteStruct->LRUAge = 0;
/* Turn on indicator LED to indicate note generation activity */
LEDs_SetAllLEDs(LEDS_LED1);
@@ -129,11 +137,9 @@ int main(void)
for (uint8_t i = 0; i < MAX_SIMULTANEOUS_NOTES; i++)
{
if (NoteData[i].Pitch == ReceivedMIDIEvent.Data2)
- {
- NoteData[i].Pitch = 0;
- FoundActiveNote = true;
- break;
- }
+ NoteData[i].Pitch = 0;
+ else if (NoteData[i].Pitch)
+ FoundActiveNote = true;
}
/* If all notes off, turn off the indicator LED */
@@ -182,15 +188,15 @@ void SetupHardware(void)
/* Sample reload timer initialization */
TIMSK0 = (1 << OCIE0A);
- OCR0A = 255;
+ OCR0A = (VIRTUAL_SAMPLE_TABLE_SIZE / 8);
TCCR0A = (1 << WGM01); // CTC mode
- TCCR0B = (1 << CS00); // Fcpu speed
+ TCCR0B = (1 << CS01); // Fcpu/8 speed
/* Set speaker as output */
DDRC |= (1 << 6);
/* PWM speaker timer initialization */
- TCCR3A = ((1 << WGM30) | (1 << COM3A1) | (1 << COM3A0)); // Set on match, clear on TOP
+ TCCR3A = ((1 << WGM31) | (1 << COM3A1) | (1 << COM3A0)); // Set on match, clear on TOP
TCCR3B = ((1 << WGM32) | (1 << CS30)); // Fast 8-Bit PWM, Fcpu speed
}
@@ -208,6 +214,10 @@ void EVENT_USB_Device_Disconnect(void)
{
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
+ /* Disable any notes currently being played */
+ for (uint8_t i = 0; i < MAX_SIMULTANEOUS_NOTES; i++)
+ NoteData[i].Pitch = 0;
+
/* Set speaker as input to reduce current draw */
DDRC &= ~(1 << 6);
}
diff --git a/Projects/Incomplete/MIDIToneGenerator/MIDIToneGenerator.h b/Projects/Incomplete/MIDIToneGenerator/MIDIToneGenerator.h
index c0644374a..2936ca2c7 100644
--- a/Projects/Incomplete/MIDIToneGenerator/MIDIToneGenerator.h
+++ b/Projects/Incomplete/MIDIToneGenerator/MIDIToneGenerator.h
@@ -65,14 +65,38 @@
/** LED mask for the library LED driver, to indicate that an error has occurred in the USB interface. */
#define LEDMASK_USB_ERROR (LEDS_LED1 | LEDS_LED3)
- #define SCALE_FACTOR 65536
- #define BASE_FREQUENCY 27.5
- #define NOTE_OCTIVE_RATIO 1.05946
- #define BASE_PITCH_INDEX 21
- #define MAX_SIMULTANEOUS_NOTES 3
+ /** Scale factor used to convert the floating point frequencies and ratios into a fixed point number */
+ #define SCALE_FACTOR 65536
- #define BASE_INCREMENT (((F_CPU / 255 / 2) / BASE_FREQUENCY))
+ /** Base (lowest) allowable MIDI note frequency */
+ #define BASE_FREQUENCY 27.5
+ /** Ratio between each note in an octave */
+ #define NOTE_OCTIVE_RATIO 1.05946
+
+ /** Lowest valid MIDI pitch index */
+ #define BASE_PITCH_INDEX 21
+
+ /** Maximum number of MIDI notes that can be played simultaneously */
+ #define MAX_SIMULTANEOUS_NOTES 3
+
+ /** Number of samples in the virtual sample table (can be expanded to lower maximum frequency, but allow for
+ * more simultaneous notes due to the reduced amount of processing time needed when the samples are spaced out)
+ */
+ #define VIRTUAL_SAMPLE_TABLE_SIZE 512
+
+ /** Sample table increments per period for the base MIDI note frequency */
+ #define BASE_INCREMENT (((F_CPU / VIRTUAL_SAMPLE_TABLE_SIZE / 2) / BASE_FREQUENCY))
+
+ /* Type Defines: */
+ typedef struct
+ {
+ uint8_t LRUAge;
+ uint8_t Pitch;
+ uint32_t TableIncrement;
+ uint32_t TablePosition;
+ } DDSNoteData;
+
/* Function Prototypes: */
void SetupHardware(void);