home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1998 June B
/
Pcwk6b98.iso
/
Mpeg3
/
Dos
/
MP3
/
MPG12304.EXE
/
AUDIO.N
< prev
next >
Wrap
Text File
|
1997-04-30
|
15KB
|
706 lines
#include <dos.h>
#include "audio.h"
#include "mpg123.h"
#include "mdma.h"
void UltraSetInterface(int,int,int,int);
void GF1OutB(UBYTE,UBYTE);
void GF1OutW(UBYTE,UWORD);
UBYTE UltraPeek(ULONG);
void interrupt far gf1handler(void);
void gf1_delay(void);
void UltraPoke(ULONG,UBYTE);
BOOL UltraProbe(void);
void UltraDisableOutput(void);
void UltraDisableLineIn(void);
void UltraDisableMicIn(void);
BOOL UltraDetect(void);
int next(int);
BOOL MIrq_OnOff(UBYTE irqno,UBYTE onoff);
PVI MIrq_SetHandler(UBYTE irqno,PVI handler);
void MIrq_EOI(UBYTE irqno);
UWORD UltraSizeDram();
void ultrastop();
void ultrastart();
UBYTE GF1InB(UBYTE);
void UltraReset(int);
BOOL UltraPP(ULONG);
void UltraClose();
void UltraSetFrequency(ULONG);
ULONG convert_to_16bit(ULONG);
ULONG UltraReadVoice(UBYTE);
ULONG make_physical_address(UWORD,UWORD,UBYTE);
UWORD GF1InW(UBYTE);
UWORD GUS_PORT;
UBYTE GUS_VOICES;
UBYTE GUS_MIX_IMAGE;
UWORD GUS_DRAM_DMA;
UWORD GUS_ADC_DMA;
UWORD GUS_GF1_IRQ;
UWORD GUS_MIDI_IRQ;
UBYTE GUS_SELECT; /* currently selected GF1 register */
PVI oldhandler;
DMAMEM * dma_control;
static int store,play,playing;
int bufs,memsize;
int audio_open(struct audio_info_struct *ai)
{
UBYTE vmode,mode;
if (ultradetect() == 0)
{
perror("Ultrasound not detected (sorry. SB support not finished)");
return -1;
}
GUS_MIX_IMAGE=0x0b;
UltraDisableLineIn();
UltraDisableMicIn();
UltraDisableOutput();
UltraReset(14);
if ((memsize=UltraSizeDram())==0)
{
perror("Go buy some memory for your GUS.");
return -1;
}
oldhandler=MIrq_SetHandler(GUS_GF1_IRQ,gf1handler);
MIrq_OnOff(GUS_GF1_IRQ,1);
bufs=memsize/(AUDIOBUFSIZE*2/1024);
store=0;
play=0;
playing=2;
outportb(GF1_VOICE_SELECT,0);
GF1OutW(SET_START_HIGH,0);
GF1OutW(SET_START_LOW,0);
vmode = VC_ROLLOVER|VOLUME_STOPPED|STOP_VOLUME;
GF1OutB(SET_VOLUME_CONTROL,vmode);
gf1_delay();
GF1OutB(SET_VOLUME_CONTROL,vmode);
GF1OutB(SET_BALANCE,0);
GF1OutW(SET_VOLUME,0xfff<<4);
mode=(VC_DATA_TYPE|VOICE_STOPPED|STOP_VOICE);
GF1OutB(SET_CONTROL,mode);
gf1_delay();
GF1OutB(SET_CONTROL,mode);
outportb(GF1_VOICE_SELECT,1);
GF1OutW(SET_START_HIGH,ADDR_HIGH(convert_to_16bit(bufs*AUDIOBUFSIZE)));
GF1OutW(SET_START_LOW,ADDR_LOW(convert_to_16bit(bufs*AUDIOBUFSIZE)));
vmode = VC_ROLLOVER|VOLUME_STOPPED|STOP_VOLUME;
GF1OutB(SET_VOLUME_CONTROL,vmode);
gf1_delay();
GF1OutB(SET_VOLUME_CONTROL,vmode);
GF1OutB(SET_BALANCE,0xf);
GF1OutW(SET_VOLUME,0xfff<<4);
mode=(VOICE_STOPPED|STOP_VOICE|VC_DATA_TYPE);
GF1OutB(SET_CONTROL,mode);
gf1_delay();
GF1OutB(SET_CONTROL,mode);
dma_control = MDma_AllocMem(AUDIOBUFSIZE);
return 0;
}
int audio_set_rate(struct audio_info_struct *ai)
{
outportb(GF1_VOICE_SELECT,0);
UltraSetFrequency(ai->rate);
outportb(GF1_VOICE_SELECT,1);
UltraSetFrequency(ai->rate);
return 0;
}
int audio_set_channels(struct audio_info_struct *ai)
{
return 0;
}
int audio_play_samples(struct audio_info_struct *ai,short *src,int size)
{
char * ptr;
int c,s,addr;
char * dma_block;
fprintf(stderr,"playing %d, play %d, store %d, ltrue %d, rtrue %d ",playing,play,store,UltraReadVoice(0)/AUDIOBUFSIZE,UltraReadVoice(1)/AUDIOBUFSIZE-bufs);
if (playing != 2)
while (store == play)
if (playing == 0)
ultrastart();
ptr=(char *) src;
s=bufs*AUDIOBUFSIZE;
addr=store*AUDIOBUFSIZE;
dma_block = MDma_GetPtr(dma_control);
store=next(store);
if (playing == 2)
playing=0;
return 0;
}
int audio_close(struct audio_info_struct *ai)
{
UltraClose();
MDma_FreeMem(dma_control);
return 0;
}
static void interrupt far gf1handler(MIRQARGS)
{
ULONG phys_end;
UBYTE oldselect=GUS_SELECT;
UBYTE mode;
inportb(GF1_IRQ_STAT);
GF1InB(GET_IRQV);
play=next(play);
outportb(GF1_VOICE_SELECT,0);
phys_end = convert_to_16bit(play*AUDIOBUFSIZE+AUDIOBUFSIZE-1);
GF1OutW(SET_END_HIGH,ADDR_HIGH(phys_end));
GF1OutW(SET_END_LOW,ADDR_LOW(phys_end));
outportb(GF1_VOICE_SELECT,1);
phys_end = convert_to_16bit(bufs*AUDIOBUFSIZE+play*AUDIOBUFSIZE+AUDIOBUFSIZE-1);
GF1OutW(SET_END_HIGH,ADDR_HIGH(phys_end));
GF1OutW(SET_END_LOW,ADDR_LOW(phys_end));
if (play == bufs-1)
{
outportb(GF1_VOICE_SELECT,0);
mode=(VC_WAVE_IRQ|VC_DATA_TYPE|VC_LOOP_ENABLE);
GF1OutB(SET_CONTROL,mode);
gf1_delay();
GF1OutB(SET_CONTROL,mode);
outportb(GF1_VOICE_SELECT,1);
mode=(VC_DATA_TYPE|VC_LOOP_ENABLE);
GF1OutB(SET_CONTROL,mode);
gf1_delay();
GF1OutB(SET_CONTROL,mode);
}
else
{
outportb(GF1_VOICE_SELECT,0);
mode=(VC_WAVE_IRQ|VC_DATA_TYPE);
GF1OutB(SET_CONTROL,mode);
gf1_delay();
GF1OutB(SET_CONTROL,mode);
outportb(GF1_VOICE_SELECT,1);
mode=(VC_DATA_TYPE);
GF1OutB(SET_CONTROL,mode);
gf1_delay();
GF1OutB(SET_CONTROL,mode);
}
if (play == store)
{
ultrastop();
}
UltraSelect(oldselect);
MIrq_EOI(GUS_GF1_IRQ);
}
void UltraReset(int voices)
{
int v;
if(voices<14) voices=14;
if(voices>32) voices=32;
GUS_VOICES=voices;
GF1OutB(MASTER_RESET,0x00);
for(v=0;v<10;v++) gf1_delay();
GF1OutB(MASTER_RESET,GF1_MASTER_RESET);
for (v=0;v<10;v++) gf1_delay();
outportb(GF1_MIDI_CTRL,MIDI_RESET);
for (v=0;v<10;v++) gf1_delay();
outportb(GF1_MIDI_CTRL,0x00);
for (v=0;v<10;v++) gf1_delay();
UltraSetInterface(GUS_DRAM_DMA,GUS_ADC_DMA,GUS_GF1_IRQ,GUS_MIDI_IRQ);
/* Clear all interrupts. */
GF1OutB(DMA_CONTROL,0x00);
GF1OutB(TIMER_CONTROL,0x00);
GF1OutB(SAMPLE_CONTROL,0x00);
/* Set the number of active voices */
GF1OutB(SET_VOICES,((voices-1) | 0xC0));
/* Clear interrupts on voices. */
/* Reading the status ports will clear the irqs. */
inportb(GF1_IRQ_STAT);
GF1InB(DMA_CONTROL);
GF1InB(SAMPLE_CONTROL);
GF1InB(GET_IRQV);
for(v=0;v<voices;v++){
outportb(GF1_PAGE,v);
GF1OutB(SET_CONTROL,VOICE_STOPPED|STOP_VOICE);
GF1OutB(SET_VOLUME_CONTROL,VOLUME_STOPPED|STOP_VOLUME);
gf1_delay(); /* Wait 4.8 micos. or more. */
GF1OutW(SET_FREQUENCY,0x0400);
GF1OutW(SET_START_HIGH,0);
GF1OutW(SET_START_LOW,0);
GF1OutW(SET_END_HIGH,0);
GF1OutW(SET_END_LOW,0);
GF1OutB(SET_VOLUME_RATE,0x01);
GF1OutB(SET_VOLUME_START,0x10);
GF1OutB(SET_VOLUME_END,0xe0);
GF1OutW(SET_VOLUME,0x0000);
GF1OutW(SET_ACC_HIGH,0);
GF1OutW(SET_ACC_LOW,0);
GF1OutB(SET_BALANCE,0x07);
}
inportb(GF1_IRQ_STAT);
GF1InB(DMA_CONTROL);
GF1InB(SAMPLE_CONTROL);
GF1InB(GET_IRQV);
GF1OutB(MASTER_RESET,GF1_MASTER_RESET|GF1_OUTPUT_ENABLE|GF1_MASTER_IRQ);
}
BOOL MIrq_OnOff(UBYTE irqno,UBYTE onoff)
{
UBYTE imr=(irqno>7) ? IMR2 : IMR1; /* interrupt mask register */
UBYTE ocr=(irqno>7) ? OCR2 : OCR1; /* ocr */
UBYTE msk=1<<(irqno&7); /* interrupt mask */
UBYTE eoi=0x60|(irqno&7); /* specific end-of-interrupt */
BOOL oldstate;
/* save current setting of this irq */
oldstate=((inportb(imr) & msk) == 0);
if(onoff){
outportb(imr,inportb(imr) & ~msk);
outportb(ocr,eoi);
if(irqno>7) MIrq_OnOff(2,1);
}
else{
outportb(imr,inportb(imr) | msk);
}
return oldstate;
}
void MIrq_EOI(UBYTE irqno)
{
outportb(0x20,0x20);
if(irqno>7) outportb(0xa0,0x20);
}
PVI MIrq_SetHandler(UBYTE irqno,PVI handler)
{
PVI oldvect;
unsigned int vecno=(irqno>7) ? irqno+0x68 : irqno+0x8;
oldvect=(PVI)_dos_getvect(vecno);
_dos_setvect(vecno,handler);
return oldvect;
}
UWORD UltraSizeDram(void)
{
if(!UltraPP(0)) return 0;
if(!UltraPP(262144)) return 256;
if(!UltraPP(524288)) return 512;
if(!UltraPP(786432)) return 768;
return 1024;
}
UBYTE GF1InB(UBYTE x)
{
UltraSelect(x);
return inportb(GF1_DATA_HI);
}
BOOL UltraPP(ULONG address)
{
UBYTE s,t;
s=UltraPeek(address);
UltraPoke(address,0xaa);
t=UltraPeek(address);
UltraPoke(address,s);
return(t==0xaa);
}
void UltraClose(void)
{
MIrq_OnOff(GUS_GF1_IRQ,0);
MIrq_SetHandler(GUS_GF1_IRQ,oldhandler);
UltraDisableOutput();
UltraDisableLineIn();
UltraDisableMicIn();
UltraReset(14);
}
void UltraSetFrequency(ULONG speed_khz)
{
// GF1OutW(SET_FREQUENCY,(((speed_khz<<9L)+(44100>>1L))/44100)<<1);
GF1OutW(SET_FREQUENCY,(int)(((float)speed_khz)/43.0243902439));
}
void ultrastop()
{
UBYTE mode;
outportb(GF1_VOICE_SELECT,0);
mode=VC_DATA_TYPE|VOICE_STOPPED|STOP_VOICE;
GF1OutB(SET_CONTROL,mode);
gf1_delay();
GF1OutB(SET_CONTROL,mode);
outportb(GF1_VOICE_SELECT,1);
mode=VC_DATA_TYPE|VOICE_STOPPED|STOP_VOICE;
GF1OutB(SET_CONTROL,mode);
gf1_delay();
GF1OutB(SET_CONTROL,mode);
playing=0;
}
void ultrastart()
{
ULONG phys_end;
ULONG phys_begin;
UBYTE mode;
outportb(GF1_VOICE_SELECT,0);
phys_begin = convert_to_16bit(play*AUDIOBUFSIZE);
phys_end = convert_to_16bit(play*AUDIOBUFSIZE+AUDIOBUFSIZE-1);
GF1OutW(SET_ACC_LOW,ADDR_LOW(phys_begin));
GF1OutW(SET_ACC_HIGH,ADDR_HIGH(phys_begin));
GF1OutW(SET_END_HIGH,ADDR_HIGH(phys_end));
GF1OutW(SET_END_LOW,ADDR_LOW(phys_end));
outportb(GF1_VOICE_SELECT,1);
phys_begin = convert_to_16bit(play*AUDIOBUFSIZE+bufs*AUDIOBUFSIZE);
phys_end = convert_to_16bit(play*AUDIOBUFSIZE+bufs*AUDIOBUFSIZE+AUDIOBUFSIZE-1);
GF1OutW(SET_ACC_LOW,ADDR_LOW(phys_begin));
GF1OutW(SET_ACC_HIGH,ADDR_HIGH(phys_begin));
GF1OutW(SET_END_HIGH,ADDR_HIGH(phys_end));
GF1OutW(SET_END_LOW,ADDR_LOW(phys_end));
outportb(GF1_VOICE_SELECT,0);
mode=(VC_WAVE_IRQ|VC_DATA_TYPE);
GF1OutB(SET_CONTROL,mode);
gf1_delay();
GF1OutB(SET_CONTROL,mode);
outportb(GF1_VOICE_SELECT,1);
mode=(VC_DATA_TYPE);
GF1OutB(SET_CONTROL,mode);
gf1_delay();
GF1OutB(SET_CONTROL,mode);
if (play == bufs-1)
{
outportb(GF1_VOICE_SELECT,0);
mode=(VC_WAVE_IRQ|VC_DATA_TYPE|VC_LOOP_ENABLE);
GF1OutB(SET_CONTROL,mode);
gf1_delay();
GF1OutB(SET_CONTROL,mode);
outportb(GF1_VOICE_SELECT,1);
mode=(VC_DATA_TYPE|VC_LOOP_ENABLE);
GF1OutB(SET_CONTROL,mode);
gf1_delay();
GF1OutB(SET_CONTROL,mode);
}
playing=1;
}
ULONG convert_to_16bit(ULONG address)
/* unsigned long address; /* 20 bit ultrasound dram address */
{
ULONG hold_address;
hold_address = address;
/* Convert to 16 translated address. */
address = address >> 1;
/* Zero out bit 17. */
address &= 0x0001ffffL;
/* Reset bits 18 and 19. */
address |= (hold_address & 0x000c0000L);
return(address);
}
void GF1OutB(UBYTE x,UBYTE y)
{
UltraSelect(x);
outportb(GF1_DATA_HI,y);
}
void GF1OutW(UBYTE x,UWORD y)
{
UltraSelect(x);
outport(GF1_DATA_LOW,y);
}
UBYTE UltraPeek(ULONG address)
{
GF1OutW(SET_DRAM_LOW,address);
GF1OutB(SET_DRAM_HIGH,(address>>16)&0xff); /* 8 bits */
return(inportb(GF1_DRAM));
}
void gf1_delay(void)
{
inportb(GF1_DRAM);
inportb(GF1_DRAM);
inportb(GF1_DRAM);
inportb(GF1_DRAM);
inportb(GF1_DRAM);
inportb(GF1_DRAM);
inportb(GF1_DRAM);
}
void UltraPoke(ULONG address,UBYTE data)
{
GF1OutW(SET_DRAM_LOW,(short)address&0xffff);
GF1OutB(SET_DRAM_HIGH,(address>>16)&0xff);
outportb(GF1_DRAM,data);
}
BOOL UltraProbe(void)
{
UBYTE s1,s2,t1,t2;
/* Pull a reset on the GF1 */
GF1OutB(MASTER_RESET,0x00);
/* Wait a little while ... */
gf1_delay();
gf1_delay();
/* Release Reset */
GF1OutB(MASTER_RESET,GF1_MASTER_RESET);
gf1_delay();
gf1_delay();
s1=UltraPeek(0); s2=UltraPeek(1);
UltraPoke(0,0xaa); t1=UltraPeek(0);
UltraPoke(1,0x55); t2=UltraPeek(1);
UltraPoke(0,s1); UltraPoke(1,s2);
return(t1==0xaa && t2==0x55);
}
void UltraDisableOutput(void)
{
GUS_MIX_IMAGE |= ENABLE_OUTPUT;
outportb(GF1_MIX_CTRL,GUS_MIX_IMAGE);
}
void UltraDisableLineIn(void)
{
GUS_MIX_IMAGE |= ENABLE_LINE_IN;
outportb(GF1_MIX_CTRL,GUS_MIX_IMAGE);
}
void UltraDisableMicIn(void)
{
GUS_MIX_IMAGE &= ~ENABLE_MIC_IN;
outportb(GF1_MIX_CTRL,GUS_MIX_IMAGE);
}
BOOL UltraDetect(void)
{
char * pointa;
pointa=(char *)getenv("ULTRASND");
if(pointa==0) return 0;
if(sscanf(pointa,"%hx,%hd,%hd,%hd,%hd",
&GUS_PORT,
&GUS_DRAM_DMA,
&GUS_ADC_DMA,
&GUS_GF1_IRQ,
&GUS_MIDI_IRQ)!=5) return 0;
return(UltraProbe());
}
int next(int supa)
{
if (supa+1 == bufs)
return 0;
return (supa+1);
}
UBYTE dmalatch[8] ={ 0,1,0,2,0,3,4,5 };
UBYTE irqlatch[16] ={ 0,0,1,3,0,2,0,4,0,0,0,5,6,0,0,7 };
void UltraSetInterface(int dram,int adc,int gf1,int midi)
/* int dram; /* dram dma chan */
/* int adc; /* adc dma chan */
/* int gf1; /* gf1 irq # */
/* int midi; /* midi irq # */
{
UBYTE gf1_irq, midi_irq,dram_dma,adc_dma;
UBYTE irq_control,dma_control;
UBYTE mix_image;
/* Don't need to check for 0 irq #. Its latch entry = 0 */
gf1_irq =irqlatch[gf1];
midi_irq=irqlatch[midi];
midi_irq<<=3;
dram_dma=dmalatch[dram];
adc_dma =dmalatch[adc];
adc_dma<<=3;
irq_control=dma_control=0x0;
mix_image=GUS_MIX_IMAGE;
irq_control|=gf1_irq;
if((gf1==midi) && (gf1!=0))
irq_control|=0x40;
else
irq_control|=midi_irq;
dma_control|=dram_dma;
if((dram==adc) && (dram!=0))
dma_control|=0x40;
else
dma_control|=adc_dma;
/* Set up for Digital ASIC */
outportb(GUS_PORT+0x0f,0x5);
outportb(GF1_MIX_CTRL,mix_image);
outportb(GF1_IRQ_CTRL,0x0);
outportb(GUS_PORT+0x0f,0x0);
/* First do DMA control register */
outportb(GF1_MIX_CTRL,mix_image);
outportb(GF1_IRQ_CTRL,dma_control|0x80);
/* IRQ CONTROL REG */
outportb(GF1_MIX_CTRL,mix_image|0x40);
outportb(GF1_IRQ_CTRL,irq_control);
/* First do DMA control register */
outportb(GF1_MIX_CTRL,mix_image);
outportb(GF1_IRQ_CTRL,dma_control);
/* IRQ CONTROL REG */
outportb(GF1_MIX_CTRL,mix_image|0x40);
outportb(GF1_IRQ_CTRL,irq_control);
/* IRQ CONTROL, ENABLE IRQ */
/* just to Lock out writes to irq\dma register ... */
outportb(GF1_VOICE_SELECT,0);
/* enable output & irq, disable line & mic input */
mix_image|=0x09;
outportb(GF1_MIX_CTRL,mix_image);
/* just to Lock out writes to irq\dma register ... */
outportb(GF1_VOICE_SELECT,0x0);
/* put image back .... */
GUS_MIX_IMAGE=mix_image;
}
ULONG UltraReadVoice(UBYTE voice)
{
outportb(GF1_VOICE_SELECT,voice);
return(make_physical_address(GF1InW(GET_ACC_LOW),GF1InW(GET_ACC_HIGH),GF1InB(GET_CONTROL))&0xfffffL);
}
ULONG make_physical_address(UWORD low,UWORD high,UBYTE mode)
{
UWORD lower_16, upper_16;
ULONG ret_address, bit_19_20;
upper_16 = high >> 9;
lower_16 = ((high & 0x01ff) << 7) | ((low >> 9) & 0x007f);
ret_address = MAKE_MS_SWORD(upper_16) + lower_16;
if (mode & VC_DATA_TYPE)
{
bit_19_20 = ret_address & 0xC0000;
ret_address <<= 1;
ret_address &= 0x3ffff;
ret_address |= bit_19_20;
}
return( ret_address );
}
UWORD GF1InW(UBYTE x)
{
UltraSelect(x);
return inport(GF1_DATA_LOW);
}