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

📄 sb.c

📁 著名SFC模拟器Snes9x的源代码。
💻 C
📖 第 1 页 / 共 2 页
字号:
/*         ______   ___    ___  *        /\  _  \ /\_ \  /\_ \  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\ *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \ *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ *                                           /\____/ *                                           \_/__/ *      By Shawn Hargreaves, *      1 Salisbury Road, *      Market Drayton, *      Shropshire, *      England, TF9 1AJ. * *      Soundblaster driver. Supports DMA driven sample playback (mixing  *      up to eight samples at a time) and raw note output to the SB MIDI  *      port. The Adlib (FM synth) MIDI playing code is in adlib.c. * *      Input routines added by Ove Kaaven. * *      See readme.txt for copyright information. */#ifndef DJGPP#error This file should only be used by the djgpp version of Allegro#endif#include <stdlib.h>#include <stdio.h>#include <dos.h>#include <go32.h>#include <dpmi.h>#include <limits.h>#include <sys/farptr.h>#include <allegro.h>#include "sb.h"#define SB_DMA_BUFFER_SIZE       32#define DISABLE()   asm volatile ("cli")#define ENABLE()    asm volatile ("sti")/* interrupt hander stuff */#define _map_irq(irq)   (((irq)>7) ? ((irq)+104) : ((irq)+8))#define _eoi(irq) { outportb(0x20, 0x20); if ((irq)>7) outportb(0xA0, 0x20); }/* external interface to the digital SB driver */void sx_sb_exit ();static int sx_sb_mixer_volume(int volume);char sx_sb_desc[80] = "not initialised";/* external interface to the SB midi output driver */static int sx_sb_in_use = FALSE;             /* is SB being used? */static int sx_sb_stereo = FALSE;             /* in stereo mode? */static int sx_sb_16bit = FALSE;              /* in 16 bit mode? */static int sx_sb_int = -1;                   /* interrupt vector */static int sx_sb_dsp_ver = -1;               /* SB DSP version */static int sx_sb_dma8 = -1;                  /* 8-bit DMA channel (SB16) */static int sx_sb_dma16 = -1;                 /* 16-bit DMA channel (SB16) */static int sx_sb_hw_dsp_ver = -1;            /* as reported by autodetect */static int sx_sb_dma_size = -1;              /* size of dma transfer in bytes */static int sx_sb_dma_mix_size = -1;          /* number of samples to mix */static int sx_sb_dma_count = 0;              /* need to resync with dma? */static volatile int sx_sb_semaphore = FALSE; /* reentrant interrupt? */static int sx_sb_freq = -1;static int sx_sb_irq = -1;static int sx_sb_dma = -1;static int sx_sb_port = -1;static int sx_sb_mute = 0;static char * mixbuffer = NULL;static int sx_sb_sel[2];                     /* selectors for the buffers */static unsigned long sx_sb_buf[2];           /* pointers to the two buffers */static int sx_sb_bufnum = 0;                 /* the one currently in use */static int sx_sb_master_vol;                 /* stored mixer settings */static int sx_sb_digi_vol;static int sx_sb_fm_vol;static void sx_sb_lock_mem();/* sx_sb_read_dsp: *  Reads a byte from the SB DSP chip. Returns -1 if it times out. */static inline volatile int sx_sb_read_dsp(){   int x;   for (x=0; x<0xffff; x++)      if (inportb(0x0E + sx_sb_port) & 0x80)	 return inportb(0x0A+sx_sb_port);   return -1; }/* sx_sb_write_dsp: *  Writes a byte to the SB DSP chip. Returns -1 if it times out. */static inline volatile int sx_sb_write_dsp(unsigned char byte){   int x;   for (x=0; x<0xffff; x++) {      if (!(inportb(0x0C+sx_sb_port) & 0x80)) {	 outportb(0x0C+sx_sb_port, byte);	 return 0;      }   }   return -1; }/* sx_sb_voice: *  Turns the SB speaker on or off. */void sx_sb_voice(int state){   if (state) {      sx_sb_write_dsp(0xD1);      if (sx_sb_hw_dsp_ver >= 0x300) {       /* set up the mixer */	 outportb(sx_sb_port+4, 0x22);      /* store master volume */	 sx_sb_master_vol = inportb(sx_sb_port+5);	 outportb(sx_sb_port+4, 4);         /* store DAC level */	 sx_sb_digi_vol = inportb(sx_sb_port+5);	 outportb(sx_sb_port+4, 0x26);      /* store FM level */	 sx_sb_fm_vol = inportb(sx_sb_port+5);      }   }   else {      sx_sb_write_dsp(0xD3);      if (sx_sb_hw_dsp_ver >= 0x300) {       /* reset previous mixer settings */	 outportb(sx_sb_port+4, 0x22);      /* restore master volume */	 outportb(sx_sb_port+5, sx_sb_master_vol);	 outportb(sx_sb_port+4, 4);         /* restore DAC level */	 outportb(sx_sb_port+5, sx_sb_digi_vol);	 outportb(sx_sb_port+4, 0x26);      /* restore FM level */	 outportb(sx_sb_port+5, sx_sb_fm_vol);      }   }}/* sx_sb_set_mixer: *  Alters the SB-Pro hardware mixer. */int sx_sb_set_mixer(int digi_volume, int midi_volume){   if (sx_sb_hw_dsp_ver < 0x300)      return -1;   if (digi_volume >= 0) {                   /* set DAC level */      outportb(sx_sb_port+4, 4);      outportb(sx_sb_port+5, (digi_volume & 0xF0) | (digi_volume >> 4));   }   if (midi_volume >= 0) {                   /* set FM level */      outportb(sx_sb_port+4, 0x26);      outportb(sx_sb_port+5, (midi_volume & 0xF0) | (midi_volume >> 4));   }   return 0;}/* sx_sb_mixer_volume: *  Sets the SB mixer volume for playing digital samples. */static int sx_sb_mixer_volume(int volume){   return sx_sb_set_mixer(volume, -1);}/* sx_sb_stereo_mode: *  Enables or disables stereo output for SB-Pro. */static void sx_sb_stereo_mode(int enable){   outportb(sx_sb_port+0x04, 0x0E);    outportb(sx_sb_port+0x05, (enable ? 2 : 0));}/* sx_sb_set_sample_rate: *  The parameter is the rate to set in Hz (samples per second). */static void sx_sb_set_sample_rate(unsigned int rate){   if (sx_sb_16bit) {      sx_sb_write_dsp(0x41);      sx_sb_write_dsp(rate >> 8);      sx_sb_write_dsp(rate & 0xff);   }   else {      if (sx_sb_stereo)	 rate *= 2;      sx_sb_write_dsp(0x40);      sx_sb_write_dsp((unsigned char)(256-1000000/rate));   }}/* sx_sb_reset_dsp: *  Resets the SB DSP chip, returning -1 on error. */int sx_sb_reset_dsp(int data){   int x;   outportb(0x06+sx_sb_port, data);   for (x=0; x<8; x++)      inportb(0x06+sx_sb_port);   outportb(0x06+sx_sb_port, 0);   if (sx_sb_read_dsp() != 0xAA)      return -1;   return 0;}/* sx_sb_read_dsp_version: *  Reads the version number of the SB DSP chip, returning -1 on error. */int sx_sb_read_dsp_version(){   int x, y;   if (sx_sb_hw_dsp_ver > 0)      return sx_sb_hw_dsp_ver;   if (sx_sb_port <= 0)      sx_sb_port = 0x220;   if (sx_sb_reset_dsp(1) != 0) {      sx_sb_hw_dsp_ver = -1;   }   else {      sx_sb_write_dsp(0xE1);      x = sx_sb_read_dsp();      y = sx_sb_read_dsp();      sx_sb_hw_dsp_ver = ((x << 8) | y);   }   return sx_sb_hw_dsp_ver;}/* sx_sb_play_buffer: *  Starts a dma transfer of size bytes. On cards capable of it, the *  transfer will use auto-initialised dma, so there is no need to call *  this routine more than once. On older cards it must be called from *  the end-of-buffer handler to switch to the new buffer. */static void sx_sb_play_buffer(int size){   if (sx_sb_dsp_ver <= 0x200) {                /* 8 bit single-shot */      sx_sb_write_dsp(0x14);      sx_sb_write_dsp((size-1) & 0xFF);      sx_sb_write_dsp((size-1) >> 8);   }   else if (sx_sb_dsp_ver < 0x400) {            /* 8 bit auto-initialised */      sx_sb_write_dsp(0x48);      sx_sb_write_dsp((size-1) & 0xFF);      sx_sb_write_dsp((size-1) >> 8);      sx_sb_write_dsp(0x90);   }   else {                                    /* 16 bit */      size /= 2;      sx_sb_write_dsp(0xB6);      sx_sb_write_dsp((sx_sb_stereo ? 0x20 : 0x00) + 0x10);      /*sx_sb_write_dsp(0x20);*/      sx_sb_write_dsp((size-1) & 0xFF);      sx_sb_write_dsp((size-1) >> 8);   }}static END_OF_FUNCTION(sx_sb_play_buffer);/* sx_sb_interrupt: *  The SB end-of-buffer interrupt handler. Swaps to the other buffer  *  if the card doesn't have auto-initialised dma, and then refills the *  buffer that just finished playing. */static int sx_sb_interrupt(){   unsigned char isr;   if (sx_sb_dsp_ver >= 0x400) {      /* read SB16 ISR mask */      outportb(sx_sb_port+4, 0x82);      isr = inportb(sx_sb_port+5) & 7;      if (isr & 4) {	 /* MPU-401 interrupt */	 /*_mpu_poll();*/	 _eoi(sx_sb_irq);	 return 0;      }      if (!(isr & 3)) {	 /* unknown interrupt */	 _eoi(sx_sb_irq);	 return 0;      }   }   if (sx_sb_dsp_ver <= 0x200) {                /* not auto-initialised */      _dma_start(sx_sb_dma, sx_sb_buf[1-sx_sb_bufnum], sx_sb_dma_size, FALSE, FALSE);      sx_sb_play_buffer(sx_sb_dma_size);   }   else {                                    /* poll dma position */      sx_sb_dma_count++;      if (sx_sb_dma_count > 16) {	 sx_sb_bufnum = (_dma_todo(sx_sb_dma) > (unsigned)sx_sb_dma_size) ? 1 : 0;	 sx_sb_dma_count = 0;      }   }   if (!sx_sb_semaphore) {      sx_sb_semaphore = TRUE;      ENABLE();                              /* mix some more samples */      sx_sb_mix_some_samples(sx_sb_buf[sx_sb_bufnum], _dos_ds);      DISABLE();      sx_sb_semaphore = FALSE;   }    sx_sb_bufnum = 1 - sx_sb_bufnum;    if (sx_sb_16bit)                             /* acknowledge SB */      inportb(sx_sb_port+0x0F);   else      inportb(sx_sb_port+0x0E);   _eoi(sx_sb_irq);                            /* acknowledge interrupt */   return 0;}static END_OF_FUNCTION(sx_sb_interrupt);void sx_sb_mix_some_samples(unsigned long buf, unsigned short seg){    int i;    if (sx_sb_mute) {       _farsetsel(seg);       if (sx_sb_16bit) {          for (i=0; i<sx_sb_dma_mix_size; i++) {             _farnspokew(buf, 0x0);             buf += 2;          }       }

⌨️ 快捷键说明

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