home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: Multimed
/
Multimed.zip
/
lbmix04.zip
/
PipeMix
/
Source
/
CS38.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-05-05
|
15KB
|
535 lines
/*
Pipe Mixer patch for Crystal Semi driver v.2.08 by Lesha Bogdanow
Copyright (C) 1999-2000 Lesha Bogdanow
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define USE_OS2_TOOLKIT_HEADERS
#define INCL_DOSPROCESS
#define INCL_MCIOS2
#define INCL_OS2MM
#define INCL_DOSDEVICES
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <os2.h>
#include <os2me.h>
#include <audio.h>
#include <sys\hw.h>
#include "call32.h"
#include "ioctl90.h"
#include "mixerapi.h"
#include "PipeMixPvt.h"
#define DEF_INFO_BUF_SIZE 128
const char szLogo[]="PipeMixer mixer patch v.0.03 for Crystal driver v.2.08.";
unsigned char ApiMap[256];
int LockRate=0;
int BasePort=0;
int AccessedPort=0;
int BaseCPort=0;
int AccessedCPort=0;
MIXSTRUCT AUX1={0,0,0}; // IOCTL90: Line
MIXSTRUCT Mic={0,0,0};
MIXSTRUCT DAC={2,0,0}; // Released initially
MIXSTRUCT ADC={2,0,0}; // Released initially
MIXSTRUCT ThreeD={6,0,0}; // Space supported, Center supported
MIXSTRUCT RecMux={6,0,0}; // Released initially, mixer
MIXSTRUCT Master={0,100,100};
int MasterOn=FALSE; // Enable master volume control
int LockPriority=PRTYC_TIMECRITICAL;
TID LockTID=0;
static void SetRegister(unsigned char idx,unsigned char data) {
if (BasePort) {
if (BasePort!=AccessedPort) {
_portaccess(BasePort,BasePort+1);
AccessedPort=BasePort;
}
_outp8(BasePort,idx);
_outp8(BasePort+1,data);
}
}
static unsigned char GetRegister(unsigned char idx) {
if (BasePort) {
if (BasePort!=AccessedPort) {
_portaccess(BasePort,BasePort+1);
AccessedPort=BasePort;
}
_outp8(BasePort,idx);
return _inp8(BasePort+1);
}
return 0;
}
static void SetXRegister(unsigned char idx,unsigned char data) {
if (!BasePort) return;
SetRegister(23,(GetRegister(23)&3) | ((idx&0xF)<<4) | ((idx&0x10)>>2) | 8);
_outp8(BasePort+1,data);
_outp8(BasePort,23); // Reset XRAE
}
static unsigned char GetXRegister(unsigned char idx) {
unsigned char rc;
if (!BasePort) return 0;
SetRegister(23,(GetRegister(23)&3) | ((idx&0xF)<<4) | ((idx&0x10)>>2) | 8);
rc=_inp8(BasePort+1);
_outp8(BasePort,23); // Reset XRAE
return rc;
}
static void SetCRegister(unsigned char idx,unsigned char data) {
if (BaseCPort) {
if (BaseCPort!=AccessedCPort) {
_portaccess(BaseCPort,BaseCPort+4);
AccessedCPort=BaseCPort;
}
_outp8(BaseCPort+3,idx);
_outp8(BaseCPort+4,data);
}
}
static unsigned char GetCRegister(unsigned char idx) {
if (BaseCPort) {
if (BaseCPort!=AccessedCPort) {
_portaccess(BaseCPort,BaseCPort+4);
AccessedCPort=BaseCPort;
}
_outp8(BaseCPort+3,idx);
return _inp8(BaseCPort+4);
}
return 0;
}
static void Limit100(MIXSTRUCT *ms) {
if (ms->VolumeL>100) ms->VolumeL=100;
if (ms->VolumeR>100) ms->VolumeR=100;
}
static void _GetInp(MIXSTRUCT *ms, int rl, int rr) {
unsigned char t;
t=GetRegister(rl);
if (t&0x80) ms->Mute|=1;
t&=0x1F;
ms->VolumeL=(32-t)*100/32;
t=GetRegister(rr)&0x1F;
ms->VolumeR=(32-t)*100/32;
Limit100(ms);
}
// Get hardware state at startup
static void GetState() {
unsigned char t;
t=GetRegister(0);
t=(t&0xF);
if (t==0xF) ADC.Mute|=1;
ADC.VolumeL=(16-t)*100/16;
Limit100(&ADC);
_GetInp(&AUX1,2,3);
t=GetRegister(6);
if (t&0x80) DAC.Mute|=1;
t&=0x3F;
DAC.VolumeL=(64-t)*100/64;
t=GetRegister(7)&0x3F;
DAC.VolumeR=(64-t)*100/64;
Limit100(&DAC);
t=GetXRegister(2);
if (t&0x40) Mic.Mute|=1;
t&=0x1F;
Mic.VolumeL=(32-t)*100/32;
t=GetXRegister(3)&0x1F;
Mic.VolumeR=(32-t)*100/32;
Limit100(&Mic);
if (!(GetXRegister(2)&0x80)) RecMux.VolumeL|=I90SRC_MIC;
if (!(GetRegister(4)&0x40)) RecMux.VolumeL|=I90SRC_CD; //CD = AUX2
if (!(GetRegister(2)&0x40)) RecMux.VolumeL|=I90SRC_LINE; //LINE = AUX1
if (!(GetRegister(18)&0x40)) RecMux.VolumeL|=I90SRC_AUX; //AUX = LINE
if (BaseCPort) {
if (!(GetCRegister(3)&0x80)) ThreeD.Mute|=1;
t=GetCRegister(2);
ThreeD.VolumeL=(16-((t&0xF0)>>4))*100/16;
ThreeD.VolumeR=(16-(t&0xF))*100/16;
Limit100(&ThreeD);
}
}
static void _SetADC(int n) {
unsigned char t;
if (ADC.Mute&1) t=15;
else t=16-(ADC.VolumeL*16)/100;
if (t>15) t=15;
t=(GetRegister(n)&0xC0) | t;
SetRegister(n,t);
}
static void SetADC() {
if (ADC.Mute&2) return;
_SetADC(0);
_SetADC(1);
}
static void SetRecMux() {
unsigned char t;
if (RecMux.Mute&2) return;
if (RecMux.VolumeL&I90SRC_MIC) t=0;
else t=0x80;
SetXRegister(2,(GetXRegister(2)&0x7F) | t);
SetXRegister(3,(GetXRegister(3)&0x7F) | t);
if (RecMux.VolumeL&I90SRC_CD) t=0;
else t=0x40;
SetRegister(4,(GetRegister(4)&0xBF) | t);
SetRegister(5,(GetRegister(5)&0xBF) | t);
if (RecMux.VolumeL&I90SRC_LINE) t=0;
else t=0x40;
SetRegister(2,(GetRegister(2)&0xBF) | t);
SetRegister(3,(GetRegister(3)&0xBF) | t);
if (RecMux.VolumeL&I90SRC_AUX) t=0;
else t=0x40;
SetRegister(18,(GetRegister(18)&0xBF) | t);
SetRegister(19,(GetRegister(19)&0xBF) | t);
}
static void _SetInp(MIXSTRUCT *ms, int rl, int rr) {
unsigned char t;
t=32-(ms->VolumeL*32)/100;
if (t>31) t=31;
if (ms->Mute&1) t|=0x80;
SetRegister(rl,t | (GetRegister(rl)&0x60));
t=32-(ms->VolumeR*32)/100;
if (t>31) t=31;
if (ms->Mute&1) t|=0x80;
SetRegister(rr,t | (GetRegister(rr)&0x60));
}
static void SetAUX1() {
_SetInp(&AUX1,2,3);
}
static void SetDAC() {
unsigned char t;
if (DAC.Mute&2) return;
t=64-(DAC.VolumeL*64)/100;
if (t>63) t=63;
if (DAC.Mute&1) t|=0x80;
SetRegister(6,t);
t=64-(DAC.VolumeR*64)/100;
if (t>63) t=63;
if (DAC.Mute&1) t|=0x80;
SetRegister(7,t);
}
static void SetMic() {
unsigned char t;
t=32-(Mic.VolumeL*32)/100;
if (t>31) t=31;
if (Mic.Mute&1) t|=0x40;
SetXRegister(2,t | (GetXRegister(2)&0xA0));
t=32-(Mic.VolumeR*32)/100;
if (t>31) t=31;
if (Mic.Mute&1) t|=0x40;
SetXRegister(3,t | (GetXRegister(3)&0xA0));
}
static void Set3D() {
unsigned char ts,tc;
if (!BaseCPort) return;
ts=16-(ThreeD.VolumeL*16)/100;
if (ts>15) ts=15;
tc=16-(ThreeD.VolumeR*16)/100;
if (tc>15) tc=15;
SetCRegister(2,(ts<<4)|tc);
if (ThreeD.Mute&1) ts=0;
else ts=0xA0;
SetCRegister(3,(GetCRegister(3)&0x5F) | ts);
}
VOID APIENTRY LockThread(ULONG Dummy) {
DosSetPriority(PRTYS_THREAD, LockPriority, 0, 0);
while(1) {
DosSleep(LockRate);
SetDAC();
SetADC();
SetRecMux();
};
}
// Initialize mixer. Return TRUE if Ok
int MixerInit(int argc, char *argv[]) {
int DriverInfo;
MIXSTRUCT dummymix;
MIXMSGBUF MixMsgBuf;
ULONG Level;
int i;
for (i=1;i<argc;i++) {
if (!stricmp(argv[i],"-d")) {
i++;
if (i==argc) return FALSE; // Syntax error
strcpy(szPddName,"\\DEV\\");
strncpy(szPddName+5,argv[i],8);
strupr(szPddName);
}
else if (!stricmp(argv[i],"-b")) {
i++;
if (i==argc) return FALSE; // Syntax error
BasePort=strtoul(argv[i],NULL,16)&0xFFFF;
}
else if (!stricmp(argv[i],"-c")) {
i++;
if (i==argc) return FALSE; // Syntax error
BaseCPort=strtoul(argv[i],NULL,16)&0xFFFF;
}
else if (!stricmp(argv[i],"-l")) {
i++;
if (i==argc) return FALSE; // Syntax error
LockRate=atoi(argv[i]);
}
else if (!stricmp(argv[i],"-mv")) MasterOn=TRUE;
else return FALSE; // Syntax error
}
if (!BasePort) return FALSE;
if (mixerapiInit(NULL)) return FALSE;
if (mixerapiIOCTL90(GETAPIMAP,ApiMap,256)) return FALSE;
if (mixerapiIOCTL90(APILEVELQUERY,&Level,sizeof(ULONG))) return FALSE;
if (Level!=1) {
fprintf(stderr,"Driver v.2.08 is expected. Newer drivers do not need this mixer patch.\n");
return FALSE;
}
if (ApiMap[MSGBUF]) {
MixMsgBuf.pBuffer=0;
MixMsgBuf.ulSize=0;
MixMsgBuf.fClear=FALSE;
if (!mixerapiIOCTL90(MSGBUF,&MixMsgBuf,sizeof(MIXMSGBUF))) {
InfoBufSize=MixMsgBuf.ulSize;
InfoBuf=malloc(InfoBufSize);
MixMsgBuf.pBuffer=(ULONG)InfoBuf;
MixMsgBuf.ulSize=InfoBufSize;
MixMsgBuf.fClear=FALSE;
if (!mixerapiIOCTL90(MSGBUF,&MixMsgBuf,sizeof(MIXMSGBUF))) {
DriverInfo=TRUE;
}
else free(InfoBuf);
}
}
if (!DriverInfo) {
InfoBufSize=DEF_INFO_BUF_SIZE;
InfoBuf=malloc(InfoBufSize);
strcpy(InfoBuf,"Driver does not return info.");
strcat(InfoBuf,"\nAPI Level: ");
_itoa(ApiLevel,InfoBuf+strlen(InfoBuf),10);
}
GetState();
if (LockRate) DosCreateThread(&LockTID,LockThread,0,0,8192);
ApiLevel=2;
if (Debug) printf("Device: %s, API Level: %d, Base port: %x, Lock rate: %d\nDriver Info: \n%s\n",
szPddName,ApiLevel,BasePort,LockRate,InfoBuf);
return TRUE;
}
// Deinitialize mixer
void MixerClose() {
if (LockTID) DosKillThread(LockTID);
mixerapiDeInit();
}
// Set Master volume/balance (0-0x7FFF) by calling PDD IOCTL
static int MasterSetVB(unsigned short vol, unsigned short bal) {
MCI_TRACK_INFO TrackInfo;
MCI_AUDIO_CHANGE AudioChange;
MCI_AUDIO_CONTROL AudioCtl;
ULONG ulSize,ulRC;
void * _Seg16 pul16; // defines a 16:16 pointer
extern HFILE hDriver;
TrackInfo.usMasterVolume=vol;
TrackInfo.usDitherPct=0; // ???
TrackInfo.usMasterVolumeDelay=0;
TrackInfo.usMasterBalance=bal;
TrackInfo.usMasterBalanceDelay=0;
pul16=(void * _Seg16)FlatToSel((unsigned long)(&TrackInfo));
AudioChange.pvDevInfo=pul16;
AudioChange.prMoreInputs=NULL;
AudioChange.prMoreOutputs=NULL;
AudioChange.pvModeInfo=NULL;
AudioCtl.usIOCtlRequest=AUDIO_CHANGE;
pul16=(void * _Seg16)FlatToSel((unsigned long)(&AudioChange));
AudioCtl.pbRequestInfo=pul16;
AudioCtl.ulPosition=0;
ulSize=sizeof(AudioCtl);
ulRC = DosDevIOCtl(hDriver,AUDIO_IOCTL_CAT,AUDIO_CONTROL,
NULL,0,NULL,&AudioCtl,ulSize,&ulSize);
return ulRC;
}
// Calculate value for master volume/balance
static unsigned short MasterVal(int v) {
unsigned short rc;
if (v<0) v=0;
rc=(v<<15)/100;
if (rc>0x7FFF) rc=0x7FFF;
return rc;
}
// Set Master volume by calling PDD IOCTL
static int MasterSet(MIXSTRUCT *MixStruct) {
int v,b;
if (MixStruct->VolumeL>MixStruct->VolumeR) v=MixStruct->VolumeL;
else v=MixStruct->VolumeR;
b=(100+MixStruct->VolumeL-MixStruct->VolumeR)/2; // Balance
return MasterSetVB(MasterVal(v),MasterVal(b));
}
/* Process a command. Buff is an output buffer, the function number and
a trailing space are already there. tokens - number of command tokens
cmd - command, p1, p2, p3 - parameters. If some of them are not specified
then default values (p1=100, p2=p1, p3=0) are supplied
*/
int ProcessCmd(char *Buff, int tokens, int cmd, int p1, int p2, int p3) {
MIXSTRUCT MixStruct;
if ((cmd==0x01)&&MasterOn) { // Master set
Master.VolumeL=p1;
Master.VolumeR=p2;
if (!MasterSet(&Master)) {
strcat(Buff,REP_OK);
}
else strcat(Buff,REP_FAILED);
}
else if ((cmd==0x11)&&MasterOn) // Master query
sprintf(Buff+strlen(Buff),"%d %d %x",Master.VolumeL,Master.VolumeR,Master.Mute);
else if ((cmd&0xF0)==0x40) {
MixStruct.VolumeL=p1;
MixStruct.VolumeR=p2;
MixStruct.Mute=p3;
switch(cmd) {
case 0x42: // Mic
Mic=MixStruct;
SetMic();
break;
case 0x43: // Line
AUX1=MixStruct;
SetAUX1();
break;
case 0x4D: // DAC
DAC=MixStruct;
SetDAC();
break;
case 0x4E: // RecMux
RecMux=MixStruct;
SetRecMux();
break;
case 0x4F: // ADC
ADC=MixStruct;
SetADC();
break;
case 0x4C: // 3D
if (BaseCPort) {
ThreeD=MixStruct;
Set3D();
}
else {
strcat(Buff,REP_UNSUPPORTED);
return TRUE;
}
break;
default:
if (ApiMap[cmd]) {
if (mixerapiIOCTL90(cmd,&MixStruct,sizeof(MIXSTRUCT))) {
strcat(Buff,REP_FAILED);
return TRUE;
}
SetRecMux(); // In case it modified an input mixer bit
}
else {
strcat(Buff,REP_UNSUPPORTED);
return TRUE;
}
}
strcat(Buff,REP_OK);
}
else if ((cmd&0xF0)==0x60) { // Query command
switch(cmd) {
case 0x62: // Mic
MixStruct=Mic;
break;
case 0x63: // Line
MixStruct=AUX1;
break;
case 0x6D: // DAC
MixStruct=DAC;
break;
case 0x6E: // RecMux
MixStruct=RecMux;
MixStruct.Mute|=4; // mixer
break;
case 0x6F: // ADC
MixStruct=ADC;
break;
case 0x6C: // 3D
if (BaseCPort) {
MixStruct=ThreeD;
MixStruct.Mute|=6; // Space supported, Center supported
}
else {
strcat(Buff,REP_UNSUPPORTED);
return TRUE;
}
break;
default:
if (ApiMap[cmd]) {
if (mixerapiIOCTL90(cmd,&MixStruct,sizeof(MIXSTRUCT))) {
strcat(Buff,REP_FAILED);
return TRUE;
}
}
else {
strcat(Buff,REP_UNSUPPORTED);
return TRUE;
}
}
sprintf(Buff+strlen(Buff),"%d %d %x",MixStruct.VolumeL,MixStruct.VolumeR,MixStruct.Mute);
}
else strcat(Buff,REP_UNSUPPORTED);
return TRUE;
}