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