home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 19 / CD_ASCQ_19_010295.iso / dos / prg / midas / s3mload.c < prev    next >
C/C++ Source or Header  |  1994-08-06  |  22KB  |  658 lines

  1. /*      S3MLOAD.C
  2.  *
  3.  * Scream Tracker 3 Module loader
  4.  *
  5.  * Copyright 1994 Petteri Kangaslampi and Jarno Paananen
  6.  *
  7.  * This file is part of the MIDAS Sound System, and may only be
  8.  * used, modified and distributed under the terms of the MIDAS
  9.  * Sound System license, LICENSE.TXT. By continuing to use,
  10.  * modify or distribute this file you indicate that you have
  11.  * read the license and understand and accept it fully.
  12. */
  13.  
  14.  
  15. #include "lang.h"
  16. #include "mtypes.h"
  17. #include "errors.h"
  18. #include "mglobals.h"
  19. #include "mmem.h"
  20. #include "file.h"
  21. #include "sdevice.h"
  22. #include "mplayer.h"
  23. #include "s3m.h"
  24. #include "ems.h"
  25. #include "vu.h"
  26.  
  27. #define NULL 0L
  28.  
  29.  
  30.  
  31.  
  32. /****************************************************************************\
  33. *
  34. * Function:     int CompMem(void *a, void *b, size_t numBytes)
  35. *
  36. * Description:  Compares two memory areas
  37. *
  38. * Input:        void *a                 memory area #1
  39. *               void *b                 memory area #2
  40. *               size_t numBytes         number of bytes to compare
  41. *
  42. * Returns:      1 if memory areas are equal, 0 if not
  43. *
  44. \****************************************************************************/
  45.  
  46. static int CompMem(void *a, void *b, size_t numBytes)
  47. {
  48.     uchar       *m1 = a, *m2 = b;
  49.     size_t      i;
  50.  
  51.     for ( i = 0; i < numBytes; i++ )
  52.         if ( m1[i] != m2[i] )
  53.             return 0;
  54.  
  55.     return 1;
  56. }
  57.  
  58.  
  59.  
  60.  
  61. /****************************************************************************\
  62. *
  63. * Function:     void CopyMem(void *dest, void *source, size_t numBytes)
  64. *
  65. * Description:  Copies a memory area
  66. *
  67. * Input:        void *dest              pointer to destination
  68. *               void *source            pointer to source
  69. *               size_t numBytes         number of bytes to copy
  70. *
  71. \****************************************************************************/
  72.  
  73. static void CopyMem(void *dest, void *source, size_t numBytes)
  74. {
  75.     uchar       *src = source, *dst = dest;
  76.     size_t      i;
  77.  
  78.     for ( i = 0; i < numBytes; i++ )
  79.         dst[i] = src[i];
  80. }
  81.  
  82.  
  83.  
  84.  
  85. /* Size of temporary memory area used for avoiding memory fragmentation
  86.    if EMS is used */
  87. #define TEMPSIZE 8192
  88.  
  89. /* Pass error code in variable "error" on, used in s3mLoadModule(). */
  90. #define S3MLOADPASSERROR { s3mLoadError(SD); PASSERROR(ID_s3mLoadModule) }
  91.  
  92.  
  93.  
  94.  
  95. /****************************************************************************\
  96. *       Module loader buffers and file pointer. These variables are static
  97. *       instead of local so that a separate deallocation can be used which
  98. *       will be called before exiting in error situations
  99. \****************************************************************************/
  100. static fileHandle f;
  101. static int      fileOpened;
  102. static mpModule *ms3m;
  103. static ushort   *instPtrs;
  104. static ushort   *pattPtrs;
  105. static uchar    *smpBuf;
  106. static void     *tempmem;
  107.  
  108.  
  109.  
  110.  
  111.  
  112. /****************************************************************************\
  113. *
  114. * Function:     int s3mFreeModule(mpModule *module, SoundDevice *SD);
  115. *
  116. * Description:  Deallocates a Scream Tracker 3 module
  117. *
  118. * Input:        mpModule *module        module to be deallocated
  119. *               SoundDevice *SD         Sound Device that has stored the
  120. *                                       samples
  121. *
  122. * Returns:      MIDAS error code
  123. *
  124. \****************************************************************************/
  125.  
  126. int CALLING s3mFreeModule(mpModule *module, SoundDevice *SD)
  127. {
  128.     int         i, error;
  129.  
  130.     if ( module == NULL )               /* valid module? */
  131.     {
  132.         ERROR(errUndefined, ID_s3mFreeModule);
  133.         return errUndefined;
  134.     }
  135.  
  136.  
  137.     /* deallocate pattern orders if allocated: */
  138.     if ( module->orders != NULL )
  139.         if ( (error = memFree(module->orders)) != OK )
  140.             PASSERROR(ID_s3mFreeModule)
  141.  
  142.     /* deallocate sample used flags: */
  143.     if ( module->instsUsed != NULL )
  144.         if ( (error = memFree(module->instsUsed)) != OK )
  145.             PASSERROR(ID_s3mFreeModule)
  146.  
  147.  
  148.     if ( module->insts != NULL )        /* instruments? */
  149.     {
  150.         for ( i = 0; i < module->numInsts; i++ )
  151.         {
  152.             /* If the instrument has been added to Sound Device, remove
  153.                it, otherwise just deallocate the sample if allocated */
  154.  
  155.             if ( (module->insts[i].sdInstHandle != 0) && (SD != NULL) )
  156.             {
  157.                 if ( (error = SD->RemInstrument(
  158.                     module->insts[i].sdInstHandle)) != OK )
  159.                     PASSERROR(ID_s3mFreeModule)
  160.             }
  161.             else
  162.                 if ( module->insts[i].sample != NULL )
  163.                     if ( (error = memFree(module->insts[i].sample)) != OK )
  164.                         PASSERROR(ID_s3mFreeModule)
  165.  
  166.             #ifdef REALVUMETERS
  167.             /* remove VU meter information if used: */
  168.             if ( realVU )
  169.             {
  170.                 if (module->insts[i].sdInstHandle != 0)
  171.                     if ( (error = vuRemove(module->insts[i].sdInstHandle))
  172.                         != OK )
  173.                         PASSERROR(ID_s3mFreeModule)
  174.             }
  175.             #endif
  176.  
  177.         }
  178.         /* deallocate instrument structures: */
  179.         if ( (error = memFree(module->insts)) != OK )
  180.             PASSERROR(ID_s3mFreeModule)
  181.     }
  182.  
  183.     if ( (module->patterns != NULL) && (module->pattEMS != NULL) )
  184.     {
  185.         for ( i = 0; i < module->numPatts; i++ )
  186.         {
  187.             /* if the pattern has been allocate, deallocate it - either
  188.                 from conventional memory or from EMS */
  189.             if ( module->patterns[i] != NULL )
  190.             {
  191.                 if ( module->pattEMS[i] == 1 )
  192.                 {
  193.                     if ( (error = emsFree((emsBlock*) module->patterns[i]))
  194.                         != OK )
  195.                         PASSERROR(ID_s3mFreeModule)
  196.                 }
  197.                 else
  198.                     if ( (error = memFree(module->patterns[i])) != OK )
  199.                         PASSERROR(ID_s3mFreeModule)
  200.             }
  201.         }
  202.         /* deallocate pattern pointers: */
  203.         if ( (error = memFree(module->patterns)) != OK )
  204.             PASSERROR(ID_s3mFreeModule)
  205.  
  206.         /* deallocate pattern EMS flags: */
  207.         if ( (error = memFree(module->pattEMS)) != OK )
  208.             PASSERROR(ID_s3mFreeModule)
  209.     }
  210.  
  211.     /* deallocate the module: */
  212.     if ( (error = memFree(module)) != OK)
  213.         PASSERROR(ID_s3mFreeModule)
  214.  
  215.     return OK;
  216. }
  217.  
  218.  
  219.  
  220.  
  221. /****************************************************************************\
  222. *
  223. * Function:     void s3mLoadError(SoundDevice *SD)
  224. *
  225. * Description:  Stops loading the module, deallocates all buffers and closes
  226. *               the file.
  227. *
  228. * Input:        SoundDevice *SD         Sound Device that has been used for
  229. *                                       loading.
  230. *
  231. \****************************************************************************/
  232.  
  233. static void s3mLoadError(SoundDevice *SD)
  234. {
  235.     /* Close file if opened. Do not process errors. */
  236.     if ( fileOpened )
  237.         if ( fileClose(f) != OK )
  238.             return;
  239.  
  240.     /* Attempt to deallocate module if allocated. Do not process errors. */
  241.     if ( ms3m != NULL )
  242.         if ( s3mFreeModule(ms3m, SD) != OK )
  243.             return;
  244.  
  245.     /* Deallocate buffers if allocated. Do not process errors. */
  246.     if ( smpBuf != NULL )
  247.         if ( memFree(smpBuf) != OK )
  248.             return;
  249.     if ( tempmem != NULL )
  250.         if ( memFree(tempmem) != OK )
  251.             return;
  252.     if ( instPtrs != NULL )
  253.         if ( memFree(instPtrs) != OK )
  254.             return;
  255.     if ( pattPtrs != NULL )
  256.         if ( memFree(pattPtrs) != OK )
  257.             return;
  258. }
  259.  
  260.  
  261.  
  262.  
  263. /****************************************************************************\
  264. *
  265. * Function:     int s3mLoadModule(char *fileName, SoundDevice *SD,
  266. *                   mpModule **module);
  267. *
  268. * Description:  Loads a Scream Tracker 3 module into memory
  269. *
  270. * Input:        char *fileName          name of module file to be loaded
  271. *               SoundDevice *SD         Sound Device which will store the
  272. *                                       samples
  273. *               mpModule **module       pointer to variable which will store
  274. *                                       the module pointer.
  275. *
  276. * Returns:      MIDAS error code.
  277. *               Pointer to module structure is stored in *module.
  278. *
  279. \****************************************************************************/
  280.  
  281. int CALLING s3mLoadModule(char *fileName, SoundDevice *SD, mpModule **module)
  282. {
  283.     s3mHeader   s3mh;
  284.     s3mInstHdr  s3mi;
  285.     int         i;
  286.     mpInstrument   *inst;
  287.     ushort      pattSize;
  288.     mpPattern   *pattData;
  289.     ushort      lend;
  290.     ulong       maxSmpLength;
  291.     int         error;
  292.     unsigned    ordersize;
  293.     void        *p;
  294.  
  295.     /* point buffers to NULL and set fileOpened to 0 so that modLoadError()
  296.        can be called at any point: */
  297.     fileOpened = 0;
  298.     ms3m = NULL;
  299.     instPtrs = NULL;
  300.     pattPtrs = NULL;
  301.     smpBuf = NULL;
  302.     tempmem = NULL;
  303.  
  304.  
  305.     /* Open module file: */
  306.     if ( (error = fileOpen(fileName, fileOpenRead, &f)) != OK )
  307.         S3MLOADPASSERROR
  308.  
  309.     /* Allocate memory for the module structure: */
  310.     if ( (error = memAlloc(sizeof(mpModule), (void**) &ms3m)) != OK )
  311.         S3MLOADPASSERROR
  312.  
  313.     ms3m->orders = NULL;                 /* clear module structure so that */
  314.     ms3m->insts = NULL;                  /* it can be deallocated with */
  315.     ms3m->patterns = NULL;               /* s3mFree() at any point */
  316.     ms3m->pattEMS = NULL;
  317.     ms3m->instsUsed = NULL;
  318.  
  319.     /* Read .S3M file header: */
  320.     if ( (error = fileRead(f, &s3mh, sizeof(s3mHeader))) != OK )
  321.         S3MLOADPASSERROR
  322.  
  323.     /* Check the "SCRM" signature in header: */
  324.     if ( !CompMem(&s3mh.SCRM[0], "SCRM", 4) )
  325.     {
  326.         ERROR(errInvalidModule, ID_s3mLoadModule);
  327.         s3mLoadError(SD);
  328.         return errInvalidModule;
  329.     }
  330.  
  331.     CopyMem(&ms3m->ID[0], &s3mh.SCRM[0], 4);    /* copy ID */
  332.     ms3m->IDnum = idS3M;                 /* S3M module ID */
  333.  
  334.     CopyMem(&ms3m->songName[0], &s3mh.name[0], 28); /* copy song name */
  335.     ms3m->songLength = s3mh.songLength;         /* copy song length */
  336.     ms3m->numInsts = s3mh.numInsts;      /* copy number of instruments */
  337.     ms3m->numPatts = s3mh.numPatts;      /* copy number of patterns */
  338.     CopyMem(&ms3m->flags, &s3mh.flags, sizeof s3mh.flags);/* copy S3M flags */
  339.     ms3m->masterVol = s3mh.masterVol;    /* copy master volume */
  340.     ms3m->speed = s3mh.speed;            /* copy initial speed */
  341.     ms3m->tempo = s3mh.tempo;            /* copy initial BPM tempo */
  342.     ms3m->masterMult = s3mh.masterMult & 15;     /* copy master multiplier */
  343.     ms3m->stereo = (s3mh.masterMult >> 4) & 1;   /* copy stereo flag */
  344.     /* copy channel settings: */
  345.  
  346.     for (i = 0; i < 32; i++)
  347.     {
  348.         if (s3mh.chanSettings[i] > 16)
  349.             ms3m->chanSettings[i] = 0;
  350.         else
  351.             if (s3mh.chanSettings[i] < 8)
  352.                 ms3m->chanSettings[i] = -64;
  353.             else
  354.                 ms3m->chanSettings[i] = 64;
  355.     }
  356.  
  357.  
  358.     /* Allocate memory for pattern orders: (length of pattern orders must be
  359.        even) */
  360.     ordersize = 2 * ((ms3m->songLength+1) / 2);
  361.     if ( (error = memAlloc(ordersize, (void**) &ms3m->orders)) != OK )
  362.         S3MLOADPASSERROR
  363.  
  364.     /* Read pattern orders from file: */
  365.     if ( (error = fileRead(f, ms3m->orders, ordersize)) != OK )
  366.         S3MLOADPASSERROR
  367.  
  368.     /* Calculate real song length: (exclude 0xFF bytes from end) */
  369.     for ( i = (ms3m->songLength - 1); ms3m->orders[i] == 0xFF; i-- );
  370.     ms3m->songLength = i + 1;
  371.  
  372.     if (!ms3m->songLength)
  373.     {
  374.         ERROR(errInvalidModule, ID_s3mLoadModule);
  375.         s3mLoadError(SD);
  376.         return errInvalidModule;
  377.     }
  378.  
  379.     /* Allocate memory for instrument structures: */
  380.     if ( (error = memAlloc(ms3m->numInsts * sizeof(mpInstrument),
  381.         (void**) &ms3m->insts)) != OK )
  382.         S3MLOADPASSERROR
  383.  
  384.     /* Clear all instruments: */
  385.     for ( i = 0; i < ms3m->numInsts; i++ )
  386.     {
  387.         ms3m->insts[i].sample = NULL;
  388.         ms3m->insts[i].sdInstHandle = 0;
  389.     }
  390.  
  391.  
  392.     /* Allocate memory for instrument paragraph pointers: */
  393.     if ( (error = memAlloc(2 * ms3m->numInsts, (void**) &instPtrs)) != OK )
  394.         S3MLOADPASSERROR
  395.  
  396.     /* Read instrument pointers: */
  397.     if ( (error = fileRead(f, instPtrs, 2 * ms3m->numInsts)) != OK )
  398.         S3MLOADPASSERROR
  399.  
  400.     /* Allocate memory for S3M file pattern pointers: */
  401.     if ( (error = memAlloc(2 * ms3m->numPatts, (void**) &pattPtrs)) != OK )
  402.         S3MLOADPASSERROR
  403.  
  404.     /* Read pattern pointers: */
  405.     if ( (error = fileRead(f, pattPtrs, 2 * ms3m->numPatts)) != OK )
  406.         S3MLOADPASSERROR
  407.  
  408.     /* Allocate memory for pattern pointers: */
  409.     if ( (error = memAlloc(ms3m->numPatts * sizeof(mpPattern*), (void**)
  410.         &ms3m->patterns)) != OK )
  411.         S3MLOADPASSERROR
  412.  
  413.     /* Allocate memory for pattern EMS flags: */
  414.     if ( (error = memAlloc(ms3m->numPatts, (void**) &ms3m->pattEMS)) != OK )
  415.         S3MLOADPASSERROR
  416.  
  417.     for ( i = 0; i < ms3m->numPatts; i++ ) /* point all unallocated patterns */
  418.         ms3m->patterns[i] = NULL;          /* to NULL for safety */
  419.  
  420.     /* Read all patterns to memory: */
  421.     for ( i = 0; i < ms3m->numPatts; i++ )
  422.     {
  423.         if(pattPtrs[i] != NULL)
  424.         {
  425.             /* Seek to pattern beginning in file: */
  426.             if ( (error = fileSeek(f, 16L * pattPtrs[i], fileSeekAbsolute))
  427.                 != OK )
  428.                 S3MLOADPASSERROR
  429.  
  430.             /* Read pattern length from file: */
  431.             if ( (error = fileRead(f, &pattSize, 2)) != OK )
  432.                 S3MLOADPASSERROR
  433.  
  434.             if ( useEMS == 1 )
  435.             {
  436.                 /* Try to allocate EMS memory for pattern: */
  437.                 if ( (error = emsAlloc(pattSize+2, (emsBlock**) &p)) != OK )
  438.                 {
  439.                     /* failed - if only EMS memory should be used, or the
  440.                        error is other than out of EMS memory, pass the error
  441.                        on */
  442.                     if ( (forceEMS == 1) || (error != errOutOfEMS) )
  443.                         S3MLOADPASSERROR
  444.                     else
  445.                     {
  446.                         /* pattern not in EMS: */
  447.                         ms3m->pattEMS[i] = 0;
  448.  
  449.                         /* try to allocate conventional memory instead: */
  450.                         if ( (error = memAlloc(pattSize+2, (void**) &p)) != OK )
  451.                             S3MLOADPASSERROR
  452.                     }
  453.                 }
  454.                 else
  455.                 {
  456.                     /* Pattern is in EMS - map pattern EMS block to conventional
  457.                         memory and point pattData to it */
  458.                     ms3m->pattEMS[i] = 1;
  459.  
  460.                     /* map EMS block to conventional memory and point pattData
  461.                         to the memory area: */
  462.                     if ( (error = emsMap((emsBlock*) p, (void**) &pattData))
  463.                         != OK )
  464.                         S3MLOADPASSERROR
  465.                 }
  466.             }
  467.             else
  468.             {
  469.                 /* No EMS memory used - allocate conventional memory for
  470.                     pattern: */
  471.                 ms3m->pattEMS[i] = 0;
  472.  
  473.                 if ( (error = memAlloc(pattSize+2, (void**) &p)) != OK )
  474.                     S3MLOADPASSERROR
  475.  
  476.                 pattData = p;
  477.             }
  478.  
  479.  
  480.             ms3m->patterns[i] = p;
  481.  
  482.             pattData->length = pattSize;    /* save pattern length */
  483.  
  484.             /* Read pattern data from file: */
  485.             if ( (error = fileRead(f, &pattData->data[0], pattSize)) != OK )
  486.                 S3MLOADPASSERROR
  487.         }
  488.     }
  489.  
  490.     /* deallocate pattern file pointers: */
  491.     if ( (error = memFree(pattPtrs)) != OK )
  492.         S3MLOADPASSERROR
  493.     pattPtrs = NULL;
  494.  
  495.     /* detect number of channels: */
  496.     if ( (error = s3mDetectChannels(ms3m, &ms3m->numChans)) != OK )
  497.         S3MLOADPASSERROR
  498.  
  499.     /* allocate memory for instrument used flags: */
  500.     if ( (error = memAlloc(ms3m->numInsts, (void **) &ms3m->instsUsed))
  501.         != OK )
  502.         S3MLOADPASSERROR
  503.  
  504.     /* find which instruments are used: */
  505.     if ( (error = s3mFindUsedInsts(ms3m, ms3m->instsUsed)) != OK )
  506.         S3MLOADPASSERROR
  507.  
  508.     /* Find maximum sample length: */
  509.     maxSmpLength = 0;
  510.     for ( i = 0; i < ms3m->numInsts; i++ )
  511.     {
  512.         /* Seek to instrument header in file: */
  513.         if ( (error = fileSeek(f, 16L * instPtrs[i], fileSeekAbsolute))
  514.             != OK )
  515.             S3MLOADPASSERROR
  516.  
  517.         /* Read instrument header from file: */
  518.         if ( (error = fileRead(f, &s3mi, sizeof(s3mInstHdr))) != OK )
  519.             S3MLOADPASSERROR
  520.  
  521.         if ( maxSmpLength < s3mi.length )
  522.             maxSmpLength = s3mi.length;
  523.     }
  524.  
  525.     /* Check that no instrument is too long: */
  526.     if ( maxSmpLength > SMPMAX )
  527.     {
  528.         ERROR(errInvalidInst, ID_s3mLoadModule);
  529.         s3mLoadError(SD);
  530.         return errInvalidInst;
  531.     }
  532.  
  533.     /* If EMS is used, allocate TEMPSIZE bytes of memory before the sample
  534.        buffer and deallocate it after allocating all temporary loading
  535.        buffers to minimize memory fragmentation */
  536.     if ( useEMS )
  537.     {
  538.         if ( (error = memAlloc(TEMPSIZE, &tempmem)) != OK )
  539.             S3MLOADPASSERROR
  540.     }
  541.  
  542.  
  543.     /* allocate memory for sample loading buffer: */
  544.     if ( (error = memAlloc(maxSmpLength, (void**) &smpBuf)) != OK )
  545.         S3MLOADPASSERROR
  546.  
  547.     if ( useEMS )
  548.     {
  549.         if ( (error = memFree(tempmem)) != OK )
  550.             S3MLOADPASSERROR
  551.         tempmem = NULL;
  552.     }
  553.  
  554.     for ( i = 0; i < ms3m->numInsts; i++ )
  555.     {
  556.  
  557.         /* point inst to current instrument structure */
  558.         inst = &ms3m->insts[i];
  559.  
  560.         /* Seek to instrument header in file: */
  561.         if ( (error = fileSeek(f, 16 * instPtrs[i], fileSeekAbsolute))
  562.             != OK )
  563.             S3MLOADPASSERROR
  564.  
  565.         /* Read instrument header from file: */
  566.         if ( (error = fileRead(f, &s3mi, sizeof(s3mInstHdr))) != OK )
  567.             S3MLOADPASSERROR
  568.  
  569.         /* Check if the instrument is valid - not too long, not stereo,
  570.            16-bit or packed */
  571.         if ( (s3mi.length > SMPMAX) || ((s3mi.flags & 6) != 0) ||
  572.             (s3mi.pack != 0) )
  573.         {
  574.             ERROR(errInvalidInst, ID_s3mLoadModule);
  575.             s3mLoadError(SD);
  576.             return errFileRead;
  577.         }
  578.  
  579.         CopyMem(&inst->fileName[0], &s3mi.dosName[0], 13); /* copy filename */
  580.         CopyMem(&inst->iname[0], &s3mi.iname[0], 28);  /* copy inst name */
  581.         inst->length = s3mi.length;         /* copy sample length */
  582.         inst->loopStart = s3mi.loopStart;   /* copy sample loop start */
  583.         inst->loopEnd = s3mi.loopEnd;       /* copy sample loop end */
  584.         inst->looping = s3mi.flags & 1;     /* copy looping status */
  585.         inst->volume = s3mi.volume;         /* copy default volume */
  586.         inst->c2Rate = s3mi.c2Rate;         /* copy C2 playing rate */
  587.  
  588.         /* Make sure that instrument volume is < 63 */
  589.         if ( inst->volume > 63 )
  590.             inst->volume = 63;
  591.  
  592.         /* Check if instrument is used: */
  593.         if ( ms3m->instsUsed[i] == 1 )
  594.         {
  595.             /* Instrument is used - check if there is a sample for this
  596.                instrument - type = 1, signature "SCRS" and length != 0 */
  597.             if ( (s3mi.type == 1) && CompMem(&s3mi.SCRS[0], "SCRS", 4)
  598.                 && (inst->length != 0) )
  599.             {
  600.                 /* Seek to sample position in file: */
  601.                 if ( (error = fileSeek(f, 16L * s3mi.samplePtr,
  602.                     fileSeekAbsolute)) != OK )
  603.                     S3MLOADPASSERROR
  604.  
  605.                 /* Read sample to loading buffer: */
  606.                 if ( (error = fileRead(f, smpBuf, inst->length)) != OK )
  607.                     S3MLOADPASSERROR
  608.             }
  609.  
  610.             /* Point inst->sample to NULL, as the instrument is not available
  611.             - only the Sound Device has it */
  612.             inst->sample = NULL;
  613.  
  614.             /* Add instrument to Sound Device: */
  615.             error = SD->AddInstrument(smpBuf, smp8bit, inst->length,
  616.                 inst->loopStart, inst->loopEnd, inst->volume, inst->looping,
  617.                 &inst->sdInstHandle);
  618.             if ( error != OK )
  619.                 S3MLOADPASSERROR
  620.  
  621.             #ifdef REALVUMETERS
  622.             /* if real VU meters are used, prepare VU meter information
  623.                 for this instrument */
  624.             if ( realVU )
  625.             {
  626.                 if ( inst->looping )
  627.                     lend = inst->loopEnd;
  628.                 else
  629.                     lend = 0;           /* no looping - set VU loop end to
  630.                                            zero */
  631.  
  632.                 if ( (error = vuPrepare(inst->sdInstHandle, smpBuf, inst->length,
  633.                     inst->loopStart, lend)) != OK )
  634.                     S3MLOADPASSERROR
  635.             }
  636.             #endif
  637.         }
  638.     }
  639.  
  640.     /* deallocate instrument pointers: */
  641.     if ( (error = memFree(instPtrs)) != OK )
  642.         S3MLOADPASSERROR
  643.     instPtrs = NULL;
  644.  
  645.     /* deallocate sample loading buffer: */
  646.     if ( (error = memFree(smpBuf)) != OK )
  647.         S3MLOADPASSERROR
  648.     smpBuf = NULL;
  649.  
  650.     if ( (error = fileClose(f)) != OK )
  651.         S3MLOADPASSERROR
  652.     fileOpened = 0;
  653.  
  654.     *module = ms3m;                     /* return module pointer in *module */
  655.  
  656.     return OK;
  657. }
  658.