home *** CD-ROM | disk | FTP | other *** search
/ Large Pack of OldSkool DOS MOD Trackers / goattracker_2.70.zip / src / gsound.c < prev    next >
C/C++ Source or Header  |  2010-01-31  |  13KB  |  531 lines

  1. //
  2. // GOATTRACKER sound routines
  3. //
  4.  
  5. #define GSOUND_C
  6.  
  7. #ifdef __WIN32__
  8. #include <windows.h>
  9. #endif
  10.  
  11. #include "goattrk2.h"
  12.  
  13. // General / reSID output
  14. int playspeed;
  15. int usehardsid = 0;
  16. int usecatweasel = 0;
  17. int initted = 0;
  18. int firsttimeinit = 1;
  19. unsigned framerate = PALFRAMERATE;
  20. Sint16 *buffer = NULL;
  21. FILE *writehandle = NULL;
  22.  
  23. void sound_playrout(void);
  24. void sound_mixer(Sint32 *dest, unsigned samples);
  25. Uint32 sound_timer(Uint32 interval);
  26.  
  27. #ifdef __WIN32__
  28.  
  29. // Win32 HardSID output
  30. typedef void (CALLBACK* lpWriteToHardSID)(Uint8 DeviceID, Uint8 SID_reg, Uint8 Data);
  31. typedef Uint8 (CALLBACK* lpReadFromHardSID)(Uint8 DeviceID, Uint8 SID_reg);
  32. typedef void (CALLBACK* lpInitHardSID_Mapper)(void);
  33. typedef void (CALLBACK* lpMuteHardSID_Line)(int Mute);
  34. typedef void (CALLBACK* lpHardSID_Delay)(Uint8 DeviceID, Uint16 Cycles);
  35. typedef void (CALLBACK* lpHardSID_Write)(Uint8 DeviceID, Uint16 Cycles, Uint8 SID_reg, Uint8 Data);
  36. typedef void (CALLBACK* lpHardSID_Flush)(Uint8 DeviceID);
  37. typedef void (CALLBACK* lpHardSID_SoftFlush)(Uint8 DeviceID);
  38. typedef boolean (CALLBACK* lpHardSID_Lock)(Uint8 DeviceID);
  39. lpWriteToHardSID WriteToHardSID = NULL;
  40. lpReadFromHardSID ReadFromHardSID = NULL;
  41. lpInitHardSID_Mapper InitHardSID_Mapper = NULL;
  42. lpMuteHardSID_Line MuteHardSID_Line = NULL;
  43. lpHardSID_Delay HardSID_Delay = NULL;
  44. lpHardSID_Write HardSID_Write = NULL;
  45. lpHardSID_Flush HardSID_Flush = NULL;
  46. lpHardSID_SoftFlush HardSID_SoftFlush = NULL;
  47. lpHardSID_Lock HardSID_Lock = NULL;
  48. HINSTANCE hardsiddll = 0;
  49. int dll_initialized = FALSE;
  50. // Cycle-exact HardSID support
  51. int cycleexacthardsid = FALSE;
  52. SDL_Thread* playerthread = NULL;
  53. SDL_mutex* flushmutex = NULL;
  54. volatile int runplayerthread = FALSE;
  55. volatile int flushplayerthread = FALSE;
  56. volatile int suspendplayroutine = FALSE;
  57. int sound_thread(void *userdata);
  58.  
  59. void InitHardDLL(void);
  60.  
  61. // Win32 CatWeasel MK3 PCI output
  62. #define SID_SID_PEEK_POKE   CTL_CODE(FILE_DEVICE_SOUND,0x0800UL + 1,METHOD_BUFFERED,FILE_ANY_ACCESS)
  63. HANDLE catweaselhandle;
  64.  
  65. #else
  66.  
  67. // Unix HardSID & CatWeasel output
  68. int hardsidfd = -1;
  69. int catweaselfd = -1;
  70.  
  71. #endif
  72.  
  73. int sound_init(unsigned b, unsigned mr, unsigned writer, unsigned hardsid, unsigned m, unsigned ntsc, unsigned multiplier, unsigned catweasel, unsigned interpolate, unsigned customclockrate)
  74. {
  75.   int c;
  76.  
  77.   #ifdef __WIN32__
  78.   if (!flushmutex)
  79.       flushmutex = SDL_CreateMutex();
  80.   #endif
  81.  
  82.   sound_uninit();
  83.  
  84.   if (multiplier)
  85.   {
  86.     if (ntsc)
  87.     {
  88.       framerate = NTSCFRAMERATE * multiplier;
  89.       snd_bpmtempo = 150 * multiplier;
  90.     }
  91.     else
  92.     {
  93.       framerate = PALFRAMERATE * multiplier;
  94.       snd_bpmtempo = 125 * multiplier;
  95.     }
  96.   }
  97.   else
  98.   {
  99.     if (ntsc)
  100.     {
  101.       framerate = NTSCFRAMERATE / 2;
  102.       snd_bpmtempo = 150 / 2;
  103.     }
  104.     else
  105.     {
  106.       framerate = PALFRAMERATE / 2;
  107.       snd_bpmtempo = 125 / 2;
  108.     }
  109.   }
  110.  
  111.   if (hardsid)
  112.   {
  113.     #ifdef __WIN32__
  114.     InitHardDLL();
  115.     if (dll_initialized)
  116.     {
  117.       usehardsid = hardsid;
  118.       if (cycleexacthardsid) {
  119.         HardSID_Lock(usehardsid-1);
  120.         HardSID_Flush(usehardsid-1);
  121.         HardSID_Write(usehardsid-1, SIDWRITEDELAY, 0, 0x00);
  122.         Sleep(300);
  123.       }
  124.       for (c = 0; c < NUMSIDREGS; c++)
  125.       {
  126.         sidreg[c] = 0;
  127.         if (cycleexacthardsid) {
  128.             HardSID_Write(usehardsid-1, SIDWRITEDELAY, c, 0x00);
  129.         }
  130.         else {
  131.             WriteToHardSID(usehardsid-1, c, 0x00);
  132.         }
  133.       }
  134.       if (cycleexacthardsid) {
  135.         HardSID_SoftFlush(usehardsid-1);
  136.       }
  137.       else {
  138.         MuteHardSID_Line(FALSE);
  139.       }
  140.     }
  141.     else return 0;
  142.     if (!cycleexacthardsid)
  143.     {
  144.       SDL_SetTimer(1000 / framerate, sound_timer);
  145.     }
  146.     else
  147.     {
  148.       runplayerthread = TRUE;
  149.       playerthread = SDL_CreateThread(sound_thread, NULL);
  150.       if (!playerthread) return 0;
  151.     }
  152.     #else
  153.     char filename[80];
  154.     sprintf(filename, "/dev/sid%d", hardsid-1);
  155.     hardsidfd = open(filename, O_WRONLY, S_IREAD|S_IWRITE);
  156.     if (hardsidfd >= 0)
  157.     {
  158.       usehardsid = hardsid;
  159.       for (c = 0; c < NUMSIDREGS; c++)
  160.       {
  161.         Uint32 dataword = c << 8;
  162.         write(hardsidfd, &dataword, 4);
  163.       }
  164.     }
  165.     else return 0;
  166.     SDL_SetTimer(1000 / framerate, sound_timer);
  167.     #endif
  168.  
  169.     goto SOUNDOK;
  170.   }
  171.  
  172.   if (catweasel)
  173.   {
  174.     #ifdef __WIN32__
  175.     catweaselhandle = CreateFile("\\\\.\\SID6581_1", GENERIC_READ, FILE_SHARE_WRITE|FILE_SHARE_READ, 0L,
  176.       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0L);
  177.     if (catweaselhandle == INVALID_HANDLE_VALUE)
  178.       return 0;
  179.     #else
  180.     catweaselfd = open("/dev/sid", O_WRONLY);
  181.     if (catweaselfd < 0)
  182.       catweaselfd = open("/dev/misc/sid", O_WRONLY);
  183.     if (catweaselfd < 0)
  184.       return 0;
  185.     #ifndef __amigaos__
  186.     if (ntsc)
  187.       ioctl(catweaselfd, CWSID_IOCTL_NTSC);
  188.     else
  189.       ioctl(catweaselfd, CWSID_IOCTL_PAL);
  190.     #endif
  191.     #endif
  192.  
  193.     usecatweasel = 1;
  194.     SDL_SetTimer(1000 / framerate, sound_timer);
  195.     goto SOUNDOK;
  196.   }
  197.  
  198.   if (!buffer) buffer = malloc(MIXBUFFERSIZE * sizeof(Sint16));
  199.   if (!buffer) return 0;
  200.  
  201.   if (writer)
  202.     writehandle = fopen("sidaudio.raw", "wb");
  203.  
  204.   playspeed = mr;
  205.   if (playspeed < MINMIXRATE) playspeed = MINMIXRATE;
  206.   if (playspeed > MAXMIXRATE) playspeed = MAXMIXRATE;
  207.   if (b < MINBUF) b = MINBUF;
  208.   if (b > MAXBUF) b = MAXBUF;
  209.  
  210.   if (firsttimeinit)
  211.   {
  212.     if (!snd_init(mr, SIXTEENBIT|MONO, b, 1, 0)) return 0;
  213.     firsttimeinit = 0;
  214.   }
  215.   playspeed = snd_mixrate;
  216.   sid_init(playspeed, m, ntsc, interpolate & 1, customclockrate, interpolate >> 1);
  217.  
  218.   snd_player = &sound_playrout;
  219.   snd_setcustommixer(sound_mixer);
  220.  
  221.   SOUNDOK:
  222.   initted = 1;
  223.   return 1;
  224. }
  225.  
  226. void sound_uninit(void)
  227. {
  228.   int c;
  229.  
  230.   if (!initted) return;
  231.   initted = 0;
  232.  
  233.   // Apparently a delay is needed to make sure the sound timer thread is
  234.   // not mixing stuff anymore, and we can safely delete related structures
  235.   SDL_Delay(50);
  236.  
  237.   if (usehardsid || usecatweasel)
  238.   {
  239.     #ifdef __WIN32__
  240.     if (!playerthread)
  241.     {
  242.       SDL_SetTimer(0, NULL);
  243.     }
  244.     else
  245.     {
  246.       runplayerthread = FALSE;
  247.       SDL_WaitThread(playerthread, NULL);
  248.       playerthread = NULL;
  249.     }
  250.     #else
  251.     SDL_SetTimer(0, NULL);
  252.     #endif
  253.   }
  254.   else
  255.   {
  256.       snd_setcustommixer(NULL);
  257.     snd_player = NULL;
  258.   }
  259.  
  260.   if (writehandle)
  261.   {
  262.     fclose(writehandle);
  263.     writehandle = NULL;
  264.   }
  265.   
  266.   if (buffer)
  267.   {
  268.     free(buffer);
  269.     buffer = NULL;
  270.   }
  271.  
  272.   if (usehardsid)
  273.   {
  274.     #ifdef __WIN32__
  275.     for (c = 0; c < NUMSIDREGS; c++)
  276.     {
  277.         if (cycleexacthardsid) {
  278.             HardSID_Write(usehardsid-1, SIDWRITEDELAY, c, 0x00);
  279.         }
  280.         else {
  281.             WriteToHardSID(usehardsid-1, c, 0x00);
  282.         }
  283.     }
  284.     MuteHardSID_Line(TRUE);
  285.     #else
  286.     if (hardsidfd >= 0)
  287.     {
  288.       for (c = 0; c < NUMSIDREGS; c++)
  289.       {
  290.         Uint32 dataword = c << 8;
  291.         write(hardsidfd, &dataword, 4);
  292.       }
  293.       close(hardsidfd);
  294.       hardsidfd = -1;
  295.     }
  296.     #endif
  297.   }
  298.  
  299.   if (usecatweasel)
  300.   {
  301.     #ifdef __WIN32__
  302.     DWORD w;
  303.     unsigned char buf[NUMSIDREGS * 2];
  304.     for (w = 0; w < NUMSIDREGS; w++)
  305.     {
  306.       buf[w*2] = 0x18 - w;
  307.       buf[w*2+1] = 0;
  308.     }
  309.     DeviceIoControl(catweaselhandle, SID_SID_PEEK_POKE, buf, sizeof(buf), 0L, 0UL, &w, 0L);
  310.     CloseHandle(catweaselhandle);
  311.     catweaselhandle = INVALID_HANDLE_VALUE;
  312.     #else
  313.     if (catweaselfd >= 0)
  314.     {
  315.       unsigned char buf[NUMSIDREGS];
  316.       memset(buf, 0, sizeof(buf));
  317.       lseek(catweaselfd, 0, SEEK_SET);
  318.       write(catweaselfd, buf, sizeof(buf));
  319.       close(catweaselfd);
  320.       catweaselfd = -1;
  321.     }
  322.     #endif
  323.   }
  324. }
  325.  
  326. void sound_suspend(void)
  327. {
  328.   #ifdef __WIN32__
  329.   SDL_LockMutex(flushmutex);
  330.   suspendplayroutine = TRUE;
  331.   SDL_UnlockMutex(flushmutex);
  332.   #endif
  333. }
  334.  
  335. void sound_flush(void)
  336. {
  337.   #ifdef __WIN32__
  338.   SDL_LockMutex(flushmutex);
  339.   flushplayerthread = TRUE;
  340.   SDL_UnlockMutex(flushmutex);
  341.   #endif
  342. }
  343.  
  344. Uint32 sound_timer(Uint32 interval)
  345. {
  346.   if (!initted) return interval;
  347.   sound_playrout();
  348.   return interval;
  349. }
  350.  
  351. #ifdef __WIN32__
  352. int sound_thread(void *userdata)
  353. {
  354.   unsigned long flush_cycles_interactive = hardsidbufinteractive * 1000; /* 0 = flush off for interactive mode*/
  355.   unsigned long flush_cycles_playback = hardsidbufplayback * 1000; /* 0 = flush off for playback mode*/
  356.   unsigned long cycles_after_flush = 0;
  357.   boolean interactive;
  358.  
  359.   while (runplayerthread)
  360.   {
  361.     unsigned cycles = 1000000 / framerate; // HardSID should be clocked at 1MHz
  362.     int c;
  363.  
  364.     if (flush_cycles_interactive > 0 || flush_cycles_playback > 0)
  365.     {
  366.       cycles_after_flush += cycles;
  367.     }
  368.  
  369.     // Do flush if starting playback, stopping playback, starting an interactive note etc.
  370.     if (flushplayerthread)
  371.     {
  372.       SDL_LockMutex(flushmutex);
  373.       if (HardSID_Flush)
  374.       {
  375.         HardSID_Flush(usehardsid-1);
  376.       }
  377.       // Can clear player suspend now (if set)
  378.       suspendplayroutine = FALSE;
  379.       flushplayerthread = FALSE;
  380.       SDL_UnlockMutex(flushmutex);
  381.  
  382.       SDL_Delay(0);
  383.     }
  384.  
  385.     if (!suspendplayroutine) playroutine();
  386.  
  387.     interactive = !(boolean)recordmode /* jam mode */ || !(boolean)isplaying();
  388.  
  389.     for (c = 0; c < NUMSIDREGS; c++)
  390.     {
  391.       unsigned o = sid_getorder(c);
  392.  
  393.         // Extra delay before loading the waveform (and mt_chngate,x)
  394.         if ((o == 4) || (o == 11) || (o == 18))
  395.         {
  396.         HardSID_Write(usehardsid-1, SIDWRITEDELAY+SIDWAVEDELAY, o, sidreg[o]);
  397.           cycles -= SIDWRITEDELAY+SIDWAVEDELAY;
  398.       }
  399.         else
  400.       {
  401.             HardSID_Write(usehardsid-1, SIDWRITEDELAY, o, sidreg[o]);
  402.             cycles -= SIDWRITEDELAY;
  403.         }
  404.     }
  405.  
  406.     // Now wait the rest of frame
  407.     while (cycles)
  408.     {
  409.       unsigned runnow = cycles;
  410.       if (runnow > 65535) runnow = 65535;
  411.       HardSID_Delay(usehardsid-1, runnow);
  412.       cycles -= runnow;
  413.     }
  414.  
  415.       if ((flush_cycles_interactive>0 && interactive && cycles_after_flush>=flush_cycles_interactive) ||
  416.           (flush_cycles_playback>0 && !interactive && cycles_after_flush>=flush_cycles_playback))
  417.     {
  418.       if (HardSID_SoftFlush)
  419.         HardSID_SoftFlush(usehardsid-1);
  420.           cycles_after_flush = 0;
  421.     }
  422.   }
  423.  
  424.   unsigned r;
  425.  
  426.   for (r = 0; r < NUMSIDREGS; r++)
  427.   {
  428.     HardSID_Write(usehardsid-1, SIDWRITEDELAY, r, 0);
  429.   }
  430.   if (HardSID_SoftFlush)
  431.     HardSID_SoftFlush(usehardsid-1);
  432.  
  433.   return 0;
  434. }
  435. #endif
  436.  
  437. void sound_playrout(void)
  438. {
  439.   int c;
  440.  
  441.   playroutine();
  442.   if (usehardsid)
  443.   {
  444.     #ifdef __WIN32__
  445.     for (c = 0; c < NUMSIDREGS; c++)
  446.     {
  447.       unsigned o = sid_getorder(c);
  448.         if (cycleexacthardsid) {
  449.             HardSID_Write(usehardsid-1, SIDWRITEDELAY, o, sidreg[o]);
  450.         }
  451.         else {
  452.             WriteToHardSID(usehardsid-1, o, sidreg[o]);
  453.         }
  454.     }
  455.     #else
  456.     for (c = 0; c < NUMSIDREGS; c++)
  457.     {
  458.       unsigned o = sid_getorder(c);
  459.       Uint32 dataword = (o << 8) | sidreg[o];
  460.       write(hardsidfd, &dataword, 4);
  461.     }
  462.     #endif
  463.   }
  464.   else if (usecatweasel)
  465.   {
  466.     #ifdef __WIN32__
  467.     DWORD w;
  468.     unsigned char buf[NUMSIDREGS * 2];
  469.  
  470.     for(w = 0; w < NUMSIDREGS; w++)
  471.     {
  472.       unsigned o = sid_getorder(w);
  473.  
  474.       buf[w*2] = o;
  475.       buf[w*2+1] = sidreg[o];
  476.     }
  477.     DeviceIoControl(catweaselhandle, SID_SID_PEEK_POKE, buf, sizeof(buf), 0L, 0UL, &w, 0L);
  478.     #else
  479.     for (c = 0; c < NUMSIDREGS; c++)
  480.     {
  481.       unsigned o = sid_getorder(c);
  482.  
  483.       lseek(catweaselfd, o, SEEK_SET);
  484.       write(catweaselfd, &sidreg[o], 1);
  485.     }
  486.     #endif
  487.   }
  488. }
  489.  
  490. void sound_mixer(Sint32 *dest, unsigned samples)
  491. {
  492.   int c;
  493.  
  494.   if (!initted) return;
  495.   if (samples > MIXBUFFERSIZE) return;
  496.   if (!buffer) return;
  497.  
  498.   sid_fillbuffer(buffer, samples);
  499.   if (writehandle)
  500.     fwrite(buffer, samples * sizeof(Uint16), 1, writehandle);
  501.  
  502.   for (c = 0; c < samples; c++)
  503.     dest[c] = buffer[c];
  504. }
  505.  
  506. #ifdef __WIN32__
  507. void InitHardDLL()
  508. {
  509.   if (!(hardsiddll=LoadLibrary("HARDSID.DLL"))) return;
  510.  
  511.   WriteToHardSID = (lpWriteToHardSID) GetProcAddress(hardsiddll, "WriteToHardSID");
  512.   ReadFromHardSID = (lpReadFromHardSID) GetProcAddress(hardsiddll, "ReadFromHardSID");
  513.   InitHardSID_Mapper = (lpInitHardSID_Mapper) GetProcAddress(hardsiddll, "InitHardSID_Mapper");
  514.   MuteHardSID_Line = (lpMuteHardSID_Line) GetProcAddress(hardsiddll, "MuteHardSID_Line");
  515.  
  516.   if (!WriteToHardSID) return;
  517.  
  518.   // Try to get cycle-exact interface
  519.   HardSID_Delay = (lpHardSID_Delay) GetProcAddress(hardsiddll, "HardSID_Delay");
  520.   HardSID_Write = (lpHardSID_Write) GetProcAddress(hardsiddll, "HardSID_Write");
  521.   HardSID_Flush = (lpHardSID_Flush) GetProcAddress(hardsiddll, "HardSID_Flush");
  522.   HardSID_SoftFlush = (lpHardSID_SoftFlush) GetProcAddress(hardsiddll, "HardSID_SoftFlush");
  523.   HardSID_Lock = (lpHardSID_Lock) GetProcAddress(hardsiddll, "HardSID_Lock");
  524.   if ((HardSID_Delay) && (HardSID_Write) && (HardSID_Flush) && (HardSID_SoftFlush) && (HardSID_Lock))
  525.     cycleexacthardsid = TRUE;
  526.  
  527.   InitHardSID_Mapper();
  528.   dll_initialized = TRUE;
  529. }
  530. #endif
  531.