home *** CD-ROM | disk | FTP | other *** search
/ Large Pack of OldSkool DOS MOD Trackers / goattracker_2.74_stereo.zip / src / gsound.c < prev    next >
C/C++ Source or Header  |  2014-07-23  |  14KB  |  559 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 lefthardsid = 0;
  17. int righthardsid = 0;
  18. int usecatweasel = 0;
  19. int initted = 0;
  20. int firsttimeinit = 1;
  21. unsigned framerate = PALFRAMERATE;
  22. Sint16 *lbuffer = NULL;
  23. Sint16 *rbuffer = NULL;
  24.  
  25. FILE *writehandle = NULL;
  26.  
  27. void sound_playrout(void);
  28. void sound_mixer(Sint32 *dest, unsigned samples);
  29. Uint32 sound_timer(Uint32 interval);
  30.  
  31. #ifdef __WIN32__
  32.  
  33. // Win32 HardSID output
  34. typedef void (CALLBACK* lpWriteToHardSID)(Uint8 DeviceID, Uint8 SID_reg, Uint8 Data);
  35. typedef Uint8 (CALLBACK* lpReadFromHardSID)(Uint8 DeviceID, Uint8 SID_reg);
  36. typedef void (CALLBACK* lpInitHardSID_Mapper)(void);
  37. typedef void (CALLBACK* lpMuteHardSID_Line)(int Mute);
  38. typedef void (CALLBACK* lpHardSID_Delay)(Uint8 DeviceID, Uint16 Cycles);
  39. typedef void (CALLBACK* lpHardSID_Write)(Uint8 DeviceID, Uint16 Cycles, Uint8 SID_reg, Uint8 Data);
  40. typedef void (CALLBACK* lpHardSID_Flush)(Uint8 DeviceID);
  41. typedef void (CALLBACK* lpHardSID_SoftFlush)(Uint8 DeviceID);
  42. lpWriteToHardSID WriteToHardSID = NULL;
  43. lpReadFromHardSID ReadFromHardSID = NULL;
  44. lpInitHardSID_Mapper InitHardSID_Mapper = NULL;
  45. lpMuteHardSID_Line MuteHardSID_Line = NULL;
  46. lpHardSID_Delay HardSID_Delay = NULL;
  47. lpHardSID_Write HardSID_Write = NULL;
  48. lpHardSID_Flush HardSID_Flush = NULL;
  49. lpHardSID_SoftFlush HardSID_SoftFlush = NULL;
  50. HINSTANCE hardsiddll = 0;
  51. int dll_initialized = FALSE;
  52. // Cycle-exact HardSID support
  53. int cycleexacthardsid = FALSE;
  54. SDL_Thread* playerthread = NULL;
  55. SDL_mutex* flushmutex = NULL;
  56. volatile int runplayerthread = FALSE;
  57. volatile int flushplayerthread = FALSE;
  58. volatile int suspendplayroutine = FALSE;
  59. int sound_thread(void *userdata);
  60.  
  61. void InitHardDLL(void);
  62.  
  63. // Win32 CatWeasel MK3 PCI output
  64. #define SID_SID_PEEK_POKE   CTL_CODE(FILE_DEVICE_SOUND,0x0800UL + 1,METHOD_BUFFERED,FILE_ANY_ACCESS)
  65. HANDLE catweaselhandle;
  66.  
  67. #else
  68.  
  69. // Unix HardSID & CatWeasel output
  70. int lefthardsidfd = -1;
  71. int righthardsidfd = -1;
  72. int catweaselfd = -1;
  73.  
  74. #endif
  75.  
  76. int sound_init(unsigned b, unsigned mr, unsigned writer, unsigned hardsid, unsigned m, unsigned ntsc, unsigned multiplier, unsigned catweasel, unsigned interpolate, unsigned customclockrate)
  77. {
  78.   int c;
  79.  
  80.   #ifdef __WIN32__
  81.   if (!flushmutex)
  82.       flushmutex = SDL_CreateMutex();
  83.   #endif
  84.  
  85.   sound_uninit();
  86.  
  87.   if (multiplier)
  88.   {
  89.     if (ntsc)
  90.     {
  91.       framerate = NTSCFRAMERATE * multiplier;
  92.       snd_bpmtempo = 150 * multiplier;
  93.     }
  94.     else
  95.     {
  96.       framerate = PALFRAMERATE * multiplier;
  97.       snd_bpmtempo = 125 * multiplier;
  98.     }
  99.   }
  100.   else
  101.   {
  102.     if (ntsc)
  103.     {
  104.       framerate = NTSCFRAMERATE / 2;
  105.       snd_bpmtempo = 150 / 2;
  106.     }
  107.     else
  108.     {
  109.       framerate = PALFRAMERATE / 2;
  110.       snd_bpmtempo = 125 / 2;
  111.     }
  112.   }
  113.  
  114.   if (hardsid)
  115.   {
  116.     lefthardsid = (hardsid & 0xf) - 1;
  117.     righthardsid = ((hardsid >> 4) & 0xf) - 1;
  118.  
  119.     if ((righthardsid == lefthardsid) || (righthardsid < 0))
  120.       righthardsid = lefthardsid + 1;
  121.  
  122.     #ifdef __WIN32__
  123.     InitHardDLL();
  124.     if (dll_initialized)
  125.     {
  126.       usehardsid = hardsid;
  127.  
  128.       for (c = 0; c < NUMSIDREGS; c++)
  129.       {
  130.         sidreg[c] = 0;
  131.         WriteToHardSID(lefthardsid, c, 0x00);
  132.         WriteToHardSID(righthardsid, c, 0x00);
  133.       }
  134.       MuteHardSID_Line(FALSE);
  135.     }
  136.     else return 0;
  137.     if (!cycleexacthardsid)
  138.     {
  139.       SDL_SetTimer(1000 / framerate, sound_timer);
  140.     }
  141.     else
  142.     {
  143.       runplayerthread = TRUE;
  144.       playerthread = SDL_CreateThread(sound_thread, NULL);
  145.       if (!playerthread) return 0;
  146.     }
  147.     #else
  148.     {
  149.     char filename[80];
  150.     sprintf(filename, "/dev/sid%d", lefthardsid);
  151.     lefthardsidfd = open(filename, O_WRONLY, S_IREAD|S_IWRITE);
  152.     sprintf(filename, "/dev/sid%d", righthardsid);
  153.     righthardsidfd = open(filename, O_WRONLY, S_IREAD|S_IWRITE);
  154.     if ((lefthardsidfd >= 0) && (righthardsidfd >= 0))
  155.     {
  156.       usehardsid = hardsid;
  157.       for (c = 0; c < NUMSIDREGS; c++)
  158.       {
  159.         Uint32 dataword = c << 8;
  160.         write(lefthardsidfd, &dataword, 4);
  161.         write(righthardsidfd, &dataword, 4);
  162.       }
  163.     }
  164.     else return 0;
  165.     SDL_SetTimer(1000 / framerate, sound_timer);
  166.     }
  167.     #endif
  168.     goto SOUNDOK;
  169.   }
  170.  
  171.   if (catweasel)
  172.   {
  173.     #ifdef __WIN32__
  174.     catweaselhandle = CreateFile("\\\\.\\SID6581_1", GENERIC_READ, FILE_SHARE_WRITE|FILE_SHARE_READ, 0L,
  175.       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0L);
  176.     if (catweaselhandle == INVALID_HANDLE_VALUE)
  177.       return 0;
  178.     #else
  179.     catweaselfd = open("/dev/sid", O_WRONLY);
  180.     if (catweaselfd < 0)
  181.       catweaselfd = open("/dev/misc/sid", O_WRONLY);
  182.     if (catweaselfd < 0)
  183.       return 0;
  184.     #ifndef __amigaos__
  185.     if (ntsc)
  186.       ioctl(catweaselfd, CWSID_IOCTL_NTSC);
  187.     else
  188.       ioctl(catweaselfd, CWSID_IOCTL_PAL);
  189.     #endif
  190.     #endif
  191.  
  192.     usecatweasel = 1;
  193.     SDL_SetTimer(1000 / framerate, sound_timer);
  194.     goto SOUNDOK;
  195.   }
  196.  
  197.   if (!lbuffer) lbuffer = malloc(MIXBUFFERSIZE * sizeof(Sint16));
  198.   if (!rbuffer) rbuffer = malloc(MIXBUFFERSIZE * sizeof(Sint16));
  199.   if ((!lbuffer) || (!rbuffer)) 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|STEREO, 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 (lbuffer)
  267.   {
  268.       free(lbuffer);
  269.       lbuffer = NULL;
  270.   }
  271.   if (rbuffer)
  272.   {
  273.       free(rbuffer);
  274.       rbuffer = NULL;
  275.   }
  276.  
  277.   if (usehardsid)
  278.   {
  279.     #ifdef __WIN32__
  280.     for (c = 0; c < NUMSIDREGS; c++)
  281.     {
  282.       WriteToHardSID(lefthardsid, c, 0x00);
  283.       WriteToHardSID(righthardsid, c, 0x00);
  284.     }
  285.     MuteHardSID_Line(TRUE);
  286.     #else
  287.     if ((lefthardsidfd >= 0) && (righthardsidfd >= 0))
  288.     {
  289.       for (c = 0; c < NUMSIDREGS; c++)
  290.       {
  291.         Uint32 dataword = c << 8;
  292.         write(lefthardsidfd, &dataword, 4);
  293.         write(righthardsidfd, &dataword, 4);
  294.       }
  295.       close(lefthardsidfd);
  296.       close(righthardsidfd);
  297.       lefthardsidfd = -1;
  298.       righthardsidfd = -1;
  299.     }
  300.     #endif
  301.   }
  302.  
  303.   if (usecatweasel)
  304.   {
  305.     #ifdef __WIN32__
  306.     DWORD w;
  307.     unsigned char buf[NUMSIDREGS * 2];
  308.     for (w = 0; w < NUMSIDREGS; w++)
  309.     {
  310.       buf[w*2] = 0x18 - w;
  311.       buf[w*2+1] = 0;
  312.     }
  313.     DeviceIoControl(catweaselhandle, SID_SID_PEEK_POKE, buf, sizeof(buf), 0L, 0UL, &w, 0L);
  314.     CloseHandle(catweaselhandle);
  315.     catweaselhandle = INVALID_HANDLE_VALUE;
  316.     #else
  317.     if (catweaselfd >= 0)
  318.     {
  319.       unsigned char buf[NUMSIDREGS];
  320.       memset(buf, 0, sizeof(buf));
  321.       lseek(catweaselfd, 0, SEEK_SET);
  322.       write(catweaselfd, buf, sizeof(buf));
  323.       close(catweaselfd);
  324.       catweaselfd = -1;
  325.     }
  326.     #endif
  327.   }
  328. }
  329.  
  330. void sound_suspend(void)
  331. {
  332.   #ifdef __WIN32__
  333.   SDL_LockMutex(flushmutex);
  334.   suspendplayroutine = TRUE;
  335.   SDL_UnlockMutex(flushmutex);
  336.   #endif
  337. }
  338.  
  339. void sound_flush(void)
  340. {
  341.   #ifdef __WIN32__
  342.   SDL_LockMutex(flushmutex);
  343.   flushplayerthread = TRUE;
  344.   SDL_UnlockMutex(flushmutex);
  345.   #endif
  346. }
  347.  
  348. Uint32 sound_timer(Uint32 interval)
  349. {
  350.   if (!initted) return interval;
  351.   sound_playrout();
  352.   return interval;
  353. }
  354.  
  355. #ifdef __WIN32__
  356. int sound_thread(void *userdata)
  357. {
  358.   unsigned long flush_cycles_interactive = hardsidbufinteractive * 1000; /* 0 = flush off for interactive mode*/
  359.   unsigned long flush_cycles_playback = hardsidbufplayback * 1000; /* 0 = flush off for playback mode*/
  360.   unsigned long cycles_after_flush = 0;
  361.   boolean interactive;
  362.  
  363.   while (runplayerthread)
  364.   {
  365.     unsigned cycles = 1000000 / framerate; // HardSID should be clocked at 1MHz
  366.     int c;
  367.  
  368.     if (flush_cycles_interactive > 0 || flush_cycles_playback > 0)
  369.     {
  370.       cycles_after_flush += cycles;
  371.     }
  372.  
  373.       // Do flush if starting playback, stopping playback, starting an interactive note etc.
  374.     if (flushplayerthread)
  375.     {
  376.         SDL_LockMutex(flushmutex);
  377.       if (HardSID_Flush)
  378.       {
  379.         HardSID_Flush(lefthardsid);
  380.       }
  381.       // Can clear player suspend now (if set)
  382.       suspendplayroutine = FALSE;
  383.       flushplayerthread = FALSE;
  384.       SDL_UnlockMutex(flushmutex);
  385.  
  386.       SDL_Delay(0);
  387.     }
  388.  
  389.     if (!suspendplayroutine) playroutine();
  390.  
  391.     interactive = !(boolean)recordmode /* jam mode */ || !(boolean)isplaying();
  392.  
  393.     // Left side
  394.     for (c = 0; c < NUMSIDREGS; c++)
  395.     {
  396.       unsigned o = sid_getorder(c);
  397.  
  398.       // Extra delay before loading the waveform (and mt_chngate,x)
  399.       if ((o == 4) || (o == 11) || (o == 18))
  400.       {
  401.         HardSID_Write(lefthardsid, SIDWRITEDELAY+SIDWAVEDELAY, o, sidreg[o]);
  402.         cycles -= SIDWRITEDELAY+SIDWAVEDELAY;
  403.       }
  404.       else 
  405.       {
  406.         HardSID_Write(lefthardsid, SIDWRITEDELAY, o, sidreg[o]);
  407.         cycles -= SIDWRITEDELAY;
  408.       }
  409.     }
  410.     
  411.     // Right side
  412.     for (c = 0; c < NUMSIDREGS; c++)
  413.     {
  414.       unsigned o = sid_getorder(c);
  415.  
  416.       // Extra delay before loading the waveform (and mt_chngate,x)
  417.       if ((o == 4) || (o == 11) || (o == 18))
  418.       {
  419.         HardSID_Write(righthardsid, SIDWRITEDELAY+SIDWAVEDELAY, o, sidreg2[o]);
  420.         cycles -= SIDWRITEDELAY+SIDWAVEDELAY;
  421.       }
  422.       else 
  423.       {
  424.         HardSID_Write(righthardsid, SIDWRITEDELAY, o, sidreg2[o]);
  425.         cycles -= SIDWRITEDELAY;
  426.       }
  427.     }
  428.  
  429.     // Now wait the rest of frame
  430.     while (cycles)
  431.     {
  432.       unsigned runnow = cycles;
  433.       if (runnow > 65535) runnow = 65535;
  434.       HardSID_Delay(lefthardsid, runnow);
  435.       cycles -= runnow;
  436.     }
  437.  
  438.     if ((flush_cycles_interactive>0 && interactive && cycles_after_flush>=flush_cycles_interactive) ||
  439.       (flush_cycles_playback>0 && !interactive && cycles_after_flush>=flush_cycles_playback)) 
  440.     {
  441.       if (HardSID_SoftFlush)
  442.         HardSID_SoftFlush(lefthardsid);
  443.       cycles_after_flush = 0;
  444.     }
  445.   }
  446.  
  447.   unsigned r;
  448.  
  449.   for (r = 0; r < NUMSIDREGS; r++)
  450.   {
  451.     HardSID_Write(lefthardsid, SIDWRITEDELAY, r, 0);
  452.     HardSID_Write(righthardsid, SIDWRITEDELAY, r, 0);
  453.   }
  454.   if (HardSID_SoftFlush)
  455.     HardSID_SoftFlush(lefthardsid);
  456.  
  457.   return 0;
  458. }
  459. #endif
  460.  
  461. void sound_playrout(void)
  462. {
  463.   int c;
  464.  
  465.   playroutine();
  466.   if (usehardsid)
  467.   {
  468.     #ifdef __WIN32__
  469.     for (c = 0; c < NUMSIDREGS; c++)
  470.     {
  471.       unsigned o = sid_getorder(c);
  472.       WriteToHardSID(lefthardsid, o, sidreg[o]);
  473.       WriteToHardSID(righthardsid, o, sidreg2[o]);
  474.     }
  475.     #else
  476.     for (c = 0; c < NUMSIDREGS; c++)
  477.     {
  478.       unsigned o = sid_getorder(c);
  479.       Uint32 dataword = (o << 8) | sidreg[o];
  480.       write(lefthardsidfd, &dataword, 4);
  481.       dataword = (o << 8) | sidreg2[o];
  482.       write(righthardsidfd, &dataword, 4);
  483.     }
  484.     #endif
  485.   }
  486.   else if (usecatweasel)
  487.   {
  488.     #ifdef __WIN32__
  489.     DWORD w;
  490.     unsigned char buf[NUMSIDREGS * 2];
  491.  
  492.     for(w = 0; w < NUMSIDREGS; w++)
  493.     {
  494.       unsigned o = sid_getorder(w);
  495.  
  496.       buf[w*2] = o;
  497.       buf[w*2+1] = sidreg[o];
  498.     }
  499.     DeviceIoControl(catweaselhandle, SID_SID_PEEK_POKE, buf, sizeof(buf), 0L, 0UL, &w, 0L);
  500.     #else
  501.     for (c = 0; c < NUMSIDREGS; c++)
  502.     {
  503.       unsigned o = sid_getorder(c);
  504.  
  505.       lseek(catweaselfd, o, SEEK_SET);
  506.       write(catweaselfd, &sidreg[o], 1);
  507.     }
  508.     #endif
  509.   }
  510. }
  511.  
  512. void sound_mixer(Sint32 *dest, unsigned samples)
  513. {
  514.   int c;
  515.  
  516.   if (!initted) return;
  517.   if (samples > MIXBUFFERSIZE) return;
  518.  
  519.   sid_fillbuffer(lbuffer, rbuffer, samples);
  520.   if (writehandle)
  521.   {
  522.     for (c = 0; c < samples; c++)
  523.     {
  524.       fwrite(&lbuffer[c], sizeof(Sint16), 1, writehandle);
  525.       fwrite(&rbuffer[c], sizeof(Sint16), 1, writehandle);
  526.     }
  527.   }
  528.   for (c = 0; c < samples; c++)
  529.   {
  530.     dest[c*2] = lbuffer[c];
  531.     dest[c*2+1] = rbuffer[c];
  532.   }
  533. }
  534.  
  535. #ifdef __WIN32__
  536. void InitHardDLL()
  537. {
  538.   if (!(hardsiddll=LoadLibrary("HARDSID.DLL"))) return;
  539.  
  540.   WriteToHardSID = (lpWriteToHardSID) GetProcAddress(hardsiddll, "WriteToHardSID");
  541.   ReadFromHardSID = (lpReadFromHardSID) GetProcAddress(hardsiddll, "ReadFromHardSID");
  542.   InitHardSID_Mapper = (lpInitHardSID_Mapper) GetProcAddress(hardsiddll, "InitHardSID_Mapper");
  543.   MuteHardSID_Line = (lpMuteHardSID_Line) GetProcAddress(hardsiddll, "MuteHardSID_Line");
  544.  
  545.   if (!WriteToHardSID) return;
  546.  
  547.   // Try to get cycle-exact interface
  548.   HardSID_Delay = (lpHardSID_Delay) GetProcAddress(hardsiddll, "HardSID_Delay");
  549.   HardSID_Write = (lpHardSID_Write) GetProcAddress(hardsiddll, "HardSID_Write");
  550.   HardSID_Flush = (lpHardSID_Flush) GetProcAddress(hardsiddll, "HardSID_Flush");
  551.   HardSID_SoftFlush = (lpHardSID_SoftFlush) GetProcAddress(hardsiddll, "HardSID_SoftFlush");
  552.   if ((HardSID_Delay) && (HardSID_Write) && (HardSID_Flush) && (HardSID_SoftFlush))
  553.     cycleexacthardsid = TRUE;
  554.   
  555.   InitHardSID_Mapper();
  556.   dll_initialized = TRUE;
  557. }
  558. #endif
  559.