
#define AUDIO
#define BUFSIZE  18432 * 8


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <proto/exec.h>
#include <exec/types.h>
#include <exec/libraries.h>
#include <exec/lists.h>
#include <exec/memory.h>
#include <libraries/prelude.h>
#include <clib/prelude_protos.h>
#include <ppcpragmas/prelude_pragmas.h>
#include <proto/dos.h>

#include "amp.h"
#include "audio.h"
#include "getbits.h"
#include "huffman.h"
#include "layer2.h"
#include "layer3.h"
#include "transform.h"
#include "misc2.h"
#include "dump.h"

extern struct ExecBase *SysBase;
struct PreludeBase *PreludeBase=NULL;

BYTE	signal;
ULONG	Signals;

UBYTE	*PlayBuffer[2];
ULONG	Buffer;
ULONG BufferFill;
UBYTE *BufferPointer;

ULONG PlayCnt;
ULONG PlayMode;
ULONG PlayFreq;
BOOL snd_eof;


int main(int argc, char **argv) {
	struct Task *ThisTask;
	struct PrlCtrl *prl;
	BYTE OldPri;

	ThisTask=FindTask(NULL);

	PreludeBase=(struct PreludeBase *)OpenLibrary("prelude.library", 2);
	if(PreludeBase==NULL) {
		fprintf(stderr, "\nError: Can't open prelude.library v2\n\n");
		return(5);
	}

	PlayBuffer[0]=PPCAllocVec(BUFSIZE, MEMF_CLEAR|MEMF_PUBLIC);
	PlayBuffer[1]=PPCAllocVec(BUFSIZE, MEMF_CLEAR|MEMF_PUBLIC);

	if(PlayBuffer[0]==NULL || PlayBuffer[1]==NULL) {
		if(PlayBuffer[0]) PPCFreeVec(PlayBuffer[0]);
		fprintf(stderr, "\nError: Out of memory for playback buffers\n\n");
		return(5);
	}

	prl=PreludeBase->PrlCtrl;
	prl->PL_SigTask=ThisTask;
	signal=AllocSignal(-1);
	prl->PL_SigMask=1L<<signal;

	A_DUMP_BINARY=FALSE;
	A_QUIET=FALSE;
	A_FORMAT_WAVE=FALSE;
	A_SHOW_CNT=FALSE;
	A_SET_VOLUME=-1;
	A_SHOW_TIME=1;
	A_AUDIO_PLAY=FALSE;
	A_WRITE_TO_FILE=TRUE;
	A_MSG_STDOUT=FALSE;
	A_DOWNMIX=FALSE;


	initialise_decoder();

	if(argc != 2) {
		fprintf(stderr, "\nUsage PreludeAMP [infilename]\n\n");
		return(5);
	}

	Buffer=0;
	BufferPointer=PlayBuffer[0];
	BufferFill=0;
	PlayCnt=0;

	fprintf(stderr, "\n\
-------------------------------------------\n\
PreludeAMP 0.4 - (C) 1998, by Thomas Wenzel\n\
based on amp (C) Tomislav Uzelac  1996,1997\n\
-------------------------------------------\n\
");

	OldPri=SetTaskPri(ThisTask, 5);
	play(argv[1], 0);
	SetTaskPri(ThisTask, OldPri);

	PrlStop(0);
	KillPrlPlayList();

	PPCFreeVec(PlayBuffer[0]);
	PPCFreeVec(PlayBuffer[1]);

	if(signal != -1) FreeSignal(signal);

	CloseLibrary((struct Library *) PreludeBase);
	return(0);
}



/* call this once at the beginning */
void initialise_decoder(void) {
	premultiply();
	imdct_init();
	calculate_t43();
}

/* call this before each file is played */
void initialise_globals(void) {
	append=data=nch=0; 
	f_bdirty=TRUE;
	bclean_bytes=0;

	memset(s,0,sizeof s);
	memset(res,0,sizeof res);
}


void play(char *inFileStr, char *outFileStr) {
	if (strcmp(inFileStr,"-")==0) {
		in_file=stdin;
	}
	else {
		if ((in_file=fopen(inFileStr,"r"))==NULL) {
			fprintf(stderr, "Could not open file: %s\n",inFileStr);
			return;
		}
	}
	if (outFileStr) {
		if (strcmp(outFileStr,"-")==0)
			out_file=stdout;
	else
		if ((out_file=fopen(outFileStr,"w"))==NULL) {
			fprintf(stderr, "Could not write to file: %s\n",outFileStr);
			return;
		}
	}

	decodeMPEG();
	
	fclose(in_file);
	if (!A_AUDIO_PLAY) fclose(out_file);
	fprintf(stderr, "\n");
}

int decodeMPEG(void) {
	struct AUDIO_HEADER header;
	int cnt=0,g;

	initialise_globals();

	if ((g=gethdr(&header))!=0) {
		report_header_error(g);
		return -1;
	}

	if (header.protection_bit==0) getcrc();

	show_header(&header);

	if (header.layer==1) {
		if (layer3_frame(&header,cnt)) {
			fprintf(stderr, " error. blip.\n");
			return -1;
		}
	} else if (header.layer==2)
		if (layer2_frame(&header,cnt)) {
			fprintf(stderr, " error. blip.\n");
			return -1;
		}


	if (nch==2) PlayMode = PRL_FMT | PRL_FMTX | PRL_Stereo;
	else        PlayMode = PRL_FMT | PRL_FMTX;
	PlayFreq=t_sampling_frequency[header.ID][header.sampling_frequency];

	/*
	 * decoder loop **********************************
	 */
	snd_eof=FALSE;
	cnt=0;
	while (!snd_eof) {
		while (!snd_eof) {
			if ((g=gethdr(&header))!=0) {
			report_header_error(g);
				snd_eof=TRUE;
				break;
      }

			if (header.protection_bit==0) getcrc();

			statusDisplay(&header,cnt);	

			if (header.layer==1) {
				if (layer3_frame(&header,cnt)) {
					fprintf(stderr, " error. blip.\n");
					return -1;
				}
			} else if (header.layer==2)
				if (layer2_frame(&header,cnt)) {
					fprintf(stderr, " error. blip.\n");
					return -1;
				}
			cnt++;
		}
	}
	return 0;
}

void report_header_error(int err) {
	switch (err) {
		case GETHDR_ERR: fprintf(stderr, "error reading mpeg bitstream. exiting.\n");
		                 break;
		case GETHDR_NS:  fprintf(stderr, "this is a file in MPEG 2.5 format, which is not defined\n");
		                 fprintf(stderr, "by ISO/MPEG. It is \"a special Fraunhofer format\".\n");
		                 fprintf(stderr, "amp does not support this format. sorry.\n");
		                 break;
		case GETHDR_FL1: fprintf(stderr, "ISO/MPEG layer 1 is not supported by amp (yet).\n");
		                 break;
		case GETHDR_FF:  fprintf(stderr, "free format bitstreams are not supported. sorry.\n");
		                 break;	
		case GETHDR_SYN: fprintf(stderr, "oops, we're out of sync.\n");
                     break;
		case GETHDR_EOF: break;
	}	
}


void statusDisplay(struct AUDIO_HEADER *header, int frameNo) {
	int minutes,seconds;

	if ((A_SHOW_CNT || A_SHOW_TIME) && !(frameNo%10))
		fprintf(stderr, "\r");
	if (A_SHOW_CNT && !(frameNo%10) ) {
		fprintf(stderr, "Frame { %d } ",frameNo);
	}
	if (A_SHOW_TIME && !(frameNo%10)) {
		seconds=frameNo*1152/t_sampling_frequency[header->ID][header->sampling_frequency];
		minutes=seconds/60;
		seconds=seconds % 60;
		fprintf(stderr, "Time [%d:%02d]", minutes, seconds);
	}
	if (A_SHOW_CNT || A_SHOW_TIME)
		fflush(stderr);
}

BOOL WayBehind=FALSE;
void printout(void) {
	int len;
	int j;

	if (nch==2) j=32 * 18 * 2;
	else        j=32 * 18;

	len=sizeof(short)*j;

	memcpy(BufferPointer, sample_buffer, len);
	BufferPointer += len;
	BufferFill    += len;

	if(BufferFill >= BUFSIZE) {
		PrlPlay(PlayBuffer[Buffer], BUFSIZE, PlayMode, PlayFreq);
		Buffer=1-Buffer;

		BufferPointer=PlayBuffer[Buffer];
		BufferFill=0;

		PlayCnt++;
		if(PlayCnt >1) Signals=Wait(1L<<signal | SIGBREAKF_CTRL_C);

		if(Signals & SIGBREAKF_CTRL_C) snd_eof=TRUE;
	}
}

void die(char *str, ...) {
}
