/* commands.c */

/*
 * $Author: Espie $
 * $Date: 91/05/12 19:58:07 $
 * $Revision: 1.1 $
 * $Log:	commands.c,v $
 * Revision 1.1  91/05/12  19:58:07  Espie
 * Initial revision
 * 
 *
 */

#include <exec/types.h>
#include <custom/cleanup.h>
#include "player.h"
#include "song.h"
#include "lproto.h"


/***
 *
 *		Possible commands
 *
 ***/

/* the void operations */
	
void ignore(struct priv_play *private, struct automaton *cst)
	{
	}
	
void do_nothing(struct priv_play *private, struct automaton *cst)
	{
	}
 




void setup_porta_up(struct priv_play *private, struct automaton *cst)
	{
		cst->pursue = do_porta_up;
		if (private->e->parameters)
			cst->rate = private->e->parameters;
	}
	
void do_porta_up(struct priv_play *private, struct automaton *cst)
	{
		cst->period-= cst->rate;
		if (cst->period < 113)
			{
				cst->period = 113;
				cst->pursue = do_nothing;
			}
		new_period(private, cst);
	}
	



void setup_porta_down(struct priv_play *private, struct automaton *cst)
	{
		cst->pursue = do_porta_down;
		if (private->e->parameters)
			cst->rate = private->e->parameters;
	}

void do_porta_down(struct priv_play *private, struct automaton *cst)
	{
		cst->period+= cst->rate;
		new_period(private, cst);
	}


void setup_portamento(struct priv_play *private, struct automaton *cst)
	{
		if (private->e->parameters)
			cst->rate = private->e->parameters;
		if (private->e->note != NO_NOTE)
			{
				cst->note = private->e->note;
				cst->pergoal = compute_period(private, cst);
			}
		if (cst->period < cst->pergoal)
			cst->pursue = do_porta0;
		if (cst->period > cst->pergoal)
			cst->pursue = do_porta1;
	}

void do_porta0(struct priv_play *private, struct automaton *cst)
	{
		cst->period += cst->rate;
		if (cst->period > cst->pergoal)
			{
				cst->period = cst->pergoal;
				cst->pursue = do_nothing;
			}
		new_period(private, cst);
	}

void do_porta1(struct priv_play *private, struct automaton *cst)
	{
		cst->period -= cst->rate;
		if (cst->period < cst->pergoal)
			{
				cst->period = cst->pergoal;
				cst->pursue = do_nothing;
			}
		new_period(private, cst);
	}
	


void setup_volume_slide(struct priv_play *private, struct automaton *cst)
	{
		if (private->e->parameters>>4)
			{
				cst->rate = private->e->parameters>>4;
				cst->pursue = do_vol_slide0;
			}
		else
			{
				cst->rate = private->e->parameters;
				cst->pursue = do_vol_slide1;
			}
	}

void do_vol_slide0(struct priv_play *private, struct automaton *cst)
	{
		cst->volume += cst->rate;
		if (cst->volume > 64)
			{
				cst->volume = 64;
				cst->pursue = do_nothing;
			}
		new_volume(private, cst);
	}

void do_vol_slide1(struct priv_play *private, struct automaton *cst)
	{
		if (cst->volume <= cst->rate)
			{
				cst->volume = 0;
				cst->pursue = do_nothing;
			}
		else
			cst->volume -= cst->rate;
		new_volume(private, cst);
	}
	



void setup_arpeggio(struct priv_play *private, struct automaton *cst)
	{
		if (private->e->parameters == 0)
			cst->pursue = do_nothing;
		else
			{					
				/* we need the instrument period table
				 * to retrieve periods for arpeggio
				 */			
				cst->arp1 = cst->note + (private->e->parameters >> 4);
				cst->arp2 = cst->note + (private->e->parameters & 0xf);
					/* the arpeggio command is implemented
					 * as a 3-state automaton
					 */
				cst->pursue = do_arpeggio1;
			}
	}

void do_arpeggio0(struct priv_play *private, struct automaton *cst)
	{
		change_period(private, cst->channel, cst->p_table[cst->note]);
		cst->pursue = do_arpeggio1;
	}
	
	
void do_arpeggio1(struct priv_play *private, struct automaton *cst)
	{
		change_period(private, cst->channel, cst->p_table[cst->arp1]);
		cst->pursue = do_arpeggio2;
	}
	
void do_arpeggio2(struct priv_play *private, struct automaton *cst)
	{
		change_period(private, cst->channel, cst->p_table[cst->arp2]);
		cst->pursue = do_arpeggio0;
	}
	


	
void setup_vibrato(struct priv_play *private, struct automaton *cst)
	{
		cst->pursue = do_vibrato;
		cst->speed = (private->e->parameters & 0xf0)>>3;
		cst->depth = private->e->parameters & 0xf;
	}

void do_vibrato(struct priv_play *private, struct automaton *cst)
	{
		change_period(private, cst->channel, cst->period
			+ ( (private->sine_table[(cst->offset>>2) & 31]
			* cst->depth) >> 5));
		cst->offset += cst->speed;
	}
	

/* 
 * the following commands don't set up anything 
 */
 
void do_fastskip(struct priv_play *private, struct automaton *cst)
	{
		private->fastskip = private->e->parameters;
	}
	
void do_change_volume(struct priv_play *private, struct automaton *cst)
	{
		cst->volume = private->e->parameters;
		new_volume(private, cst);
	}


void do_skip(struct priv_play *private, struct automaton *cst)
	{
			/* another quirk, this parameter is BCD */
		private->skip = (private->e->parameters)&0xf
				+ 10 * (private->e->parameters>>4);
	}

void do_change_speed(struct priv_play *private, struct automaton *cst)
	{
		private->newspeed = private->e->parameters;
	}
		
void do_change_filter(struct priv_play *private, struct automaton *cst)
	{
		private->filter = !private->e->parameters;
		install_filter(private);
	}
