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

  1. /*      MIDAS.C
  2.  *
  3.  * Simple MIDAS Sound System programming interface
  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. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <conio.h>
  17. #include <string.h>
  18. #include "midas.h"
  19.  
  20.  
  21.  
  22. /****************************************************************************\
  23. *      Global variables:
  24. \****************************************************************************/
  25.  
  26. SoundDevice     *SD;                    /* current Sound Device */
  27. ModulePlayer    *MP;                    /* current Module Player */
  28.  
  29. SoundDevice     *midasSoundDevices[NUMSDEVICES] =
  30.     { &GUS,                             /* array of pointers to all Sound */
  31.       &PAS,                             /* Devices, in numbering and */
  32.       &WSS,                             /* detection order - GUS is SD #1 */
  33.       &SB,                              /* and will be detected first */
  34.       &NSND };
  35.  
  36.     /* pointers to all Module Players: */
  37. ModulePlayer    *midasModulePlayers[NUMMPLAYERS] =
  38.     { &mpS3M,
  39.       &mpMOD };
  40.  
  41.     /* Amiga Loop Emulation flags for Module Players: */
  42. short           midasMPALE[NUMMPLAYERS] =
  43.     { 0, 1 };
  44.  
  45.  
  46.  
  47.  
  48.  
  49.  
  50. /****************************************************************************\
  51. *      Static variables used by midasXXXX() functions:
  52. \****************************************************************************/
  53.  
  54. static int      disableEMS;             /* should EMS usage be disabled? */
  55. static ushort   sdNum;                  /* Sound Device number (0xFFFF for
  56.                                            autodetect) */
  57. static ushort   ioPort;                 /* I/O port number (0xFFFF for
  58.                                            autodetect/default) */
  59. static uchar    IRQ;                    /* IRQ number (0xFF for autodetect/
  60.                                            default) */
  61. static uchar    DMA;                    /* DMA channel number (0xFF for
  62.                                            autodetect/default) */
  63. static ushort   mixRate;                /* mixing rate */
  64. static ushort   mode;                   /* forced output mode */
  65.  
  66. static int      emsInitialized;         /* is EMS heap manager initialized? */
  67. static int      tmrInitialized;         /* is TempoTimer initialized? */
  68. static int      sdInitialized;          /* is Sound Device initialized? */
  69. static int      sdChOpen;               /* are Sound Device channels open? */
  70. static int      vuInitialized;          /* are real VU-meters initialized? */
  71. static int      mpInit;                 /* is Module Player initialized? */
  72. static int      mpPlay;                 /* is Module Player playing? */
  73. static int      mpInterrupt;            /* is Module Player interrupt set? */
  74.  
  75.  
  76.  
  77.  
  78.  
  79. /****************************************************************************\
  80. *
  81. * Function:     void midasError(char *msg)
  82. *
  83. * Description:  Prints an MIDAS error message to stderr, uninitializes MIDAS
  84. *               and exits to DOS
  85. *
  86. * Input:        char *msg               Pointer to error message string
  87. *
  88. \****************************************************************************/
  89.  
  90. void midasError(char *msg)
  91. {
  92.     textmode(C80);
  93.     fprintf(stderr, "MIDAS Error: %s\n", msg);
  94. #ifdef DEBUG
  95.     errPrintList();                     /* print error list */
  96. #endif
  97.     midasClose();
  98.     exit(EXIT_FAILURE);
  99. }
  100.  
  101.  
  102.  
  103.  
  104. /****************************************************************************\
  105. *
  106. * Function:     void midasUninitError(char *msg)
  107. *
  108. * Description:  Prints an error message to stderr and exits to DOS without
  109. *               uninitializing MIDAS. This function should only be used
  110. *               from midasClose();
  111. *
  112. * Input:        char *msg               Pointer to error message string
  113. *
  114. \****************************************************************************/
  115.  
  116. void midasUninitError(char *msg)
  117. {
  118.     textmode(C80);
  119.     fprintf(stderr, "FATAL: MIDAS uninitialization error: %s\n", msg);
  120. #ifdef DEBUG
  121.     errPrintList();                     /* print error list */
  122. #endif
  123.     abort();
  124. }
  125.  
  126.  
  127.  
  128.  
  129. /****************************************************************************\
  130. *
  131. * Function:     void midasDetectSD(void)
  132. *
  133. * Description:  Attempts to detect a Sound Device. Sets the global variable
  134. *               SD to point to the detected Sound Device or NULL if no
  135. *               Sound Device was detected
  136. *
  137. \****************************************************************************/
  138.  
  139. void midasDetectSD(void)
  140. {
  141.     int         dsd;
  142.     int         dResult;
  143.     int         error;
  144.  
  145.     SD = NULL;                          /* no Sound Device detected yet */
  146.     dsd = 0;                            /* start from first Sound Device */
  147.  
  148.     /* search through Sound Devices until a Sound Device is detected: */
  149.     while ( (SD == NULL) && (dsd < NUMSDEVICES) )
  150.     {
  151.         /* attempt to detect current SD: */
  152.         if ( (error = (*midasSoundDevices[dsd]->Detect)(&dResult)) != OK )
  153.             midasError(errorMsg[error]);
  154.         if ( dResult == 1 )
  155.         {
  156.             sdNum = dsd;                /* Sound Device detected */
  157.             SD = midasSoundDevices[dsd]; /* point SD to this Sound Device */
  158.         }
  159.         dsd++;                          /* try next Sound Device */
  160.     }
  161. }
  162.  
  163.  
  164.  
  165.  
  166. /****************************************************************************\
  167. *
  168. * Function:     void midasInit(void);
  169. *
  170. * Description:  Initializes MIDAS Sound System
  171. *
  172. \****************************************************************************/
  173.  
  174. void midasInit(void)
  175. {
  176.     int         error, result;
  177.  
  178.     if ( !disableEMS )                  /* is EMS usage disabled? */
  179.     {
  180.         /* Initialize EMS Heap Manager: */
  181.         if ( (error = emsInit(&emsInitialized)) != OK )
  182.             midasError(errorMsg[error]);
  183.  
  184.         /* was EMS Heap Manager initialized? */
  185.         if ( emsInitialized == 1 )
  186.         {
  187.             useEMS = 1;                 /* yes, use EMS memory, but do not */
  188.             forceEMS = 0;               /* force its usage */
  189.         }
  190.         else
  191.         {
  192.             useEMS = 0;                 /* no, do not use EMS memory */
  193.             forceEMS = 0;
  194.         }
  195.     }
  196.     else
  197.     {
  198.         useEMS = 0;                     /* EMS disabled - do not use it */
  199.         forceEMS = 0;
  200.     }
  201.  
  202.  
  203.     if ( sdNum == 0xFFFF )             /* has a Sound Device been selected? */
  204.     {
  205.         midasDetectSD();               /* attempt to detect Sound Device */
  206.         if ( SD == NULL )
  207.             midasError("Unable to detect Sound Device");
  208.     }
  209.     else
  210.     {
  211.         SD = midasSoundDevices[sdNum];  /* use Sound Device sdNum */
  212.  
  213.         /* Sound Device number was forced, but if no I/O port, IRQ or DMA
  214.            number has been set, try to autodetect the values for this Sound
  215.            Device. If detection fails, use default values */
  216.  
  217.         if ( (ioPort == 0xFFFF) && (IRQ == 0xFF) && (DMA == 0xFF) )
  218.         {
  219.             if ( (error = SD->Detect(&result)) != OK )
  220.                 midasError(errorMsg[error]);
  221.             if ( result != 1 )
  222.                 midasError("Unable to detect Sound Device values");
  223.         }
  224.     }
  225.  
  226.     if ( ioPort != 0xFFFF )             /* has an I/O port been set? */
  227.         SD->port = ioPort;              /* if yes, set it to Sound Device */
  228.     if ( IRQ != 0xFF )                  /* what about IRQ number? */
  229.         SD->IRQ = IRQ;
  230.     if ( DMA != 0xFF )                  /* or DMA channel number */
  231.         SD->DMA = DMA;
  232.  
  233.     /* initialize TempoTimer: */
  234.     if ( (error = tmrInit()) != OK )
  235.         midasError(errorMsg[error]);
  236.  
  237.     tmrInitialized = 1;                 /* TempoTimer initialized */
  238.  
  239.     /* initialize Sound Device: */
  240.     if ( (error = SD->Init(mixRate, mode)) != OK )
  241.         midasError(errorMsg[error]);
  242.  
  243.     sdInitialized = 1;                  /* Sound Device initialized */
  244.  
  245. #ifdef REALVUMETERS
  246.     if ( realVU )
  247.     {
  248.         /* initialize real VU-meters: */
  249.         if ( (error = vuInit()) != OK )
  250.             midasError(errorMsg[error]);
  251.  
  252.         vuInitialized = 1;
  253.     }
  254. #endif
  255. }
  256.  
  257.  
  258.  
  259. /****************************************************************************\
  260. *
  261. * Function:     void midasClose(void)
  262. *
  263. * Description:  Uninitializes MIDAS Sound System
  264. *
  265. \****************************************************************************/
  266.  
  267. void midasClose(void)
  268. {
  269.     int         error;
  270.  
  271.     /* if Module Player interrupt is running, remove it: */
  272.     if ( mpInterrupt )
  273.     {
  274.         if ( (error = MP->RemoveInterrupt()) != OK )
  275.             midasUninitError(errorMsg[error]);
  276.         mpInterrupt = 0;
  277.     }
  278.  
  279.     /* if Module Player is playing, stop it: */
  280.     if ( mpPlay )
  281.     {
  282.         if ( (error = MP->StopModule()) != OK )
  283.             midasUninitError(errorMsg[error]);
  284.         mpPlay = 0;
  285.     }
  286.  
  287.     /* if Module Player has been initialized, uninitialize it: */
  288.     if ( mpInit )
  289.     {
  290.         if ( (error = MP->Close()) != OK )
  291.             midasUninitError(errorMsg[error]);
  292.         mpInit = 0;
  293.         MP = NULL;
  294.     }
  295.  
  296. #ifdef REALVUMETERS
  297.     /* if real VU-meters have been initialized, uninitialize them: */
  298.     if ( vuInitialized )
  299.     {
  300.         if ( (error = vuClose()) != OK )
  301.             midasUninitError(errorMsg[error]);
  302.         vuInitialized = 0;
  303.     }
  304. #endif
  305.  
  306.     /* if Sound Device channels are open, close them: */
  307.     if ( sdChOpen )
  308.     {
  309.         if ( (error = SD->CloseChannels()) != OK )
  310.             midasUninitError(errorMsg[error]);
  311.         sdChOpen = 0;
  312.     }
  313.  
  314.     /* if Sound Device is initialized, uninitialize it: */
  315.     if ( sdInitialized )
  316.     {
  317.         if ( (error = SD->Close()) != OK )
  318.             midasUninitError(errorMsg[error]);
  319.         sdInitialized = 0;
  320.         SD = NULL;
  321.     }
  322.  
  323.     /* if TempoTimer is initialized, uninitialize it: */
  324.     if ( tmrInitialized )
  325.     {
  326.         if ( (error = tmrClose()) != OK )
  327.             midasUninitError(errorMsg[error]);
  328.         tmrInitialized = 0;
  329.     }
  330.  
  331.     /* if EMS Heap Manager is initialized, uninitialize it: */
  332.     if ( emsInitialized )
  333.     {
  334.         if ( (error = emsClose()) != OK )
  335.             midasUninitError(errorMsg[error]);
  336.         emsInitialized = 0;
  337.     }
  338. }
  339.  
  340.  
  341.  
  342.  
  343. /****************************************************************************\
  344. *
  345. * Function:     void midasSetDefaults(void)
  346. *
  347. * Description:  Initializes MIDAS Sound System variables to their default
  348. *               states. MUST be the first MIDAS function called.
  349. *
  350. \****************************************************************************/
  351.  
  352. void midasSetDefaults(void)
  353. {
  354.     emsInitialized = 0;                 /* EMS heap manager is not
  355.                                            initialized yet */
  356.     tmrInitialized = 0;                 /* TempoTimer is not initialized */
  357.     sdInitialized = 0;                  /* Sound Device is not initialized */
  358.     sdChOpen = 0;                       /* Sound Device channels are not
  359.                                            open */
  360.     vuInitialized = 0;                  /* VU meter are not initialized */
  361.     mpInit = 0;                         /* Module Player is not initialized */
  362.     mpPlay = 0;                         /* Module Player is not playing */
  363.     mpInterrupt = 0;                    /* No Module Player interrupt */
  364.  
  365.  
  366.     ptTempo = 1;                        /* enable ProTracker BPM tempos */
  367.     usePanning = 1;                     /* enable ProTracker panning cmds */
  368.     surround = 0;                       /* disable surround to save GUS mem */
  369.     realVU = 1;                         /* enable real VU-meters */
  370.  
  371.     disableEMS = 0;                     /* do not disable EMS usage */
  372.     sdNum = 0x0FFFF;                    /* no Sound Device forced */
  373.     ioPort = 0xFFFF;                    /* no I/O port forced */
  374.     IRQ = 0xFF;                         /* no IRQ number forced */
  375.     DMA = 0xFF;                         /* no DMA channel number forced */
  376.     mode = 0;                           /* no output mode forced */
  377.     mixRate = 44100;                    /* attempt to use 44100Hz mixing
  378.                                            rate */
  379.  
  380.     SD = NULL;                          /* point SD and MP to NULL for */
  381.     MP = NULL;                          /* safety */
  382. }
  383.  
  384.  
  385.  
  386. /****************************************************************************\
  387. *
  388. * Function:     void midasParseOption(char *option)
  389. *
  390. * Description:  Parses one MIDAS command line option.
  391. *
  392. * Input:        char *option            Command line option string WITHOUT
  393. *                                       the leading '-' or '/'.
  394. *
  395. * Recognized options:
  396. *       -sx     Force Sound Device x (1 = GUS, 2 = PAS, 3 = WSS, 4 = SB,
  397. *               5 = No Sound)
  398. *       -pxxx   Force I/O port xxx (hex) for Sound Device
  399. *       -ix     Force IRQ x for Sound Device
  400. *       -dx     Force DMA channel x for Sound Device
  401. *       -mxxxx  Set mixing rate to xxxx Hz
  402. *       -oxxx   Force output mode (8 = 8-bit, 1 = 16-bit, s = stereo,
  403. *               m = mono)
  404. *       -e      Disable EMS usage
  405. *       -t      Disable ProTracker BPM tempos
  406. *       -u      Enable Surround sound
  407. *       -v      Disable real VU-meters
  408. *
  409. \****************************************************************************/
  410.  
  411. void midasParseOption(char *option)
  412. {
  413.     int         c;
  414.     char        *opt;
  415.  
  416.     opt = &option[1];
  417.     switch ( option[0] )
  418.     {
  419.         /* -sx     Force Sound Device x */
  420.         case 's':
  421.             sdNum = atoi(opt) - 1;
  422.             if ( sdNum >= NUMSDEVICES )
  423.                 midasError("Illegal Sound Device number");
  424.             break;
  425.  
  426.         /* -pxxx   Force I/O port xxx (hex) for Sound Device */
  427.         case 'p':
  428.             sscanf(opt, "%X", &ioPort);
  429.             break;
  430.  
  431.         /* -ix     Force IRQ x for Sound Device */
  432.         case 'i':
  433.             IRQ = atoi(opt);
  434.             break;
  435.  
  436.         /* -dx     Force DMA channel x for Sound Device */
  437.         case 'd':
  438.             DMA = atoi(opt);
  439.             break;
  440.  
  441.         /* -mxxxx  Set mixing rate to xxxx Hz */
  442.         case 'm':
  443.             mixRate = atol(opt);
  444.             if ( mixRate < 1 )
  445.                 midasError("Invalid mixing rate");
  446.             break;
  447.  
  448.         /* -e      Disable EMS usage */
  449.         case 'e':
  450.             disableEMS = 1;
  451.             break;
  452.  
  453.         /* -t      Disable ProTracker BPM tempos */
  454.         case 't':
  455.             ptTempo = 0;
  456.             break;
  457.  
  458.         /* -u      Enable Surround sound */
  459.         case 'u':
  460.             surround = 1;
  461.             break;
  462.  
  463.         /* -oxxx   Force output mode */
  464.         case 'o':
  465.             for ( c = 0; c < strlen(opt); c++ )
  466.             {
  467.                 switch( opt[c] )
  468.                 {
  469.                     /* Output mode '8' - 8-bit */
  470.                     case '8':
  471.                         mode |= sd8bit;
  472.                         mode &= 0xFFFF ^ sd16bit;
  473.                         break;
  474.  
  475.                     /* Output mode '1' - 16-bit */
  476.                     case '1':
  477.                         mode |= sd16bit;
  478.                         mode &= 0xFFFF ^ sd8bit;
  479.                         break;
  480.  
  481.                     /* Output mode 'm' - mono */
  482.                     case 'm':
  483.                         mode |= sdMono;
  484.                         mode &= 0xFFFF ^ sdStereo;
  485.                         break;
  486.  
  487.                     /* Output mode 's' - stereo */
  488.                     case 's':
  489.                         mode |= sdStereo;
  490.                         mode &= 0xFFFF ^ sdMono;
  491.                         break;
  492.  
  493.                     default:
  494.                         midasError("Invalid output mode character");
  495.                         break;
  496.                 }
  497.             }
  498.             break;
  499.  
  500.         /* -v      Disable real VU-meters */
  501.         case 'v':
  502.             realVU = 0;
  503.             break;
  504.  
  505.         default:
  506.             midasError("Unknown option character");
  507.             break;
  508.     }
  509. }
  510.  
  511.  
  512.  
  513.  
  514. /****************************************************************************\
  515. *
  516. * Function:     void midasParseOptions(int optCount, char **options)
  517. *
  518. * Description:  Parses MIDAS command line options and sets MIDAS variables
  519. *               accordingly.
  520. *
  521. * Input:        int optCount            Number of options
  522. *               char **options          Pointer to an array of pointers to
  523. *                                       option strings.
  524. *
  525. * Also '/' is recognized as a option delimiter.
  526. *
  527. \****************************************************************************/
  528.  
  529. void midasParseOptions(int optCount, char **options)
  530. {
  531.     int         i;
  532.  
  533.     for ( i = 0; i < optCount; i++ )
  534.     {
  535.         if ( ( options[i][0] == '-' ) || ( options[i][0] == '/' )  )
  536.             midasParseOption(&options[i][1]);
  537.         else
  538.             midasError("Invalid command line option");
  539.     }
  540. }
  541.  
  542.  
  543.  
  544.  
  545. /****************************************************************************\
  546. *
  547. * Function:     void midasParseEnvironment(void)
  548. *
  549. * Description:  Parses the MIDAS environment string, which has same format
  550. *               as the command line options.
  551. *
  552. \****************************************************************************/
  553.  
  554. void midasParseEnvironment(void)
  555. {
  556.     char        *envs, *midasenv, *opt;
  557.     int         spos, slen, stopparse, error;
  558.  
  559.     /* try to get pointer to MIDAS environment string: */
  560.     envs = getenv("MIDAS");
  561.  
  562.     if ( envs != NULL )
  563.     {
  564.         slen = strlen(envs);
  565.         /* allocate memory for a copy of the environment string: */
  566.         if ( (error = memAlloc(slen+1, (void**) &midasenv)) != OK )
  567.             midasError(errorMsg[error]);
  568.  
  569.         /* copy environment string to midasenv: */
  570.         strcpy(midasenv, envs);
  571.  
  572.         spos = 0;                       /* search position = 0 */
  573.         opt = NULL;                     /* current option string = NULL */
  574.         stopparse = 0;
  575.  
  576.         /* parse the whole environment string: */
  577.         while ( !stopparse )
  578.         {
  579.             switch ( midasenv[spos] )
  580.             {
  581.                 case ' ':
  582.                     /* current character is space - change it to '\0' and
  583.                        parse this option string if it exists*/
  584.                     midasenv[spos] = 0;
  585.                     if ( opt != NULL )
  586.                         midasParseOption(opt);
  587.  
  588.                     opt = NULL;         /* no option string */
  589.                     spos++;             /* next character */
  590.                     break;
  591.  
  592.                 case 0:
  593.                     /* Current character is '\0' - end. Parse option string
  594.                        if it exists and stop parsing. */
  595.                     if ( (opt != NULL) && (*opt != 0) )
  596.                         midasParseOption(opt);
  597.                     stopparse = 1;
  598.                     break;
  599.  
  600.                 case '-':
  601.                 case '/':
  602.                     /* Current character is '-' or '/' - option string starts
  603.                        from next character */
  604.                     spos++;
  605.                     opt = &midasenv[spos];
  606.                     break;
  607.  
  608.                 default:
  609.                     /* some normal character - continue parsing from next
  610.                        character */
  611.                     spos++;
  612.             }
  613.         }
  614.  
  615.         if ( (error = memFree(midasenv)) != OK )
  616.             midasError(errorMsg[error]);
  617.     }
  618. }
  619.  
  620.  
  621.  
  622. /****************************************************************************\
  623. *
  624. * Function:     mpModule *midasPlayModule(char *fileName, int numEffectChns)
  625. *
  626. * Description:  Loads a module into memory, points MP to the correct Module
  627. *               Player and starts playing it.
  628. *
  629. * Input:        char *fileName          Pointer to module file name
  630. *               int numEffectChns       Number of channels to open for sound
  631. *                                       effects.
  632. *
  633. * Returns:      Pointer to module structure. This function can not fail,
  634. *               as it will call midasError() to handle all error cases.
  635. *
  636. * Notes:        The Sound Device channels available for sound effects are the
  637. *               _first_ numEffectChns channels. So, for example, if you use
  638. *               midasPlayModule("TUNE.MOD", 3), you can use channels 0-2 for
  639. *               sound effects.
  640. *
  641. \****************************************************************************/
  642.  
  643. mpModule *midasPlayModule(char *fileName, int numEffectChns)
  644. {
  645.     uchar       *header;
  646.     fileHandle  f;
  647.     mpModule    *module;
  648.     short       numChans;
  649.     int         error, mpNum, recognized;
  650.  
  651.     if ( (error = memAlloc(MPHDRSIZE, (void**) &header)) != OK )
  652.         midasError(errorMsg[error]);
  653.  
  654.     if ( (error = fileOpen(fileName, fileOpenRead, &f)) != OK )
  655.         midasError(errorMsg[error]);
  656.  
  657.     /* read MPHDRSIZE bytes of module header: */
  658.     if ( (error = fileRead(f, header, MPHDRSIZE)) != OK )
  659.         midasError(errorMsg[error]);
  660.  
  661.     if ( (error = fileClose(f)) != OK )
  662.         midasError(errorMsg[error]);
  663.  
  664.     /* Search through all Module Players to find one that recognizes
  665.        file header: */
  666.     mpNum = 0; MP = NULL;
  667.     while ( (mpNum < NUMMPLAYERS) && (MP == NULL) )
  668.     {
  669.         if ( (error = midasModulePlayers[mpNum]->Identify(header,
  670.             &recognized)) != OK )
  671.             midasError(errorMsg[error]);
  672.         if ( recognized )
  673.         {
  674.             MP = midasModulePlayers[mpNum];
  675.             ALE = midasMPALE[mpNum];
  676.         }
  677.         mpNum++;
  678.     }
  679.  
  680.     if ( MP == NULL )
  681.         midasError("Unknown module format");
  682.  
  683.     /* deallocate module header: */
  684.     if ( (error = memFree(header)) != OK )
  685.         midasError(errorMsg[error]);
  686.  
  687.     /* initialize module player: */
  688.     if ( (error = MP->Init(SD)) != OK )
  689.         midasError(errorMsg[error]);
  690.     mpInit = 1;
  691.  
  692.     /* load module: */
  693.     if ( (error = MP->LoadModule(fileName, SD, (mpModule**) &module)) != OK )
  694.         midasError(errorMsg[error]);
  695.  
  696.     numChans = module->numChans;
  697.  
  698.     /* open Sound Device channels: */
  699.     if ( (error = SD->OpenChannels(numChans + numEffectChns)) != OK )
  700.         midasError(errorMsg[error]);
  701.     sdChOpen = 1;
  702.  
  703.     /* Start playing the module using Sound Device channels (numEffectChns) -
  704.        (numEffectChns+numChans-1) and looping the whole song: */
  705.     if ( (error = MP->PlayModule(module, numEffectChns, numChans, 0, 32767))
  706.         != OK )
  707.         midasError(errorMsg[error]);
  708.     mpPlay = 1;
  709.  
  710.     /* start playing using the timer: */
  711.     if ( (error = MP->SetInterrupt()) != OK )
  712.         midasError(errorMsg[error]);
  713.  
  714.     return module;
  715. }
  716.  
  717.  
  718.  
  719.  
  720. /****************************************************************************\
  721. *
  722. * Function:     void midasStopModule(mpModule *module)
  723. *
  724. * Description:  Stops playing a module, deallocates it and uninitializes
  725. *               the Module Player. Also closes _all_ Sound Device channels,
  726. *               including those opened for effects.
  727. *
  728. \****************************************************************************/
  729.  
  730. void midasStopModule(mpModule *module)
  731. {
  732.     int         error;
  733.  
  734.     /* remove Module Player interrupt: */
  735.     if ( (error = MP->RemoveInterrupt()) != OK )
  736.         midasError(errorMsg[error]);
  737.     mpInterrupt = 0;
  738.  
  739.     /* stop playing the module: */
  740.     if ( (error = MP->StopModule()) != OK )
  741.         midasError(errorMsg[error]);
  742.     mpPlay = 0;
  743.  
  744.     /* deallocate module: */
  745.     if ( (error = MP->FreeModule(module, SD)) != OK )
  746.         midasError(errorMsg[error]);
  747.  
  748.     /* uninitialize Module Player: */
  749.     if ( (error = MP->Close()) != OK )
  750.         midasError(errorMsg[error]);
  751.     mpInit = 0;
  752.     MP = NULL;                          /* point MP to NULL for safety */
  753.  
  754.     /* close Sound Device channels: */
  755.     if ( (error = SD->CloseChannels()) != OK )
  756.         midasError(errorMsg[error]);
  757.     sdChOpen = 0;
  758. }
  759.