/*
	Skeleton for Player class
*/
#include <InterfaceKit.h>
#include <StorageKit.h>
#include <Font.h>
#include "Player.h"
#include "amp.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

#define AUDIO
#include "proto.h"
#include "audio.h"
#include "getbits.h"
#include "huffman.h"
#include "layer3.h"
#include "layer2.h"
#include "transform.h"

static uchar large_icon[] = {
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,
0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,
0xff,0xff,0x00,0x3f,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x2a,0x00,0x10,0x00,0x3f,0xac,
0xac,0x23,0x00,0x10,0x00,0x3f,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x2a,0x00,0x10,0xff,
0xff,0xff,0x00,0x5a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2f,0x00,0x10,0x00,0xac,0x23,
0x23,0x26,0x00,0x10,0x00,0x5a,0x2a,0x2a,0x2f,0x2f,0x2f,0x2f,0x2f,0x00,0x10,0xff,
0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0x00,0xac,0x23,
0x23,0x26,0x00,0x10,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x00,0x00,0x00,0x00,0x10,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0x00,0xac,0x23,
0x23,0x26,0x00,0x10,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0x10,0x10,0x10,0x10,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0x00,0xac,0x23,
0x23,0x26,0x00,0x10,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0x00,0xac,0x23,
0x23,0x26,0x00,0x10,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0x00,0xac,0x23,
0x23,0x26,0x00,0x10,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0x00,0xac,0x23,
0x23,0x26,0x00,0x10,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0x00,0xac,0x23,
0x23,0x26,0x00,0x10,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0x00,0xac,0x23,
0x23,0x26,0x00,0x10,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0x00,0xac,0x23,
0x23,0x26,0x00,0x10,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0x00,0xac,0x23,
0x23,0x26,0x00,0x10,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0x00,0xac,0x23,
0x23,0x26,0x00,0x10,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0x00,0xac,0x23,
0x23,0x26,0x00,0x10,0x00,0x5a,0x2a,0x2a,0x2f,0x00,0x00,0x00,0x00,0x00,0xff,0xff,
0xff,0xff,0x00,0x3f,0x5a,0x5a,0x5a,0x5a,0x2a,0x2a,0x2f,0x00,0x10,0x00,0xac,0x23,
0x23,0x26,0x00,0x10,0x00,0x5a,0x2a,0x2a,0x2a,0x5a,0x5a,0x5a,0x2a,0x00,0x10,0xff,
0xff,0xff,0x00,0x2a,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x00,0x10,0x00,0x23,0x26,
0x26,0x26,0x00,0x10,0x00,0x2a,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x00,0x10,0xff,
0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0xff,
0xff,0xff,0xff,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0xff,0x10,0x10,
0x10,0x10,0x10,0x10,0xff,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,
0xff,0x00,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0x00,0x00,0xfa,0xfa,0xfa,0xfa,0xfa,
0x00,0x00,0xfa,0xfa,0xfa,0xfa,0xfa,0x00,0x00,0xfa,0xfa,0xfa,0x00,0x10,0xff,0xff,
0xff,0x00,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0x00,0xfa,0xfa,0x00,0x00,0xfa,
0xfa,0x00,0xfa,0xfa,0x00,0x00,0x00,0x00,0xfa,0xfa,0x00,0x00,0x00,0x00,0x00,0xff,
0xff,0x00,0xfa,0xfa,0x00,0xfa,0xfa,0x00,0xfa,0xfa,0x00,0xfa,0xfa,0xcb,0xcb,0xfa,
0xfa,0x00,0xfa,0xfa,0xfa,0xfa,0xfa,0x00,0xfa,0xfa,0x00,0xfa,0xfa,0xfa,0x00,0x10,
0xff,0x00,0xfa,0xfa,0x00,0xfa,0xfa,0x00,0xfa,0xfa,0x00,0xfa,0xfa,0xfa,0xfa,0xfa,
0x00,0x00,0xfa,0xfa,0x00,0x00,0x00,0x00,0xfa,0xfa,0x00,0x00,0xfa,0xfa,0x00,0x10,
0xff,0x00,0xfa,0xfa,0x00,0xfa,0xfa,0x00,0xfa,0xfa,0x00,0xfa,0xfa,0x00,0x00,0x00,
0x00,0x00,0xfa,0xfa,0xfa,0xfa,0xfa,0x00,0x00,0xfa,0xfa,0xfa,0xfa,0x00,0x00,0x10,
0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x10,0xff,
0xff,0xff,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0xff,0xff,
0xff,0xff,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0xff,0x10,0x10,0x10,0x10,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
};
static uchar small_icon[] = {
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,
0x00,0x3f,0x5a,0x5a,0x7b,0x00,0x3f,0xac,0x22,0x00,0x3f,0x5a,0x5a,0x7b,0x00,0x10,
0x00,0x5a,0x2a,0x2a,0x2f,0x00,0xac,0x22,0x26,0x00,0x5a,0x2a,0x2a,0x2a,0x00,0x10,
0x00,0x00,0x7b,0x2a,0x2f,0x00,0xac,0x22,0x26,0x00,0x5a,0x2a,0x2f,0x00,0x00,0x10,
0x10,0x00,0x7b,0x2a,0x2f,0x00,0xac,0x22,0x26,0x00,0x7b,0x2a,0x2f,0x00,0x10,0x10,
0xff,0x00,0x7b,0x2a,0x2f,0x00,0xac,0x22,0x26,0x00,0x7b,0x2a,0x2f,0x00,0x10,0xff,
0xff,0x00,0x7b,0x2a,0x2f,0x00,0xac,0x22,0x26,0x00,0x7b,0x2a,0x2f,0x00,0x10,0xff,
0xff,0x00,0x7b,0x2a,0x2f,0x00,0xac,0x22,0x26,0x00,0x7b,0x2a,0x2f,0x00,0x10,0xff,
0xff,0x00,0x7b,0x2a,0x2f,0x00,0xac,0x22,0x26,0x00,0x7b,0x2a,0x2f,0x00,0x10,0xff,
0x00,0x00,0x7b,0x2a,0x2f,0x00,0xac,0x22,0x26,0x00,0x7b,0x2a,0x2f,0x00,0x00,0xff,
0x00,0x3f,0x7b,0x2a,0x2f,0x00,0xac,0x22,0x26,0x00,0x7b,0x2a,0x2f,0x2f,0x00,0x10,
0x00,0x7b,0x2f,0x2f,0xf7,0x00,0x22,0x26,0x29,0x00,0x2f,0x2f,0x2f,0xf7,0x00,0x10,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,
0xff,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
}; 

char *mimelist[]=
{
	"audio/mpeg",
	NULL
};

#define PLAYER_NAME "DualMP V1.02"

sem_id     	 ok_to_read, ok_to_write;
thread_id	 thread;
bool		 running=FALSE;
struct AUDIO_HEADER header;
Object		*dual_object=0;
char 		*au_buf;
int32 		 au_siz;

static char *t_modes[] = {
        "Stereo","Joint Stereo","Dual Channel","Single Channel"};


class PrefsView;

struct instance_struct
{
	PrefsView	*prefs_view;
	BMessage 	*prefs;
	bool		loop;
	int			volume;
	int			oldvol;
	int 		pos;
	int			spccnt;
	int			track;
	char		actfile[1023];
	int			frequency;
	int			stereo;
	int			length;
	BFont		*plain;
	BFont		*bold;
};

class PrefsView : public BView
{
	instance_struct	*inst;

	public:
				PrefsView(instance_struct *i):BView(BRect(0,0,199,179),"PrefsView",NULL,B_WILL_DRAW)
				{
					inst=i;
				};
		
	void		Draw(BRect frame)
				{
					SetHighColor(200,0,0);

					
#define OFF_X 34
#define OFF_Y 10
					
					FillRect(BRect(OFF_X+0,OFF_Y,OFF_X+44,OFF_Y+11));
					FillRect(BRect(OFF_X+22,OFF_Y,OFF_X+44,OFF_Y+66));
					FillRect(BRect(OFF_X+0,OFF_Y+55,OFF_X+44,OFF_Y+66));

					FillRect(BRect(OFF_X+88,OFF_Y,OFF_X+88+44,OFF_Y+11));
					FillRect(BRect(OFF_X+88,OFF_Y,OFF_X+88+22,OFF_Y+66));
					FillRect(BRect(OFF_X+88,OFF_Y+55,OFF_X+88+44,OFF_Y+66));
					
					SetHighColor(0,0,200);
		
					FillRect(BRect(OFF_X+54,OFF_Y,OFF_X+78,OFF_Y+66));
					
					SetHighColor(0,0,0);
					
					SetDrawingMode(B_OP_OVER);
					SetFont(inst->bold);
					const char *version="MPEG layer2 and layer3";
					SetFontSize(14);
					DrawString(version,BPoint((200-StringWidth(version))/2,OFF_Y+66+14+6));
					SetFontSize(11);
					const char *world="The worlds fastest MPEG player!";
					DrawString(world,BPoint((200-StringWidth(world))/2,120));
					SetFont(inst->plain);
					SetFontSize(9);					
					const char *copy1="©1997 by Tomislav Uzelac";
					DrawString(copy1,BPoint((200-StringWidth(copy1))/2,152));
					const char *copy2="Player & PowerPC optimisations by Tinic Uro";
					DrawString(copy2,BPoint((200-StringWidth(copy2))/2,164));
					const char *copy3="Standalone version (BeMP) by Andy Lo A Foe";
					DrawString(copy3,BPoint((200-StringWidth(copy3))/2,176));
					BView::Draw(frame);
					Sync();
				}
};

static char *extract_name(char *path)
{
	int c=strlen(path);
	int pos=0;
	
	for(int i=0;i<c;i++)
		if(path[i]=='/') pos=i+1;

	return &path[pos];
}

int processHeader(struct AUDIO_HEADER *header, int cnt)
{
	int g;

	if (cnt==1) memcpy(&buffer[BUFFER_SIZE],buffer,4);
	
	if ((g=gethdr(header))!=0) {
		return(1);
	}

	if (header->protection_bit==0) getcrc();

	return(0);
}

static bool do_forward=FALSE;
static long frame_size=0;
static long frame_seek=0;
static long frame_table[262144]; // Should be enough...
static long frame_cnt;

int seek_to_frame(long frame)
{
	char buffer[4096];

	if(frame_cnt>=frame)
	{
		fseek(in_file,frame_table[frame],SEEK_SET);	    
	    return frame;
	}
	else
	{
		dual_object->DoMethod(D_NEW_MESSAGE,"Please wait...");
		for(int i=frame_cnt;i<(frame);i++)
		{
			frame_table[i]=ftell(in_file);
			frame_cnt=i;
			
			if (processHeader(&header,i)) goto fail1;
			fread(buffer,1,frame_size-4+header.padding_bit,in_file);
		}
		
		return frame;
	}

fail1:

	fseek(in_file,0,SEEK_SET);
	return 0;
}

void looper(instance_struct *inst)
{
	bool restarted=FALSE;
restart:
	for (int cnt=0;;cnt++) 
	{		
		if(do_forward)
		{	
			if(inst->spccnt>1)
			{
				inst->spccnt--;
			}
			else if(inst->spccnt==1)
			{
				inst->spccnt=0;
				do_forward=FALSE;
				inst->volume=inst->oldvol;
			}
			else
			{
				inst->oldvol=inst->volume;
				inst->volume=0;
				inst->spccnt=8;
				cnt=seek_to_frame(frame_seek);
			}
		}
		
		inst->pos=cnt;
		
		if(cnt || restarted)
		{
			frame_table[cnt]=ftell(in_file);
			frame_cnt=max_c(frame_cnt,cnt);	
			if (processHeader(&header,cnt))goto fail;
		}
		if (header.layer==1) 
		{
			if (layer3_frame(&header,cnt)) goto fail;
		}
		else if(header.layer==2) 
		{
			if (layer2_frame(&header,cnt)) goto fail;
		}		
		if(cnt==0)
		{
			frame_size=ftell(in_file);
			restarted=TRUE;
		}		
	}
	
fail:
	
	if(inst->loop)
	{
		fseek(in_file,0,SEEK_SET);
		goto restart;
	}

	running=FALSE;

	if(ok_to_read)
	{
		delete_sem(ok_to_read);
		ok_to_read=0;
	}
	if(ok_to_write)
	{
		delete_sem(ok_to_write);
		ok_to_write=0;
	}	
	
	while(1){}
}

long class_dispatcher(Class *c, Object *o, ulong MethodID, ulong *data)
{
	instance_struct *inst=(instance_struct *)o->Instance(c);	

	o->SetError(B_NO_ERROR);

	switch(MethodID)
	{

		case	B_METHOD_CONSTRUCT:	// void (void)
				{					
					inst->prefs_view = new PrefsView(inst);
					inst->prefs = NULL;
				    
				    args(0,0);
				    imdct_init();
				    premultiply();
				    
				    thread=NULL;

					BMimeType *mime = new BMimeType("audio/mpeg");
					if(!mime->IsInstalled())
					{
						BBitmap *large = new BBitmap(BRect(0,0,31,31),B_COLOR_8_BIT);
						large->SetBits(large_icon,32*32,0,B_COLOR_8_BIT);
						BBitmap *mini = new BBitmap(BRect(0,0,15,15),B_COLOR_8_BIT);
						mini->SetBits(small_icon,16*16,0,B_COLOR_8_BIT);

						BMessage *msg = new BMessage();
						msg->AddData("extensions",'MXTT',"mp3",4);
						mime->SetIcon(large,B_LARGE_ICON);
						mime->SetIcon(mini,B_MINI_ICON);
						mime->SetFileExtensions((const BMessage *)msg);
						mime->SetPreferredApp("application/x-tinic.DualPlayer");
						mime->SetShortDescription("MPEG Layer3 file");
						mime->SetLongDescription("Audio MPEG file in layer3 format.");
						mime->Install();

						delete msg;
						delete large;
						delete mini;
					}
					delete mime;

					inst->plain = new BFont(be_plain_font);
					inst->bold = new BFont(be_bold_font);
					inst->plain->SetSpacing(B_BITMAP_SPACING);
					inst->bold->SetSpacing(B_BITMAP_SPACING);
					
					return 0;
				}

		case	B_METHOD_DESTROY:	// void (void)
				{				
					delete inst->plain;
					delete inst->bold;
					
					return 0;
				}				
				
		case	P_LOAD:				// bool handle (char *path)
				{			
					char *path=(char *)data[0];

					BNode *node = new BNode(path);
					off_t l;
					node->GetSize(&l);
					inst->length=l;

					au_buf=0;

					if ((in_file=fopen(path,"r"))==NULL) 
					{
						return FALSE;
					}
										
					strcpy(inst->actfile,extract_name(path));
					
				    ok_to_read = create_sem(0, "streambuf read");
    				ok_to_write = create_sem(0, "streambuf write"); 

					if (processHeader(&header,0))
					{
						fclose(in_file);
						return FALSE;
					}

					BNodeInfo *nodeinfo = new BNodeInfo(node);
					nodeinfo->SetType("audio/mpeg");
					delete nodeinfo;
					delete node;

					frame_size=0;
					frame_table[0]=0;
					frame_cnt=0;

					inst->frequency=t_sampling_frequency[header.ID][header.sampling_frequency];
					inst->stereo=(header.mode!=3);
					
					running=TRUE;
					
					dual_object->DoMethod(D_NEW_MESSAGE,"DualMP 1.02, by Tinic Urou & Andy Lo a Foe");

					resume_thread(thread=spawn_thread((thread_entry)looper,"looper",B_MEDIA_LEVEL,(void *)inst));

					return TRUE; 
				}
									
		case	P_FREE:				// void (int handle)
				{
					int handle=(int)data[0];

					if(ok_to_read)
					{
						delete_sem(ok_to_read);
						ok_to_read=0;
					}
					if(ok_to_write)
					{
						delete_sem(ok_to_write);
						ok_to_write=0;
					}	

					running=FALSE;

					if(thread)kill_thread(thread);
					if(in_file)fclose(in_file);
					if(au_buf)free(au_buf);
					
					au_buf=0;
					
					return 0;
				}
					
		case	P_SETUPSTREAM:		
				{
					return 0;
				}
				
		case	P_STREAM:			// bool (void *arg, char *buffer, int size)
				{
					void *arg		= (void *)data[0];
					char *buffer	= (char *)data[1];
					int size		= (int)   data[2];

					
					au_siz=size;
					if(au_buf==0)
					{	
						if(au_buf=(char *)malloc(au_siz))	release_sem(ok_to_write);
						else 								return 0;
					}
					
					if(acquire_sem(ok_to_read)==B_NO_ERROR)
					{
						short *b=(short *)buffer;
						
						memcpy(b,au_buf,au_siz);						
						release_sem(ok_to_write);

						for(int i=0;i<size/2;i++)
						{
							int v=((int)b[i]*inst->volume)/128;
							b[i]=(v>32767) ? 32767 : ((v<-32768) ? -32768 : v);
						}			    
					}

					if(running)	return 1; 
					else		return 0;
				}
				
		case	P_SETATTR:			//  void (ulong AttributeID, ulong data)
				{
					ulong ATTR =(ulong)data[0];
					ulong DATA =(ulong)data[1];

					switch(ATTR)
					{
						case	P_ATTR_PREFS:				// Setup the pointer to the preferences BMessage
								inst->prefs=(BMessage *)DATA;
								break;
						case	P_ATTR_BOOST:				// Set volume 0..128, special boost from 128..255
								inst->volume=(int)DATA;
								break;
						case	P_ATTR_LOOP:				// Loop the file?
								inst->loop=(bool)DATA;
								break;
						case	P_ATTR_MODPOS:
								frame_seek=((inst->length*DATA)/100)/frame_size;
								do_forward=TRUE;
								break;
						case	P_ATTR_DUALOBJECT:
								dual_object=(Object *)DATA;
								break;
					}
					o->DoSuperMethod(c,P_SETATTR,data);
					return 0;
				}
				
		case	P_GETATTR:			//  void (ulong AttributeID, ulong data)
				{
					ulong ATTR =(ulong)data[0];
					ulong DATA =(ulong)data[1];

					switch(ATTR)
					{
						case	P_ATTR_ID:					// ID String which is displayed in the ListView, this must be valid!
								*((char **)DATA)=PLAYER_NAME;
								break;
						case	P_ATTR_VIEW:				// Get the pointer to the Preferences BView, this must be valid!
								*((BView **)DATA)=inst->prefs_view;
								break;
						case	P_ATTR_RECOGNITION:			// return 0 when there are no tracks.
								*((int *)DATA)=50;
								break;
						case	P_ATTR_MODLENGTH:
								*((int *)DATA)=100;
								break;
						case	P_ATTR_MODPOS:
								if(!do_forward)
								{
									*((int *)DATA)=((ftell(in_file)*100)/inst->length);
								}
								break;
						case	P_ATTR_MIME:
								*((char ***)DATA)=mimelist;
								break;
						default:
								return o->DoSuperMethod(c,P_GETATTR,data);
					}
					return 0;
				}
				
		case	P_DRAWSTATUS:		// void (BView *view)
				{
					char str[256];
					BView *view=(BView *)data[0];

					view->MovePenTo(BPoint(4, 11));
					view->DrawString("File");
					view->MovePenTo(BPoint(40, 11));
					sprintf(str,": %s",inst->actfile);
					view->DrawString(str);
					view->MovePenTo(BPoint(4, 22));
					view->DrawString("Type");
				 	view->MovePenTo(BPoint(40, 22));
				 	sprintf(str,": Layer%d %s",4-header.layer,t_modes[header.mode]);
					view->DrawString(str);
					view->MovePenTo(BPoint(4, 33));
					view->DrawString("Bitrate");
					view->MovePenTo(BPoint(40, 33));
					sprintf(str,": %d",t_bitrate[header.ID][3-header.layer][header.bitrate_index]);
					view->DrawString(str);
					
					return 0;
				}
				
		case	P_POSITIONSTRING:
				{
					char *str=(char *)data[0];
					int allowedsize=(int)data[1];
					long value=(long)data[2];
				
					sprintf(str,"%d%%",value);
					
					return 0;
				}
				break;
				
		case	P_CREATEINFO: 		// void (char ***info)
				{
					char ***info=(char ***)data[0];

					*info=0;	// Safety settings
																		
					return 0;
				}

		case	P_FREEINFO: 		// void (char ***info)
				{
					char ***info=(char ***)data[0];
					
					return 0;
				}

		default:
				return o->DoSuperMethod(c,MethodID,data);
	}
}

char *class_superclass()	// Superclassname for ALL players
{
	return "dualplayer/player/baseplayer.zclass";
};

long class_instancesize()
{
	return sizeof(struct instance_struct);
};

long class_superversion()	// minimum version needed of the superclass
{
	return 2;
};

long class_version()		// This class version
{
	return 2;
};
