home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 1.2 / amidev_cd_12.iso / reference_library / devices / dev_examples / audio_8svx.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-20  |  12.3 KB  |  490 lines

  1. /*
  2.  * Audio_8SVX.c
  3.  *
  4.  * 8SVX example - double buffers >128K samples
  5.  *
  6.  * Compile with SAS C 5.10  lc -b1 -cfistq -v -y -L
  7.  *
  8.  * Run from CLI only
  9.  */
  10.  
  11. #include <exec/types.h>
  12. #include <exec/memory.h>
  13. #include <devices/audio.h>
  14. #include <dos/dos.h>
  15. #include <dos/dosextens.h>
  16. #include <graphics/gfxbase.h>
  17. #include <iff/iff.h>
  18. #include <iff/8svx.h>
  19.  
  20. #include <clib/exec_protos.h>
  21. #include <clib/alib_protos.h>
  22. #include <clib/dos_protos.h>
  23. #include <clib/graphics_protos.h>
  24.  
  25. #include <stdlib.h>
  26. #include <stdio.h>
  27.  
  28. #ifdef LATTICE
  29. int CXBRK(void) { return(0); }     /* Disable SAS CTRL/C handling */
  30. int chkabort(void) { return(0); }  /* really */
  31. #endif
  32.  
  33. #define VHDR MakeID('V','H','D','R')
  34. #define BODY MakeID('B','O','D','Y')
  35. #define MY8S MakeID('8','S','V','X')
  36.  
  37. void              kill8svx(char *);
  38. void              kill8(void);
  39.  
  40. /*--------------------*/              /* These globals are needed */
  41. /*   G L O B A L S    */              /* by the clean up routines */
  42. /*--------------------*/
  43. struct IOAudio     *AIOptr1,          /* Pointers to Audio IOBs      */
  44.                    *AIOptr2,
  45.                    *Aptr;
  46. struct Message     *msg;              /* Msg, port and device for    */
  47. struct MsgPort     *port,             /* driving audio               */
  48.                    *port1,*port2;
  49.        ULONG        device;
  50.        UBYTE       *sbase,*fbase;     /* For sample memory allocation */
  51.        ULONG        fsize,ssize;      /* and freeing                  */
  52.  
  53. struct FileHandle  *v8handle;
  54.        UBYTE        chan1[]  = {  1 };/* Audio channel allocation arrays */
  55.        UBYTE        chan2[]  = {  2 };
  56.        UBYTE        chan3[]  = {  4 };
  57.        UBYTE        chan4[]  = {  8 };
  58.        UBYTE       *chans[] = {chan1,chan2,chan3,chan4};
  59.  
  60.        BYTE         oldpri,c;         /* Stuff for bumping priority */
  61.  
  62. struct Task        *mt=0L;
  63. struct GfxBase     *GfxBase = NULL;
  64.  
  65.  
  66. /*-----------*/
  67. /*  M A I N  */
  68. /*-----------*/
  69.  
  70. void main(int argc,char **argv)
  71. {
  72.  
  73. /*-------------*/
  74. /* L O C A L S */
  75. /*-------------*/
  76.  
  77.        char         *fname;               /* File name and data pointer*/
  78.        UBYTE        *p8data;              /* for file read.            */
  79.        ULONG         clock;               /* Clock constant            */
  80.        ULONG         length[2];           /* Sample lengths            */
  81.        BYTE          iobuffer[8],         /* Buffer for 8SVX header    */
  82.                     *psample[2];          /* Sample pointers           */
  83.        Chunk        *p8Chunk;             /* Pointers for 8SVX parsing */
  84.        Voice8Header *pVoice8Header;
  85.        ULONG         y,rd8count,speed;    /* Counters, sampling speed  */
  86.        ULONG         wakebit;             /* A wakeup mask             */
  87.  
  88. /*-------------*/
  89. /*   C O D E   */
  90. /*-------------*/
  91.  
  92. /*------------------------------*/
  93. /* Check Arguments, Initialize  */
  94. /*------------------------------*/
  95.  
  96. fbase=0L;
  97. sbase=0L;
  98. AIOptr1=0L;
  99. AIOptr2=0L;
  100. port=0L;
  101. port1=0L;
  102. port2=0L;
  103. v8handle=0L;
  104. device=1L;
  105.  
  106. if (argc < 2)
  107.     {
  108.     kill8svx("No file name given.\n");
  109.     exit(1L);
  110.     }
  111. fname=argv[1];
  112.  
  113. /*---------------------------*/
  114. /* Initialize Clock Constant */
  115. /*---------------------------*/
  116.  
  117. GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",0L);
  118. if (GfxBase==0L)
  119.     {
  120.     puts("Can't open graphics library\n");
  121.     exit(1L);
  122.     }
  123.  
  124. if (GfxBase->DisplayFlags & PAL)
  125.     clock=3546895L;        /* PAL clock */
  126. else
  127.     clock=3579545L;        /* NTSC clock */
  128.  
  129. if (GfxBase)
  130.     CloseLibrary( (struct Library *) GfxBase);
  131.  
  132. /*---------------*/
  133. /* Open the File */
  134. /*---------------*/
  135.  
  136. v8handle= (struct FileHandle *) Open(fname,MODE_OLDFILE);
  137. if (v8handle==0)
  138.     {
  139.     kill8svx("Can't open 8SVX file.\n");
  140.     exit(1L);
  141.     }
  142.  
  143. /*-------------------------------------------*/
  144. /* Read the 1st 8 Bytes of the File for Size */
  145. /*-------------------------------------------*/
  146. rd8count=Read((BPTR)v8handle,iobuffer,8L);
  147. if (rd8count==-1)
  148.     {
  149.     kill8svx ("Read error.\n");
  150.     exit(1L);
  151.     }
  152.  
  153. if (rd8count<8)
  154.     {
  155.     kill8svx ("Not an IFF 8SVX file, too short\n");
  156.     exit(1L);
  157.     }
  158.  
  159. /*-----------------*/
  160. /* Evaluate Header */
  161. /*-----------------*/
  162. p8Chunk=(Chunk *)iobuffer;
  163. if (p8Chunk->ckID != FORM )
  164.     {
  165.     kill8svx("Not an IFF FORM.\n");
  166.     exit(1L);
  167.     }
  168.  
  169. /*--------------------------------------------*/
  170. /* Allocate Memory for File and Read it in.   */
  171. /*--------------------------------------------*/
  172. fbase= (UBYTE *)AllocMem(fsize=p8Chunk->ckSize , MEMF_PUBLIC|MEMF_CLEAR);
  173. if (fbase==0)
  174.     {
  175.     kill8svx("No memory for read.\n");
  176.     exit(1L);
  177.     }
  178.  
  179. p8data=fbase;
  180.  
  181. rd8count=Read((BPTR)v8handle,p8data,p8Chunk->ckSize);
  182. if (rd8count==-1)
  183.     {
  184.     kill8svx ("Read error.\n");
  185.     exit(1L);
  186.     }
  187.  
  188. if (rd8count<p8Chunk->ckSize)
  189.     {
  190.     kill8svx ("Malformed IFF, too short.\n");
  191.     exit(1L);
  192.     }
  193.  
  194. /*-------------------*/
  195. /* Evaluate IFF Type */
  196. /*-------------------*/
  197. if (MakeID( *p8data, *(p8data+1) , *(p8data+2) , *(p8data+3) ) != MY8S )
  198.     {
  199.     kill8svx("Not an IFF 8SVX file.\n");
  200.     exit(1L);
  201.     }
  202.  
  203. /*----------------------*/
  204. /* Evaluate 8SVX Chunks */
  205. /*----------------------*/
  206. p8data=p8data+4;
  207.  
  208. while( p8data < fbase+fsize )
  209.   {
  210.   p8Chunk=(Chunk *)p8data;
  211.  
  212.   switch(p8Chunk->ckID)
  213.     {
  214.     case VHDR:
  215.       /*------------------------------------------------*/
  216.       /* Get a pointer to the 8SVX header for later use */
  217.       /*------------------------------------------------*/
  218.       pVoice8Header=(Voice8Header *)(p8data+8L);
  219.       break;
  220.  
  221.     case BODY:
  222.       /*-------------------------------------------------*/
  223.       /* Create pointers to 1-shot and continuous parts  */
  224.       /* for the top octave and get length. Store them.  */
  225.       /*-------------------------------------------------*/
  226.         psample[0] = (BYTE *)(p8data + 8L);
  227.         psample[1] = psample[0] + pVoice8Header->oneShotHiSamples;
  228.         length[0] = (ULONG)pVoice8Header->oneShotHiSamples;
  229.         length[1] = (ULONG)pVoice8Header->repeatHiSamples;
  230.         break;
  231.  
  232.     default:
  233.       break;
  234.     }
  235.     /* end switch */
  236.  
  237.   p8data = p8data + 8L + p8Chunk->ckSize;
  238.  
  239.   if (p8Chunk->ckSize&1L == 1)
  240.       p8data++;
  241.   }
  242.  
  243. /* Play either the one-shot or continuous, not both */
  244. if (length[0]==0)
  245.     y=1;
  246. else
  247.     y=0;
  248.  
  249. /*---------------------------------------*/
  250. /* Allocate chip memory for samples and  */
  251. /* copy from read buffer to chip memory. */
  252. /*---------------------------------------*/
  253. if (length[y]<=102400)
  254.     ssize=length[y];
  255. else
  256.     ssize=102400;
  257.  
  258. sbase=(UBYTE *)AllocMem( ssize , MEMF_CHIP | MEMF_CLEAR);
  259. if (sbase==0)
  260.     {
  261.     kill8svx("No chip memory.\n");
  262.     exit(1L);
  263.     }
  264.  
  265. CopyMem(psample[y],sbase,ssize);
  266. psample[y]+=ssize;
  267.  
  268. /*----------------------------------*/
  269. /* Calculate playback sampling rate */
  270. /*----------------------------------*/
  271. speed =  clock / pVoice8Header->samplesPerSec;
  272.  
  273. /*-------------------*/
  274. /* Bump our priority */
  275. /*-------------------*/
  276. mt=FindTask(NULL);
  277. oldpri=SetTaskPri(mt,21);
  278.  
  279. /*--------------------------------*/
  280. /* Allocate two audio I/O blocks  */
  281. /*--------------------------------*/
  282. AIOptr1=(struct IOAudio *)
  283.       AllocMem( sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR);
  284. if (AIOptr1==0)
  285.     {
  286.     kill8svx("No IO memory\n");
  287.     exit(1L);
  288.     }
  289.  
  290. AIOptr2=(struct IOAudio *)
  291.       AllocMem( sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR);
  292. if (AIOptr2==0)
  293.     {
  294.     kill8svx("No IO memory\n");
  295.     exit(1L);
  296.     }
  297.  
  298. /*----------------------*/
  299. /* Make two reply ports */
  300. /*----------------------*/
  301.  
  302. port1=CreatePort(0,0);
  303. if (port1==0)
  304.     {
  305.     kill8svx("No port\n");
  306.     exit(1L);
  307.     }
  308.  
  309. port2=CreatePort(0,0);
  310. if (port2==0)
  311.     {
  312.     kill8svx("No port\n");
  313.     exit(1L);
  314.     }
  315.  
  316. c=0;
  317. while(device!=0 && c<4)
  318.   {
  319.   /*---------------------------------------*/
  320.   /* Set up audio I/O block for channel    */
  321.   /* allocation and Open the audio device  */
  322.   /*---------------------------------------*/
  323.   AIOptr1->ioa_Request.io_Message.mn_ReplyPort   = port1;
  324.   AIOptr1->ioa_Request.io_Message.mn_Node.ln_Pri = 127;  /* No stealing! */
  325.   AIOptr1->ioa_AllocKey                          = 0;
  326.   AIOptr1->ioa_Data                              = chans[c];
  327.   AIOptr1->ioa_Length                            = 1;
  328.  
  329.   device=OpenDevice(AUDIONAME,0L,(struct IORequest *)AIOptr1,0L);
  330.   c++;
  331.   }
  332.  
  333. if (device!=0)
  334.     {
  335.     kill8svx("No channel\n");
  336.     exit(1L);
  337.     }
  338.  
  339. /*-------------------------------------------*/
  340. /* Set Up Audio IO Blocks for Sample Playing */
  341. /*-------------------------------------------*/
  342.  
  343. AIOptr1->ioa_Request.io_Command   =CMD_WRITE;
  344. AIOptr1->ioa_Request.io_Flags     =ADIOF_PERVOL;
  345.  
  346. /*--------*/
  347. /* Volume */
  348. /*--------*/
  349.  
  350. AIOptr1->ioa_Volume=60;
  351.  
  352. /*---------------*/
  353. /* Period/Cycles */
  354. /*---------------*/
  355.  
  356. AIOptr1->ioa_Period =(UWORD)speed;
  357. AIOptr1->ioa_Cycles =1;
  358.  
  359. *AIOptr2 = *AIOptr1;   /* Make sure we have the same allocation keys, */
  360.                        /* same channels selected and same flags       */
  361.                        /* (but different ports...)                    */
  362.  
  363. AIOptr1->ioa_Request.io_Message.mn_ReplyPort   = port1;
  364. AIOptr2->ioa_Request.io_Message.mn_ReplyPort   = port2;
  365.  
  366. /*--------*/
  367. /*  Data  */
  368. /*--------*/
  369.  
  370. AIOptr1->ioa_Data            =(UBYTE *)sbase;
  371. AIOptr2->ioa_Data            =(UBYTE *)sbase + 51200;
  372.  
  373.  
  374. /*-----------------*/
  375. /*  Run the sample */
  376. /*-----------------*/
  377.  
  378. if (length[y]<=102400)
  379.     {
  380.     AIOptr1->ioa_Length=length[y];         /* No double buffering needed */
  381.     BeginIO((struct IORequest *)AIOptr1);  /* Begin the sample, wait for */
  382.     wakebit=0L;                            /* it to finish, then quit.   */
  383.     wakebit=Wait(1 << port1->mp_SigBit);
  384.     while((msg=GetMsg(port1))==0){};
  385.     }
  386. else
  387.     {
  388.     length[y]-=102400;                    /* It's a real long sample so  */
  389.     AIOptr1->ioa_Length=51200L;           /* double buffering is needed  */
  390.     AIOptr2->ioa_Length=51200L;
  391.     BeginIO((struct IORequest *)AIOptr1); /* Start up the first 2 blocks */
  392.     BeginIO((struct IORequest *)AIOptr2);
  393.     Aptr=AIOptr1;
  394.     port=port1;                           /* Set the switch... */
  395.  
  396.     while(length[y]>0)
  397.       {                                   /* Wait() for one IO to finish */
  398.       wakebit=Wait(1 << port->mp_SigBit); /* reuse the IO block & queue  */
  399.       while((msg=GetMsg(port))==0){};     /* it up again while the 2nd IO*/
  400.                                           /* block plays.Switch & repeat */
  401.       /* Set length of next IO block */
  402.       if (length[y]<=51200)
  403.           Aptr->ioa_Length=length[y];
  404.       else
  405.           Aptr->ioa_Length=51200L;
  406.  
  407.       /* Copy sample fragment from read buffer to chip memory */
  408.       CopyMem(psample[y],Aptr->ioa_Data,Aptr->ioa_Length);
  409.  
  410.       /* Adjust size and pointer of read buffer*/
  411.       length[y]-=Aptr->ioa_Length;
  412.       psample[y]+=51200;
  413.  
  414.       BeginIO((struct IORequest *)Aptr);
  415.  
  416.       if (Aptr==AIOptr1)
  417.           {
  418.           Aptr=AIOptr2;                /* This logic handles switching  */
  419.           port=port2;                  /* between the 2 IO blocks and   */
  420.           }                            /* the 2 ports we are using.     */
  421.       else
  422.           {
  423.           Aptr=AIOptr1;
  424.           port=port1;
  425.           }
  426.       }
  427.  
  428.     /*-------------------------------------------------*/
  429.     /* OK we are at the end of the sample so just wait */
  430.     /* for the last two parts of the sample to finish  */
  431.     /*-------------------------------------------------*/
  432.     wakebit=Wait(1 << port->mp_SigBit);
  433.     while((msg=GetMsg(port))==0){};
  434.     if (Aptr==AIOptr1)
  435.         {
  436.         Aptr=AIOptr2;                  /* This logic handles switching  */
  437.         port=port2;                    /* between the 2 IO blocks and   */
  438.         }                              /* the 2 ports we are using.     */
  439.     else
  440.         {
  441.         Aptr=AIOptr1;
  442.         port=port1;
  443.         }
  444.     wakebit=Wait(1 << port->mp_SigBit);
  445.     while((msg=GetMsg(port))==0){};
  446.     }
  447.  
  448. kill8();
  449. exit(0L);
  450. }
  451.  
  452. /*----------------*/
  453. /* Abort the Read */
  454. /*----------------*/
  455. void
  456. kill8svx(kill8svxstring)
  457. char *kill8svxstring;
  458. {
  459. puts(kill8svxstring);
  460. kill8();
  461. }
  462.  
  463. /*-------------------------*/
  464. /* Return system resources */
  465. /*-------------------------*/
  466. void kill8()
  467. {
  468. if (device ==0)
  469.     CloseDevice((struct IORequest *)AIOptr1);
  470. if (port1  !=0)
  471.     DeletePort(port1);
  472. if (port2  !=0)
  473.     DeletePort(port2);
  474. if (AIOptr1!=0)
  475.     FreeMem( AIOptr1,sizeof(struct IOAudio) );
  476. if (AIOptr2!=0)
  477.     FreeMem( AIOptr2,sizeof(struct IOAudio) );
  478.  
  479. if (mt!=0)
  480.     SetTaskPri(mt,oldpri);
  481.  
  482. if (sbase !=0)
  483.     FreeMem (sbase, ssize);
  484. if (fbase !=0)
  485.     FreeMem(fbase,fsize);
  486. if (v8handle!=0)
  487.     Close((BPTR)v8handle);
  488. }
  489.  
  490.