home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 561a.lha / DSound_v0.91a / DSound.c < prev    next >
C/C++ Source or Header  |  1991-09-18  |  12KB  |  533 lines

  1.  
  2. /**************************************************************************/
  3. /*                 DSound V0.91a                  */
  4. /*     Copyright 1991 by Dave Schreiber, All Rights Reserved          */
  5. /*                                      */
  6. /* To compile:                                  */
  7. /*    lc -Lcd -v DSound                           */
  8. /*                                      */
  9. /* Revision history:                              */
  10. /*    V0.91a - First release (September 11, 1991)                         */
  11. /**************************************************************************/
  12.  
  13. #include <exec/types.h>
  14. #include <exec/exec.h>
  15. #include <devices/audio.h>
  16. #include <dos/dos.h>
  17. #include <intuition/intuition.h>
  18. #include <intuition/intuitionbase.h>
  19. #include <graphics/gfxbase.h>
  20. #include "dsound.h"
  21.  
  22. #include <clib/intuition_protos.h>
  23. #include <clib/exec_protos.h>
  24.  
  25. UBYTE rightAMap[]={2,4};
  26. UBYTE leftAMap[]={1,8};
  27. UBYTE eitherAMap[]={1,2,4,8};
  28. UBYTE *allocationMap=eitherAMap;
  29. char filename[140];
  30.  
  31. #define BUF_SIZE 30000
  32.  
  33. void InterpretArgs(int argc,char *argv[]);
  34. BOOL noFilter=FALSE;
  35. UBYTE volume=0;
  36. UWORD speed=0;
  37. ULONG bufSize=BUF_SIZE;
  38.  
  39. void filter_on(void);
  40. void filter_off(void);
  41.  
  42. char *version="$VER: DSound V0.91a (11.9.91)";
  43. char *copyright="Copyright 1991 by Dave Schreiber, All Rights Reserved";
  44.  
  45. struct IntuitionBase *IntuitionBase=NULL;
  46. struct GfxBase *GfxBase=NULL;
  47.  
  48. struct Window *window=NULL;
  49.  
  50. struct NewWindow newWindow=
  51. {
  52.    100,50,300,10,-1,-1,CLOSEWINDOW,WINDOWCLOSE|WINDOWDRAG|WINDOWDEPTH,
  53.    NULL,NULL,"<-- Click to stop (DSound V0.91)",NULL,NULL,1,1,1000,1000,
  54.    WBENCHSCREEN
  55. };
  56.  
  57. BPTR file=NULL;
  58.  
  59. main(int argc,char *argv[])
  60. {
  61.    struct IOAudio *iob1,*iob2;
  62.    struct Voice8Header vhdr;
  63.    UBYTE foo2[5];
  64.    ULONG len;
  65.    ULONG toRead;
  66.    BOOL done=FALSE;
  67.  
  68.    filename[0]=NULL;
  69.  
  70.    GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",0L);
  71.  
  72.    IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",0L);
  73.  
  74.    if(GfxBase==NULL || IntuitionBase==NULL)
  75.       cleanup(50);
  76.  
  77.    InterpretArgs(argc,argv);
  78.  
  79.    if(filename[0]==NULL)
  80.    {
  81.       WriteMsg("Please specify a filename\n");
  82.       cleanup(75);
  83.    }
  84.  
  85.    /*Open the file*/
  86.    file=Open(filename,MODE_OLDFILE);
  87.    if(file==NULL)
  88.    {
  89.       WriteMsg("Couldn't open the file\n");
  90.       cleanup(100);
  91.    }
  92.  
  93.    newWindow.Height=IntuitionBase->ActiveScreen->Font->ta_YSize+3;
  94.  
  95.    window=OpenWindow(&newWindow);
  96.  
  97.    if(window==NULL)
  98.       cleanup(110);
  99.  
  100.    /*Read the header*/
  101.    Position(file,"VHDR");
  102.    Read(file,foo2,4);
  103.    Read(file,&vhdr,sizeof(struct Voice8Header));
  104.  
  105.    /*Check for compression*/
  106.    if(vhdr.sCompression!=0)
  107.    {
  108.       WriteMsg("The sound sample is compressed\n");
  109.       cleanup(400);
  110.    }
  111.  
  112.    /*Find the BODY*/
  113.    Position(file,"BODY");
  114.    Read(file,foo2,4);
  115.  
  116.    /*Get the length of the sample*/
  117.    len=vhdr.oneShotHiSamples;
  118.  
  119.    /*Get the first audio channel*/
  120.    iob1=GetAudioChannel(bufSize);
  121.    if(iob1==NULL)
  122.    {
  123.       WriteMsg("Couldn't create the first buffer\n");
  124.       cleanup(150);
  125.    }
  126.  
  127.    /* If the user didn't specify a volume, get it from the VHDR */
  128.    if(volume==0)
  129.       volume=(vhdr.volume>>10);
  130.  
  131.    /* If the VHDR gave a volume of zero, use maximum volume*/
  132.    if(volume==0)
  133.       volume=64;
  134.  
  135.    /* Get the samples/sec rate (either the rate given by the user, or the*/
  136.    /* rate found in the VHDR) */
  137.    if(speed==0)
  138.       speed=1000000000/(vhdr.samplesPerSec*279);
  139.    else
  140.       speed=1000000000/(speed*279);
  141.  
  142.    InitAudioChannel(iob1,volume,speed);
  143.  
  144.    /*Get the 2nd audio channel*/
  145.    iob2=DuplicateAudioChannel(iob1);
  146.  
  147.    if(iob2==NULL)
  148.    {
  149.       FreeAudioChannel(iob1);
  150.       WriteMsg("Couldn't create the second buffer");
  151.       cleanup(175);
  152.    }
  153.  
  154.    /* Load the first buffer*/
  155.    toRead=MIN(len,bufSize);
  156.    LoadAudioBuffer(file,iob1,toRead);
  157.    len-=toRead;
  158.    iob1->ioa_Length=toRead;
  159.  
  160.    /* Make sure there's enough data so that we have something to put in */
  161.    /* the second buffer */
  162.    if(len!=0)
  163.    {
  164.       toRead=MIN(len,bufSize);
  165.       LoadAudioBuffer(file,iob2,toRead);
  166.       len-=toRead;
  167.       iob2->ioa_Length=toRead;
  168.    }
  169.    else
  170.       /* It appears that the entire sound sample is small enough to */
  171.       /* fit into the first buffer, so don't play the second */
  172.       iob2->ioa_Length=0;
  173.  
  174.    /*Switch off the filter, if necessary */
  175.    if(noFilter)
  176.       filter_off();
  177.  
  178.    /*And queue up the play requests*/
  179.    BeginIO((struct ioRequest *)iob1);
  180.    if(iob2->ioa_Length!=0)
  181.       BeginIO((struct ioRequest *)iob2);
  182.  
  183.    /* If the sound sample was small enough to fit into the two buffers, */
  184.    /* play them then finish up */
  185.    if(len==0 || GetMsg(window->UserPort)!=NULL)
  186.    {
  187.       WaitIO((struct ioRequest *)iob1);
  188.       if(iob2->ioa_Length!=0)
  189.      WaitIO((struct ioRequest *)iob2);
  190.       done=TRUE;
  191.    }
  192.    /*Otherwise, play those samples then read more from disk*/
  193.  
  194.    /*Loop while there's stuff to read*/
  195.    while(!done)
  196.    {
  197.       /*Fill the first buffer*/
  198.       WaitIO((struct ioRequest *)iob1);
  199.  
  200.       toRead=MIN(len,bufSize);
  201.  
  202.       if(toRead==0 || GetMsg(window->UserPort)!=NULL)
  203.       {
  204.      /*If there's no stuff left to read, wait 'till the second buffer*/
  205.      /*finishes, then quit*/
  206.      WaitIO((struct ioRequest *)iob2);
  207.      done=TRUE;
  208.      break;
  209.       }
  210.  
  211.       LoadAudioBuffer(file,iob1,toRead);
  212.       len-=toRead;
  213.  
  214.       /*Play the first buffer*/
  215.       BeginIO((struct ioRequest *)iob1);
  216.  
  217.       /*Wait for the second buffer to finish*/
  218.       WaitIO((struct ioRequest *)iob2);
  219.  
  220.       toRead=MIN(len,bufSize);
  221.  
  222.       if(toRead==0 || GetMsg(window->UserPort)!=NULL)
  223.       {
  224.      /*If there's no stuff left to read, wait 'till the first buffer*/
  225.      /*finishes, then quit*/
  226.      WaitIO((struct ioRequest *)iob1);
  227.      done=TRUE;
  228.      break;
  229.       }
  230.  
  231.       /*Reload it*/
  232.       LoadAudioBuffer(file,iob2,toRead);
  233.       len-=toRead;
  234.  
  235.       /*Play it*/
  236.       BeginIO((struct ioRequest *)iob2);
  237.    }
  238.  
  239.    /*Switch the filter off if it was switched off*/
  240.    if(noFilter)
  241.       filter_on();
  242.  
  243.    /*Restore the buffer lengths, so that FreeAudio() channel, etc., knows*/
  244.    /*how much memory to free*/
  245.    iob1->ioa_Length=iob2->ioa_Length=bufSize;
  246.    FreeAudioChannel(iob1);
  247.    DeleteDuplication(iob2);
  248.  
  249.    /*Free allocated resources and exit*/
  250.    cleanup(0);
  251. }
  252.  
  253.  
  254. // Get an audio channel
  255. struct IOAudio *GetAudioChannel(ULONG bufferSize)
  256. {
  257.    struct IOAudio *aIOB;
  258.    void *audioBuf;
  259.    struct Port *aPort;
  260.  
  261.    aPort=(struct Port *)CreatePort("dsound",0);
  262.    if(aPort==NULL)
  263.       return(NULL);
  264.  
  265.    /* Allocate the chip memory buffer for the channel */
  266.    audioBuf=(void *)AllocMem(bufferSize,MEMF_CHIP);
  267.    if(audioBuf==NULL)
  268.    {
  269.       DeletePort(aPort);
  270.       return(NULL);
  271.    }
  272.  
  273.    /* Allocate an IOAudio structure*/
  274.    aIOB=(struct IOAudio *)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR);
  275.    if(aIOB==NULL)
  276.    {
  277.       DeletePort(aPort);
  278.       FreeMem(audioBuf,bufferSize);
  279.       return(NULL);
  280.    }
  281.  
  282.    /* Set up the IOAudio to allocate the command channel */
  283.    aIOB->ioa_Request.io_Message.mn_Node.ln_Pri=0;
  284.    aIOB->ioa_Request.io_Message.mn_ReplyPort=aPort;
  285.  
  286.    aIOB->ioa_Data=allocationMap;
  287.    aIOB->ioa_Length=2;
  288.    aIOB->ioa_Request.io_Command=ADCMD_ALLOCATE;
  289.  
  290.    OpenDevice("audio.device",0,(struct ioRequest *)aIOB,0);
  291.    if(aIOB->ioa_AllocKey==0)
  292.    {
  293.       DeletePort(aPort);
  294.       FreeMem(audioBuf,bufferSize);
  295.       FreeMem(aIOB,sizeof(struct IOAudio));
  296.       return(NULL);
  297.    }
  298.    else
  299.    {
  300.       /* Set up the IOAudio for writes */
  301.       aIOB->ioa_Request.io_Command=CMD_WRITE;
  302.       aIOB->ioa_Request.io_Flags=ADIOF_PERVOL;
  303.       aIOB->ioa_Data=audioBuf;
  304.       aIOB->ioa_Length=bufferSize;
  305.       return(aIOB);
  306.    }
  307. }
  308.  
  309. /* Free an allocated audio channel */
  310. void FreeAudioChannel(struct IOAudio *aIOB)
  311. {
  312.    if(aIOB==NULL)
  313.       return;
  314.  
  315.    /* Free the audi obuffer */
  316.    if(aIOB->ioa_Data!=NULL)
  317.       FreeMem(aIOB->ioa_Data,aIOB->ioa_Length);
  318.  
  319.    /* Free the audio channel */
  320.    aIOB->ioa_Request.io_Command=ADCMD_FREE;
  321.    BeginIO((struct ioRequest *)aIOB);
  322.    WaitIO((struct ioRequest *)aIOB);
  323.    DeletePort(aIOB->ioa_Request.io_Message.mn_ReplyPort);
  324.  
  325.    /* Close the audio channel */
  326.    CloseDevice((struct ioRequest *)aIOB);
  327.  
  328.    /* Free the IOAudio structure */
  329.    FreeMem(aIOB,sizeof(struct IOAudio));
  330.    return;
  331. }
  332.  
  333. /* Initialize an IOAudio's volume, period, and set the number of cycles */
  334. /* to one */
  335. void InitAudioChannel(struct IOAudio *aIOB,UWORD volume,UWORD period)
  336. {
  337.    aIOB->ioa_Period=period;
  338.    aIOB->ioa_Volume=volume;
  339.    aIOB->ioa_Cycles=1;
  340.    return;
  341. }
  342.  
  343. /* Duplicate an IOAudio structure */
  344. struct IOAudio *DuplicateAudioChannel(struct IOAudio *OrigIOB)
  345. {
  346.    struct IOAudio *aIOB;
  347.    void *audioBuf;
  348.  
  349.    if(OrigIOB==NULL)
  350.       return(NULL);
  351.  
  352.    /* Allocate the alternate buffer */
  353.    audioBuf=(void *)AllocMem(OrigIOB->ioa_Length,MEMF_CHIP);
  354.    if(audioBuf==NULL)
  355.       return(NULL);
  356.  
  357.    /*Allocate the IOAudio structure*/
  358.    aIOB=(struct IOAudio *)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR);
  359.    if(aIOB==NULL)
  360.    {
  361.       FreeMem(audioBuf,OrigIOB->ioa_Length);
  362.       return(NULL);
  363.    }
  364.  
  365.    /*Copy the original IOAudio's contents to the new one*/
  366.    CopyMem(OrigIOB,aIOB,sizeof(struct IOAudio));
  367.  
  368.    /*Except for the buffer pointer, of course*/
  369.    aIOB->ioa_Data=audioBuf;
  370.  
  371.    return(aIOB);
  372. }
  373.  
  374. /*Delete a duplicated IOAudio*/
  375. void DeleteDuplication(struct IOAudio *aIOB)
  376. {
  377.    if(aIOB != NULL)
  378.    {
  379.       /* Free the memory for the buffer and IOAudio */
  380.       if(aIOB->ioa_Data != NULL)
  381.      FreeMem(aIOB->ioa_Data,aIOB->ioa_Length);
  382.       FreeMem(aIOB,sizeof(struct IOAudio));
  383.    }
  384.    return;
  385. }
  386.  
  387. /* Load an IOAudio's buffer from an open file */
  388. ULONG LoadAudioBuffer(BPTR file,struct IOAudio *aIOB,ULONG toRead)
  389. {
  390.    if(toRead==0)
  391.       return(0);
  392.    aIOB->ioa_Length=Read(file,aIOB->ioa_Data,toRead);
  393.    return(aIOB->ioa_Length);
  394. }
  395.  
  396. /* Seek forward in a file until the given string is found (useful for */
  397. /* finding chunk in IFF files */
  398. void Position(BPTR file,char *string)
  399. {
  400.    UBYTE len;
  401.    char chr;
  402.    UBYTE i;
  403.  
  404.    len=strlen(string);
  405.  
  406.    for(;;)
  407.    {
  408.       Read(file,&chr,1);
  409.       if(chr==string[0])
  410.       {
  411.      Read(file,&chr,1);
  412.      for(i=1;i<4 && string[i]==chr;i++)
  413.      {
  414.         if(i!=3)
  415.            Read(file,&chr,1);
  416.      }
  417.      if(i==4)
  418.         return;
  419.       }
  420.    }
  421. }
  422.  
  423.  
  424. /* Interpret the command line arguments */
  425. void InterpretArgs(int argc,char *argv[])
  426. {
  427.    int i;
  428.  
  429.    for(i=1;i<argc;i++)
  430.    {
  431.       if(argv[i][0]=='-')
  432.      switch(argv[i][1])
  433.      {
  434.         /* Use the left channel */
  435.         case 'l':
  436.         case 'L':
  437.            allocationMap=leftAMap;
  438.            break;
  439.  
  440.         /* Use the right channel */
  441.         case 'r':
  442.         case 'R':
  443.            allocationMap=rightAMap;
  444.            break;
  445.  
  446.         /* Switch off the low-pass filter while the sample is playing */
  447.         case 'f':
  448.         case 'F':
  449.            noFilter=TRUE;
  450.            break;
  451.  
  452.         /* Play a sample at a given speed */
  453.         case 's':
  454.         case 'S':
  455.            speed=atol(&argv[i][2]);
  456.            if(speed > 28000)
  457.           speed=0;
  458.            break;
  459.  
  460.         /* The volume at which the sample should be played */
  461.         case 'v':
  462.         case 'V':
  463.            volume=atol(&argv[i][2]);
  464.            if(volume > 64)
  465.           volume=0;
  466.            break;
  467.  
  468.         /* The size of the chip RAM buffers */
  469.         case 'b':
  470.         case 'B':
  471.            bufSize=(atol(&argv[i][2])+1)&(~1);
  472.            if(bufSize==0)
  473.           bufSize=BUF_SIZE;
  474.            break;
  475.      }
  476.       else if(argv[i][0]=='?')
  477.       {
  478.      /*On-line help*/
  479.      WriteMsg("DSound V0.91a ©1991 by Dave Schreiber\n");
  480.      WriteMsg("Usage:\m");
  481.      WriteMsg("  DSound <options> <filename>\n");
  482.      WriteMsg("Where the options are:\n");
  483.      WriteMsg("  -l -- Play the sample using the left speaker\n");
  484.      WriteMsg("  -r -- Play the sample using the right speaker\n");
  485.      WriteMsg("  -f -- Shut off the low-pass filter\n");
  486.      WriteMsg("  -s<speed> -- Play the sample at the given speed (samples/sec)\n");
  487.      WriteMsg("  -v<volume> -- Play the sample at the given volume (0-64)\n");
  488.      WriteMsg("  -b<bufsize> -- Use a buffer of size <bufsize> (default is 30K)\n");
  489.      exit(0);
  490.       }
  491.       else     /*Otherwise, the argument is a filename */
  492.      strcpy(filename,argv[i]);
  493.    }
  494. }
  495.  
  496. /*Switch on the low-pass filter */
  497. void filter_on()
  498. {
  499.    *((char *)0x0bfe001)&=0xFD;
  500. }
  501.  
  502. /*Switch off the low-pass filter*/
  503. void filter_off()
  504. {
  505.    *((char *)0x0bfe001)|=0x02;
  506. }
  507.  
  508. /*Write a message to the CLI*/
  509. void WriteMsg(char *errMsg)
  510. {
  511.    Write(Output(),errMsg,strlen(errMsg));
  512. }
  513.  
  514. /* Free allocated resources */
  515. void cleanup(int err)
  516. {
  517.    if(file!=NULL)
  518.       Close(file);
  519.  
  520.    if(window!=NULL)
  521.       CloseWindow(window);
  522.  
  523.    if(GfxBase!=NULL)
  524.       CloseLibrary((struct Library *)GfxBase);
  525.  
  526.    if(IntuitionBase!=NULL)
  527.       CloseLibrary((struct Library *)IntuitionBase);
  528.  
  529.    exit(err);
  530. }
  531.  
  532.  
  533.