home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / setpas.zip / PAS.C next >
C/C++ Source or Header  |  1994-04-15  |  13KB  |  432 lines

  1. /*
  2.  *  Utilty to set the mixer values of Mediavision Pro Audio 16
  3.  *
  4.  *  Platform: IBM OS/2 2.x , IBM C-Set ( V1.0 used )
  5.  *
  6.  *  Mediavision Device-Driver 'mvprodd' required.
  7.  *
  8.  *  Written by Johannes Deisenhofer (S_DEISENH@rzmain.rz.uni-ulm.de)
  9.  *
  10.  *  Version 1.00   24.02.94
  11.  *
  12.  *  This software works by sending DevIOCtl-commands to the 'PAS161$' device. 
  13.  *
  14.  *  Freeware. Use at your own risk.
  15.  *
  16.  */
  17.       
  18. #include <stdio.h>
  19. #include <string.h>
  20.  
  21. #define INCL_BASE
  22. #include <os2.h>
  23.  
  24.  
  25. /* MVPRODD-specific Constants */
  26.  
  27. #define DEVNAME "PAS161$" /* Name of the Device */ 
  28.       
  29. #define MIXER_CAT 0x81    /* This IOCtl-Category is used for mixing */
  30.  
  31. /* Device Commands defined by the device driver. */
  32. /* There are more of them , but I don't know what they do */
  33.  
  34. typedef enum { 
  35.                PAS_GetState = 0x47,
  36.                PAS_SetState = 0x48,
  37.                PAS_GetValue = 0x4d,
  38.                PAS_SetValue = 0x4e 
  39.              } DEVCMD;
  40.       
  41. /* Audio channels, do not reorder */
  42.  
  43. typedef enum { FM=0,            /* FM-Chip */
  44.                RecMon,          /* Record Monitor */
  45.                Aux,             /* Aux */
  46.                CD,              /* CD Input */
  47.                Mic,             /* Microphone */
  48.                W16,             /* 16-Bit DA */
  49.                Spkr,            /* PC Speaker */
  50.                SB,              /* Soundblaster */
  51.                Global=256,      /* Global Volume and Settings */
  52.                Input=0xc5       /* Input Level */
  53.               } CHAN;
  54.               
  55.               
  56. /* 'Global' channel has these Subcommands */
  57.               
  58. typedef enum  { G_Volume    = 1,
  59.                 G_Sound     = 8,
  60.                 G_Loud      = 0x20,
  61.                 G_Enhance   = 0x100
  62.               } SCMD;               
  63.               
  64. /* channel mode flags */
  65.               
  66. typedef enum { 
  67.     
  68.         noflags=0,          
  69.         isbass,             /* Is Bass or Treble : trigger special handling */
  70.         istreble, 
  71.         switchable = 0x20,  /* Record/Play selectable */ 
  72.         stereo     = 0x40   /* Stereo channel */
  73.         } SFLAG;              
  74.         
  75.         
  76. /* This table binds keywords to channels and their flags */        
  77.  
  78. struct {
  79.     char *devstr;    /* Commandline keyword */
  80.     CHAN channel;    /* channel number */
  81.     SCMD subcmd;     /* sub-command */
  82.     SFLAG flag;      /* flags */
  83.  
  84. devtbl[] =    
  85.  
  86. {
  87.   { "BASS",     Global, G_Sound,  isbass      }, 
  88.   { "TREBLE" ,  Global, G_Sound,  istreble    }, 
  89.   { "FM",       FM,     1,        switchable | stereo },
  90.   { "Synth",    FM,     1,        switchable | stereo  },
  91.   { "MON",      RecMon, 1,        stereo  },
  92.   { "INT",      CD,     1,        switchable | stereo  },
  93.   { "CD",       CD,     1,        switchable | stereo  },
  94.   { "EXT",      Aux,    1,        switchable | stereo  },
  95.   { "AUX",      Aux,    1,        switchable | stereo  },
  96.   { "MIC",      Mic,    1,        switchable | stereo  },
  97.   { "PCM",      W16,    1,        switchable | stereo  },
  98.   { "WAVE",     W16,    1,        switchable | stereo  },
  99.   { "SPEAKER",  Spkr,   1,        switchable | stereo  },
  100.   { "SPKR",     Spkr,   1,        switchable | stereo  },
  101.   { "SB",       SB,     1,        switchable | stereo  },
  102.   { "SoundBlaster", SB, 1,        switchable | stereo  },
  103.   { "VOLUME",   Global, G_Volume, stereo  },
  104.   { "VOL",      Global, G_Volume, stereo  },
  105.   { "MASTER",   Global, G_Volume, stereo  },
  106.   { "INPUT",    Input,  1,        stereo  },
  107.   { "LOUDNESS", Global, G_Loud,   noflags },
  108.   { "ENHANCE",  Global, G_Enhance,noflags }
  109.  };
  110.  
  111.              
  112. /* Values used by PAS_Set/GetValue */             
  113.              
  114. typedef enum { Monitor = 1,
  115.                Record  = 2 
  116.              } MONCMD;
  117.              
  118.              
  119. /* Globals */
  120.              
  121. HFILE filehandle;      /* Filehandle of Device-Driver. Used globally */
  122. extern const char *helptext; /* I want to have this one at the end of the program */
  123.         
  124. typedef ULONG CTRL_PACKET[6];    /* Values are passed back in this structure */
  125.  
  126.  
  127. /* Set a value 
  128.  * Args: CHAN    ch    : channel
  129.  *       SCMD    sc    : subchannel
  130.  *       USHORT  left,
  131.  *               right : Value, 0 min, 0xffff max 
  132.  */        
  133.             
  134. int pas_setval(CHAN ch, SCMD sc,USHORT left, USHORT right)
  135. {
  136.     return pas_mix_cmd(PAS_SetValue,ch,sc, left<<16 | right );
  137. }
  138.  
  139. /* Get a value 
  140.  * Args: CHAN    ch    : channel
  141.  */
  142.  
  143. ULONG pas_getval(CHAN ch,SCMD sc)
  144. {   
  145.     ULONG retval;
  146.     
  147.     /* Pass Adress as a 16:16 Pointer - CSet Syntax */
  148.     pas_mix_cmd(PAS_GetValue,ch,sc,(ULONG)(ULONG * _Seg16)&retval);
  149.     return retval;
  150. }
  151.  
  152. /* Set a switch
  153.  * Args: CHAN    ch    : channel
  154.  *       MONCMD  cmd   : new state of switch
  155.  */        
  156.  
  157. int pas_setmon(CHAN ch, MONCMD cmd)
  158. {
  159.     return pas_mix_cmd(PAS_SetState,ch,cmd);
  160. }    
  161.  
  162. /* Get a switch
  163.  * Args: CHAN    ch    : channel
  164.  * Ret : MONCMD  cmd   : new state of switch
  165.  */        
  166.  
  167. MONCMD pas_getmon(CHAN ch)
  168. {
  169.     ULONG retval;
  170.     
  171.     /* Pass Adress as a 16:16 Pointer - CSet Syntax */
  172.     pas_mix_cmd(PAS_GetState,ch,(ULONG)(ULONG * _Seg16)&retval,0);
  173.     return retval;
  174. }
  175.  
  176. /* 
  177.  * pas_mix_cmd : Send Command to Driver 
  178.  *
  179.  * uses global 'filehandle'
  180.  * 
  181.  * Assembles ULONG values into a packet and sends it to the DD
  182.  *
  183.  */
  184.         
  185. int pas_mix_cmd(DEVCMD function, ULONG arg1, ULONG arg2, ULONG arg3) 
  186. {  
  187.     
  188.     APIRET rc;
  189.     CTRL_PACKET ctrl;
  190.     ULONG size1, size2;
  191.     
  192.     memset(&ctrl,0,sizeof(CTRL_PACKET));
  193.     
  194.     ctrl[0]=arg1;
  195.     ctrl[1]=arg2;
  196.     ctrl[2]=arg3;
  197.     
  198.     size2=0;
  199.     size1=sizeof(CTRL_PACKET);
  200.     
  201.     rc = DosDevIOCtl(filehandle,MIXER_CAT,function,
  202.                      &ctrl,sizeof(ctrl),&size1,
  203.                      NULL,0,&size2);
  204.     return rc;
  205. }                     
  206.  
  207. /* Macros for converting USHORT values to percentages and back */
  208.  
  209. #define TOPROC(a) ((((a)*100/0x7fff)+1)/2)
  210. #define TOSHORT(a)((((a)*0xffff/50)+1)/2)
  211.  
  212. /* Parse Command Line */
  213.  
  214. int do_proc(int argc,char** argv)
  215. {
  216.   int argptr=1,k;
  217.    
  218.   enum { LEFT,RIGHT,BOTH } chansel = BOTH;   /* Flag for selected channel */
  219.     
  220.   if (argc<3) return (-1);
  221.     
  222.   while (argptr<argc) {
  223.     
  224.     /* GET Values */
  225.     
  226.     if (!stricmp(argv[argptr],"GET"))
  227.     {
  228.         
  229.         ULONG value;
  230.         MONCMD mode;
  231.         
  232.         argptr++;
  233.         if (argptr+1>argc) return -1;
  234.         
  235.         /* Find string in Table */
  236.         for(k=0;k<sizeof(devtbl)/sizeof(*devtbl);k++) 
  237.             if(!stricmp(argv[argptr],devtbl[k].devstr)) break;
  238.         if(k==sizeof(devtbl)/sizeof(*devtbl)) return -1;  /* Not found */
  239.         
  240.         /* Get value if found */
  241.         value=pas_getval(devtbl[k].channel,devtbl[k].subcmd);
  242.         
  243.         /* Format output for BASS and TREBLE */
  244.         if (devtbl[k].flag==istreble || devtbl[k].flag==isbass) 
  245.            printf("Level of %s is %d%%",
  246.                    devtbl[k].devstr,
  247.                    devtbl[k].flag==isbass 
  248.                      ? TOPROC((value>>16)*256)
  249.                      : TOPROC((value&0xffff)*256)
  250.                   );
  251.         
  252.         /* Format output for stereo channels */          
  253.         else if (devtbl[k].flag & stereo) 
  254.            printf("Level of %s is %d%% (L:%d%% R:%d%%)",
  255.                    devtbl[k].devstr,
  256.                    (TOPROC(value>>16)+TOPROC(value&0xffff))/2,
  257.                    TOPROC(value>>16), 
  258.                    TOPROC(value&0xffff)
  259.                   );
  260.                   
  261.         /* Format output for all other (mono) devices */                  
  262.         else          
  263.            printf("Level of %s is %d%%",
  264.                    devtbl[k].devstr,
  265.                    (TOPROC(value>>16)+TOPROC(value&0xffff))/2
  266.                   );
  267.                   
  268.         /* print 'mode' if defined and a CR */          
  269.         if ((devtbl[k].flag & switchable) == switchable ) {
  270.                 mode=pas_getmon(devtbl[k].channel);
  271.                 printf(" Mode: %s\n", (mode==Record ? "Record" : "Monitor") );
  272.         }        
  273.         else printf("\n");              
  274.         argptr++;
  275.         
  276.     }
  277.     
  278.     /*  SET Values   */
  279.     
  280.     else if(!stricmp(argv[1],"SET"))
  281.     {
  282.         ULONG value=0;
  283.         
  284.         argptr++;
  285.         if (argptr+1>argc) return -1;
  286.         
  287.         /* check for LEFT/RIGHT keywords */
  288.         
  289.         if      (!stricmp(argv[argptr],"LEFT"))  { chansel=LEFT; argptr++; }
  290.         else if (!stricmp(argv[argptr],"RIGHT")) { chansel=RIGHT;argptr++; }
  291.         if (argptr>argc) return -1;
  292.         
  293.         /* Find string in Table */
  294.         
  295.         for(k=0;k<sizeof(devtbl)/sizeof(*devtbl);k++) 
  296.             if(!stricmp(argv[argptr],devtbl[k].devstr)) break;
  297.         if(k==sizeof(devtbl)/sizeof(*devtbl)) return -1;  /* Not found */
  298.         
  299.         argptr++;
  300.         if(argptr+1>argc) return -1;
  301.         
  302.         if (!stricmp(argv[argptr],"TO")) 
  303.         {
  304.         
  305.             argptr++;
  306.             if(argptr+1>argc) return -1;
  307.         
  308.             /* Get and check value */
  309.             value= atol(argv[argptr]);
  310.         
  311.             if(value<0 || value > 100 ) return -1;
  312.         
  313.             /* Convert to USHORT */
  314.             value=TOSHORT(value);
  315.         
  316.             /* Special treatment for Bass and Treble */
  317.             if (devtbl[k].flag==isbass  )  {
  318.                 chansel=LEFT;  /* Bass */
  319.                 value/=256;
  320.             }    
  321.             if (devtbl[k].flag==istreble)  {
  322.                 chansel=RIGHT; /* Treble */
  323.                 value/=256;
  324.             }    
  325.             
  326.             /* No left/right keyword given */
  327.             if (chansel==BOTH)
  328.                 /* Set left and right channel to equal values */
  329.                 pas_setval(devtbl[k].channel,devtbl[k].subcmd,value,value);
  330.             /* Left channel */    
  331.             else if (chansel==LEFT)
  332.                 pas_setval(devtbl[k].channel,devtbl[k].subcmd,value,
  333.                            pas_getval(devtbl[k].channel,devtbl[k].subcmd)&0xffff);
  334.             /* Right channel */                           
  335.             else if (chansel==RIGHT)
  336.                pas_setval(devtbl[k].channel,devtbl[k].subcmd,
  337.                            pas_getval(devtbl[k].channel,devtbl[k].subcmd)>>16, value );
  338.                     
  339.             argptr++;
  340.         }
  341.         
  342.         /* FOR */
  343.         
  344.         else if (!stricmp(argv[argptr],"FOR")) 
  345.         {   
  346.             argptr++;
  347.             if(argptr+1>argc) return -1;
  348.             
  349.             /* record or play-mode */
  350.             if (!stricmp(argv[argptr],"Record")) 
  351.             {
  352.                 if ((devtbl[k].flag&switchable)==switchable) 
  353.                     pas_setmon(devtbl[k].channel,Record);    
  354.                 argptr++;
  355.             }
  356.             else if (!stricmp(argv[argptr],"Monitor")) 
  357.             {
  358.                 if ((devtbl[k].flag& switchable)==switchable) 
  359.                     pas_setmon(devtbl[k].channel,Monitor);    
  360.                 argptr++;
  361.             }
  362.             else return -1;
  363.         }    
  364.         else return -1; /* Error */
  365.         
  366.     }
  367.     else return -1;
  368.   }  
  369.    
  370.   return 0;         /* All Commands processed */
  371. }    
  372.  
  373.  
  374. int main(int argc, char**argv)
  375. {
  376.     
  377.     APIRET rc;
  378.     ULONG action=0;
  379.     
  380.     if(argc==1) {       /* Show Help */
  381.         puts(helptext);
  382.         exit (-1);
  383.     }    
  384.     
  385.     rc=DosOpen( DEVNAME,&filehandle,&action,0,
  386.                 FILE_NORMAL,OPEN_ACTION_OPEN_IF_EXISTS,
  387.                 OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE,
  388.                 NULL 
  389.                );
  390.  
  391.     if(rc != NO_ERROR) {
  392.         printf("Can't open device %s !\n",DEVNAME);
  393.         exit(-1);
  394.     }
  395.     
  396.     if(do_proc(argc,argv)!=0)   /* Do Processing */
  397.     
  398.         puts("Syntax error. Type PAS without parameter for help\n");
  399.     
  400.     DosClose(filehandle);
  401.     return (0);
  402.     
  403. }    
  404.  
  405. /* Helptext. */
  406.  
  407. const char *helptext = 
  408. "\n"
  409. "PAS -- Pro AudioSpectrum Mixer and Volume Control Utility, Version 01.00\n"
  410. "by Johannes Deisenhofer '94. No Rights Reserved. Use at your own risk.\n"
  411. "\n"
  412. "  PAS ─┬─>┬── GET <SETTING> ───────────────────────>──────────────┐ \n"
  413. "       ^  └── SET ──┬─ [LEFT/RIGHT] <SETTING> TO <Level> ─────────┼───>─┬──┤\n"
  414. "       │            └─ <SETTING> FOR [RECORD/MONITOR] ────────────┘     │\n"
  415. "       └────────────────<────────────────────────────────<──────────────┘\n"
  416. " <SETTING> : \n"
  417. "   - FM    : Synth Chip volume     │    - MON      : Record monitor volume\n"
  418. "   - MIC   : Microphone volume     │    - VOLUME   : Master Volume\n"
  419. "   - AUX   : Aux Input volume      │    - ENHANCE  : Stereo Enhance\n"
  420. "   - CD    : CD Input volume       │    - BASS     : Bass\n"
  421. "   - PCM   : 16-Bit DAC volume     │    - TREBLE   : Treble\n"
  422. "   - SB    : Soundblaster volume   │    - INPUT    : Input Level (PAS Studio ?)\n"
  423. "   - SPKR  : PC Speaker volume     │    - LOUDNESS : Loudness level\n"
  424. " <LEVEL> is a Number from 0 to 100\n"
  425. "\n"
  426. "Examples:\n"
  427. "\n"
  428. " pas set left volume to 100 set right volume to 80 set enhance to 0 set cd to 0\n"
  429. " pas get volume\n";
  430.  
  431.