home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: Multimed
/
Multimed.zip
/
lbmix04.zip
/
PipeMix
/
Source
/
CS3.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-05-05
|
11KB
|
353 lines
/*
Pipe Mixer patch for Crystal Semi driver v.2.09+ 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.09+.";
unsigned char ApiMap[256];
int BaseCPort=0;
int AccessedCPort=0;
int DACPatch=FALSE; // Patch non-continuous DAC volume
MIXSTRUCT DAC={2,0,0}; // Released initially
MIXSTRUCT ThreeD={6,0,0}; // Space supported, Center supported
MIXSTRUCT Master={0,100,100};
int MasterOn=FALSE; // Enable master volume control
/* Volume map, mixer -> driver */
const int VolFMap[]={0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,4,4,4,4,4,4,5,5,6,
9,1,1,12,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,
3,17,17,17,17,17,17,17,17,17,
17,17,17,17,17,17,17,15,15,20,
20,24,25,25,26,28,28,29,29,40,
43,43,46,48,48,50,50,50,50,50,
50};
/* Volume map, driver -> mixer */
const int VolRMap[]={26,42,42,45,35,37,39,39,39,40,
40,42,43,43,45,78,78,76,76,78,
79,79,79,79,81,82,84,84,85,87,
87,84,84,84,85,85,85,85,87,87,
89,89,89,90,90,90,92,92,93,93,
95,95,76,78,78,79,79,76,79,81,
82,84,85,87,87,87,87,87,87,87,
87,87,87,87,87,87,87,87,87,87,
87,87,87,87,87,87,87,87,87,87,
87,87,87,87,87,87,87,87,87,87,
87};
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;
}
// Get hardware state at startup
static int GetState() {
unsigned char t;
MIXSTRUCT MixStruct;
if (DACPatch) {
if (mixerapiIOCTL90(0x6D,&MixStruct,sizeof(MIXSTRUCT))) return FALSE;
Limit100(&DAC);
DAC.VolumeL=VolRMap[DAC.VolumeL];
DAC.VolumeR=VolRMap[DAC.VolumeR];
}
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;
}
return TRUE;
}
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);
}
// 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],"-c")) {
i++;
if (i==argc) return FALSE; // Syntax error
BaseCPort=strtoul(argv[i],NULL,16)&0xFFFF;
}
else if (!stricmp(argv[i],"-dac")) DACPatch=TRUE;
else if (!stricmp(argv[i],"-mv")) MasterOn=TRUE;
else return FALSE; // Syntax error
}
if (mixerapiInit(NULL)) return FALSE;
if (mixerapiIOCTL90(GETAPIMAP,ApiMap,256)) return FALSE;
if (mixerapiIOCTL90(APILEVELQUERY,&Level,sizeof(ULONG))) return FALSE;
if (Level<2) {
fprintf(stderr,"Drivers v.2.09+ are expected.\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);
}
if (BaseCPort&&ApiMap[0x4C]&&ApiMap[0x6C]) {
printf("WARNING: 3D processing is supported by the driver.");
BaseCPort=0;
}
if (!GetState()) return FALSE;
ApiLevel=2;
if (Debug) printf("Device: %s, API Level: %d\nDriver Info: \n%s\n",
szPddName,ApiLevel,InfoBuf);
return TRUE;
}
// Deinitialize mixer
void MixerClose() {
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 0x4C: // 3D
if (BaseCPort) {
ThreeD=MixStruct;
Set3D();
}
else {
strcat(Buff,REP_UNSUPPORTED);
return TRUE;
}
break;
case 0x4D: // DAC
if (DACPatch) {
DAC=MixStruct;
Limit100(&MixStruct);
MixStruct.VolumeL=VolFMap[MixStruct.VolumeL];
MixStruct.VolumeR=VolFMap[MixStruct.VolumeR];
}
default:
if (ApiMap[cmd]) {
if (mixerapiIOCTL90(cmd,&MixStruct,sizeof(MIXSTRUCT))) {
strcat(Buff,REP_FAILED);
return TRUE;
}
}
else {
strcat(Buff,REP_UNSUPPORTED);
return TRUE;
}
}
strcat(Buff,REP_OK);
}
else if ((cmd&0xF0)==0x60) { // Query command
switch(cmd) {
case 0x6C: // 3D
if (BaseCPort) {
MixStruct=ThreeD;
MixStruct.Mute|=6; // Space supported, Center supported
}
else {
strcat(Buff,REP_UNSUPPORTED);
return TRUE;
}
break;
case 0x6D: // DAC
if (DACPatch) {
MixStruct=DAC;
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;
}