home *** CD-ROM | disk | FTP | other *** search
/ PC Action 1998 January / PCA0198.ISO / MENUE / POSTFACH / 98012064.TXT < prev    next >
Text File  |  1997-11-25  |  9KB  |  426 lines

  1. 0
  2. Sound-Blaster fⁿr C (das war die Quelle!!!)
  3. Der Zauberleerling
  4. Listings
  5. #define STEREO     
  6. #define OPL3      
  7.  
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <conio.h>
  11. #include <ctype.h>
  12. #include <dos.h>
  13.  
  14. #define KEYON     0x20  
  15.  
  16.  /* These are offsets from the base I/O address. 
  17. */
  18. #define FM       8       
  19. #define PROFM1   0      
  20.                         
  21. #define PROFM2   2     
  22.                   
  23.  
  24.  
  25.  
  26. #ifdef OPL3
  27.   #define LEFT     0x10
  28.   #define RIGHT       0x20
  29. #endif
  30.  
  31.  
  32. unsigned IOport;      
  33.  
  34.  
  35.  
  36. void mydelay(unsigned long clocks)
  37.  
  38. {
  39.    unsigned long elapsed=0;
  40.    unsigned int last,next,ncopy,diff;
  41.  
  42.    outp(0x43,0);                           
  43.    last=inp(0x40);                          
  44.    last=~((inp(0x40)<< 8) + last);          
  45.  
  46.    do {
  47.       outp(0x43,0);                        
  48.       next=inp(0x40);                        
  49.       ncopy=next=~((inp(0x40)<< 8) + next);  
  50.  
  51.       next-=last;    
  52.  
  53.       elapsed += next; 
  54.       last=ncopy;
  55.    } while (elapsed<clocks);
  56. }
  57.  
  58.  
  59.  
  60. int base16(char **str, unsigned *val)
  61.  
  62. {
  63.    char c;
  64.    int digit;
  65.    *val = 0;
  66.  
  67.    while ( **str != ' ') {
  68.       c = toupper(**str);
  69.       if (c >= '0' && c <= '9')
  70.          digit = c - '0';
  71.       else if (c >= 'A' && c <= 'F')
  72.          digit = c - 'A'  + 10;
  73.       else
  74.          return 1;         
  75.  
  76.       *val = *val * 16 + digit;
  77.       (*str)++;
  78.    }
  79.    return 0;
  80. }
  81.  
  82.  
  83.  
  84. int base10(char **str, unsigned *val)
  85.  
  86. {
  87.    char c;
  88.    int digit;
  89.    *val = 0;
  90.  
  91.    while ( **str != ' ') {
  92.       c = toupper(**str);
  93.       if (c >= '0' && c <= '9')
  94.          digit = c - '0';
  95.       else
  96.          return 1;         
  97.  
  98.       *val = *val * 10 + digit;
  99.       (*str)++;
  100.    }
  101.    return 0;
  102. }
  103.  
  104.  
  105.  
  106. unsigned ReadBlasterEnv(unsigned *port, unsigned 
  107. *irq, unsigned *dma8,
  108.  unsigned *dma16)
  109. /*   Meldet:
  110.  *   0  erfolgreich
  111.  *   1  Adress-Port-Lesefehler.
  112.  *   2  IRQ-Nummer-Lesefehler.
  113.  *   3  8-bit DMA Channel-Lesefehler.
  114.  *   4  16-bit DMA Channel-Lesefehler.
  115.  */
  116. {
  117.    char     *env;
  118.    unsigned val;
  119.    int      digit;
  120.  
  121.    env = getenv("BLASTER");
  122.  
  123.    while (*env) {
  124.       switch(toupper( *(env++) )) {
  125.          case 'A':
  126.             if (base16(&env, port))   
  127.                return 1;               
  128.             break;
  129.          case 'I':
  130.             if (base10(&env, irq))    
  131.                return 2;                
  132.             break;
  133.          case 'D':
  134.             if (base10(&env, dma8))    
  135.                return 3;
  136.             break;
  137.          case 'H':
  138.             if (base10(&env, dma16))  
  139.                return 4;
  140.             break;
  141.          default:
  142.             break;
  143.       }
  144.    }
  145.  
  146.    return 0;
  147. }
  148.  
  149.  
  150.  
  151. void FMoutput(unsigned port, int reg, int val)
  152. {
  153.    outp(port, reg);
  154.    mydelay(8);        
  155.    outp(port+1, val);
  156.    mydelay(55);       
  157. }
  158.  
  159.  
  160.  
  161. void fm(int reg, int val)
  162. {
  163.    FMoutput(IOport+FM, reg, val);
  164. }
  165.  
  166.  
  167. void Profm1(int reg, int val)
  168.  
  169. {
  170.    FMoutput(IOport+PROFM1, reg, val);
  171. }
  172.  
  173.  
  174. void Profm2(int reg, int val)
  175.  
  176. {
  177.    FMoutput(IOport+PROFM2, reg, val);
  178. }
  179.  
  180.  
  181.  
  182.  
  183. void main(void)
  184. {
  185.    int i,val1,val2;
  186.  
  187.    int block,b,m,f,fn;
  188.  
  189.    unsigned dummy;
  190.  
  191.  
  192.    clrscr();
  193.  
  194.    ReadBlasterEnv(&IOport, &dummy, &dummy, 
  195. &dummy);
  196.  
  197. #ifdef STEREO
  198.  #ifdef OPL3
  199.    printf("Program compiled for Sound Blaster 
  200. Pro ver. 2 (CT-1600) and SB16 cards.\n");
  201.  #else
  202.    printf("Program compiled for Sound Blaster 
  203. Pro ver. 1 (CT-1330) cards.\n");
  204.  #endif
  205. #else
  206.    printf("Program compiled for Sound Blaster 
  207. 1.0 - 2.0 cards (monaural).\n");
  208. #endif
  209.  
  210.  
  211.    fm(1,0);   
  212.  
  213. #ifdef OPL3
  214.    Profm2(5, 1); 
  215.    fm(0xC0,LEFT | RIGHT | 1);    
  216. #else
  217.    fm(0xC0,               1);    
  218. #endif
  219.  
  220.  
  221.    fm(0x23,0x21);  /* no amplitude modulation 
  222. (D7=0), no vibrato (D6=0),
  223.                     * sustained envelope type 
  224. (D5=1), KSR=0 (D4=0),
  225.                     * frequency multiplier=1 
  226. (D4-D0=1)
  227.                     */
  228.  
  229.    fm(0x43,0x0);   /* no volume decrease with 
  230. pitch (D7-D6=0),
  231.                     * no attenuation (D5-D0=0)
  232.                     */
  233.  
  234.    fm(0x63,0xff);  /* fast attack (D7-D4=0xF) 
  235. and decay (D3-D0=0xF) */
  236.    fm(0x83,0x05);  /* high sustain level 
  237. (D7-D4=0), slow release rate (D3-D0=5) */
  238.  
  239.  
  240.    /*****************************************
  241.     * Set parameters for the modulator cell *
  242.     *****************************************/
  243.  
  244.    fm(0x20,0x20);  /* sustained envelope type, 
  245. frequency multiplier=0    */
  246.    fm(0x40,0x3f);  /* maximum attenuation, no 
  247. volume decrease with pitch */
  248.  
  249.    /* Since the modulator signal is attenuated 
  250. as much as possible, these
  251.     * next two values shouldn't have any effect.
  252.     */
  253.    fm(0x60,0x44);  /* slow attack and decay */
  254.    fm(0x80,0x05);  /* high sustain level, slow 
  255. release rate */
  256.  
  257.  
  258.    
  259. /***********************************************
  260. **
  261.     * Generate tone from values looked up in 
  262. table. *
  263.     
  264. ************************************************
  265. */
  266.  
  267.    printf("440 Hz tone, values looked up in 
  268. table.\n");
  269.    fm(0xa0,0x41);  /* 440 Hz */
  270.    fm(0xb0,0x32);  /* 440 Hz, block 0, key on */
  271.  
  272.    getche();
  273.  
  274.    fm(0xb0,0x12);  /* key off */
  275.  
  276.  
  277.    /******************************************
  278.     * Generate tone from a calculated value. *
  279.     ******************************************/
  280.  
  281.    printf("440 Hz tone, values calculated.\n");
  282.    block=4;        /* choose block=4 and m=1 */
  283.    m=1;               /* m is the frequency 
  284. multiple number */
  285.    f=440;          /* want f=440 Hz */
  286.    b= 1 << block;
  287.  
  288.    /* This is the equation to calculate 
  289. frequency number from frequency. */
  290.  
  291.    fn=(long)f * 1048576 / b / m /50000L;
  292.  
  293.    fm(0x23,0x20 | (m & 0xF));   /* 0x20 sets 
  294. sustained envelope, low nibble
  295.                                  * is multiple 
  296. number
  297.                                  */
  298.    fm(0xA0,(fn & 0xFF));
  299.    fm(0xB0,((fn >> 8) & 0x3) + (block << 2) | 
  300. KEYON);
  301.  
  302.    getche();
  303.  
  304.  
  305.    
  306. /***********************************************
  307. **********
  308.     * Generate a range of octaves by changing 
  309. block number. *
  310.     
  311. ************************************************
  312. *********/
  313.  
  314.    printf("Range of frequencies created by 
  315. changing block number.\n");
  316.    for (block=0; block<=7; block++) {
  317.       printf("f=%5ld Hz (press 
  318. Enter)\n",(long)440*(1 << block)/16);
  319.       fm(0xB0,((fn >> 8) & 0x3) + (block << 2) | 
  320. KEYON);
  321.       getche();
  322.    }
  323.  
  324.  
  325.    
  326. /***********************************************
  327. ******************
  328.     * Generate a range of frequencies by 
  329. changing frequency number. *
  330.     
  331. ************************************************
  332. *****************/
  333.  
  334.    printf("Range of frequencies created by 
  335. changing frequency number.\n");
  336.    block=4;
  337.    for (fn=0; fn<1024; fn++) {
  338.       fm(0xA0,(fn & 0xFF));
  339.       fm(0xB0,((fn >> 8) & 0x3) + (block << 2) | 
  340. KEYON);
  341.       delay(1);
  342.    }
  343.  
  344.  
  345.    
  346. /***********************************************
  347. *********************
  348.     * Single tone again.  Both channels, then if 
  349. on stereo board,      *
  350.     * play tone in just the left channel, then 
  351. just the right channel. *
  352.     
  353. ************************************************
  354. ********************/
  355.  
  356.    printf("440 Hz again, both channels.\n");
  357.    block=4;
  358.    fn=577;                /* This number makes 
  359. 440 Hz when block=4 and m=1 */
  360.    fm(0xA0,(fn & 0xFF));
  361.    fm(0xB0,((fn >> 8) & 0x3) + (block << 2) | 
  362. KEYON);
  363.  
  364. #ifdef STEREO
  365.  #ifdef OPL3
  366.     /* This left and right channel stuff is the 
  367. only part of this program
  368.      * that uses OPL3 mode.  Everything else is 
  369. available on the OPL2.
  370.      */
  371.  
  372.     getche();
  373.     printf("Left channel only\n");
  374.     fm(0xC0,LEFT | 1);      /* set left channel 
  375. only, parallel connection */
  376.  
  377.     getche();
  378.     printf("Right channel only\n");
  379.     fm(0xC0,RIGHT | 1);     /* set right channel 
  380. only, parallel connection */
  381.  #else
  382.     getche();
  383.     fm(0xB0,((fn >> 8) & 0x3) + (block << 2));    
  384. // key off
  385.  
  386.     printf("Left channel only\n");
  387.     Profm1(0xB0,((fn >> 8) & 0x3) + (block << 2) 
  388. | KEYON);
  389.  
  390.     getche();
  391.     Profm1(0xB0,((fn >> 8) & 0x3) + (block << 
  392. 2));   // key off
  393.  
  394.     printf("Right channel only\n");
  395.     Profm2(0xB0,((fn >> 8) & 0x3) + (block << 2) 
  396. | KEYON);
  397.  
  398.  
  399.  #endif
  400. #endif
  401.  
  402.  
  403.    /*********************************
  404.     * Attenuate the signal by 3 dB. *
  405.     *********************************/
  406.  
  407.    getche();
  408.    fm(0xB0,((fn >> 8) & 0x3) + (block << 2) | 
  409. KEYON);
  410.    printf("Attenuated by 3 dB.\n");
  411.    fm(0x43,4);     /* attenuate by 3 dB */
  412.    getche();
  413.  
  414.    fm(0xB0,((fn >> 8) & 0x3) + (block << 2));
  415.  
  416. #ifdef OPL3
  417.    /* Set OPL-3 back to OPL-2 mode, because if 
  418. the next program to run was
  419.     * written for the OPL-2, then it won't set 
  420. the LEFT and RIGHT bits to
  421.     * one, so no sound will be heard.
  422.     */
  423.    Profm2(5, 0);   /* set back to OPL2 mode */
  424. #endif
  425. }
  426.