📄 playmix.cpp
字号:
dspout(dspcmdDMADAC); /* program dsp for dma mode dac */
dspout(count & 0xFF); /* block size low byte */
dspout(count >> 8); /* high byte */
#endif
}
void SetMixer(void)
/* Resets the Sound Blaster card and sets the volume levels in the SB-PRO
* mixer chip.
*/
{
unsigned int val;
outp(dspaddrReset,1); /* reset DSP */
delay(1);
outp(dspaddrReset,0);
dspin(&val);
if (val!=dspReady)
printf("SBPRO not ready.");
outp(mixeraddr,MICVOL);
outp(mixerdata,0); /* turn mic vol off */
outp(mixeraddr,VOCVOL);
outp(mixerdata,0xFF); /* both chans up */
outp(mixeraddr,MASTERVOL);
outp(mixerdata,0xFF); /* master up */
dspout(0xD1); /* turn speaker on*/
}
void interrupt OutputDMAend(...)
/* This is the playback interrupt service routine. It acknowledges the
* interrupt, reprograms the sound blaster card and the DMA controller for
* another buffer transfer, and sends and End Of Interrupt to the interrupt
* controller.
*/
{
inp(dspaddrDataAvail); /* acknowledge interrupt */
BusyBuf ^= 1; /* toggle BusyBuf because other buffer is now busy */
#ifdef AUTOINIT
/* no re-programming necessary. */
#else
if (BusyBuf) {
SetupOutputDMA(page1,offset1,count,outtc);
} else {
SetupOutputDMA(page0,offset0,count,outtc);
}
#endif
outp(PICMODE,PICEOI); /* end of interrupt */
}
void FillBuffer(void)
/* Fills the buffer specified to BufToFill with data from the VOC file. */
{
unsigned char *ptr;
unsigned int i;
if (BufToFill)
ptr=buf1;
else ptr=buf0;
for (i=0; i<BUFSIZE; i++)
*ptr++ = (v1.GetSample() + v2.GetSample()) >> 1;
BufToFill ^= 1; /* toggle so BufToFill specifies other one */
}
void PrintShiftStat(void)
{
gotoxy(1,14);
printf("File 2 pitch shifting: %3s",v2pitchshift ? "ON":"OFF");
}
void NewShift(int skip)
{
v2.SetShiftAmount(skip);
gotoxy(1,15);
printf("skip amount: %7u\r",skip);
}
void SetFile1Repeat(boolean repeat)
{
v1.SetRepeat(v1repeat=repeat);
gotoxy(1,11);
printf("File 1 repeat: %3s",v1repeat ? "ON" : "OFF");
}
void SetFile2Repeat(boolean repeat)
{
v2.SetRepeat(v2repeat=repeat);
gotoxy(1,12);
printf("File 2 repeat: %3s",v2repeat ? "ON" : "OFF");
}
void SetupScreen(void)
{
clrscr();
printf("VOC file mixing and pitch shift sample program.\n\n");
printf("File 1: %s\n",filename1);
printf("File 2: %s\n\n",filename2);
printf("F1 - Toggle file 1 repeat F3 - Reset file 1\n");
printf("F2 - Toggle file 2 repeat F4 - Reset file 2\n");
printf("SPACE - Toggle file 2 pitch shift L/R arrows - shift pitch\n");
printf("ESC to quit.\n\n");
}
void appendvoc(char *fname)
/* Appends the .voc extension to a filename, if necessary. */
{
char drive[MAXDRIVE], dir[MAXDIR], name[MAXFILE], ext[MAXEXT];
fnsplit(fname, drive, dir, name, ext); /* split fname into components */
if (strlen(ext)==0) /* if there's no extension */
strcpy(ext,".voc"); /* add .voc */
fnmerge(fname, drive, dir, name, ext); /* recombine components */
}
void main(int argc, char *argv[])
{
int i,c,err;
void interrupt (*IRQsave)(...);
unsigned long physaddr,endaddr;
unsigned int masksave;
boolean done=false;
SegToPhys(buf0,BUFSIZE,&physaddr,&endaddr);
if (BUFSIZE > PhysToPage(physaddr,endaddr,&page0,&offset0)) {
printf("Page error.\n");
exit(1);
/* If this happens, you should dynamically allocate memory instead,
* and don't use any blocks of memory that fail the above test.
*/
}
SegToPhys(buf1,BUFSIZE,&physaddr,&endaddr);
if (BUFSIZE > PhysToPage(physaddr,endaddr,&page1,&offset1)) {
printf("page error\n");
exit(1);
/* See comment above. */
}
clrscr();
if (argc > 1)
strcpy(filename1, argv[1]);
else {
printf("\n.voc file 1 name: ");
scanf("%s",filename1);
}
appendvoc(filename1);
if (argc > 2)
strcpy(filename2, argv[2]);
else {
printf(".voc file 2 name: ");
scanf("%s",filename2);
}
appendvoc(filename2);
if (0 != (err=v1.open(filename1))) {
printf("Error %d opening %s\n",err,filename1);
exit(1);
}
if (0 != (err=v2.open(filename2))) {
printf("Error %d opening %s\n",err,filename2);
exit(1);
}
v2.SetPitchShift(v2pitchshift);
SetupScreen();
PrintShiftStat();
SetFile1Repeat(true);
SetFile2Repeat(true);
for (i=0; i<BUFSIZE; i++) {
buf0[i]=0; /* Clear the buffers. Not necessary, but good idea */
buf1[i]=0; /* in case something goes wrong. */
}
SetMixer();
IRQsave=getvect(IRQ); /* save the old interrupt vector */
setvect(IRQ,OutputDMAend); /* point to new ISR */
BufToFill=0;
FillBuffer(); /* fill buffer 0 */
BusyBuf=0; /* buffer 0 will start playing soon */
masksave=inp(PICMASK); /* save mask to restore later */
outp(PICMASK,(masksave & ~IRQmask)); /* enable interrupt */
#ifdef AUTOINIT
SetupOutputDMA(page0,offset0,2*BUFSIZE,outtc); /* this will start buf0 playing */
#else
SetupOutputDMA(page0,offset0,count,outtc); /* this will start buf0 playing */
#endif
do {
while (!done && BufToFill==BusyBuf) {
/* mainly wait until it's OK to refill BusyBuf, but check keyboard
* in the mean time */
if (kbhit()) {
c=getch();
switch (c) {
case 0:
c=getch();
switch (c) {
case LEFTKEY:
v2skip += 1;
NewShift(v2skip);
break;
case RIGHTKEY:
if (v2skip>1) /* don't let go to zero */
v2skip -= 1;
NewShift(v2skip);
break;
case F1KEY:
SetFile1Repeat((boolean)!v1repeat);
break;
case F2KEY:
SetFile2Repeat((boolean)!v2repeat);
break;
case F3KEY:
v1.ResetVOC();
break;
case F4KEY:
v2.ResetVOC();
break;
}
break;
case SPACEKEY:
v2pitchshift= (boolean) !v2pitchshift;
v2.SetPitchShift(v2pitchshift);
PrintShiftStat();
break;
case ESC:
done=true;
break;
}
}
}
FillBuffer(); /* refill the next buffer */
} while (!done);
#ifdef AUTOINIT
dspout(dspcmdHaltAuto); /* stop auto-init DMA transfer */
#else
dspout(dspcmdHaltDMA); /* stop DMA transfer */
#endif
outp(PICMASK, masksave); /* restore interrupt mask */
setvect(IRQ,IRQsave); /* restore old vector */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -