// Where's the Party At?
// Todd Michael Bailey
// Rev 1.01 firmware, first production run PCBs
// Mon Apr  6 16:01:14 CDT 2009

//=============================
// HOLLER-WARE LICENSE:
// Todd Bailey wrote this.  Do whatever you want with this code, but holler at me if you like it, use it, got a nice ride / big ol' butt, or know how to do it better.
// xoxoxo
// bai1ey.tm@gmail.com
//
// Todd Bailey would like to take this opportunity to shout out to:
//
// Todd Squires, who continues to be wholly intolerant of my bad programming habits,
// Limor Fried, for staying on my ass about making kits,
// BMT Toys and everybody there for putting me through the embedded-systems wringer for 3+ years of programming challenges, and for putting up with my chronic lateness and body-odor,
// Jim Williams, Paul Horowitz, Winfield Hill, and all the other people who've forgotten more than I'll ever know about all things analog,
// and most importantly,
// You, the Customer.
//=============================

//=============================
// Atmel AVR Atmega164p MCU, 5v operation.
// 20MHz Crystal Oscillator.
// Originally built with:
// AVR-Binutils 2.19,
// AVR-GCC 4.3.2,
// AVR-libc 1.6.4
//==============================

/*
Description:
==============================================================================
Just rock out, you know?


Changes and Updates from Last Revision:
==============================================================================

Fri Dec  5 14:12:30 CST 2008
Added new serial send and receive routines to accomodate helper IC.
Added new LED routines.
Changed softclock so it doesn't generate interrupts.
Changed UART routines slightly.
Changed the way the analog control input is monitored.
Changed program to accomodate new LED handling.
Changed key handling to accomodate helper IC.
MAJOR change to ISR to accomodate new parallel latch structure.
MAJOR change by combining redundant ANALOG and MIDI ISRs into a single Audio ISR accessed from multiple vectors.
Changed the names of a lot of silly things so they make sense, hopefully.


NOTES and for real ToDo stuff (Things That Make Me Go Hmm):
==============================================================================

Tue Apr  7 13:38:22 CDT 2009

Integrate Midi/Loop sampling (ISR) functions -- FIX OVERDUB
Integrate Midi/Loop sampling state machines
Set up new button and UI system
Set up 2-sample bank memory system
Write effects functions
Implement midi out fifo
Port gay PWM-style intro

Sun Apr 12 17:37:39 CDT 2009
Get effects working in caveman
Restructure effects and overdubbing in midi with CC and PC messages and whatnot.
New effects functions:
	Granular divide
	Software jitter
	bit reduce input (no SRAM storage)
	(Multiply / XOR / compare-and-output-larger-sample / whatever) the two sample banks.
	Use MIDI velocity to scale output?
Implement midi output FIFO and MIDI out in general.
Provide for setting up and storing MIDI channels in eeprom
Gay intro still -- maybe also display FW version number during startup
Write debug mode?



rough jitter calculation:

	At the first interrupt, do this:
	
	jitterValue=(potValue/MAX_POT_VALUE)										// Get the magnitude of jitter based on the user's input.
	jitterValue*=normalTimeUntilNextInterrupt;									// Scale it to our current clock value.
	jitterValue=rand()%jitterValue;												// Pick a random value somewhere between the max and min jitter value. 
	actualTimeUntilNextInterrupt=(normalTimeUntilNextInterrupt-jitterValue);	// Subtract the jitter from the time before the next interrupt, and set the interrupt to happen then.
	
	At next interrupt, make audio and set the next interrupt for jitterValue cycles.
	At the following interrupt we've gone normalTime cycles.  Do the problem again and repeat.  We'll stay synced to the proper sample clock, our sample will just bounce all over.
	It will be a pain to do this for the external clock.
	Remember to scale this to 128 values (not 256) so that the MIDI CC controls can do the same thing as the pot.


Wed Apr  8 11:50:17 CDT 2009
	Bank System -- should be able to trigger playback/record/overdub independently in the two separate banks.
	Separate clock sources for the two banks, too.

Sat Mar 14 13:48:33 CDT 2009

Remove MCU-MCU serial communication code (may want to keep a variant around for debug)
	@@@ Make the output fifo used for the Helper into a MIDI out FIFO.
Implement MIDI out
Change Databus arbitration to include LED latch; may need to change RAM code also to accomodate this.
Include (again) analog pot handling on the ADC.
Include switch handling functions.
Change LED functions to include new latch.
Implement software jitter generator
Fix all DDRs
@@@ There are a lot of redundant settings of OE and WE and the LATCH_DDR.
@@@ There are too many calls to start and stop reading pots.
@@@ The loop sampler state machine is incredibly ugly.  Perhaps Include the LED blinking and pot reading code in the "Start Recording" functions if you can.
		There has to be a way to break those down more elegantly.  The midi code is a lot prettier.
### Ought to make the representations of audio into signed versions.
	NOTE:  It makes sense that it's the RAM's drivers which need time for turn around since in all the ADDRESS changes on the latch output we assign the port value and immediately toggle the strobe in the next command.
	NOTE:  Adding the overdubs digitally allows us to use the top bits in the DAC even if the opamps can't swing that high because we've got them loaded so hard!
	NOTE:  I wonder if having the opamps loaded so hard is also partially responsible for signal getting into places it shouldn't -- because the power output of that noise source is relatively high.
### We seem to be getting buggy shit when aftertouch data comes in (I think, could be velocity, but I think it's aftertouch)

Fri Apr 10 14:46:34 CDT 2009

@@@ Ive broken the 1 or (n) rule again by dividing the midi clocks up for the two banks.  We now assign BANK_0 to the OCR1A interrupt and BANK_1 to the OCR1B interrupt which allows us to separate pitch in the MIDI domain.
### Am currently changing the TIMER1 OCR1x interrupt system to stop using the CTC based timer mode since this will not work for two banks.  We've got to go to normal mode and implement a rolling interrupt. 
	NOTE:  If the elusive Atmega1284p comes out, you could drop it in (pin compatible) and could increase this to 4 MIDI voices with the same scheme (it has 2 16 bit counters).

Old stuff:
MIDI OVERDUB was never specified in the old version.
Remember to implement saving the MIDI channel to eeprom.
@@@ Might want to make the DAC recenter to mid-scale when it isn't spitting data.  This may or may not be necessesary based on whether or not the overdub input is DC coupled (right now it is) and how we ultimately end up doing overdubbing.
A great way to figure out where all the definitions for all the constants are kept locally is to try and redefine them and see how the compiler complains.  Just try defining PORTB as YOURMOM and see what happens.


Ideas, Indulgent Dreaming:
==============================================================================
	--------->  Analog clock in is on an Input Capture pin which can edge trigger -- could we also use this to change pitches up by, say fifths, right???  Cool....  Read up on this module.
	Nope, not really.  If you used the clock input (T1 or T0) you could do this with the output compare module...  Alas they're on PORTB.  Hmmm.
	Could still overclock and then divide in software, maybe.  We'd probably vector to the ISR way too often then.
	Could we mess with pitch by changing the Input Capture Edge?  Could double or halve it no problem that way, but other integers would suck.  Could also do this without polling by changing between ICP and PC interrupts.
	Halving the clock rate might also help the VCO be more tunable, too...  Hmm.  Could shift down by a 5th too by triggering on rise, not fall, not rise, fall.  Or something....
 	...Just playing it straight for now, trigger on rising edge.

	--------->  Could do a cool granular synthesis thing by dividing a sample by 2^EffectSelector, and shuffling the parts in playback.  Could also shuffle the array of pointers on a user command -- this would probably be better b/c a pattern
	would repeat until you told it to pick something new.  Would take a 256-byte long RAM table to shuffle.  Bigger part here we come....

	--------->  Now that banked samples are possible, it'll be cool to record more than one sample and then combine them in weird ways on playback (ie, not add, but multiply or XOR or whatever).
	--------->  Never did implement real-time effects.  Ought to.  Wonder if the RAM can get used for something (other than delay) with real time effects?  Like an envelope mask or something.
				Or, like the "banked sample" idea where you record one thing and then you multiply in real time against it.  Or something.
	VARIABLE crust, adjustable with the knob and not just ultimate crust.
	--------->	Should implement a tap-tempo one loop repeat feature

Nuts / Volts:
==============================================================================
Fuse bits:

EByte:  Don't change.
HByte:  0xD9	-- turn off JTAG.
LByte:  CKSEL=0111  SUT=11  CKDIV=1  CKOUT=1  so  1111 0111 or 0xF7

The device will then start at 20MHz.
I use:
avrdude -p m164p -c stk500v2 -u -t
r lfuse (should be 62)
w lfuse 0 0xF7
r hfuse (99 is default)
w hfuse 0 0xD9

*/

#include	"includes.h"

//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
//Application Defines:
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------

// PORT / PIN Masks:
#define	LATCH_PORT		PORTB		// This is the all-purpose data port we use to write data to the RAM address and DAC latches and read and write from RAM.
#define	LATCH_DDR		DDRB		// It's associated DDR.
#define	LATCH_INPUT		PINB		// And the associated input latch.

// Input and output bitmasks:
// PORTD:
#define	Om_LED_LA			(1<<PD5)

// PORTA:
#define	Om_RAM_WE			(1<<PA1)
#define	Om_RAM_OE			(1<<PA2)
#define	Om_RAM_L_ADR_LA		(1<<PA3)
#define	Om_RAM_H_ADR_LA		(1<<PA4)
#define	Om_DAC_LA			(1<<PA5)

// Switch Input Bitmasks:
// These are on multiple ports, and the bit positions we describe here are the places we look for switchmasks in the application.
// The actual switch handling code worries about the hardware specifics.

#define		Im_SWITCH_0			(1<<0)
#define		Im_SWITCH_1			(1<<1)
#define		Im_SWITCH_2			(1<<2)
#define		Im_SWITCH_3			(1<<3)
#define		Im_SWITCH_4			(1<<4)
#define		Im_SWITCH_5			(1<<5)

// RAM constants
#define	MAX_RAM_ADDRESS	((unsigned long)0x7FFFF)	//	512k of SRAM here.


// Switch Definitions by Function
// In the most recent sampler, the switches have a function that they more or less stick with.  I've renamed them to make it easier to
// tell what's going on when reading the code.

#define		Im_REC			Im_SWITCH_0
#define		Im_ODUB			Im_SWITCH_1
#define		Im_PLAY_PAUSE	Im_SWITCH_2
#define		Im_SINGLE_PLAY	Im_SWITCH_3
#define		Im_BANK			Im_SWITCH_4
#define		Im_EFFECT		Im_SWITCH_5


//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// Lists:
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------

// Audio ISR States -- these are the different things we can do in the audio related ISR.
//---------------------------------------------------------------------------------------

enum
	{
		AUDIO_IDLE=0,
		AUDIO_SAWTOOTH,
		AUDIO_RECORD,
		AUDIO_PLAYBACK,
		AUDIO_OVERDUB,
		NUM_AUDIO_FUNCTIONS,
	};


// ADC Channels:
//-----------------------------------------------------------------------
enum
{
	A_INPUT=0,
	A_OVERDUB,
	A_POT,
	NUM_ADCS,
};


// LEDs.
//-----------------------------------------------------------------------
enum					// LED enum used for keeping track of our LED masks.
	{
		LED_0=0,
		LED_1,
		LED_2,
		LED_3,
		LED_4,
		LED_5,
		LED_6,
		LED_7,
		NUM_LEDS,
	};

// WTPA has gotten to the point where each LED pretty much corresponds to an indicator of something specific.
// To reflect this, the masks here arrange LEDs by FUNCTION, to make code easier to read.

#define	Om_LED_REC			(1<<LED_0)
#define	Om_LED_ODUB			(1<<LED_1)
#define	Om_LED_PLAY			(1<<LED_2)
#define	Om_LED_OUT_OF_MEM	(1<<LED_3)
#define	Om_LED_BANK			(1<<LED_4)
#define	Om_LED_FX2			(1<<LED_5)
#define	Om_LED_FX1			(1<<LED_6)
#define	Om_LED_FX0			(1<<LED_7)

static unsigned char
	ledOnOffMask,		// What leds are on and off now?
	ledBlinkMask;		// What leds are blinking right now?

//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// Application Globals:
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------

// RAM address, data, and DAC stuff.
//-----------------------------------------------------------------------

static volatile unsigned char
	isrType;						// Keeps track of what interrupt vector we're handling since the flag is cleared by hardware before the jump.  @@@ I think.

// Keys and analog reading variables.
//-----------------------------------------------------------------------
static unsigned char
	keyState,
	newKeys,
	potValue;		// Current value of our analog control pot input.

static bool
	updatePot;		// OK to read the analog pot now?


// Application flags and housekeeping.
//-----------------------------------------------------------------------
STATE_FUNC				//  Creates a pointer called State to an instance of STATE_FUNC().
	*State;
static unsigned char
	subState;			//  Keeps track of the minor states (sub states) the device can be in.

static volatile bool
	outOfRam;				// Goes true in the ISR if we run out of RAM.

static unsigned char		// The number that we display on the LEDs and use to select different effects and stuff.  Generated from the pot's reading.
	scaledPotValue;


//==============================================
// Bankey shit: a good laugh walking to this.

typedef struct
// In this structure we keep track of what's going on in any given independent sample (bank).
// There are variables here for states and also for where we're looking in memory.  The sample start and end addresses should be hardcoded at the beginning and
// end of RAM for the two-bank system we're using -- we'll count down and up respectively.
// Wed Apr  8 17:09:13 CDT 2009
{
	unsigned char
		audioFunction;			// What should we do when we get to the isr?
	bool
		loopOnce;				// Flags for FX.
	bool
		halfBitDepth;
	bool
		halfSpeed;
	bool
		backwardsPlayback;
	unsigned char
		clockMode;					// Which interrupt source (none, external or internal clock) are we supposed to be triggering on?
	unsigned int
		timerCyclesForNextNote;		// The number of cycles we need to wait before triggering again to maintain our assigned pitch (used for internal clock generation)
	unsigned long
		endAddress;
	unsigned long
		startAddress;
	unsigned long
		currentAddress;
}	BANK_STATE;

enum	// Flags we use to determine what to set our clock source to when setting up an audio interrupt.
{
	CLK_NONE=0,
	CLK_EXTERNAL,
	CLK_INTERNAL,
};

enum	// Flags we use to determine our IRQ source when servicing an interrupt.
{
	IRQ_CAPT=0,			// External Timer 1 capture event.
	IRQ_COMPA,			// Compare match A, Timer 1
	IRQ_COMPB,			// Compare match B, Timer 1
};


// @@@ Our enum list of banks is in defines.h, so midi.c can see it.  Kludgy.

static volatile BANK_STATE					// Keep track of what's going on in all the implemented banks.
	bankStates[NUM_BANKS];



// I hate Prototypes:
//-----------------------------------------------------------------------
// None so far....





//----------------------------------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------------------------------
// Da Code:
//----------------------------------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------------------------------




//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// Interrupt Service Routines:
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// This is where all the audio business happens in this program.
// Variables messed with in the ISRs AND mainline code should be declared volatile.
// The functions declared up here should _ONLY_ ever be called from an interrupt.

static unsigned char UpdateAudioChannel(unsigned char theBank, signed char adcInputByte)
// New banked idea of the audio handler.
{
	signed int
		sum;			// For doing saturated adds.
	signed char
		outputByte;		// What will we pass out at the end?
	static unsigned char
		sawtooth;		// Used for our dac test.
	static bool
		flipFlops[NUM_BANKS];

	outputByte=0;		// Pass out midscale by default.

	switch(bankStates[theBank].audioFunction)
	{
		case AUDIO_SAWTOOTH:
		// Puts out a noble sawtooth wave.  Doesn't talk to the RAM at all.
		outputByte=sawtooth++;			// Increment a variable for the dac and just pass it back out.
		break;

		case AUDIO_RECORD:
		// Samples the current ADC channel and loads it into RAM.  Overwrites whatever is there and ALWAYS writes from the beginning of the sample to the end.
		LATCH_DDR=0xFF;						// Data bus to output -- we never need to read the RAM in this version of the ISR.

		LATCH_PORT=(bankStates[theBank].currentAddress&0xFF);	// Put the LSB of the address on the latch.
		PORTA|=(Om_RAM_L_ADR_LA);								// Strobe it to the latch output...
		PORTA&=~(Om_RAM_L_ADR_LA);								// ...Keep it there.

		LATCH_PORT=((bankStates[theBank].currentAddress>>8)&0xFF);	// Put the middle byte of the address on the latch.
		PORTA|=(Om_RAM_H_ADR_LA);									// Strobe it to the latch output...
		PORTA&=~(Om_RAM_H_ADR_LA);									// ...Keep it there.

		PORTC=(0xF8|((bankStates[theBank].currentAddress>>16)&0x07));	// Only switches on PORTC now.

		LATCH_PORT=adcInputByte;				// Put the data to write on the RAM's input port

//		MACRO_DoTenNops						// @@@

		PORTA&=~(Om_RAM_WE);				// Strobe Write Enable low.  This latches the data in.
//		MACRO_DoTenNops						// @@@
		PORTA|=(Om_RAM_WE);					// Disbale writes.

		if(theBank==BANK_0)					// @@@ Specific to two-bank memory handling, bank_0 increments from the first location in RAM and bank_1 decrements from the last location.
		{
			bankStates[theBank].currentAddress++;	// Next address please.
			bankStates[theBank].endAddress++;		// Push ending address of the sample forward by one.
		}
		else
		{
			bankStates[theBank].currentAddress--;	// Next address please.
			bankStates[theBank].endAddress--;		// Push ending address of the sample back by one.
		}

		if(bankStates[BANK_0].endAddress>=bankStates[BANK_1].endAddress)	// Banks stepping on each other?  Note, this test will result in one overlapping RAM location.
		{
			bankStates[theBank].audioFunction=AUDIO_IDLE;	// Stop recording on this channel.
			outOfRam=true;									// Signal mainline code that we're out of memory.
		}
		break;

		case AUDIO_PLAYBACK:
		// Goes through RAM and spits out bytes, looping (usually) from the beginning of the sample to the end.
		// The playback ISR also allows the various effects to change the output.
		// Since we cannot count on the OE staying low or the AVR's DDR remaining an input, we will explicitly set all the registers we need to every time through this ISR.

		if((bankStates[theBank].halfSpeed==false)||(bankStates[theBank].halfSpeed&&flipFlops[theBank]))		// Play the sample back every ISR if we aren't at half speed, OR play the sample back every other time if we are.
		{
			// Read memory (as of now all audio functions end with the LATCH_DDR as an output so we don't need to set it at the beginning of this function)
			LATCH_PORT=(bankStates[theBank].currentAddress&0xFF);	// Put the LSB of the address on the latch.
			PORTA|=(Om_RAM_L_ADR_LA);								// Strobe it to the latch output...
			PORTA&=~(Om_RAM_L_ADR_LA);								// ...Keep it there.

			LATCH_PORT=((bankStates[theBank].currentAddress>>8)&0xFF);	// Put the middle byte of the address on the latch.
			PORTA|=(Om_RAM_H_ADR_LA);									// Strobe it to the latch output...
			PORTA&=~(Om_RAM_H_ADR_LA);									// ...Keep it there.

			PORTC=(0xF8|((bankStates[theBank].currentAddress>>16)&0x07));	// Only switches on PORTC now.

			LATCH_DDR=0x00;						// Turn the data bus around (AVR's data port to inputs)
			PORTA&=~(Om_RAM_OE);				// RAM's IO pins to outputs.

			asm volatile("nop"::);
			asm volatile("nop"::);
			// @@@ This is the magic spot for turn around time. All the other delays are unnecessary but we need at least this much delay (two nops) here for bus turnaround.  No delay gives no signal, and one nop is crusty.  Try to elegant this up later.
//			MACRO_DoTenNops						// @@@

			outputByte=LATCH_INPUT;				// Get the byte from this address in RAM.
//			MACRO_DoTenNops						// @@@

			PORTA|=(Om_RAM_OE);					// Tristate the RAM.
			LATCH_DDR=0xFF;						// Turn the data bus around (AVR's data port to outputs)

			if(bankStates[theBank].halfBitDepth)	// Low bit rate?
			{
				outputByte^=0x80;		// Bring the signed char back to unsigned for the bitmask.				
				outputByte&=0x80;		// Mask off top bit.
				outputByte^=0x80;		// Bring it back to signed.
			}

			if(bankStates[theBank].backwardsPlayback)	// Paul is dead?  Devil voices?
			{
				if((bankStates[theBank].currentAddress==bankStates[theBank].startAddress)&&(bankStates[theBank].loopOnce==true))	// If we're looping once AND we're at the beginning of the sample, stop playing back.
				{
					bankStates[theBank].audioFunction=AUDIO_IDLE;
					bankStates[theBank].clockMode=CLK_NONE;
				}
				else if(bankStates[theBank].currentAddress==bankStates[theBank].startAddress)	// We're looping and have reached the beginning of the sample, so...
				{
					bankStates[theBank].currentAddress=bankStates[theBank].endAddress;			// Back to the, um, future.
				}
				else
				{
					if(theBank==BANK_0)		// We're not at the beginning of the loop, keep heading there.
					{
						bankStates[theBank].currentAddress--;		// In BANK_0, the beginning is low.
					}
					else
					{
						bankStates[theBank].currentAddress++;		// In BANK_1, the beginning is high.
					}
				}
			}
			else	// Going forward through the sample.
			{
				if((bankStates[theBank].currentAddress==bankStates[theBank].endAddress)&&(bankStates[theBank].loopOnce==true))	// If we're looping once AND we're at the end of the sample, stop playing back.
				{
					bankStates[theBank].audioFunction=AUDIO_IDLE;
					bankStates[theBank].clockMode=CLK_NONE;
				}
				else if(bankStates[theBank].currentAddress==bankStates[theBank].endAddress)		// We're looping and have reached the end of the sample, so...
				{
					bankStates[theBank].currentAddress=bankStates[theBank].startAddress;			// Loop around to the beginning.
				}
				else
				{
					if(theBank==BANK_0)		// We're not at the end of the loop, keep heading there.
					{
						bankStates[theBank].currentAddress++;		// In BANK_0, the end is high.
					}
					else
					{
						bankStates[theBank].currentAddress--;		// In BANK_1, the end is low.
					}
				}
			}
		}

		if(flipFlops[theBank])			// Toggle our half-speed flip flop.
		{
			flipFlops[theBank]=false;
		}
		else
		{
			flipFlops[theBank]=true;
		}
		break;

		case AUDIO_OVERDUB:
		// WTPA has a destructive overdub as of now.
		if((bankStates[theBank].halfSpeed==false)||(bankStates[theBank].halfSpeed&&flipFlops[theBank]))		// Play the sample back every ISR if we aren't at half speed, OR play the sample back every other time if we are.
		{
			// Read memory (as of now all audio functions end with the LATCH_DDR as an output so we don't need to set it at the beginning of this function)
			LATCH_PORT=(bankStates[theBank].currentAddress&0xFF);	// Put the LSB of the address on the latch.
			PORTA|=(Om_RAM_L_ADR_LA);								// Strobe it to the latch output...
			PORTA&=~(Om_RAM_L_ADR_LA);								// ...Keep it there.

			LATCH_PORT=((bankStates[theBank].currentAddress>>8)&0xFF);	// Put the middle byte of the address on the latch.
			PORTA|=(Om_RAM_H_ADR_LA);									// Strobe it to the latch output...
			PORTA&=~(Om_RAM_H_ADR_LA);									// ...Keep it there.

			PORTC=(0xF8|((bankStates[theBank].currentAddress>>16)&0x07));	// Only switches on PORTC now.

			LATCH_DDR=0x00;						// Turn the data bus around (AVR's data port to inputs)
			PORTA&=~(Om_RAM_OE);				// RAM's IO pins to outputs.

			asm volatile("nop"::);
			asm volatile("nop"::);
			// @@@ This is the magic spot for turn around time. All the other delays are unnecessary but we need at least this much delay (two nops) here for bus turnaround.  No delay gives no signal, and one nop is crusty.  Try to elegant this up later.
//			MACRO_DoTenNops						// @@@

			outputByte=LATCH_INPUT;				// Get the byte from this address in RAM -- this will get sent to the DAC.
//			MACRO_DoTenNops						// @@@

			PORTA|=(Om_RAM_OE);					// Tristate the RAM.
			LATCH_DDR=0xFF;						// Turn the data bus around (AVR's data port to outputs)

			if(bankStates[theBank].halfBitDepth)	// Low bit rate?
			{
				outputByte^=0x80;		// Bring the signed char back to unsigned for the bitmask.				
				outputByte&=0x80;		// Mask off top bit.
				outputByte^=0x80;		// Bring it back to signed.
			}

			// Do saturated add mess.
			sum=outputByte+adcInputByte;
			if(sum>127)		// Saturate to top rail.
			{
				sum=127;
			}
			else if(sum<-128) // Saturate to bottom rail.
			{
				sum=-128;
			}

			adcInputByte=(signed char)sum;	// Back to 8 bits, please.

			LATCH_PORT=adcInputByte;	// Now replace the data at this RAM location with the data summed from the ADC and output bytes.
//			MACRO_DoTenNops				// @@@
			PORTA&=~(Om_RAM_WE);		// Strobe Write Enable low.  This latches the data in.
//			MACRO_DoTenNops				// @@@
			PORTA|=(Om_RAM_WE);			// Disbale writes.

			if(bankStates[theBank].backwardsPlayback)	// Paul is dead?  Devil voices?
			{
				if((bankStates[theBank].currentAddress==bankStates[theBank].startAddress)&&(bankStates[theBank].loopOnce==true))	// If we're looping once AND we're at the beginning of the sample, stop playing back.
				{
					bankStates[theBank].audioFunction=AUDIO_IDLE;
					bankStates[theBank].clockMode=CLK_NONE;
				}
				else if(bankStates[theBank].currentAddress==bankStates[theBank].startAddress)	// We're looping and have reached the beginning of the sample, so...
				{
					bankStates[theBank].currentAddress=bankStates[theBank].endAddress;			// Back to the, um, future.
				}
				else
				{
					if(theBank==BANK_0)		// We're not at the beginning of the loop, keep heading there.
					{
						bankStates[theBank].currentAddress--;		// In BANK_0, the beginning is low.
					}
					else
					{
						bankStates[theBank].currentAddress++;		// In BANK_1, the beginning is high.
					}
				}
			}
			else	// Going forward through the sample.
			{
				if((bankStates[theBank].currentAddress==bankStates[theBank].endAddress)&&(bankStates[theBank].loopOnce==true))	// If we're looping once AND we're at the end of the sample, stop playing back.
				{
					bankStates[theBank].audioFunction=AUDIO_IDLE;
					bankStates[theBank].clockMode=CLK_NONE;
				}
				else if(bankStates[theBank].currentAddress==bankStates[theBank].endAddress)		// We're looping and have reached the end of the sample, so...
				{
					bankStates[theBank].currentAddress=bankStates[theBank].startAddress;			// Loop around to the beginning.
				}
				else
				{
					if(theBank==BANK_0)		// We're not at the end of the loop, keep heading there.
					{
						bankStates[theBank].currentAddress++;		// In BANK_0, the end is high.
					}
					else
					{
						bankStates[theBank].currentAddress--;		// In BANK_1, the end is low.
					}
				}
			}
		}

		if(flipFlops[theBank])			// Toggle our half-speed flip flop.
		{
			flipFlops[theBank]=false;
		}
		else
		{
			flipFlops[theBank]=true;
		}
		break;

		default:	// This will include the "NONE" case.
		break;
	}

	return(outputByte);
}

static void DoInterruptHandler(void)
// Calls the audio interrupt as needed for the different banks and clock sources.
// Vector here from directly from IRQa and then figure out what you need to do.
// We could make the bank system a "1 or (n)" case handling loop here, but I've unrolled it to go faster in the ISR.  Adding more banks will complicate this.
// NOTE:  Can't use an ALIASOF in the different ISRs anymore because we now need to know what got us to the interrupt handler.  We can't test the Interrupt Flags because they'll be cleared before we
// vector here.  So we just set our own flag in either interrupt vector and then jump here.
// Right now we have 3 possible clock sources.  This is a little less general than I'd like, but I did it so that we'd be able to separate the pitch of the two independent MIDI outputs.
// The external clock source (an edge trigger on TIMER1 input compare) can generate audio on either bank.
// The internal clock is based on TIMER1's output compares, and can generate two different interrupts -- OCR1A and OCR1B.  These are explicitly associated with BANK_0 and BANK_1 respectively.
// I could not see a way to make the pitch of the two midi samples independent without doing this.  As it stands, the pitch of the two banks is not independent when using the external interrupts,
// but I decided the extra complexity was worth it to separate the pitches for the two midi channels.

// On signage:  The adc data comes in unsigned and we make it a signed twos complement char.  It stays this way until we spit it back out again on the DAC because this makes summing the independent audio channels easier.
// On the audio channels:  We need to know the difference between an interrupt source which is ACTIVE but not being triggered in this current call now and one which is not active.
//		One which is active should retain its value even if it isn't being updated, and one which is inactive should default to midscale.  The idle channels have their contributions negated in the switch statement before the sum.
{
	static signed char
		adcByte,			// The current reading from the ADC.
		extIsrOutputBank0,
		extIsrOutputBank1,
		midiOutputBank0,
		midiOutputBank1;

	signed int
		sum;			

	static unsigned char
		lastDacByte;	// Very possible we haven't changed output values since last time (like for instance we're recording) so don't bother strobing it out.
	unsigned char
		dacByte;		// What will we eventually put on the DAC?

	if(!(ADCSRA&(1<<ADSC)))			// Last conversion done (note that once we start using different clock sources it's really possible to read this too often, so always check to make sure a conversion is done)
	{
		adcByte=(ADCH^0x80);		// Update our ADC conversion variable.  If we're really flying or using both interrupt sources we may use this value more than once.  Make it a signed char.
		ADCSRA |= (1<<ADSC);  		// Start the next conversion.
	}

	if(isrType==IRQ_CAPT)		// An input compare got us here -- the edge from the external clock.  Either or both banks can trigger on the external clock.
	{
		if(bankStates[BANK_0].clockMode==CLK_EXTERNAL)		// Is bank 0 supposed to be triggering off the external clock?
		{
			extIsrOutputBank0=UpdateAudioChannel(BANK_0,adcByte);		// If so, then call the audioIsr for bank 0 and do whatever it's currently supposed to do.
		}
		if(bankStates[BANK_1].clockMode==CLK_EXTERNAL)		// Is bank 1 supposed to be triggering off the external clock?
		{
			extIsrOutputBank1=UpdateAudioChannel(BANK_1,adcByte);		// If so, then call the audioIsr for bank 1 and do whatever it's currently supposed to do.
		}
	}
	else if(isrType==IRQ_COMPA)		// Did we get here because of an interrupt triggered from the internally generated TIMER1 OCR1A clock (BANK_0 and MIDI related)?
	{
		if(bankStates[BANK_0].clockMode==CLK_INTERNAL)		// Is bank 0 supposed to be triggering off the internal (midi) clock?
		{
			midiOutputBank0=UpdateAudioChannel(BANK_0,adcByte);			// If so, then call the audioIsr for bank 0 and do whatever it's currently supposed to do.
			OCR1A+=bankStates[BANK_0].timerCyclesForNextNote;		// Set the interrupt register correctly for the next interrupt time.
		}		
	}
	else							// Must be the internally generated TIMER1 OCR1B clock (BANK_1 and MIDI related) by process of elimination.
	{
		if(bankStates[BANK_1].clockMode==CLK_INTERNAL)		// Is bank 1 supposed to be triggering off the internal (midi) clock?
		{
			midiOutputBank1=UpdateAudioChannel(BANK_1,adcByte);		// If so, then call the audioIsr for bank 1 and do whatever it's currently supposed to do.
			OCR1B+=bankStates[BANK_1].timerCyclesForNextNote;	// Set the interrupt register correctly for the next interrupt time.
		}	
	}

	// Now void any input to the DAC from interrupts that aren't happening:
	
	switch(bankStates[BANK_0].clockMode)
	{
		case CLK_NONE:				// No clock on this channel means no output from either source.
		extIsrOutputBank0=0;
		midiOutputBank0=0;
		break;		
	
		case CLK_EXTERNAL:			// External clock on the bank means no midi output for this channel / bank.
		midiOutputBank0=0;
		break;
		
		case CLK_INTERNAL:			// Internal clock on the bank means no caveman output for this channel / bank.
		extIsrOutputBank0=0;
		break;
		
		default:
		break;						
	}

	switch(bankStates[BANK_1].clockMode)
	{
		case CLK_NONE:				// No clock on this channel means no output from either source.
		extIsrOutputBank1=0;
		midiOutputBank1=0;
		break;		
	
		case CLK_EXTERNAL:			// External clock on the bank means no midi output for this channel / bank.
		midiOutputBank1=0;
		break;
		
		case CLK_INTERNAL:			// Internal clock on the bank means no caveman output for this channel / bank.
		extIsrOutputBank1=0;
		break;
		
		default:
		break;						
	}

/*
### Multiplying the two banks would go something like:
	bank0sum=extIsrOutputBank0+midiOutputBank0;
	bank1sum=extIsrOutputBank1+midiOutputBank1;
	// Pin to range, make into signed chars...

	if(multiplyChannels)
	{
		(singed int)theProduct=(bank0sum*bank1Sum/256);
		dacByte blah blah;
	}
	else if(xorChannels)
	{
		// make them unsigned chars
		theProduct=(bank0Sum^bank1Sum);
	}
	else if(any other weird non-sum math)
	{
		...
	}
	else
	{
//		Finish the sum similar to below.
	}

### while I'm at it, variable bit mask is like:
	bitReduceMask=(0xFF<<scaledPotValue);	// Where scaled pot value is 0-7.
	and there's a char in the bankStates to hold this mask instead of the bool halfBitDepth

*/	
	sum=(extIsrOutputBank0+extIsrOutputBank1+midiOutputBank0+midiOutputBank1);		// Now sum everything that might be involved in our output waveform:
	if(sum>127)		// Pin high.
	{
		sum=127;
	}
	if(sum<-128)
	{
		sum=-128;
	}

	dacByte=(signed char)sum;		// Cast back to 8 bits.
	dacByte^=(0x80);				// Make unsigned again (shift 0 up to 128, -127 up to 0, etc)
	
	if(dacByte!=lastDacByte)
	{
		PORTA|=(Om_RAM_OE);		// Tristate the RAM.
		LATCH_DDR=0xFF;			// Turn the data bus around (AVR's data port to outputs)

		LATCH_PORT=dacByte;		// Put the dacByte on the output latch's input.
		PORTA|=(Om_DAC_LA);		// Strobe dac latch enable high -- this puts the dacByte on the 373's output...
		PORTA&=~(Om_DAC_LA);	// ...And keeps it there.
	}

	lastDacByte=dacByte;		// Flag this byte has having been spit out last time.
}

ISR(TIMER1_CAPT_vect)
{
	isrType=IRQ_CAPT;		// Set a flag so we know which vector sent us to the interrupt handler.
	DoInterruptHandler();	// Do all the audio work.
}

ISR(TIMER1_COMPA_vect)
{
	isrType=IRQ_COMPA;		// Set a flag so we know which vector sent us to the interrupt handler.
	DoInterruptHandler();	// Do all the audio work.
}

ISR(TIMER1_COMPB_vect)
{
	isrType=IRQ_COMPB;		// Set a flag so we know which vector sent us to the interrupt handler.
	DoInterruptHandler();	// Do all the audio work.
}

ISR(__vector_default)
{
    //  This means a bug happened.  Some interrupt that shouldn't have generated an interrupt went here, the default interrupt vector.
	//	printf("Buggy Interrupt Generated!  Flags = ");
	//  printf("*****put interrupt register values here****");
}


//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// State Machine Functions.
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------

static void SetState(STATE_FUNC *newState)		// Sets the device to a new state, assumes it should begin at the first minor sub-state.
{
	State=newState;
	subState=SS_0;
}

//-----------------------------------------------------------------------
// LED functions:
//-----------------------------------------------------------------------

static void SetLedsOnOff(unsigned char theMask)
// Sets the LEDs to be on or off according to the bitmask.  This mask is sent out to the LEDs in the main loop.
{
	ledOnOffMask=theMask;
}

static void BlinkLeds(unsigned int theMask, unsigned long blinkTime)
// Sets up the mask of leds to blink and their blink rate.
// NOTE:  All leds made to blink will blink synchronously at the rate last set.  This saves us from having 8 separate software clocks.
// NOTE:  When an LED is told to stop blinking it will revert to OFF, even if the LED was ON when we told it to blink.  I can live with this.
{
	unsigned char
		i;

	for(i=0; i<NUM_LEDS; i++)		// Go through all the LEDs...
	{
		if(ledBlinkMask&(1<<i))		// ...and if a LED was supposed to be blinking...
		{
			ledOnOffMask&=~(1<<i);		// ...turn it off.  This makes sure any blinking LEDs don't stop their blinks in the 'on' state.
		}
	}

	ledBlinkMask=theMask;				// Now assign new leds to blink.
	SetTimer(TIMER_BLINK,blinkTime);	// And the time that they will all blink to.
}

static void StopBlinking(void)
// Stops all blinking LEDs.
{
	BlinkLeds(0,0);		// Durrrr.....
}

static void KillLeds(void)
// Turns off all LEDs immediately.
{
	ledOnOffMask=0;
	BlinkLeds(0,0);		// Durrrr.....
}

static void WriteLedLatch(unsigned char theMask)
// Take the current on/off LED mask and put it onto the LED output latch.
// This is the only mainline (non IRQ) code that messes with the databus.
{
	unsigned char
		sreg;

	sreg=SREG;	// Store global interrupt state
	cli();		// Clear global interrupts (so we don't get an audio interrupt while messing with OE and WE)

	PORTA|=(Om_RAM_OE|Om_RAM_WE);	// Disable reading and writing to RAM.
	LATCH_PORT=theMask;				// Put passed data onto bus.
	LATCH_DDR=0xFF;					// Make sure the bus is an output.
	PORTD|=(Om_LED_LA);				// Strobe it to the latch output...
	PORTD&=~(Om_LED_LA);			// ...Keep it there.

	SREG=sreg;						// Restore interrupts.
}

static void HandleLeds(void)
// Runs in the main loop updating the state of the LEDs.  Only messes with the databus when there's something to change.
{
	unsigned char
		i;
	static bool
		toggle;				// Flip flop for blinking.
	static unsigned char
		lastLedMask=0;		// Used to see if LEDs have been changed during a given loop.

	if(ledBlinkMask&&CheckTimer(TIMER_BLINK))		// Are we blinking and is it time to toggle?
	{
		for(i=0; i<NUM_LEDS; i++)	// Which LEDs are we blinking?
		{
			if(ledBlinkMask&(1<<i))
			{
				if(toggle)			// Flip flop the LEDs we're blinking every time the timer runs out.
				{
					ledOnOffMask|=(1<<i);
				}
				else
				{
					ledOnOffMask&=~(1<<i);
				}
			}
		}

		toggle=(!toggle);				// flip the sign of the led for next time.
		ResetTimer(TIMER_BLINK);		// And wait until next time.
		WriteLedLatch(ledOnOffMask);	// Send the LED value to the latch.
	}
	else if(lastLedMask!=ledOnOffMask) // If we're not blinking, but our LEDs have been instructed to change...
	{
		WriteLedLatch(ledOnOffMask);	// ...send the LED value to the latch.
		lastLedMask=ledOnOffMask;		// And mark it as sent.
	}
}

static void InitLeds(void)
{
	ledOnOffMask=0;
	ledBlinkMask=0;
	WriteLedLatch(0);	// ...send the LED value to the latch.
}


//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// Switch functions:
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------

static void InitSwitches(void)
{
	MCUCR&=~(1<<PUD);	// Globally enable pullups (should be default)
	DDRD&=~(1<<PD7);	// PD7 to input
	DDRC&=~(0xF8);		// PC3-7 to input
	PORTD|=(1<<PD7);	// Pullup on.
	PORTC|=(0xF8);		// Pullups on.

	SetTimer(TIMER_DEBOUNCE,(SECOND/32));
}

static void HandleSwitches(void)
// Read input pins, debounce, make keypresses positive-true, and flag newly-appeared keys.
{
	static unsigned char
		lastKeyState;


	if(CheckTimer(TIMER_DEBOUNCE))
	{
		keyState=(PIND&0x80)>>7;		// Switch 0 (PIND, bit 7)
		keyState|=(PINC&0xF8)>>2;		// Switches 1-5 (PINC bits 3-7)
		keyState=(~keyState)&0x3F;		// Flip bits to make low input level a 1, then mask off unused bits.
		SetTimer(TIMER_DEBOUNCE,(SECOND/32));
	}

	newKeys=((keyState^lastKeyState)&(keyState));		// Flag the keys which have been pressed since the last test.
	lastKeyState=keyState;								// And store this keystate as old news.
}

//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// A/D Control Functions:
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// WTPA uses 3 analog inputs (ADC6,7, and 0).  The first is used to sample the audio input.  The second is used to sample the summed output of the input and the DAC when we're overdubbing.
// The third is used to sample the user input pot (the bootleg shuttlewheel).
// The best resolution we can get from this hardware is 10 bits, +/- 2 lsbs.
// The max sampling rate we can pull at full resolution is 15kHz.  We always use the ADC single ended (so far) as the datasheet says that the ADC isn't guaranteed to
// work in differential mode with the PDIP package.  A conversion takes 13 ADC clocks normally, or 25 for the first conversion after the channel is selected.
// The datasheet is unclear how much resolution is lost above 15kHz.  Guess we'll find out!
// NOTE:  Since the RAM can only store 8 bits per sample, we're only using 8 bits of the conversion data.  Can't imagine those last two bits are going to be worth much at these sample rates anyhoo.

// WARNING:  It is the caller's responsibility to NOT point the ADC at the pot while sampling is taking place, and to make sure that polling is disabled.

static void SetAdcChannel(unsigned char theChannel)
{
	switch(theChannel)
	{
		case A_INPUT:
		ADMUX=(ADMUX&0xF0);		// Clear the mux bits that we care about.
		ADMUX|=0x06;			// ADC6 selected.
		break;
/*
		case A_OVERDUB:
		ADMUX=(ADMUX&0xF0);		// Clear the mux bits that we care about.
		ADMUX|=0x07;			// ADC7
		break;
*/
		case A_POT:
		ADMUX=(ADMUX&0xF0);		// Clear the mux bits that we care about, and leave them.  This selects ADC0.
		break;
/*
		default:				// You goofed.  Shouldn't happen.
		ADMUX=(ADMUX&0xF8);		// Clear the mux bits that we care about.
		ADMUX|=0x06;			// ADC6 selected.
		break;
*/
	}
}

static void StopReadingPot(void)
// Stop reading the pot from the ADC.
{
	updatePot=false;
}

static void StartReadingPot(void)
// Set up to read the pot on the ADC.
{
	SetAdcChannel(A_POT);		// Set the channel correctly.
	ADCSRA |= (1<<ADSC);  		// Start the next conversion.
	updatePot=true;				// Raise flag for the update routine to poll.
}

static void HandleReadingPot(void)
// Sits in the background and periodically updates the analog control input.
// Right now we only do this when we're playing back and never when we're sampling, so it's OK to pre-empt the ADC for this.
// We're also not doing any oversampling...  Yet.
{
	if(updatePot)						// Is it OK to be messing with this right now?
	{
		if(!(ADCSRA&(1<<ADSC)))			// Last conversion done?
		{
			potValue=ADCH;				// Store it.
			ADCSRA |= (1<<ADSC);  		// Start the next conversion.
		}
	}
}

/*
static void UnInitAdc(void)
{
	ADCSRA&=~(1<<ADEN);		// Disable ADC.
	PRR|=(1<<PRADC);		// Power down the ADC.
}
*/

static void InitAdc(void)
// Note, we don't set up the Adc to trigger on anything right away.
{
	PRR&=~(1<<PRADC);		// Turn the ADC power on (clear the bit to power on).
	ADMUX = 0x66; 			// 0110 0110.  AVCC is the reference (w/ ext cap), left justify the result, start with ADC6 as the channel.  The ADC always wants to see a cap at AREF if the internal references or VCC are used.
	DIDR0 = 0xC1;			// Disable the digital inputs for ADC6,ADC7, and ADC0.
	ADCSRA = 0x96;			// 1001 0110 (prescaler to 64 = 24kHz sample rate, (32 = 48kHz).  Enable the ADC, no autotrigger or interrupts. (For ex: at 8MHz sysclk and 1/64, ADC clock = 125kHz, normal conversion ~= 10kHz (13 samples per conversion).  According to the datasheet, to get max resolution from the converter, the ADC clock must be between 50 and 200kHz.)

	ADCSRA |= (1<<ADSC);  	// Start the first conversion to initialize the ADC.
	updatePot=false;		// Don't read the pot yet.

	// ADCSRB controls auto-triggering, which we aren't using right now.
}

//-----------------------------------------------------------------------
// RAM / DAC functions:
//-----------------------------------------------------------------------
// Will be totally different than the oldschool serial biz.....
// Should probably all be inlined in the ISR.
// Just so you remember, Parallel SRAM pretty much always works like this:

// The chip is always enabled (CS is always low).  The other two control pins are active low also -- they are Write Enable and Output Enable.
// When WE is low, the value on the DATA pins is latched into the address on the ADDRESS pins.  Asserting WE will also override OE and make the RAM's DATA Pins go high impedance.
// When WE is high, the byte stored at the ADDRESS on pins A0-A18 is latched out on the DATA pins, assuming OE is low.
// If OE is high, the DATA port will be high impedance no matter what.
// The ADDRESS pins can always be outputs as far as the MCU is concerned.

// A typical write might look like:
// 1.)  OE and WE are high.
// 2.)  The address is set and the data latches on the MCU are made into outputs. The correct values of Data and Address are set on the corresponding pins.
// 3.)  WE is brought low and the data is latched in.
// 4.)  WE is brought high.  The address and data lines can now be changed without messing up data on the RAM chip.

// A typical read might look like this:
// 1.)  OE and WE are high.
// 2.)  The address is set correctly and the DATA PORT on the MCU is made high impedance.
// 3.)  OE is brought low, and the data to be read shows up on the DATA lines.
// 4.)  The MCU reads the DATA lines.
// 5.)  OE can be brought high again or left low -- it only needs to change if we're going to write to the chip.

// On 373 Parallel Latches:
// These guys are pretty simple.  In this circuit, their OE is tied low (enabled).
// While LE (Latch Enable) is High, the Latch is transparent from input port to output port.
// When LE is brought low, the current state of the inputs will be latched, and the outputs will that hold value while LE remains low (there's a little delay but it isn't relevant for us).
// So, we will will probably just leave LE low most of the time on the latches and strobe it high when we want to update that particular latch.

//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// General Sampler/ISR Functions:
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// We've changed these to use both OCR1x interrupts and the "normal" waveform generation mode (from the single OCR1A and CTC mode).
// 	This allows us to generate different pitches for the two banks using TIMER1.  We do this by reading the counter and adding the number of cycles until the next interrupt to the OCR every time
// 	that interrupt occurs.  The OCR value will keep rolling like this, the timer will never be reset to zero, and we will be able to use as many OCRs as are available to generate different pitches.
//  On the mega164p this is two, there are newer devices with more 16 bit timers, and more interrupts per timer.

static void SetSampleClock(unsigned char theBank, unsigned char theClock, unsigned int theRate)
// This code is common to all the requests to start different audio modes (record, playback, overdub, etc) and sets the correct clock source for a given bank.
// Timer interrupts should be disabled when you call this!
{
	if(bankStates[theBank].clockMode==CLK_INTERNAL)			// The internally counted clock is usually associated with MIDI-controlled sampling (output capture on timer 1)
	{
		bankStates[theBank].timerCyclesForNextNote=theRate;	// No matter what bank we're in, keep this value so we can use it to keep setting interrupt times.

		if(theBank==BANK_0)		// Bank 0 is associated with OCR1A
		{
			OCR1A=(theRate+TCNT1);	// Find spot for next interrupt to give the right pitch.		
			TIFR1|=(1<<OCF1A);		// Clear the interrupt flag.
			TIMSK1|=(1<<OCIE1A);	// Enable the compare match interrupt.
			TCCR1B=0x01;			// Make sure TIMER1 is going, and in normal mode.
		}
		else					// Bank 1 is associated with OCR1B
		{
			OCR1B=(theRate+TCNT1);	// Find spot for next interrupt to give the right pitch.		
			TIFR1|=(1<<OCF1B);		// Clear the interrupt flag.
			TIMSK1|=(1<<OCIE1B);	// Enable the compare match interrupt.
			TCCR1B=0x01;			// Make sure TIMER1 is going, and in normal mode.			
		}
	}
	else if(bankStates[theBank].clockMode==CLK_EXTERNAL)	// External clock is based on Input Capture interrupts (rising edge from the sample clock oscillator)
	{
		TCCR1B|=(1<<ICES1);		// Trigger on a rising edge.
		TIFR1|=(1<<ICF1);		// Clear Input Capture interrupt flag.
		TIMSK1|=(1<<ICIE1);		// Enable Input Capture Interrupt (yo, son, I thought I was the Icy One?)
	}
}

static void StartRecording(unsigned char theBank, unsigned char theClock, unsigned int theRate)
// Set the memory pointer to the start of RAM, set up the clock source, set the interrupt to the recording handler, and enable interrupts.
// If we're using the internal clock, set the rate.
// Sat Apr 11 13:49:31 CDT 2009
{
	unsigned char
		sreg;

	sreg=SREG;	// Store global interrupt state.
	cli();		// Disable interrupts while we muck with the settings.

	bankStates[theBank].audioFunction=AUDIO_RECORD;							// What should we be doing when we get into the ISR?
	bankStates[theBank].clockMode=theClock;									// What type of interrupt should trigger this sample bank?
	bankStates[theBank].currentAddress=bankStates[theBank].startAddress;	// Point to the beginning of our allocated sampling area.
	bankStates[theBank].endAddress=bankStates[theBank].startAddress;		// And indicate that our sample is now 0 samples big.
	outOfRam=false;						// Plenty of ram left...
	SetAdcChannel(A_INPUT);				// Point ADC at the input.

	SetSampleClock(theBank,theClock,theRate);			// Set the appropriate clock source for this audio function.

	SREG=sreg;		// Restore interrupts.
}

static void StartPlayback(unsigned char theBank, unsigned char theClock, unsigned int theRate)
// Point to the beginning of RAM, select the clock source, and get the interrupts going.
// Set the clock rate if we're using the internal clock.
{
	unsigned char
		sreg;

	sreg=SREG;	// Store global interrupt state.
	cli();		// Disable interrupts while we muck with the settings.

	bankStates[theBank].audioFunction=AUDIO_PLAYBACK;						// What should we be doing when we get into the ISR?
	bankStates[theBank].clockMode=theClock;									// What type of interrupt should trigger this sample bank?
	bankStates[theBank].currentAddress=bankStates[theBank].startAddress;	// Point to the beginning of our allocated sampling area.

	SetSampleClock(theBank,theClock,theRate);			// Set the appropriate clock source for this audio function.

	SREG=sreg;		// Restore interrupts.
}

static void ContinuePlayback(unsigned char theBank, unsigned char theClock, unsigned int theRate)
// Sets the clock source and ISR appropriately to do playback, but does not move the RAM pointer.
// Used if we pause playback and want to continue where we left off, or stop overdubbing and jump right back into playback.
{
	unsigned char
		sreg;

	sreg=SREG;	// Store global interrupt state.
	cli();		// Disable interrupts while we muck with the settings.

	bankStates[theBank].clockMode=theClock;				// What type of interrupt should trigger this sample bank?
	bankStates[theBank].audioFunction=AUDIO_PLAYBACK;	// What should we be doing when we get into the ISR?

	SetSampleClock(theBank,theClock,theRate);			// Set the appropriate clock source for this audio function.

	SREG=sreg;		// Restore interrupts.
}

static void StartOverdub(unsigned char theBank, unsigned char theClock, unsigned int theRate)
// Begin recording to ram at the current RAM address.
// Continue playing back from that address, too.
{
	unsigned char
		sreg;

	sreg=SREG;	// Store global interrupt state.
	cli();		// Disable interrupts while we muck with the settings.

	bankStates[theBank].clockMode=theClock;				// What type of interrupt should trigger this sample bank?
	bankStates[theBank].audioFunction=AUDIO_OVERDUB;	// What should we be doing when we get into the ISR?
	SetAdcChannel(A_INPUT);								// Point ADC at the input.

	PORTA|=(Om_RAM_OE);						// Tristate the RAM's IO pins.
	PORTA|=(Om_RAM_WE);						// Disbale writes.
	LATCH_DDR=0xFF;							// MCU's data port to outputs.

	SetSampleClock(theBank,theClock,theRate);			// Set the appropriate clock source for this audio function.

	SREG=sreg;		// Restore interrupts.
}

/*
static void UnInitSampleClock(void)
{
	PRR|=(1<<PRTIM1);	// Turn the TMR1 power off.
}
*/

static void InitSampleClock(void)
// Get TMR1 ready to generate some equal temperament, or as equal as I can do (for MIDI)
// Or just turn it on so we can use the Input Capture pin to generate interrupts for the external clock (for the loop sampler).
{
	PRR&=~(1<<PRTIM1);	// Turn the TMR1 power on.
	TIMSK1=0x00;		// Disable all Timer 1 associated interrupts.
	OCR1A=65535;		// Set the compare register arbitrarily
	OCR1B=65535;		// Set the compare register arbitrarily
	TCCR1A=0;			// Normal Ports.
	TCCR1B=0;			// Stop the timer.
	TCNT1=0;			// Initialize the counter to 0.
	TIFR1=0xFF;			// Clear the interrupt flags by writing ones.
}

//--------------------------------------
//--------------------------------------
// MIDI Functions
//--------------------------------------
//--------------------------------------
// We use Program Changes to do record and change parameters.  We use notes to play back samples at a certain frequency.
// Not sure what to do with Control Changes yet.

#define		MIDI_RECORD_RATE		((OctaveZeroCompareMatches[C_NOTE])>>5)		// About 9.6k

// Program Change messages:
#define		MIDI_START_RECORDING		0
#define		MIDI_STOP_RECORDING			1
#define		MIDI_LOOP_CONTINUOUS		2
#define		MIDI_LOOP_ONCE				3
#define		MIDI_HALF_SPEED				4
#define		MIDI_NORMAL_SPEED			5
#define		MIDI_ONE_BIT_DEPTH			6
#define		MIDI_NORMAL_BIT_DEPTH		7
#define		MIDI_PLAY_BACKWARDS			8
#define		MIDI_PLAY_FORWARDS			9
#define		MIDI_CANCEL_EFFECTS			10


static const unsigned int OctaveZeroCompareMatches[]=
// This table corresponds to a musical octave (the lowest octave we can generate with a 16-bit compare match timer) in 12 tone equal temperament.
{
	65535,		// This is 300 Hz. (Followed by 600, 1.2k, 2.4k, 4.8k, 9.6k, 19.2k shifted over by 1 to 6 resp -- probably can't handle 19.2k, but maybe.  10-bit resolution at >>6)
	61857,
	58385,
	55108,
	52015,
	49096,
	46340,
	43739,
	41284,
	38967,
	36780,
	34716,
};

enum	// Note names for lookups.
{
	C_NOTE=0,
	D_FLAT_NOTE,
	D_NOTE,
	E_FLAT_NOTE,
	E_NOTE,
	F_NOTE,
	G_FLAT_NOTE,
	G_NOTE,
	A_FLAT_NOTE,
	A_NOTE,
	B_FLAT_NOTE,
	B_NOTE,
};

static unsigned int	GetPlaybackRateFromNote(unsigned char theNote)
// Here we take a midi note number and turn it into the timer one compare match interrupt value.
{
	unsigned char
		theIndex,
		theOctave;

	theOctave=(theNote/12);	// Which octave?
	theIndex=(theNote%12);	// Which note inside the octave?

	return((OctaveZeroCompareMatches[theIndex])>>theOctave);		// Return our value using the lookup table.

}

static void DoMidiSampler(void)
// Handle sampling and playing back samples based on the midi messages we get.
// Do all the other fancy effects from here, too.
// Playing a note stops the recording immediately, and starting recording stops a note.  A note turning off doesn't stop a recording.
// RECORD LIGHT = LED_0
// PLAYBACK LIGHT = LED_1
{
/*
	static MIDI_MESSAGE
		currentMidiMessage;

	static unsigned char
		currentNoteOn;

	static bool
		isSamplePlaying,
		isRecording;

	unsigned int
		pitchWheelValue;

	if(subState==SS_0)
	{
//		Uart0ToMidi();					// Make sure the midi baud rate is going.
		midiChannelNumber=0x01;			// @@@ Single midi channel for now.
		StopReadingPot();				// Make sure this silly business is gone (for now)
		loopOnce=true;					// Generally, play midi samples once when the note is turned on.
		halfBitDepth=false;				// And don't do anything else weird.
		halfSpeed=false;
		backwardsPlayback=false;
		isSamplePlaying=false;
		isRecording=false;
		clockMode=CLK_INTERNAL;			// Use internal timing for MIDI.

		KillLeds();					// All leds off, and no blinking.
		subState=SS_1;
	}
	else if(subState==SS_1)
	{
		if(midiMessagesInFifo)
		{
			GetMidiMessageFromFifo(&currentMidiMessage);

			if(currentMidiMessage.messageType==MESSAGE_TYPE_NOTE_OFF)		//  Note off.  Do it.
			{
				if(isSamplePlaying&&(isRecording==false))					// Are we playing a sample to begin with, and are we not recording right now?
				{
					if(currentMidiMessage.dataByteOne==currentNoteOn)		// Sampler is mono.  Only turn off the last note we turned on.
					{
						StopAudio();										// All samples stop the same way.
						isSamplePlaying=false;

						SetLedsOnOff(ledOnOffMask&~(1<<LED_1));		// Playback light off.
					}
				}
			}
			else if(currentMidiMessage.messageType==MESSAGE_TYPE_NOTE_ON)		// Note on.
			{
				if(isSamplePlaying)									// Are we playing a sample already?
				{
					StopAudio();									// Stop it, get ready to play new note.
					isSamplePlaying=false;
					// No need to turn off light here.
				}

				if(isRecording)							// Are we currently recording?
				{
					StopAudio();						// Stop it, get ready to play new note.
					sampleEndAddress=ramAddress;		// Log the location of end of our sample.
					isRecording=false;
					SetLedsOnOff(ledOnOffMask&~(1<<LED_0));		// Record light off.
				}

				currentNoteOn=currentMidiMessage.dataByteOne;			// This is our new note.
				StartPlayback(GetPlaybackRateFromNote(currentNoteOn));	// Do it.
				isSamplePlaying=true;

				SetLedsOnOff(ledOnOffMask|(1<<LED_1));		// Playback light on.
			}

			else if(currentMidiMessage.messageType==MESSAGE_TYPE_PROGRAM_CHANGE)	// We use program to control sampler parameters and start recordings.
			{
				switch(currentMidiMessage.dataByteOne)
				{
					case MIDI_START_RECORDING:						// Can re-start recording arbitrarily.
					StartRecording(MIDI_RECORD_RATE);
					isRecording=true;
					SetLedsOnOff(ledOnOffMask|(1<<LED_0));	// Record light on.
					break;

					case MIDI_STOP_RECORDING:							// Can only stop a recording if a recording is currently happening.
					if(isRecording)
					{
						StopAudio();
						sampleEndAddress=ramAddress;	// Log the location of end of our sample.
						isRecording=false;
						SetLedsOnOff(ledOnOffMask&~(1<<LED_0));	// Record light off.
					}
					break;

					case MIDI_LOOP_CONTINUOUS:						// Keep playing samples over again until note off.
					loopOnce=false;
					SetLedsOnOff(ledOnOffMask|(1<<LED_4));	//  Effect light on.
					break;

					case MIDI_LOOP_ONCE:							// Play sample once after a note on.
					loopOnce=true;
					SetLedsOnOff(ledOnOffMask&~(1<<LED_4));	//  Effect light off.
					break;

					case MIDI_HALF_SPEED:							// Skrew and chop.
					halfSpeed=true;
					SetLedsOnOff(ledOnOffMask|(1<<LED_5));	//  Effect light on.
					break;

					case MIDI_NORMAL_SPEED:							// Un-skrew.
					halfSpeed=false;
					SetLedsOnOff(ledOnOffMask&~(1<<LED_5));	//  Effect light off.
					break;

					case MIDI_ONE_BIT_DEPTH:						// Crusty.
					halfBitDepth=true;
					SetLedsOnOff(ledOnOffMask|(1<<LED_6));	//  Effect light on.
					break;

					case MIDI_NORMAL_BIT_DEPTH:						// Slightly less crusty.
					halfBitDepth=false;
					SetLedsOnOff(ledOnOffMask&~(1<<LED_6));	//  Effect light off.
					break;

					case MIDI_PLAY_BACKWARDS:						// "Paul is Dead"
					backwardsPlayback=true;
					SetLedsOnOff(ledOnOffMask|(1<<LED_7));	//  Effect light on.
					break;

					case MIDI_PLAY_FORWARDS:						// "This Song is Wack"
					backwardsPlayback=false;
					SetLedsOnOff(ledOnOffMask&~(1<<LED_7));	//  Effect light off.
					break;

					case MIDI_CANCEL_EFFECTS:						// Escape from audio mess please.
					loopOnce=true;
					halfBitDepth=false;
					halfSpeed=false;
					backwardsPlayback=false;
					SetLedsOnOff(ledOnOffMask&~((1<<LED_4)|(1<<LED_5)|(1<<LED_6)|(1<<LED_7)));		//  Effect lights off.
					break;

					default:
					break;
				}
			}

			else if(currentMidiMessage.messageType==MESSAGE_TYPE_CONTROL_CHANGE)	// We use Control Changes to ??
			{
				switch(currentMidiMessage.dataByteOne)
				{
					default:
					break;
				}
			}

			else if(currentMidiMessage.messageType==MESSAGE_TYPE_PITCH_WHEEL)
			{
				pitchWheelValue=((currentMidiMessage.dataByteTwo<<7)+currentMidiMessage.dataByteOne);		// Turn the two data bytes into a single 14-bit number (that's how pitch wheel rolls).

				if(pitchWheelValue!=0x2000)		// Pitch wheel being wanked?
				{
					if(pitchWheelValue<0x2000)	// Lower the note by some amount (add value to the OCR1A).	@@@ This wraps around 0 but it sounds cool.
					{
						OCR1A=(GetPlaybackRateFromNote(currentNoteOn)+(0x2000-pitchWheelValue));
					}
					else						// Pitch the note by some amount (add value to the OCR1A).
					{
						OCR1A=(GetPlaybackRateFromNote(currentNoteOn)-(pitchWheelValue-0x2000));
					}
				}
				else
				{
					OCR1A=(GetPlaybackRateFromNote(currentNoteOn));		// Got told to center the note, just do it.
				}
			}
		}
	}

	if(isRecording)							// Stop recording if we're out of RAM.
	{
		if(outOfRam)
		{
			StopAudio();
			sampleEndAddress=ramAddress;	// Log the location of end of our sample.
			isRecording=false;
			SetLedsOnOff(ledOnOffMask&~(1<<LED_0));		// Record light off.
		}
	}
*/
}

//--------------------------------------
//--------------------------------------
// Caveman Interface Functions
//--------------------------------------
//--------------------------------------

//==============================================
// Display update stuff, housekeeping:

static void BankStatesToLeds(unsigned char theBank)
// Looks at the current bank and decides how to set the LEDs.
{
	unsigned char
		temp;

	temp=ledOnOffMask&0xE0;		// Mask off the LEDs we care about, then turn them on if appropriate.

	if(bankStates[theBank].audioFunction==AUDIO_RECORD)
	{
		temp|=Om_LED_REC;
	}
	if(bankStates[theBank].audioFunction==AUDIO_PLAYBACK)
	{
		temp|=Om_LED_PLAY;
	}
	if(bankStates[theBank].audioFunction==AUDIO_OVERDUB)
	{
		temp|=Om_LED_ODUB;
	}
	if(outOfRam==true)
	{
		temp|=Om_LED_OUT_OF_MEM;
	}
	if(theBank==BANK_1)
	{
		temp|=Om_LED_BANK;
	}

	ledOnOffMask=temp;

	if(bankStates[theBank].startAddress==bankStates[theBank].endAddress)		// If we don't have a sample in this bank...
	{
		if(!(ledBlinkMask&Om_LED_PLAY))			// And we aren't already a-twinkle,
		{
			BlinkLeds(Om_LED_PLAY,(SECOND/8));	// Blink the play LED to indicate we have no sample ready to go in our current bank.
		}
	}
	else
	{
		StopBlinking();						// Right now we can do this b/c the above condition is the only blinking we do.
	}
}

static bool CheckPotReadAvailability(void)
// If any banks are overdubbing or recording it is not OK to read the pot (adc is otherwise committed) so return false.
{
	unsigned char
		i;

	for(i=0;i<NUM_BANKS;i++)	// Go through the banks.
	{
		if((bankStates[i].audioFunction==AUDIO_RECORD)||(bankStates[i].audioFunction==AUDIO_OVERDUB))	// If any banks are using the adc,
		{
			return(false);	// We shouldn't read the pot.
		}
	}

	return(true);			// Otherwise it's OK.
}

static void AnalogReadingToLeds(void)
// Take the value on our analog input, scale it, and display it on the LEDs.
// Do this anytime we see the pot change.
// @@@ Note, this is a badly named function since it both generates the scaled global pot value AND displays it on the LEDs.
{
	unsigned char
		lastPotValue=0,
		temp;

	if(potValue!=lastPotValue)
	{
		scaledPotValue=(potValue/32);		// Divide our pot's throw into 8 sections (assumes 8-bit range).
		temp=(ledOnOffMask&0x1F);					// Make a bitmask from the current ledMask and zero the LEDs we're testing.

		if(scaledPotValue&(1<<0))
		{
			temp|=(1<<7);	// OR in this bit to the mask to the LEDs.
		}
		if(scaledPotValue&(1<<1))
		{
			temp|=(1<<6);	// OR in this bit to the mask to the LEDs.
		}
		if(scaledPotValue&(1<<2))
		{
			temp|=(1<<5);	// OR in this bit to the mask to the LEDs.
		}

		SetLedsOnOff(temp);		// Update the leds.
	}

	lastPotValue=potValue;		// Our data is old news.
}

static void StopUnusedInterrupts(void)
// Look through all the banks, and if none are using a given interrupt source, disable that interrupt source.
{
	if((bankStates[BANK_0].clockMode!=CLK_EXTERNAL)&&(bankStates[BANK_1].clockMode!=CLK_EXTERNAL))	// If neither bank is using the external interrupt...
	{
		TIMSK1&=~(1<<ICIE1);		// Disable Input Capture Interrupt (yo, son, I thought I was the Icy One?)
		TIFR1|=(1<<ICF1);			// Clear the interrupt flag by writing a 1.	
	}

	if(bankStates[BANK_0].clockMode!=CLK_INTERNAL)		// OC1A in use?
	{
		TIMSK1&=~(1<<OCIE1A);		// Disable the compare match interrupt.
		TIFR1|=(1<<OCF1A);			// Clear the interrupt flag by writing a 1.	
	}

	if(bankStates[BANK_1].clockMode!=CLK_INTERNAL)		// OC1B in use?
	{
		TIMSK1&=~(1<<OCIE1B);		// Disable the compare match interrupt.
		TIFR1|=(1<<OCF1B);			// Clear the interrupt flag by writing a 1.	
	}
}

static void DoSampler(void)
// This state is the font from which all sampler bullshit flows.
// As WTPA stands now, the switches all basically retain the same functions regardless of what the sampler is currently doing.
// Same goes for the LEDs.  So we've gotten rid of a modal system and now just watch for commands via the buttons or midi and update everything accordingly.
// Also, I'm not sure the blinking really helps the user (it used to indicate "ready" to do something) but the sampler is basically either doing something or ready to do it, with the exception
// power up where it has no sample stored yet and is not ready to play.  Perhaps blinking would be useful to indicate "not ready" since this is uncommon.  It'd only ever be useful for the play indicator, though.

// Wed Apr  8 11:42:07 CDT 2009
// This state is based on the idea that playing, recording, and overdubbing are all discrete things and that if you're doing one you can't be doing another.
{
	unsigned char
		i;
	static unsigned char
		currentBank;					// Keeps track of the bank we're thinking about.

	static MIDI_MESSAGE
		currentMidiMessage;				// Used to point to incoming midi messages.

	static unsigned char
		currentNoteOn[NUM_BANKS];		// Used to keep track of what notes we've got on in MIDI.

	unsigned int
		pitchWheelValue;				// Figures out what to do with the pitchbend data.

	if(subState==SS_0)
	// Initialize everything.
	{
		midiChannelNumberA=0x01;			// @@@ Hardcoded midi channels for now.
		midiChannelNumberB=0x02;			// @@@ Hardcoded midi channels for now.
		bankStates[BANK_0].startAddress=0;					// @@@ hardcode bank 0 to start at the beginning of RAM
		bankStates[BANK_1].startAddress=MAX_RAM_ADDRESS;	// @@@ hardcode bank 1 to start at the end of RAM (it will count down).

		for(i=0;i<NUM_BANKS;i++)		// Initialize all the banks.
		{
			bankStates[i].audioFunction=AUDIO_IDLE;		// Nothing to do in the ISR yet.
			bankStates[i].clockMode=CLK_NONE;			// This bank doesn't do anything on any clock interrupts yet.
			bankStates[i].loopOnce=false;
			bankStates[i].halfBitDepth=false;
			bankStates[i].halfSpeed=false;
			bankStates[i].backwardsPlayback=false;
			bankStates[i].currentAddress=bankStates[i].startAddress;	// Point initial ram address to the beginning of the bank.
			bankStates[i].endAddress=bankStates[i].startAddress;		// ...And indicate that the sample is 0 samples big.
		}

		currentBank=BANK_0;			// Point at the first bank until we change banks.
		StartReadingPot();			// Get Pot info until we're told otherwise.

		KillLeds();					// All leds off, and no blinking.
		subState=SS_1;
	}

	else if(subState==SS_1)
	{
		if(keyState&Im_EFFECT)			// If we're holding the effect switch, our other switches call up patches instead of their normal functions.  It's like a shift key.
		{

		}
		else
		{
			if(newKeys&Im_REC)										// Record switch pressed.
			{
				if(bankStates[currentBank].audioFunction==AUDIO_RECORD)			// Were we recording already?
				{
					StartPlayback(currentBank,CLK_EXTERNAL,0);					// Begin playing back the loop we just recorded (ext clock)
					bankStates[currentBank].loopOnce=false;
				}
				else											// We're not recording right now, so start doing it.
				{
					StartRecording(currentBank,CLK_EXTERNAL,0);	// Start recording (ext clock)
				}
			}

			else if(newKeys&Im_ODUB)			// Overdub switch pressed.  Odub is similar to record except it takes its recording from a different analog input, and it cannot be invoked unless there is already a sample in the bank.
			{
				if(bankStates[currentBank].audioFunction==AUDIO_OVERDUB)		// Were we overdubbing already?
				{
					ContinuePlayback(currentBank,CLK_EXTERNAL,0);				// Begin playing back the loop we just recorded (ext clock, not from the beginning)
					bankStates[currentBank].loopOnce=false;
				}
				else							// We're not recording right now, so start doing it.
				{
					if(bankStates[currentBank].startAddress!=bankStates[currentBank].endAddress)		// Because of how OVERDUB thinks about memory we can't do it unless you there's already a sample in the bank.
					{
						StartOverdub(currentBank,CLK_EXTERNAL,0);					// Get bizzy (ext clock).
					}
				}
			}
			else if(newKeys&Im_PLAY_PAUSE)		// Play / Pause switch pressed.  If anything is happening this will stop it.  Otherwise, this will start playing back AS A LOOP.  This will not restart a playing sample from the beginning.
			{
				if(bankStates[currentBank].audioFunction==AUDIO_IDLE)		// Doing nothing?
				{
					if(bankStates[currentBank].startAddress!=bankStates[currentBank].endAddress)	// Do we have something to play?
					{
						ContinuePlayback(currentBank,CLK_EXTERNAL,0);			// Continue playing back from wherever we are in the sample memory (ext clock, not from the beginning) @@@ So as of now, this will begin playback at the END of a sample if we've just finished recording.  Ugly.
						bankStates[currentBank].loopOnce=false;
					}
				}
				else		// Pause whatever we were doing.
				{
					bankStates[currentBank].audioFunction=AUDIO_IDLE;		// Nothing to do in the ISR
					bankStates[currentBank].clockMode=CLK_NONE;				// Don't trigger this bank.
				}

			}
			else if(newKeys&Im_SINGLE_PLAY)		// Stop whatever we're doing and play the sample from the beginning, one time.
			{
				if(bankStates[currentBank].startAddress!=bankStates[currentBank].endAddress)	// Do we have something to play?
				{
					StartPlayback(currentBank,CLK_EXTERNAL,0);			// Play back this sample.
					bankStates[currentBank].loopOnce=true;				// And do it one time, for your mind.
				}
			}

			else if(newKeys&Im_BANK)		// Increment through banks when this button is pressed.
			{
				currentBank++;
				if(currentBank>=NUM_BANKS)
				{
					currentBank=BANK_0;		// Loop around.
				}
			}
		}

// Dealt with Caveman inputs, now deal with MIDI.

		if(midiMessagesInFifo)
		{
			GetMidiMessageFromFifo(&currentMidiMessage);
/*
			if(currentMidiMessage.messageType==REAL_TIME_STUFF)
			{
				// Do this here.
			}
*/
			if(currentMidiMessage.messageType==MESSAGE_TYPE_NOTE_OFF)		//  Note off.  Do it.  NOTE:  Our serial-to-midi functions handle turning velocity 0 NOTE_ON messages into NOTE_OFFs.
			{
				if(bankStates[currentMidiMessage.channelNumber].audioFunction==AUDIO_PLAYBACK)	// Are we playing a sample to begin with?
				{
					if(currentMidiMessage.dataByteOne==currentNoteOn[currentMidiMessage.channelNumber])			// Sampler channels are mono.  Only turn off the last note we turned on.
					{
						bankStates[currentMidiMessage.channelNumber].audioFunction=AUDIO_IDLE;	// Nothing to do in the ISR
						bankStates[currentMidiMessage.channelNumber].clockMode=CLK_NONE;		// Don't trigger this bank.
					}
				}
			}
			else if(currentMidiMessage.messageType==MESSAGE_TYPE_NOTE_ON)		// Note on.
			{
				currentNoteOn[currentMidiMessage.channelNumber]=currentMidiMessage.dataByteOne;															// This is our new note.
				StartPlayback(currentMidiMessage.channelNumber,CLK_INTERNAL,GetPlaybackRateFromNote(currentNoteOn[currentMidiMessage.channelNumber]));	// Do it.
			}

			else if(currentMidiMessage.messageType==MESSAGE_TYPE_PROGRAM_CHANGE)	// We use program changes to control sampler parameters and start recordings.
			{
				switch(currentMidiMessage.dataByteOne)
				{
					case MIDI_START_RECORDING:						// Can re-start recording arbitrarily.
					StartRecording(currentMidiMessage.channelNumber,CLK_INTERNAL,MIDI_RECORD_RATE);
					break;

					case MIDI_STOP_RECORDING:						// Can only stop a recording if a recording is currently happening.
					if(bankStates[currentMidiMessage.channelNumber].audioFunction==AUDIO_RECORD)
					{
						bankStates[currentMidiMessage.channelNumber].audioFunction=AUDIO_IDLE;			// Nothing to do in the ISR
						bankStates[currentMidiMessage.channelNumber].clockMode=CLK_NONE;				// Don't trigger this bank.
					}
					break;

					case MIDI_LOOP_CONTINUOUS:						// Keep playing samples over again until note off.
					bankStates[currentMidiMessage.channelNumber].loopOnce=false;
					break;

					case MIDI_LOOP_ONCE:							// Play sample once after a note on.
					bankStates[currentMidiMessage.channelNumber].loopOnce=true;
					break;

					case MIDI_HALF_SPEED:							// Skrew and chop.
					bankStates[currentMidiMessage.channelNumber].halfSpeed=true;
					break;

					case MIDI_NORMAL_SPEED:							// Un-skrew.
					bankStates[currentMidiMessage.channelNumber].halfSpeed=false;
					break;

					case MIDI_ONE_BIT_DEPTH:						// Crusty.
					bankStates[currentMidiMessage.channelNumber].halfBitDepth=true;
					break;

					case MIDI_NORMAL_BIT_DEPTH:						// Slightly less crusty.
					bankStates[currentMidiMessage.channelNumber].halfBitDepth=false;
					break;

					case MIDI_PLAY_BACKWARDS:						// "Paul is Dead"
					bankStates[currentMidiMessage.channelNumber].backwardsPlayback=true;
					break;

					case MIDI_PLAY_FORWARDS:						// "This Song is Wack"
					bankStates[currentMidiMessage.channelNumber].backwardsPlayback=false;
					break;

					case MIDI_CANCEL_EFFECTS:						// Escape from audio mess please.
					bankStates[currentMidiMessage.channelNumber].loopOnce=true;
					bankStates[currentMidiMessage.channelNumber].halfBitDepth=false;
					bankStates[currentMidiMessage.channelNumber].halfSpeed=false;
					bankStates[currentMidiMessage.channelNumber].backwardsPlayback=false;
					break;

					default:
					break;
				}
			}

			else if(currentMidiMessage.messageType==MESSAGE_TYPE_CONTROL_CHANGE)	// We use Control Changes to ??? (unimplemented so far)
			{
				switch(currentMidiMessage.dataByteOne)
				{
					default:
					break;
				}
			}

			else if(currentMidiMessage.messageType==MESSAGE_TYPE_PITCH_WHEEL)		// @@@ ought to make this into signed data also?
			{
				pitchWheelValue=((currentMidiMessage.dataByteTwo<<7)+currentMidiMessage.dataByteOne);		// Turn the two data bytes into a single 14-bit number (that's how pitch wheel rolls).

				if(pitchWheelValue!=0x2000)		// Pitch wheel being wanked?
				{
					if(pitchWheelValue<0x2000)	// Lower the note by some amount (add value to the OCR1A).	@@@ This wraps around 0 but it sounds cool, sort of.
					{
						bankStates[currentMidiMessage.channelNumber].timerCyclesForNextNote=(GetPlaybackRateFromNote(currentNoteOn[currentMidiMessage.channelNumber])+(0x2000-pitchWheelValue));
					}
					else						// Pitch the note by some amount (add value to the OCR1A).
					{
						bankStates[currentMidiMessage.channelNumber].timerCyclesForNextNote=(GetPlaybackRateFromNote(currentNoteOn[currentMidiMessage.channelNumber])-(pitchWheelValue-0x2000));
					}
				}
				else
				{
					bankStates[currentMidiMessage.channelNumber].timerCyclesForNextNote=(GetPlaybackRateFromNote(currentNoteOn[currentMidiMessage.channelNumber]));		// Got told to center the note, just do it.
				}
			}
		}
	}

	if(CheckPotReadAvailability()==false)		// Not OK to read the pot?
	{
		StopReadingPot();
	}
	else
	{
		if(updatePot==false)				// Is it OK to read the pot and we aren't doing it yet?
		{
			StartReadingPot();
		}
	}

	StopUnusedInterrupts();			// If we've enabled an interrupt and we aren't using it, disable it.
	AnalogReadingToLeds();			// Display our pot's relative value on the leds.
	BankStatesToLeds(currentBank);	// Display the current bank's data on the LEDs.
}

//--------------------------------------
//--------------------------------------
// DAC Testing.
//--------------------------------------
//--------------------------------------

static void DoSawtooth(void)
// See if we can get some audio out.  And look good doing it.
{
	if(subState==SS_0)
	{
		KillLeds();										// Start with LEDs off.
		BlinkLeds(((1<<LED_6)|(1<<LED_7)),(SECOND/8));	// Blink Leds 6, 7.
		subState=SS_1;
	}
	else if(subState==SS_1)
	{
		bankStates[BANK_0].audioFunction=AUDIO_SAWTOOTH;	// Set the external analog clock interrupt vector to make sawtooth waves.
		bankStates[BANK_0].clockMode=CLK_EXTERNAL;			// Cont'd...
		TCCR1B|=(1<<ICES1);						// Trigger on a rising edge.
		TIFR1=0xFF;								// Clear interrupts.
		TIMSK1|=(1<<ICIE1);						// Enable Input Capture Interrupt (yo, son, I thought I was the Icy One?)

		subState=SS_2;					// And wait forever.
	}
	else if(subState==SS_2)
	{
		if(newKeys&Im_SWITCH_0)
		{
			SetLedsOnOff(ledOnOffMask^(1<<LED_0));	// Toggle the LED.
		}
		if(newKeys&Im_SWITCH_1)
		{
			SetLedsOnOff(ledOnOffMask^(1<<LED_1));	// Toggle the LED.
		}
		if(newKeys&Im_SWITCH_2)
		{
			SetLedsOnOff(ledOnOffMask^(1<<LED_2));	// Toggle the LED.
		}
		if(newKeys&Im_SWITCH_3)
		{
			SetLedsOnOff(ledOnOffMask^(1<<LED_3));	// Toggle the LED.
		}
		if(newKeys&Im_SWITCH_4)
		{
			SetLedsOnOff(ledOnOffMask^(1<<LED_4));	// Toggle the LED.
		}
		if(newKeys&Im_SWITCH_5)
		{
			SetLedsOnOff(ledOnOffMask^(1<<LED_5));	// Toggle the LED.
		}
	}
}
/*
static void MidiOutputTestBinnis(void)
{
	if(subState==SS_0)
	{
		midiChannelNumberA=0x01;			// @@@ Hardcoded midi channel for now.
		midiChannelNumberB=0x02;			// @@@ Hardcoded midi channel for now.
		StopReadingPot();				// Make sure this silly business is gone (for now)
		KillLeds();						// All leds off, and no blinking.
		subState=SS_1;
	}
	else
	{
		if(newKeys&Im_SWITCH_0)
		{
			SetLedsOnOff(ledOnOffMask^(1<<LED_0));	// Toggle the LED.
			// Hardcoded Note On, middle C, Velocity 64, Midi channel 1.
			Uart0SendByte(0x91);		// @@@
			Uart0SendByte(60);			// @@@
			Uart0SendByte(64);			// @@@

		}
		if(newKeys&Im_SWITCH_1)
		{
			SetLedsOnOff(ledOnOffMask^(1<<LED_1));	// Toggle the LED.
			// Hardcoded Note Off, middle C, Velocity 0, Midi channel 1.
			Uart0SendByte(0x91);		// @@@
			Uart0SendByte(60);			// @@@
			Uart0SendByte(0);			// @@@
		}
	}
}
*/

static void DoTurningOn(void)
// Make all our initial state decisions.
// Give switches time to settle.
{
	if(subState==SS_0)
	{
		SetTimer(TIMER_1,(SECOND/8));
		subState=SS_1;
	}
	else
	{
		if(CheckTimer(TIMER_1))
		{
			if(keyState&Im_SWITCH_0)
			{
				SetState(DoSawtooth);
			}
			else if(keyState&Im_SWITCH_1)
			{
				SetState(DoMidiSampler);
			}
			else
			{
				SetState(DoSampler);
			}
		}
	}

//		SetState(DoSawtooth);
//		SetState(DoLoopSampler);
//		printf("Can I bring my gat?\n");
//		SetState(DoMidiSampler);
//		SetState(MidiOutputTestBinnis);
}

//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// Local Software Clock stuff.
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------

static void HandleSoftclock(void)
{
	if(TIFR0&(1<<TOV0))		// Got a timer overflow flag?
	{
		TIFR0 |= (1<<TOV0);		// Reset the flag (by writing a one).
		systemTicks++;			// Increment the system ticks.
	}
}

static void InitSoftclock(void)
// Wed Dec  3 22:28:06 CST 2008
// I've changed the way the softclock works from the last rev.  It's no longer and interrupt based thing, so it doesn't potentially get in the way of the audio interrupts.
// Also, since hardware TIMR1 is needed for bigger and better things than keeping human-time, we're going to set the softclock timer up to poll a flag.
// This means we don't steal cycles from any other ISRs, but it also means that if we write dumb code (if we hang the main loop for more than a tick time)
// we might miss a systemTick.
// NOTE:  w/ TMR0 running at 1/256 prescale at 20MHz, our smallest time unit is 3.2768mSecs.
// NOTE:  w/ 16-bit system ticks we can only time 214 seconds at this rate.
{
	PRR&=~(1<<PRTIM0);	// Turn the TMR0 power on.
	TIMSK0=0x00;		// Disable all Timer 0 associated interrupts.
	TCCR0A=0;			// Normal Ports.
	TCNT0=0;			// Initialize the counter to 0.
	TIFR0=0xFF;			// Clear the interrupt flags by writing ones.
	systemTicks=0;
	TCCR0B=0x04;		// Start the timer in Normal mode, prescaler at 1/256
}

//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// Program main loop.
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------

int main (void)
// Initialize this mess.
{
	PRR=0xFF;			// Power off everything, let the initialization routines turn on modules you need.

	// Set the DDRs for all RAM, DAC, latch related pins here.  Switches and ADC and everything else with a specific init routine will be intialized separately.

	PORTD=0x9F;			// Turn on pullups for everything except ACLK and the UART inits will get rid of the ones we don't need, and leave PD5 low.
	DDRD=0x20;			// PORTD is mostly inputs with the exception of the UARTs and the LED Latch enable on PD5.

	PORTA=0x06;			// OE and WE high, latch enables low, everything else don't care.
	DDRA=0x3E;			// PORTA is digital outputs (latch strobe lines and OE/WE lines) and analog ins (on 0, 6, 7)

	DDRB=0xFF;			// Latch port to OP.
	LATCH_PORT=0;		// And low (PORTB).

	DDRC=0x07;			// PORTC is switch inputs (initialized later) and direct address line outputs which must be initialized here.
	PORTC=0x00;			// 0, 1, 2 are the address lines.

	InitSwitches();
	InitLeds();
	InitMidi();					// Get the MIDI stack initialized.
	InitUart0();
	InitUart1();
	InitAdc();
	InitSoftclock();
//	InitSerialTransmitFifo();	@@@
	InitSampleClock();	// Turns on TIMER1 and gets it ready to generate interrupts.

	newKeys=0;
	keyState=0;

	sei();						// THE ONLY PLACE we should globally enable interrupts in this code.

 	SetState(DoTurningOn);

	while(1)
	{
		HandleSwitches();		// Flag newKeys.
		HandleSoftclock();		// Keep the timer timing.
		HandleLeds();			// Keep LEDs updated.
		HandleReadingPot();		// Read the analog pot input if appropros.  Oui oui!

		if(Uart0GotByte())		// Handle receiving midi messages: Parse any bytes coming in over the UART into MIDI messages we can use.
		{
			HandleMidiByte(Uart0GetByte());		// Deal with the UART message and put it in the incoming MIDI FIFO if relevant.
		}

//		if(serialBytesInFifo>0)		// Got something to transmit to the Helper?	@@@
//		{
//			if(UCSR1A&(1<<UDRE1))	// UART transmitter ready for new data?
//			{
//				UDR1=GetByteFromSerialTransmitFifo();	// Send the byte.
//			}
//		}

		State();				// Execute the current program state.
	}
	return(0);
}

