📄 sb.c
字号:
/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \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 + -