added an old version of mikmod for dos
[dosdemo] / libs / oldmik / src / load_xm.c
diff --git a/libs/oldmik/src/load_xm.c b/libs/oldmik/src/load_xm.c
new file mode 100644 (file)
index 0000000..a593b42
--- /dev/null
@@ -0,0 +1,603 @@
+/*\r
+\r
+Name:\r
+LOAD_XM.C\r
+\r
+Description:\r
+Fasttracker (XM) module loader\r
+\r
+Portability:\r
+All systems - all compilers (hopefully)\r
+\r
+*/\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <ctype.h>\r
+#include <malloc.h>\r
+#include "mikmod.h"\r
+\r
+/**************************************************************************\r
+**************************************************************************/\r
+\r
+\r
+typedef struct XMHEADER{\r
+       char  id[17];                   /* ID text: 'Extended module: ' */\r
+       char  songname[21];             /* Module name, padded with zeroes and 0x1a at the end */\r
+       char  trackername[20];  /* Tracker name */\r
+       UWORD version;                  /* (word) Version number, hi-byte major and low-byte minor */\r
+       ULONG headersize;               /* Header size */\r
+       UWORD songlength;               /* (word) Song length (in patten order table) */\r
+       UWORD restart;                  /* (word) Restart position */\r
+       UWORD numchn;                   /* (word) Number of channels (2,4,6,8,10,...,32) */\r
+       UWORD numpat;                   /* (word) Number of patterns (max 256) */\r
+       UWORD numins;                   /* (word) Number of instruments (max 128) */\r
+       UWORD flags;                    /* (word) Flags: bit 0: 0 = Amiga frequency table (see below) 1 = Linear frequency table */\r
+       UWORD tempo;                    /* (word) Default tempo */\r
+       UWORD bpm;                              /* (word) Default BPM */\r
+       UBYTE orders[256];              /* (byte) Pattern order table */\r
+} XMHEADER;\r
+\r
+\r
+typedef struct XMINSTHEADER{\r
+       ULONG size;                             /* (dword) Instrument size */\r
+       char  name[22];                 /* (char) Instrument name */\r
+       UBYTE type;                             /* (byte) Instrument type (always 0) */\r
+       UWORD numsmp;                   /* (word) Number of samples in instrument */\r
+       ULONG ssize;                    /* */\r
+} XMINSTHEADER;\r
+\r
+\r
+typedef struct XMPATCHHEADER{\r
+       UBYTE what[96];         /* (byte) Sample number for all notes */\r
+       UBYTE volenv[48];       /* (byte) Points for volume envelope */\r
+       UBYTE panenv[48];       /* (byte) Points for panning envelope */\r
+       UBYTE volpts;           /* (byte) Number of volume points */\r
+       UBYTE panpts;           /* (byte) Number of panning points */\r
+       UBYTE volsus;           /* (byte) Volume sustain point */\r
+       UBYTE volbeg;           /* (byte) Volume loop start point */\r
+       UBYTE volend;           /* (byte) Volume loop end point */\r
+       UBYTE pansus;           /* (byte) Panning sustain point */\r
+       UBYTE panbeg;           /* (byte) Panning loop start point */\r
+       UBYTE panend;           /* (byte) Panning loop end point */\r
+       UBYTE volflg;           /* (byte) Volume type: bit 0: On; 1: Sustain; 2: Loop */\r
+       UBYTE panflg;           /* (byte) Panning type: bit 0: On; 1: Sustain; 2: Loop */\r
+       UBYTE vibflg;           /* (byte) Vibrato type */\r
+       UBYTE vibsweep;         /* (byte) Vibrato sweep */\r
+       UBYTE vibdepth;         /* (byte) Vibrato depth */\r
+       UBYTE vibrate;          /* (byte) Vibrato rate */\r
+       UWORD volfade;          /* (word) Volume fadeout */\r
+       UWORD reserved[11];     /* (word) Reserved */\r
+} XMPATCHHEADER;\r
+\r
+\r
+typedef struct XMWAVHEADER{\r
+       ULONG length;           /* (dword) Sample length */\r
+       ULONG loopstart;        /* (dword) Sample loop start */\r
+       ULONG looplength;       /* (dword) Sample loop length */\r
+       UBYTE volume;           /* (byte) Volume */\r
+       SBYTE finetune;          /* (byte) Finetune (signed byte -128..+127) */\r
+       UBYTE type;                     /* (byte) Type: Bit 0-1: 0 = No loop, 1 = Forward loop, */\r
+/*                                        2 = Ping-pong loop; */\r
+/*                                        4: 16-bit sampledata */\r
+       UBYTE panning;          /* (byte) Panning (0-255) */\r
+       SBYTE  relnote;          /* (byte) Relative note number (signed byte) */\r
+       UBYTE reserved;         /* (byte) Reserved */\r
+       char  samplename[22];   /* (char) Sample name */\r
+} XMWAVHEADER;\r
+\r
+\r
+typedef struct XMPATHEADER{\r
+       ULONG size;                             /* (dword) Pattern header length */\r
+       UBYTE packing;                  /* (byte) Packing type (always 0) */\r
+       UWORD numrows;                  /* (word) Number of rows in pattern (1..256) */\r
+       UWORD packsize;                 /* (word) Packed patterndata size */\r
+} XMPATHEADER;\r
+\r
+typedef struct MTMNOTE{\r
+       UBYTE a,b,c;\r
+} MTMNOTE;\r
+\r
+\r
+typedef struct XMNOTE{\r
+       UBYTE note,ins,vol,eff,dat;\r
+}XMNOTE;\r
+\r
+XMNOTE *xmpat;\r
+\r
+/**************************************************************************\r
+**************************************************************************/\r
+\r
+\r
+\r
+static XMHEADER *mh;\r
+\r
+char XM_Version[]="XM";\r
+\r
+\r
+\r
+BOOL XM_Test(void)\r
+{\r
+       char id[17];\r
+       if(!fread(id,17,1,modfp)) return 0;\r
+       if(!memcmp(id,"Extended Module: ",17)) return 1;\r
+       return 0;\r
+}\r
+\r
+\r
+BOOL XM_Init(void)\r
+{\r
+       mh=NULL;\r
+       if(!(mh=(XMHEADER *)MyCalloc(1,sizeof(XMHEADER)))) return 0;\r
+       return 1;\r
+}\r
+\r
+\r
+void XM_Cleanup(void)\r
+{\r
+       if(mh!=NULL) free(mh);\r
+}\r
+\r
+\r
+void XM_ReadNote(XMNOTE *n)\r
+{\r
+       UBYTE cmp;\r
+       memset(n,0,sizeof(XMNOTE));\r
+\r
+       cmp=fgetc(modfp);\r
+\r
+       if(cmp&0x80){\r
+               if(cmp&1) n->note=fgetc(modfp);\r
+               if(cmp&2) n->ins=fgetc(modfp);\r
+               if(cmp&4) n->vol=fgetc(modfp);\r
+               if(cmp&8) n->eff=fgetc(modfp);\r
+               if(cmp&16) n->dat=fgetc(modfp);\r
+       }\r
+       else{\r
+               n->note=cmp;\r
+               n->ins=fgetc(modfp);\r
+               n->vol=fgetc(modfp);\r
+               n->eff=fgetc(modfp);\r
+               n->dat=fgetc(modfp);\r
+       }\r
+}\r
+\r
+\r
+UBYTE *XM_Convert(XMNOTE *xmtrack,UWORD rows)\r
+{\r
+       int t;\r
+       UBYTE note,ins,vol,eff,dat;\r
+\r
+       UniReset();\r
+\r
+       for(t=0;t<rows;t++){\r
+\r
+               note=xmtrack->note;\r
+               ins=xmtrack->ins;\r
+               vol=xmtrack->vol;\r
+               eff=xmtrack->eff;\r
+               dat=xmtrack->dat;\r
+\r
+                if(note!=0) UniNote(note-1);\r
+\r
+                if(ins!=0) UniInstrument(ins-1);\r
+\r
+/*              printf("Vol:%d\n",vol); */\r
+\r
+               switch(vol>>4){\r
+\r
+                       case 0x6:                                       /* volslide down */\r
+                               if(vol&0xf){\r
+                                       UniWrite(UNI_XMEFFECTA);\r
+                                       UniWrite(vol&0xf);\r
+                               }\r
+                               break;\r
+\r
+                       case 0x7:                                       /* volslide up */\r
+                               if(vol&0xf){\r
+                                       UniWrite(UNI_XMEFFECTA);\r
+                                       UniWrite(vol<<4);\r
+                               }\r
+                               break;\r
+\r
+                       /* volume-row fine volume slide is compatible with protracker\r
+                          EBx and EAx effects i.e. a zero nibble means DO NOT SLIDE, as\r
+                          opposed to 'take the last sliding value'.\r
+                       */\r
+\r
+                       case 0x8:                                               /* finevol down */\r
+                               UniPTEffect(0xe,0xb0 | (vol&0xf));\r
+                               break;\r
+\r
+                       case 0x9:                       /* finevol up */\r
+                               UniPTEffect(0xe,0xa0 | (vol&0xf));\r
+                               break;\r
+\r
+                       case 0xa:                       /* set vibrato speed */\r
+                               UniPTEffect(0x4,vol<<4);\r
+                               break;\r
+\r
+                       case 0xb:                       /* vibrato */\r
+                               UniPTEffect(0x4,vol&0xf);\r
+                               break;\r
+\r
+                       case 0xc:                       /* set panning */\r
+                               UniPTEffect(0x8,vol<<4);\r
+                               break;\r
+\r
+                       case 0xd:                       /* panning slide left */\r
+                               /* only slide when data nibble not zero: */\r
+\r
+                               if(vol&0xf){\r
+                                       UniWrite(UNI_XMEFFECTP);\r
+                                       UniWrite(vol&0xf);\r
+                               }\r
+                               break;\r
+\r
+                       case 0xe:                       /* panning slide right */\r
+                               /* only slide when data nibble not zero: */\r
+\r
+                               if(vol&0xf){\r
+                                       UniWrite(UNI_XMEFFECTP);\r
+                                       UniWrite(vol<<4);\r
+                               }\r
+                               break;\r
+\r
+                       case 0xf:                       /* tone porta */\r
+                               UniPTEffect(0x3,vol<<4);\r
+                               break;\r
+\r
+                       default:\r
+                               if(vol>=0x10 && vol<=0x50){\r
+                                       UniPTEffect(0xc,vol-0x10);\r
+                               }\r
+               }\r
+\r
+/*              if(eff>0xf) printf("Effect %d",eff); */\r
+\r
+               switch(eff){\r
+\r
+                       case 'G'-55:                    /* G - set global volume */\r
+                               if(dat>64) dat=64;\r
+                               UniWrite(UNI_XMEFFECTG);\r
+                               UniWrite(dat);\r
+                               break;\r
+\r
+                       case 'H'-55:                    /* H - global volume slide */\r
+                               UniWrite(UNI_XMEFFECTH);\r
+                               UniWrite(dat);\r
+                               break;\r
+\r
+                       case 'K'-55:                    /* K - keyoff */\r
+                               UniNote(96);\r
+                               break;\r
+\r
+                       case 'L'-55:                    /* L - set envelope position */\r
+                               break;\r
+\r
+                       case 'P'-55:                    /* P - panning slide */\r
+                               UniWrite(UNI_XMEFFECTP);\r
+                               UniWrite(dat);\r
+                               break;\r
+\r
+                       case 'R'-55:                    /* R - multi retrig note */\r
+                               UniWrite(UNI_S3MEFFECTQ);\r
+                               UniWrite(dat);\r
+                               break;\r
+\r
+                       case 'T'-55:                            /* T - Tremor !! (== S3M effect I) */\r
+                               UniWrite(UNI_S3MEFFECTI);\r
+                               UniWrite(dat);\r
+                               break;\r
+\r
+                       case 'X'-55:\r
+                               if((dat>>4)==1){                /* X1 extra fine porta up */\r
+\r
+\r
+                               }\r
+                               else{                                   /* X2 extra fine porta down */\r
+\r
+                               }\r
+                               break;\r
+\r
+                       default:\r
+                               if(eff==0xa){\r
+                                       UniWrite(UNI_XMEFFECTA);\r
+                                       UniWrite(dat);\r
+                               }\r
+                               else if(eff<=0xf) UniPTEffect(eff,dat);\r
+                               break;\r
+               }\r
+\r
+               UniNewline();\r
+               xmtrack++;\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+\r
+\r
+BOOL XM_Load(void)\r
+{\r
+       INSTRUMENT *d;\r
+       SAMPLE *q;\r
+       int t,u,v,p,numtrk;\r
+       long next;\r
+\r
+       /* try to read module header */\r
+\r
+       _mm_read_str(mh->id,17,modfp);\r
+       _mm_read_str(mh->songname,21,modfp);\r
+       _mm_read_str(mh->trackername,20,modfp);\r
+       mh->version             =_mm_read_I_UWORD(modfp);\r
+       mh->headersize  =_mm_read_I_ULONG(modfp);\r
+       mh->songlength  =_mm_read_I_UWORD(modfp);\r
+       mh->restart             =_mm_read_I_UWORD(modfp);\r
+       mh->numchn              =_mm_read_I_UWORD(modfp);\r
+       mh->numpat              =_mm_read_I_UWORD(modfp);\r
+       mh->numins              =_mm_read_I_UWORD(modfp);\r
+       mh->flags               =_mm_read_I_UWORD(modfp);\r
+       mh->tempo               =_mm_read_I_UWORD(modfp);\r
+       mh->bpm                 =_mm_read_I_UWORD(modfp);\r
+       _mm_read_UBYTES(mh->orders,256,modfp);\r
+\r
+       if(feof(modfp)){\r
+               myerr = ERROR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* set module variables */\r
+\r
+       of.initspeed=mh->tempo;\r
+       of.inittempo=mh->bpm;\r
+       of.modtype=DupStr(mh->trackername,20);\r
+       of.numchn=mh->numchn;\r
+       of.numpat=mh->numpat;\r
+       of.numtrk=(UWORD)of.numpat*of.numchn;   /* get number of channels */\r
+       of.songname=DupStr(mh->songname,20);    /* make a cstr of songname */\r
+       of.numpos=mh->songlength;                       /* copy the songlength */\r
+       of.reppos=mh->restart;\r
+       of.numins=mh->numins;\r
+       of.flags|=UF_XMPERIODS;\r
+       if(mh->flags&1) of.flags|=UF_LINEAR;\r
+\r
+       memcpy(of.positions,mh->orders,256);\r
+\r
+/*\r
+        WHY THIS CODE HERE?? I CAN'T REMEMBER!\r
+\r
+        of.numpat=0;\r
+       for(t=0;t<of.numpos;t++){\r
+               if(of.positions[t]>of.numpat) of.numpat=of.positions[t];\r
+       }\r
+       of.numpat++;\r
+*/\r
+\r
+/*     printf("Modtype :%s\n",of.modtype);\r
+       printf("Version :%x\n",mh->version);\r
+       printf("Song    :%s\n",of.songname);\r
+       printf("Speed   :%d,%d\n",of.initspeed,of.inittempo);\r
+       printf("Channels:%d\n",of.numchn);\r
+       printf("Numins  :%d\n",mh->numins);\r
+*/\r
+       if(!AllocTracks()) return 0;\r
+       if(!AllocPatterns()) return 0;\r
+\r
+       numtrk=0;\r
+       for(t=0;t<mh->numpat;t++){\r
+               XMPATHEADER ph;\r
+\r
+/*             printf("Reading pattern %d\n",t); */\r
+\r
+               ph.size         =_mm_read_I_ULONG(modfp);\r
+               ph.packing      =_mm_read_UBYTE(modfp);\r
+               ph.numrows      =_mm_read_I_UWORD(modfp);\r
+               ph.packsize     =_mm_read_I_UWORD(modfp);\r
+\r
+/*             printf("headln:  %ld\n",ph.size); */\r
+/*             printf("numrows: %d\n",ph.numrows); */\r
+/*             printf("packsize:%d\n",ph.packsize); */\r
+\r
+                of.pattrows[t]=ph.numrows;\r
+\r
+               /*\r
+                       Gr8.. when packsize is 0, don't try to load a pattern.. it's empty.\r
+                       This bug was discovered thanks to Khyron's module..\r
+               */\r
+\r
+               if(!(xmpat=(XMNOTE *)MyCalloc(ph.numrows*of.numchn,sizeof(XMNOTE)))) return 0;\r
+\r
+               if(ph.packsize>0){\r
+                       for(u=0;u<ph.numrows;u++){\r
+                               for(v=0;v<of.numchn;v++){\r
+                                       XM_ReadNote(&xmpat[(v*ph.numrows)+u]);\r
+                               }\r
+                       }\r
+               }\r
+\r
+               for(v=0;v<of.numchn;v++){\r
+                       of.tracks[numtrk++]=XM_Convert(&xmpat[v*ph.numrows],ph.numrows);\r
+               }\r
+\r
+               free(xmpat);\r
+       }\r
+\r
+       if(!AllocInstruments()) return 0;\r
+\r
+       d=of.instruments;\r
+\r
+       for(t=0;t<of.numins;t++){\r
+               XMINSTHEADER ih;\r
+\r
+               /* read instrument header */\r
+\r
+               ih.size         =_mm_read_I_ULONG(modfp);\r
+               _mm_read_str (ih.name, 22, modfp);\r
+               ih.type         =_mm_read_UBYTE(modfp);\r
+               ih.numsmp       =_mm_read_I_UWORD(modfp);\r
+               ih.ssize        =_mm_read_I_ULONG(modfp);\r
+\r
+/*      printf("Size: %ld\n",ih.size);\r
+               printf("Name:   %22.22s\n",ih.name);\r
+               printf("Samples:%d\n",ih.numsmp);\r
+               printf("sampleheadersize:%ld\n",ih.ssize);\r
+*/\r
+               d->insname=DupStr(ih.name,22);\r
+               d->numsmp=ih.numsmp;\r
+\r
+               if(!AllocSamples(d)) return 0;\r
+\r
+               if(ih.numsmp>0){\r
+                       XMPATCHHEADER pth;\r
+                       XMWAVHEADER wh;\r
+\r
+                       _mm_read_UBYTES (pth.what, 96, modfp);\r
+                       _mm_read_UBYTES (pth.volenv, 48, modfp);\r
+                       _mm_read_UBYTES (pth.panenv, 48, modfp);\r
+                       pth.volpts              =_mm_read_UBYTE(modfp);\r
+                       pth.panpts              =_mm_read_UBYTE(modfp);\r
+                       pth.volsus              =_mm_read_UBYTE(modfp);\r
+                       pth.volbeg              =_mm_read_UBYTE(modfp);\r
+                       pth.volend              =_mm_read_UBYTE(modfp);\r
+                       pth.pansus              =_mm_read_UBYTE(modfp);\r
+                       pth.panbeg              =_mm_read_UBYTE(modfp);\r
+                       pth.panend              =_mm_read_UBYTE(modfp);\r
+                       pth.volflg              =_mm_read_UBYTE(modfp);\r
+                       pth.panflg              =_mm_read_UBYTE(modfp);\r
+                       pth.vibflg              =_mm_read_UBYTE(modfp);\r
+                       pth.vibsweep    =_mm_read_UBYTE(modfp);\r
+                       pth.vibdepth    =_mm_read_UBYTE(modfp);\r
+                       pth.vibrate             =_mm_read_UBYTE(modfp);\r
+                       pth.volfade             =_mm_read_I_UWORD(modfp);\r
+                       _mm_read_I_UWORDS(pth.reserved, 11, modfp);\r
+\r
+                       memcpy(d->samplenumber,pth.what,96);\r
+\r
+                       d->volfade=pth.volfade;\r
+\r
+/*                     printf("Volfade %x\n",d->volfade); */\r
+\r
+                       memcpy(d->volenv,pth.volenv,24);\r
+                       d->volflg=pth.volflg;\r
+                       d->volsus=pth.volsus;\r
+                       d->volbeg=pth.volbeg;\r
+                       d->volend=pth.volend;\r
+                       d->volpts=pth.volpts;\r
+\r
+/*                     printf("volume points   : %d\n"\r
+                                  "volflg                      : %d\n"\r
+                                  "volbeg                      : %d\n"\r
+                                  "volend                      : %d\n"\r
+                                  "volsus                      : %d\n",\r
+                                  d->volpts,\r
+                                  d->volflg,\r
+                                  d->volbeg,\r
+                                  d->volend,\r
+                                  d->volsus);\r
+*/\r
+                       /* scale volume envelope: */\r
+\r
+                       for(p=0;p<12;p++){\r
+                               d->volenv[p].val<<=2;\r
+/*                             printf("%d,%d,",d->volenv[p].pos,d->volenv[p].val); */\r
+                       }\r
+\r
+                       memcpy(d->panenv,pth.panenv,24);\r
+                       d->panflg=pth.panflg;\r
+                       d->pansus=pth.pansus;\r
+                       d->panbeg=pth.panbeg;\r
+                       d->panend=pth.panend;\r
+                       d->panpts=pth.panpts;\r
+\r
+/*                                       printf("Panning points        : %d\n"\r
+                                  "panflg                      : %d\n"\r
+                                  "panbeg                      : %d\n"\r
+                                  "panend                      : %d\n"\r
+                                  "pansus                      : %d\n",\r
+                                  d->panpts,\r
+                                  d->panflg,\r
+                                  d->panbeg,\r
+                                  d->panend,\r
+                                  d->pansus);\r
+*/\r
+                       /* scale panning envelope: */\r
+\r
+                       for(p=0;p<12;p++){\r
+                               d->panenv[p].val<<=2;\r
+/*                             printf("%d,%d,",d->panenv[p].pos,d->panenv[p].val); */\r
+                       }\r
+\r
+/*                      for(u=0;u<256;u++){ */\r
+/*                              printf("%2.2x ",fgetc(modfp)); */\r
+/*                      } */\r
+\r
+                       next=0;\r
+\r
+                       for(u=0;u<ih.numsmp;u++){\r
+                               q=&d->samples[u];\r
+\r
+                               wh.length               =_mm_read_I_ULONG (modfp);\r
+                               wh.loopstart    =_mm_read_I_ULONG (modfp);\r
+                               wh.looplength   =_mm_read_I_ULONG (modfp);\r
+                               wh.volume               =_mm_read_UBYTE (modfp);\r
+                               wh.finetune             =_mm_read_SBYTE (modfp);\r
+                               wh.type                 =_mm_read_UBYTE (modfp);\r
+                               wh.panning              =_mm_read_UBYTE (modfp);\r
+                               wh.relnote              =_mm_read_SBYTE (modfp);\r
+                               wh.reserved             =_mm_read_UBYTE (modfp);\r
+                               _mm_read_str(wh.samplename, 22, modfp);\r
+\r
+/*              printf("wav %d:%22.22s\n",u,wh.samplename); */\r
+\r
+                               q->samplename   =DupStr(wh.samplename,22);\r
+                               q->length       =wh.length;\r
+                               q->loopstart    =wh.loopstart;\r
+                               q->loopend      =wh.loopstart+wh.looplength;\r
+                               q->volume       =wh.volume;\r
+                               q->c2spd                =wh.finetune+128;\r
+                               q->transpose    =wh.relnote;\r
+                               q->panning      =wh.panning;\r
+                               q->seekpos              =next;\r
+\r
+                               if(wh.type&0x10){\r
+                                       q->length>>=1;\r
+                                       q->loopstart>>=1;\r
+                                       q->loopend>>=1;\r
+                               }\r
+\r
+                               next+=wh.length;\r
+\r
+/*                              printf("Type %u\n",wh.type); */\r
+/*                             printf("Trans %d\n",wh.relnote); */\r
+\r
+                               q->flags|=SF_OWNPAN;\r
+                               if(wh.type&0x3) q->flags|=SF_LOOP;\r
+                               if(wh.type&0x2) q->flags|=SF_BIDI;\r
+\r
+                               if(wh.type&0x10) q->flags|=SF_16BITS;\r
+                               q->flags|=SF_DELTA;\r
+                               q->flags|=SF_SIGNED;\r
+                       }\r
+\r
+                       for(u=0;u<ih.numsmp;u++) d->samples[u].seekpos+=_mm_ftell(modfp);\r
+\r
+                       _mm_fseek(modfp,next,SEEK_CUR);\r
+               }\r
+\r
+               d++;\r
+       }\r
+\r
+\r
+       return 1;\r
+}\r
+\r
+\r
+LOADER load_xm={\r
+       NULL,\r
+       "XM",\r
+       "Portable XM loader v0.4 - for your ears only / MikMak",\r
+       XM_Init,\r
+       XM_Test,\r
+       XM_Load,\r
+       XM_Cleanup\r
+};\r