找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 5369|回复: 6

【DOS】C语言写的声卡(Sound Blaster 16)驱动

[复制链接]
发表于 2015-9-14 00:52:18 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
转载请注明出处:http://www.0xaa55.com/thread-1514-1-1.html

经过实际的测试,可以使DOSBOX、Virtual PC虚拟的DOS、Virtual Box虚拟的DOS、VMware虚拟的DOS播放WAV音乐(支持44100 Hz 16-bit CD音质)
这就是编写能播放音乐的DOS游戏所需的玩意儿了。
目前的代码对Sound Blaster 16(版本4.xx)的支持比较好,但是对低版本的(2.00以下"SBLO")支持不太好。现在已经解决了播放声音时有杂音的问题。原先的代码没有搞对时序。
但是现在遇到的问题是播放MIDI的时候,貌似不能在VMware虚拟的DOS中播放MIDI音乐。但是可以在DOSBOX中正常播放。
这个驱动是纯C写的。所以可以拿去给你的DOS游戏作为声音模块使用。
编译器用的是WATCOM C。
20150914004744.png

BIN: demo.7z (28.88 KB, 下载次数: 8)
整个程序的所有源码,回帖后即可下载。
游客,如果您要查看本帖隐藏内容请回复


编译器:WATCOM C
http://www.0xaa55.com/thread-1329-1-1.html

参考资料:
【PDF】Sound Blaster 16 声霸卡驱动编写向导 英文
http://www.0xaa55.com/thread-1500-1-1.html
【DOS】混合语言实现WAV文件播放的程序,声霸卡驱动源码
http://www.0xaa55.com/thread-125-1-1.html
【C语言】Midi文件播放器(可跨平台)
http://www.0xaa55.com/forum.php? ... =1489&fromuid=1

下面放出最关键的代码。
  1. #include"sb.h"
  2. #include<dos.h>
  3. #include<time.h>
  4. #include<ctype.h>
  5. #include<conio.h>
  6. #include<stdio.h>
  7. #include<stdarg.h>
  8. #include<stdlib.h>
  9. #include<memory.h>

  10. SBInfo_t g_SBInfo={0};

  11. #define g_Port                                g_SBInfo.IOInfo.PortNum
  12. #define g_Version                        g_SBInfo.HWInfo.Version
  13. #define g_DMAL                                g_SBInfo.IOInfo.DMAL
  14. #define g_DMALAddr                        g_SBInfo.DMAInfo.DMALAddr
  15. #define g_DMALCount                        g_SBInfo.DMAInfo.DMALCount
  16. #define g_DMALPage                        g_SBInfo.DMAInfo.DMALPage
  17. #define g_DMAH                                g_SBInfo.IOInfo.DMAH
  18. #define g_DMAHAddr                        g_SBInfo.DMAInfo.DMAHAddr
  19. #define g_DMAHCount                        g_SBInfo.DMAInfo.DMAHCount
  20. #define g_DMAHPage                        g_SBInfo.DMAInfo.DMAHPage
  21. #define g_IRQ                                g_SBInfo.IOInfo.IRQ
  22. #define g_BufAddr                        g_SBInfo.pBufAddr
  23. #define g_BufSize                        g_SBInfo.BufSize
  24. #define g_bPlaying8                        g_SBInfo.bPlaying8
  25. #define g_bPlaying16                g_SBInfo.bPlaying16
  26. #define g_bRecording8                g_SBInfo.bRecording8
  27. #define g_bRecording16                g_SBInfo.bRecording16
  28. #define g_bFirstBuf                        g_SBInfo.bFirstBuf
  29. #define g_OnBuffer                        g_SBInfo.pfnOnBuffer
  30. #define g_Print                                g_SBInfo.pfnOnDebugOutput

  31. #define Far2Phys(f) (((uint32_t)f & 0xFFFF) + ((uint32_t)f >> 12))

  32. #define SBPort_BaseBegin        0x210
  33. #define SBPort_BaseStep                0x10
  34. #define SBPort_BaseEnd                0x260

  35. #define SBPort_MixerRegNum        0x04
  36. #define SBPort_MixerRegVal        0x05
  37. #define SBPort_Reset                0x06
  38. #define SBPort_Read                        0x0A
  39. #define SBPort_Write                0x0C
  40. #define SBPort_WBufState        0x0C
  41. #define SBPort_RBufState        0x0E
  42. #define SBPort_Ack8                        0x0E
  43. #define SBPort_Ack16                0x0F

  44. #define SBMixer_VoiceVol        0x04
  45. #define SBMixer_MicVol                0x0A
  46. #define SBMixer_MasterVol        0x22

  47. //Programmable Interrupt Controller
  48. #define        PIC_MASK                        0x21
  49. #define        PIC_MODE                        0x20
  50. #define        PIC2_MASK                        0xA1
  51. #define        PIC2_MODE                        0xA0

  52. #define        PIC_EOI                                0x20
  53. #define        PIC_SPECEOI                        0x60

  54. #define        PIC_IRQ0_7BEGIN                0x08
  55. #define        PIC_IRQ8_FBEGIN                0x70

  56. #define        PIC_INTNUM(x)                ((x>7)?PIC_IRQ8_FBEGIN+(x):PIC_IRQ0_7BEGIN+(x))

  57. //DMA
  58. #define DMA8_FF_REG                        0x0C
  59. #define DMA8_MASK_REG                0x0A
  60. #define DMA8_MODE_REG                0x0B

  61. #define DMA16_FF_REG                0xD8
  62. #define DMA16_MASK_REG                0xD4
  63. #define DMA16_MODE_REG                0xD6

  64. #define DMA0_ADDR                        0x00
  65. #define DMA0_COUNT                        0x01
  66. #define DMA0_PAGE                        0x87

  67. #define DMA1_ADDR                        0x02
  68. #define DMA1_COUNT                        0x03
  69. #define DMA1_PAGE                        0x83

  70. #define DMA2_ADDR                        0x04
  71. #define DMA2_COUNT                        0x05
  72. #define DMA2_PAGE                        0x81

  73. #define DMA3_ADDR                        0x06
  74. #define DMA3_COUNT                        0x07
  75. #define DMA3_PAGE                        0x82

  76. #define DMA4_ADDR                        0xC0
  77. #define DMA4_COUNT                        0xC2
  78. #define DMA4_PAGE                        0x8F

  79. #define DMA5_ADDR                        0xC4
  80. #define DMA5_COUNT                        0xC6
  81. #define DMA5_PAGE                        0x8B

  82. #define DMA6_ADDR                        0xC8
  83. #define DMA6_COUNT                        0xCA
  84. #define DMA6_PAGE                        0x89

  85. #define DMA7_ADDR                        0xCC
  86. #define DMA7_COUNT                        0xCE
  87. #define DMA7_PAGE                        0x8A

  88. //=============================================================================
  89. //Func: OnDebugOutput
  90. //Desc: Debug info output by Sound Blaster driver
  91. //-----------------------------------------------------------------------------
  92. void SBCallBack_t DefOnDebugOutput(char*format,...)
  93. {
  94.         va_list ap;
  95.         va_start(ap,format);
  96.         vfprintf(stderr,format,ap);
  97.         va_end(ap);
  98. }

  99. //=============================================================================
  100. //Func: SBIn
  101. //Desc: Read a byte at the Read Data port
  102. //-----------------------------------------------------------------------------
  103. SB_i(uint8_t,SBIn)(uint16_t uPortNum)
  104. {
  105.         while(!(inp(uPortNum+SBPort_RBufState) & 0x80));
  106.         return inp(uPortNum+SBPort_Read);
  107. }

  108. //=============================================================================
  109. //Func: SBOut
  110. //Desc: Write a byte to the Write Data port
  111. //-----------------------------------------------------------------------------
  112. SB_i(void,SBOut)(uint16_t uPortNum,uint8_t Data)
  113. {
  114.         while(inp(uPortNum+SBPort_WBufState) & 0x80);
  115.         outp(uPortNum+SBPort_Write,Data);
  116. }

  117. //=============================================================================
  118. //Func: SBGetMixerReg
  119. //Desc: Read a mixer register value
  120. //-----------------------------------------------------------------------------
  121. SB_i(uint8_t,SBGetMixerReg)(uint16_t uPortNum,uint8_t uMixerReg)
  122. {
  123.         if(g_Version<SBVer_SBPro)
  124.                 return 0;
  125.         outp(uPortNum+SBPort_MixerRegNum,uMixerReg);
  126.         return inp(uPortNum+SBPort_MixerRegVal);
  127. }

  128. //=============================================================================
  129. //Func: SBSetMixerReg
  130. //Desc: Write a mixer register value
  131. //-----------------------------------------------------------------------------
  132. SB_i(void,SBSetMixerReg)(uint16_t uPortNum,uint8_t uMixerReg,uint8_t uVal)
  133. {
  134.         if(g_Version<SBVer_SBPro)
  135.                 return;
  136.         outp(uPortNum+SBPort_MixerRegNum,uMixerReg);
  137.         outp(uPortNum+SBPort_MixerRegVal,uVal);
  138. }

  139. //=============================================================================
  140. //Func: SBReset
  141. //Desc: Initialize or reset the sound blaster
  142. //-----------------------------------------------------------------------------
  143. SB_i(bool_t,SBReset)(uint16_t uPortNum)
  144. {
  145.         clock_t c;
  146.        
  147.         //Write a "1" to the Reset port (2x6h) and wait for atleast 3 ms
  148.         outp(uPortNum+SBPort_Reset,1);
  149.        
  150.         //wait for 10 ms
  151.         delay(10);
  152.        
  153.         //Write a "0" to the Reset port
  154.         outp(uPortNum+SBPort_Reset,0);
  155.        
  156.         //Wait until it had finished initializing
  157.         c=clock();
  158.         while(!(inp(uPortNum+SBPort_RBufState) & 0x80))
  159.         {
  160.                 //quit when out of time
  161.                 if(clock()-c>CLOCKS_PER_SEC*200/1000)
  162.                         return false;
  163.         }
  164.        
  165.         if(inp(uPortNum+SBPort_Read)==0xAA)
  166.                 return true;
  167.         return false;
  168. }

  169. //=============================================================================
  170. //Func: SBGetIOInfoByEnv
  171. //Desc: Retrieve the informations from %BLASTER%
  172. //-----------------------------------------------------------------------------
  173. SB_i(bool_t,SBGetIOInfoByEnv)(SBIOInfo_p pIOInfo,char*szEnv)
  174. {
  175.         char Buf[5],SaveChar;
  176.         bool_t DMAFound = false;
  177.         bool_t IOPortFound = false;
  178.         bool_t IRQFound = false;
  179.         int i,mul;
  180.        
  181.         if(!szEnv)
  182.                 return false;
  183.        
  184.         do
  185.         {
  186.                 switch(*szEnv)
  187.                 {
  188.                 case'A':// I/O base port address found
  189.                 case'a':
  190.                         szEnv++;
  191.                         for (i = 0; i < 3; i++)  // Grab the digits
  192.                         {
  193.                                 if(*szEnv==' ')
  194.                                         break;
  195.                                 Buf[i] = *szEnv;
  196.                                 szEnv++;
  197.                         }
  198.                        
  199.                         // Convert to HEX
  200.                         mul = 1;
  201.                         pIOInfo->PortNum = 0;
  202.                         while(i--)
  203.                         {
  204.                                 int Digit;
  205.                                
  206.                                 if (Buf[i] >= '0' && Buf[i] <= '9')
  207.                                         Digit = Buf[i] - '0';
  208.                                 else if (Buf[i] >= 'A' && Buf[i] <= 'F')
  209.                                         Digit = Buf[i] - 'A' + 10;
  210.                                 else if (Buf[i] >= 'a' && Buf[i] <= 'f')
  211.                                         Digit = Buf[i] - 'a' + 10;

  212.                                 pIOInfo->PortNum += Digit * mul;
  213.                                 mul <<= 4;
  214.                         }
  215.                         IOPortFound=true;
  216.                         break;
  217.                        
  218.                 case'D': // 8-bit DMA channel
  219.                 case'd':
  220.                 case'H': // 16-bit DMA channel
  221.                 case'h':
  222.                 case'I': // IRQ number
  223.                 case'i':
  224.                         SaveChar=*szEnv++;
  225.                         Buf[0]=*szEnv++;
  226.                         if(isdigit(*szEnv))
  227.                         {
  228.                                 Buf[1]=*szEnv++;
  229.                                 Buf[2]='\0';
  230.                         }
  231.                         else
  232.                                 Buf[1]='\0';
  233.                         if(SaveChar=='D' || SaveChar=='d')
  234.                         {
  235.                                 pIOInfo->DMAL = atoi(Buf);
  236.                                 DMAFound=true;
  237.                         }
  238.                         else if(SaveChar=='H' || SaveChar=='h')
  239.                         {
  240.                                 pIOInfo->DMAH = atoi(Buf);
  241.                                 DMAFound=true;
  242.                         }
  243.                         else if(SaveChar=='I' || SaveChar=='i')
  244.                         {
  245.                                 pIOInfo->IRQ = atoi(Buf);
  246.                                 IRQFound=true;
  247.                         }
  248.                         break;
  249.                        
  250.                 default:
  251.                         szEnv++;
  252.                 }
  253.         }while(*szEnv);
  254.        
  255.         if(!IOPortFound || !DMAFound || !IRQFound)
  256.         {
  257.                 g_Print("Incorrect %%BLASTER%% env.\n");
  258.                 return false;
  259.         }
  260.         return true;
  261. }

  262. //=============================================================================
  263. //Func: SBGetHWInfo
  264. //Desc: Retrieve the hardware informations.
  265. //-----------------------------------------------------------------------------
  266. SB_i(void,SBGetHWInfo)(uint16_t uPortNum,SBHWInfo_p pHWInfo)
  267. {
  268.         SBOut(uPortNum,0xE1);//get version
  269.         pHWInfo->Version=SBIn(uPortNum);
  270.         pHWInfo->Version<<=8;
  271.         pHWInfo->Version|=SBIn(uPortNum);
  272. }

  273. //=============================================================================
  274. //Func: SBGetInfo
  275. //Desc: Retrieve the informations by IO.
  276. //Note: If failed getting info from BLASTER, the function will try to get the
  277. //      info by read it from the mixer register. But only SB16 supports it.
  278. //-----------------------------------------------------------------------------
  279. SB_i(bool_t,SBGetInfo)(SBIOInfo_p pIOInfo,SBHWInfo_p pHWInfo)
  280. {
  281.         if(SBGetIOInfoByEnv(pIOInfo,getenv("BLASTER")))
  282.         {
  283.                 pIOInfo->InfoFromEnv=true;
  284.                 SBGetHWInfo(pIOInfo->PortNum,pHWInfo);
  285.                 return true;
  286.         }
  287.         else
  288.         {
  289.                 uint16_t        Port;
  290.                 uint8_t                IRQBits;
  291.                 uint8_t                DMABits;
  292.                
  293.                 pIOInfo->InfoFromEnv=false;
  294.                
  295.                 //Scan the port to determine the port of the sound blaster
  296.                 for(Port=SBPort_BaseBegin;
  297.                         Port<=SBPort_BaseEnd;
  298.                         Port+=SBPort_BaseStep)
  299.                 {
  300.                         if(!SBReset(Port))
  301.                                 continue;
  302.                        
  303.                         pIOInfo->PortNum=Port;
  304.                        
  305.                         SBGetHWInfo(Port,pHWInfo);
  306.                        
  307.                         if(pHWInfo->Version<SBVer_SB16)
  308.                         {
  309.                                 pIOInfo->IRQ=5;
  310.                                 pIOInfo->DMAL=1;
  311.                                 pIOInfo->DMAH=5;
  312.                                 return true;
  313.                         }
  314.                        
  315.                         //Read the mixer registers
  316.                         IRQBits=SBGetMixerReg(Port,0x80);
  317.                         DMABits=SBGetMixerReg(Port,0x81);
  318.                        
  319.                         //Get IRQ number
  320.                         switch(IRQBits & 0xF)
  321.                         {
  322.                         case 1:
  323.                                 pIOInfo->IRQ=2;
  324.                                 break;
  325.                         case 2:
  326.                                 pIOInfo->IRQ=5;
  327.                                 break;
  328.                         case 4:
  329.                                 pIOInfo->IRQ=7;
  330.                                 break;
  331.                         case 8:
  332.                                 pIOInfo->IRQ=10;
  333.                                 break;
  334.                         default:
  335.                                 continue;
  336.                         }
  337.                        
  338.                         //Get 8-bit DMA channel
  339.                         switch(DMABits & 0xF)
  340.                         {
  341.                         case 1:
  342.                                 pIOInfo->DMAL=0;
  343.                                 break;
  344.                         case 2:
  345.                                 pIOInfo->DMAL=1;
  346.                                 break;
  347.                         case 8:
  348.                                 pIOInfo->DMAL=3;
  349.                                 break;
  350.                         default:
  351.                                 continue;
  352.                         }
  353.                        
  354.                         //Get 16-bit DMA channel
  355.                         switch(DMABits & 0xF0)
  356.                         {
  357.                         case 0x20:
  358.                                 pIOInfo->DMAH=5;
  359.                                 break;
  360.                         case 0x40:
  361.                                 pIOInfo->DMAH=6;
  362.                                 break;
  363.                         case 0x80:
  364.                                 pIOInfo->DMAH=7;
  365.                                 break;
  366.                         default:
  367.                                 continue;
  368.                         }
  369.                        
  370.                         return true;
  371.                 }
  372.                
  373.                 g_Print("Sound Blaster not found.\n");
  374.                 return false;
  375.         }
  376. }

  377. //=============================================================================
  378. //Func: _SendEOI
  379. //Desc: Send end-of-interrupt to 8259
  380. //-----------------------------------------------------------------------------
  381. SB_i(void,_SendEOI)(uint8_t uIRQNum)
  382. {
  383.         if(uIRQNum<8)
  384.                 outp(PIC_MODE,PIC_SPECEOI|uIRQNum);
  385.         else
  386.                 outp(PIC2_MODE,PIC_SPECEOI|(uIRQNum-8));
  387. }

  388. //=============================================================================
  389. //Func: _SetPICMask
  390. //Desc: Set PIC mask bit for uIRQNum
  391. //-----------------------------------------------------------------------------
  392. SB_i(void,_SetPICMask)(uint8_t uIRQNum)
  393. {
  394.         if(uIRQNum<8)
  395.                 outp(PIC_MASK,inp(PIC_MASK)|(1<<uIRQNum));
  396.         else
  397.                 outp(PIC2_MASK,inp(PIC_MASK)|(1<<(uIRQNum-8)));
  398. }

  399. //=============================================================================
  400. //Func: _ClearPICMask
  401. //Desc: Clear PIC mask bit for uIRQNum
  402. //-----------------------------------------------------------------------------
  403. SB_i(void,_ClearPICMask)(uint8_t uIRQNum)
  404. {
  405.         if(uIRQNum<8)
  406.                 outp(PIC_MASK,inp(PIC_MASK)&~(1<<uIRQNum));
  407.         else
  408.                 outp(PIC2_MASK,inp(PIC_MASK)&~(1<<(uIRQNum-8)));
  409. }

  410. //=============================================================================
  411. //Func: _CallBufCB
  412. //Desc: Call the user specified callback function
  413. //-----------------------------------------------------------------------------
  414. SB_i(void,_CallBufCB)()
  415. {
  416.         uint8_t far*pPtr=g_BufAddr;
  417.         if(!g_bFirstBuf)
  418.         {
  419.                 g_bFirstBuf=true;
  420.                 g_OnBuffer(pPtr,g_BufSize/2);
  421.         }
  422.         else
  423.         {
  424.                 pPtr+=g_BufSize/2;
  425.                 g_bFirstBuf=false;
  426.                 g_OnBuffer(pPtr,g_BufSize/2);
  427.         }
  428. }

  429. //=============================================================================
  430. //Func: _SBISR
  431. //Desc: Sound blaster interrupt handler.
  432. //-----------------------------------------------------------------------------
  433. SB_ISR(_SBISR)(void)
  434. {
  435.         uint8_t uReason;
  436.        
  437.         if(g_Version>=SBVer_SB16)
  438.         {
  439.                 uReason=SBGetMixerReg(g_Port,0x82);
  440.                
  441.                 if(uReason & 0x01)
  442.                 {
  443.                         inp(g_Port+SBPort_Ack8);
  444.                         outp(DMA8_FF_REG,0);
  445.                         _CallBufCB();
  446.                 }
  447.                 if(uReason & 0x02)
  448.                 {
  449.                         inp(g_Port+SBPort_Ack16);
  450.                         outp(DMA16_FF_REG,0);
  451.                         _CallBufCB();
  452.                 }
  453.         }
  454.         else
  455.         {
  456.                 inp(g_Port+SBPort_Ack8);
  457.                 outp(DMA8_FF_REG,0);
  458.         }
  459.        
  460.         _SendEOI(g_IRQ);
  461.         g_SBInfo.pfnISRSave();
  462. }

  463. //=============================================================================
  464. //Func: _InstallISR
  465. //Desc: Install the interrupt service routine
  466. //-----------------------------------------------------------------------------
  467. SB_i(void,_InstallISR)()
  468. {
  469.         ISR_f OrgISR;
  470.        
  471.         OrgISR=_dos_getvect(PIC_INTNUM(g_IRQ));
  472.         if(OrgISR!=_SBISR)
  473.         {
  474.                 g_SBInfo.pfnISRSave=OrgISR;
  475.                 _dos_setvect(PIC_INTNUM(g_IRQ),_SBISR);
  476.                
  477.                 _ClearPICMask(g_IRQ);
  478.         }
  479. }

  480. //=============================================================================
  481. //Func: _RestoreISR
  482. //Desc: Restore the interrupt service routine to the old one.
  483. //-----------------------------------------------------------------------------
  484. SB_i(void,_RestoreISR)()
  485. {
  486.         _dos_setvect(PIC_INTNUM(g_IRQ),g_SBInfo.pfnISRSave);
  487. }

  488. //=============================================================================
  489. //Func: SBInit
  490. //Desc: Initialize sound blaster.
  491. //-----------------------------------------------------------------------------
  492. SB_f(bool_t,SBInit)(DbgOut_f pfnOnDebugOutput)
  493. {
  494.         if(pfnOnDebugOutput)
  495.                 g_Print=pfnOnDebugOutput;
  496.         else
  497.                 g_Print=DefOnDebugOutput;
  498.        
  499.         if(!SBGetInfo(&(g_SBInfo.IOInfo),&(g_SBInfo.HWInfo)))
  500.                 return false;
  501.        
  502.         switch(g_DMAL)
  503.         {
  504.         case 0:
  505.                 g_DMALAddr= DMA0_ADDR;
  506.                 g_DMALCount=DMA0_COUNT;
  507.                 g_DMALPage= DMA0_PAGE;
  508.                 break;
  509.         case 1:
  510.                 g_DMALAddr= DMA1_ADDR;
  511.                 g_DMALCount=DMA1_COUNT;
  512.                 g_DMALPage= DMA1_PAGE;
  513.                 break;
  514.         case 3:
  515.                 g_DMALAddr= DMA3_ADDR;
  516.                 g_DMALCount=DMA3_COUNT;
  517.                 g_DMALPage= DMA3_PAGE;
  518.                 break;
  519.         }
  520.         switch(g_DMAH)
  521.         {
  522.         case 5:
  523.                 g_DMAHAddr= DMA5_ADDR;
  524.                 g_DMAHCount=DMA5_COUNT;
  525.                 g_DMAHPage= DMA5_PAGE;
  526.                 break;
  527.         case 6:
  528.                 g_DMAHAddr= DMA6_ADDR;
  529.                 g_DMAHCount=DMA6_COUNT;
  530.                 g_DMAHPage= DMA6_PAGE;
  531.                 break;
  532.         case 7:
  533.                 g_DMAHAddr= DMA7_ADDR;
  534.                 g_DMAHCount=DMA7_COUNT;
  535.                 g_DMAHPage= DMA7_PAGE;
  536.                 break;
  537.         }
  538.        
  539.         _InstallISR();

  540.         return true;
  541. }

  542. //=============================================================================
  543. //Func: _CheckDMAAddr
  544. //Desc: If the buffer crosses a page boundary, the func. returns false.
  545. //-----------------------------------------------------------------------------
  546. SB_i(bool_t,_CheckDMAAddr)(void far*Base,uint16_t Count)
  547. {
  548.         if((((uint32_t)Base & 0xFFFF)+Count) >> 16)
  549.                 return false;
  550.        
  551.         return true;
  552. }

  553. //=============================================================================
  554. //Func: _StopDMAL
  555. //Desc: Stop DMA
  556. //-----------------------------------------------------------------------------
  557. SB_i(void,_StopDMAL)()
  558. {
  559.         outp(DMA8_MASK_REG,0x04 | g_DMAL);
  560. }

  561. //=============================================================================
  562. //Func: _StopDMAH
  563. //Desc: Stop DMA
  564. //-----------------------------------------------------------------------------
  565. SB_i(void,_StopDMAH)()
  566. {
  567.         outp(DMA16_MASK_REG,0x04 | (g_DMAH-4));
  568. }

  569. //=============================================================================
  570. //Func: _StopDMAL
  571. //Desc: Stop DMA
  572. //-----------------------------------------------------------------------------
  573. SB_i(void,_StartDMAL)()
  574. {
  575.         outp(DMA8_MASK_REG, g_DMAL);
  576. }

  577. //=============================================================================
  578. //Func: _StopDMAH
  579. //Desc: Stop DMA
  580. //-----------------------------------------------------------------------------
  581. SB_i(void,_StartDMAH)()
  582. {
  583.         outp(DMA16_MASK_REG, (g_DMAH-4));
  584. }

  585. //=============================================================================
  586. //Func: _SetupDMAL
  587. //Desc: Setup DMA for playing
  588. //-----------------------------------------------------------------------------
  589. SB_i(void,_SetupDMAL)(void far*Base,uint16_t Count,bool_t Input)
  590. {
  591.         uint32_t uPhysAddr=Far2Phys(Base);
  592.         uint16_t uOffs=uPhysAddr & 0xFFFF;
  593.         uint8_t uPage=uPhysAddr>>16;
  594.        
  595.         //Disable DMA
  596.         _StopDMAL();
  597.        
  598.         //Clear FF
  599.         outp(DMA8_FF_REG,0);
  600.        
  601.         //Set mode
  602.         if(Input)
  603.                 outp(DMA8_MODE_REG,0x54 | g_DMAL);
  604.         else
  605.                 outp(DMA8_MODE_REG,0x58 | g_DMAL);
  606.        
  607.         Count--;
  608.         outp(g_DMALCount,(Count & 0xFF));                // LO byte of count
  609.         outp(g_DMALCount,(Count >> 8));                        // HI byte of count
  610.        
  611.         outp(g_DMALAddr, uOffs & 0xFF);                // LO byte address of buffer
  612.         outp(g_DMALAddr, uOffs >> 8);                // HI byte address of buffer
  613.         outp(g_DMALPage, uPage);                        // Physical page number
  614.        
  615.         //Enable DMA
  616.         _StartDMAL();
  617. }

  618. //=============================================================================
  619. //Func: _SetupDMAH
  620. //Desc: Setup DMA for playing
  621. //-----------------------------------------------------------------------------
  622. SB_i(void,_SetupDMAH)(void far*Base,uint16_t Count,bool_t Input)
  623. {
  624.         uint32_t uPhysAddr=Far2Phys(Base);
  625.         uint16_t uOffs=(uPhysAddr>>1) & 0xFFFF;
  626.         uint8_t uPage=uPhysAddr>>16;
  627.        
  628.         //Disable DMA
  629.         _StopDMAH();
  630.        
  631.         //Clear FF
  632.         outp(DMA16_FF_REG,0);
  633.        
  634.         //Set mode
  635.         if(Input)
  636.                 outp(DMA16_MODE_REG,0x54 | (g_DMAH-4));
  637.         else
  638.                 outp(DMA16_MODE_REG,0x58 | (g_DMAH-4));

  639.         Count=Count/2-1;//Two bytes per transfer
  640.         outp(g_DMAHCount,(Count & 0xFF));        // LO byte of count
  641.         outp(g_DMAHCount,(Count >> 8));                // HI byte of count
  642.        
  643.         outp(g_DMAHAddr, uOffs & 0xFF);                // LO byte address of buffer
  644.         outp(g_DMAHAddr, uOffs >> 8);                // HI byte address of buffer
  645.         outp(g_DMAHPage, uPage);                        // Physical page number
  646.        
  647.         //Enable DMA
  648.         _StartDMAH();
  649. }
  650. //=============================================================================
  651. //Func: SBShutDown
  652. //Desc: Shutdown the sound blaster, stop playing, restore IRQ
  653. //-----------------------------------------------------------------------------
  654. SB_f(void,SBShutDown)()
  655. {
  656.         if(!g_Version)
  657.                 return;
  658.         SBStop();
  659.         SBReset(g_Port);
  660.         _SetPICMask(g_IRQ);
  661.         _RestoreISR();
  662.         memset(&g_SBInfo,0,sizeof(g_SBInfo));
  663. }

  664. //=============================================================================
  665. //Func: SBDirectOut8
  666. //Desc: 8-bit direct mode single byte digitized sound output
  667. //-----------------------------------------------------------------------------
  668. SB_f(bool_t,SBDirectOut8)(uint8_t uByte)
  669. {
  670.         SBOut(g_Port,0x10);
  671.         SBOut(g_Port,uByte);
  672.         return true;
  673. }

  674. //=============================================================================
  675. //Func: SBInByte8
  676. //Desc: 8-bit direct mode single byte digitized sound input
  677. //-----------------------------------------------------------------------------
  678. SB_f(bool_t,SBDirectIn8)(uint8_t*pByte)
  679. {
  680.         SBOut(g_Port,0x20);
  681.         *pByte=SBIn(g_Port);
  682.         return true;
  683. }

  684. //=============================================================================
  685. //Func: _SBSetTimeConst
  686. //Desc: set digitized sound output sampling rate
  687. //-----------------------------------------------------------------------------
  688. SB_i(bool_t,_SBSetTimeConst)(uint32_t SplRate,uint8_t uChannels)
  689. {
  690.         if(SplRate<4000)
  691.         {
  692.                 g_Print("The sampling rate is too low.\n");
  693.                 return false;
  694.         }
  695.        
  696.         if(g_Version<SBVer_SBLO)
  697.         {
  698.                 if(SplRate>13000)
  699.                 {
  700.                         g_Print("The sampling rate is too high for the current Sound Blast"
  701.                         "er.\n");
  702.                         return false;
  703.                 }
  704.         }
  705.        
  706.         if(g_Version<SBVer_SBPro)
  707.         {
  708.                 if(uChannels!=1)
  709.                 {
  710.                         g_Print("The current Sound Blaster doesn't support stereo digitize"
  711.                         "d sound data.\n");
  712.                         return false;
  713.                 }
  714.         }
  715.        
  716.         if(SplRate>44100)
  717.         {
  718.                 g_Print("The sampling rate is too high for the current Sound Blaster."
  719.                 "\n");
  720.                 return false;
  721.         }
  722.        
  723.         if(uChannels!=1 && uChannels!=2)
  724.         {
  725.                 g_Print("Invalid channel number.\n");
  726.                 return false;
  727.         }
  728.        
  729.         SBOut(g_Port,0x40);
  730.         SBOut(g_Port,256 - 1000000/(uChannels*SplRate));
  731.         return true;
  732. }

  733. //=============================================================================
  734. //Func: SBSetOutSplRate
  735. //Desc: set digitized sound output sampling rate
  736. //-----------------------------------------------------------------------------
  737. SB_f(bool_t,SBSetOutSplRate)(uint32_t SplRate,uint8_t uChannels)
  738. {
  739.         if(g_Version<SBVer_SB16)
  740.                 return _SBSetTimeConst(SplRate,uChannels);
  741.         else
  742.         {
  743.                 if(SplRate<5000)
  744.                         return _SBSetTimeConst(SplRate,uChannels);
  745.                 else if(SplRate>45000)
  746.                 {
  747.                         g_Print("The sampling rate is too high.\n");
  748.                         return false;
  749.                 }
  750.                
  751.                 SBOut(g_Port,0x41);
  752.                 SBOut(g_Port,SplRate >> 8);
  753.                 SBOut(g_Port,SplRate & 0xFF);
  754.                 return true;
  755.         }
  756. }

  757. //=============================================================================
  758. //Func: SBSetInSplRate
  759. //Desc: set digitized sound input sampling rate
  760. //-----------------------------------------------------------------------------
  761. SB_f(bool_t,SBSetInSplRate)(uint32_t SplRate,uint8_t uChannels)
  762. {
  763.         if(g_Version<SBVer_SB16)
  764.                 return _SBSetTimeConst(SplRate,uChannels);
  765.         else
  766.         {
  767.                 if(SplRate<5000)
  768.                         return _SBSetTimeConst(SplRate,uChannels);
  769.                 else if(SplRate>45000)
  770.                 {
  771.                         g_Print("The sampling rate is too high.\n");
  772.                         return false;
  773.                 }
  774.                
  775.                 SBOut(g_Port,0x42);
  776.                 SBOut(g_Port,SplRate >> 8);
  777.                 SBOut(g_Port,SplRate & 0xFF);
  778.                 return true;
  779.         }
  780. }

  781. //=============================================================================
  782. //Func: _SBSetBlockSize
  783. //Desc: Set DSP block transfer size
  784. //-----------------------------------------------------------------------------
  785. SB_i(bool_t,_SBSetBlockSize)(uint16_t BlockSize)
  786. {
  787.         if(g_Version<SBVer_SBLO)
  788.         {
  789.                 g_Print("The current sound blaster doesn't support auto-init mode.\n");
  790.                 return false;
  791.         }
  792.                
  793.         SBOut(g_Port,0x48);
  794.         SBOut(g_Port,BlockSize & 0xFF);
  795.         SBOut(g_Port,BlockSize >> 8);
  796.         return true;
  797. }

  798. //=============================================================================
  799. //Func: _Stop8
  800. //Desc: Pause 8-bit digitized sound ip
  801. //-----------------------------------------------------------------------------
  802. SB_i(bool_t,_Stop8)()
  803. {
  804.         SBOut(g_Port,0xD0);
  805.         _StopDMAL();
  806.         return true;
  807. }

  808. //=============================================================================
  809. //Func: _Start8
  810. //Desc: Continue 8-bit digitized sound ip
  811. //-----------------------------------------------------------------------------
  812. SB_i(bool_t,_Start8)()
  813. {
  814.         SBOut(g_Port,0xD4);
  815.         _StartDMAL();
  816.         return true;
  817. }

  818. //=============================================================================
  819. //Func: _Stop16
  820. //Desc: Pause 16-bit digitized sound ip
  821. //-----------------------------------------------------------------------------
  822. SB_i(bool_t,_Stop16)()
  823. {
  824.         if(g_Version<SBVer_SB16)
  825.         {
  826.                 g_Print("The current sound blaster doesn't support 16-bit digitized so"
  827.                 "und data.\n");
  828.                 return false;
  829.         }
  830.         SBOut(g_Port,0xD5);
  831.         _StopDMAH();
  832.         return true;
  833. }

  834. //=============================================================================
  835. //Func: _Start16
  836. //Desc: Continue 16-bit digitized sound ip
  837. //-----------------------------------------------------------------------------
  838. SB_i(bool_t,_Start16)()
  839. {
  840.         if(g_Version<SBVer_SB16)
  841.         {
  842.                 g_Print("The current sound blaster doesn't support 16-bit digitized so"
  843.                 "und data.\n");
  844.                 return false;
  845.         }
  846.         SBOut(g_Port,0xD6);
  847.         _StartDMAH();
  848.         return true;
  849. }

  850. //=============================================================================
  851. //Func: SBStop
  852. //Desc: Stop(Pause) digitized sound ip
  853. //-----------------------------------------------------------------------------
  854. SB_f(void,SBStop)()
  855. {
  856.         if(g_bPlaying8 || g_bRecording8)
  857.                 _Stop8();
  858.         if(g_bPlaying16 || g_bRecording16)
  859.                 _Stop16();
  860. }

  861. //=============================================================================
  862. //Func: SBStart
  863. //Desc: Start(Continue) digitized sound ip
  864. //-----------------------------------------------------------------------------
  865. SB_f(void,SBStart)()
  866. {
  867.         if(g_bPlaying8 || g_bRecording8)
  868.                 _Start8();
  869.         if(g_bPlaying16 || g_bRecording16)
  870.                 _Start16();
  871. }

  872. //=============================================================================
  873. //Func: SBOut8
  874. //Desc: 8-bit auto-init mode digitized sound output
  875. //-----------------------------------------------------------------------------
  876. SB_f(bool_t,SBOut8)
  877. (
  878.         void far*BufAddr,
  879.         uint16_t BufSize,
  880.         uint8_t uChannels,
  881.         uint32_t SplRate,
  882.         Buffer_f pfnOnBuffer
  883. )
  884. {
  885.         //Double buffering
  886.         uint16_t HalfSize;
  887.        
  888.         if(g_Version<SBVer_SBLO)//no auto-init
  889.         {
  890.                 g_Print("The current Sound Blaster doesn't support auto-init mode.\n");
  891.                 return false;
  892.         }
  893.        
  894.         if(g_Version<SBVer_SB16 & uChannels!=1)//no stereo
  895.         {
  896.                 g_Print("The current Sound Blaster doesn't support stereo sound data."
  897.                 "\n");
  898.                 return false;
  899.         }
  900.                
  901.         if(!_CheckDMAAddr(BufAddr,BufSize))
  902.         {
  903.                 g_Print("DMA segbound wrapping.\n");
  904.                 return false;
  905.         }
  906.        
  907.         if(!SBSetOutSplRate(SplRate,uChannels))
  908.                 return false;
  909.        
  910.         SBStop();
  911.        
  912.         g_SBInfo.pfnOnBuffer=pfnOnBuffer;
  913.         g_BufAddr=BufAddr;
  914.         g_BufSize=BufSize;
  915.        
  916.         g_bFirstBuf=false;
  917.         _CallBufCB();
  918.         _CallBufCB();
  919.        
  920.         _SetupDMAL(BufAddr,BufSize-uChannels,0);
  921.        
  922.         //Double buffering
  923.         HalfSize=BufSize/2-uChannels;
  924.        
  925.         if(uChannels==1)
  926.         {
  927.                 if(g_Version<SBVer_SB16)
  928.                 {
  929.                         _SBSetBlockSize(HalfSize);
  930.                         if(SplRate<=23000)//low speed
  931.                                 SBOut(g_Port,0x1C);
  932.                         else
  933.                         {
  934.                                 if(g_Version<SBVer_SBHI)
  935.                                         return false;
  936.                                
  937.                                 SBOut(g_Port,0x90);
  938.                         }
  939.                 }
  940.                 else
  941.                 {
  942.                         SBOut(g_Port,0xC4);//Output, auto-init, no fifo
  943.                         SBOut(g_Port,0x00);//mono, unsigned
  944.                         SBOut(g_Port,HalfSize & 0xFF);
  945.                         SBOut(g_Port,HalfSize >> 8);
  946.                 }
  947.         }
  948.         else if(uChannels==2)
  949.         {
  950.                 SBOut(g_Port,0xC4);//Output, auto-init, no fifo
  951.                 SBOut(g_Port,0x20);//stereo, unsigned
  952.                 SBOut(g_Port,HalfSize & 0xFF);
  953.                 SBOut(g_Port,HalfSize >> 8);
  954.         }
  955.         else
  956.                 return false;
  957.        
  958.         g_bPlaying8=true;
  959.         g_bPlaying16=false;
  960.         g_bRecording8=false;
  961.         g_bRecording16=false;
  962.         return true;
  963. }

  964. //=============================================================================
  965. //Func: SBIn8
  966. //Desc: 8-bit auto-init mode digitized sound input
  967. //-----------------------------------------------------------------------------
  968. SB_f(bool_t,SBIn8)
  969. (
  970.         void far*BufAddr,
  971.         uint16_t BufSize,
  972.         uint8_t uChannels,
  973.         uint32_t SplRate,
  974.         Buffer_f pfnOnBuffer
  975. )
  976. {
  977.         if(g_Version<SBVer_SBLO)//no auto-init
  978.         {
  979.                 g_Print("The current Sound Blaster doesn't support auto-init mode.\n");
  980.                 return false;
  981.         }
  982.        
  983.         if(g_Version<SBVer_SB16 & uChannels!=1)//no stereo
  984.         {
  985.                 g_Print("The current Sound Blaster doesn't support stereo sound data."
  986.                 "\n");
  987.                 return false;
  988.         }
  989.                
  990.         if(!_CheckDMAAddr(BufAddr,BufSize))
  991.         {
  992.                 g_Print("DMA segbound wrapping.\n");
  993.                 return false;
  994.         }
  995.        
  996.         if(!SBSetInSplRate(SplRate,uChannels))
  997.                 return false;
  998.        
  999.         SBStop();
  1000.        
  1001.         g_SBInfo.pfnOnBuffer=pfnOnBuffer;
  1002.         g_BufAddr=BufAddr;
  1003.         g_BufSize=BufSize;
  1004.        
  1005.         g_bFirstBuf=false;
  1006.        
  1007.         //Double buffering
  1008.         _SetupDMAL(BufAddr,BufSize-uChannels,1);
  1009.        
  1010.         //Double buffering
  1011.         BufSize=BufSize/2-uChannels;
  1012.        
  1013.         if(uChannels==1)
  1014.         {
  1015.                 if(g_Version<SBVer_SB16)
  1016.                 {
  1017.                         _SBSetBlockSize(BufSize);//Double buffer
  1018.                         if(SplRate<=23000)//low speed
  1019.                                 SBOut(g_Port,0x2C);
  1020.                         else
  1021.                         {
  1022.                                 if(g_Version<SBVer_SBHI)
  1023.                                         return false;
  1024.                                
  1025.                                 SBOut(g_Port,0x98);
  1026.                         }
  1027.                 }
  1028.                 else
  1029.                 {
  1030.                         SBOut(g_Port,0xCC);//Input, auto-init, no fifo
  1031.                         SBOut(g_Port,0x00);//mono, unsigned
  1032.                         SBOut(g_Port,BufSize & 0xFF);
  1033.                         SBOut(g_Port,BufSize >> 8);
  1034.                 }
  1035.         }
  1036.         else if(uChannels==2)
  1037.         {
  1038.                 SBOut(g_Port,0xCC);//Input, auto-init, no fifo
  1039.                 SBOut(g_Port,0x20);//stereo, unsigned
  1040.                 SBOut(g_Port,BufSize & 0xFF);
  1041.                 SBOut(g_Port,BufSize >> 8);
  1042.         }
  1043.         else
  1044.                 return false;
  1045.        
  1046.         g_bPlaying8=false;
  1047.         g_bPlaying16=false;
  1048.         g_bRecording8=true;
  1049.         g_bRecording16=false;
  1050.         return true;
  1051. }

  1052. //=============================================================================
  1053. //Func: SBOut16
  1054. //Desc: 16-bit auto-init mode digitized sound output
  1055. //-----------------------------------------------------------------------------
  1056. SB_f(bool_t,SBOut16)
  1057. (
  1058.         void far*BufAddr,
  1059.         uint16_t BufSize,
  1060.         uint8_t uChannels,
  1061.         uint32_t SplRate,
  1062.         Buffer_f pfnOnBuffer
  1063. )
  1064. {       
  1065.         //Double buffering
  1066.         uint16_t HalfSize;
  1067.        
  1068.         if(g_Version<SBVer_SB16)
  1069.         {
  1070.                 g_Print("The current sound blaster doesn't support 16-bit digitized so"
  1071.                 "und data.\n");
  1072.                 return false;
  1073.         }
  1074.        
  1075.         if(uChannels!=1 && uChannels!=2)
  1076.         {
  1077.                 g_Print("Invalid channel number.\n");
  1078.                 return false;
  1079.         }
  1080.        
  1081.         if(!_CheckDMAAddr(BufAddr,BufSize))
  1082.         {
  1083.                 g_Print("DMA segbound wrapping.\n");
  1084.                 return false;
  1085.         }
  1086.        
  1087.         if(!SBSetOutSplRate(SplRate,uChannels))
  1088.                 return false;
  1089.        
  1090.         SBStop();
  1091.        
  1092.         g_SBInfo.pfnOnBuffer=pfnOnBuffer;
  1093.         g_BufAddr=BufAddr;
  1094.         g_BufSize=BufSize;
  1095.        
  1096.         g_bFirstBuf=false;
  1097.         _CallBufCB();
  1098.         _CallBufCB();
  1099.        
  1100.         _SetupDMAH(BufAddr,BufSize,0);
  1101.        
  1102.         //Two bytes per sample, double buffering
  1103.         HalfSize=BufSize/4-1;
  1104.        
  1105.         SBOut(g_Port,0xB4);//Output, auto-init, no fifo
  1106.         SBOut(g_Port,uChannels==1?0x10:0x30);//stereo, unsigned
  1107.         SBOut(g_Port,HalfSize & 0xFF);
  1108.         SBOut(g_Port,HalfSize >> 8);
  1109.        
  1110.         g_bPlaying8=false;
  1111.         g_bPlaying16=true;
  1112.         g_bRecording8=false;
  1113.         g_bRecording16=false;
  1114.         return true;
  1115. }

  1116. //=============================================================================
  1117. //Func: SBIn16
  1118. //Desc: 16-bit auto-init mode digitized sound input
  1119. //-----------------------------------------------------------------------------
  1120. SB_f(bool_t,SBIn16)
  1121. (
  1122.         void far*BufAddr,
  1123.         uint16_t BufSize,
  1124.         uint8_t uChannels,
  1125.         uint32_t SplRate,
  1126.         Buffer_f pfnOnBuffer
  1127. )
  1128. {
  1129.         if(g_Version<SBVer_SB16)
  1130.         {
  1131.                 g_Print("The current sound blaster doesn't support 16-bit digitized so"
  1132.                 "und data.\n");
  1133.                 return false;
  1134.         }
  1135.        
  1136.         if(uChannels!=1 && uChannels!=2)
  1137.         {
  1138.                 g_Print("Invalid channel number.\n");
  1139.                 return false;
  1140.         }
  1141.        
  1142.         if(!_CheckDMAAddr(BufAddr,BufSize))
  1143.         {
  1144.                 g_Print("DMA segbound wrapping.\n");
  1145.                 return false;
  1146.         }
  1147.        
  1148.         if(!SBSetInSplRate(SplRate,uChannels))
  1149.                 return false;
  1150.        
  1151.         SBStop();
  1152.        
  1153.         g_SBInfo.pfnOnBuffer=pfnOnBuffer;
  1154.         g_BufAddr=BufAddr;
  1155.         g_BufSize=BufSize;
  1156.        
  1157.         g_bFirstBuf=false;
  1158.         _SetupDMAH(BufAddr,BufSize,1);
  1159.        
  1160.         //Two bytes per sample, double buffering
  1161.         BufSize=BufSize/4-1;
  1162.        
  1163.         SBOut(g_Port,0xBC);//Input, auto-init, no fifo
  1164.         SBOut(g_Port,uChannels==1?0x10:0x30);//stereo, unsigned
  1165.         SBOut(g_Port,BufSize & 0xFF);
  1166.         SBOut(g_Port,BufSize >> 8);
  1167.        
  1168.         g_bPlaying8=false;
  1169.         g_bPlaying16=false;
  1170.         g_bRecording8=false;
  1171.         g_bRecording16=true;
  1172.         return true;
  1173. }

  1174. //=============================================================================
  1175. //Func: SBSetVolume
  1176. //Desc: Set speaker volume
  1177. //-----------------------------------------------------------------------------
  1178. SB_f(bool_t,SBSetVolume)(uint8_t Master,uint8_t Voice,uint8_t Mic)
  1179. {
  1180.         if(g_Version<SBVer_SBPro)
  1181.         {
  1182.                 g_Print("The current sound blaster doesn't have a mixer.\n");
  1183.                 return false;
  1184.         }
  1185.         SBSetMixerReg(g_Port,SBMixer_MasterVol,Master);
  1186.         SBSetMixerReg(g_Port,SBMixer_VoiceVol,Voice);
  1187.         SBSetMixerReg(g_Port,SBMixer_MicVol,Mic);
  1188.         return true;
  1189. }

  1190. //=============================================================================
  1191. //Func: SBSendMIDIByte
  1192. //Desc: Output MIDI data to the MIDI port in non-UART mode
  1193. //-----------------------------------------------------------------------------
  1194. SB_f(bool_t,SBSendMIDIByte)(uint8_t MIDI_Byte)
  1195. {
  1196.         SBOut(g_Port,0x38);
  1197.         SBOut(g_Port,MIDI_Byte);
  1198.         return true;
  1199. }
复制代码

本帖被以下淘专辑推荐:

回复

使用道具 举报

发表于 2015-9-16 12:25:57 | 显示全部楼层
1134Lines 不容易!
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2015-9-19 18:15:14 | 显示全部楼层
cyycoish 发表于 2015-9-16 12:25
1134Lines 不容易!

已更新
回复 赞! 靠!

使用道具 举报

发表于 2017-11-12 20:46:42 | 显示全部楼层
666666666666666666666666
回复 赞! 靠!

使用道具 举报

发表于 2019-1-31 22:18:22 | 显示全部楼层
屌!一个C语言文件写的程序感觉好爽啊哈哈
回复 赞! 靠!

使用道具 举报

发表于 2020-1-27 16:09:30 | 显示全部楼层
谢谢分享
回复

使用道具 举报

发表于 2020-2-2 08:24:25 | 显示全部楼层
感谢分享
回复

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-11-22 11:30 , Processed in 0.044059 second(s), 30 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表