};\r
\r
/** Array of structures describing each note being generated */\r
-struct\r
-{\r
- uint8_t Pitch;\r
- uint32_t TableIncrement;\r
- uint32_t TablePosition;\r
-} NoteData[3];\r
-\r
-uint8_t PhaseCounter;\r
+DDSNoteData NoteData[MAX_SIMULTANEOUS_NOTES];\r
\r
/** Main program entry point. This routine contains the overall program flow, including initial\r
* setup of all components and the main program loop.\r
{\r
if ((ReceivedMIDIEvent.Command == (MIDI_COMMAND_NOTE_ON >> 4)) && ((ReceivedMIDIEvent.Data1 & 0x0F) == 0))\r
{\r
+ DDSNoteData* LRUNoteStruct = &NoteData[0];\r
+ \r
/* Find a free entry in the note table to use for the note being turned on */\r
for (uint8_t i = 0; i < MAX_SIMULTANEOUS_NOTES; i++)\r
{\r
+ /* Check if the note is unused */\r
if (!(NoteData[i].Pitch))\r
{\r
- NoteData[i].Pitch = ReceivedMIDIEvent.Data2;\r
- NoteData[i].TableIncrement = (uint32_t)(BASE_INCREMENT * SCALE_FACTOR) +\r
- ((uint32_t)(BASE_INCREMENT * NOTE_OCTIVE_RATIO * SCALE_FACTOR) *\r
- (ReceivedMIDIEvent.Data2 - BASE_PITCH_INDEX));\r
- NoteData[i].TablePosition = 0;\r
+ /* If a note is unused, it's age is essentially infinite - always prefer unused not entries */\r
+ LRUNoteStruct = &NoteData[i];\r
break;\r
}\r
+ else if (NoteData[i].LRUAge > LRUNoteStruct->LRUAge)\r
+ {\r
+ /* If an older entry that the current entry has been found, prefer overwriting that one */ \r
+ LRUNoteStruct = &NoteData[i];\r
+ }\r
+ \r
+ NoteData[i].LRUAge++;\r
}\r
+ \r
+ /* Update the oldest note entry with the new note data and reset its age */\r
+ LRUNoteStruct->Pitch = ReceivedMIDIEvent.Data2;\r
+ LRUNoteStruct->TableIncrement = (uint32_t)(BASE_INCREMENT * SCALE_FACTOR) +\r
+ ((uint32_t)(BASE_INCREMENT * NOTE_OCTIVE_RATIO * SCALE_FACTOR) *\r
+ (ReceivedMIDIEvent.Data2 - BASE_PITCH_INDEX));\r
+ LRUNoteStruct->TablePosition = 0;\r
+ LRUNoteStruct->LRUAge = 0;\r
\r
/* Turn on indicator LED to indicate note generation activity */\r
LEDs_SetAllLEDs(LEDS_LED1);\r
for (uint8_t i = 0; i < MAX_SIMULTANEOUS_NOTES; i++)\r
{\r
if (NoteData[i].Pitch == ReceivedMIDIEvent.Data2)\r
- {\r
- NoteData[i].Pitch = 0;\r
- FoundActiveNote = true;\r
- break;\r
- }\r
+ NoteData[i].Pitch = 0;\r
+ else if (NoteData[i].Pitch)\r
+ FoundActiveNote = true;\r
}\r
\r
/* If all notes off, turn off the indicator LED */\r
\r
/* Sample reload timer initialization */\r
TIMSK0 = (1 << OCIE0A);\r
- OCR0A = 255;\r
+ OCR0A = (VIRTUAL_SAMPLE_TABLE_SIZE / 8);\r
TCCR0A = (1 << WGM01); // CTC mode\r
- TCCR0B = (1 << CS00); // Fcpu speed\r
+ TCCR0B = (1 << CS01); // Fcpu/8 speed\r
\r
/* Set speaker as output */\r
DDRC |= (1 << 6);\r
\r
/* PWM speaker timer initialization */\r
- TCCR3A = ((1 << WGM30) | (1 << COM3A1) | (1 << COM3A0)); // Set on match, clear on TOP\r
+ TCCR3A = ((1 << WGM31) | (1 << COM3A1) | (1 << COM3A0)); // Set on match, clear on TOP\r
TCCR3B = ((1 << WGM32) | (1 << CS30)); // Fast 8-Bit PWM, Fcpu speed\r
}\r
\r
{\r
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);\r
\r
+ /* Disable any notes currently being played */\r
+ for (uint8_t i = 0; i < MAX_SIMULTANEOUS_NOTES; i++)\r
+ NoteData[i].Pitch = 0;\r
+\r
/* Set speaker as input to reduce current draw */\r
DDRC &= ~(1 << 6);\r
}\r