home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 15 / CD_ASCQ_15_070894.iso / vrac / mikmod43.zip / MIKMOD.C < prev    next >
C/C++ Source or Header  |  1994-04-30  |  9KB  |  432 lines

  1. /*
  2.     MIKMOD.C    Programmed by MikMak of Unicorn Design
  3. */
  4.  
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <dos.h>
  8. #include <string.h>
  9. #include <alloc.h>
  10. #include <conio.h>
  11. #include <ctype.h>
  12.  
  13. #include "modload.h"
  14. #include "modplay.h"
  15. #include "mytypes.h"
  16. #include "forte.h"
  17. #include "gf1proto.h"
  18. #include "extern.h"
  19. #include "ultraerr.h"
  20. #include "ultraext.h"
  21.  
  22. #include "wildfile.h"
  23. #include "getopt.h"
  24.  
  25. extern ULTRA_CFG config;
  26.  
  27. #define MAXHANDLE 31
  28.  
  29. /* this example only loads 1 module
  30.  at a time, so 31 handles are enough */
  31.  
  32. ULONG Ultra[MAXHANDLE];
  33.  
  34. /* Ultra[] holds the sample dram adresses
  35.    of the 31 samples of a module */
  36.  
  37.  
  38.  
  39. void SetBPM(int bpm)
  40. {
  41.     /* The player routine has to be called (bpm*50)/125 times a second,
  42.        so the interval between calls takes 125/(bpm*50) seconds (amazing!).
  43.  
  44.        The Timer1 handler has a resolution of 160 microseconds.
  45.  
  46.        So the timer value to program:
  47.  
  48.        (125/(bpm*50)) / 1.6e-4 = 15625/bpm
  49.     */
  50.  
  51.     UltraStartTimer(1,15625/bpm);
  52. }
  53.  
  54.  
  55.  
  56. #pragma argsused
  57.  
  58. void GusPlay(int voice,AUDTMP *aud,MODFILE *mf)
  59. /*
  60.     Callback routine for playing the samples on a GUS. (this routine is
  61.     called each tick, for each voice)
  62. */
  63. {
  64.     UWORD period,vol,frq;
  65.     ULONG base;
  66.  
  67.     /* get sample period and volume */
  68.  
  69.     period=aud->period;
  70.  
  71.     if(period<50)   period=50;        // limit the period value
  72.     if(period>1814) period=1814;
  73.  
  74.     vol=((UWORD)mp_mainvol*aud->volume)/0xd;
  75.     frq=3579546UL/period;
  76.  
  77.     // Check if the sample has to be restarted
  78.  
  79.     if(aud->kick){
  80.  
  81.         // Get sample dram address
  82.  
  83.         base=Ultra[aud->handle];
  84.  
  85.         /* When the previous sample still is active, ramp down the volume
  86.            and wait until the ramping is done */
  87.  
  88.         if (!UltraVoiceStopped(voice)) {
  89.             UltraVectorLinearVolume(voice,0,0x3f,0);
  90.             while (!UltraVolumeStopped(voice)) ;
  91.             UltraStopVoice(voice);
  92.         }
  93.  
  94.         UltraSetFrequency(voice,frq);
  95.  
  96.         if(aud->loop<aud->size){
  97.  
  98.             // Start a looping sample
  99.  
  100.             UltraStartVoice(voice,
  101.                             base+aud->start,
  102.                             base+aud->loop,
  103.                             base+aud->size,0x8);
  104.         }
  105.         else{
  106.  
  107.             // Start a one-shot sample
  108.  
  109.             UltraStartVoice(voice,
  110.                             base+aud->start,
  111.                             base+aud->start,
  112.                             base+aud->size,0);
  113.         }
  114.         aud->kick=0;
  115.     }
  116.     else{
  117.         /* Voice doesn't have to be restarted, so
  118.            just update the period */
  119.  
  120.         UltraSetFrequency(voice,frq);
  121.     }
  122.  
  123.     // and update volume
  124.  
  125.     UltraVectorLinearVolume(voice,vol,0x3f,0);
  126. }
  127.  
  128.  
  129.  
  130.  
  131. void HandleTimer1()
  132. {
  133.     static int odd=0;
  134.  
  135.     /* Do not service the odd calls to this handler .. This
  136.        effectively makes this a 2*80=160 microsecond handler */
  137.  
  138.     if(odd^=1) return;
  139.  
  140.     MP_HandleTick();    // Call the player routine
  141.     SetBPM(mp_bpm);        // Update beats-per-minute
  142. }
  143.  
  144.  
  145.  
  146.  
  147.  
  148.  
  149. int GusLoad(FILE *fp,SAMPLEINFO *smp)
  150. /*
  151.     callback routine for the MODLOAD module.
  152.  
  153.     fp            :file ptr to that sample
  154.     smp            :Sampleinfo of the sample that is being loaded.
  155.  
  156.     returns:    -1 on error
  157.                  or
  158.                 >=0 samplehandle
  159. */
  160. {
  161.     int handle;
  162.  
  163.     // Find empty slot to put sample address in
  164.  
  165.     for(handle=0;handle<MAXHANDLE;handle++){
  166.         if(Ultra[handle]==0) break;
  167.     }
  168.     if(handle==MAXHANDLE) return -1;
  169.  
  170.     // Allocate GUS dram and store the address in Ultra[handle]
  171.     // Alloc 1 byte more for anticlick measures. see below.
  172.  
  173.     if(UltraMemAlloc(smp->length+1,&Ultra[handle])!=ULTRA_OK)
  174.         return -1;
  175.  
  176.     // Load the sample
  177.  
  178.     if(UltraFileload(fp,DMA_8|DMA_NO_CVT,Ultra[handle],smp->length)==0)    return -1;
  179.  
  180.     if(smp->replen>2){    // looping sample ?
  181.  
  182.         /*    Anticlick for looping samples:
  183.             Copy the first byte in the loop
  184.             one place beyond the end of the loop */
  185.  
  186.         UltraPoke(Ultra[handle]+smp->reppos+smp->replen,
  187.                   UltraPeek(Ultra[handle]+smp->reppos));
  188.     }
  189.     else{
  190.  
  191.         /*     Anticlick for one-shot samples:
  192.             Zero the byte beyond the end of the sample.
  193.         */
  194.  
  195.         UltraPoke(Ultra[handle]+smp->length,0);
  196.     }
  197.     return handle;
  198. }
  199.  
  200.  
  201.  
  202. void GusUnLoad(int handle,SAMPLEINFO *smp)
  203. /*
  204.     callback routine to unload samples
  205.  
  206.     handle        :Sample-handle that is being freed
  207.     smp            :sampleinfo of sample that is being freed
  208. */
  209. {
  210.     UltraMemFree(smp->length+1,Ultra[handle]);
  211.     Ultra[handle]=0;
  212. }
  213.  
  214.  
  215. int PlayModule(char *file)
  216. {
  217.     char c;
  218.     int t;
  219.     MODFILE *mf;
  220.  
  221.     printf("\nFile      : %s\n",file);
  222.  
  223.     if((mf=ML_Open(file,NULL))==NULL){
  224.         printf("MikMod Error: %s\n",ML_Error());
  225.         return 0;
  226.     }
  227.  
  228.     printf("Title     : %s\n"
  229.            "ModType   : %s %d channels\n"
  230.            "Patterns  : %d\n"
  231.            "Songlength: %d\n",
  232.            mf->songname,
  233.            mf->modtype,
  234.            mf->numchn,
  235.            mf->numpat,
  236.            mf->songlength);
  237.  
  238.     if(!ML_Load(mf)){
  239.         printf("MikMod Error: %s\n",ML_Error());
  240.         ML_Free(mf);
  241.         return 0;
  242.     }
  243.  
  244.     MP_Init(mf);
  245.  
  246.     for(t=0;t<mf->numchn;t++) UltraSetBalance(t,7+t-(mf->numchn>>1));
  247.  
  248.     // Let's make some noise !
  249.  
  250.     UltraEnableOutput();
  251.     delay(30);
  252.     SetBPM(125);            // Kickstart the timer
  253.  
  254.     puts("Press space to continue, ESC to quit..");
  255.  
  256.     // You might want to do something more useful here
  257.  
  258.     do c=getch(); while(c!=' ' && c!=0x1b);
  259.  
  260.     UltraStopTimer(1);
  261.     for(t=0;t<mf->numchn;t++) UltraVoiceOff(t,0);
  262.  
  263.     UltraDisableOutput();
  264.  
  265.     ML_Free(mf);
  266.  
  267.     return(c!=0x1b);
  268. }
  269.  
  270.  
  271.  
  272. int PlayWildModule(char *wildname)
  273. /*
  274.     Plays all modules that correspond to the wildcard filename 'wildname'
  275. */
  276. {
  277.     int ok;
  278.     char *name;
  279.  
  280.     if((name=GetFirstName(wildname))==NULL){
  281.         printf("Could not find %s\n",wildname);
  282.         return 0;
  283.     }
  284.     do{
  285.         ok=PlayModule(name);
  286.     } while(ok && (name=GetNextName())!=NULL);
  287.  
  288.     return ok;
  289. }
  290.  
  291.  
  292. int breakhandler(void)
  293. {
  294.     return 1;
  295. }
  296.  
  297.  
  298.  
  299. int main(int argc,char *argv[])
  300. {
  301.     int t;
  302.     char opt,*arg;
  303.     int argcount=0;        // counts number of 'real' arguments
  304.     int cmderr=0;        // error in commandline flag
  305.     int morehelp=0;        // set if user wants more help
  306.  
  307.     printf("MIKMOD v0.43 or how to make a modplayer using the GUS SDK Toolkit v2.10\n"
  308.            "Programmed by MikMak of Unicorn Design. This is SOURCEWARE/PUBLIC DOMAIN\n"
  309.            "So you may use my routines as long as you mention my name :)\n"
  310.            "E-Mail: mikmak@stack.urc.tue.nl\n\n");
  311.  
  312.     /* init the option scanner to look
  313.      for the options /? /H /L /X and /V */
  314.  
  315.     InitOpt(argc,argv,"?hHlLxXv:V:");
  316.  
  317.     while((t=GetOpt(&opt,&arg))!=GO_EOF && !cmderr){
  318.  
  319.         switch(t){
  320.  
  321.             case GO_OPT:
  322.  
  323.                 switch(tolower(opt)){
  324.  
  325.                     case 'l':
  326.                         ML_Load15(1);
  327.                         break;
  328.  
  329.                     case 'x':
  330.                         MP_ExtSpd(0);
  331.                         break;
  332.  
  333.                     case 'v':
  334.                         MP_MainVol(atoi(arg));
  335.                         break;
  336.  
  337.                     case '?':
  338.                     case 'h':
  339.                         morehelp=1;
  340.                         cmderr=1;
  341.                         break;
  342.                 }
  343.                 break;
  344.  
  345.             case GO_ARG:
  346.                 argcount++;    // count the number of "real" arguments
  347.                 break;
  348.  
  349.             case GO_UNKNOWN_SWITCH:
  350.                 printf("\07Unknown switch - '%c'\n\n",opt);
  351.                 cmderr=1;
  352.                 break;
  353.  
  354.             case GO_SWITCH_NEEDS_ARG:
  355.                 printf("\07Switch needs an argument - '%c'\n\n",opt);
  356.                 cmderr=1;
  357.                 break;
  358.         }
  359.     }
  360.  
  361.     if(cmderr || argcount==0){
  362.  
  363.         puts("Usage: MIKMOD <fletch.mod> [spacedb.mod] ... [/X] [/L] [/Vxx] [/?] [/H]\n");
  364.  
  365.         if(morehelp)
  366.             puts("- /L   enables loading old 15-instrument modules\n"
  367.                  "- /X   disables protracker extended speed\n"
  368.                  "- /Vxx Sets volume from 0 (silence) to 100 (mayhem). Default=80\n"
  369.                  "- Wildcards are allowed\n"
  370.                  "- Options can be placed anywhere on the commandline\n"
  371.                  "- Options can be combined behind a single switch char: /XV 100\n\n"
  372.                  "Examples:\n\n"
  373.                  "MIKMOD teardrop.mod /L /V50\tPlays 15-instr. module at 50% volume\n"
  374.                  "MIKMOD /X klisjepa.mod /V100\tPlays klisjepa.mod without ext. spd at max vol.\n"
  375.                  "MIKMOD x*.mod y*.mod \t\tPlays all modules starting with 'x' and 'y'\n");
  376.         else
  377.             puts("Type MIKMOD /? or MIKMOD /h for more help.");
  378.  
  379.         return -1;
  380.     }
  381.  
  382.     /* disable control-break by
  383.        installing a custom handler */
  384.  
  385.     ctrlbrk(breakhandler);
  386.  
  387.     /* Get the ULTRASND environment string parameters */
  388.  
  389.     if(!UltraGetCfg(&config)){
  390.         puts("Ultrasound env. string not found..");
  391.         return -1;
  392.     }
  393.  
  394.     /* Set up 14 channels */
  395.  
  396.     if(UltraOpen(&config,14)==NO_ULTRA){
  397.         puts("No ultrasound card found");
  398.         return -1;
  399.     }
  400.  
  401.     /* Report size of GUS DRAM */
  402.  
  403.     printf("This GUS has %dK of Dram\n",UltraSizeDram());
  404.  
  405.     /* Grab the 80 microsecond timer handler */
  406.  
  407.     UltraTimer1Handler(HandleTimer1);
  408.  
  409.     /* Make MODLOAD and MODPLAY use the gus-
  410.       specific load,unload and play routines */
  411.  
  412.     ML_RegisterLoader(GusLoad);
  413.     ML_RegisterUnLoader(GusUnLoad);
  414.     MP_RegisterPlayer(GusPlay);
  415.  
  416.  
  417.     /* Then try to load and play each module yeah */
  418.  
  419.     InitOpt(argc,argv,"?hHlLxXv:V:");
  420.  
  421.     while((t=GetOpt(&opt,&arg))!=GO_EOF){
  422.         if(t==GO_ARG){
  423.             if(!PlayWildModule(arg)) break;
  424.         }
  425.     }
  426.  
  427.     /* Shut sound down & re-init hardware ... */
  428.  
  429.     UltraClose();
  430.     return 0;
  431. }
  432.