home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD1.iso / Emulatoren / UAE061.LZH / uae-0.6.1 / dos-snd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-28  |  5.2 KB  |  213 lines

  1.  /*
  2.   * UAE - The Un*x Amiga Emulator
  3.   *
  4.   * DOS Sound interface
  5.   *
  6.   * (c) 1996 Gustavo Goedert
  7.   */
  8.  
  9. #include <go32.h>
  10. #include <dpmi.h>
  11. #include <pc.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <stdio.h>
  15.  
  16. int DetectInitSound(int *bits, int *rate, int *bufsize);
  17. int SB_DetectInitSound(int *bits, int *rate, int *bufsize);
  18. void (*PlaySample)(void *buffer);
  19.  
  20. int DetectInitSound(int *bits, int *rate, int *bufsize) {
  21.     return(SB_DetectInitSound(bits, rate, bufsize));
  22. }
  23.  
  24. /*
  25.  * Sound Blaster Interface
  26.  */
  27.  
  28. int SB_BufferSize = -1;
  29. int SB_Port = -1;
  30. int SB_Irq = -1;
  31. int SB_Dma = -1;
  32. volatile int SB_IsPlaying = 0;
  33. unsigned int SB_BufAddr[2];
  34. int SB_BufNum = 0;
  35. _go32_dpmi_seginfo SB_OldIrq, SB_NewIrq, SB_Buf[2];
  36.  
  37. void SB_MyHandler(void);
  38. int SB_AllocateBuffer(int num);
  39. inline void SB_WriteDSP(char data);
  40. inline unsigned char SB_ReadDSP(void);
  41. void SB_Exit(void);
  42. void SB_PlaySample(void *buffer);
  43.  
  44. int SB_DetectInitSound(int *bits, int *rate, int *bufsize) {
  45.     char *SB_Env, *tmp;
  46.     unsigned char SB_Pic1, SB_Pic2;
  47.     int i;
  48.  
  49.     *bits = 8;
  50.     *rate = 22050;
  51.     if ((*bufsize) > 65536)
  52.     *bufsize = 65536;
  53.     if ((*bufsize) < 4)
  54.     *bufsize = 4;
  55.     *bufsize = ((*bufsize)>>2)<<2;
  56.     SB_BufferSize = *bufsize;
  57.     /* Get SB parameters */
  58.     SB_Env = getenv("BLASTER");
  59.     do {
  60.     tmp = strchr(SB_Env, ' ');
  61.     if (tmp!=NULL) {
  62.         *tmp = '\0';
  63.         tmp++;
  64.     }
  65.     switch (*SB_Env) {
  66.         case 'a':
  67.         case 'A':
  68.         SB_Port = strtol(SB_Env + 1, NULL, 16);
  69.         break;
  70.         case 'i':
  71.         case 'I':
  72.         SB_Irq = atoi(SB_Env + 1);
  73.         break;
  74.         case 'd':
  75.         case 'D':
  76.         SB_Dma = atoi(SB_Env + 1);
  77.         break;
  78.     }
  79.     SB_Env = tmp;
  80.     } while(SB_Env != NULL);
  81.     if ((SB_Port == -1) || (SB_Irq == -1) || (SB_Dma == -1))
  82.     return(0);
  83.     if (SB_Irq > 7) {
  84.     fprintf(stderr, "Currently Sound Blaster IRQ must be either 5 or 7.\n");
  85.     return(0);
  86.     }
  87.     if (SB_Dma != 1) {
  88.     fprintf(stderr, "Currently Sound Blaster DMA must be equal to 1.\n");
  89.     return(0);
  90.     }
  91.     /* Reset SB */
  92.     inportb(SB_Port + 0x0A);
  93.     outportb(SB_Port + 0x06, 1);
  94.     inportb(SB_Port + 0x06);
  95.     inportb(SB_Port + 0x06);
  96.     inportb(SB_Port + 0x06);
  97.     inportb(SB_Port + 0x06);
  98.     outportb(SB_Port + 0x06, 0);
  99.     for (i=0; i<100; i++) {
  100.     if (inportb(SB_Port + 0x0E) & 0x08)
  101.         if (inportb(SB_Port + 0x0A) == 0xAA)
  102.         break;
  103.     }
  104.     if (i == 100)
  105.     return(0);
  106.     /* Install IRQ Handler */
  107.     SB_NewIrq.pm_offset = (int)SB_MyHandler;
  108.     _go32_dpmi_allocate_iret_wrapper(&SB_NewIrq);
  109.     _go32_dpmi_get_protected_mode_interrupt_vector(SB_Irq + 8, &SB_OldIrq);
  110.     _go32_dpmi_set_protected_mode_interrupt_vector(SB_Irq + 8, &SB_NewIrq);
  111.     /* Alocate Buffers */
  112.     if ((SB_AllocateBuffer(0) == 0) || (SB_AllocateBuffer(1) == 0))
  113.     return(0);
  114.     /* Enable interrupts on PIC */
  115.     SB_Pic1 = inportb(0x21);
  116.     SB_Pic2 = ~(1 << SB_Irq);
  117.     outportb(0x21, SB_Pic1 & SB_Pic2);
  118.     /* Set Sample Rate */
  119.     inportb(SB_Port + 0x0E);
  120.     SB_WriteDSP(0x40);
  121.     SB_WriteDSP(256-(1000000/(*rate)));
  122.     /* Turn Speaker On */
  123.     SB_WriteDSP(0xd1);
  124.     /* Register Cleanup Function */
  125.     atexit(SB_Exit);
  126.     /* Register Play Sample Function */
  127.     PlaySample=SB_PlaySample;
  128.     /* Lock Memory Touched by Handler */
  129.     _go32_dpmi_lock_code(SB_MyHandler, (unsigned int)SB_AllocateBuffer-(unsigned int)SB_MyHandler);
  130.     _go32_dpmi_lock_data(&SB_Port, sizeof(SB_Port));
  131.     _go32_dpmi_lock_data(&SB_IsPlaying, sizeof(SB_IsPlaying));
  132.     /* All ok */
  133.     return(1);
  134. }
  135.  
  136. void SB_MyHandler(void) {
  137.     inportb(SB_Port + 0x0E);
  138.     outportb(0x20, 0x20);
  139.     SB_IsPlaying = 0;
  140. }
  141.  
  142. int SB_AllocateBuffer(int num) {
  143.     unsigned int Page;
  144.  
  145.     SB_Buf[num].size = SB_BufferSize >> 3;
  146.     if (_go32_dpmi_allocate_dos_memory(&SB_Buf[num]))
  147.     return(0);
  148.     SB_BufAddr[num] = SB_Buf[num].rm_segment << 4;
  149.     /* Force a don't cross 64k boundary */
  150.     Page = SB_BufAddr[num] & 0xFFFF;
  151.     if ((Page + SB_BufferSize) > 0xFFFF)
  152.     SB_BufAddr[num] = (SB_BufAddr[num] - Page) + 0x10000;
  153.     return(1);
  154. }
  155.  
  156. inline void SB_WriteDSP(char data) {
  157.     while(inportb(SB_Port + 0x0C) & 0x80);
  158.     outportb(SB_Port + 0x0C, data);
  159. }
  160.  
  161. inline unsigned char SB_ReadDSP(void) {
  162.     while(!(inportb(SB_Port + 0x0E) & 0x80));
  163.     return(inportb(SB_Port + 0x0A));
  164. }
  165.  
  166. void SB_Exit(void) {
  167.     /* Turn Speaker Off */
  168.     SB_WriteDSP(0xD3);
  169.     /* Stop any DMA transfer */
  170.     SB_WriteDSP(0xD0);
  171.     /* Free DOS memory */
  172.     _go32_dpmi_free_dos_memory(&SB_Buf[0]);
  173.     _go32_dpmi_free_dos_memory(&SB_Buf[1]);
  174.     /* Restore old IRQ Handler */
  175.     _go32_dpmi_set_protected_mode_interrupt_vector(SB_Irq + 8, &SB_OldIrq);
  176. }
  177.  
  178. void SB_PlaySample(void *buffer) {
  179.     unsigned int Size = SB_BufferSize - 1;
  180.  
  181.     asm ("
  182.      push %%es
  183.      cld
  184.      movw %0, %%es
  185.      shrl $2, %%ecx
  186.      rep
  187.      movsl
  188.      pop %%es
  189.      "
  190.      :
  191.      : "g" (_dos_ds),
  192.        "S" (buffer), "D" (SB_BufAddr[SB_BufNum]), "c" (SB_BufferSize)
  193.      : "%esi", "%edi", "%ecx", "cc"
  194.     );
  195.     /* Wait current sample stop playing */
  196.     while(SB_IsPlaying);
  197.     /* Start DMA */
  198.     outportb(0x0A, 0x05);
  199.     outportb(0x0C, 0x00);
  200.     outportb(0x0B, 0x59);
  201.     outportb(0x02, SB_BufAddr[SB_BufNum]);
  202.     outportb(0x02, SB_BufAddr[SB_BufNum] >> 8);
  203.     outportb(0x83, SB_BufAddr[SB_BufNum] >> 16);
  204.     outportb(0x03, Size);
  205.     outportb(0x03, Size >> 8);
  206.     outportb(0x0A, 0x01);
  207.     SB_WriteDSP(0x14);
  208.     SB_WriteDSP(Size);
  209.     SB_WriteDSP(Size >> 8);
  210.     SB_IsPlaying = 1;
  211.     SB_BufNum = !SB_BufNum;
  212. }
  213.