Program SelfTestPlayer;

{$librarypath '../blibs'}
uses atari, sysutils, b_crt, graph;

const
	AUDF1 = $D200;
	AUDCTL = $D208;
	RTCLOCK = $14; 
	XITVBV = $E462;
	SYSVBV = $E45F;
	
	Melody0: array[0..30] of byte = (
		0, 0, 6,			// clockVal=0, noteNum=0, notes
		16, 0, 0, 0,		//init+delay @start
		32, 81, 168, 8,  // note  1: noteTime, audf, audc, audctl
		32, 91, 168, 8,  // note  2
		32, 68, 168, 8,  // note  3
		16, 60, 168, 8,  // note  4
		16, 45, 168, 8,  // note  5
		32, 53, 168, 8   // note  6
	);
	Melody1: array[0..34] of byte = (
		0, 0, 7,			// clockVal=0, noteNum=0, notes
		16, 0, 0, 0,		//init+delay @start
		32, 81, 168, 0,  // note  1: noteTime, audf, audc, audctl
		32, 91, 168, 0,  // note  2
		32, 68, 168, 0,  // note  3
		16, 60, 168, 0,  // note  4
		16, 45, 168, 0,  // note  5
		32, 53, 168, 0,  // note  6
		16,  0,  0,  0   // note  7
	);
	Melody2: array[0..34] of byte = (
		0, 0, 7,			// clockVal=0, noteNum=0, notes
		16, 0, 0, 0,		//init+delay @start
		32, 81, 168, 0,  // note  1: noteTime, audf, audc, audctl
		32, 91, 168, 0,  // note  2
		32, 68, 168, 0,  // note  3
		16, 60, 168, 0,  // note  4
		16, 45, 168, 0,  // note  5
		32, 53, 168, 0,  // note  6
		32,  0,  0,  0   // note  7
	);
	Melody3: array[0..34] of byte = (
		0, 0, 7,			// clockVal=0, noteNum=0, notes
		16, 0, 0, 0,		//init+delay @start
		32, 81, 168, 0,  // note  1: noteTime, audf, audc, audctl
		32, 91, 168, 0,  // note  2
		32, 68, 168, 0,  // note  3
		16, 60, 168, 0,  // note  4
		16, 45, 168, 0,  // note  5
		32, 53, 168, 0,  // note  6
		64,  0,  0,  0   // note  7
	);
	audioChannels = 4;

var
	i: byte = 0;
	oldVBL: pointer;

procedure PlayMelody; interrupt;

var
	melody_pos: word;
	melody_pos1: byte;
		currentAUDRej: word;
		currentMelodyAdr: word;
		channelCounter: byte;
		timeCounter: byte;

begin

	//asm { phr ; store registers };
	channelCounter := 0;
	timeCounter := Peek(RTCLOCK);
	//
	repeat
	
		case channelCounter of
			0: currentMelodyAdr := word(@Melody0);
			1: currentMelodyAdr := word(@Melody1);
			2: currentMelodyAdr := word(@Melody2);
			3: currentMelodyAdr := word(@Melody3);
		end;

	//melody_pos at the beginning points to position zero of the melody table,
	//now it's curruntNote[EndTime] == MelodyN[0]
	melody_pos:= currentMelodyAdr;

	// set the channel-specific register
	currentAUDRej:= AUDF1;
	inc(currentAUDRej, channelCounter shl 1);
	
	// update when it's time to play
	// - zero element /EndTime/ = timeCounter
	// 'equal' only for VBLK, outside VBLK use 'less than or equal'
	if (Peek(melody_pos) = timeCounter) then
		begin
			inc(melody_pos);
			
			//DO NOT USE UNDER VBLK!
			//Writeln(intToStr(timeCounter),' ',intToStr(Peek(currentMelodyAdr)),' ',intToStr(Peek(melody_pos)),' ',intToStr(Peek(melody_pos+1)),' ');
			
			//if the note number (melody_pos) 
			//is equal to the number of notes (melody_pos+1)
			if (Peek(melody_pos) = Peek(melody_pos+1)) then
			begin
				melody_pos1:= 0;// set the note to first one
			end
			else
			begin
				melody_pos1:= Peek(melody_pos)+1;// inc noteNum to next one
			end;
			
			Poke(melody_pos, melody_pos1); //set the current note number
			
			inc(melody_pos, 2); //jump over note counters to first note
			inc(melody_pos, melody_pos1 shl 2);  // jump further, if not first note, by noteNum*4
			// set timeCounter plus the time of this note to position zero /cloclVal/
			Poke(currentMelodyAdr, Peek(melody_pos)+timeCounter);  
			inc(melody_pos);  // move to audf of the note
			Poke(currentAUDRej, Peek(melody_pos));  // set currentAUDRej with audf
			inc(melody_pos);  // move to audc of the note
			inc(currentAUDRej);  // set register to AUDC of the chanel (AUDF+1)
			Poke(currentAUDRej, Peek(melody_pos));  // set AUDC with note audc
			inc(melody_pos);  // move to audctl of the note
			Poke(AUDCTL, Peek(melody_pos));  // set AUDCTL
		end;
		// go to the next audioChannel
		inc(channelCounter);
	until channelCounter >= audioChannels;

	//end the VBLD with the jump to XITVBV rpoc
	asm
		jmp XITVBV
	end;
end;

//
//InitPlayIn: set clockVal to current clock +10 to not wait for sync
//
procedure InitPlayIn;

var
	clockVal:byte;

begin
	clockVal:= Peek(RTCLOCK)+10;
	Poke (@Melody0, clockVal);
	Poke (@Melody1, clockVal);
	Poke (@Melody2, clockVal);
	Poke (@Melody3, clockVal);
end;

procedure InstallVBL; 
begin
	//getIntVec(iVBL, oldVBL);
	SetIntVec(iVBLD, @PlayMelody);
end;

//
// START PROGRAM
//
begin
		//Reserve memoryPage
		RAMTOP:=$50;
		InitGraph(0);
	 
		// Set graphics mode and playfield colors
		CRT_Init;
		CRT_Clear(0);
		//Poke(710, 122); Poke(712, 130);
		//Poke(709, 64);
		
		InitPlayIn;
	
	InstallVBL;
	
	repeat
	//PlayMelody;
		until CRT_KeyPressed;
	
end.