home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Exec 1 / CD_Magazyn_EXEC_nr_1.iso / Gry / battalion.lha / Battalion / source / amigasnd.c next >
C/C++ Source or Header  |  1999-12-23  |  9KB  |  352 lines

  1. /* Amiga Sound Interface for Battalion */
  2. /* Written by Frank Wille <frank@phoenix.owl.de> in 1999 */
  3.  
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <exec/memory.h>
  7. #include <exec/errors.h>
  8. #include <graphics/gfxbase.h>
  9. #include <devices/audio.h>
  10. #include <proto/exec.h>
  11. #include <clib/alib_protos.h>
  12. #ifdef __PPC__
  13. #include <clib/powerpc_protos.h>
  14. #endif
  15. #include "amigasnd.h"
  16.  
  17.  
  18. struct Channel {
  19.   struct MsgPort *audmp;
  20.   struct IOAudio *audio;
  21. };
  22.  
  23.  
  24. /* table to convert ULAW-samples into Amiga native signed 8-bit format */
  25. static UBYTE ulaw2signed8[256] = {
  26.   0x82,0x86,0x8a,0x8e,0x92,0x96,0x9a,0x9e,
  27.   0xa2,0xa6,0xaa,0xae,0xb2,0xb6,0xba,0xbe,
  28.   0xc1,0xc3,0xc5,0xc7,0xc9,0xcb,0xcd,0xcf,
  29.   0xd1,0xd3,0xd5,0xd7,0xd9,0xdb,0xdd,0xdf,
  30.   0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,
  31.   0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf0,
  32.   0xf0,0xf1,0xf1,0xf2,0xf2,0xf3,0xf3,0xf4,
  33.   0xf4,0xf5,0xf5,0xf6,0xf6,0xf7,0xf7,0xf8,
  34.   0xf8,0xf8,0xf9,0xf9,0xf9,0xf9,0xfa,0xfa,
  35.   0xfa,0xfa,0xfb,0xfb,0xfb,0xfb,0xfc,0xfc,
  36.   0xfc,0xfc,0xfc,0xfc,0xfd,0xfd,0xfd,0xfd,
  37.   0xfd,0xfd,0xfd,0xfd,0xfe,0xfe,0xfe,0xfe,
  38.   0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,
  39.   0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  40.   0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  41.   0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,
  42.   0x7d,0x79,0x75,0x71,0x6d,0x69,0x65,0x61,
  43.   0x5d,0x59,0x55,0x51,0x4d,0x49,0x45,0x41,
  44.   0x3e,0x3c,0x3a,0x38,0x36,0x34,0x32,0x30,
  45.   0x2e,0x2c,0x2a,0x28,0x26,0x24,0x22,0x20,
  46.   0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,
  47.   0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x0f,
  48.   0x0f,0x0e,0x0e,0x0d,0x0d,0x0c,0x0c,0x0b,
  49.   0x0b,0x0a,0x0a,0x09,0x09,0x08,0x08,0x07,
  50.   0x07,0x07,0x06,0x06,0x06,0x06,0x05,0x05,
  51.   0x05,0x05,0x04,0x04,0x04,0x04,0x03,0x03,
  52.   0x03,0x03,0x03,0x03,0x02,0x02,0x02,0x02,
  53.   0x02,0x02,0x02,0x02,0x01,0x01,0x01,0x01,
  54.   0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
  55.   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  56.   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  57.   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  58. };
  59.  
  60. static struct Channel chans[ADHARD_CHANNELS] = { 0 };
  61. static struct IOAudio *aud_io = NULL;
  62. static int audio_dev = -1;  /* 0, when audio.device was openend */
  63. static long sysclock;  /* PAL or NTSC system clock */
  64. static int chidx = 1;  /* next free channel, max is ADHARD_CHANNELS-1 */
  65. static struct SoundInfo *playing[ADHARD_CHANNELS] = { NULL };
  66.  
  67.  
  68.  
  69. static struct IOAudio *create_ioaudio(struct MsgPort *port)
  70. {
  71.   struct IOAudio *ioa = NULL;
  72.  
  73. #ifdef __PPC__
  74.   ioa = (struct IOAudio *)AllocVecPPC(sizeof(struct IOAudio),
  75.                                         MEMF_CLEAR|MEMF_PUBLIC,0);
  76. #else /* M68k */
  77.   ioa = (struct IOAudio *)AllocVec(sizeof(struct IOAudio),
  78.                                      MEMF_CLEAR|MEMF_PUBLIC);
  79. #endif
  80.  
  81. /*  ioa->ioa_Request.io_Message.mn_Node.ln_Type = NT_MESSAGE;*/
  82.   ioa->ioa_Request.io_Message.mn_ReplyPort = port;
  83.   ioa->ioa_Request.io_Message.mn_Length = sizeof(struct IOAudio);
  84.   return ioa;
  85. }
  86.  
  87.  
  88. static void delete_ioaudio(struct IOAudio *ioa)
  89. {
  90.   int i=-1;
  91.  
  92.   if (ioa) {
  93.     ioa->ioa_Request.io_Message.mn_Node.ln_Type = i;
  94.     ioa->ioa_Request.io_Device = (struct Device *)i;
  95.     ioa->ioa_Request.io_Unit = (struct Unit *)i;
  96. #ifdef __PPC__
  97.     FreeVecPPC(ioa);
  98. #else
  99.     FreeVec(ioa);
  100. #endif
  101.   }
  102. }
  103.  
  104.  
  105. static int alloc_sound(struct SoundInfo *snd)
  106. {
  107.   if (snd) {
  108. #ifdef __PPC__
  109.     if (!(snd->data = (UBYTE *)AllocVecPPC(snd->length,
  110.                                            MEMF_CHIP|MEMF_PUBLIC,0))) {
  111. #else /* M68k */
  112.     if (!(snd->data = (UBYTE *)AllocVec(snd->length,
  113.                                         MEMF_CHIP|MEMF_PUBLIC))) {
  114. #endif
  115.       printf("alloc_sound(): Failed to allocate %lu bytes Chip RAM\n",
  116.              snd->length);
  117.     }
  118.     else
  119.       return 1;
  120.   }
  121.   return 0;
  122. }
  123.  
  124.  
  125. static void free_sound(struct SoundInfo *snd)
  126. {
  127.   if (snd) {
  128.     if (snd->loaded!=0 && snd->data!=NULL && snd->length>0) {
  129. #ifdef __PPC__
  130.       FreeVecPPC(snd->data);
  131. #else
  132.       FreeVec(snd->data);
  133. #endif
  134.       memset(snd,0,sizeof(struct SoundInfo));
  135.     }
  136.   }
  137. }
  138.  
  139.  
  140. static void stop_channel(int ch)
  141. /* stop audio output for this channel */
  142. {
  143.   if (audio_dev == 0) {
  144.     if (chans[ch].audio) {
  145.       if (chans[ch].audio->ioa_Request.io_Message.mn_Node.ln_Type) {
  146.         if (!CheckIO((struct IORequest *)chans[ch].audio))
  147.           AbortIO((struct IORequest *)chans[ch].audio);
  148.         WaitIO((struct IORequest *)chans[ch].audio);
  149.       }
  150.     }
  151.   }
  152. }
  153.  
  154.  
  155. static void freechans(void)
  156. /* free MsgPorts and IOAudios of alls channels, close audio.device */
  157. {
  158.   int i;
  159.  
  160.   if (audio_dev==0 && aud_io) {
  161.     aud_io->ioa_Request.io_Unit = (struct Unit *)((1<<ADHARD_CHANNELS)-1);
  162.     CloseDevice((struct IORequest *)aud_io);
  163.     audio_dev = -1;
  164.   }
  165.   for (i=0; i<ADHARD_CHANNELS; i++) {
  166.     if (chans[i].audio) {
  167.       delete_ioaudio(chans[i].audio);
  168.       chans[i].audio = NULL;
  169.     }
  170.     if (chans[i].audmp) {
  171.       DeletePort(chans[i].audmp);
  172.       chans[i].audmp = NULL;
  173.     }
  174.   }
  175.   if (aud_io) {
  176.     delete_ioaudio(aud_io);
  177.     aud_io = NULL;
  178.   }
  179. }
  180.  
  181.  
  182. /*
  183. ** PUBLIC FUNCTIONS
  184. */
  185.  
  186. int amigasnd_init(void)
  187. {
  188.   static const char *fn = "amigasnd_init(): ";
  189.   static UBYTE chmask = (1<<ADHARD_CHANNELS)-1;
  190.   struct GfxBase *gfxb;
  191.   int i;
  192.  
  193.   /* determine clock constant */
  194.   if (gfxb = (struct GfxBase *)OpenLibrary("graphics.library",36)) {
  195.     sysclock = (gfxb->DisplayFlags & PAL) ? 3546895 : 3579545;
  196.     CloseLibrary((struct Library *)gfxb);
  197.   }
  198.   else {
  199.     printf("%sCan't determine clock constant,"
  200.            " graphics.library V36 required!\n",fn);
  201.     return (0);
  202.   }
  203.  
  204.   /* create MsgPorts */
  205.   for (i=0; i<ADHARD_CHANNELS; i++) {
  206.     if (!(chans[i].audmp = CreatePort(NULL,0))) {
  207.       printf("%sCan't create MsgPort for channel %d.\n",fn,i);
  208.       freechans();
  209.       return (0);
  210.     }
  211.   }
  212.  
  213.   if (aud_io = create_ioaudio(chans[0].audmp)) {
  214.     aud_io->ioa_Request.io_Message.mn_Node.ln_Pri = ADALLOC_MAXPREC;
  215.     aud_io->ioa_Request.io_Command = ADCMD_ALLOCATE;
  216.     aud_io->ioa_Request.io_Flags = ADIOF_NOWAIT;
  217.     aud_io->ioa_AllocKey = 0;
  218.     aud_io->ioa_Data = &chmask;
  219.     aud_io->ioa_Length = 1;
  220.     audio_dev = OpenDevice(AUDIONAME,0,(struct IORequest *)aud_io,0);
  221.   }
  222.   else {
  223.     printf("%sCan't allocate audio I/O block\n",fn);
  224.     freechans();
  225.     return (0);
  226.   }
  227.   if (audio_dev) {
  228.     printf("%sUnable to get all channels from %s\n",fn,AUDIONAME);
  229.     freechans();
  230.     return (0);
  231.   }
  232.  
  233.   for (i=0; i<ADHARD_CHANNELS; i++) {
  234.     /* allocate audio channels */
  235.     if (chans[i].audio = create_ioaudio(NULL)) {
  236.       *chans[i].audio = *aud_io;
  237.       chans[i].audio->ioa_Request.io_Message.mn_ReplyPort = chans[i].audmp;
  238.       chans[i].audio->ioa_Request.io_Message.mn_Node.ln_Type = 0;
  239.       chans[i].audio->ioa_Request.io_Unit = (struct Unit *)(1 << i);
  240.       playing[i] = NULL;  /* sound, which is currently played here */
  241.     }
  242.     else {
  243.       printf("%sCan't alloc IOAudio for channel %d.\n",fn,i);
  244.       freechans();
  245.       return (0);
  246.     }
  247.   }
  248.  
  249.   return (1);
  250. }
  251.  
  252.  
  253. void amigasnd_exit(void)
  254. {
  255.   int i;
  256.  
  257.   for (i=0; i<ADHARD_CHANNELS; stop_channel(i++));
  258.   freechans();
  259. }
  260.  
  261.  
  262. void amigasnd_loadau(struct SoundInfo *snd,char *name)
  263. {
  264.   static const char *fn = "amigasnd_loadau: ";
  265.   unsigned long header[8];
  266.   FILE *fh;
  267.  
  268.   free_sound(snd);
  269.   if (fh = fopen(name,"r")) {
  270.     /* read au-header */
  271.     if (fread(header,sizeof(unsigned long),8,fh) == 8) {
  272.       if (header[0] == 0x2e736e64) {  /* ".snd" */
  273.         snd->period = (UWORD)(sysclock / (long)header[4]);
  274.         fseek(fh,0,SEEK_END);
  275.         snd->length = (int)ftell(fh) - 32;
  276.         fseek(fh,32,SEEK_SET);
  277.  
  278.         if (alloc_sound(snd)) {
  279.           /* read and convert sample data into Chip-RAM buffer */
  280.           UBYTE idx, *p = snd->data;
  281.           ULONG len = snd->length;
  282.  
  283.           fread(p,1,len,fh);
  284.           while (len-- != 0) {
  285.             idx = *p;
  286.             *p++ = ulaw2signed8[idx];  /* convert */
  287.           }
  288.           snd->loaded = 1;
  289.         }
  290.       }
  291.       else
  292.         printf("%s%s is no au-file in ulaw-format\n",fn,name);
  293.     }
  294.     else
  295.       printf("%sRead error in header of %s\n",fn,name);
  296.  
  297.     fclose(fh);
  298.   }
  299.   else
  300.     printf("%sCan't open %s\n",fn,name);
  301. }
  302.  
  303.  
  304. void amigasnd_free(struct SoundInfo *snd)
  305. {
  306.   int i;
  307.  
  308.   for (i=0; i<ADHARD_CHANNELS; i++) {
  309.     if (playing[i] == snd)
  310.       stop_channel(i);
  311.   }
  312.   free_sound(snd);
  313. }
  314.  
  315.  
  316. void amigasnd_play(struct SoundInfo *snd,int ch)
  317. {
  318.   struct IOAudio *ioa;
  319.  
  320.   if (ch>=0 && ch<ADHARD_CHANNELS && snd->loaded) {
  321.     stop_channel(ch);
  322.     ioa = chans[ch].audio;
  323.     ioa->ioa_Request.io_Command = CMD_WRITE;
  324.     ioa->ioa_Request.io_Flags = ADIOF_PERVOL;
  325.     ioa->ioa_Data = snd->data;
  326.     ioa->ioa_Length = snd->length;
  327.     ioa->ioa_Period = snd->period;
  328.     ioa->ioa_Volume = 64;
  329.     ioa->ioa_Cycles = 1;
  330.     BeginIO((struct IORequest *)ioa);
  331.   }
  332. }
  333.  
  334.  
  335. int amigasnd_getchannels(void)
  336. {
  337.   return (ADHARD_CHANNELS);
  338. }
  339.  
  340.  
  341. #if 0
  342. void snd_sync(void)
  343. {
  344.   /* wait for sounds to end */
  345.   if (audio_dev==0 && audio!=NULL) {
  346.     if (audio->ioa_Request.io_Message.mn_Node.ln_Type) {
  347.       WaitIO((struct IORequest *)audio);
  348.     }
  349.   }
  350. }
  351. #endif
  352.