📄 delay.c
字号:
outp(card2->Reset,1);
delay(1);
outp(card2->Reset,0);
if (dspin(card2,&val))
if (val!=dspReady)
printf("Sound Blaster card #2 not ready.");
switch (card2->cardtype) {
case 2:
case 4: // SBPRO
dspout(card2,0xD1); // turn speaker on
break;
case 6:
outp(card2->MixerAddr, SB16INPUTL);
outp(card2->MixerData, 0); // select nothing
outp(card2->MixerAddr, SB16INPUTR);
outp(card2->MixerData, 0); // select nothing
break;
}
}
void InitScreen(void)
{
clrscr();
printf("Two Sound Blaster Delay program.\nPress any key to stop.\n");
}
void DrainInputBuffer(void)
// Copies half the DMA buffer to one of the record buffers.
{
// Copy data from current half of DMA buffer to next input buffer.
memcpy(inbuffers[NumRecBufToFill], recbuf + HalfBufToEmpty*BUFSIZE/2, BUFSIZE/2);
// Make next buffer current
++NumRecBufToFill;
if (NumRecBufToFill >= NUMBUFS)
NumRecBufToFill = 0;
// Increment count of filled input buffers.
++NumFilledInBufs;
// Next time use other half of DMA buffer.
HalfBufToEmpty ^= 1;
}
void FillOutputBuffer(void)
// Copies one of the output buffers to half the DMA buffer.
{
// Copy data from next output buffer to current half of DMA buffer.
memcpy(playbuf + HalfBufToFill*BUFSIZE/2, outbuffers[NumPlayBufToEmpty], BUFSIZE/2);
// Make next buffer current
++NumPlayBufToEmpty;
if (NumPlayBufToEmpty >= NUMBUFS)
NumPlayBufToEmpty = 0;
// Decrement count of filled output buffers.
--NumFilledOutBufs;
// Next time use other half of DMA buffer.
HalfBufToFill ^= 1;
}
void interrupt InputSBISR(void)
// Service interrupts from SB doing input.
{
// Make sure this wasn't a spurious interrupt.
if (card1.irq == 7) {
outp(PIC1MODE, 0xB); // select In Service Register
if ((inp(PIC1MODE) & 0x80) == 0) // if bit 7 == 0, spurious interrupt
return;
}
inp(card1.DataAvail); // acknowledge interrupt
DrainInputBuffer();
if (card1.irq > 8) // If irq 10, send EOI to second PIC.
outp(PIC2MODE, PICEOI);
outp(PIC1MODE,PICEOI); // Send EOI to first PIC.
}
void interrupt OutputSBISR(void)
// Service interrupts from SB doing output.
{
// Make sure this wasn't a spurious interrupt.
if (card2.irq == 7) {
outp(PIC1MODE, 0xB); // select In Service Register
if ((inp(PIC1MODE) & 0x80) == 0) // if bit 7 == 0, spurious interrupt
return;
}
inp(card2.DataAvail); // acknowledge interrupt
FillOutputBuffer();
if (card2.irq > 8) // If irq 10, send EOI to second PIC.
outp(PIC2MODE, PICEOI);
outp(PIC1MODE,PICEOI); // Send EOI to first PIC.
}
int GetCardInfo(char *name, cardinfo *card)
// Read a blaster environment string.
{
int result;
int dummy;
result=ReadBlasterEnv(name, &card->base, &card->irq, &card->dma8, &dummy,
&dummy, &card->cardtype);
if (result != 0) {
switch (result) {
case 1:
printf("Error in %s port address.\n",name);
break;
case 2:
printf("Error in %s IRQ number.\n",name);
break;
case 3:
printf("Error in %s 8-bit DMA channel.\n",name);
break;
case 4:
printf("Error in %s 16-bit DMA channel.\n",name);
break;
case 5:
printf("Error in %s MIDI address.\n",name);
break;
case 6:
printf("Error in %s card type number.\n",name);
break;
case 7:
printf("Error: %s environment variable not set.\n",name);
break;
}
}
card->WrBuf = card->base + dspoffsetWrBuf;
card->Reset = card->base + dspoffsetReset;
card->ReadData = card->base + dspoffsetReadData;
card->DataAvail = card->base + dspoffsetDataAvail;
card->MixerAddr = card->base + dspoffsetMixerAddr;
card->MixerData = card->base + dspoffsetMixerData;
return result;
}
void EnableCardInterrupt(cardinfo *card, void interrupt (*newvect)())
{
int intrmask;
// calculate interrupt number for IRQ
if (card->irq < 8)
card->intrnum = card->irq + 8; // IRQs 0-7 map to interrupts 8-15.
else
card->intrnum = card->irq - 8 + 0x70; // IRQs 8-15 map to interrupts 70H-78H.
// generate 16-bit mask for IRQ
card->intrmask = 1 << card->irq;
card->intvecsave = getvect(card->intrnum); // save previous interrupt vector
setvect(card->intrnum, newvect); // set new interrupt vector
// enable interrupts at interrupt controllers
intrmask = card->intrmask;
outp(PIC1MASK, inp(PIC1MASK) & ~intrmask);
intrmask >>= 8;
outp(PIC2MASK, inp(PIC2MASK) & ~intrmask);
}
void DisableCardInterrupt(cardinfo *card)
{
int intrmask;
// disable interrupts at interrupt controllers
intrmask = card->intrmask;
outp(PIC1MASK, inp(PIC1MASK) | intrmask);
intrmask >>= 8;
outp(PIC2MASK, inp(PIC2MASK) | intrmask);
// Restore previous vector
setvect(card->intrnum, card->intvecsave);
}
int CompareCards(cardinfo *card1, cardinfo *card2)
// Make sure the two SB cards don't have the same settings.
{
int result = 0;
if (card1->base == card2->base) {
printf("Error: Cards are at the same I/O address: %X\n",card1->base);
result |= 1;
}
if (card1->irq == card2->irq) {
printf("Error: Cards are using the same interrupt: %d\n",card1->irq);
result |= 2;
}
if (card1->dma8 == card2->dma8) {
printf("Error: Cards are using the same DMA channel: %d\n",card1->dma8);
result |= 4;
}
return result;
}
void WriteBufsToDisk(int handle)
// Writes all the record buffers that have data to the disk.
{
unsigned nread;
// While there are input buffers with data, write them to disk
while (NumFilledInBufs > 0) {
_dos_write(handle, inbuffers[NumRecBufToEmpty], BUFSIZE/2, &nread);
++NumBufsWritten;
--NumFilledInBufs;
++NumRecBufToEmpty;
if (NumRecBufToEmpty >= NUMBUFS)
NumRecBufToEmpty = 0;
}
}
void ReadBufsFromDisk(int handle)
// Fills all empty playback buffers from disk.
{
unsigned nread;
// While some output buffers are empty, fill them from disk
while (NumFilledOutBufs < NUMBUFS) {
_dos_read(handle, outbuffers[NumPlayBufToFill], BUFSIZE/2, &nread);
++NumFilledOutBufs;
++NumPlayBufToFill;
if (NumPlayBufToFill >= NUMBUFS)
NumPlayBufToFill = 0;
}
}
void main(void)
{
int i,b,c;
unsigned long physaddr,endaddr;
boolean done=false;
int result;
int rech, playh; // file handles for recording and playing
char fname[] = FILENAME;
result=GetCardInfo("BLASTER", &card1);
if (result != 0)
return;
result=GetCardInfo("BLASTER2", &card2);
if (result != 0)
return;
if (CompareCards(&card1, &card2))
return;
SegToPhys(recbuf,BUFSIZE,&physaddr,&endaddr);
if (PhysToPage(physaddr,endaddr,&inpage,&inoffset) < BUFSIZE) {
printf("The DMA buffer crossed a page boundary. Sorry, I didn't write the program\n");
printf("to deal with this. See comments in program. Terminating.\n");
return;
/*
* The program should dynamically allocate buffers until a buffer is
* found that doesn't cross a DMA page boundary. I took a short cut
* here by just using an array, which usually works if it's much less
* than 64K bytes.
*/
}
SegToPhys(playbuf,BUFSIZE,&physaddr,&endaddr);
if (PhysToPage(physaddr,endaddr,&outpage,&outoffset) < BUFSIZE) {
printf("The DMA buffer crossed a page boundary. Sorry, I didn't write the program\n");
printf("to deal with this. See comments in program. Terminating.\n");
return;
}
InitScreen();
// allocate buffers to transfer data between DMA buffer and disk
for (i=0; i<NUMBUFS; i++) {
inbuffers[i] = malloc(BUFSIZE/2);
if (!inbuffers[i]) {
printf("Error: memory couldn't be allocated.\n");
return;
}
outbuffers[i] = malloc(BUFSIZE/2);
if (!outbuffers[i]) {
printf("Error: memory couldn't be allocated.\n");
return;
}
}
if (_dos_creat(fname, 0, &rech)) {
printf("Couldn't open file %s for writing.\n",fname);
return;
}
if (_dos_open(fname, O_RDONLY, &playh)) {
printf("Couldn't open file %s for reading.\n",fname);
return;
}
SetMixer(&card1, &card2);
EnableCardInterrupt(&card1, InputSBISR);
EnableCardInterrupt(&card2, OutputSBISR);
// Fill playback buffers with silence and mark them as filled so the
// playback of the actual file will start delayed by 2+NUMBUFS buffers.
for (b=0; b<NUMBUFS; b++)
for (i=0; i<BUFSIZE/2; ++i) {
*((char *)outbuffers[b] + i) = 0x80;
}
NumFilledOutBufs = NUMBUFS;
// fill both halves of output DMA buffer
FillOutputBuffer();
FillOutputBuffer();
// Start recording
SetupInputDMA(inpage,inoffset,count,TIMECONST);
// Wait until several buffers have been written to disk before starting
// playback. This gives the recording section a head start. This is
// necessary because the playback section tries to fill all of its buffers,
// so there must be that much data already on the disk.
do {
WriteBufsToDisk(rech);
} while (NumBufsWritten < NUMBUFS);
// Now start playing.
SetupOutputDMA(outpage,outoffset,count,TIMECONST);
while (!done) {
WriteBufsToDisk(rech); // write all full input buffers
ReadBufsFromDisk(playh); // fill all empty output buffers
gotoxy(1,3);
printf("Number of buffers written to disk: %5d\n",NumBufsWritten);
if (kbhit()) {
c=getch();
switch (c) {
case ESC:
done=true;
break;
// Used to have other stuff here in a previous program.
default:
done=true;
}
}
}
// Stop recording and playing.
dspout(&card1,dspcmdHaltDMA8);
dspout(&card2,dspcmdHaltDMA8);
DisableCardInterrupt(&card1);
DisableCardInterrupt(&card2);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -