1 // mixctl.h - MixCtl class provides control of audio mixer functions
2 // 05/09/98  Release 1.0 Beta1
3 // Copyright (C) 1998  Sam Hawker <shawkie@geocities.com>
4 // This software comes with ABSOLUTELY NO WARRANTY
5 // This software is free software, and you are welcome to redistribute it
6 // under certain conditions
7 // See the COPYING file for details.
8 
9 // Although mixctl.h is an integral part of wmmixer, it may also be distributed seperately.
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <sys/ioctl.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <unistd.h>
18 #ifdef __NetBSD__
19 #include <soundcard.h>
20 #endif
21 #ifdef __FreeBSD__
22 #include <sys/soundcard.h>
23 #endif
24 #ifdef __linux__
25 #include <linux/soundcard.h>
26 #endif
27 
28 class MixCtl
29 {
30 public:
MixCtl(char * dname)31    MixCtl(char *dname){
32       device=(char *)malloc(sizeof(char)*(strlen(dname)+1));
33       strcpy(device,dname);
34       if(mixfdopen=(mixfd=open(device,O_RDONLY | O_NONBLOCK))!=-1){
35          nrdevices=SOUND_MIXER_NRDEVICES;
36          char *devnames[]=SOUND_DEVICE_NAMES;
37          char *devlabels[]=SOUND_DEVICE_LABELS;
38          ioctl(mixfd, SOUND_MIXER_READ_DEVMASK, &devmask);
39          ioctl(mixfd, SOUND_MIXER_READ_STEREODEVS, &stmask);
40          ioctl(mixfd, SOUND_MIXER_READ_RECMASK, &recmask);
41          ioctl(mixfd, SOUND_MIXER_READ_CAPS, &caps);
42          mixdevs=(struct MixDev *)malloc(sizeof(struct MixDev)*nrdevices);
43          int mixmask=1;
44          for(int i=0;i<nrdevices;i++){
45             mixdevs[i].support=devmask & mixmask;
46             mixdevs[i].stereo=stmask & mixmask;
47             mixdevs[i].records=recmask & mixmask;
48             mixdevs[i].mask=mixmask;
49             mixdevs[i].name=devnames[i];
50             mixdevs[i].label=devlabels[i];
51             mixmask*=2;
52          }
53          doStatus();
54       }
55    }
~MixCtl()56    ~MixCtl(){
57       if(mixfdopen){
58          if(mixdevs!=NULL)
59             free(mixdevs);
60          close(mixfd);
61       }
62    }
openOK()63    bool openOK(){
64       return mixfdopen;
65    }
doStatus()66    void doStatus(){
67       ioctl(mixfd, SOUND_MIXER_READ_RECSRC, &recsrc);
68       for(int i=0;i<nrdevices;i++){
69 	 if(mixdevs[i].support)
70 	    ioctl(mixfd, MIXER_READ(i), &mixdevs[i].value);
71          mixdevs[i].recsrc=(recsrc & mixdevs[i].mask);
72       }
73    }
74 
75    // Return volume for a device, optionally reading it from device first.
76    // Can be used as a way to avoid calling doStatus().
readVol(int dev,bool read)77    int readVol(int dev, bool read){
78       if(read)
79          ioctl(mixfd, MIXER_READ(dev), &mixdevs[dev].value);
80       return mixdevs[dev].value;
81    }
82 
83    // Return left and right componenets of volume for a device.
84    // If you are lazy, you can call readVol to read from the device, then these
85    // to get left and right values.
readLeft(int dev)86    int readLeft(int dev){
87       return mixdevs[dev].value%256;
88    }
readRight(int dev)89    int readRight(int dev){
90       return mixdevs[dev].value/256;
91    }
92 
93    // Write volume to device. Use setVolume, setLeft and setRight first.
writeVol(int dev)94    void writeVol(int dev){
95       ioctl(mixfd, MIXER_WRITE(dev), &mixdevs[dev].value);
96    }
97 
98    // Set volume (or left or right component) for a device. You must call writeVol to write it.
setVol(int dev,int value)99    void setVol(int dev, int value){
100       mixdevs[dev].value=value;
101    }
setBoth(int dev,int l,int r)102    void setBoth(int dev, int l, int r){
103       mixdevs[dev].value=256*r+l;
104    }
setLeft(int dev,int l)105    void setLeft(int dev, int l){
106       int r;
107       if(mixdevs[dev].stereo)
108          r=mixdevs[dev].value/256;
109       else
110          r=l;
111       mixdevs[dev].value=256*r+l;
112    }
setRight(int dev,int r)113    void setRight(int dev, int r){
114       int l;
115       if(mixdevs[dev].stereo)
116          l=mixdevs[dev].value%256;
117       else
118          l=r;
119       mixdevs[dev].value=256*r+l;
120    }
121 
122    // Return record source value for a device, optionally reading it from device first.
readRec(int dev,bool read)123    bool readRec(int dev, bool read){
124       if(read){
125 	 ioctl(mixfd, SOUND_MIXER_READ_RECSRC, &recsrc);
126          mixdevs[dev].recsrc=(recsrc & mixdevs[dev].mask);
127       }
128       return mixdevs[dev].recsrc;
129    }
130 
131    // Write record source values to device. Use setRec first.
writeRec()132    void writeRec(){
133       ioctl(mixfd, SOUND_MIXER_WRITE_RECSRC, &recsrc);
134    }
135 
136    // Make a device (not) a record source.
setRec(int dev,bool rec)137    void setRec(int dev, bool rec){
138       if(rec){
139          if(caps & SOUND_CAP_EXCL_INPUT)
140             recsrc=mixdevs[dev].mask;
141          else
142             recsrc|=mixdevs[dev].mask;
143       }
144       else
145          recsrc&=~mixdevs[dev].mask;
146    }
147 
148    // Return various other info
getDevName()149    char *getDevName(){
150       return device;
151    }
getNrDevices()152    int getNrDevices(){
153       return nrdevices;
154    }
getCapabilities()155    int getCapabilities(){
156       return caps;
157    }
getSupport(int dev)158    bool getSupport(int dev){
159       return mixdevs[dev].support;
160    }
getStereo(int dev)161    bool getStereo(int dev){
162       return mixdevs[dev].stereo;
163    }
getRecords(int dev)164    bool getRecords(int dev){
165       return mixdevs[dev].records;
166    }
getName(int dev)167    char *getName(int dev){
168       return mixdevs[dev].name;
169    }
getLabel(int dev)170    char *getLabel(int dev){
171       return mixdevs[dev].label;
172    }
173 
174 private:
175    int mixfd;
176    int mixfdopen;
177    char *device;
178 
179    struct MixDev{
180       bool support;
181       bool stereo;
182       bool recsrc;
183       bool records;
184       char *name;
185       char *label;
186       int value;
187       int mask;
188    };
189 
190    int nrdevices;       // maximum number of devices
191    int devmask;         // supported devices
192    int stmask;          // stereo devices
193    int recmask;         // devices which can be recorded from
194    int caps;            // capabilities
195    int recsrc;          // devices which are being recorded from
196    struct MixDev *mixdevs;
197 };
198