/* RandomTuneTask -- Random Tune for the Feeling Abaondoned speaker
 */
#include <Tunes.h>	// get extern defines
#include <pitches.h>	// get note defines

// get the prototypes for the schip-scheduler
//  (hidden in arduino-1.0.4/hardware/arduino/cores/schip
//   and accessed from default cores/arduino directory)
//#include "schip/scheduler.h"
#include <schip.h>

//#define TESTTUNE	// Just do 50 notes and quit for testing

// minimums
#define MINDUR	16	// 1ms ticks
#define MINLEN	21  // 1ms ticks
#define MINPIT	NOTE_F1	// F1 is a count of 44

// one random number to rule them all
typedef union
{
  word w;			// needed to do casting
  struct			// actual bits'n'things
  {
	word pit:4;	// 16 possible pitches
	word dur:4;	// 16 possible durations
	word len:5;	// 32 possible lengths
  };
} RND;

RND Mask;	// to limit range of random values

// generates a random melody and reposts itself
// @param ind -- index into Melody, ignored here,
//                 unless used for testing length limit
static void RandomTuneTask( word ind )
{
	word pitch;
	word duration;
	word length;
	word x;
	RND rnd;

#ifdef TESTTUNE	// Just do 50 notes and quit for testing
	// use this for testing to limit length of sequence...
	if( ind > 50 )	return;
#endif

	// if nothing to do, don't do it
	if( !(Tunes::Melody == (Note*)0xffff) )	return;

	// AND range mask to values so we can make it more excited
	// TODO should do an OR on bottom bits to make less excited too...
	rnd.w = (random( 0xFFFF ) & Mask.w);

	// pitch is one of 16 values from 44 to 164 in steps of 8 counts
	pitch = ( (rnd.pit << 3) + MINPIT );
	// make duration an inverse function of pitch
	//  this will range from (200-164+16=)52 to (200-44+16=)172
	x = (200 - pitch) + MINDUR;
	// duration is one of 16 values from 52 to 232ms
	duration = ( (rnd.dur << 2) + x );
	// length is one of 32 values from 21 to 2005 in steps of 64
	//   we have the 4 top bits to work with from 0x07D5 to 0x0055
	length = ( (rnd.len << 6) + MINLEN );

	// arg -- argument to the next call of this function (next Melody index)
	// duration -- ON ticks of this note
	// length -- ticks until next event
	// pitch -- buzzer frequency
	// play() reposts the current task if length != 0
	Tunes::play( ++ind, pitch, duration, length );

	return;
}

// start playing randomly
void Tunes::startRandomTune()
{
	// fake out the stop flag... when Melody == 0 we stop
	Tunes::Melody = (Note*)0xffff;
	// default to everything on
	Mask.w = 0xffff;

	postTask( 0, RandomTuneTask, 0 );

	return;
}

/** set the range parameters for RandomTune
 *   mask applied to random selections:
 *	word pitch -- frequency (low 4 bits)
 *	word duration -- ON ticks (low 4 bits)
 *	word length -- ticks until next event (low 5 bits)
 **/
void Tunes::setRandomRange( byte pitch, byte duration, byte length )
{
	Mask.pit = pitch;
	Mask.dur = duration;
	Mask.len = length;

	return;
}
