home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: Multimed / Multimed.zip / lbmix04.zip / PipeMix / Source / CS3.c < prev    next >
C/C++ Source or Header  |  2000-05-05  |  11KB  |  353 lines

  1. /* 
  2.  
  3. Pipe Mixer patch for Crystal Semi driver v.2.09+ by Lesha Bogdanow
  4. Copyright (C) 1999-2000  Lesha Bogdanow
  5.  
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20.  */
  21.  
  22. #define USE_OS2_TOOLKIT_HEADERS
  23. #define INCL_DOSPROCESS
  24. #define INCL_MCIOS2
  25. #define INCL_OS2MM
  26. #define INCL_DOSDEVICES
  27. #include <stddef.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <os2.h>
  31. #include <os2me.h>
  32. #include <audio.h>
  33. #include <sys\hw.h>
  34.  
  35. #include "call32.h"
  36. #include "ioctl90.h"
  37. #include "mixerapi.h"
  38. #include "PipeMixPvt.h"
  39.  
  40. #define DEF_INFO_BUF_SIZE 128
  41.  
  42. const char szLogo[]="PipeMixer mixer patch v.0.03 for Crystal driver v.2.09+.";
  43.  
  44. unsigned char ApiMap[256];
  45.  
  46. int    BaseCPort=0;
  47. int    AccessedCPort=0;
  48. int    DACPatch=FALSE;        // Patch non-continuous DAC volume
  49.  
  50. MIXSTRUCT DAC={2,0,0};        // Released initially
  51. MIXSTRUCT ThreeD={6,0,0};    // Space supported, Center supported
  52. MIXSTRUCT Master={0,100,100};
  53. int MasterOn=FALSE;        // Enable master volume control
  54.  
  55. /* Volume map, mixer -> driver */
  56. const int VolFMap[]={0,0,0,0,0,0,0,0,0,0,
  57.              0,0,0,0,0,0,0,0,0,0,
  58.              0,0,0,0,0,0,0,0,0,0,
  59.              0,4,4,4,4,4,4,5,5,6,
  60.              9,1,1,12,3,3,3,3,3,3,
  61.              3,3,3,3,3,3,3,3,3,3,
  62.              3,17,17,17,17,17,17,17,17,17,
  63.              17,17,17,17,17,17,17,15,15,20,
  64.              20,24,25,25,26,28,28,29,29,40,
  65.              43,43,46,48,48,50,50,50,50,50,
  66.              50};
  67. /* Volume map, driver -> mixer */
  68. const int VolRMap[]={26,42,42,45,35,37,39,39,39,40,
  69.              40,42,43,43,45,78,78,76,76,78,
  70.              79,79,79,79,81,82,84,84,85,87,
  71.              87,84,84,84,85,85,85,85,87,87,
  72.              89,89,89,90,90,90,92,92,93,93,
  73.              95,95,76,78,78,79,79,76,79,81,
  74.              82,84,85,87,87,87,87,87,87,87,
  75.              87,87,87,87,87,87,87,87,87,87,
  76.              87,87,87,87,87,87,87,87,87,87,
  77.              87,87,87,87,87,87,87,87,87,87,
  78.              87};
  79.  
  80.  
  81. static void SetCRegister(unsigned char idx,unsigned char data) {
  82.    if (BaseCPort) {
  83.       if (BaseCPort!=AccessedCPort) {
  84.          _portaccess(BaseCPort,BaseCPort+4);
  85.          AccessedCPort=BaseCPort;
  86.          }
  87.       _outp8(BaseCPort+3,idx);
  88.       _outp8(BaseCPort+4,data);
  89.       }
  90.    }
  91.  
  92. static unsigned char GetCRegister(unsigned char idx) {
  93.    if (BaseCPort) {
  94.       if (BaseCPort!=AccessedCPort) {
  95.          _portaccess(BaseCPort,BaseCPort+4);
  96.          AccessedCPort=BaseCPort;
  97.          }
  98.       _outp8(BaseCPort+3,idx);
  99.       return _inp8(BaseCPort+4);
  100.       }
  101.    return 0;
  102.    }
  103.  
  104. static void Limit100(MIXSTRUCT *ms) {
  105.    if (ms->VolumeL>100) ms->VolumeL=100;
  106.    if (ms->VolumeR>100) ms->VolumeR=100;
  107.    }
  108.  
  109. // Get hardware state at startup
  110. static int GetState() {
  111.    unsigned char t;
  112.    MIXSTRUCT MixStruct;
  113.  
  114.    if (DACPatch) {
  115.       if (mixerapiIOCTL90(0x6D,&MixStruct,sizeof(MIXSTRUCT))) return FALSE;
  116.       Limit100(&DAC);
  117.       DAC.VolumeL=VolRMap[DAC.VolumeL];
  118.       DAC.VolumeR=VolRMap[DAC.VolumeR];
  119.       }
  120.  
  121.    if (BaseCPort) {
  122.       if (!(GetCRegister(3)&0x80)) ThreeD.Mute|=1;
  123.       t=GetCRegister(2);
  124.       ThreeD.VolumeL=(16-((t&0xF0)>>4))*100/16;
  125.       ThreeD.VolumeR=(16-(t&0xF))*100/16;
  126.       }
  127.    return TRUE;
  128.    }
  129.  
  130. static void Set3D() {
  131.    unsigned char ts,tc;
  132.  
  133.    if (!BaseCPort) return;
  134.    ts=16-(ThreeD.VolumeL*16)/100;
  135.    if (ts>15) ts=15;
  136.    tc=16-(ThreeD.VolumeR*16)/100;
  137.    if (tc>15) tc=15;
  138.    SetCRegister(2,(ts<<4)|tc);
  139.    if (ThreeD.Mute&1) ts=0;
  140.    else ts=0xA0;
  141.    SetCRegister(3,(GetCRegister(3)&0x5F) | ts);
  142.    }
  143.  
  144. // Initialize mixer. Return TRUE if Ok
  145. int MixerInit(int argc, char *argv[]) {
  146.    int DriverInfo;
  147.    MIXSTRUCT dummymix;
  148.    MIXMSGBUF MixMsgBuf;
  149.    ULONG Level;
  150.    int i;
  151.  
  152.    for (i=1;i<argc;i++) {
  153.      if (!stricmp(argv[i],"-d"))  {
  154.         i++;
  155.         if (i==argc) return FALSE;        // Syntax error
  156.         strcpy(szPddName,"\\DEV\\");
  157.         strncpy(szPddName+5,argv[i],8);
  158.         strupr(szPddName);
  159.         }
  160.      else if (!stricmp(argv[i],"-c"))  {
  161.         i++;
  162.         if (i==argc) return FALSE;        // Syntax error
  163.         BaseCPort=strtoul(argv[i],NULL,16)&0xFFFF;
  164.         }
  165.      else if (!stricmp(argv[i],"-dac"))  DACPatch=TRUE;
  166.      else if (!stricmp(argv[i],"-mv")) MasterOn=TRUE;
  167.      else return FALSE;                // Syntax error
  168.      }
  169.    if (mixerapiInit(NULL)) return FALSE;
  170.    if (mixerapiIOCTL90(GETAPIMAP,ApiMap,256)) return FALSE;
  171.    if (mixerapiIOCTL90(APILEVELQUERY,&Level,sizeof(ULONG))) return FALSE;
  172.    if (Level<2) {
  173.       fprintf(stderr,"Drivers v.2.09+ are expected.\n");
  174.       return FALSE;
  175.       }
  176.    if (ApiMap[MSGBUF]) {
  177.       MixMsgBuf.pBuffer=0;
  178.       MixMsgBuf.ulSize=0;
  179.       MixMsgBuf.fClear=FALSE;
  180.       if (!mixerapiIOCTL90(MSGBUF,&MixMsgBuf,sizeof(MIXMSGBUF))) {
  181.          InfoBufSize=MixMsgBuf.ulSize;
  182.          InfoBuf=malloc(InfoBufSize);
  183.          MixMsgBuf.pBuffer=(ULONG)InfoBuf;
  184.          MixMsgBuf.ulSize=InfoBufSize;
  185.          MixMsgBuf.fClear=FALSE;
  186.          if (!mixerapiIOCTL90(MSGBUF,&MixMsgBuf,sizeof(MIXMSGBUF))) {
  187.             DriverInfo=TRUE;
  188.             }
  189.          else free(InfoBuf);
  190.          }
  191.       }
  192.    if (!DriverInfo) {
  193.       InfoBufSize=DEF_INFO_BUF_SIZE;
  194.       InfoBuf=malloc(InfoBufSize);
  195.       strcpy(InfoBuf,"Driver does not return info.");
  196.       strcat(InfoBuf,"\nAPI Level: ");
  197.       _itoa(ApiLevel,InfoBuf+strlen(InfoBuf),10);
  198.       }
  199.    if (BaseCPort&&ApiMap[0x4C]&&ApiMap[0x6C]) {
  200.       printf("WARNING: 3D processing is supported by the driver.");
  201.       BaseCPort=0;
  202.       }
  203.    if (!GetState()) return FALSE;
  204.    ApiLevel=2;
  205.    if (Debug) printf("Device: %s, API Level: %d\nDriver Info: \n%s\n",
  206.                      szPddName,ApiLevel,InfoBuf);
  207.    return TRUE;
  208.    }
  209.  
  210. // Deinitialize mixer
  211. void MixerClose() {
  212.    mixerapiDeInit();
  213.    }
  214.  
  215. // Set Master volume/balance (0-0x7FFF) by calling PDD IOCTL
  216. static int MasterSetVB(unsigned short vol, unsigned short bal) {
  217.    MCI_TRACK_INFO TrackInfo;
  218.    MCI_AUDIO_CHANGE AudioChange;
  219.    MCI_AUDIO_CONTROL AudioCtl;
  220.    ULONG ulSize,ulRC;
  221.    void * _Seg16 pul16;                   // defines a 16:16 pointer
  222.    extern HFILE hDriver;
  223.  
  224.    TrackInfo.usMasterVolume=vol;
  225.    TrackInfo.usDitherPct=0;        // ???
  226.    TrackInfo.usMasterVolumeDelay=0;
  227.    TrackInfo.usMasterBalance=bal;
  228.    TrackInfo.usMasterBalanceDelay=0;
  229.    pul16=(void * _Seg16)FlatToSel((unsigned long)(&TrackInfo));
  230.    AudioChange.pvDevInfo=pul16;
  231.    AudioChange.prMoreInputs=NULL;
  232.    AudioChange.prMoreOutputs=NULL;
  233.    AudioChange.pvModeInfo=NULL;
  234.    AudioCtl.usIOCtlRequest=AUDIO_CHANGE;
  235.    pul16=(void * _Seg16)FlatToSel((unsigned long)(&AudioChange));
  236.    AudioCtl.pbRequestInfo=pul16;
  237.    AudioCtl.ulPosition=0;
  238.  
  239.    ulSize=sizeof(AudioCtl);
  240.    ulRC = DosDevIOCtl(hDriver,AUDIO_IOCTL_CAT,AUDIO_CONTROL,
  241.                          NULL,0,NULL,&AudioCtl,ulSize,&ulSize);
  242.    return ulRC;
  243.    }
  244.  
  245. // Calculate value for master volume/balance
  246. static unsigned short MasterVal(int v) {
  247.    unsigned short rc;
  248.  
  249.    if (v<0) v=0;
  250.    rc=(v<<15)/100;
  251.    if (rc>0x7FFF) rc=0x7FFF;
  252.    return rc;
  253.    }
  254.  
  255. // Set Master volume by calling PDD IOCTL
  256. static int MasterSet(MIXSTRUCT *MixStruct) {
  257.    int v,b;
  258.  
  259.    if (MixStruct->VolumeL>MixStruct->VolumeR) v=MixStruct->VolumeL;
  260.    else v=MixStruct->VolumeR;
  261.    b=(100+MixStruct->VolumeL-MixStruct->VolumeR)/2;    // Balance
  262.    return MasterSetVB(MasterVal(v),MasterVal(b));
  263.    }
  264.  
  265. /* Process a command. Buff is an output buffer, the function number and
  266.    a trailing space are already there. tokens - number of command tokens
  267.    cmd - command, p1, p2, p3 - parameters. If some of them are not specified
  268.    then default values (p1=100, p2=p1, p3=0) are supplied
  269. */
  270. int ProcessCmd(char *Buff, int tokens, int cmd, int p1, int p2, int p3) {
  271.    MIXSTRUCT MixStruct;
  272.  
  273.    if ((cmd==0x01)&&MasterOn) {            // Master set
  274.       Master.VolumeL=p1;
  275.       Master.VolumeR=p2;
  276.       if (!MasterSet(&Master)) {
  277.          strcat(Buff,REP_OK);
  278.          }
  279.       else strcat(Buff,REP_FAILED);
  280.       }
  281.    else if ((cmd==0x11)&&MasterOn)        // Master query
  282.       sprintf(Buff+strlen(Buff),"%d %d %x",Master.VolumeL,Master.VolumeR,Master.Mute);
  283.    else if ((cmd&0xF0)==0x40) {
  284.       MixStruct.VolumeL=p1;
  285.       MixStruct.VolumeR=p2;
  286.       MixStruct.Mute=p3;
  287.       switch(cmd) {
  288.          case 0x4C:        // 3D
  289.             if (BaseCPort) {
  290.                ThreeD=MixStruct;
  291.                Set3D();
  292.                }
  293.             else {
  294.                strcat(Buff,REP_UNSUPPORTED);
  295.                return TRUE;
  296.                }
  297.             break;
  298.          case 0x4D:        // DAC
  299.             if (DACPatch) {
  300.                DAC=MixStruct;
  301.                Limit100(&MixStruct);
  302.                MixStruct.VolumeL=VolFMap[MixStruct.VolumeL];
  303.                MixStruct.VolumeR=VolFMap[MixStruct.VolumeR];
  304.                }
  305.          default:
  306.             if (ApiMap[cmd]) {
  307.                if (mixerapiIOCTL90(cmd,&MixStruct,sizeof(MIXSTRUCT))) {
  308.                   strcat(Buff,REP_FAILED);
  309.                   return TRUE;
  310.                   }
  311.                }
  312.             else {
  313.                strcat(Buff,REP_UNSUPPORTED);
  314.                return TRUE;
  315.                }
  316.          }
  317.       strcat(Buff,REP_OK);
  318.       }
  319.    else if ((cmd&0xF0)==0x60) {    // Query command
  320.       switch(cmd) {
  321.          case 0x6C:        // 3D
  322.             if (BaseCPort) {
  323.                MixStruct=ThreeD;
  324.                MixStruct.Mute|=6;    // Space supported, Center supported
  325.                }
  326.             else {
  327.                strcat(Buff,REP_UNSUPPORTED);
  328.                return TRUE;
  329.                }
  330.             break;
  331.          case 0x6D:        // DAC
  332.             if (DACPatch) {
  333.                MixStruct=DAC;
  334.                break;
  335.                }
  336.          default:
  337.             if (ApiMap[cmd]) {
  338.                if (mixerapiIOCTL90(cmd,&MixStruct,sizeof(MIXSTRUCT))) {
  339.                   strcat(Buff,REP_FAILED);
  340.                   return TRUE;
  341.                   }
  342.                }
  343.             else {
  344.                strcat(Buff,REP_UNSUPPORTED);
  345.                return TRUE;
  346.                }
  347.          }
  348.       sprintf(Buff+strlen(Buff),"%d %d %x",MixStruct.VolumeL,MixStruct.VolumeR,MixStruct.Mute);
  349.       }
  350.    else strcat(Buff,REP_UNSUPPORTED);
  351.    return TRUE;
  352.    }
  353.