【DOS】C语言写的声卡(Sound Blaster 16)驱动
转载请注明出处: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。
BIN:
整个程序的所有源码,回帖后即可下载。**** Hidden Message *****
编译器: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?mod=viewthread&tid=1489&fromuid=1
下面放出最关键的代码。#include"sb.h"
#include<dos.h>
#include<time.h>
#include<ctype.h>
#include<conio.h>
#include<stdio.h>
#include<stdarg.h>
#include<stdlib.h>
#include<memory.h>
SBInfo_t g_SBInfo={0};
#define g_Port g_SBInfo.IOInfo.PortNum
#define g_Version g_SBInfo.HWInfo.Version
#define g_DMAL g_SBInfo.IOInfo.DMAL
#define g_DMALAddr g_SBInfo.DMAInfo.DMALAddr
#define g_DMALCount g_SBInfo.DMAInfo.DMALCount
#define g_DMALPage g_SBInfo.DMAInfo.DMALPage
#define g_DMAH g_SBInfo.IOInfo.DMAH
#define g_DMAHAddr g_SBInfo.DMAInfo.DMAHAddr
#define g_DMAHCount g_SBInfo.DMAInfo.DMAHCount
#define g_DMAHPage g_SBInfo.DMAInfo.DMAHPage
#define g_IRQ g_SBInfo.IOInfo.IRQ
#define g_BufAddr g_SBInfo.pBufAddr
#define g_BufSize g_SBInfo.BufSize
#define g_bPlaying8 g_SBInfo.bPlaying8
#define g_bPlaying16 g_SBInfo.bPlaying16
#define g_bRecording8 g_SBInfo.bRecording8
#define g_bRecording16 g_SBInfo.bRecording16
#define g_bFirstBuf g_SBInfo.bFirstBuf
#define g_OnBuffer g_SBInfo.pfnOnBuffer
#define g_Print g_SBInfo.pfnOnDebugOutput
#define Far2Phys(f) (((uint32_t)f & 0xFFFF) + ((uint32_t)f >> 12))
#define SBPort_BaseBegin 0x210
#define SBPort_BaseStep 0x10
#define SBPort_BaseEnd 0x260
#define SBPort_MixerRegNum 0x04
#define SBPort_MixerRegVal 0x05
#define SBPort_Reset 0x06
#define SBPort_Read 0x0A
#define SBPort_Write 0x0C
#define SBPort_WBufState 0x0C
#define SBPort_RBufState 0x0E
#define SBPort_Ack8 0x0E
#define SBPort_Ack16 0x0F
#define SBMixer_VoiceVol 0x04
#define SBMixer_MicVol 0x0A
#define SBMixer_MasterVol 0x22
//Programmable Interrupt Controller
#define PIC_MASK 0x21
#define PIC_MODE 0x20
#define PIC2_MASK 0xA1
#define PIC2_MODE 0xA0
#define PIC_EOI 0x20
#define PIC_SPECEOI 0x60
#define PIC_IRQ0_7BEGIN 0x08
#define PIC_IRQ8_FBEGIN 0x70
#define PIC_INTNUM(x) ((x>7)?PIC_IRQ8_FBEGIN+(x):PIC_IRQ0_7BEGIN+(x))
//DMA
#define DMA8_FF_REG 0x0C
#define DMA8_MASK_REG 0x0A
#define DMA8_MODE_REG 0x0B
#define DMA16_FF_REG 0xD8
#define DMA16_MASK_REG 0xD4
#define DMA16_MODE_REG 0xD6
#define DMA0_ADDR 0x00
#define DMA0_COUNT 0x01
#define DMA0_PAGE 0x87
#define DMA1_ADDR 0x02
#define DMA1_COUNT 0x03
#define DMA1_PAGE 0x83
#define DMA2_ADDR 0x04
#define DMA2_COUNT 0x05
#define DMA2_PAGE 0x81
#define DMA3_ADDR 0x06
#define DMA3_COUNT 0x07
#define DMA3_PAGE 0x82
#define DMA4_ADDR 0xC0
#define DMA4_COUNT 0xC2
#define DMA4_PAGE 0x8F
#define DMA5_ADDR 0xC4
#define DMA5_COUNT 0xC6
#define DMA5_PAGE 0x8B
#define DMA6_ADDR 0xC8
#define DMA6_COUNT 0xCA
#define DMA6_PAGE 0x89
#define DMA7_ADDR 0xCC
#define DMA7_COUNT 0xCE
#define DMA7_PAGE 0x8A
//=============================================================================
//Func: OnDebugOutput
//Desc: Debug info output by Sound Blaster driver
//-----------------------------------------------------------------------------
void SBCallBack_t DefOnDebugOutput(char*format,...)
{
va_list ap;
va_start(ap,format);
vfprintf(stderr,format,ap);
va_end(ap);
}
//=============================================================================
//Func: SBIn
//Desc: Read a byte at the Read Data port
//-----------------------------------------------------------------------------
SB_i(uint8_t,SBIn)(uint16_t uPortNum)
{
while(!(inp(uPortNum+SBPort_RBufState) & 0x80));
return inp(uPortNum+SBPort_Read);
}
//=============================================================================
//Func: SBOut
//Desc: Write a byte to the Write Data port
//-----------------------------------------------------------------------------
SB_i(void,SBOut)(uint16_t uPortNum,uint8_t Data)
{
while(inp(uPortNum+SBPort_WBufState) & 0x80);
outp(uPortNum+SBPort_Write,Data);
}
//=============================================================================
//Func: SBGetMixerReg
//Desc: Read a mixer register value
//-----------------------------------------------------------------------------
SB_i(uint8_t,SBGetMixerReg)(uint16_t uPortNum,uint8_t uMixerReg)
{
if(g_Version<SBVer_SBPro)
return 0;
outp(uPortNum+SBPort_MixerRegNum,uMixerReg);
return inp(uPortNum+SBPort_MixerRegVal);
}
//=============================================================================
//Func: SBSetMixerReg
//Desc: Write a mixer register value
//-----------------------------------------------------------------------------
SB_i(void,SBSetMixerReg)(uint16_t uPortNum,uint8_t uMixerReg,uint8_t uVal)
{
if(g_Version<SBVer_SBPro)
return;
outp(uPortNum+SBPort_MixerRegNum,uMixerReg);
outp(uPortNum+SBPort_MixerRegVal,uVal);
}
//=============================================================================
//Func: SBReset
//Desc: Initialize or reset the sound blaster
//-----------------------------------------------------------------------------
SB_i(bool_t,SBReset)(uint16_t uPortNum)
{
clock_t c;
//Write a "1" to the Reset port (2x6h) and wait for atleast 3 ms
outp(uPortNum+SBPort_Reset,1);
//wait for 10 ms
delay(10);
//Write a "0" to the Reset port
outp(uPortNum+SBPort_Reset,0);
//Wait until it had finished initializing
c=clock();
while(!(inp(uPortNum+SBPort_RBufState) & 0x80))
{
//quit when out of time
if(clock()-c>CLOCKS_PER_SEC*200/1000)
return false;
}
if(inp(uPortNum+SBPort_Read)==0xAA)
return true;
return false;
}
//=============================================================================
//Func: SBGetIOInfoByEnv
//Desc: Retrieve the informations from %BLASTER%
//-----------------------------------------------------------------------------
SB_i(bool_t,SBGetIOInfoByEnv)(SBIOInfo_p pIOInfo,char*szEnv)
{
char Buf,SaveChar;
bool_t DMAFound = false;
bool_t IOPortFound = false;
bool_t IRQFound = false;
int i,mul;
if(!szEnv)
return false;
do
{
switch(*szEnv)
{
case'A':// I/O base port address found
case'a':
szEnv++;
for (i = 0; i < 3; i++)// Grab the digits
{
if(*szEnv==' ')
break;
Buf = *szEnv;
szEnv++;
}
// Convert to HEX
mul = 1;
pIOInfo->PortNum = 0;
while(i--)
{
int Digit;
if (Buf >= '0' && Buf <= '9')
Digit = Buf - '0';
else if (Buf >= 'A' && Buf <= 'F')
Digit = Buf - 'A' + 10;
else if (Buf >= 'a' && Buf <= 'f')
Digit = Buf - 'a' + 10;
pIOInfo->PortNum += Digit * mul;
mul <<= 4;
}
IOPortFound=true;
break;
case'D': // 8-bit DMA channel
case'd':
case'H': // 16-bit DMA channel
case'h':
case'I': // IRQ number
case'i':
SaveChar=*szEnv++;
Buf=*szEnv++;
if(isdigit(*szEnv))
{
Buf=*szEnv++;
Buf='\0';
}
else
Buf='\0';
if(SaveChar=='D' || SaveChar=='d')
{
pIOInfo->DMAL = atoi(Buf);
DMAFound=true;
}
else if(SaveChar=='H' || SaveChar=='h')
{
pIOInfo->DMAH = atoi(Buf);
DMAFound=true;
}
else if(SaveChar=='I' || SaveChar=='i')
{
pIOInfo->IRQ = atoi(Buf);
IRQFound=true;
}
break;
default:
szEnv++;
}
}while(*szEnv);
if(!IOPortFound || !DMAFound || !IRQFound)
{
g_Print("Incorrect %%BLASTER%% env.\n");
return false;
}
return true;
}
//=============================================================================
//Func: SBGetHWInfo
//Desc: Retrieve the hardware informations.
//-----------------------------------------------------------------------------
SB_i(void,SBGetHWInfo)(uint16_t uPortNum,SBHWInfo_p pHWInfo)
{
SBOut(uPortNum,0xE1);//get version
pHWInfo->Version=SBIn(uPortNum);
pHWInfo->Version<<=8;
pHWInfo->Version|=SBIn(uPortNum);
}
//=============================================================================
//Func: SBGetInfo
//Desc: Retrieve the informations by IO.
//Note: If failed getting info from BLASTER, the function will try to get the
// info by read it from the mixer register. But only SB16 supports it.
//-----------------------------------------------------------------------------
SB_i(bool_t,SBGetInfo)(SBIOInfo_p pIOInfo,SBHWInfo_p pHWInfo)
{
if(SBGetIOInfoByEnv(pIOInfo,getenv("BLASTER")))
{
pIOInfo->InfoFromEnv=true;
SBGetHWInfo(pIOInfo->PortNum,pHWInfo);
return true;
}
else
{
uint16_t Port;
uint8_t IRQBits;
uint8_t DMABits;
pIOInfo->InfoFromEnv=false;
//Scan the port to determine the port of the sound blaster
for(Port=SBPort_BaseBegin;
Port<=SBPort_BaseEnd;
Port+=SBPort_BaseStep)
{
if(!SBReset(Port))
continue;
pIOInfo->PortNum=Port;
SBGetHWInfo(Port,pHWInfo);
if(pHWInfo->Version<SBVer_SB16)
{
pIOInfo->IRQ=5;
pIOInfo->DMAL=1;
pIOInfo->DMAH=5;
return true;
}
//Read the mixer registers
IRQBits=SBGetMixerReg(Port,0x80);
DMABits=SBGetMixerReg(Port,0x81);
//Get IRQ number
switch(IRQBits & 0xF)
{
case 1:
pIOInfo->IRQ=2;
break;
case 2:
pIOInfo->IRQ=5;
break;
case 4:
pIOInfo->IRQ=7;
break;
case 8:
pIOInfo->IRQ=10;
break;
default:
continue;
}
//Get 8-bit DMA channel
switch(DMABits & 0xF)
{
case 1:
pIOInfo->DMAL=0;
break;
case 2:
pIOInfo->DMAL=1;
break;
case 8:
pIOInfo->DMAL=3;
break;
default:
continue;
}
//Get 16-bit DMA channel
switch(DMABits & 0xF0)
{
case 0x20:
pIOInfo->DMAH=5;
break;
case 0x40:
pIOInfo->DMAH=6;
break;
case 0x80:
pIOInfo->DMAH=7;
break;
default:
continue;
}
return true;
}
g_Print("Sound Blaster not found.\n");
return false;
}
}
//=============================================================================
//Func: _SendEOI
//Desc: Send end-of-interrupt to 8259
//-----------------------------------------------------------------------------
SB_i(void,_SendEOI)(uint8_t uIRQNum)
{
if(uIRQNum<8)
outp(PIC_MODE,PIC_SPECEOI|uIRQNum);
else
outp(PIC2_MODE,PIC_SPECEOI|(uIRQNum-8));
}
//=============================================================================
//Func: _SetPICMask
//Desc: Set PIC mask bit for uIRQNum
//-----------------------------------------------------------------------------
SB_i(void,_SetPICMask)(uint8_t uIRQNum)
{
if(uIRQNum<8)
outp(PIC_MASK,inp(PIC_MASK)|(1<<uIRQNum));
else
outp(PIC2_MASK,inp(PIC_MASK)|(1<<(uIRQNum-8)));
}
//=============================================================================
//Func: _ClearPICMask
//Desc: Clear PIC mask bit for uIRQNum
//-----------------------------------------------------------------------------
SB_i(void,_ClearPICMask)(uint8_t uIRQNum)
{
if(uIRQNum<8)
outp(PIC_MASK,inp(PIC_MASK)&~(1<<uIRQNum));
else
outp(PIC2_MASK,inp(PIC_MASK)&~(1<<(uIRQNum-8)));
}
//=============================================================================
//Func: _CallBufCB
//Desc: Call the user specified callback function
//-----------------------------------------------------------------------------
SB_i(void,_CallBufCB)()
{
uint8_t far*pPtr=g_BufAddr;
if(!g_bFirstBuf)
{
g_bFirstBuf=true;
g_OnBuffer(pPtr,g_BufSize/2);
}
else
{
pPtr+=g_BufSize/2;
g_bFirstBuf=false;
g_OnBuffer(pPtr,g_BufSize/2);
}
}
//=============================================================================
//Func: _SBISR
//Desc: Sound blaster interrupt handler.
//-----------------------------------------------------------------------------
SB_ISR(_SBISR)(void)
{
uint8_t uReason;
if(g_Version>=SBVer_SB16)
{
uReason=SBGetMixerReg(g_Port,0x82);
if(uReason & 0x01)
{
inp(g_Port+SBPort_Ack8);
outp(DMA8_FF_REG,0);
_CallBufCB();
}
if(uReason & 0x02)
{
inp(g_Port+SBPort_Ack16);
outp(DMA16_FF_REG,0);
_CallBufCB();
}
}
else
{
inp(g_Port+SBPort_Ack8);
outp(DMA8_FF_REG,0);
}
_SendEOI(g_IRQ);
g_SBInfo.pfnISRSave();
}
//=============================================================================
//Func: _InstallISR
//Desc: Install the interrupt service routine
//-----------------------------------------------------------------------------
SB_i(void,_InstallISR)()
{
ISR_f OrgISR;
OrgISR=_dos_getvect(PIC_INTNUM(g_IRQ));
if(OrgISR!=_SBISR)
{
g_SBInfo.pfnISRSave=OrgISR;
_dos_setvect(PIC_INTNUM(g_IRQ),_SBISR);
_ClearPICMask(g_IRQ);
}
}
//=============================================================================
//Func: _RestoreISR
//Desc: Restore the interrupt service routine to the old one.
//-----------------------------------------------------------------------------
SB_i(void,_RestoreISR)()
{
_dos_setvect(PIC_INTNUM(g_IRQ),g_SBInfo.pfnISRSave);
}
//=============================================================================
//Func: SBInit
//Desc: Initialize sound blaster.
//-----------------------------------------------------------------------------
SB_f(bool_t,SBInit)(DbgOut_f pfnOnDebugOutput)
{
if(pfnOnDebugOutput)
g_Print=pfnOnDebugOutput;
else
g_Print=DefOnDebugOutput;
if(!SBGetInfo(&(g_SBInfo.IOInfo),&(g_SBInfo.HWInfo)))
return false;
switch(g_DMAL)
{
case 0:
g_DMALAddr= DMA0_ADDR;
g_DMALCount=DMA0_COUNT;
g_DMALPage= DMA0_PAGE;
break;
case 1:
g_DMALAddr= DMA1_ADDR;
g_DMALCount=DMA1_COUNT;
g_DMALPage= DMA1_PAGE;
break;
case 3:
g_DMALAddr= DMA3_ADDR;
g_DMALCount=DMA3_COUNT;
g_DMALPage= DMA3_PAGE;
break;
}
switch(g_DMAH)
{
case 5:
g_DMAHAddr= DMA5_ADDR;
g_DMAHCount=DMA5_COUNT;
g_DMAHPage= DMA5_PAGE;
break;
case 6:
g_DMAHAddr= DMA6_ADDR;
g_DMAHCount=DMA6_COUNT;
g_DMAHPage= DMA6_PAGE;
break;
case 7:
g_DMAHAddr= DMA7_ADDR;
g_DMAHCount=DMA7_COUNT;
g_DMAHPage= DMA7_PAGE;
break;
}
_InstallISR();
return true;
}
//=============================================================================
//Func: _CheckDMAAddr
//Desc: If the buffer crosses a page boundary, the func. returns false.
//-----------------------------------------------------------------------------
SB_i(bool_t,_CheckDMAAddr)(void far*Base,uint16_t Count)
{
if((((uint32_t)Base & 0xFFFF)+Count) >> 16)
return false;
return true;
}
//=============================================================================
//Func: _StopDMAL
//Desc: Stop DMA
//-----------------------------------------------------------------------------
SB_i(void,_StopDMAL)()
{
outp(DMA8_MASK_REG,0x04 | g_DMAL);
}
//=============================================================================
//Func: _StopDMAH
//Desc: Stop DMA
//-----------------------------------------------------------------------------
SB_i(void,_StopDMAH)()
{
outp(DMA16_MASK_REG,0x04 | (g_DMAH-4));
}
//=============================================================================
//Func: _StopDMAL
//Desc: Stop DMA
//-----------------------------------------------------------------------------
SB_i(void,_StartDMAL)()
{
outp(DMA8_MASK_REG, g_DMAL);
}
//=============================================================================
//Func: _StopDMAH
//Desc: Stop DMA
//-----------------------------------------------------------------------------
SB_i(void,_StartDMAH)()
{
outp(DMA16_MASK_REG, (g_DMAH-4));
}
//=============================================================================
//Func: _SetupDMAL
//Desc: Setup DMA for playing
//-----------------------------------------------------------------------------
SB_i(void,_SetupDMAL)(void far*Base,uint16_t Count,bool_t Input)
{
uint32_t uPhysAddr=Far2Phys(Base);
uint16_t uOffs=uPhysAddr & 0xFFFF;
uint8_t uPage=uPhysAddr>>16;
//Disable DMA
_StopDMAL();
//Clear FF
outp(DMA8_FF_REG,0);
//Set mode
if(Input)
outp(DMA8_MODE_REG,0x54 | g_DMAL);
else
outp(DMA8_MODE_REG,0x58 | g_DMAL);
Count--;
outp(g_DMALCount,(Count & 0xFF)); // LO byte of count
outp(g_DMALCount,(Count >> 8)); // HI byte of count
outp(g_DMALAddr, uOffs & 0xFF); // LO byte address of buffer
outp(g_DMALAddr, uOffs >> 8); // HI byte address of buffer
outp(g_DMALPage, uPage); // Physical page number
//Enable DMA
_StartDMAL();
}
//=============================================================================
//Func: _SetupDMAH
//Desc: Setup DMA for playing
//-----------------------------------------------------------------------------
SB_i(void,_SetupDMAH)(void far*Base,uint16_t Count,bool_t Input)
{
uint32_t uPhysAddr=Far2Phys(Base);
uint16_t uOffs=(uPhysAddr>>1) & 0xFFFF;
uint8_t uPage=uPhysAddr>>16;
//Disable DMA
_StopDMAH();
//Clear FF
outp(DMA16_FF_REG,0);
//Set mode
if(Input)
outp(DMA16_MODE_REG,0x54 | (g_DMAH-4));
else
outp(DMA16_MODE_REG,0x58 | (g_DMAH-4));
Count=Count/2-1;//Two bytes per transfer
outp(g_DMAHCount,(Count & 0xFF)); // LO byte of count
outp(g_DMAHCount,(Count >> 8)); // HI byte of count
outp(g_DMAHAddr, uOffs & 0xFF); // LO byte address of buffer
outp(g_DMAHAddr, uOffs >> 8); // HI byte address of buffer
outp(g_DMAHPage, uPage); // Physical page number
//Enable DMA
_StartDMAH();
}
//=============================================================================
//Func: SBShutDown
//Desc: Shutdown the sound blaster, stop playing, restore IRQ
//-----------------------------------------------------------------------------
SB_f(void,SBShutDown)()
{
if(!g_Version)
return;
SBStop();
SBReset(g_Port);
_SetPICMask(g_IRQ);
_RestoreISR();
memset(&g_SBInfo,0,sizeof(g_SBInfo));
}
//=============================================================================
//Func: SBDirectOut8
//Desc: 8-bit direct mode single byte digitized sound output
//-----------------------------------------------------------------------------
SB_f(bool_t,SBDirectOut8)(uint8_t uByte)
{
SBOut(g_Port,0x10);
SBOut(g_Port,uByte);
return true;
}
//=============================================================================
//Func: SBInByte8
//Desc: 8-bit direct mode single byte digitized sound input
//-----------------------------------------------------------------------------
SB_f(bool_t,SBDirectIn8)(uint8_t*pByte)
{
SBOut(g_Port,0x20);
*pByte=SBIn(g_Port);
return true;
}
//=============================================================================
//Func: _SBSetTimeConst
//Desc: set digitized sound output sampling rate
//-----------------------------------------------------------------------------
SB_i(bool_t,_SBSetTimeConst)(uint32_t SplRate,uint8_t uChannels)
{
if(SplRate<4000)
{
g_Print("The sampling rate is too low.\n");
return false;
}
if(g_Version<SBVer_SBLO)
{
if(SplRate>13000)
{
g_Print("The sampling rate is too high for the current Sound Blast"
"er.\n");
return false;
}
}
if(g_Version<SBVer_SBPro)
{
if(uChannels!=1)
{
g_Print("The current Sound Blaster doesn't support stereo digitize"
"d sound data.\n");
return false;
}
}
if(SplRate>44100)
{
g_Print("The sampling rate is too high for the current Sound Blaster."
"\n");
return false;
}
if(uChannels!=1 && uChannels!=2)
{
g_Print("Invalid channel number.\n");
return false;
}
SBOut(g_Port,0x40);
SBOut(g_Port,256 - 1000000/(uChannels*SplRate));
return true;
}
//=============================================================================
//Func: SBSetOutSplRate
//Desc: set digitized sound output sampling rate
//-----------------------------------------------------------------------------
SB_f(bool_t,SBSetOutSplRate)(uint32_t SplRate,uint8_t uChannels)
{
if(g_Version<SBVer_SB16)
return _SBSetTimeConst(SplRate,uChannels);
else
{
if(SplRate<5000)
return _SBSetTimeConst(SplRate,uChannels);
else if(SplRate>45000)
{
g_Print("The sampling rate is too high.\n");
return false;
}
SBOut(g_Port,0x41);
SBOut(g_Port,SplRate >> 8);
SBOut(g_Port,SplRate & 0xFF);
return true;
}
}
//=============================================================================
//Func: SBSetInSplRate
//Desc: set digitized sound input sampling rate
//-----------------------------------------------------------------------------
SB_f(bool_t,SBSetInSplRate)(uint32_t SplRate,uint8_t uChannels)
{
if(g_Version<SBVer_SB16)
return _SBSetTimeConst(SplRate,uChannels);
else
{
if(SplRate<5000)
return _SBSetTimeConst(SplRate,uChannels);
else if(SplRate>45000)
{
g_Print("The sampling rate is too high.\n");
return false;
}
SBOut(g_Port,0x42);
SBOut(g_Port,SplRate >> 8);
SBOut(g_Port,SplRate & 0xFF);
return true;
}
}
//=============================================================================
//Func: _SBSetBlockSize
//Desc: Set DSP block transfer size
//-----------------------------------------------------------------------------
SB_i(bool_t,_SBSetBlockSize)(uint16_t BlockSize)
{
if(g_Version<SBVer_SBLO)
{
g_Print("The current sound blaster doesn't support auto-init mode.\n");
return false;
}
SBOut(g_Port,0x48);
SBOut(g_Port,BlockSize & 0xFF);
SBOut(g_Port,BlockSize >> 8);
return true;
}
//=============================================================================
//Func: _Stop8
//Desc: Pause 8-bit digitized sound ip
//-----------------------------------------------------------------------------
SB_i(bool_t,_Stop8)()
{
SBOut(g_Port,0xD0);
_StopDMAL();
return true;
}
//=============================================================================
//Func: _Start8
//Desc: Continue 8-bit digitized sound ip
//-----------------------------------------------------------------------------
SB_i(bool_t,_Start8)()
{
SBOut(g_Port,0xD4);
_StartDMAL();
return true;
}
//=============================================================================
//Func: _Stop16
//Desc: Pause 16-bit digitized sound ip
//-----------------------------------------------------------------------------
SB_i(bool_t,_Stop16)()
{
if(g_Version<SBVer_SB16)
{
g_Print("The current sound blaster doesn't support 16-bit digitized so"
"und data.\n");
return false;
}
SBOut(g_Port,0xD5);
_StopDMAH();
return true;
}
//=============================================================================
//Func: _Start16
//Desc: Continue 16-bit digitized sound ip
//-----------------------------------------------------------------------------
SB_i(bool_t,_Start16)()
{
if(g_Version<SBVer_SB16)
{
g_Print("The current sound blaster doesn't support 16-bit digitized so"
"und data.\n");
return false;
}
SBOut(g_Port,0xD6);
_StartDMAH();
return true;
}
//=============================================================================
//Func: SBStop
//Desc: Stop(Pause) digitized sound ip
//-----------------------------------------------------------------------------
SB_f(void,SBStop)()
{
if(g_bPlaying8 || g_bRecording8)
_Stop8();
if(g_bPlaying16 || g_bRecording16)
_Stop16();
}
//=============================================================================
//Func: SBStart
//Desc: Start(Continue) digitized sound ip
//-----------------------------------------------------------------------------
SB_f(void,SBStart)()
{
if(g_bPlaying8 || g_bRecording8)
_Start8();
if(g_bPlaying16 || g_bRecording16)
_Start16();
}
//=============================================================================
//Func: SBOut8
//Desc: 8-bit auto-init mode digitized sound output
//-----------------------------------------------------------------------------
SB_f(bool_t,SBOut8)
(
void far*BufAddr,
uint16_t BufSize,
uint8_t uChannels,
uint32_t SplRate,
Buffer_f pfnOnBuffer
)
{
//Double buffering
uint16_t HalfSize;
if(g_Version<SBVer_SBLO)//no auto-init
{
g_Print("The current Sound Blaster doesn't support auto-init mode.\n");
return false;
}
if(g_Version<SBVer_SB16 & uChannels!=1)//no stereo
{
g_Print("The current Sound Blaster doesn't support stereo sound data."
"\n");
return false;
}
if(!_CheckDMAAddr(BufAddr,BufSize))
{
g_Print("DMA segbound wrapping.\n");
return false;
}
if(!SBSetOutSplRate(SplRate,uChannels))
return false;
SBStop();
g_SBInfo.pfnOnBuffer=pfnOnBuffer;
g_BufAddr=BufAddr;
g_BufSize=BufSize;
g_bFirstBuf=false;
_CallBufCB();
_CallBufCB();
_SetupDMAL(BufAddr,BufSize-uChannels,0);
//Double buffering
HalfSize=BufSize/2-uChannels;
if(uChannels==1)
{
if(g_Version<SBVer_SB16)
{
_SBSetBlockSize(HalfSize);
if(SplRate<=23000)//low speed
SBOut(g_Port,0x1C);
else
{
if(g_Version<SBVer_SBHI)
return false;
SBOut(g_Port,0x90);
}
}
else
{
SBOut(g_Port,0xC4);//Output, auto-init, no fifo
SBOut(g_Port,0x00);//mono, unsigned
SBOut(g_Port,HalfSize & 0xFF);
SBOut(g_Port,HalfSize >> 8);
}
}
else if(uChannels==2)
{
SBOut(g_Port,0xC4);//Output, auto-init, no fifo
SBOut(g_Port,0x20);//stereo, unsigned
SBOut(g_Port,HalfSize & 0xFF);
SBOut(g_Port,HalfSize >> 8);
}
else
return false;
g_bPlaying8=true;
g_bPlaying16=false;
g_bRecording8=false;
g_bRecording16=false;
return true;
}
//=============================================================================
//Func: SBIn8
//Desc: 8-bit auto-init mode digitized sound input
//-----------------------------------------------------------------------------
SB_f(bool_t,SBIn8)
(
void far*BufAddr,
uint16_t BufSize,
uint8_t uChannels,
uint32_t SplRate,
Buffer_f pfnOnBuffer
)
{
if(g_Version<SBVer_SBLO)//no auto-init
{
g_Print("The current Sound Blaster doesn't support auto-init mode.\n");
return false;
}
if(g_Version<SBVer_SB16 & uChannels!=1)//no stereo
{
g_Print("The current Sound Blaster doesn't support stereo sound data."
"\n");
return false;
}
if(!_CheckDMAAddr(BufAddr,BufSize))
{
g_Print("DMA segbound wrapping.\n");
return false;
}
if(!SBSetInSplRate(SplRate,uChannels))
return false;
SBStop();
g_SBInfo.pfnOnBuffer=pfnOnBuffer;
g_BufAddr=BufAddr;
g_BufSize=BufSize;
g_bFirstBuf=false;
//Double buffering
_SetupDMAL(BufAddr,BufSize-uChannels,1);
//Double buffering
BufSize=BufSize/2-uChannels;
if(uChannels==1)
{
if(g_Version<SBVer_SB16)
{
_SBSetBlockSize(BufSize);//Double buffer
if(SplRate<=23000)//low speed
SBOut(g_Port,0x2C);
else
{
if(g_Version<SBVer_SBHI)
return false;
SBOut(g_Port,0x98);
}
}
else
{
SBOut(g_Port,0xCC);//Input, auto-init, no fifo
SBOut(g_Port,0x00);//mono, unsigned
SBOut(g_Port,BufSize & 0xFF);
SBOut(g_Port,BufSize >> 8);
}
}
else if(uChannels==2)
{
SBOut(g_Port,0xCC);//Input, auto-init, no fifo
SBOut(g_Port,0x20);//stereo, unsigned
SBOut(g_Port,BufSize & 0xFF);
SBOut(g_Port,BufSize >> 8);
}
else
return false;
g_bPlaying8=false;
g_bPlaying16=false;
g_bRecording8=true;
g_bRecording16=false;
return true;
}
//=============================================================================
//Func: SBOut16
//Desc: 16-bit auto-init mode digitized sound output
//-----------------------------------------------------------------------------
SB_f(bool_t,SBOut16)
(
void far*BufAddr,
uint16_t BufSize,
uint8_t uChannels,
uint32_t SplRate,
Buffer_f pfnOnBuffer
)
{
//Double buffering
uint16_t HalfSize;
if(g_Version<SBVer_SB16)
{
g_Print("The current sound blaster doesn't support 16-bit digitized so"
"und data.\n");
return false;
}
if(uChannels!=1 && uChannels!=2)
{
g_Print("Invalid channel number.\n");
return false;
}
if(!_CheckDMAAddr(BufAddr,BufSize))
{
g_Print("DMA segbound wrapping.\n");
return false;
}
if(!SBSetOutSplRate(SplRate,uChannels))
return false;
SBStop();
g_SBInfo.pfnOnBuffer=pfnOnBuffer;
g_BufAddr=BufAddr;
g_BufSize=BufSize;
g_bFirstBuf=false;
_CallBufCB();
_CallBufCB();
_SetupDMAH(BufAddr,BufSize,0);
//Two bytes per sample, double buffering
HalfSize=BufSize/4-1;
SBOut(g_Port,0xB4);//Output, auto-init, no fifo
SBOut(g_Port,uChannels==1?0x10:0x30);//stereo, unsigned
SBOut(g_Port,HalfSize & 0xFF);
SBOut(g_Port,HalfSize >> 8);
g_bPlaying8=false;
g_bPlaying16=true;
g_bRecording8=false;
g_bRecording16=false;
return true;
}
//=============================================================================
//Func: SBIn16
//Desc: 16-bit auto-init mode digitized sound input
//-----------------------------------------------------------------------------
SB_f(bool_t,SBIn16)
(
void far*BufAddr,
uint16_t BufSize,
uint8_t uChannels,
uint32_t SplRate,
Buffer_f pfnOnBuffer
)
{
if(g_Version<SBVer_SB16)
{
g_Print("The current sound blaster doesn't support 16-bit digitized so"
"und data.\n");
return false;
}
if(uChannels!=1 && uChannels!=2)
{
g_Print("Invalid channel number.\n");
return false;
}
if(!_CheckDMAAddr(BufAddr,BufSize))
{
g_Print("DMA segbound wrapping.\n");
return false;
}
if(!SBSetInSplRate(SplRate,uChannels))
return false;
SBStop();
g_SBInfo.pfnOnBuffer=pfnOnBuffer;
g_BufAddr=BufAddr;
g_BufSize=BufSize;
g_bFirstBuf=false;
_SetupDMAH(BufAddr,BufSize,1);
//Two bytes per sample, double buffering
BufSize=BufSize/4-1;
SBOut(g_Port,0xBC);//Input, auto-init, no fifo
SBOut(g_Port,uChannels==1?0x10:0x30);//stereo, unsigned
SBOut(g_Port,BufSize & 0xFF);
SBOut(g_Port,BufSize >> 8);
g_bPlaying8=false;
g_bPlaying16=false;
g_bRecording8=false;
g_bRecording16=true;
return true;
}
//=============================================================================
//Func: SBSetVolume
//Desc: Set speaker volume
//-----------------------------------------------------------------------------
SB_f(bool_t,SBSetVolume)(uint8_t Master,uint8_t Voice,uint8_t Mic)
{
if(g_Version<SBVer_SBPro)
{
g_Print("The current sound blaster doesn't have a mixer.\n");
return false;
}
SBSetMixerReg(g_Port,SBMixer_MasterVol,Master);
SBSetMixerReg(g_Port,SBMixer_VoiceVol,Voice);
SBSetMixerReg(g_Port,SBMixer_MicVol,Mic);
return true;
}
//=============================================================================
//Func: SBSendMIDIByte
//Desc: Output MIDI data to the MIDI port in non-UART mode
//-----------------------------------------------------------------------------
SB_f(bool_t,SBSendMIDIByte)(uint8_t MIDI_Byte)
{
SBOut(g_Port,0x38);
SBOut(g_Port,MIDI_Byte);
return true;
}
1134Lines 不容易! cyycoish 发表于 2015-9-16 12:25
1134Lines 不容易!
已更新 666666666666666666666666 屌!一个C语言文件写的程序感觉好爽啊哈哈 谢谢分享 感谢分享
页:
[1]