home *** CD-ROM | disk | FTP | other *** search
/ Power CD-ROM!! 8 / Power CD-ROM 8.iso / prgmming / fmsamp / fmsample.c next >
Encoding:
C/C++ Source or Header  |  1994-04-16  |  18.1 KB  |  512 lines

  1. /* -------------------------------------------------------------------------- */
  2. /*                                                                            */
  3. /* FM synthesizer low-level interface demo program.                           */
  4. /* Copyright (c) 1994 Creative Labs, Inc.                                     */
  5. /*                                                                            */
  6. /* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY      */
  7. /* KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE        */
  8. /* IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR      */
  9. /* PURPOSE.                                                                   */
  10. /*                                                                            */
  11. /* You have a royalty-free right to use, modify, reproduce and                */
  12. /* distribute the Sample Files (and/or any modified version) in               */
  13. /* any way you find useful, provided that you agree that                      */
  14. /* Creative has no warranty obligations or liability for any Sample Files.    */
  15. /*                                                                            */
  16. /*----------------------------------------------------------------------------*/
  17.   
  18. /*
  19.  *  This Program is written using Borland C++ Ver 3.1.
  20.  *  To Compile : BCC FMSAMPLE.C
  21.  * ---------------------------------------------------------------------
  22.  *
  23.  * This program is not intended to explain all the aspects of FM sound
  24.  * generation on Sound Blaster cards.  The chips are too complicated for
  25.  * that.  This program is just to demonstrate how to generate a tone and
  26.  * control the left and right channels.  For more information on the FM
  27.  * synthesizer chip, contact Yamaha.
  28.  *
  29.  * Here's a brief description of FM:  Each sound is created by two operator
  30.  * cells (called "slots" in the Yamaha documentation), a modulator and a
  31.  * carrier.  When FM synthesis was invented, the output value of the
  32.  * modulator affected the frequency of the carrier.  In the Yamaha chips, the
  33.  * modulator output actually affects the phase of the carrier instead of
  34.  * frequency, but this has a similar  effect.
  35.  *
  36.  * Normally the modulator and carrier would probably be connected in series
  37.  * for complex sounds.  For this program, I wanted a pure sine wave, so I
  38.  * connected them in parallel and turned the modulator output down all the
  39.  * way and used just the carrier.
  40.  *
  41.  * Sound Blaster 1.0 - 2.0 cards have one OPL-2 FM synthesis chip at
  42.  * addresses 2x8 and 2x9 (base + 8 and base + 9).  Sound Blaster Pro version
  43.  * 1 cards (CT-1330) achieve stereo FM with two OPL-2 chips, one for each
  44.  * speaker.  The left channel FM chip is at addresses 2x0 and 2x1.  The right
  45.  * is at 2x2 and 2x3.  Addresses 2x8 and 2x9 address both chips
  46.  * simultaneously, thus maintaining compatibility with the monaural Sound
  47.  * Blaster cards.  The OPL-2 contains 18 operator cells which make up the
  48.  * nine 2-operator channels.  Since the CT-1330 SB Pro has two OPL-2 chips,
  49.  * it is therefore capable of generating 9 voices in each speaker.
  50.  *
  51.  * Sound Blaster Pro version 2 (CT-1600) and Sound Blaster 16 cards have one
  52.  * OPL-3 stereo FM chip at addresses 2x0 - 2x3.  The OPL-3 is separated into
  53.  * two "banks."  Ports 2x0 and 2x1 control bank 0, while 2x2 and 2x3 control
  54.  * bank 1.  Each bank can generate nine 2-operator voices.  However, when the
  55.  * OPL-3 is reset, it switches into OPL-2 mode.  It must be put into OPL-3
  56.  * mode to use the voices in bank 1 or the stereo features.  For stereo
  57.  * control, each channel may be sent to the left, the right, or both
  58.  * speakers, controlled by two bits in registers C0H - C8H.
  59.  *
  60.  * The FM chips are controlled through a set of registers.  The following
  61.  * table shows how operator cells and channels are related, and the register
  62.  * offsets to use.
  63.  *
  64.  * FUNCTION  MODULATOR-  -CARRIER--  MODULATOR-  -CARRIER--  MODULATOR-  -CARRIER--
  65.  * OP CELL    1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18
  66.  * CHANNEL    1   2   3   1   2   3   4   5   6   4   5   6   7   8   9   7   8   9
  67.  * OFFSET    00  01  02  03  04  05  08  09  0A  0B  0C  0D  10  11  12  13  14  15
  68.  *
  69.  * An example will make the use of this table clearer:  suppose you want to
  70.  * set the attenuation of both of the operators of channel 4.  The KSL/TOTAL LEVEL
  71.  * registers (which set the attenuation) are 40H - 55H.  The modulator for
  72.  * channel 4 is op cell 7, and the carrier for channel 4 is op cell 10.  The
  73.  * offsets for the modulator and carrier cells are 08H and 0BH, respectively.
  74.  * Therefore, to set the attenuation of the modulator, you would output a
  75.  * value to register 40H + 08H == 48H, and to set the carrier's attenuation,
  76.  * you would output to register 40H + 0BH == 4BH.
  77.  *
  78.  * In this program, I used just channel 1, so the registers I used were 20H,
  79.  * 40H, 60H, etc., and 23H, 43H, 63H, etc.
  80.  *
  81.  * The frequencies of each channel are controlled with a frequency number and
  82.  * a multiplier.  The modulator and carrier of a channel both get the same
  83.  * frequency number, but they may be given different multipliers.  Frequency
  84.  * numbers are programmed in registers A0H - A8H (low 8 bits) and B0H - B8H
  85.  * (high 2 bits).  Those registers control entire channels (2 operators), not
  86.  * individual operator cells.  To turn a note on, the key-on bit in the
  87.  * appropriate channel register is set.  Since these registers deal with
  88.  * channels, you do not use the offsets listed in the table above.  Instead,
  89.  * add (channel-1) to A0H or B0H.  For example, to turn channel 1 on,
  90.  * program the frequency number in registers A0H and B0H, and set the key-on
  91.  * bit to 1 in register B0H.  For channel 3, use registers A2H and B2H.
  92.  *
  93.  * Bits 2 - 4 in registers B0H - B8H are the block (octave) number for the
  94.  * channel.
  95.  *
  96.  * Multipliers for each operator cell are programmed through registers 20H -
  97.  * 35H.  The table below shows what multiple number to program into the
  98.  * register to get the desired multiplier.  The multiple number goes into
  99.  * bits 0 - 3 in the register.  Note that it's a bit strange at the end.
  100.  *
  101.  *   multiple number     multiplier        multiple number     multiplier
  102.  *          0                1/2                   8               8
  103.  *          1                 1                    9               9
  104.  *          2                 2                    10              10
  105.  *          3                 3                    11              10
  106.  *          4                 4                    12              12
  107.  *          5                 5                    13              12
  108.  *          6                 6                    14              15
  109.  *          7                 7                    15              15
  110.  *
  111.  * This equation shows how to calculate the required frequency number (to
  112.  * program into registers A0H - A8H and B0H - B8H) to get the desired
  113.  * frequency:
  114.  *                fn=(long)f * 1048576 / b / m /50000L
  115.  * where f is the frequency in Hz,
  116.  *       b is the block (octave) number between 0 and 7 inclusive, and
  117.  *       m is the multiple number between 0 and 15 inclusive.
  118.  *
  119.  */
  120.  
  121.  
  122. #define STEREO         // Define this for SBPro CT-1330 or later card.
  123. #define OPL3           // Also define this for SBPro CT-1600 or later card.
  124.  
  125.  
  126. #include <stdio.h>
  127. #include <stdlib.h>
  128. #include <conio.h>
  129. #include <ctype.h>
  130. #include <dos.h>
  131.  
  132. #define KEYON     0x20     // key-on bit in regs b0 - b8
  133.  
  134.  /* These are offsets from the base I/O address. */
  135. #define FM       8        // SB (mono) ports (e.g. 228H and 229H)
  136. #define PROFM1   0        // On CT-1330, this is left OPL-2.  On CT-1600 and
  137.                           // later cards, it's OPL-3 bank 0.
  138. #define PROFM2   2        // On CT-1330, this is right OPL-2.  On CT-1600 and
  139.                           // later cards, it's OPL-3 bank 1.
  140.  
  141.  
  142.  
  143. #ifdef OPL3
  144.   #define LEFT     0x10
  145.   #define RIGHT       0x20
  146. #endif
  147.  
  148.  
  149. unsigned IOport;        // Sound Blaster port address
  150.  
  151.  
  152.  
  153. void mydelay(unsigned long clocks)
  154. /*
  155.  * "clocks" is clock pulses (at 1.193180 MHz) to elapse, but remember that
  156.  * normally the system timer runs in mode 3, in which it counts down by twos,
  157.  * so delay3(1193180) will only delay half a second.
  158.  *
  159.  *   clocks = time * 2386360
  160.  *
  161.  *     time = clocks / 2386360
  162.  */
  163. {
  164.    unsigned long elapsed=0;
  165.    unsigned int last,next,ncopy,diff;
  166.  
  167.    /* Read the counter value. */
  168.    outp(0x43,0);                              /* want to read timer 0 */
  169.    last=inp(0x40);                            /* low byte */
  170.    last=~((inp(0x40)<< 8) + last);            /* high byte */
  171.  
  172.    do {
  173.       /* Read the counter value. */
  174.       outp(0x43,0);                           /* want to read timer 0 */
  175.       next=inp(0x40);                         /* low byte */
  176.       ncopy=next=~((inp(0x40)<< 8) + next);   /* high byte */
  177.  
  178.       next-=last;      /* this is now number of elapsed clock pulses since last read */
  179.  
  180.       elapsed += next; /* add to total elapsed clock pulses */
  181.       last=ncopy;
  182.    } while (elapsed<clocks);
  183. }
  184.  
  185.  
  186.  
  187. int base16(char **str, unsigned *val)
  188. /* Takes a double pointer to a string, interprets the characters as a
  189.  * base-16 number, and advances the pointer.
  190.  * Returns 0 if successful, 1 if not.
  191.  */
  192. {
  193.    char c;
  194.    int digit;
  195.    *val = 0;
  196.  
  197.    while ( **str != ' ') {
  198.       c = toupper(**str);
  199.       if (c >= '0' && c <= '9')
  200.          digit = c - '0';
  201.       else if (c >= 'A' && c <= 'F')
  202.          digit = c - 'A'  + 10;
  203.       else
  204.          return 1;          // error in string
  205.  
  206.       *val = *val * 16 + digit;
  207.       (*str)++;
  208.    }
  209.    return 0;
  210. }
  211.  
  212.  
  213.  
  214. int base10(char **str, unsigned *val)
  215. /* Takes a double pointer to a string, interprets the characters as a
  216.  * base-10 number, and advances the pointer.
  217.  * Returns 0 if successful, 1 if not.
  218.  */
  219. {
  220.    char c;
  221.    int digit;
  222.    *val = 0;
  223.  
  224.    while ( **str != ' ') {
  225.       c = toupper(**str);
  226.       if (c >= '0' && c <= '9')
  227.          digit = c - '0';
  228.       else
  229.          return 1;          // error in string
  230.  
  231.       *val = *val * 10 + digit;
  232.       (*str)++;
  233.    }
  234.    return 0;
  235. }
  236.  
  237.  
  238.  
  239. unsigned ReadBlasterEnv(unsigned *port, unsigned *irq, unsigned *dma8,
  240.  unsigned *dma16)
  241. /* Gets the Blaster environment statement and stores the values in the
  242.  * variables whose addresses were passed to it.
  243.  * Returns:
  244.  *   0  if successful
  245.  *   1  if there was an error reading the port address.
  246.  *   2  if there was an error reading the IRQ number.
  247.  *   3  if there was an error reading the 8-bit DMA channel.
  248.  *   4  if there was an error reading the 16-bit DMA channel.
  249.  */
  250. {
  251.    char     *env;
  252.    unsigned val;
  253.    int      digit;
  254.  
  255.    env = getenv("BLASTER");
  256.  
  257.    while (*env) {
  258.       switch(toupper( *(env++) )) {
  259.          case 'A':
  260.             if (base16(&env, port))     // interpret port value as hex
  261.                return 1;                // error
  262.             break;
  263.          case 'I':
  264.             if (base10(&env, irq))      // interpret IRQ as decimal
  265.                return 2;                // error
  266.             break;
  267.          case 'D':
  268.             if (base10(&env, dma8))     // 8-bit DMA channel is decimal
  269.                return 3;
  270.             break;
  271.          case 'H':
  272.             if (base10(&env, dma16))    // 16-bit DMA channel is decimal
  273.                return 4;
  274.             break;
  275.          default:
  276.             break;
  277.       }
  278.    }
  279.  
  280.    return 0;
  281. }
  282.  
  283.  
  284.  
  285. void FMoutput(unsigned port, int reg, int val)
  286. /* This outputs a value to a specified FM register at a specified FM port. */
  287. {
  288.    outp(port, reg);
  289.    mydelay(8);          /* need to wait 3.3 microsec */
  290.    outp(port+1, val);
  291.    mydelay(55);         /* need to wait 23 microsec */
  292. }
  293.  
  294.  
  295.  
  296. void fm(int reg, int val)
  297. /* This function outputs a value to a specified FM register at the Sound
  298.  * Blaster (mono) port address.
  299.  */
  300. {
  301.    FMoutput(IOport+FM, reg, val);
  302. }
  303.  
  304.  
  305. void Profm1(int reg, int val)
  306. /* This function outputs a value to a specified FM register at the Sound
  307.  * Blaster Pro left FM port address (or OPL-3 bank 0).
  308.  */
  309. {
  310.    FMoutput(IOport+PROFM1, reg, val);
  311. }
  312.  
  313.  
  314. void Profm2(int reg, int val)
  315. /* This function outputs a value to a specified FM register at the Sound
  316.  * Blaster Pro right FM port address (or OPL-3 bank 1).
  317.  */
  318. {
  319.    FMoutput(IOport+PROFM2, reg, val);
  320. }
  321.  
  322.  
  323.  
  324.  
  325. void main(void)
  326. {
  327.    int i,val1,val2;
  328.  
  329.    int block,b,m,f,fn;
  330.  
  331.    unsigned dummy;
  332.  
  333.  
  334.    clrscr();
  335.  
  336.    ReadBlasterEnv(&IOport, &dummy, &dummy, &dummy);
  337.  
  338. #ifdef STEREO
  339.  #ifdef OPL3
  340.    printf("Program compiled for Sound Blaster Pro ver. 2 (CT-1600) and SB16 cards.\n");
  341.  #else
  342.    printf("Program compiled for Sound Blaster Pro ver. 1 (CT-1330) cards.\n");
  343.  #endif
  344. #else
  345.    printf("Program compiled for Sound Blaster 1.0 - 2.0 cards (monaural).\n");
  346. #endif
  347.  
  348.  
  349.    fm(1,0);        /* must initialize this to zero */
  350.  
  351. #ifdef OPL3
  352.    Profm2(5, 1);  /* set to OPL3 mode, necessary for stereo */
  353.    fm(0xC0,LEFT | RIGHT | 1);     /* set both channels, parallel connection */
  354. #else
  355.    fm(0xC0,               1);     /* parallel connection */
  356. #endif
  357.  
  358.    /***************************************
  359.     * Set parameters for the carrier cell *
  360.     ***************************************/
  361.  
  362.    fm(0x23,0x21);  /* no amplitude modulation (D7=0), no vibrato (D6=0),
  363.                     * sustained envelope type (D5=1), KSR=0 (D4=0),
  364.                     * frequency multiplier=1 (D4-D0=1)
  365.                     */
  366.  
  367.    fm(0x43,0x0);   /* no volume decrease with pitch (D7-D6=0),
  368.                     * no attenuation (D5-D0=0)
  369.                     */
  370.  
  371.    fm(0x63,0xff);  /* fast attack (D7-D4=0xF) and decay (D3-D0=0xF) */
  372.    fm(0x83,0x05);  /* high sustain level (D7-D4=0), slow release rate (D3-D0=5) */
  373.  
  374.  
  375.    /*****************************************
  376.     * Set parameters for the modulator cell *
  377.     *****************************************/
  378.  
  379.    fm(0x20,0x20);  /* sustained envelope type, frequency multiplier=0    */
  380.    fm(0x40,0x3f);  /* maximum attenuation, no volume decrease with pitch */
  381.  
  382.    /* Since the modulator signal is attenuated as much as possible, these
  383.     * next two values shouldn't have any effect.
  384.     */
  385.    fm(0x60,0x44);  /* slow attack and decay */
  386.    fm(0x80,0x05);  /* high sustain level, slow release rate */
  387.  
  388.  
  389.    /*************************************************
  390.     * Generate tone from values looked up in table. *
  391.     *************************************************/
  392.  
  393.    printf("440 Hz tone, values looked up in table.\n");
  394.    fm(0xa0,0x41);  /* 440 Hz */
  395.    fm(0xb0,0x32);  /* 440 Hz, block 0, key on */
  396.  
  397.    getche();
  398.  
  399.    fm(0xb0,0x12);  /* key off */
  400.  
  401.  
  402.    /******************************************
  403.     * Generate tone from a calculated value. *
  404.     ******************************************/
  405.  
  406.    printf("440 Hz tone, values calculated.\n");
  407.    block=4;        /* choose block=4 and m=1 */
  408.    m=1;               /* m is the frequency multiple number */
  409.    f=440;          /* want f=440 Hz */
  410.    b= 1 << block;
  411.  
  412.    /* This is the equation to calculate frequency number from frequency. */
  413.  
  414.    fn=(long)f * 1048576 / b / m /50000L;
  415.  
  416.    fm(0x23,0x20 | (m & 0xF));   /* 0x20 sets sustained envelope, low nibble
  417.                                  * is multiple number
  418.                                  */
  419.    fm(0xA0,(fn & 0xFF));
  420.    fm(0xB0,((fn >> 8) & 0x3) + (block << 2) | KEYON);
  421.  
  422.    getche();
  423.  
  424.  
  425.    /*********************************************************
  426.     * Generate a range of octaves by changing block number. *
  427.     *********************************************************/
  428.  
  429.    printf("Range of frequencies created by changing block number.\n");
  430.    for (block=0; block<=7; block++) {
  431.       printf("f=%5ld Hz (press Enter)\n",(long)440*(1 << block)/16);
  432.       fm(0xB0,((fn >> 8) & 0x3) + (block << 2) | KEYON);
  433.       getche();
  434.    }
  435.  
  436.  
  437.    /*****************************************************************
  438.     * Generate a range of frequencies by changing frequency number. *
  439.     *****************************************************************/
  440.  
  441.    printf("Range of frequencies created by changing frequency number.\n");
  442.    block=4;
  443.    for (fn=0; fn<1024; fn++) {
  444.       fm(0xA0,(fn & 0xFF));
  445.       fm(0xB0,((fn >> 8) & 0x3) + (block << 2) | KEYON);
  446.       delay(1);
  447.    }
  448.  
  449.  
  450.    /********************************************************************
  451.     * Single tone again.  Both channels, then if on stereo board,      *
  452.     * play tone in just the left channel, then just the right channel. *
  453.     ********************************************************************/
  454.  
  455.    printf("440 Hz again, both channels.\n");
  456.    block=4;
  457.    fn=577;                /* This number makes 440 Hz when block=4 and m=1 */
  458.    fm(0xA0,(fn & 0xFF));
  459.    fm(0xB0,((fn >> 8) & 0x3) + (block << 2) | KEYON);
  460.  
  461. #ifdef STEREO
  462.  #ifdef OPL3
  463.     /* This left and right channel stuff is the only part of this program
  464.      * that uses OPL3 mode.  Everything else is available on the OPL2.
  465.      */
  466.  
  467.     getche();
  468.     printf("Left channel only\n");
  469.     fm(0xC0,LEFT | 1);      /* set left channel only, parallel connection */
  470.  
  471.     getche();
  472.     printf("Right channel only\n");
  473.     fm(0xC0,RIGHT | 1);     /* set right channel only, parallel connection */
  474.  #else
  475.     getche();
  476.     fm(0xB0,((fn >> 8) & 0x3) + (block << 2));       // key off
  477.  
  478.     printf("Left channel only\n");
  479.     Profm1(0xB0,((fn >> 8) & 0x3) + (block << 2) | KEYON);
  480.  
  481.     getche();
  482.     Profm1(0xB0,((fn >> 8) & 0x3) + (block << 2));   // key off
  483.  
  484.     printf("Right channel only\n");
  485.     Profm2(0xB0,((fn >> 8) & 0x3) + (block << 2) | KEYON);
  486.  
  487.  
  488.  #endif
  489. #endif
  490.  
  491.  
  492.    /*********************************
  493.     * Attenuate the signal by 3 dB. *
  494.     *********************************/
  495.  
  496.    getche();
  497.    fm(0xB0,((fn >> 8) & 0x3) + (block << 2) | KEYON);
  498.    printf("Attenuated by 3 dB.\n");
  499.    fm(0x43,4);     /* attenuate by 3 dB */
  500.    getche();
  501.  
  502.    fm(0xB0,((fn >> 8) & 0x3) + (block << 2));
  503.  
  504. #ifdef OPL3
  505.    /* Set OPL-3 back to OPL-2 mode, because if the next program to run was
  506.     * written for the OPL-2, then it won't set the LEFT and RIGHT bits to
  507.     * one, so no sound will be heard.
  508.     */
  509.    Profm2(5, 0);   /* set back to OPL2 mode */
  510. #endif
  511. }
  512.