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

#include "config.h"
#include "common.h"
#include "instrum.h"
#include "playmidi.h"
#include "readmidi.h"
#include "output.h"
#include "controls.h"
#include "tables.h"
#include "Dual.h"
#include "Player.h"

static const 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,0x00,0x00,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,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,0x15,0x15,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,0x15,0x15,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,0x15,0x15,0xff,0xff,0xff,0xff,
0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0x00,0x00,0x00,0x00,0xab,0xab,0xab,
0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0x00,0x00,0xd1,0xd1,0xab,0xab,0xab,0xab,
0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0x00,0x00,0x0e,0x00,0x00,0x00,0xd1,0xd1,0xd1,
0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0x00,0x00,0xf7,0xf7,0xd1,0xd1,0xd1,0xd1,
0x62,0x62,0x62,0x62,0x62,0x62,0x00,0x0e,0x00,0x00,0x00,0x00,0x00,0x0d,0x0d,0x62,
0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x00,0x00,0x0d,0x0d,0x62,0x62,0x62,0x62,
0x62,0x62,0x62,0x62,0x62,0x00,0x00,0x00,0x00,0x62,0x62,0x00,0x00,0x0d,0x0d,0x62,
0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x00,0x00,0x0d,0x0d,0x62,0x62,0x62,0x62,
0x62,0x62,0x62,0x62,0x00,0x00,0x00,0x62,0x62,0x00,0x00,0x00,0x00,0x0d,0x0d,0x62,
0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x00,0x00,0x0d,0x0d,0x62,0x62,0x62,0x62,
0x62,0x62,0x62,0x62,0x00,0x00,0x62,0x00,0x00,0x0e,0x00,0x00,0x00,0x0d,0x0d,0x62,
0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x00,0x00,0x0d,0x0d,0x62,0x62,0x62,0x62,
0x62,0x62,0x62,0x00,0x00,0x62,0x00,0x0e,0x00,0x00,0x00,0x00,0x00,0x0d,0x0d,0x62,
0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x00,0x00,0x0d,0x0d,0x62,0x62,0x62,0x62,
0x62,0x62,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x62,0x62,0x00,0x00,0x0d,0x0d,0x62,
0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x00,0x00,0x0d,0x0d,0x62,0x62,0x62,0x62,
0x62,0x62,0x62,0x62,0x62,0x00,0x00,0x62,0x62,0x0d,0x0d,0x00,0x00,0x0d,0x0d,0x62,
0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x00,0x00,0x0d,0x0d,0x62,0x62,0x62,0x62,
0xab,0xab,0xab,0xab,0x00,0x00,0x00,0xd1,0xd1,0xd1,0xd1,0x00,0x00,0xd1,0xd1,0xab,
0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0x00,0x00,0xd1,0xd1,0xab,0xab,0xab,0xab,
0xd1,0xd1,0xd1,0xd1,0x00,0x00,0xd1,0xf7,0xf7,0xd1,0xd1,0x00,0x00,0xf7,0xf7,0xd1,
0xab,0x00,0x00,0x00,0x00,0x00,0xab,0xd1,0x00,0x00,0xf7,0xf7,0xd1,0xd1,0xd1,0xd1,
0x62,0x62,0x62,0x62,0x00,0x00,0x0d,0x0d,0x0d,0x62,0x62,0x00,0x00,0x0d,0x0d,0x00,
0x00,0x00,0x08,0x0d,0x08,0x00,0x00,0x00,0x00,0x00,0x0d,0x0d,0x62,0x62,0x62,0x62,
0x62,0x62,0x62,0x62,0x62,0x62,0x0d,0x0d,0x62,0x62,0x62,0x00,0x00,0x0d,0x00,0x00,
0x13,0xff,0xff,0xff,0xff,0xff,0x13,0x00,0x00,0x00,0x0d,0x0d,0x00,0x00,0x00,0x62,
0x62,0x62,0x62,0x62,0x62,0x62,0x0d,0x0d,0x62,0x62,0x62,0x00,0x00,0x0d,0x00,0x08,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x08,0x00,0x00,0x0d,0x0d,0x00,0x00,0x00,0x0d,
0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x00,0x00,0x0d,0x00,0x08,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x08,0x00,0x00,0x0d,0x0d,0x00,0x00,0x00,0x0d,
0x62,0x62,0x62,0xab,0x00,0x00,0x00,0x00,0x00,0xab,0x62,0x00,0x00,0x0d,0x00,0x00,
0x13,0xff,0xff,0xff,0xff,0xff,0x13,0x00,0x00,0x0d,0x0d,0x0d,0x62,0x0d,0x0d,0x0d,
0x62,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x0d,0x00,
0x00,0x00,0x08,0x0d,0x08,0x00,0x00,0x00,0x0d,0x0d,0x0d,0x62,0x62,0x62,0x62,0x62,
0x62,0x00,0x00,0x08,0xff,0xff,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x0d,0x62,
0xab,0x00,0x00,0x00,0x00,0x00,0x0d,0x0d,0x0d,0x0d,0x62,0x62,0x62,0x62,0x62,0x62,
0xab,0x00,0x00,0xff,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0xd1,0xab,
0xab,0xab,0xab,0xd1,0xd1,0xd1,0xd1,0xd1,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,
0xd1,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf7,0xf7,0xd1,
0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,
0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x15,0x15,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,0x12,0x15,0x15,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0x12,0x00,0x00,0x00,0x00,0x00,0x12,0x15,0x15,0x15,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,0x15,0x15,0x15,0x15,0x15,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,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
};
static const uchar small_icon[] = {
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x0f,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x0f,
0xab,0xab,0xab,0x00,0x00,0x00,0x00,0x06,0xab,0xab,0xab,0xab,0xab,0x06,0x00,0x06,
0x62,0x62,0x00,0x00,0x00,0x00,0x00,0x0b,0x62,0x62,0x62,0x62,0x62,0x0b,0x00,0x0b,
0x62,0x00,0x00,0x62,0x62,0x0b,0x00,0x0b,0x0d,0x62,0x62,0x62,0x62,0x0b,0x00,0x0b,
0x62,0x00,0x62,0x00,0x00,0x00,0x00,0x0b,0x0d,0x62,0x62,0x62,0x62,0x0b,0x00,0x0b,
0x62,0x62,0x00,0x00,0x00,0x00,0x00,0x0b,0x0d,0x62,0x62,0x62,0x62,0x0b,0x00,0x0b,
0xab,0x00,0x00,0xd1,0xd1,0x06,0x00,0x06,0xd1,0xab,0xab,0xab,0xab,0x06,0x00,0x06,
0x62,0x00,0x0d,0x62,0x62,0x0f,0x00,0x0b,0x0d,0x00,0x00,0x00,0x00,0x0b,0x00,0x0b,
0x62,0x0d,0x62,0x62,0x62,0x0b,0x00,0x0b,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x0b,
0x62,0x00,0x00,0x00,0x00,0x0b,0x00,0x0b,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x0b,
0x00,0x0d,0x3f,0x00,0x00,0x00,0x00,0x0b,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x0d,
0x00,0x3f,0x00,0x00,0x00,0x00,0x00,0x0b,0x0d,0x00,0x00,0x00,0x00,0x00,0x0d,0x62,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0xab,0xab,0xd1,0xd1,0xd1,0xd1,0xab,0xab,
0xff,0x00,0x00,0x00,0x00,0x00,0x12,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0x12,0x12,0x12,0x12,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
};

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

#define PLAYER_NAME "TiMidity MIDI Player V0.21"

#define BEOS_JUMP 	1
#define BEOS_VOLUME	2
#define BEOS_LOOP	3

Object	*dual_object=0;

// some globals we import unclean for other parts
ulong beos_flags;
ulong beos_volume;
ulong beos_jump;
int   beos_tracks;

int free_instruments_afterwards=0;
static char def_instr_name[256]="";

class PrefsView;

struct instance_struct
{
	PrefsView	*prefs_view;
	BMessage 	*prefs;
	bool		loop;
	int			volume;
	int 		pos;
	int			track;

	MidiEvent 	*event;
	int32 		events;
	int32		samples;
	
	char 		fn[512];
	thread_id	t1;
	bool		initdone;
	bool		endreached;
};

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)
				{
					SetFont(be_plain_font);
					SetDrawingMode(B_OP_OVER);
					DrawString("©1995 Tuukka Toivonen.",BPoint(45,164));
					DrawString("BeOS version by Tinic Uro.",BPoint(40,176));
					BView::Draw(frame);
				}
};


int 	 stream_size;
char 	*stream_data;
sem_id 	 stream_sem1;
sem_id 	 stream_sem2;

#define MAXWORDS 10

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];
}

static void config_error(char *message)
{
	BAlert *alert = new BAlert("TiMidity: MidiPrefs",message,"I'll change it");
	alert->Go();
}

static int read_config_file(char *name)
{
  	FILE *fp;
  	char tmp[1024], *w[MAXWORDS], *cp;
  	char str[1024];
  	ToneBank *bank=0;
  	int i, j, k, line=0, words;
  	static int rcf_count=0;

  	if (rcf_count>50)
	{
		config_error("Probable source loop in configuration files");
		return (-1);
	}

  	if (!(fp=open_file(name, 1, OF_VERBOSE))) return -1;

  	while (fgets(tmp, sizeof(tmp), fp))
	{
      	line++;
		w[words=0]=strtok(tmp, " \t\r\n\240");
		if (!w[0] || (*w[0]=='#')) continue;
      	while (w[words] && (words < MAXWORDS)) w[++words]=strtok(0," \t\r\n\240");
      	if (!strcmp(w[0], "dir"))
		{
	  		if (words < 2)
		 	{
	      		sprintf(str, "%s: line %d: No directory given\n", name, line);
	      		config_error(str);
	      		return -2;
		 	}
	  		for (i=1; i<words; i++) add_to_pathlist(w[i]);
		}
		else if (!strcmp(w[0], "source"))
		{
	  		if (words < 2)
	    	{
	      		sprintf(str, "%s: line %d: No file name given\n", name, line);
	      		config_error(str);
	      		return -2;
		 	}
	  		for (i=1; i<words; i++)
	    	{
	      		rcf_count++;
				read_config_file(w[i]);
	      		rcf_count--;
	    	}
		}
      	else if (!strcmp(w[0], "default"))
		{
	  		if (words != 2)
	    	{
	      		sprintf(str, "%s: line %d: Must specify exactly one patch name\n", name, line);
	      		config_error(str);
	      		return -2;
	    	}
	  		strncpy(def_instr_name, w[1], 255);
	  		def_instr_name[255]='\0';
		}
		else if (!strcmp(w[0], "drumset"))
		{
	  		if (words < 2)
	    	{
	      		sprintf(str, "%s: line %d: No drum set number given\n", name, line);
	      		config_error(str);
				return -2;
	    	}
	  		i=atoi(w[1]);
	  		if (i<0 || i>127)
		 	{
	      		sprintf(str, "%s: line %d: Drum set must be between 0 and 127\n",name, line);
	      		config_error(str);
	      		return -2;
		 	}
	  		if (!drumset[i])
	    	{
	      		drumset[i]=(ToneBank *)safe_malloc(sizeof(ToneBank));
				memset(drumset[i], 0, sizeof(ToneBank));
		 	}
	  		bank=drumset[i];
		}
		else if (!strcmp(w[0], "bank"))
		{
	  		if (words < 2)
		 	{
	      		sprintf(str, "%s: line %d: No bank number given\n", name, line);
	      		config_error(str);
	      		return -2;
		 	}
	  		i=atoi(w[1]);
	  		if (i<0 || i>127)
	    	{
	      		sprintf(str, "%s: line %d: Tone bank must be between 0 and 127\n",name, line);
	      		config_error(str);
	      		return -2;
	    	}
	  		if (!tonebank[i])
		 	{
				tonebank[i]=(ToneBank *)safe_malloc(sizeof(ToneBank));
	      		memset(tonebank[i], 0, sizeof(ToneBank));
	    	}
	  		bank=tonebank[i];
		}
      	else 
      	{
			if ((words < 2) || (*w[0] < '0' || *w[0] > '9'))
	  		{
		 		sprintf(str, "%s: line %d: syntax error\n", name, line);
	      		config_error(str);
		 		return -2;
	  		}
			i=atoi(w[0]);
			if (i<0 || i>127)
	  		{
	    		sprintf(str, "%s: line %d: Program must be between 0 and 127\n", name, line);
	      		config_error(str);
	    		return -2;
	  		}
			if (!bank)
	  		{
	    		sprintf(str, "%s: line %d: Must specify tone bank or drum set before assignment\n", name, line);
	      		config_error(str);
		 		return -2;
	  		}
			if (bank->tone[i].name) free(bank->tone[i].name);
			strcpy((bank->tone[i].name=(char *)safe_malloc(strlen(w[1])+1)),w[1]);
			
			bank->tone[i].note=
			bank->tone[i].amp=
			bank->tone[i].pan=
			bank->tone[i].strip_loop=
			bank->tone[i].strip_envelope=
			bank->tone[i].strip_tail=-1;

			for (j=2; j<words; j++)
	  		{
	    		if (!(cp=strchr(w[j], '=')))
	      		{
					sprintf(str, "%s: line %d: bad patch option %s\n",name, line, w[j]);
		      		config_error(str);
					return -2;
		      	}
		    	*cp++=0;
		    	if (!strcmp(w[j], "amp"))
				{
					k=atoi(cp);
					if ((k<0 || k>MAX_AMPLIFICATION) || (*cp < '0' || *cp > '9'))
			  		{
				 		sprintf(str,"%s: line %d: amplification must be between 0 and %d\n", name, line, MAX_AMPLIFICATION);
			      		config_error(str);
				 		return -2;
			  		}
					bank->tone[i].amp=k;
		      	}
		    	else if (!strcmp(w[j], "note"))
		      	{
					k=atoi(cp);
					if ((k<0 || k>127) || (*cp < '0' || *cp > '9'))
			  		{
				 		sprintf(str,"%s: line %d: note must be between 0 and 127\n",name, line);
			      		config_error(str);
			    		return -2;
			  		}
					bank->tone[i].note=k;
				}
			 	else if (!strcmp(w[j], "pan"))
				{
					if (!strcmp(cp, "center")) k=64;
					else if (!strcmp(cp, "left")) k=0;
					else if (!strcmp(cp, "right")) k=127;
					else k=((atoi(cp)+100) * 100) / 157;
					if ((k<0 || k>127) || (k==0 && *cp!='-' && (*cp < '0' || *cp > '9')))
			  		{
				 		sprintf(str,"%s: line %d: panning must be left, right, center, or between -100 and 100\n",name, line);
			      		config_error(str);
				 		return -2;
			  		}
					bank->tone[i].pan=k;
				}
			 	else if (!strcmp(w[j], "keep"))
				{
					if (!strcmp(cp, "env")) bank->tone[i].strip_envelope=0;
					else if (!strcmp(cp, "loop"))bank->tone[i].strip_loop=0;
					else
			  		{
				 		sprintf(str, "%s: line %d: keep must be env or loop\n",name, line);
			      		config_error(str);
				 		return -2;
			  		}
				}
			 	else if (!strcmp(w[j], "strip"))
				{
					if (!strcmp(cp, "env"))bank->tone[i].strip_envelope=1;
					else if (!strcmp(cp, "loop"))bank->tone[i].strip_loop=1;
					else if (!strcmp(cp, "tail"))bank->tone[i].strip_tail=1;
					else
			  		{
				 		sprintf(str, "%s: line %d: strip must be env, loop, or tail\n",name, line);
			      		config_error(str);
				 		return -2;
			  		}
				}
			 	else
				{
					sprintf(str, "%s: line %d: bad patch option %s\n",name, line, w[j]);
		      		config_error(str);
					return -2;
				}
	  		}
		}
	}

  	if (ferror(fp))
	{
		close_file(fp);
		return -2;
	}
  	close_file(fp);
  	return 0;
}

static int play_midi_beos(instance_struct *inst)
{
	play_midi(inst->event, inst->events, inst->samples);

	inst->endreached=TRUE;
	
	// Safety, we wait for killthread...
	for(;;)
	{
		acquire_sem(stream_sem1);
		release_sem(stream_sem2);		
	}
}

extern PlayMode beos_play_mode;
PlayMode *play_mode;

long class_dispatcher(Class *c, Object *o, uint32 MethodID, uint32 *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;

				  	stream_size=0;
				  	stream_data=0;

					if(read_config_file(CONFIG_FILE)==NULL)
					{
						play_mode=&beos_play_mode;
						play_mode->encoding |= PE_16BIT;
						play_mode->encoding &= ~PE_MONO;
					  	play_mode->rate=DEFAULT_RATE;
					  	play_mode->name=0;
						init_tables();
					  	ctl->open(1,1);				  	
					  	play_mode->open_output();
	
						if (!control_ratio)
						{
		  					control_ratio = play_mode->rate / CONTROLS_PER_SECOND;
		  					if(control_ratio<1)
		  					{
			 					control_ratio=1;
		  					}
		  					else if (control_ratio > MAX_CONTROL_RATIO)
			 				{
			 					control_ratio=MAX_CONTROL_RATIO;
							}
						}
						inst->initdone=TRUE;
					}
					else
					{
						inst->initdone=FALSE;
					}

					BMimeType *mime = new BMimeType("audio/midi");
					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->AddString("extensions","mid");
						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("MIDI file");
						mime->SetLongDescription("General MIDI file");
						mime->Install();

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

					return 0;
				}

		case	B_METHOD_DESTROY:	// void (void)
				{
					if(inst->initdone)
					{					
						play_mode->close_output();
						ctl->close();
					}
					return 0;
				}				
				
		case	P_LOAD:				// int handle (char *filename)
				{			
					char *filename=(char *)data[0];
					FILE *fp;

					if(inst->initdone)
					{					
						strcpy(inst->fn,filename);
					
					  	stream_sem1=create_sem(0,"stream_sem1");
					  	stream_sem2=create_sem(0,"stream_sem2");

						inst->endreached=FALSE;

						if (fp=open_file(filename, 1, OF_VERBOSE))
						{
							ctl->file_name(current_filename);
							inst->event=read_midi_file(fp, &inst->events, &inst->samples);	
						    close_file(fp);	

							if (inst->event)
							{
								char str[512];
								BNode *node = new BNode(filename);
								BNodeInfo *nodeinfo = new BNodeInfo(node);
								nodeinfo->SetType("audio/midi");
								delete nodeinfo;
								delete node;

								// Print message in DualPlayer
								sprintf(str, "%d supported events, %d samples", inst->events, inst->samples);
								dual_object->DoMethod(D_NEW_MESSAGE,str);

								ctl->total_time(inst->samples);
								ctl->master_volume(amplification);
								load_missing_instruments();
								resume_thread(inst->t1=spawn_thread((thread_entry)play_midi_beos,"play_midi",B_MEDIA_LEVEL,(void *)inst));
	
								return 1;						
							}
							printf("fail\n");
						}
					}					
					return 0;
				}
									
		case	P_FREE:				// void (int handle)
				{
					int handle=(int)data[0];

					kill_thread(inst->t1);

					delete_sem(stream_sem1);
					delete_sem(stream_sem2);

					if (free_instruments_afterwards) free_instruments();
  					free(inst->event);	

					return 0;
				}

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

		case	P_PAUSE:			// void (int handle)
				{
					int handle=(int)data[0];
					return 0;
				}
					
		case	P_SETUPSTREAM:		// void (BSubscriber *subs, BDACStream *stream)
				{
					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];
					
					stream_size=size;
					stream_data=buffer;
					release_sem(stream_sem1);
					acquire_sem(stream_sem2);
					
					if(!inst->endreached) return TRUE;
					else return FALSE;
				}
				
		case	P_SETATTR:			//  void (ulong AttributeID, ulong data)
				{
					ulong ATTR =(ulong)data[0];
					ulong DATA =(ulong)data[1];
					
					switch(ATTR)
					{
						case	P_ATTR_TRACK:				
								inst->track=(int)DATA;
								break;
						case	P_ATTR_PREFS:				
								inst->prefs=(BMessage *)DATA;
								break;
						case	P_ATTR_BOOST:				
								inst->volume=(((int)DATA*70)/128);
								beos_volume=inst->volume;
								beos_flags |= (1<<BEOS_VOLUME);
								return 0;
						case	P_ATTR_MODPOS:				
								inst->pos=(int)DATA;
								beos_jump=inst->pos*DEFAULT_RATE;
								beos_flags |= (1<<BEOS_JUMP);
								break;
						case	P_ATTR_LOOP:				
								inst->loop=(bool)DATA;
								if(inst->loop)
								{
									beos_flags |= (1<<BEOS_LOOP);
								}
								else
								{
									beos_flags &= ~(1<<BEOS_LOOP);
								}
								break;
						case	P_ATTR_DUALOBJECT:
								dual_object=(Object *)DATA;
								break;
					}
					o->DoSuperMethod(c,P_SETATTR,data);
					return 0;
				}

		case	P_POSITIONSTRING:
				{
					char *str=(char *)data[0];
					int allowedsize=(int)data[1];
					long value=(long)data[2];
				
					sprintf(str,"%03d",value);
					
					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_STREAMARG:			
								*((int *)DATA)=0;
								return 0;
						case	P_ATTR_ID:					
								*((char **)DATA)=PLAYER_NAME;
								return 0;
						case	P_ATTR_VIEW:				
								*((BView **)DATA)=inst->prefs_view;
								return 0;
						case	P_ATTR_MODLENGTH:			
								*((int *)DATA)=inst->samples/DEFAULT_RATE;
								return 0;
						case	P_ATTR_MODPOS:			
								*((int *)DATA)=get_position()/DEFAULT_RATE;
								return 0;
						case	P_ATTR_TRACK:				
								*((int *)DATA)=0;
								return 0;
						case	P_ATTR_TRACKNUM:			
								*((int *)DATA)=0;
								return 0;
						case	P_ATTR_RECOGNITION:			
								*((int *)DATA)=85;
								return 0;
						case	P_ATTR_MIME:
								*((char ***)DATA)=mimelist;
						default:
								return o->DoSuperMethod(c,P_GETATTR,data);
					}
				}
				
		case	P_DRAWSTATUS:		// void (BView *view)
				{
					BView *view=(BView *)data[0];

					char str[1024];
					view->MovePenTo(BPoint(4, 11));
					view->DrawString("Filename");
					view->MovePenTo(BPoint(60, 11));
					sprintf(str,": %s",extract_name(inst->fn));
					view->DrawString((char *)str);
					view->MovePenTo(BPoint(4, 22));
					view->DrawString("Playlength");
					view->MovePenTo(BPoint(60, 22));
					sprintf(str,": %dmin %dsec",(inst->samples/DEFAULT_RATE)/60,(inst->samples/DEFAULT_RATE)%60);
					view->DrawString((char *)str);
					view->MovePenTo(BPoint(4, 33));
					view->DrawString("Tracks");
					view->MovePenTo(BPoint(60, 33));
					sprintf(str,": %d",beos_tracks);
					view->DrawString((char *)str);
					
					return 0;
				}
				
		case	P_CREATEINFO: 		// void (char ***info, int *lines)
				{
					char ***info=(char ***)data[0];
					int *lines=(int *)data[1];
																		
					return 0;
				}

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

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

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

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

long class_superversion()
{
	return 2;
};

long class_version()
{
	return 2;
};
