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

  1. /* 
  2.  
  3. Pipe Mixer patch for Crystal Semi driver v.2.08 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.08.";
  43.  
  44. unsigned char ApiMap[256];
  45.  
  46. int    LockRate=0;
  47. int    BasePort=0;
  48. int    AccessedPort=0;
  49. int    BaseCPort=0;
  50. int    AccessedCPort=0;
  51.  
  52. MIXSTRUCT AUX1={0,0,0};        // IOCTL90: Line 
  53. MIXSTRUCT Mic={0,0,0};
  54. MIXSTRUCT DAC={2,0,0};        // Released initially
  55. MIXSTRUCT ADC={2,0,0};        // Released initially
  56. MIXSTRUCT ThreeD={6,0,0};    // Space supported, Center supported
  57. MIXSTRUCT RecMux={6,0,0};    // Released initially, mixer
  58. MIXSTRUCT Master={0,100,100};
  59. int MasterOn=FALSE;        // Enable master volume control
  60.  
  61. int    LockPriority=PRTYC_TIMECRITICAL;
  62. TID    LockTID=0;
  63.  
  64. static void SetRegister(unsigned char idx,unsigned char data) {
  65.    if (BasePort) {
  66.       if (BasePort!=AccessedPort) {
  67.          _portaccess(BasePort,BasePort+1);
  68.          AccessedPort=BasePort;
  69.          }
  70.       _outp8(BasePort,idx);
  71.       _outp8(BasePort+1,data);
  72.       }
  73.    }
  74.  
  75. static unsigned char GetRegister(unsigned char idx) {
  76.    if (BasePort) {
  77.       if (BasePort!=AccessedPort) {
  78.          _portaccess(BasePort,BasePort+1);
  79.          AccessedPort=BasePort;
  80.          }
  81.       _outp8(BasePort,idx);
  82.       return _inp8(BasePort+1);
  83.       }
  84.    return 0;
  85.    }
  86.  
  87. static void SetXRegister(unsigned char idx,unsigned char data) {
  88.    if (!BasePort) return;
  89.    SetRegister(23,(GetRegister(23)&3) | ((idx&0xF)<<4) | ((idx&0x10)>>2) | 8);
  90.    _outp8(BasePort+1,data);
  91.    _outp8(BasePort,23);        // Reset XRAE
  92.    }
  93.  
  94. static unsigned char GetXRegister(unsigned char idx) {
  95.    unsigned char rc;
  96.  
  97.    if (!BasePort) return 0;
  98.    SetRegister(23,(GetRegister(23)&3) | ((idx&0xF)<<4) | ((idx&0x10)>>2) | 8);
  99.    rc=_inp8(BasePort+1);
  100.    _outp8(BasePort,23);        // Reset XRAE
  101.    return rc;
  102.    }
  103.  
  104. static void SetCRegister(unsigned char idx,unsigned char data) {
  105.    if (BaseCPort) {
  106.       if (BaseCPort!=AccessedCPort) {
  107.          _portaccess(BaseCPort,BaseCPort+4);
  108.          AccessedCPort=BaseCPort;
  109.          }
  110.       _outp8(BaseCPort+3,idx);
  111.       _outp8(BaseCPort+4,data);
  112.       }
  113.    }
  114.  
  115. static unsigned char GetCRegister(unsigned char idx) {
  116.    if (BaseCPort) {
  117.       if (BaseCPort!=AccessedCPort) {
  118.          _portaccess(BaseCPort,BaseCPort+4);
  119.          AccessedCPort=BaseCPort;
  120.          }
  121.       _outp8(BaseCPort+3,idx);
  122.       return _inp8(BaseCPort+4);
  123.       }
  124.    return 0;
  125.    }
  126.  
  127. static void Limit100(MIXSTRUCT *ms) {
  128.    if (ms->VolumeL>100) ms->VolumeL=100;
  129.    if (ms->VolumeR>100) ms->VolumeR=100;
  130.    }
  131.  
  132. static void _GetInp(MIXSTRUCT *ms, int rl, int rr) {
  133.    unsigned char t;
  134.  
  135.    t=GetRegister(rl);
  136.    if (t&0x80) ms->Mute|=1;
  137.    t&=0x1F;
  138.    ms->VolumeL=(32-t)*100/32;
  139.    t=GetRegister(rr)&0x1F;
  140.    ms->VolumeR=(32-t)*100/32;
  141.    Limit100(ms);
  142.    }
  143.  
  144. // Get hardware state at startup
  145. static void GetState() {
  146.    unsigned char t;
  147.  
  148.    t=GetRegister(0);
  149.    t=(t&0xF);
  150.    if (t==0xF) ADC.Mute|=1;
  151.    ADC.VolumeL=(16-t)*100/16;
  152.    Limit100(&ADC);
  153.  
  154.    _GetInp(&AUX1,2,3);
  155.  
  156.    t=GetRegister(6);
  157.    if (t&0x80) DAC.Mute|=1;
  158.    t&=0x3F;
  159.    DAC.VolumeL=(64-t)*100/64;
  160.    t=GetRegister(7)&0x3F;
  161.    DAC.VolumeR=(64-t)*100/64;
  162.    Limit100(&DAC);
  163.  
  164.    t=GetXRegister(2);
  165.    if (t&0x40) Mic.Mute|=1;
  166.    t&=0x1F;
  167.    Mic.VolumeL=(32-t)*100/32;
  168.    t=GetXRegister(3)&0x1F;
  169.    Mic.VolumeR=(32-t)*100/32;
  170.    Limit100(&Mic);
  171.  
  172.    if (!(GetXRegister(2)&0x80)) RecMux.VolumeL|=I90SRC_MIC;
  173.    if (!(GetRegister(4)&0x40)) RecMux.VolumeL|=I90SRC_CD; //CD = AUX2
  174.    if (!(GetRegister(2)&0x40)) RecMux.VolumeL|=I90SRC_LINE; //LINE = AUX1
  175.    if (!(GetRegister(18)&0x40)) RecMux.VolumeL|=I90SRC_AUX; //AUX = LINE
  176.  
  177.    if (BaseCPort) {
  178.       if (!(GetCRegister(3)&0x80)) ThreeD.Mute|=1;
  179.       t=GetCRegister(2);
  180.       ThreeD.VolumeL=(16-((t&0xF0)>>4))*100/16;
  181.       ThreeD.VolumeR=(16-(t&0xF))*100/16;
  182.       Limit100(&ThreeD);
  183.       }
  184.    }
  185.  
  186. static void _SetADC(int n) {
  187.    unsigned char t;
  188.  
  189.    if (ADC.Mute&1) t=15;
  190.    else t=16-(ADC.VolumeL*16)/100;
  191.    if (t>15) t=15;
  192.    t=(GetRegister(n)&0xC0) | t;
  193.    SetRegister(n,t);
  194.    }
  195. static void SetADC() {
  196.    if (ADC.Mute&2) return;
  197.    _SetADC(0);
  198.    _SetADC(1);
  199.    }
  200. static void SetRecMux() {
  201.    unsigned char t;
  202.  
  203.    if (RecMux.Mute&2) return;
  204.  
  205.    if (RecMux.VolumeL&I90SRC_MIC) t=0;
  206.    else t=0x80;
  207.    SetXRegister(2,(GetXRegister(2)&0x7F) | t);
  208.    SetXRegister(3,(GetXRegister(3)&0x7F) | t);
  209.  
  210.    if (RecMux.VolumeL&I90SRC_CD) t=0;
  211.    else t=0x40;
  212.    SetRegister(4,(GetRegister(4)&0xBF) | t);
  213.    SetRegister(5,(GetRegister(5)&0xBF) | t);
  214.  
  215.    if (RecMux.VolumeL&I90SRC_LINE) t=0;
  216.    else t=0x40;
  217.    SetRegister(2,(GetRegister(2)&0xBF) | t);
  218.    SetRegister(3,(GetRegister(3)&0xBF) | t);
  219.  
  220.    if (RecMux.VolumeL&I90SRC_AUX) t=0;
  221.    else t=0x40;
  222.    SetRegister(18,(GetRegister(18)&0xBF) | t);
  223.    SetRegister(19,(GetRegister(19)&0xBF) | t);
  224.    }
  225. static void _SetInp(MIXSTRUCT *ms, int rl, int rr) {
  226.    unsigned char t;
  227.  
  228.    t=32-(ms->VolumeL*32)/100;
  229.    if (t>31) t=31;
  230.    if (ms->Mute&1) t|=0x80;
  231.    SetRegister(rl,t | (GetRegister(rl)&0x60));
  232.    t=32-(ms->VolumeR*32)/100;
  233.    if (t>31) t=31;
  234.    if (ms->Mute&1) t|=0x80;
  235.    SetRegister(rr,t | (GetRegister(rr)&0x60));
  236.    }
  237. static void SetAUX1() {
  238.    _SetInp(&AUX1,2,3);
  239.    }
  240. static void SetDAC() {
  241.    unsigned char t;
  242.  
  243.    if (DAC.Mute&2) return;
  244.  
  245.    t=64-(DAC.VolumeL*64)/100;
  246.    if (t>63) t=63;
  247.    if (DAC.Mute&1) t|=0x80;
  248.    SetRegister(6,t);
  249.    t=64-(DAC.VolumeR*64)/100;
  250.    if (t>63) t=63;
  251.    if (DAC.Mute&1) t|=0x80;
  252.    SetRegister(7,t);
  253.    }
  254. static void SetMic() {
  255.    unsigned char t;
  256.  
  257.    t=32-(Mic.VolumeL*32)/100;
  258.    if (t>31) t=31;
  259.    if (Mic.Mute&1) t|=0x40;
  260.    SetXRegister(2,t | (GetXRegister(2)&0xA0));
  261.    t=32-(Mic.VolumeR*32)/100;
  262.    if (t>31) t=31;
  263.    if (Mic.Mute&1) t|=0x40;
  264.    SetXRegister(3,t | (GetXRegister(3)&0xA0));
  265.    }
  266. static void Set3D() {
  267.    unsigned char ts,tc;
  268.  
  269.    if (!BaseCPort) return;
  270.    ts=16-(ThreeD.VolumeL*16)/100;
  271.    if (ts>15) ts=15;
  272.    tc=16-(ThreeD.VolumeR*16)/100;
  273.    if (tc>15) tc=15;
  274.    SetCRegister(2,(ts<<4)|tc);
  275.    if (ThreeD.Mute&1) ts=0;
  276.    else ts=0xA0;
  277.    SetCRegister(3,(GetCRegister(3)&0x5F) | ts);
  278.    }
  279.  
  280. VOID APIENTRY LockThread(ULONG Dummy) {
  281.    DosSetPriority(PRTYS_THREAD, LockPriority, 0, 0);
  282.  
  283.    while(1) {
  284.       DosSleep(LockRate);
  285.       SetDAC();
  286.       SetADC();
  287.       SetRecMux();
  288.       };
  289.    }
  290.  
  291.  
  292. // Initialize mixer. Return TRUE if Ok
  293. int MixerInit(int argc, char *argv[]) {
  294.    int DriverInfo;
  295.    MIXSTRUCT dummymix;
  296.    MIXMSGBUF MixMsgBuf;
  297.    ULONG Level;
  298.    int i;
  299.  
  300.  
  301.    for (i=1;i<argc;i++) {
  302.      if (!stricmp(argv[i],"-d"))  {
  303.         i++;
  304.         if (i==argc) return FALSE;        // Syntax error
  305.         strcpy(szPddName,"\\DEV\\");
  306.         strncpy(szPddName+5,argv[i],8);
  307.         strupr(szPddName);
  308.         }
  309.      else if (!stricmp(argv[i],"-b"))  {
  310.         i++;
  311.         if (i==argc) return FALSE;        // Syntax error
  312.         BasePort=strtoul(argv[i],NULL,16)&0xFFFF;
  313.         }
  314.      else if (!stricmp(argv[i],"-c"))  {
  315.         i++;
  316.         if (i==argc) return FALSE;        // Syntax error
  317.         BaseCPort=strtoul(argv[i],NULL,16)&0xFFFF;
  318.         }
  319.      else if (!stricmp(argv[i],"-l"))  {
  320.         i++;
  321.         if (i==argc) return FALSE;        // Syntax error
  322.         LockRate=atoi(argv[i]);
  323.         }
  324.      else if (!stricmp(argv[i],"-mv")) MasterOn=TRUE;
  325.      else return FALSE;                // Syntax error
  326.      }
  327.    if (!BasePort) return FALSE;
  328.    if (mixerapiInit(NULL)) return FALSE;
  329.    if (mixerapiIOCTL90(GETAPIMAP,ApiMap,256)) return FALSE;
  330.    if (mixerapiIOCTL90(APILEVELQUERY,&Level,sizeof(ULONG))) return FALSE;
  331.    if (Level!=1) {
  332.       fprintf(stderr,"Driver v.2.08 is expected. Newer drivers do not need this mixer patch.\n");
  333.       return FALSE;
  334.       }
  335.    if (ApiMap[MSGBUF]) {
  336.       MixMsgBuf.pBuffer=0;
  337.       MixMsgBuf.ulSize=0;
  338.       MixMsgBuf.fClear=FALSE;
  339.       if (!mixerapiIOCTL90(MSGBUF,&MixMsgBuf,sizeof(MIXMSGBUF))) {
  340.          InfoBufSize=MixMsgBuf.ulSize;
  341.          InfoBuf=malloc(InfoBufSize);
  342.          MixMsgBuf.pBuffer=(ULONG)InfoBuf;
  343.          MixMsgBuf.ulSize=InfoBufSize;
  344.          MixMsgBuf.fClear=FALSE;
  345.          if (!mixerapiIOCTL90(MSGBUF,&MixMsgBuf,sizeof(MIXMSGBUF))) {
  346.             DriverInfo=TRUE;
  347.             }
  348.          else free(InfoBuf);
  349.          }
  350.       }
  351.    if (!DriverInfo) {
  352.       InfoBufSize=DEF_INFO_BUF_SIZE;
  353.       InfoBuf=malloc(InfoBufSize);
  354.       strcpy(InfoBuf,"Driver does not return info.");
  355.       strcat(InfoBuf,"\nAPI Level: ");
  356.       _itoa(ApiLevel,InfoBuf+strlen(InfoBuf),10);
  357.       }
  358.    GetState();
  359.    if (LockRate) DosCreateThread(&LockTID,LockThread,0,0,8192);
  360.    ApiLevel=2;
  361.    if (Debug) printf("Device: %s, API Level: %d, Base port: %x, Lock rate: %d\nDriver Info: \n%s\n",
  362.                      szPddName,ApiLevel,BasePort,LockRate,InfoBuf);
  363.    return TRUE;
  364.    }
  365.  
  366. // Deinitialize mixer
  367. void MixerClose() {
  368.    if (LockTID) DosKillThread(LockTID);
  369.    mixerapiDeInit();
  370.    }
  371.  
  372. // Set Master volume/balance (0-0x7FFF) by calling PDD IOCTL
  373. static int MasterSetVB(unsigned short vol, unsigned short bal) {
  374.    MCI_TRACK_INFO TrackInfo;
  375.    MCI_AUDIO_CHANGE AudioChange;
  376.    MCI_AUDIO_CONTROL AudioCtl;
  377.    ULONG ulSize,ulRC;
  378.    void * _Seg16 pul16;                   // defines a 16:16 pointer
  379.    extern HFILE hDriver;
  380.  
  381.    TrackInfo.usMasterVolume=vol;
  382.    TrackInfo.usDitherPct=0;        // ???
  383.    TrackInfo.usMasterVolumeDelay=0;
  384.    TrackInfo.usMasterBalance=bal;
  385.    TrackInfo.usMasterBalanceDelay=0;
  386.    pul16=(void * _Seg16)FlatToSel((unsigned long)(&TrackInfo));
  387.    AudioChange.pvDevInfo=pul16;
  388.    AudioChange.prMoreInputs=NULL;
  389.    AudioChange.prMoreOutputs=NULL;
  390.    AudioChange.pvModeInfo=NULL;
  391.    AudioCtl.usIOCtlRequest=AUDIO_CHANGE;
  392.    pul16=(void * _Seg16)FlatToSel((unsigned long)(&AudioChange));
  393.    AudioCtl.pbRequestInfo=pul16;
  394.    AudioCtl.ulPosition=0;
  395.  
  396.    ulSize=sizeof(AudioCtl);
  397.    ulRC = DosDevIOCtl(hDriver,AUDIO_IOCTL_CAT,AUDIO_CONTROL,
  398.                          NULL,0,NULL,&AudioCtl,ulSize,&ulSize);
  399.    return ulRC;
  400.    }
  401.  
  402. // Calculate value for master volume/balance
  403. static unsigned short MasterVal(int v) {
  404.    unsigned short rc;
  405.  
  406.    if (v<0) v=0;
  407.    rc=(v<<15)/100;
  408.    if (rc>0x7FFF) rc=0x7FFF;
  409.    return rc;
  410.    }
  411.  
  412. // Set Master volume by calling PDD IOCTL
  413. static int MasterSet(MIXSTRUCT *MixStruct) {
  414.    int v,b;
  415.  
  416.    if (MixStruct->VolumeL>MixStruct->VolumeR) v=MixStruct->VolumeL;
  417.    else v=MixStruct->VolumeR;
  418.    b=(100+MixStruct->VolumeL-MixStruct->VolumeR)/2;    // Balance
  419.    return MasterSetVB(MasterVal(v),MasterVal(b));
  420.    }
  421.  
  422. /* Process a command. Buff is an output buffer, the function number and
  423.    a trailing space are already there. tokens - number of command tokens
  424.    cmd - command, p1, p2, p3 - parameters. If some of them are not specified
  425.    then default values (p1=100, p2=p1, p3=0) are supplied
  426. */
  427. int ProcessCmd(char *Buff, int tokens, int cmd, int p1, int p2, int p3) {
  428.    MIXSTRUCT MixStruct;
  429.  
  430.    if ((cmd==0x01)&&MasterOn) {            // Master set
  431.       Master.VolumeL=p1;
  432.       Master.VolumeR=p2;
  433.       if (!MasterSet(&Master)) {
  434.          strcat(Buff,REP_OK);
  435.          }
  436.       else strcat(Buff,REP_FAILED);
  437.       }
  438.    else if ((cmd==0x11)&&MasterOn)        // Master query
  439.       sprintf(Buff+strlen(Buff),"%d %d %x",Master.VolumeL,Master.VolumeR,Master.Mute);
  440.    else if ((cmd&0xF0)==0x40) {
  441.       MixStruct.VolumeL=p1;
  442.       MixStruct.VolumeR=p2;
  443.       MixStruct.Mute=p3;
  444.       switch(cmd) {
  445.          case 0x42:        // Mic
  446.             Mic=MixStruct;
  447.             SetMic();
  448.             break;
  449.          case 0x43:        // Line
  450.             AUX1=MixStruct;
  451.             SetAUX1();
  452.             break;
  453.          case 0x4D:        // DAC
  454.             DAC=MixStruct;
  455.             SetDAC();
  456.             break;
  457.          case 0x4E:        // RecMux
  458.             RecMux=MixStruct;
  459.             SetRecMux();
  460.             break;
  461.          case 0x4F:        // ADC
  462.             ADC=MixStruct;
  463.             SetADC();
  464.             break;
  465.          case 0x4C:        // 3D
  466.             if (BaseCPort) {
  467.                ThreeD=MixStruct;
  468.                Set3D();
  469.                }
  470.             else {
  471.                strcat(Buff,REP_UNSUPPORTED);
  472.                return TRUE;
  473.                }
  474.             break;
  475.          default:
  476.             if (ApiMap[cmd]) {
  477.                if (mixerapiIOCTL90(cmd,&MixStruct,sizeof(MIXSTRUCT))) {
  478.                   strcat(Buff,REP_FAILED);
  479.                   return TRUE;
  480.                   }
  481.                SetRecMux(); // In case it modified an input mixer bit
  482.                }
  483.             else {
  484.                strcat(Buff,REP_UNSUPPORTED);
  485.                return TRUE;
  486.                }
  487.          }
  488.       strcat(Buff,REP_OK);
  489.       }
  490.    else if ((cmd&0xF0)==0x60) {    // Query command
  491.       switch(cmd) {
  492.          case 0x62:        // Mic
  493.             MixStruct=Mic;
  494.             break;
  495.          case 0x63:        // Line
  496.             MixStruct=AUX1;
  497.             break;
  498.          case 0x6D:        // DAC
  499.             MixStruct=DAC;
  500.             break;
  501.          case 0x6E:        // RecMux
  502.             MixStruct=RecMux;
  503.             MixStruct.Mute|=4;    // mixer
  504.             break;
  505.          case 0x6F:        // ADC
  506.             MixStruct=ADC;
  507.             break;
  508.          case 0x6C:        // 3D
  509.             if (BaseCPort) {
  510.                MixStruct=ThreeD;
  511.                MixStruct.Mute|=6;    // Space supported, Center supported
  512.                }
  513.             else {
  514.                strcat(Buff,REP_UNSUPPORTED);
  515.                return TRUE;
  516.                }
  517.             break;
  518.          default:
  519.             if (ApiMap[cmd]) {
  520.                if (mixerapiIOCTL90(cmd,&MixStruct,sizeof(MIXSTRUCT))) {
  521.                   strcat(Buff,REP_FAILED);
  522.                   return TRUE;
  523.                   }
  524.                }
  525.             else {
  526.                strcat(Buff,REP_UNSUPPORTED);
  527.                return TRUE;
  528.                }
  529.          }
  530.       sprintf(Buff+strlen(Buff),"%d %d %x",MixStruct.VolumeL,MixStruct.VolumeR,MixStruct.Mute);
  531.       }
  532.    else strcat(Buff,REP_UNSUPPORTED);
  533.    return TRUE;
  534.    }
  535.