home *** CD-ROM | disk | FTP | other *** search
/ Large Pack of OldSkool DOS MOD Trackers / goattracker_2.68.zip / src / gsound.c < prev    next >
C/C++ Source or Header  |  2009-01-03  |  12KB  |  499 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.   if (!buffer) 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 & 1, customclockrate, interpolate >> 1);
  197.  
  198.   snd_player = &sound_playrout;
  199.   snd_setcustommixer(sound_mixer);
  200.  
  201.   SOUNDOK:
  202.   initted = 1;
  203.   return 1;
  204. }
  205.  
  206. void sound_uninit(void)
  207. {
  208.   int c;
  209.  
  210.   if (!initted) return;
  211.   initted = 0;
  212.  
  213.   // Apparently a delay is needed to make sure the sound timer thread is
  214.   // not mixing stuff anymore, and we can safely delete related structures
  215.   SDL_Delay(50);
  216.  
  217.   if (usehardsid || usecatweasel)
  218.   {
  219.     #ifdef __WIN32__
  220.     if (!playerthread)
  221.     {
  222.       SDL_SetTimer(0, NULL);
  223.     }
  224.     else
  225.     {
  226.       runplayerthread = FALSE;
  227.       SDL_WaitThread(playerthread, NULL);
  228.       playerthread = NULL;
  229.     }
  230.     #else
  231.     SDL_SetTimer(0, NULL);
  232.     #endif
  233.   }
  234.   else
  235.   {
  236.       snd_setcustommixer(NULL);
  237.     snd_player = NULL;
  238.   }
  239.  
  240.   if (writehandle)
  241.   {
  242.     fclose(writehandle);
  243.     writehandle = NULL;
  244.   }
  245.   
  246.   if (buffer)
  247.   {
  248.     free(buffer);
  249.     buffer = NULL;
  250.   }
  251.  
  252.   if (usehardsid)
  253.   {
  254.     #ifdef __WIN32__
  255.     for (c = 0; c < NUMSIDREGS; c++)
  256.     {
  257.       WriteToHardSID(usehardsid-1, c, 0x00);
  258.     }
  259.     MuteHardSID_Line(TRUE);
  260.     #else
  261.     if (hardsidfd >= 0)
  262.     {
  263.       for (c = 0; c < NUMSIDREGS; c++)
  264.       {
  265.         Uint32 dataword = c << 8;
  266.         write(hardsidfd, &dataword, 4);
  267.       }
  268.       close(hardsidfd);
  269.       hardsidfd = -1;
  270.     }
  271.     #endif
  272.   }
  273.  
  274.   if (usecatweasel)
  275.   {
  276.     #ifdef __WIN32__
  277.     DWORD w;
  278.     unsigned char buf[NUMSIDREGS * 2];
  279.     for (w = 0; w < NUMSIDREGS; w++)
  280.     {
  281.       buf[w*2] = 0x18 - w;
  282.       buf[w*2+1] = 0;
  283.     }
  284.     DeviceIoControl(catweaselhandle, SID_SID_PEEK_POKE, buf, sizeof(buf), 0L, 0UL, &w, 0L);
  285.     CloseHandle(catweaselhandle);
  286.     catweaselhandle = INVALID_HANDLE_VALUE;
  287.     #else
  288.     if (catweaselfd >= 0)
  289.     {
  290.       unsigned char buf[NUMSIDREGS];
  291.       memset(buf, 0, sizeof(buf));
  292.       lseek(catweaselfd, 0, SEEK_SET);
  293.       write(catweaselfd, buf, sizeof(buf));
  294.       close(catweaselfd);
  295.       catweaselfd = -1;
  296.     }
  297.     #endif
  298.   }
  299. }
  300.  
  301. void sound_suspend(void)
  302. {
  303.   #ifdef __WIN32__
  304.   SDL_LockMutex(flushmutex);
  305.   suspendplayroutine = TRUE;
  306.   SDL_UnlockMutex(flushmutex);
  307.   #endif
  308. }
  309.  
  310. void sound_flush(void)
  311. {
  312.   #ifdef __WIN32__
  313.   SDL_LockMutex(flushmutex);
  314.   flushplayerthread = TRUE;
  315.   SDL_UnlockMutex(flushmutex);
  316.   #endif
  317. }
  318.  
  319. Uint32 sound_timer(Uint32 interval)
  320. {
  321.   if (!initted) return interval;
  322.   sound_playrout();
  323.   return interval;
  324. }
  325.  
  326. #ifdef __WIN32__
  327. int sound_thread(void *userdata)
  328. {
  329.   unsigned long flush_cycles_interactive = hardsidbufinteractive * 1000; /* 0 = flush off for interactive mode*/
  330.   unsigned long flush_cycles_playback = hardsidbufplayback * 1000; /* 0 = flush off for playback mode*/
  331.   unsigned long cycles_after_flush = 0;
  332.   boolean interactive;
  333.  
  334.   while (runplayerthread)
  335.   {
  336.     unsigned cycles = 1000000 / framerate; // HardSID should be clocked at 1MHz
  337.     int c;
  338.  
  339.     if (flush_cycles_interactive > 0 || flush_cycles_playback > 0)
  340.     {
  341.       cycles_after_flush += cycles;
  342.     }
  343.  
  344.     // Do flush if starting playback, stopping playback, starting an interactive note etc.
  345.     if (flushplayerthread)
  346.     {
  347.       SDL_LockMutex(flushmutex);
  348.       if (HardSID_Flush)
  349.       {
  350.         HardSID_Flush(usehardsid-1);
  351.       }
  352.       // Can clear player suspend now (if set)
  353.       suspendplayroutine = FALSE;
  354.       flushplayerthread = FALSE;
  355.       SDL_UnlockMutex(flushmutex);
  356.  
  357.       SDL_Delay(0);
  358.     }
  359.  
  360.     if (!suspendplayroutine) playroutine();
  361.  
  362.     interactive = !(boolean)recordmode /* jam mode */ || !(boolean)isplaying();
  363.  
  364.     for (c = 0; c < NUMSIDREGS; c++)
  365.     {
  366.       unsigned o = sid_getorder(c);
  367.  
  368.         // Extra delay before loading the waveform (and mt_chngate,x)
  369.         if ((o == 4) || (o == 11) || (o == 18))
  370.         {
  371.         HardSID_Write(usehardsid-1, SIDWRITEDELAY+SIDWAVEDELAY, o, sidreg[o]);
  372.           cycles -= SIDWRITEDELAY+SIDWAVEDELAY;
  373.       }
  374.         else
  375.       {
  376.             HardSID_Write(usehardsid-1, SIDWRITEDELAY, o, sidreg[o]);
  377.             cycles -= SIDWRITEDELAY;
  378.         }
  379.     }
  380.  
  381.     // Now wait the rest of frame
  382.     while (cycles)
  383.     {
  384.       unsigned runnow = cycles;
  385.       if (runnow > 65535) runnow = 65535;
  386.       HardSID_Delay(usehardsid-1, runnow);
  387.       cycles -= runnow;
  388.     }
  389.  
  390.       if ((flush_cycles_interactive>0 && interactive && cycles_after_flush>=flush_cycles_interactive) ||
  391.           (flush_cycles_playback>0 && !interactive && cycles_after_flush>=flush_cycles_playback))
  392.     {
  393.       if (HardSID_SoftFlush)
  394.         HardSID_SoftFlush(usehardsid-1);
  395.           cycles_after_flush = 0;
  396.     }
  397.   }
  398.  
  399.   unsigned r;
  400.  
  401.   for (r = 0; r < NUMSIDREGS; r++)
  402.   {
  403.     HardSID_Write(usehardsid-1, SIDWRITEDELAY, r, 0);
  404.   }
  405.   if (HardSID_SoftFlush)
  406.     HardSID_SoftFlush(usehardsid-1);
  407.  
  408.   return 0;
  409. }
  410. #endif
  411.  
  412. void sound_playrout(void)
  413. {
  414.   int c;
  415.  
  416.   playroutine();
  417.   if (usehardsid)
  418.   {
  419.     #ifdef __WIN32__
  420.     for (c = 0; c < NUMSIDREGS; c++)
  421.     {
  422.       unsigned o = sid_getorder(c);
  423.       WriteToHardSID(usehardsid-1, o, sidreg[o]);
  424.     }
  425.     #else
  426.     for (c = 0; c < NUMSIDREGS; c++)
  427.     {
  428.       unsigned o = sid_getorder(c);
  429.       Uint32 dataword = (o << 8) | sidreg[o];
  430.       write(hardsidfd, &dataword, 4);
  431.     }
  432.     #endif
  433.   }
  434.   else if (usecatweasel)
  435.   {
  436.     #ifdef __WIN32__
  437.     DWORD w;
  438.     unsigned char buf[NUMSIDREGS * 2];
  439.  
  440.     for(w = 0; w < NUMSIDREGS; w++)
  441.     {
  442.       unsigned o = sid_getorder(w);
  443.  
  444.       buf[w*2] = o;
  445.       buf[w*2+1] = sidreg[o];
  446.     }
  447.     DeviceIoControl(catweaselhandle, SID_SID_PEEK_POKE, buf, sizeof(buf), 0L, 0UL, &w, 0L);
  448.     #else
  449.     for (c = 0; c < NUMSIDREGS; c++)
  450.     {
  451.       unsigned o = sid_getorder(c);
  452.  
  453.       lseek(catweaselfd, o, SEEK_SET);
  454.       write(catweaselfd, &sidreg[o], 1);
  455.     }
  456.     #endif
  457.   }
  458. }
  459.  
  460. void sound_mixer(Sint32 *dest, unsigned samples)
  461. {
  462.   int c;
  463.  
  464.   if (!initted) return;
  465.   if (samples > MIXBUFFERSIZE) return;
  466.   if (!buffer) return;
  467.  
  468.   sid_fillbuffer(buffer, samples);
  469.   if (writehandle)
  470.     fwrite(buffer, samples * sizeof(Uint16), 1, writehandle);
  471.  
  472.   for (c = 0; c < samples; c++)
  473.     dest[c] = buffer[c];
  474. }
  475.  
  476. #ifdef __WIN32__
  477. void InitHardDLL()
  478. {
  479.   if (!(hardsiddll=LoadLibrary("HARDSID.DLL"))) return;
  480.  
  481.   WriteToHardSID = (lpWriteToHardSID) GetProcAddress(hardsiddll, "WriteToHardSID");
  482.   ReadFromHardSID = (lpReadFromHardSID) GetProcAddress(hardsiddll, "ReadFromHardSID");
  483.   InitHardSID_Mapper = (lpInitHardSID_Mapper) GetProcAddress(hardsiddll, "InitHardSID_Mapper");
  484.   MuteHardSID_Line = (lpMuteHardSID_Line) GetProcAddress(hardsiddll, "MuteHardSID_Line");
  485.  
  486.   if (!WriteToHardSID) return;
  487.  
  488.   // Try to get cycle-exact interface
  489.   HardSID_Delay = (lpHardSID_Delay) GetProcAddress(hardsiddll, "HardSID_Delay");
  490.   HardSID_Write = (lpHardSID_Write) GetProcAddress(hardsiddll, "HardSID_Write");
  491.   HardSID_Flush = (lpHardSID_Flush) GetProcAddress(hardsiddll, "HardSID_Flush");
  492.   HardSID_SoftFlush = (lpHardSID_SoftFlush) GetProcAddress(hardsiddll, "HardSID_SoftFlush");
  493.   if ((HardSID_Delay) && (HardSID_Write)) cycleexacthardsid = TRUE;
  494.  
  495.   InitHardSID_Mapper();
  496.   dll_initialized = TRUE;
  497. }
  498. #endif
  499.