home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 February / PCO_0299.ISO / filesbbs / linux / mikmod-3.000 / mikmod-3 / mikmod-3.1.2 / loaders / load_med.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-12-07  |  14.0 KB  |  568 lines

  1. /*    MikMod sound library
  2.     (c) 1998 Miodrag Vallat and others - see file AUTHORS for complete list
  3.  
  4.     This library is free software; you can redistribute it and/or modify
  5.     it under the terms of the GNU Library General Public License as
  6.     published by the Free Software Foundation; either version 2 of
  7.     the License, or (at your option) any later version.
  8.  
  9.     This program is distributed in the hope that it will be useful,
  10.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.     GNU Library General Public License for more details.
  13.  
  14.     You should have received a copy of the GNU Library General Public
  15.     License along with this library; if not, write to the Free Software
  16.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18.  
  19. /*==============================================================================
  20.  
  21.   $Id: load_med.c,v 1.17 1998/12/07 06:00:16 miod Exp $
  22.  
  23.   Amiga MED module loader
  24.  
  25. ==============================================================================*/
  26.  
  27. #ifdef HAVE_CONFIG_H
  28. #include "config.h"
  29. #endif
  30.  
  31. #include <string.h>
  32.  
  33. #include <mikmod_internals.h>
  34.  
  35. /*========== Module information */
  36.  
  37. typedef struct MMD0 {
  38.     ULONG id;
  39.     ULONG modlen;
  40.     ULONG MMD0songP;        /* struct MMD0song *song; */
  41.     UWORD psecnum;          /* for the player routine, MMD2 only */
  42.     UWORD pseq;             /*  "   "   "   " */
  43.     ULONG MMD0BlockPP;      /* struct MMD0Block **blockarr; */
  44.     ULONG reserved1;
  45.     ULONG InstrHdrPP;       /* struct InstrHdr **smplarr; */
  46.     ULONG reserved2;
  47.     ULONG MMD0expP;         /* struct MMD0exp *expdata; */
  48.     ULONG reserved3;
  49.     UWORD pstate;           /* some data for the player routine */
  50.     UWORD pblock;
  51.     UWORD pline;
  52.     UWORD pseqnum;
  53.     SWORD actplayline;
  54.     UBYTE counter;
  55.     UBYTE extra_songs;      /* number of songs - 1 */
  56. } MMD0;
  57.  
  58. typedef struct MMD0sample {
  59.     UWORD rep,replen;        /* offs: 0(s), 2(s) */
  60.     UBYTE midich;            /* offs: 4(s) */
  61.     UBYTE midipreset;        /* offs: 5(s) */
  62.     UBYTE svol;              /* offs: 6(s) */
  63.     SBYTE strans;            /* offs: 7(s) */
  64. } MMD0sample;
  65.  
  66. typedef struct MMD0song {
  67.     MMD0sample    sample[63];      /* 63 * 8 bytes = 504 bytes */
  68.     UWORD        numblocks;       /* offs: 504 */
  69.     UWORD        songlen;         /* offs: 506 */
  70.     UBYTE        playseq[256];    /* offs: 508 */
  71.     UWORD        deftempo;        /* offs: 764 */
  72.     SBYTE        playtransp;      /* offs: 766 */
  73.     UBYTE        flags;           /* offs: 767 */
  74.     UBYTE        flags2;          /* offs: 768 */
  75.     UBYTE        tempo2;          /* offs: 769 */
  76.     UBYTE        trkvol[16];      /* offs: 770 */
  77.     UBYTE        mastervol;       /* offs: 786 */
  78.     UBYTE        numsamples;      /* offs: 787 */
  79. } MMD0song;
  80.  
  81. typedef struct MMD0NOTE {
  82.     UBYTE a,b,c;
  83. } MMD0NOTE;
  84.  
  85. typedef struct MMD1NOTE {
  86.     UBYTE a,b,c,d;
  87. } MMD1NOTE;
  88.  
  89. typedef struct InstrHdr {
  90.     ULONG    length;
  91.     SWORD    type;
  92.     /* Followed by actual data */
  93. } InstrHdr;
  94.  
  95. /*========== Loader variables */
  96.  
  97. #define MMD0_string 0x4D4D4430
  98. #define MMD1_string 0x4D4D4431
  99.  
  100. static    MMD0 *mh     = NULL;
  101. static    MMD0song *ms = NULL;
  102. static    ULONG *ba    = NULL;
  103. static    MMD0NOTE *mmd0pat = NULL;
  104. static    MMD1NOTE *mmd1pat = NULL;
  105.  
  106. static    int currentspeed,currentbpm,speeddivisor;
  107. static    BOOL decimalvolumes;
  108. static    BOOL bpmtempos;
  109.  
  110. #define d0note(row,col) mmd0pat[((row)*(UWORD)of.numchn)+(col)]
  111. #define d1note(row,col) mmd1pat[((row)*(UWORD)of.numchn)+(col)]
  112.  
  113. static    CHAR MED_Version[] = "OctaMED";
  114.  
  115. /*========== Loader code */
  116.  
  117. BOOL MED_Test(void)
  118. {
  119.     UBYTE id[4];
  120.  
  121.     if(!_mm_read_UBYTES(id,4,modfp)) return 0;
  122.     if((!memcmp(id,"MMD0",4))||(!memcmp(id,"MMD1",4))) return 1;
  123.     return 0;
  124. }
  125.  
  126. BOOL MED_Init(void)
  127. {
  128.     if(!(mh=(MMD0*)_mm_malloc(sizeof(MMD0)))) return 0;
  129.     if(!(ms=(MMD0song*)_mm_malloc(sizeof(MMD0song)))) return 0;
  130.     return 1;
  131. }
  132.  
  133. void MED_Cleanup(void)
  134. {
  135.     if(mh) free(mh);
  136.     if(ms) free(ms);
  137.     if(ba) free(ba);
  138.     if(mmd0pat) free(mmd0pat);
  139.     if(mmd1pat) free(mmd1pat);
  140.  
  141.     mh = NULL;
  142.     ms = NULL;
  143.     ba = NULL;
  144.     mmd0pat = NULL;
  145.     mmd1pat = NULL;    
  146. }
  147.  
  148. void EffectCvt(UBYTE eff,UBYTE dat)
  149. {
  150.      switch(eff) {
  151.         /* 0x0 0x1 0x2 0x3 0x4 PT effects */
  152.         case 0x5:    /* PT vibrato with speed/depth nibbles swapped */
  153.             UniPTEffect(0x4,(dat>>4)|((dat&0xf)<<4));
  154.             break;
  155.         /* 0x6 0x7 not used */
  156.         case 0x6:
  157.         case 0x7:
  158.             break;
  159.         case 0x8:    /* midi hold/decay */
  160.             break;
  161.         case 0x9:
  162.             if(dat<=0x20) {
  163.                 if(!dat) currentspeed=of.initspeed;
  164.                 else {
  165.                     if(bpmtempos) currentspeed=dat*4/speeddivisor;
  166.                     else currentspeed=dat/speeddivisor;
  167.                 }
  168.                 UniPTEffect(0xf,currentspeed);
  169.             } else {
  170.                 if(bpmtempos)
  171.                     currentbpm=dat;
  172.                 else {
  173.                     int val=((UWORD)dat*125)/(33*speeddivisor);
  174.                     currentbpm=(val<32)?32:(val>255?255:val);
  175.                 }
  176.                 UniPTEffect(0xf,currentbpm);
  177.             }
  178.             break;
  179.         /* 0xa 0xb PT effects */
  180.         case 0xc:
  181.             if(decimalvolumes) dat=(dat>>4)*10+(dat&0xf);
  182.             UniPTEffect(0xc,dat);
  183.             break;
  184.         case 0xd:    /* same as PT volslide */
  185.             UniPTEffect(0xa,dat);
  186.             break;
  187.         case 0xe:    /* synth jmp - midi */
  188.             break;
  189.         case 0xf:
  190.             switch(dat) {
  191.                 case 0: /* patternbreak */
  192.                     UniPTEffect(0xd,0);
  193.                     break;
  194.                 case 0xf1: /* play note twice */
  195.                     UniPTEffect(0xe,0x90|(currentspeed/2));
  196.                     break;
  197.                 case 0xf2: /* delay note */
  198.                     UniPTEffect(0xe,0xd0|(currentspeed/2));
  199.                     break;
  200.                 case 0xf3: /* play note three times */
  201.                     UniPTEffect(0xe,0x90|(currentspeed/3));
  202.                     break;
  203.                 case 0xfe: /* stop playing */
  204.                     UniPTEffect(0xb,of.numpat);
  205.                     break;
  206.                 case 0xff: /* note cut */
  207.                     UniPTEffect(0xc,0);
  208.                     break;
  209.                 default:
  210.                     if(dat<=10) {
  211.                         currentspeed=dat*4/speeddivisor;
  212.                         UniPTEffect(0xf,currentspeed);
  213.                     } else if(dat<=240) {
  214.                         if(bpmtempos)
  215.                             currentbpm=(dat<32)?32:dat;
  216.                         else {
  217.                             int val=((UWORD)dat*125)/33;
  218.                             currentbpm=(val<32)?32:(val>255?255:val);
  219.                         }
  220.                         UniPTEffect(0xf,currentbpm);
  221.                     }
  222.             }
  223.             break;
  224.         default:    /* all normal PT effects are handled here */
  225.             UniPTEffect(eff,dat);
  226.             break;
  227.     }    
  228. }
  229.  
  230. UBYTE *MED_Convert1(int count,int col)
  231. {
  232.     int t;
  233.     UBYTE inst,note,eff,dat;
  234.     MMD1NOTE *n;
  235.     int trackspeed=currentspeed,trackbpm=currentbpm;
  236.  
  237.     UniReset();
  238.     for(t=0;t<count;t++) {
  239.         n=&d1note(t,col);
  240.  
  241.         note=n->a&0x7f;
  242.         inst=n->b&0x3f;
  243.         eff =n->c&0xf;
  244.         dat =n->d;
  245.  
  246.         if(inst) UniInstrument(inst-1);
  247.         if(note) UniNote(note+3*OCTAVE-1);
  248.  
  249.         if((eff!=9)||(dat>0x20))
  250.             if(trackspeed!=currentspeed) UniPTEffect(0xf,currentspeed=trackspeed);
  251.         if((eff!=9)||(dat<=0x20))
  252.             if(trackbpm!=currentbpm) UniPTEffect(0xf,currentbpm=trackbpm);
  253.         EffectCvt(eff,dat);
  254.         if((eff!=9)||(!t)) {
  255.             trackspeed=currentspeed;
  256.             trackbpm=currentbpm;
  257.         }
  258.         UniNewline();
  259.     }
  260.     return UniDup();
  261. }
  262.  
  263. UBYTE *MED_Convert0(int count,int col)
  264. {
  265.     int t;
  266.     UBYTE a,b,inst,note,eff,dat;
  267.     MMD0NOTE *n;
  268.     int trackspeed=currentspeed,trackbpm=currentbpm;
  269.  
  270.     UniReset();
  271.     for(t=0;t<count;t++) {
  272.         n=&d0note(t,col);
  273.         a=n->a;
  274.         b=n->b;
  275.  
  276.         note=a&0x3f;
  277.         a>>=6;
  278.         a=((a&1)<<1)|(a>>1);
  279.         inst=(b>>4)|(a<<4);
  280.         eff=b&0xf;
  281.         dat=n->c;
  282.  
  283.         if(inst) UniInstrument(inst-1);
  284.         if(note) UniNote(note+3*OCTAVE-1);
  285.  
  286.         if((eff!=9)||(dat>0x20))
  287.             if(trackspeed!=currentspeed) UniPTEffect(0xf,currentspeed=trackspeed);
  288.         if((eff!=9)||(dat<=0x20))
  289.             if(trackbpm!=currentbpm) UniPTEffect(0xf,currentbpm=trackbpm);
  290.         EffectCvt(eff,dat);
  291.         if((eff!=9)||(!t)) {
  292.             trackspeed=currentspeed;
  293.             trackbpm=currentbpm;
  294.         }
  295.         UniNewline();
  296.     }
  297.     return UniDup();
  298. }
  299.  
  300. BOOL LoadMMD0Patterns(void)
  301. {
  302.     int t,row,col;
  303.     UWORD numtracks,numlines,maxlines=0,track=0;
  304.     MMD0NOTE *mmdp;
  305.  
  306.     /* first, scan patterns to see how many channels are used */
  307.     for(t=0;t<of.numpat;t++) {
  308.         _mm_fseek(modfp,ba[t],SEEK_SET);
  309.         numtracks=_mm_read_UBYTE(modfp);
  310.         numlines=_mm_read_UBYTE(modfp);
  311.  
  312.         if(numtracks>of.numchn) of.numchn=numtracks;
  313.         if(numlines>maxlines) maxlines=numlines;
  314.     }
  315.  
  316.     of.numtrk=of.numpat*of.numchn;
  317.     if(!AllocTracks()) return 0;
  318.     if(!AllocPatterns()) return 0;
  319.  
  320.     if(!(mmd0pat=(MMD0NOTE*)_mm_calloc(of.numchn*(maxlines+1),sizeof(MMD0NOTE))))
  321.         return 0;
  322.  
  323.     /* second read: read and convert patterns */
  324.     for(t=0;t<of.numpat;t++) {
  325.         _mm_fseek(modfp,ba[t],SEEK_SET);
  326.         numtracks=_mm_read_UBYTE(modfp);
  327.         numlines=_mm_read_UBYTE(modfp);
  328.  
  329.         of.pattrows[t]=++numlines;
  330.         memset(mmdp=mmd0pat,0,of.numchn*maxlines*sizeof(MMD0NOTE));
  331.         for(row=numlines;row;row--) {
  332.             for(col=numtracks;col;col--,mmdp++) {
  333.                 mmdp->a=_mm_read_UBYTE(modfp);
  334.                 mmdp->b=_mm_read_UBYTE(modfp);
  335.                 mmdp->c=_mm_read_UBYTE(modfp);
  336.             }
  337.         }
  338.  
  339.         for(col=0;col<of.numchn;col++) 
  340.             of.tracks[track++]=MED_Convert0(numlines,col);
  341.     }
  342.     return 1;
  343. }
  344.  
  345. BOOL LoadMMD1Patterns(void)
  346. {
  347.     int t,row,col;
  348.     UWORD numtracks,numlines,maxlines=0,track=0;
  349.     MMD1NOTE *mmdp;
  350.  
  351.     /* first, scan patterns to see how many channels are used */
  352.     for(t=0;t<of.numpat;t++) {
  353.         _mm_fseek(modfp,ba[t],SEEK_SET);
  354.         numtracks=_mm_read_M_UWORD(modfp);
  355.         numlines=_mm_read_M_UWORD(modfp);
  356.         if(numtracks>of.numchn) of.numchn=numtracks;
  357.         if(numlines>maxlines) maxlines=numlines;
  358.     }
  359.  
  360.     of.numtrk = of.numpat*of.numchn;
  361.     if(!AllocTracks()) return 0;
  362.     if(!AllocPatterns()) return 0;
  363.  
  364.     if(!(mmd1pat=(MMD1NOTE*)_mm_calloc(of.numchn*(maxlines+1),sizeof(MMD1NOTE))))
  365.         return 0;
  366.  
  367.     /* second read: really read and convert patterns */
  368.     for(t=0;t<of.numpat;t++) {
  369.         _mm_fseek(modfp,ba[t],SEEK_SET);
  370.         numtracks=_mm_read_M_UWORD(modfp);
  371.         numlines=_mm_read_M_UWORD(modfp);
  372.  
  373.         _mm_fseek(modfp,sizeof(ULONG),SEEK_CUR);
  374.         of.pattrows[t]=++numlines;
  375.         memset(mmdp=mmd1pat,0,of.numchn*maxlines*sizeof(MMD1NOTE));
  376.  
  377.         for(row=numlines;row;row--) {
  378.             for(col=numtracks;col;col--,mmdp++) {
  379.                 mmdp->a=_mm_read_UBYTE(modfp);
  380.                 mmdp->b=_mm_read_UBYTE(modfp);
  381.                 mmdp->c=_mm_read_UBYTE(modfp);
  382.                 mmdp->d=_mm_read_UBYTE(modfp);
  383.             }
  384.         }
  385.  
  386.         for(col=0;col<of.numchn;col++) 
  387.             of.tracks[track++]=MED_Convert1(numlines,col);
  388.     }
  389.     return 1;
  390. }
  391.  
  392. BOOL MED_Load(BOOL curious)
  393. {
  394.     int t;
  395.     ULONG sa[64];
  396.     InstrHdr s;
  397.     SAMPLE *q;
  398.     MMD0sample *mss;
  399.  
  400.     /* try to read module header */
  401.     mh->id          = _mm_read_M_ULONG(modfp);
  402.     mh->modlen      = _mm_read_M_ULONG(modfp);
  403.     mh->MMD0songP   = _mm_read_M_ULONG(modfp);
  404.     mh->psecnum     = _mm_read_M_UWORD(modfp);
  405.     mh->pseq        = _mm_read_M_UWORD(modfp);
  406.     mh->MMD0BlockPP = _mm_read_M_ULONG(modfp);
  407.     mh->reserved1   = _mm_read_M_ULONG(modfp);
  408.     mh->InstrHdrPP  = _mm_read_M_ULONG(modfp);
  409.     mh->reserved2   = _mm_read_M_ULONG(modfp);
  410.     mh->MMD0expP    = _mm_read_M_ULONG(modfp);
  411.     mh->reserved3   = _mm_read_M_ULONG(modfp);
  412.     mh->pstate      = _mm_read_M_UWORD(modfp);
  413.     mh->pblock      = _mm_read_M_UWORD(modfp);
  414.     mh->pline       = _mm_read_M_UWORD(modfp);
  415.     mh->pseqnum     = _mm_read_M_UWORD(modfp);
  416.     mh->actplayline = _mm_read_M_SWORD(modfp);
  417.     mh->counter     = _mm_read_UBYTE(modfp);
  418.     mh->extra_songs = _mm_read_UBYTE(modfp);
  419.  
  420.     /* Seek to MMD0song struct */
  421.     _mm_fseek(modfp,mh->MMD0songP,SEEK_SET);
  422.  
  423.     /* Load the MMD0 Song Header */
  424.     mss = ms->sample;     /* load the sample data first */
  425.     for(t=63;t;t--,mss++) {
  426.         mss->rep        = _mm_read_M_UWORD(modfp);
  427.         mss->replen     = _mm_read_M_UWORD(modfp);
  428.         mss->midich     = _mm_read_UBYTE(modfp);
  429.         mss->midipreset = _mm_read_UBYTE(modfp);
  430.         mss->svol       = _mm_read_UBYTE(modfp);
  431.         mss->strans     = _mm_read_SBYTE(modfp);
  432.     }
  433.  
  434.     ms->numblocks  = _mm_read_M_UWORD(modfp);
  435.     ms->songlen    = _mm_read_M_UWORD(modfp);
  436.     _mm_read_UBYTES(ms->playseq,256,modfp);
  437.     ms->deftempo   = _mm_read_M_UWORD(modfp);
  438.     ms->playtransp = _mm_read_SBYTE(modfp);
  439.     ms->flags      = _mm_read_UBYTE(modfp);
  440.     ms->flags2     = _mm_read_UBYTE(modfp);
  441.     ms->tempo2     = _mm_read_UBYTE(modfp);
  442.     _mm_read_UBYTES(ms->trkvol,16,modfp);
  443.     ms->mastervol  = _mm_read_UBYTE(modfp);
  444.     ms->numsamples = _mm_read_UBYTE(modfp);
  445.  
  446.     /* check for a bad header */
  447.     if(feof(modfp)) {
  448.         _mm_errno = MMERR_LOADING_HEADER;
  449.         return 0;
  450.     }
  451.  
  452.     /* seek to and read the samplepointer array */
  453.     _mm_fseek(modfp,mh->InstrHdrPP,SEEK_SET);
  454.     if(!_mm_read_M_ULONGS(sa,ms->numsamples,modfp)) {
  455.         _mm_errno = MMERR_LOADING_HEADER;
  456.         return 0;
  457.     }
  458.  
  459.     /* alloc and read the blockpointer array */
  460.     if(!(ba=(ULONG *)_mm_calloc(ms->numblocks, sizeof(ULONG)))) return 0;
  461.     _mm_fseek(modfp,mh->MMD0BlockPP,SEEK_SET);
  462.     if(!_mm_read_M_ULONGS(ba,ms->numblocks,modfp)) {
  463.         _mm_errno = MMERR_LOADING_HEADER;
  464.         return 0;
  465.     }
  466.  
  467.     /* copy song positions */
  468.     if(!AllocPositions(ms->songlen)) return 0;
  469.     for(t=0;t<ms->songlen;t++)
  470.         of.positions[t]=ms->playseq[t];
  471.  
  472.     decimalvolumes=(ms->flags&0x10)?0:1;
  473.     bpmtempos=(ms->flags2&0x20)?1:0;
  474.  
  475.     if(bpmtempos) {
  476.         speeddivisor=(ms->flags2&0x1f)+1;
  477.         of.initspeed=(ms->tempo2*4)/speeddivisor;
  478.         of.inittempo=ms->deftempo;
  479.     } else {
  480.         of.initspeed=ms->tempo2;
  481.         speeddivisor=4;
  482.         of.inittempo=(ms->deftempo>=68)?255:(ms->deftempo?ms->deftempo*125/33:128);
  483.     }
  484.     currentspeed=of.initspeed;
  485.     currentbpm=of.inittempo;
  486.     of.modtype   = strdup(MED_Version);
  487.     of.numchn    = 0;                         /* will be counted later */
  488.     of.numpat    = ms->numblocks;
  489.     of.numpos    = ms->songlen;
  490.     of.numins    = ms->numsamples;
  491.     of.numsmp    = of.numins;
  492.     of.songname  = DupStr(NULL,0);
  493.     of.reppos    = 0;
  494.  
  495.     if(!AllocSamples()) return 0;
  496.     q = of.samples;
  497.     for(t=0;t<of.numins;t++) {
  498.         q->flags     = SF_SIGNED;
  499.         q->speed     = 8363;
  500.         q->volume    = 64;
  501.         q->samplename = NULL;
  502.         if (sa[t]) {
  503.             _mm_fseek(modfp,sa[t],SEEK_SET);
  504.             s.length = _mm_read_M_ULONG(modfp);
  505.             s.type   = _mm_read_M_SWORD(modfp);
  506.  
  507.             if(s.type) {
  508. #ifdef MIKMOD_DEBUG
  509.                 fputs("\rNon-sample instruments not supported in MED loader yet\n",stderr);
  510. #endif
  511.                 if(!curious) {
  512.                     _mm_errno = MMERR_MED_SYNTHSAMPLES;
  513.                     return 0;
  514.                 }
  515.                 s.length=0;
  516.             }
  517.  
  518.             if(feof(modfp)) {
  519.                 _mm_errno = MMERR_LOADING_SAMPLEINFO;
  520.                 return 0;
  521.             }
  522.  
  523.             q->length    = s.length;
  524.             q->seekpos   = _mm_ftell(modfp);
  525.             q->loopstart = ms->sample[t].rep<<1;
  526.             q->loopend   = q->loopstart+(ms->sample[t].replen<<1);
  527.  
  528.             if(ms->sample[t].replen>1) q->flags|=SF_LOOP;
  529.  
  530.             /* don't load sample if length>='MMD0'...
  531.                such kluges make MikMod code unique !!! */
  532.             if(q->length >= MMD0_string) q->length=0;
  533.         } else
  534.             q->length=0;
  535.         q++;
  536.     }
  537.  
  538.     if(mh->id==MMD0_string) {
  539.         if(!LoadMMD0Patterns()) {
  540.             _mm_errno=MMERR_LOADING_PATTERN;
  541.             return 0;
  542.         }
  543.     } else
  544.       if(mh->id==MMD1_string) {
  545.         if(!LoadMMD1Patterns()) {
  546.             _mm_errno=MMERR_LOADING_PATTERN;
  547.             return 0;
  548.         }
  549.     } else {
  550.         _mm_errno = MMERR_NOT_A_MODULE;
  551.         return 0;
  552.     }
  553.     return 1;
  554. }
  555.  
  556. /*========== Loader information */
  557.  
  558. MLOADER load_med={
  559.     NULL,
  560.     "MED",
  561.     "MED loader v0.2",
  562.     MED_Init,
  563.     MED_Test,
  564.     MED_Load,
  565.     MED_Cleanup,
  566.     NULL
  567. };
  568.