home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC Action 1998 January
/
PCA0198.ISO
/
MENUE
/
POSTFACH
/
98012064.TXT
< prev
next >
Wrap
Text File
|
1997-11-25
|
9KB
|
426 lines
0
Sound-Blaster fⁿr C (das war die Quelle!!!)
Der Zauberleerling
Listings
#define STEREO
#define OPL3
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <ctype.h>
#include <dos.h>
#define KEYON 0x20
/* These are offsets from the base I/O address.
*/
#define FM 8
#define PROFM1 0
#define PROFM2 2
#ifdef OPL3
#define LEFT 0x10
#define RIGHT 0x20
#endif
unsigned IOport;
void mydelay(unsigned long clocks)
{
unsigned long elapsed=0;
unsigned int last,next,ncopy,diff;
outp(0x43,0);
last=inp(0x40);
last=~((inp(0x40)<< 8) + last);
do {
outp(0x43,0);
next=inp(0x40);
ncopy=next=~((inp(0x40)<< 8) + next);
next-=last;
elapsed += next;
last=ncopy;
} while (elapsed<clocks);
}
int base16(char **str, unsigned *val)
{
char c;
int digit;
*val = 0;
while ( **str != ' ') {
c = toupper(**str);
if (c >= '0' && c <= '9')
digit = c - '0';
else if (c >= 'A' && c <= 'F')
digit = c - 'A' + 10;
else
return 1;
*val = *val * 16 + digit;
(*str)++;
}
return 0;
}
int base10(char **str, unsigned *val)
{
char c;
int digit;
*val = 0;
while ( **str != ' ') {
c = toupper(**str);
if (c >= '0' && c <= '9')
digit = c - '0';
else
return 1;
*val = *val * 10 + digit;
(*str)++;
}
return 0;
}
unsigned ReadBlasterEnv(unsigned *port, unsigned
*irq, unsigned *dma8,
unsigned *dma16)
/* Meldet:
* 0 erfolgreich
* 1 Adress-Port-Lesefehler.
* 2 IRQ-Nummer-Lesefehler.
* 3 8-bit DMA Channel-Lesefehler.
* 4 16-bit DMA Channel-Lesefehler.
*/
{
char *env;
unsigned val;
int digit;
env = getenv("BLASTER");
while (*env) {
switch(toupper( *(env++) )) {
case 'A':
if (base16(&env, port))
return 1;
break;
case 'I':
if (base10(&env, irq))
return 2;
break;
case 'D':
if (base10(&env, dma8))
return 3;
break;
case 'H':
if (base10(&env, dma16))
return 4;
break;
default:
break;
}
}
return 0;
}
void FMoutput(unsigned port, int reg, int val)
{
outp(port, reg);
mydelay(8);
outp(port+1, val);
mydelay(55);
}
void fm(int reg, int val)
{
FMoutput(IOport+FM, reg, val);
}
void Profm1(int reg, int val)
{
FMoutput(IOport+PROFM1, reg, val);
}
void Profm2(int reg, int val)
{
FMoutput(IOport+PROFM2, reg, val);
}
void main(void)
{
int i,val1,val2;
int block,b,m,f,fn;
unsigned dummy;
clrscr();
ReadBlasterEnv(&IOport, &dummy, &dummy,
&dummy);
#ifdef STEREO
#ifdef OPL3
printf("Program compiled for Sound Blaster
Pro ver. 2 (CT-1600) and SB16 cards.\n");
#else
printf("Program compiled for Sound Blaster
Pro ver. 1 (CT-1330) cards.\n");
#endif
#else
printf("Program compiled for Sound Blaster
1.0 - 2.0 cards (monaural).\n");
#endif
fm(1,0);
#ifdef OPL3
Profm2(5, 1);
fm(0xC0,LEFT | RIGHT | 1);
#else
fm(0xC0, 1);
#endif
fm(0x23,0x21); /* no amplitude modulation
(D7=0), no vibrato (D6=0),
* sustained envelope type
(D5=1), KSR=0 (D4=0),
* frequency multiplier=1
(D4-D0=1)
*/
fm(0x43,0x0); /* no volume decrease with
pitch (D7-D6=0),
* no attenuation (D5-D0=0)
*/
fm(0x63,0xff); /* fast attack (D7-D4=0xF)
and decay (D3-D0=0xF) */
fm(0x83,0x05); /* high sustain level
(D7-D4=0), slow release rate (D3-D0=5) */
/*****************************************
* Set parameters for the modulator cell *
*****************************************/
fm(0x20,0x20); /* sustained envelope type,
frequency multiplier=0 */
fm(0x40,0x3f); /* maximum attenuation, no
volume decrease with pitch */
/* Since the modulator signal is attenuated
as much as possible, these
* next two values shouldn't have any effect.
*/
fm(0x60,0x44); /* slow attack and decay */
fm(0x80,0x05); /* high sustain level, slow
release rate */
/***********************************************
**
* Generate tone from values looked up in
table. *
************************************************
*/
printf("440 Hz tone, values looked up in
table.\n");
fm(0xa0,0x41); /* 440 Hz */
fm(0xb0,0x32); /* 440 Hz, block 0, key on */
getche();
fm(0xb0,0x12); /* key off */
/******************************************
* Generate tone from a calculated value. *
******************************************/
printf("440 Hz tone, values calculated.\n");
block=4; /* choose block=4 and m=1 */
m=1; /* m is the frequency
multiple number */
f=440; /* want f=440 Hz */
b= 1 << block;
/* This is the equation to calculate
frequency number from frequency. */
fn=(long)f * 1048576 / b / m /50000L;
fm(0x23,0x20 | (m & 0xF)); /* 0x20 sets
sustained envelope, low nibble
* is multiple
number
*/
fm(0xA0,(fn & 0xFF));
fm(0xB0,((fn >> 8) & 0x3) + (block << 2) |
KEYON);
getche();
/***********************************************
**********
* Generate a range of octaves by changing
block number. *
************************************************
*********/
printf("Range of frequencies created by
changing block number.\n");
for (block=0; block<=7; block++) {
printf("f=%5ld Hz (press
Enter)\n",(long)440*(1 << block)/16);
fm(0xB0,((fn >> 8) & 0x3) + (block << 2) |
KEYON);
getche();
}
/***********************************************
******************
* Generate a range of frequencies by
changing frequency number. *
************************************************
*****************/
printf("Range of frequencies created by
changing frequency number.\n");
block=4;
for (fn=0; fn<1024; fn++) {
fm(0xA0,(fn & 0xFF));
fm(0xB0,((fn >> 8) & 0x3) + (block << 2) |
KEYON);
delay(1);
}
/***********************************************
*********************
* Single tone again. Both channels, then if
on stereo board, *
* play tone in just the left channel, then
just the right channel. *
************************************************
********************/
printf("440 Hz again, both channels.\n");
block=4;
fn=577; /* This number makes
440 Hz when block=4 and m=1 */
fm(0xA0,(fn & 0xFF));
fm(0xB0,((fn >> 8) & 0x3) + (block << 2) |
KEYON);
#ifdef STEREO
#ifdef OPL3
/* This left and right channel stuff is the
only part of this program
* that uses OPL3 mode. Everything else is
available on the OPL2.
*/
getche();
printf("Left channel only\n");
fm(0xC0,LEFT | 1); /* set left channel
only, parallel connection */
getche();
printf("Right channel only\n");
fm(0xC0,RIGHT | 1); /* set right channel
only, parallel connection */
#else
getche();
fm(0xB0,((fn >> 8) & 0x3) + (block << 2));
// key off
printf("Left channel only\n");
Profm1(0xB0,((fn >> 8) & 0x3) + (block << 2)
| KEYON);
getche();
Profm1(0xB0,((fn >> 8) & 0x3) + (block <<
2)); // key off
printf("Right channel only\n");
Profm2(0xB0,((fn >> 8) & 0x3) + (block << 2)
| KEYON);
#endif
#endif
/*********************************
* Attenuate the signal by 3 dB. *
*********************************/
getche();
fm(0xB0,((fn >> 8) & 0x3) + (block << 2) |
KEYON);
printf("Attenuated by 3 dB.\n");
fm(0x43,4); /* attenuate by 3 dB */
getche();
fm(0xB0,((fn >> 8) & 0x3) + (block << 2));
#ifdef OPL3
/* Set OPL-3 back to OPL-2 mode, because if
the next program to run was
* written for the OPL-2, then it won't set
the LEFT and RIGHT bits to
* one, so no sound will be heard.
*/
Profm2(5, 0); /* set back to OPL2 mode */
#endif
}