⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 snd_gus.c

📁 quake1 dos源代码最新版本
💻 C
📖 第 1 页 / 共 3 页
字号:

//=============================================================================
// Programs the DMA controller to start DMAing in Auto-init mode
//=============================================================================
static void GUS_StartDMA(BYTE DmaChannel,short *dma_buffer,int count)
{
   int mode;
   int RealAddr;

   RealAddr = ptr2real(dma_buffer);

   if (DmaChannel <= 3)
   {
      ModeReg = 0x0B;
      DisableReg = 0x0A;
      ClearReg = 0x0E;
   }
   else
   {
      ModeReg = 0xD6;
      DisableReg = 0xD4;
      ClearReg = 0xDC;
   }
   CountReg=CountRegs[DmaChannel];
   AddrReg=AddrRegs[DmaChannel];

   dos_outportb(DisableReg, DmaChannel | 4);	// disable channel

   // set mode- see "undocumented pc", p.876
   mode = (1<<6)	        // single-cycle
          +(0<<5)	        // address increment
	  +(1<<4)	        // auto-init dma
	  +(2<<2)	        // read
	  +(DmaChannel & 0x03);	// channel #
   dos_outportb(ModeReg, mode);

   // set page
   dos_outportb(PageRegs[DmaChannel], RealAddr >> 16);

   if (DmaChannel <= 3)
   {	// address is in bytes
      dos_outportb(0x0C, 0);		// prepare to send 16-bit value
      dos_outportb(AddrReg, RealAddr & 0xff);
      dos_outportb(AddrReg, (RealAddr>>8) & 0xff);

      dos_outportb(0x0C, 0);		// prepare to send 16-bit value
      dos_outportb(CountReg, (count-1) & 0xff);
      dos_outportb(CountReg, (count-1) >> 8);
   }
   else
   {	// address is in words
      dos_outportb(0xD8, 0);	        // prepare to send 16-bit value
      dos_outportb(AddrReg, (RealAddr>>1) & 0xff);
      dos_outportb(AddrReg, (RealAddr>>9) & 0xff);

      dos_outportb(0xD8, 0);		// prepare to send 16-bit value
      dos_outportb(CountReg, ((count>>1)-1) & 0xff);
      dos_outportb(CountReg, ((count>>1)-1) >> 8);
   }

   dos_outportb(ClearReg, 0);		// clear write mask
   dos_outportb(DisableReg, DmaChannel & ~4);
}

//=============================================================================
// Starts the CODEC playing
//=============================================================================
static void GUS_StartCODEC(int count,BYTE FSVal)
{
   int i,j;

   // Clear any pending IRQs
   dos_inportb(CodecStatus);
   dos_outportb(CodecStatus,0);

   // Set mode to 2
   dos_outportb(CodecRegisterSelect,CODEC_MODE_AND_ID);
   dos_outportb(CodecData,0xC0);

   // Stop any playback or capture which may be happening
   dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
   dos_outportb(CodecData,dos_inportb(CodecData) & 0xFC);

   // Set FS
   dos_outportb(CodecRegisterSelect,CODEC_FS_FORMAT | 0x40);
   dos_outportb(CodecData,FSVal | 0x50); // Or in stereo and 16 bit bits

   // Wait a bit
   for (i=0;i<10;i++)
      dos_inportb(CodecData);

   // Routine 1 to counter CODEC bug - wait for init bit to clear and then a
   // bit longer (i=min loop count, j=timeout
   for (i=0,j=0;i<1000 && j<0x7FFFF;j++)
      if ((dos_inportb(CodecRegisterSelect) & 0x80)==0)
         i++;

   // Routine 2 to counter CODEC bug - this is from Forte's code. For me it
   // does not seem to cure the problem, but is added security
   // Waits till we can modify index register
   for (j=0;j<0x7FFFF;j++)
   {
      dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG | 0x40);
      if (dos_inportb(CodecRegisterSelect)==(CODEC_INTERFACE_CONFIG | 0x40))
         break;
   }

   // Perform ACAL
   dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG | 0x40);
   dos_outportb(CodecData,0x08);

   // Clear MCE bit - this makes ACAL happen
   dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);

   // Wait for ACAL to finish
   for (j=0;j<0x7FFFF;j++)
   {
      if ((dos_inportb(CodecRegisterSelect) & 0x80) != 0)
         continue;
      dos_outportb(CodecRegisterSelect,CODEC_ERROR_STATUS_AND_INIT);
      if ((dos_inportb(CodecData) & 0x20) == 0)
         break;
   }

   // Clear ACAL bit
   dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG | 0x40);
   dos_outportb(CodecData,0x00);
   dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);

   // Set some other junk
   dos_outportb(CodecRegisterSelect,CODEC_LOOPBACK_CONTROL);
   dos_outportb(CodecData,0x00);
   dos_outportb(CodecRegisterSelect,CODEC_PIN_CONTROL);
   dos_outportb(CodecData,0x08); // IRQ is disabled in PIN control

   // Set count (it doesn't really matter what value we stuff in here
   dos_outportb(CodecRegisterSelect,CODEC_PLAYBACK_LOWER_BASE_COUNT);
   dos_outportb(CodecData,count & 0xFF);
   dos_outportb(CodecRegisterSelect,CODEC_PLAYBACK_UPPER_BASE_COUNT);
   dos_outportb(CodecData,count >> 8);

   // Start playback
   dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
   dos_outportb(CodecData,0x01);
}

//=============================================================================
// Starts the GF1 playing
//=============================================================================
static void GUS_StartGf1(int count,BYTE Voices)
{
   DWORD StartAddressL,EndAddressL,StartAddressR,EndAddressR;

   // Set number of voices to give us the sampling rate we want
   SetGf18(SET_VOICES,0xC0 | (Voices-1));

   // Figure out addresses
   StartAddressL=ConvertTo16(0);
   EndAddressL=ConvertTo16(count-2-2);
   StartAddressR=ConvertTo16(2);
   EndAddressR=ConvertTo16(count-2);

   // Set left voice addresses
   dos_outportb(Gf1PageRegister,0);
   SetGf116(SET_START_LOW,StartAddressL<<9);
   SetGf116(SET_START_HIGH,StartAddressL>>7);
   SetGf116(SET_ACC_LOW,StartAddressL<<9);
   SetGf116(SET_ACC_HIGH,StartAddressL>>7);
   SetGf116(SET_END_LOW,EndAddressL<<9);
   SetGf116(SET_END_HIGH,EndAddressL>>7);
   // Set balance to full left
   SetGf18(SET_BALANCE,0);
   // Set volume to full
   SetGf116(SET_VOLUME,0xFFF0);
   // Set FC to 2 (so we play every second sample)
   SetGf116(SET_FREQUENCY,0x0800);

   // Set right voice addresses
   dos_outportb(Gf1PageRegister,1);
   SetGf116(SET_START_LOW,StartAddressR<<9);
   SetGf116(SET_START_HIGH,StartAddressR>>7);
   SetGf116(SET_ACC_LOW,StartAddressR<<9);
   SetGf116(SET_ACC_HIGH,StartAddressR>>7);
   SetGf116(SET_END_LOW,EndAddressR<<9);
   SetGf116(SET_END_HIGH,EndAddressR>>7);
   // Set balance to full right
   SetGf18(SET_BALANCE,15);
   // Set volume to full
   SetGf116(SET_VOLUME,0xFFF0);
   // Set FC to 2 (so we play every second sample)
   SetGf116(SET_FREQUENCY,0x0800);

   // Start voices
   dos_outportb(Gf1PageRegister,0);
   SetGf18(SET_CONTROL,0x0C);
   dos_outportb(Gf1PageRegister,1);
   SetGf18(SET_CONTROL,0x0C);
   Gf1Delay();
   dos_outportb(Gf1PageRegister,0);
   SetGf18(SET_CONTROL,0x0C);
   dos_outportb(Gf1PageRegister,1);
   SetGf18(SET_CONTROL,0x0C);
}


//=============================================================================
// Figures out what kind of UltraSound we have, if any, and starts it playing
//=============================================================================
qboolean GUS_Init(void)
{
	int rc;
	int RealAddr;
	BYTE FSVal,Voices;
	struct CodecRateStruct *CodecRate;
	struct Gf1RateStruct *Gf1Rate;

	// See what kind of UltraSound we have, if any
	if (GUS_GetIWData()==false)
		if (GUS_GetMAXData()==false)
			if (GUS_GetGUSData()==false)
				return(false);

	shm = &sn;

	if (HaveCodec)
	{
		// do 11khz sampling rate unless command line parameter wants different
		shm->speed = 11025;
		FSVal = 0x03;
		rc = COM_CheckParm("-sspeed");
		if (rc)
		{
			shm->speed = Q_atoi(com_argv[rc+1]);

			// Make sure rate not too high
			if (shm->speed>48000)
				shm->speed=48000;

			// Adjust speed to match one of the possible CODEC rates
			for (CodecRate=CodecRates;CodecRate->Rate!=0;CodecRate++)
			{
				if (shm->speed <= CodecRate->Rate)
				{
					shm->speed=CodecRate->Rate;
					FSVal=CodecRate->FSVal;
					break;
				}
			}
		}


		// Always do 16 bit stereo
		shm->channels = 2;
		shm->samplebits = 16;

		// allocate buffer twice the size we need so we can get aligned buffer
		dma_buffer = dos_getmemory(BUFFER_SIZE*2);
		if (dma_buffer==NULL)
		{
			Con_Printf("Couldn't allocate sound dma buffer");
			return false;
		}

		RealAddr = ptr2real(dma_buffer);
		RealAddr = (RealAddr + BUFFER_SIZE) & ~(BUFFER_SIZE-1);
		dma_buffer = (short *) real2ptr(RealAddr);

		// Zero off DMA buffer
		memset(dma_buffer, 0, BUFFER_SIZE);

		shm->soundalive = true;
		shm->splitbuffer = false;

		shm->samplepos = 0;
		shm->submission_chunk = 1;
		shm->buffer = (unsigned char *) dma_buffer;
		shm->samples = BUFFER_SIZE/(shm->samplebits/8);

		GUS_StartDMA(DmaChannel,dma_buffer,BUFFER_SIZE);
		GUS_StartCODEC(BUFFER_SIZE,FSVal);
	}
	else
	{
		// do 19khz sampling rate unless command line parameter wants different
		shm->speed = 19293;
		Voices=32;
		rc = COM_CheckParm("-sspeed");
		if (rc)
		{
			shm->speed = Q_atoi(com_argv[rc+1]);

			// Make sure rate not too high
			if (shm->speed>44100)
				shm->speed=44100;

			// Adjust speed to match one of the possible GF1 rates
			for (Gf1Rate=Gf1Rates;Gf1Rate->Rate!=0;Gf1Rate++)
			{
				if (shm->speed <= Gf1Rate->Rate)
				{
					shm->speed=Gf1Rate->Rate;
					Voices=Gf1Rate->Voices;
					break;
				}
			}
		}

		// Always do 16 bit stereo
		shm->channels = 2;
		shm->samplebits = 16;

		// allocate buffer twice the size we need so we can get aligned buffer
		dma_buffer = dos_getmemory(BUFFER_SIZE*2);
		if (dma_buffer==NULL)
		{
			Con_Printf("Couldn't allocate sound dma buffer");
			return false;
		}

		RealAddr = ptr2real(dma_buffer);
		RealAddr = (RealAddr + BUFFER_SIZE) & ~(BUFFER_SIZE-1);
		dma_buffer = (short *) real2ptr(RealAddr);

		// Zero off DMA buffer
		memset(dma_buffer, 0, BUFFER_SIZE);

		shm->soundalive = true;
		shm->splitbuffer = false;

		shm->samplepos = 0;
		shm->submission_chunk = 1;
		shm->buffer = (unsigned char *) dma_buffer;
		shm->samples = BUFFER_SIZE/(shm->samplebits/8);

		GUS_StartDMA(DmaChannel,dma_buffer,BUFFER_SIZE);
		SetGf116(SET_DMA_ADDRESS,0x0000);
		if (DmaChannel<=3)
			SetGf18(DMA_CONTROL,0x41);
		else
			SetGf18(DMA_CONTROL,0x45);
		GUS_StartGf1(BUFFER_SIZE,Voices);
	}
	return(true);
}

//=============================================================================
// Returns the current playback position
//=============================================================================
int GUS_GetDMAPos(void)
{
   int count;

	if (HaveCodec)
	{
	   // clear 16-bit reg flip-flop
 	  // load the current dma count register
 	  if (DmaChannel < 4)
 	  {
 	     dos_outportb(0x0C, 0);
 	     count = dos_inportb(CountReg);
 	     count += dos_inportb(CountReg) << 8;
 	     if (shm->samplebits == 16)
 	        count /= 2;
 	     count = shm->samples - (count+1);
 	  }
 	  else
 	  {
 	     dos_outportb(0xD8, 0);
 	     count = dos_inportb(CountReg);
 	     count += dos_inportb(CountReg) << 8;
 	     if (shm->samplebits == 8)
 	        count *= 2;
 	     count = shm->samples - (count+1);
 	  }

	}
	else
	{
		// Read current position from GF1
		dos_outportb(Gf1PageRegister,0);
		count=(GetGf116(GET_ACC_HIGH)<<7) & 0xFFFF;
		// See which half of buffer we are in. Note that since this is 16 bit
		// data we are playing, position is in 16 bit samples
		if (GetGf18(DMA_CONTROL) & 0x40)
		{
			GUS_StartDMA(DmaChannel,dma_buffer,BUFFER_SIZE);
			SetGf116(SET_DMA_ADDRESS,0x0000);
			if (DmaChannel<=3)
				SetGf18(DMA_CONTROL,0x41);
			else
				SetGf18(DMA_CONTROL,0x45);
		}
	}

   shm->samplepos = count & (shm->samples-1);
   return(shm->samplepos);
}

//=============================================================================
// Stops the UltraSound playback
//=============================================================================
void GUS_Shutdown (void)
{
	if (HaveCodec)
	{
		// Stop CODEC
		dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
		dos_outportb(CodecData,0x01);
	}
	else
	{
		// Stop Voices
		dos_outportb(Gf1PageRegister,0);
		SetGf18(SET_CONTROL,0x03);
		dos_outportb(Gf1PageRegister,1);
		SetGf18(SET_CONTROL,0x03);
		Gf1Delay();
		dos_outportb(Gf1PageRegister,0);
		SetGf18(SET_CONTROL,0x03);
		dos_outportb(Gf1PageRegister,1);
		SetGf18(SET_CONTROL,0x03);

		// Stop any DMA
		SetGf18(DMA_CONTROL,0x00);
		GetGf18(DMA_CONTROL);
	}

	dos_outportb(DisableReg, DmaChannel | 4); // disable dma channel
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -