mirror of
https://github.com/alsa-project/alsa-tools.git
synced 2025-10-29 05:40:25 -04:00
- Bugfix: Makes sure that the "changed" event will be triggered when we will set the right value (the trick of setting an out of range value do not work anymore with gtk+-2.x). - Bugfix: Same as above for toggle buttons. Signed-off-by: Giuliano Pochini <pochini@shiny.it>
2822 lines
97 KiB
C
2822 lines
97 KiB
C
/*
|
||
* ALSA mixer console for Echoaudio soundcards.
|
||
* Copyright (C) 2003 Giuliano Pochini <pochini@shiny.it>
|
||
*
|
||
* 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; version 2 of the License.
|
||
*
|
||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||
*/
|
||
|
||
#define EM_VERSION "%s Echomixer v" VERSION
|
||
|
||
|
||
/*******
|
||
Remove the "//" if you want to compile Echomixer in reverse mode.
|
||
*******/
|
||
|
||
//#define REVERSE
|
||
|
||
|
||
/*******
|
||
Constants marked with *M* can be modified to customize the interface.
|
||
*******/
|
||
|
||
|
||
#define BORDER 6 // *M* Inner border of GTK containers
|
||
#define SPACING 8 // *M* Spacing of control sections
|
||
|
||
// Graphic mixer constants
|
||
#define GM_BARWIDTH 5 // *M* Width of meters bars
|
||
#define XCELLBORDER 2 // *M* Space between the grid lines and the content of the cell
|
||
#define YCELLBORDER 2 // *M*
|
||
#define XCELLDIM 20 // *M* Width of the cell
|
||
#define YCELLDIM 32 // Height of the cell
|
||
#define XCELLTOT (1+XCELLBORDER*2+XCELLDIM) // line + left border + cell + right border
|
||
#define YCELLTOT (1+YCELLBORDER*2+YCELLDIM)
|
||
#define XVOLUME (1+XCELLBORDER+3) // Position of the volume slider
|
||
#define XMETER (1+XCELLBORDER-GM_BARWIDTH/2+13) // Position of the VU bar
|
||
|
||
// VU-meter constants
|
||
#define VU_XGRAF 30 // Left margin of the graphic
|
||
#define VU_YGRAF 20 // Top margin
|
||
#define VU_BARWIDTH 6 // *M* Width of VU-meters bars
|
||
#define VU_BARSEP 2 // *M* Space between bars
|
||
|
||
#define SHORTSTEP 1 // *M* 1dB (when the users moves a slider with cursor keys)
|
||
#define LONGSTEP 6 // *M* 6dB (with Page up/down or clicking the background)
|
||
#define DIGITAL_MODES 16 // Max number of digital modes
|
||
#define ECHO_CLOCKS 8 // Max number of clock sources
|
||
|
||
#define INPUT 0
|
||
#define OUTPUT 1
|
||
#define ECHO_MAXAUDIO_IOS 32 // The maximum number of inputs + outputs
|
||
#define ECHO_MAXAUDIOINPUTS 32 // Max audio input channels
|
||
#define ECHO_MAXAUDIOOUTPUTS 32 // Max audio output channels
|
||
#define ECHOGAIN_MUTED (-128) // Minimum possible gain
|
||
#define ECHOGAIN_MINOUT (-128) // Min output gain (unit is 1dB)
|
||
#define ECHOGAIN_MAXOUT 6 // Max output gain (unit is 1dB)
|
||
#define ECHOGAIN_MININP (-50) // Min input gain (unit is 0.5dB)
|
||
#define ECHOGAIN_MAXINP 50 // Max input gain (unit is 0.5dB)
|
||
|
||
// GTK+ adjustment widgets have the mininum value at top and maximum at bottom,
|
||
// position, but we need the opposite. This function puts the scale upside-down.
|
||
#define INVERT(x) (ECHOGAIN_MINOUT+ECHOGAIN_MAXOUT-(x))
|
||
#define IN_INVERT(x) (ECHOGAIN_MININP+ECHOGAIN_MAXINP-(x))
|
||
|
||
// REAL is for debugging only.
|
||
#define REAL
|
||
|
||
//#define CTLID_DEBUG(x) printf x
|
||
#define CTLID_DEBUG(x)
|
||
|
||
#define UI_DEBUG(x)
|
||
//#define UI_DEBUG(x) printf x
|
||
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <ctype.h>
|
||
#include <gtk/gtk.h>
|
||
#include <gdk/gdk.h>
|
||
#include <alsa/asoundlib.h>
|
||
|
||
|
||
char card[64], cardId[16];
|
||
char dmodeName[DIGITAL_MODES][64], clocksrcName[DIGITAL_MODES][64], spdifmodeName[DIGITAL_MODES][64];
|
||
char NominalIn[ECHO_MAXAUDIOINPUTS], NominalOut[ECHO_MAXAUDIOOUTPUTS];
|
||
int nLOut, nIn, fdIn, fdOut, nPOut, ClockMask;
|
||
int ndmodes, nclocksrc, nspdifmodes;
|
||
int GMixerRow, GMixerColumn, Gang;
|
||
int lineinId, pcmoutId, lineoutId, mixerId, vmixerId, p4InId, p4OutId, dmodeId, clocksrcId, spdifmodeId, vuswitchId, vumetersId, channelsId, phantomId;
|
||
int metersStreams, metersNumber, metersTypes;
|
||
int outvolCount;
|
||
int mouseY, mouseButton;
|
||
int dmodeVal, clocksrcVal, spdifmodeVal;
|
||
int VUwidth, VUheight, Mixwidth, Mixheight;
|
||
|
||
#define DONT_DRAW (ECHOGAIN_MUTED-1)
|
||
#define NOPOS 999999
|
||
struct geometry {
|
||
int st; // window status: 0 = hidden ; 1 = visible ; NOPOS = no stored setting
|
||
GtkWidget *toggler; // The toggle button that controls this window
|
||
int x, y;
|
||
int w, h;
|
||
} Mainw_geom, Miscw_geom, PVw_geom, LVw_geom, Mixerw_geom, Vmixerw_geom, VUw_geom, GMw_geom;
|
||
|
||
// This structure contains the first and the last row of each section of the graphic mixer window
|
||
struct {
|
||
int Monitor; // The first is always 0
|
||
int VmixerFirst, VmixerLast;
|
||
int LineOut; // There is only one row
|
||
} GMixerSection;
|
||
|
||
struct mixel {
|
||
int id;
|
||
int Gain;
|
||
};
|
||
|
||
snd_ctl_t *ctlhandle;
|
||
|
||
|
||
#if __GNUC__ == 3 // gcc 2.x doesn't like unnamed unions inside structures
|
||
|
||
struct mixerControl_s {
|
||
union { // Currently selected channels
|
||
int vchannel;
|
||
int input;
|
||
};
|
||
union { // Number of channels
|
||
int vchannels;
|
||
int inputs;
|
||
};
|
||
int output, outputs;
|
||
int id;
|
||
GtkWidget *window;
|
||
GtkWidget *volume[ECHO_MAXAUDIOOUTPUTS];
|
||
GtkWidget *label[ECHO_MAXAUDIOOUTPUTS];
|
||
GtkObject *adj[ECHO_MAXAUDIOOUTPUTS];
|
||
GtkWidget *outsel[ECHO_MAXAUDIOOUTPUTS];
|
||
union {
|
||
GtkWidget *inpsel[ECHO_MAXAUDIOINPUTS];
|
||
GtkWidget *vchsel[ECHO_MAXAUDIOOUTPUTS];
|
||
};
|
||
struct mixel mixer[ECHO_MAXAUDIOOUTPUTS][ECHO_MAXAUDIOOUTPUTS];
|
||
} mixerControl, vmixerControl;
|
||
|
||
#else
|
||
|
||
struct mixerControl_s {
|
||
int vchannel;
|
||
int input;
|
||
int vchannels;
|
||
int inputs;
|
||
int output, outputs;
|
||
int id;
|
||
GtkWidget *window;
|
||
GtkWidget *volume[ECHO_MAXAUDIOOUTPUTS];
|
||
GtkWidget *label[ECHO_MAXAUDIOOUTPUTS];
|
||
GtkObject *adj[ECHO_MAXAUDIOOUTPUTS];
|
||
GtkWidget *outsel[ECHO_MAXAUDIOOUTPUTS];
|
||
GtkWidget *inpsel[ECHO_MAXAUDIOINPUTS];
|
||
GtkWidget *vchsel[ECHO_MAXAUDIOOUTPUTS];
|
||
struct mixel mixer[ECHO_MAXAUDIOOUTPUTS][ECHO_MAXAUDIOOUTPUTS];
|
||
} mixerControl, vmixerControl;
|
||
|
||
#endif
|
||
|
||
|
||
struct VolumeControl {
|
||
int input, output; // Currently selected channels
|
||
int inputs, outputs;
|
||
int id;
|
||
GtkWidget *window;
|
||
GtkWidget *volume[ECHO_MAXAUDIOOUTPUTS];
|
||
GtkWidget *label[ECHO_MAXAUDIOOUTPUTS];
|
||
GtkObject *adj[ECHO_MAXAUDIOOUTPUTS];
|
||
int Gain[ECHO_MAXAUDIOOUTPUTS];
|
||
} lineinControl, lineoutControl, pcmoutControl;
|
||
|
||
GtkWidget *p4dbuOut[ECHO_MAXAUDIOOUTPUTS], *p4dbuIn[ECHO_MAXAUDIOINPUTS]; // +4dBu/-10dBV toggles
|
||
GtkWidget *clocksrc_menuitem[ECHO_CLOCKS];
|
||
GtkWidget *dmodeOpt, *clocksrcOpt, *spdifmodeOpt, *phantomToggle;
|
||
GtkWidget *window, *Mainwindow, *Miscwindow, *LVwindow, *VUwindow, *GMwindow;
|
||
GtkWidget *VUdarea, *Mixdarea;
|
||
gint VUtimer, Mixtimer, clocksrctimer;
|
||
|
||
GdkGC *gc=0;
|
||
static GdkPixmap *VUpixmap = NULL;
|
||
static GdkPixmap *Mixpixmap = NULL;
|
||
GdkFont *fnt;
|
||
|
||
|
||
int CountBits(int n) {
|
||
int c;
|
||
|
||
c=0;
|
||
while (n) {
|
||
c++;
|
||
n&=(n-1);
|
||
}
|
||
return(c);
|
||
}
|
||
|
||
|
||
|
||
void ClampOutputVolume(int *v) {
|
||
|
||
if (*v>ECHOGAIN_MAXOUT)
|
||
*v=ECHOGAIN_MAXOUT;
|
||
else if (*v<ECHOGAIN_MINOUT)
|
||
*v=ECHOGAIN_MINOUT;
|
||
}
|
||
|
||
|
||
|
||
void ClampInputVolume(int *v) {
|
||
|
||
if (*v>ECHOGAIN_MAXINP)
|
||
*v=ECHOGAIN_MAXINP;
|
||
else if (*v<ECHOGAIN_MININP)
|
||
*v=ECHOGAIN_MININP;
|
||
}
|
||
|
||
|
||
|
||
// -128 dB means muted, that is -infinite dB
|
||
int Add_dB (int a, int b) {
|
||
|
||
if (a==ECHOGAIN_MINOUT || b==ECHOGAIN_MINOUT)
|
||
return(ECHOGAIN_MINOUT);
|
||
a+=b;
|
||
if (a<ECHOGAIN_MINOUT)
|
||
return(ECHOGAIN_MINOUT);
|
||
return(a);
|
||
}
|
||
|
||
|
||
|
||
char *strOutGain(char *s, int g) {
|
||
|
||
if (g==ECHOGAIN_MINOUT)
|
||
strcpy(s, "mute");
|
||
else
|
||
sprintf(s, "%+d", g);
|
||
return(s);
|
||
}
|
||
|
||
|
||
|
||
int ADATmode() {
|
||
return(!memcmp(dmodeName[dmodeVal], "ADAT", 4));
|
||
}
|
||
|
||
|
||
|
||
// Write an enumerated ALSA control
|
||
int SetEnum(int numid, int val) {
|
||
int err;
|
||
snd_ctl_elem_id_t *id;
|
||
snd_ctl_elem_value_t *control;
|
||
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_value_alloca(&control);
|
||
snd_ctl_elem_id_set_interface(id, numid==clocksrcId ? SND_CTL_ELEM_IFACE_PCM : SND_CTL_ELEM_IFACE_CARD);
|
||
snd_ctl_elem_id_set_numid(id, numid);
|
||
snd_ctl_elem_value_set_id(control, id);
|
||
snd_ctl_elem_value_set_enumerated(control, 0, val);
|
||
if ((err=snd_ctl_elem_write(ctlhandle, control)) < 0)
|
||
printf("Control %s element write error: %s\n", card, snd_strerror(err));
|
||
return(err);
|
||
}
|
||
|
||
|
||
|
||
// Read an enumerated ALSA control
|
||
int GetEnum(int numid) {
|
||
int err, val;
|
||
snd_ctl_elem_id_t *id;
|
||
snd_ctl_elem_value_t *control;
|
||
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_value_alloca(&control);
|
||
snd_ctl_elem_id_set_interface(id, numid==clocksrcId ? SND_CTL_ELEM_IFACE_PCM : SND_CTL_ELEM_IFACE_CARD);
|
||
snd_ctl_elem_id_set_numid(id, numid);
|
||
snd_ctl_elem_value_set_id(control, id);
|
||
if ((err=snd_ctl_elem_read(ctlhandle, control)) < 0)
|
||
printf("Control %s element read error: %s\n", card, snd_strerror(err));
|
||
val=snd_ctl_elem_value_get_enumerated(control, 0);
|
||
return(val);
|
||
}
|
||
|
||
|
||
|
||
// Turn VU-meters on/off
|
||
void SetVUmeters(int onoff) {
|
||
static signed char oncount=0;
|
||
int err;
|
||
snd_ctl_elem_id_t *id;
|
||
snd_ctl_elem_value_t *control;
|
||
|
||
if (onoff)
|
||
oncount++;
|
||
else
|
||
if (--oncount<0)
|
||
oncount=0;
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_value_alloca(&control);
|
||
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_CARD);
|
||
snd_ctl_elem_id_set_numid(id, vuswitchId);
|
||
snd_ctl_elem_value_set_id(control, id);
|
||
snd_ctl_elem_value_set_integer(control, 0, !!oncount);
|
||
if ((err=snd_ctl_elem_write(ctlhandle, control)) < 0) {
|
||
printf("Control %s element write error: %s\n", card, snd_strerror(err));
|
||
}
|
||
}
|
||
|
||
|
||
|
||
void GetVUmeters(int *InLevel, int *InPeak, int *OutLevel, int *OutPeak, int *VirLevel, int *VirPeak) {
|
||
int err, i, m;
|
||
snd_ctl_elem_id_t *id;
|
||
snd_ctl_elem_value_t *control;
|
||
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_value_alloca(&control);
|
||
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
|
||
snd_ctl_elem_id_set_numid(id, vumetersId);
|
||
snd_ctl_elem_value_set_id(control, id);
|
||
if ((err = snd_ctl_elem_read(ctlhandle, control)) < 0) {
|
||
printf("Control %s element read error: %s\n", card, snd_strerror(err));
|
||
return;
|
||
}
|
||
|
||
m=0;
|
||
for (i=0; i<nLOut; i++) {
|
||
OutLevel[i]=snd_ctl_elem_value_get_integer(control, m++);
|
||
OutPeak[i]=snd_ctl_elem_value_get_integer(control, m++);
|
||
}
|
||
|
||
m=1*metersNumber*metersTypes;
|
||
for (i=0; i<nIn; i++) {
|
||
InLevel[i]=snd_ctl_elem_value_get_integer(control, m++);
|
||
InPeak[i]=snd_ctl_elem_value_get_integer(control, m++);
|
||
}
|
||
|
||
if (metersStreams==3) { // Has PCM levels (Mia only) ?
|
||
m=2*metersNumber*metersTypes;
|
||
#ifdef REAL
|
||
for (i=0; i<nPOut; i++) {
|
||
VirLevel[i]=snd_ctl_elem_value_get_integer(control, m++);
|
||
VirPeak[i]=snd_ctl_elem_value_get_integer(control, m++);
|
||
}
|
||
#else
|
||
for (i=0; i<nPOut; i++) {
|
||
VirLevel[i]=i*5-100;
|
||
VirPeak[i]=i*5-90;
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
|
||
|
||
|
||
#ifdef REVERSE
|
||
|
||
// Enable/disable widgets that control ADAT digital channels
|
||
void SetSensitivity(int enable) {
|
||
int i;
|
||
|
||
for (i=fdOut+2; i<nLOut; i++) {
|
||
if (!enable && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mixerControl.outsel[i])))
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mixerControl.outsel[0]), TRUE);
|
||
if (mixerId)
|
||
gtk_widget_set_sensitive(mixerControl.outsel[i], enable);
|
||
if (vmixerId) {
|
||
if (!enable && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(vmixerControl.outsel[i])))
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(vmixerControl.outsel[0]), TRUE);
|
||
gtk_widget_set_sensitive(vmixerControl.outsel[i], enable);
|
||
}
|
||
if (pcmoutId) {
|
||
gtk_widget_set_sensitive(pcmoutControl.label[i], enable);
|
||
gtk_widget_set_sensitive(pcmoutControl.volume[i], enable);
|
||
}
|
||
// Line-out control is always present
|
||
gtk_widget_set_sensitive(lineoutControl.label[i], enable);
|
||
gtk_widget_set_sensitive(lineoutControl.volume[i], enable);
|
||
}
|
||
for (i=fdIn+2; i<nIn; i++) {
|
||
gtk_widget_set_sensitive(mixerControl.label[i], enable);
|
||
gtk_widget_set_sensitive(mixerControl.volume[i], enable);
|
||
}
|
||
if (!enable && mixerControl.input>=fdIn+2)
|
||
mixerControl.input=0;
|
||
}
|
||
|
||
#else // REVERSE
|
||
|
||
// Enable/disable widgets that control ADAT digital channels
|
||
void SetSensitivity(int enable) {
|
||
int i;
|
||
|
||
for (i=fdIn+2; i<nIn; i++) {
|
||
if (!enable && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mixerControl.inpsel[i])))
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mixerControl.inpsel[0]), TRUE);
|
||
gtk_widget_set_sensitive(mixerControl.inpsel[i], enable);
|
||
}
|
||
for (i=fdOut+2; i<nLOut; i++) {
|
||
if (mixerId) {
|
||
gtk_widget_set_sensitive(mixerControl.label[i], enable);
|
||
gtk_widget_set_sensitive(mixerControl.volume[i], enable);
|
||
}
|
||
if (vmixerId) {
|
||
gtk_widget_set_sensitive(vmixerControl.label[i], enable);
|
||
gtk_widget_set_sensitive(vmixerControl.volume[i], enable);
|
||
}
|
||
if (pcmoutId) {
|
||
gtk_widget_set_sensitive(pcmoutControl.label[i], enable);
|
||
gtk_widget_set_sensitive(pcmoutControl.volume[i], enable);
|
||
}
|
||
// Line-out control is always present
|
||
gtk_widget_set_sensitive(lineoutControl.label[i], enable);
|
||
gtk_widget_set_sensitive(lineoutControl.volume[i], enable);
|
||
}
|
||
if (!enable && mixerControl.output>=fdOut+2)
|
||
mixerControl.output=0;
|
||
if (vmixerId && !enable && vmixerControl.output>=fdOut+2)
|
||
vmixerControl.output=0;
|
||
}
|
||
|
||
#endif // REVERSE
|
||
|
||
|
||
|
||
// At startup this functions reads if the dithering is enabled sets the button accordingly.
|
||
void InitPhantomPowerGUI(int numid) {
|
||
snd_ctl_elem_id_t *id;
|
||
snd_ctl_elem_value_t *control;
|
||
int err;
|
||
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_value_alloca(&control);
|
||
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_CARD);
|
||
snd_ctl_elem_id_set_numid(id, phantomId);
|
||
snd_ctl_elem_value_set_id(control, id);
|
||
if ((err=snd_ctl_elem_read(ctlhandle, control))<0)
|
||
printf("Control %s element read error: %s\n", card, snd_strerror(err));
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(phantomToggle), snd_ctl_elem_value_get_integer(control, 0));
|
||
}
|
||
|
||
|
||
|
||
// Read current control settings.
|
||
void ReadControl(int *vol, int channels, int volId) {
|
||
snd_ctl_elem_id_t *id;
|
||
snd_ctl_elem_value_t *control;
|
||
int err, ch;
|
||
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_value_alloca(&control);
|
||
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
|
||
snd_ctl_elem_id_set_numid(id, volId);
|
||
snd_ctl_elem_value_set_id(control, id);
|
||
if ((err=snd_ctl_elem_read(ctlhandle, control))<0) {
|
||
printf("Control %s element read error: %s\n", card, snd_strerror(err));
|
||
return;
|
||
}
|
||
|
||
for (ch=0; ch<channels; ch++)
|
||
vol[ch]=snd_ctl_elem_value_get_integer(control, ch);
|
||
}
|
||
|
||
|
||
|
||
void ReadNominalLevels(char *NominalLevel, int numid) {
|
||
snd_ctl_elem_id_t *id;
|
||
snd_ctl_elem_value_t *control;
|
||
int err, i, n;
|
||
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_value_alloca(&control);
|
||
|
||
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
|
||
n=(numid==p4InId) ? fdIn : fdOut;
|
||
snd_ctl_elem_id_set_numid(id, numid);
|
||
snd_ctl_elem_value_set_id(control, id);
|
||
if ((err=snd_ctl_elem_read(ctlhandle, control))<0)
|
||
printf("Control %s element read error: %s\n", card, snd_strerror(err));
|
||
for (i=0; i<n; i++)
|
||
NominalLevel[i]=snd_ctl_elem_value_get_integer(control, i);
|
||
}
|
||
|
||
|
||
|
||
int SetMixerGain(struct mixel *mxl, int Gain) {
|
||
snd_ctl_elem_id_t *id;
|
||
snd_ctl_elem_value_t *control;
|
||
int err;
|
||
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_value_alloca(&control);
|
||
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
|
||
snd_ctl_elem_id_set_numid(id, mxl->id);
|
||
snd_ctl_elem_value_set_id(control, id);
|
||
snd_ctl_elem_value_set_integer(control, 0, Gain);
|
||
if ((err = snd_ctl_elem_write(ctlhandle, control)) < 0) {
|
||
printf("Control %s element write error: %s\n", card, snd_strerror(err));
|
||
return(err);
|
||
}
|
||
return(0);
|
||
}
|
||
|
||
|
||
|
||
// Read current (v)mixer settings.
|
||
void ReadMixer(struct mixerControl_s *mixer) {
|
||
int err, in, out;
|
||
snd_ctl_elem_id_t *id;
|
||
snd_ctl_elem_value_t *control;
|
||
|
||
#ifndef REAL
|
||
return;
|
||
#endif
|
||
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_value_alloca(&control);
|
||
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
|
||
|
||
for (out=0; out<mixer->outputs; out++) {
|
||
for (in=0; in<mixer->inputs; in++) {
|
||
snd_ctl_elem_id_set_numid(id, mixer->mixer[out][in].id);
|
||
snd_ctl_elem_value_set_id(control, id);
|
||
if ((err=snd_ctl_elem_read(ctlhandle, control))<0)
|
||
printf("InitMixer - Control %s element read error: %s\n", card, snd_strerror(err));
|
||
mixer->mixer[out][in].Gain=snd_ctl_elem_value_get_integer(control, 0);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
void GetChannels(void) {
|
||
snd_ctl_elem_id_t *id;
|
||
snd_ctl_elem_value_t *control;
|
||
int err;
|
||
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_value_alloca(&control);
|
||
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_HWDEP);
|
||
snd_ctl_elem_id_set_numid(id, channelsId);
|
||
snd_ctl_elem_value_set_id(control, id);
|
||
if ((err = snd_ctl_elem_read(ctlhandle, control)) < 0) {
|
||
printf("GetChannels() read error: %s\n", snd_strerror(err));
|
||
exit(1);
|
||
}
|
||
if (!nIn) { // Only read the first time (mainly for debugging, see #define REAL)
|
||
nIn=snd_ctl_elem_value_get_integer(control, 0); // Number of input channels
|
||
fdIn=snd_ctl_elem_value_get_integer(control, 1); // First digital in (= number of analog input channels)
|
||
nLOut=snd_ctl_elem_value_get_integer(control, 2); // Number of output channels
|
||
fdOut=snd_ctl_elem_value_get_integer(control, 3); // First digital out
|
||
nPOut=snd_ctl_elem_value_get_integer(control, 4); // Number of virtual output channels (==nLOut on non-vmixer cards)
|
||
}
|
||
ClockMask=snd_ctl_elem_value_get_integer(control, 5); // Bitmask of available input clocks
|
||
}
|
||
|
||
|
||
|
||
// Read what input clocks are valid and (de)activate the pop-down menu items accordingly
|
||
gint CheckInputs(gpointer unused) {
|
||
int i;
|
||
|
||
GetChannels();
|
||
for (i=0; i<nclocksrc; i++)
|
||
gtk_widget_set_sensitive(clocksrc_menuitem[i], !!(ClockMask & (1<<i)));
|
||
return(TRUE);
|
||
}
|
||
|
||
|
||
|
||
void DrawBar(int x, int y, int level, int peak, int gain) {
|
||
GdkColor Bars={0x00FF00, 0, 0, 0};
|
||
GdkColor Bars1={0x000000, 0, 0, 0};
|
||
GdkColor Peak={0x1BABFF, 0, 0, 0};
|
||
GdkColor Level={0xC0B000, 0, 0, 0};
|
||
int db;
|
||
|
||
x=XMETER+XCELLTOT*x;
|
||
y=YCELLTOT*y+YCELLBORDER;
|
||
|
||
if (level>ECHOGAIN_MUTED) {
|
||
// Draw the "integer" part of the bar
|
||
db=level>>2;
|
||
gdk_gc_set_foreground(gc, &Bars);
|
||
gdk_draw_rectangle(Mixpixmap, gc, TRUE, x, y-db, GM_BARWIDTH, YCELLDIM+db);
|
||
|
||
// Draw the antialiased part
|
||
Bars1.pixel=(level&3) << (6 + 8); // 4 levels (256/4==64==2^6) of green (2^8)
|
||
if (Bars1.pixel) {
|
||
gdk_gc_set_foreground(gc, &Bars1);
|
||
gdk_draw_rectangle(Mixpixmap, gc, TRUE, x, y-db-1, GM_BARWIDTH, 1);
|
||
}
|
||
}
|
||
|
||
// Draw the peak
|
||
if (peak>ECHOGAIN_MUTED) {
|
||
db=peak>>2;
|
||
gdk_gc_set_foreground(gc, &Peak);
|
||
gdk_draw_rectangle(Mixpixmap, gc, TRUE, x, y-db, GM_BARWIDTH, 1);
|
||
}
|
||
|
||
// Draw the mixer gain
|
||
if (gain>=ECHOGAIN_MUTED) {
|
||
db=gain>>2;
|
||
gdk_gc_set_foreground(gc, &Level);
|
||
gdk_draw_rectangle(Mixpixmap, gc, TRUE, x-XMETER+XVOLUME, y, 1, YCELLDIM);
|
||
gdk_draw_rectangle(Mixpixmap, gc, TRUE, x-XMETER+XVOLUME-2, y-db, 5, 1);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
// Draw the matrix mixer
|
||
gint DrawMixer(gpointer unused) {
|
||
GdkRectangle update_rect;
|
||
int InLevel[ECHO_MAXAUDIOINPUTS];
|
||
int InPeak[ECHO_MAXAUDIOINPUTS];
|
||
int OutLevel[ECHO_MAXAUDIOOUTPUTS];
|
||
int OutPeak[ECHO_MAXAUDIOOUTPUTS];
|
||
int VirLevel[ECHO_MAXAUDIOOUTPUTS];
|
||
int VirPeak[ECHO_MAXAUDIOOUTPUTS];
|
||
static int InClip[ECHO_MAXAUDIOINPUTS];
|
||
static int OutClip[ECHO_MAXAUDIOOUTPUTS];
|
||
char str[8];
|
||
int i, o, dB, inchannels, outchannels;
|
||
GdkColor Grid={0x787878, 0, 0, 0};
|
||
GdkColor Labels={0x9694C4, 0, 0, 0};
|
||
GdkColor Hilight={0x000078, 0, 0, 0};
|
||
GdkColor Hilight2={0x600000, 0, 0, 0};
|
||
|
||
if (ADATmode()) {
|
||
inchannels=nIn;
|
||
outchannels=nLOut;
|
||
} else {
|
||
inchannels=fdIn+2;
|
||
outchannels=fdOut+2;
|
||
}
|
||
|
||
if (!Mixpixmap)
|
||
return(TRUE);
|
||
|
||
update_rect.x = 0;
|
||
update_rect.y = 0;
|
||
update_rect.width = Mixwidth;
|
||
update_rect.height = Mixheight;
|
||
GetVUmeters(InLevel, InPeak, OutLevel, OutPeak, VirLevel, VirPeak);
|
||
|
||
if (!gc) {
|
||
gc=gdk_gc_new(gtk_widget_get_parent_window(Mixdarea));
|
||
for (i=0; i<nIn; i++)
|
||
InClip[i]=0;
|
||
for (i=0; i<nLOut; i++)
|
||
OutClip[i]=0;
|
||
}
|
||
|
||
gdk_draw_rectangle(Mixpixmap, Mixdarea->style->black_gc, TRUE, 0, 0, Mixwidth, Mixheight);
|
||
|
||
// Highlight
|
||
gdk_gc_set_foreground(gc, &Hilight);
|
||
gdk_draw_rectangle(Mixpixmap, gc, TRUE, 0, YCELLTOT*mixerControl.input, XCELLTOT*(mixerControl.output+1), YCELLTOT);
|
||
gdk_draw_rectangle(Mixpixmap, gc, TRUE, XCELLTOT*(mixerControl.output+1), YCELLTOT*mixerControl.input, XCELLTOT, Mixheight);
|
||
if (vmixerId) {
|
||
gdk_gc_set_foreground(gc, &Hilight2);
|
||
gdk_draw_rectangle(Mixpixmap, gc, TRUE, 0, YCELLTOT*(GMixerSection.VmixerFirst+vmixerControl.vchannel), XCELLTOT*(vmixerControl.output+1), YCELLTOT);
|
||
gdk_draw_rectangle(Mixpixmap, gc, TRUE, XCELLTOT*(vmixerControl.output+1), YCELLTOT*(GMixerSection.VmixerFirst+vmixerControl.vchannel), XCELLTOT, Mixheight);
|
||
}
|
||
|
||
// Draw the grid
|
||
|
||
gdk_gc_set_font(gc, fnt);
|
||
// Horizontal lines and input channel labels
|
||
for (i=0; i<GMixerSection.LineOut; i++) {
|
||
gdk_gc_set_foreground(gc, &Grid);
|
||
gdk_draw_rectangle(Mixpixmap, gc, TRUE, 0, YCELLTOT*(i+1)-1, Mixwidth, 1);
|
||
if (i<fdIn)
|
||
sprintf(str, "A%d", i); // Analog
|
||
else if (i<nIn)
|
||
sprintf(str, "D%d", i-fdIn); // Digital
|
||
else
|
||
sprintf(str, "V%d", i-nIn); // Virtual
|
||
gdk_gc_set_foreground(gc, &Labels);
|
||
gdk_draw_string(Mixpixmap, fnt, gc, 1, YCELLTOT*i+(YCELLTOT/2)+4, str);
|
||
}
|
||
|
||
// Vertical lines and output channel labels
|
||
for (o=0; o<nLOut; o++) {
|
||
gdk_gc_set_foreground(gc, &Grid);
|
||
gdk_draw_rectangle(Mixpixmap, gc, TRUE, XCELLTOT*(o+1), 0, 1, Mixheight);
|
||
if (o<fdOut)
|
||
sprintf(str, "A%d", o);
|
||
else
|
||
sprintf(str, "D%d", o-fdOut);
|
||
gdk_gc_set_foreground(gc, &Labels);
|
||
gdk_draw_string(Mixpixmap, fnt, gc, XCELLTOT*(o+1)+(XCELLTOT/2)-6, YCELLTOT*GMixerSection.LineOut+YCELLTOT+8, str);
|
||
}
|
||
gdk_draw_string(Mixpixmap, fnt, gc, 1, 8, "In");
|
||
gdk_draw_string(Mixpixmap, fnt, gc, 1, YCELLTOT*GMixerSection.LineOut+YCELLTOT+8, "Out");
|
||
gdk_gc_set_foreground(gc, &Grid);
|
||
gdk_draw_rectangle(Mixpixmap, gc, TRUE, 0, YCELLTOT*(GMixerSection.LineOut+1)-1, Mixwidth, 1);
|
||
|
||
// Draw input levels and peaks
|
||
for (i=0; i<inchannels; i++)
|
||
DrawBar(0, i, InLevel[i], InPeak[i], DONT_DRAW);
|
||
|
||
// Draw vchannels levels and peaks (Vmixer cards only)
|
||
if (vmixerId) {
|
||
for (i=0; i<vmixerControl.vchannels; i++)
|
||
DrawBar(0, i+GMixerSection.VmixerFirst, VirLevel[i], VirPeak[i], DONT_DRAW);
|
||
}
|
||
|
||
// Draw output levels, peaks and volumes
|
||
for (o=0; o<outchannels; o++)
|
||
DrawBar(o+1, GMixerSection.LineOut, OutLevel[o], OutPeak[o], lineoutControl.Gain[o]);
|
||
|
||
// Draw monitor mixer elements
|
||
for (o=0; o<outchannels; o++) {
|
||
for (i=0; i<inchannels; i++) {
|
||
dB=Add_dB(mixerControl.mixer[o][i].Gain, InLevel[i]);
|
||
DrawBar(o+1, i, dB, DONT_DRAW, mixerControl.mixer[o][i].Gain);
|
||
}
|
||
}
|
||
|
||
// Draw vmixer elements (Vmixer cards only)
|
||
if (vmixerId) {
|
||
for (o=0; o<outchannels; o++)
|
||
for (i=0; i<vmixerControl.vchannels; i++)
|
||
DrawBar(o+1, i+GMixerSection.VmixerFirst, VirLevel[i], DONT_DRAW, vmixerControl.mixer[o][i].Gain);
|
||
}
|
||
|
||
gtk_widget_draw(Mixdarea, &update_rect);
|
||
return(TRUE);
|
||
}
|
||
|
||
|
||
|
||
// Draw the VU-meter
|
||
gint DrawVUmeters(gpointer unused) {
|
||
GdkRectangle update_rect;
|
||
int InLevel[ECHO_MAXAUDIOINPUTS];
|
||
int InPeak[ECHO_MAXAUDIOINPUTS];
|
||
int OutLevel[ECHO_MAXAUDIOOUTPUTS];
|
||
int OutPeak[ECHO_MAXAUDIOOUTPUTS];
|
||
int VirLevel[ECHO_MAXAUDIOOUTPUTS];
|
||
int VirPeak[ECHO_MAXAUDIOOUTPUTS];
|
||
static int InClip[ECHO_MAXAUDIOINPUTS];
|
||
static int OutClip[ECHO_MAXAUDIOOUTPUTS];
|
||
int i, x, dB;
|
||
char str[16];
|
||
GdkColor Selected={0xC86060, 0, 0, 0};
|
||
GdkColor Grid={0x9694C4, 0, 0, 0};
|
||
GdkColor Grid2={0x646383, 0, 0, 0};
|
||
GdkColor dBValues={0x00B000, 0, 0, 0};
|
||
GdkColor AnBars={0x00E0B8, 0, 0, 0};
|
||
GdkColor DiBars={0x98E000, 0, 0, 0};
|
||
GdkColor ClipPeak={0, 0, 0, 0};
|
||
GdkColor Peak={0x00FF00, 0, 0, 0};
|
||
|
||
if (!VUpixmap)
|
||
return(TRUE);
|
||
|
||
update_rect.x = 0;
|
||
update_rect.y = 0;
|
||
update_rect.width = VUwidth;
|
||
update_rect.height = VUheight;
|
||
GetVUmeters(InLevel, InPeak, OutLevel, OutPeak, VirLevel, VirPeak);
|
||
|
||
if (!gc) {
|
||
gc=gdk_gc_new(gtk_widget_get_parent_window(VUdarea));
|
||
for (i=0; i<nIn; i++)
|
||
InClip[i]=0;
|
||
for (i=0; i<nLOut; i++)
|
||
OutClip[i]=0;
|
||
}
|
||
|
||
// Clear the image
|
||
gdk_draw_rectangle(VUpixmap, VUdarea->style->black_gc, TRUE, 0, 0, VUwidth, VUheight);
|
||
|
||
// Draw the dB scale and the grid
|
||
gdk_gc_set_font(gc, fnt);
|
||
gdk_gc_set_foreground(gc, &Peak);
|
||
gdk_draw_string(VUpixmap, fnt, gc, 2, VU_YGRAF-12+4, " dB");
|
||
for (i=0; i<=120; i+=12) {
|
||
sprintf(str, "%4d", -i);
|
||
gdk_gc_set_foreground(gc, &dBValues);
|
||
gdk_draw_string(VUpixmap, fnt, gc, 2, VU_YGRAF+i+4, str);
|
||
gdk_gc_set_foreground(gc, &Grid);
|
||
gdk_draw_rectangle(VUpixmap, gc, TRUE, VU_XGRAF, VU_YGRAF+i, VUwidth-VU_XGRAF, 1);
|
||
}
|
||
gdk_gc_set_foreground(gc, &Grid2);
|
||
gdk_draw_rectangle(VUpixmap, gc, TRUE, VU_XGRAF, VU_YGRAF+128, VUwidth-VU_XGRAF, 1);
|
||
|
||
x=VU_XGRAF+VU_BARSEP;
|
||
|
||
// Draw inputs
|
||
for (i=0; i<nIn; i++) {
|
||
if (i<fdIn)
|
||
gdk_gc_set_foreground(gc, &AnBars);
|
||
else
|
||
gdk_gc_set_foreground(gc, &DiBars);
|
||
dB=InLevel[i];
|
||
gdk_draw_rectangle(VUpixmap, gc, TRUE, x, VU_YGRAF-dB, VU_BARWIDTH, 129+VU_YGRAF-(VU_YGRAF-dB));
|
||
|
||
dB=InPeak[i];
|
||
if (dB==0)
|
||
InClip[i]=64;
|
||
if (InClip[i]) {
|
||
InClip[i]--;
|
||
ClipPeak.pixel=(InClip[i]<<18)+((255-(InClip[i]*3))<<8);
|
||
gdk_gc_set_foreground(gc, &ClipPeak);
|
||
} else {
|
||
gdk_gc_set_foreground(gc, &Peak);
|
||
}
|
||
gdk_draw_rectangle(VUpixmap, gc, TRUE, x, VU_YGRAF-dB, VU_BARWIDTH, 1);
|
||
if (mixerControl.input==i) {
|
||
gdk_gc_set_foreground(gc, &Selected);
|
||
gdk_draw_rectangle(VUpixmap, gc, TRUE, x+1, VU_YGRAF+128+3, VU_BARWIDTH-2, 1);
|
||
gdk_draw_rectangle(VUpixmap, gc, TRUE, x, VU_YGRAF+128+4, VU_BARWIDTH, 1);
|
||
}
|
||
x+=VU_BARWIDTH+VU_BARSEP;
|
||
}
|
||
|
||
// Draw outputs
|
||
x+=VU_BARWIDTH+VU_BARSEP;
|
||
for (i=0; i<nLOut; i++) {
|
||
if (i<fdOut)
|
||
gdk_gc_set_foreground(gc, &AnBars);
|
||
else
|
||
gdk_gc_set_foreground(gc, &DiBars);
|
||
dB=OutLevel[i];
|
||
gdk_draw_rectangle(VUpixmap, gc, TRUE, x, VU_YGRAF-dB, VU_BARWIDTH, 129+VU_YGRAF-(VU_YGRAF-dB));
|
||
|
||
dB=OutPeak[i];
|
||
if (dB==0)
|
||
OutClip[i]=64;
|
||
if (OutClip[i]) {
|
||
OutClip[i]--;
|
||
ClipPeak.pixel=(OutClip[i]<<18)+((255-(OutClip[i]*3))<<8);
|
||
gdk_gc_set_foreground(gc, &ClipPeak);
|
||
} else {
|
||
gdk_gc_set_foreground(gc, &Peak);
|
||
}
|
||
gdk_draw_rectangle(VUpixmap, gc, TRUE, x, VU_YGRAF-dB, VU_BARWIDTH, 1);
|
||
if (mixerControl.output==i) {
|
||
gdk_gc_set_foreground(gc, &Selected);
|
||
gdk_draw_rectangle(VUpixmap, gc, TRUE, x+1, VU_YGRAF+128+3, VU_BARWIDTH-2, 1);
|
||
gdk_draw_rectangle(VUpixmap, gc, TRUE, x, VU_YGRAF+128+4, VU_BARWIDTH, 1);
|
||
}
|
||
x+=VU_BARWIDTH+VU_BARSEP;
|
||
}
|
||
|
||
gtk_widget_draw(VUdarea, &update_rect);
|
||
|
||
return(TRUE);
|
||
}
|
||
|
||
|
||
|
||
///////////////////// GUI events
|
||
|
||
|
||
#ifdef REVERSE
|
||
|
||
void Mixer_Output_selector_clicked(GtkWidget *widget, gpointer och) {
|
||
int ich, val;
|
||
snd_ctl_elem_id_t *id;
|
||
snd_ctl_elem_value_t *control;
|
||
|
||
if (mixerControl.output==(int)och)
|
||
return;
|
||
|
||
mixerControl.output=(int)och;
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_value_alloca(&control);
|
||
|
||
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
|
||
for (ich=0; ich<nIn; ich++) {
|
||
val=INVERT(mixerControl.mixer[mixerControl.output][ich].Gain);
|
||
gtk_adjustment_set_value(GTK_ADJUSTMENT(mixerControl.adj[ich]), (gfloat)val);
|
||
}
|
||
}
|
||
|
||
#else // REVERSE
|
||
|
||
void Mixer_Input_selector_clicked(GtkWidget *widget, gpointer ich) {
|
||
int och, val;
|
||
snd_ctl_elem_id_t *id;
|
||
snd_ctl_elem_value_t *control;
|
||
|
||
if (mixerControl.input==(int)ich)
|
||
return;
|
||
|
||
mixerControl.input=(int)ich;
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_value_alloca(&control);
|
||
|
||
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
|
||
for (och=0; och<nLOut; och++) {
|
||
val=INVERT(mixerControl.mixer[och][mixerControl.input].Gain);
|
||
gtk_adjustment_set_value(GTK_ADJUSTMENT(mixerControl.adj[och]), (gfloat)val);
|
||
}
|
||
}
|
||
|
||
#endif // REVERSE
|
||
|
||
|
||
#ifdef REVERSE
|
||
|
||
static gint Gmixer_button_press(GtkWidget *widget, GdkEventButton *event) {
|
||
|
||
GMixerRow=(int)event->y/YCELLTOT;
|
||
GMixerColumn=(int)event->x/XCELLTOT-1;
|
||
|
||
/* grab_focus must follow set_active because the latter causes
|
||
Vmixer_*_selector_clicked() to be called and, in turn,
|
||
Vmixer_volume_changed() which changes mixerControl.input
|
||
(or .output in non-reverse mode). grab_focus then causes
|
||
Vmixer_volume_clicked() to be called and that event handler
|
||
finally sets the correct value of mixerControl.input */
|
||
if (GMixerRow<=GMixerSection.Monitor) {
|
||
if (GMixerColumn!=mixerControl.output && GMixerColumn>=0) {
|
||
if (GMixerColumn<fdOut+2 || (ADATmode() && GMixerColumn<nLOut))
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mixerControl.outsel[GMixerColumn]), TRUE);
|
||
}
|
||
if (GMixerRow!=mixerControl.input)
|
||
gtk_widget_grab_focus(GTK_WIDGET(mixerControl.volume[GMixerRow]));
|
||
} else if (GMixerRow>=GMixerSection.VmixerFirst && GMixerRow<=GMixerSection.VmixerLast) {
|
||
if (GMixerColumn!=vmixerControl.output && GMixerColumn>=0) {
|
||
if (GMixerColumn<fdOut+2 || (ADATmode() && GMixerColumn<vmixerControl.outputs))
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(vmixerControl.outsel[GMixerColumn]), TRUE);
|
||
}
|
||
if (GMixerRow!=vmixerControl.vchannel)
|
||
gtk_widget_grab_focus(GTK_WIDGET(vmixerControl.volume[GMixerRow-GMixerSection.VmixerFirst]));
|
||
}
|
||
|
||
if (event->button==1) {
|
||
mouseY=event->y;
|
||
mouseButton=1;
|
||
}
|
||
return(TRUE);
|
||
}
|
||
|
||
#else //REVERSE
|
||
|
||
static gint Gmixer_button_press(GtkWidget *widget, GdkEventButton *event) {
|
||
|
||
GMixerRow=(int)event->y/YCELLTOT;
|
||
GMixerColumn=(int)event->x/XCELLTOT-1;
|
||
|
||
// See the note above
|
||
if (GMixerRow<=GMixerSection.Monitor) {
|
||
if (GMixerRow!=mixerControl.input)
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mixerControl.inpsel[GMixerRow]), TRUE);
|
||
if (GMixerColumn!=mixerControl.output && GMixerColumn>=0) {
|
||
if (GMixerColumn<fdOut+2 || (ADATmode() && GMixerColumn<nLOut))
|
||
gtk_widget_grab_focus(GTK_WIDGET(mixerControl.volume[GMixerColumn]));
|
||
}
|
||
} else if (GMixerRow>=GMixerSection.VmixerFirst && GMixerRow<=GMixerSection.VmixerLast) {
|
||
if (GMixerRow!=vmixerControl.vchannel)
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(vmixerControl.vchsel[GMixerRow-GMixerSection.VmixerFirst]), TRUE);
|
||
if (GMixerColumn!=vmixerControl.output && GMixerColumn>=0) {
|
||
if (GMixerColumn<fdOut+2 || (ADATmode() && GMixerColumn<vmixerControl.outputs))
|
||
gtk_widget_grab_focus(GTK_WIDGET(vmixerControl.volume[GMixerColumn]));
|
||
}
|
||
}
|
||
|
||
if (event->button==1) {
|
||
mouseY=event->y;
|
||
mouseButton=1;
|
||
}
|
||
return(TRUE);
|
||
}
|
||
|
||
#endif //REVERSE
|
||
|
||
|
||
|
||
static gint Gmixer_button_release(GtkWidget *widget, GdkEventButton *event) {
|
||
|
||
if (event->state & GDK_BUTTON1_MASK)
|
||
mouseButton=0;
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
static gint Gmixer_motion_notify(GtkWidget *widget, GdkEventMotion *event) {
|
||
int x, y;
|
||
GdkModifierType state;
|
||
float val;
|
||
|
||
if (event->is_hint)
|
||
gdk_window_get_pointer(event->window, &x, &y, &state);
|
||
else {
|
||
x=event->x;
|
||
y=event->y;
|
||
state=event->state;
|
||
}
|
||
|
||
// Check if the button is still pressed because the release event can fall in another window, so we may miss it.
|
||
if (!(state & GDK_BUTTON1_MASK))
|
||
mouseButton=0;
|
||
|
||
if (GMixerRow<=GMixerSection.Monitor) {
|
||
if (mouseButton && Mixpixmap != NULL) {
|
||
val=INVERT(mixerControl.mixer[mixerControl.output][mixerControl.input].Gain);
|
||
val+=y-mouseY;
|
||
mouseY=y;
|
||
// Gtk already limits the range of "val"
|
||
#ifdef REVERSE
|
||
gtk_adjustment_set_value(GTK_ADJUSTMENT(mixerControl.adj[mixerControl.input]), (gfloat)val);
|
||
#else
|
||
gtk_adjustment_set_value(GTK_ADJUSTMENT(mixerControl.adj[mixerControl.output]), (gfloat)val);
|
||
#endif
|
||
}
|
||
} else if (GMixerRow>=GMixerSection.VmixerFirst && GMixerRow<=GMixerSection.VmixerLast) {
|
||
if (mouseButton && Mixpixmap != NULL) {
|
||
val=INVERT(vmixerControl.mixer[vmixerControl.output][vmixerControl.vchannel].Gain);
|
||
val+=y-mouseY;
|
||
mouseY=y;
|
||
// Gtk already limits the range of "val"
|
||
#ifdef REVERSE
|
||
gtk_adjustment_set_value(GTK_ADJUSTMENT(vmixerControl.adj[vmixerControl.vchannel]), (gfloat)val);
|
||
#else
|
||
gtk_adjustment_set_value(GTK_ADJUSTMENT(vmixerControl.adj[vmixerControl.output]), (gfloat)val);
|
||
#endif
|
||
}
|
||
} else if (GMixerRow==GMixerSection.LineOut) {
|
||
if (mouseButton && Mixpixmap != NULL) {
|
||
val=INVERT(lineoutControl.Gain[GMixerColumn]);
|
||
val+=y-mouseY;
|
||
mouseY=y;
|
||
// Gtk already limits the range of "val"
|
||
gtk_adjustment_set_value(GTK_ADJUSTMENT(lineoutControl.adj[GMixerColumn]), (gfloat)val);
|
||
}
|
||
}
|
||
|
||
return(TRUE);
|
||
}
|
||
|
||
|
||
|
||
void Monitor_volume_changed(GtkWidget *widget, gpointer cnl) {
|
||
int val, rval, ch;
|
||
int i, o;
|
||
char str[16];
|
||
|
||
UI_DEBUG(("Monitor_volume_changed() %d %d\n",mixerControl.input,mixerControl.output));
|
||
val=rval=INVERT((int)GTK_ADJUSTMENT(widget)->value);
|
||
|
||
ch=(int)cnl;
|
||
|
||
#ifdef REVERSE
|
||
i=ch;
|
||
o=mixerControl.output;
|
||
#else
|
||
i=mixerControl.input;
|
||
o=ch;
|
||
#endif
|
||
|
||
// Emulate the line-out volume if this card can't do it in hw.
|
||
if (!lineoutId) {
|
||
rval=Add_dB(val, lineoutControl.Gain[o]);
|
||
ClampOutputVolume(&rval);
|
||
}
|
||
|
||
SetMixerGain(&mixerControl.mixer[o][i], rval); //@ we should restore the old adj position on error
|
||
mixerControl.mixer[o][i].Gain=val;
|
||
|
||
if (Gang) {
|
||
SetMixerGain(&mixerControl.mixer[o^1][i^1], rval);
|
||
mixerControl.mixer[o^1][i^1].Gain=val;
|
||
}
|
||
|
||
gtk_label_set_text(GTK_LABEL(mixerControl.label[ch]), strOutGain(str, val));
|
||
}
|
||
|
||
|
||
|
||
void Monitor_volume_clicked(GtkWidget *widget, gpointer ch) {
|
||
|
||
#ifdef REVERSE
|
||
mixerControl.input=(int)ch;
|
||
#else
|
||
mixerControl.output=(int)ch;
|
||
#endif
|
||
}
|
||
|
||
|
||
|
||
void Gang_button_toggled(GtkWidget *widget, gpointer unused) {
|
||
|
||
Gang=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
|
||
}
|
||
|
||
|
||
|
||
void PCM_volume_changed(GtkWidget *widget, gpointer ch) {
|
||
snd_ctl_elem_id_t *id;
|
||
snd_ctl_elem_value_t *control;
|
||
char str[16];
|
||
int err, channel, val, rval;
|
||
struct VolumeControl *vol;
|
||
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_value_alloca(&control);
|
||
|
||
if ((int)ch<ECHO_MAXAUDIOINPUTS) {
|
||
// Input
|
||
channel=(int)ch;
|
||
vol=&lineinControl;
|
||
rval=val=IN_INVERT((int)GTK_ADJUSTMENT(widget)->value);
|
||
sprintf(str, "%+4.1f", 0.5*val);
|
||
} else {
|
||
// Output
|
||
channel=(int)ch-ECHO_MAXAUDIOINPUTS;
|
||
vol=&pcmoutControl;
|
||
val=rval=INVERT((int)GTK_ADJUSTMENT(widget)->value);
|
||
pcmoutControl.Gain[channel]=val;
|
||
// Emulate the line-out volume if this card can't do it in hw.
|
||
if (!lineoutId) {
|
||
rval=Add_dB(val, lineoutControl.Gain[channel]);
|
||
ClampOutputVolume(&rval);
|
||
}
|
||
strOutGain(str, val);
|
||
}
|
||
|
||
gtk_label_set_text(GTK_LABEL(vol->label[channel]), str);
|
||
|
||
snd_ctl_elem_id_set_numid(id, vol->id);
|
||
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
|
||
snd_ctl_elem_value_set_id(control, id);
|
||
|
||
if ((err=snd_ctl_elem_read(ctlhandle, control))<0) {
|
||
printf("Control %s element read error: %s\n", card, snd_strerror(err));
|
||
return;
|
||
}
|
||
|
||
snd_ctl_elem_value_set_integer(control, channel, rval);
|
||
if ((err=snd_ctl_elem_write(ctlhandle, control))<0) {
|
||
printf("Control %s element write error: %s\n", card, snd_strerror(err));
|
||
} else {
|
||
vol->Gain[channel]=val;
|
||
}
|
||
if (Gang)
|
||
gtk_adjustment_set_value(GTK_ADJUSTMENT(vol->adj[channel^1]), (gfloat)GTK_ADJUSTMENT(widget)->value);
|
||
}
|
||
|
||
|
||
|
||
// Changes the PCM volume according to the current Line-out volume for non-vmixer cards
|
||
void UpdatePCMVolume(int outchannel) {
|
||
snd_ctl_elem_id_t *id;
|
||
snd_ctl_elem_value_t *control;
|
||
int err, val;
|
||
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_value_alloca(&control);
|
||
snd_ctl_elem_id_set_numid(id, pcmoutId);
|
||
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
|
||
snd_ctl_elem_value_set_id(control, id);
|
||
|
||
if ((err=snd_ctl_elem_read(ctlhandle, control))<0)
|
||
printf("Control %s element read error: %s\n", card, snd_strerror(err));
|
||
|
||
val=Add_dB(pcmoutControl.Gain[outchannel], lineoutControl.Gain[outchannel]);
|
||
ClampOutputVolume(&val);
|
||
|
||
snd_ctl_elem_value_set_integer(control, outchannel, val);
|
||
if ((err=snd_ctl_elem_write(ctlhandle, control))<0)
|
||
printf("Control %s element write error: %s\n", card, snd_strerror(err));
|
||
}
|
||
|
||
|
||
|
||
// Changes the monitor mixer volume according to the current Line-out volume for non-vmixer cards.
|
||
void UpdateMixerVolume(int outchannel) {
|
||
snd_ctl_elem_id_t *id;
|
||
snd_ctl_elem_value_t *control;
|
||
int err, val, ch;
|
||
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_value_alloca(&control);
|
||
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
|
||
|
||
for (ch=0; ch<nIn; ch++) {
|
||
val=Add_dB(mixerControl.mixer[outchannel][ch].Gain, lineoutControl.Gain[outchannel]);
|
||
ClampOutputVolume(&val);
|
||
snd_ctl_elem_id_set_numid(id, mixerControl.mixer[outchannel][ch].id);
|
||
snd_ctl_elem_value_set_id(control, id);
|
||
snd_ctl_elem_value_set_integer(control, 0, val);
|
||
if ((err = snd_ctl_elem_write(ctlhandle, control)) < 0)
|
||
printf("Control %s element write error: %s\n", card, snd_strerror(err));
|
||
}
|
||
}
|
||
|
||
|
||
|
||
void LineOut_volume_changed(GtkWidget *widget, gpointer ch) {
|
||
char str[16];
|
||
int err, channel, val;
|
||
|
||
channel=(int)ch;
|
||
|
||
val=INVERT((int)GTK_ADJUSTMENT(widget)->value);
|
||
lineoutControl.Gain[channel]=val;
|
||
|
||
gtk_label_set_text(GTK_LABEL(lineoutControl.label[channel]), strOutGain(str, val));
|
||
|
||
if (lineoutId) { // If this card has the line-out control, use it
|
||
snd_ctl_elem_id_t *id;
|
||
snd_ctl_elem_value_t *control;
|
||
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_value_alloca(&control);
|
||
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
|
||
snd_ctl_elem_id_set_numid(id, lineoutId);
|
||
snd_ctl_elem_value_set_id(control, id);
|
||
|
||
if ((err=snd_ctl_elem_read(ctlhandle, control))<0)
|
||
printf("Control %s element read error: %s\n", card, snd_strerror(err));
|
||
snd_ctl_elem_value_set_integer(control, channel, val);
|
||
if ((err=snd_ctl_elem_write(ctlhandle, control))<0)
|
||
printf("Control %s element write error: %s\n", card, snd_strerror(err));
|
||
} else { // Otherwise we have to emulate it.
|
||
UpdatePCMVolume(channel);
|
||
UpdateMixerVolume(channel);
|
||
}
|
||
|
||
if (Gang)
|
||
gtk_adjustment_set_value(GTK_ADJUSTMENT(lineoutControl.adj[channel^1]), (gfloat)GTK_ADJUSTMENT(widget)->value);
|
||
}
|
||
|
||
|
||
|
||
void Vmixer_volume_changed(GtkWidget *widget, gpointer ch) {
|
||
char str[16];
|
||
int val, channel;
|
||
int o, v;
|
||
|
||
channel=(int)ch;
|
||
|
||
#ifdef REVERSE
|
||
v=channel;
|
||
o=vmixerControl.output;
|
||
#else
|
||
v=vmixerControl.vchannel;
|
||
o=channel;
|
||
#endif
|
||
|
||
val=INVERT((int)GTK_ADJUSTMENT(widget)->value);
|
||
|
||
SetMixerGain(&vmixerControl.mixer[o][v], val);
|
||
vmixerControl.mixer[o][v].Gain=val;
|
||
|
||
if (Gang) {
|
||
SetMixerGain(&vmixerControl.mixer[o^1][v^1], val);
|
||
vmixerControl.mixer[o^1][v^1].Gain=val;
|
||
}
|
||
|
||
gtk_label_set_text(GTK_LABEL(vmixerControl.label[channel]), strOutGain(str, val));
|
||
}
|
||
|
||
|
||
|
||
void Vmixer_volume_clicked(GtkWidget *widget, gpointer ch) {
|
||
|
||
#ifdef REVERSE
|
||
vmixerControl.vchannel=(int)ch;
|
||
UI_DEBUG(("Vmixer_volume_clicked vch=%d\n",vmixerControl.vchannel));
|
||
#else
|
||
vmixerControl.output=(int)ch;
|
||
UI_DEBUG(("Vmixer_volume_clicked out=%d\n",vmixerControl.output));
|
||
#endif
|
||
}
|
||
|
||
|
||
|
||
#ifdef REVERSE
|
||
|
||
void Vmixer_output_selector_clicked(GtkWidget *widget, gpointer ch) {
|
||
int c, val;
|
||
snd_ctl_elem_id_t *id;
|
||
snd_ctl_elem_value_t *control;
|
||
|
||
if (vmixerControl.output==(int)ch)
|
||
return;
|
||
vmixerControl.output=(int)ch;
|
||
|
||
UI_DEBUG(("Vmixer_selector_clicked out=%d\n",vmixerControl.output));
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_value_alloca(&control);
|
||
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
|
||
for (c=vmixerControl.vchannels-1; c>=0; c--) {
|
||
val=INVERT(vmixerControl.mixer[vmixerControl.output][c].Gain);
|
||
gtk_adjustment_set_value(GTK_ADJUSTMENT(vmixerControl.adj[c]), (gfloat)val);
|
||
}
|
||
}
|
||
|
||
#else
|
||
|
||
void Vmixer_vchannel_selector_clicked(GtkWidget *widget, gpointer ch) {
|
||
int c, val;
|
||
snd_ctl_elem_id_t *id;
|
||
snd_ctl_elem_value_t *control;
|
||
|
||
if (vmixerControl.vchannel==(int)ch)
|
||
return;
|
||
vmixerControl.vchannel=(int)ch;
|
||
|
||
UI_DEBUG(("Vmixer_selector_clicked vch=%d\n",vmixerControl.vchannel));
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_value_alloca(&control);
|
||
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
|
||
for (c=vmixerControl.outputs-1; c>=0; c--) {
|
||
val=INVERT(vmixerControl.mixer[c][vmixerControl.vchannel].Gain);
|
||
gtk_adjustment_set_value(GTK_ADJUSTMENT(vmixerControl.adj[c]), (gfloat)val);
|
||
}
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
|
||
void Nominal_level_toggled(GtkWidget *widget, gpointer ch) {
|
||
snd_ctl_elem_id_t *id;
|
||
snd_ctl_elem_value_t *control;
|
||
GtkWidget **button;
|
||
int err, val, channel;
|
||
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_value_alloca(&control);
|
||
|
||
val=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
|
||
|
||
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
|
||
if ((int)ch<ECHO_MAXAUDIOINPUTS) {
|
||
channel=(int)ch;
|
||
button=p4dbuIn;
|
||
NominalIn[channel]=!val;
|
||
snd_ctl_elem_id_set_numid(id, p4InId);
|
||
} else {
|
||
channel=(int)ch-ECHO_MAXAUDIOINPUTS;
|
||
button=p4dbuOut;
|
||
NominalOut[channel]=!val;
|
||
snd_ctl_elem_id_set_numid(id, p4OutId);
|
||
}
|
||
snd_ctl_elem_value_set_id(control, id);
|
||
if ((err=snd_ctl_elem_read(ctlhandle, control))<0)
|
||
printf("Control %s element read error: %s\n", card, snd_strerror(err));
|
||
snd_ctl_elem_value_set_integer(control, channel, !val); // FALSE is +4
|
||
if ((err=snd_ctl_elem_write(ctlhandle, control))<0)
|
||
printf("Control %s element write error: %s\n", card, snd_strerror(err));
|
||
if (Gang)
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button[channel^1]), val);
|
||
}
|
||
|
||
|
||
|
||
void PhantomPower_toggled(GtkWidget *widget, gpointer unused) {
|
||
snd_ctl_elem_id_t *id;
|
||
snd_ctl_elem_value_t *control;
|
||
int err, val;
|
||
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_value_alloca(&control);
|
||
|
||
val=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
|
||
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_CARD);
|
||
snd_ctl_elem_id_set_numid(id, phantomId);
|
||
snd_ctl_elem_value_set_id(control, id);
|
||
snd_ctl_elem_value_set_integer(control, 0, val);
|
||
if ((err=snd_ctl_elem_write(ctlhandle, control))<0) {
|
||
printf("Control %s element write error: %s\n", card, snd_strerror(err));
|
||
}
|
||
}
|
||
|
||
|
||
|
||
void Digital_mode_activate(GtkWidget *widget, gpointer mode) {
|
||
int adat;
|
||
|
||
if (SetEnum(dmodeId, (int)mode)<0)
|
||
// Restore old value if it failed
|
||
gtk_option_menu_set_history(GTK_OPTION_MENU(dmodeOpt), dmodeVal);
|
||
else {
|
||
dmodeVal=(int)mode;
|
||
// When I change the digital mode, the clock source can change too
|
||
gtk_option_menu_set_history(GTK_OPTION_MENU(clocksrcOpt), clocksrcVal=GetEnum(clocksrcId));
|
||
}
|
||
adat=ADATmode();
|
||
SetSensitivity(adat);
|
||
if (adat)
|
||
GMixerSection.Monitor=nIn-1;
|
||
else
|
||
GMixerSection.Monitor=fdIn+2-1; // S/PDIF has only 2 channels
|
||
}
|
||
|
||
|
||
|
||
void Clock_source_activate(GtkWidget *widget, gpointer clk) {
|
||
|
||
if (SetEnum(clocksrcId, (int)clk)<0)
|
||
gtk_option_menu_set_history(GTK_OPTION_MENU(clocksrcOpt), clocksrcVal);
|
||
else
|
||
clocksrcVal=(int)clk;
|
||
}
|
||
|
||
|
||
|
||
void SPDIF_mode_activate(GtkWidget *widget, gpointer mode) {
|
||
|
||
SetEnum(spdifmodeId, (int)mode); // This one should never fail
|
||
spdifmodeVal=(int)mode;
|
||
}
|
||
|
||
|
||
|
||
// Create a new backing pixmap of the appropriate size
|
||
static gint VU_configure_event(GtkWidget *widget, GdkEventConfigure *event) {
|
||
|
||
if (VUpixmap)
|
||
gdk_pixmap_unref(VUpixmap);
|
||
VUpixmap=gdk_pixmap_new(widget->window, widget->allocation.width, widget->allocation.height, -1);
|
||
gdk_draw_rectangle(VUpixmap, widget->style->black_gc, TRUE, 0, 0, widget->allocation.width, widget->allocation.height);
|
||
return(TRUE);
|
||
}
|
||
|
||
|
||
|
||
// Redraw the screen from the backing pixmap
|
||
static gint VU_expose(GtkWidget *widget, GdkEventExpose *event) {
|
||
|
||
if (VUpixmap)
|
||
gdk_draw_pixmap(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], VUpixmap,
|
||
event->area.x, event->area.y,
|
||
event->area.x, event->area.y,
|
||
event->area.width, event->area.height);
|
||
return(FALSE);
|
||
}
|
||
|
||
|
||
|
||
// Create a new backing pixmap of the appropriate size
|
||
static gint Gmixer_configure_event(GtkWidget *widget, GdkEventConfigure *event) {
|
||
|
||
if (Mixpixmap)
|
||
gdk_pixmap_unref(Mixpixmap);
|
||
Mixpixmap=gdk_pixmap_new(widget->window, widget->allocation.width, widget->allocation.height, -1);
|
||
gdk_draw_rectangle(Mixpixmap, widget->style->black_gc, TRUE, 0, 0, widget->allocation.width, widget->allocation.height);
|
||
return(TRUE);
|
||
}
|
||
|
||
|
||
|
||
// Redraw the screen from the backing pixmap
|
||
static gint Gmixer_expose(GtkWidget *widget, GdkEventExpose *event) {
|
||
|
||
if (Mixpixmap)
|
||
gdk_draw_pixmap(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], Mixpixmap,
|
||
event->area.x, event->area.y,
|
||
event->area.x, event->area.y,
|
||
event->area.width, event->area.height);
|
||
return(FALSE);
|
||
}
|
||
|
||
|
||
|
||
gint CloseWindow(GtkWidget *widget, GdkEvent *event, gpointer geom) {
|
||
struct geometry *g=geom;
|
||
|
||
gdk_window_get_root_origin(widget->window, &g->x, &g->y);
|
||
gdk_window_get_size(widget->window, &g->w, &g->h);
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->toggler), FALSE); // This hides the window
|
||
//gtk_widget_set_uposition(widget, g->x, g->y);
|
||
return(TRUE); // Do not destroy it
|
||
}
|
||
|
||
|
||
|
||
gint Mainwindow_delete(GtkWidget *widget, GdkEvent *event, gpointer geom) {
|
||
struct geometry *g=geom;
|
||
|
||
if (VUwindow) {
|
||
gdk_window_get_root_origin(VUwindow->window, &VUw_geom.x, &VUw_geom.y);
|
||
gtk_widget_destroy(VUwindow);
|
||
}
|
||
if (GMwindow) {
|
||
gdk_window_get_root_origin(GMwindow->window, &GMw_geom.x, &GMw_geom.y);
|
||
gtk_widget_destroy(GMwindow);
|
||
}
|
||
gdk_window_get_root_origin(Mainwindow->window, &g->x, &g->y);
|
||
gtk_main_quit();
|
||
return(FALSE);
|
||
}
|
||
|
||
|
||
|
||
gint VUwindow_delete(GtkWidget *widget, GdkEvent *event, gpointer geom) {
|
||
struct geometry *g=geom;
|
||
|
||
gdk_window_get_root_origin(widget->window, &g->x, &g->y);
|
||
g->st=0;
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->toggler), FALSE);
|
||
return(FALSE);
|
||
}
|
||
|
||
|
||
|
||
gint VUwindow_destroy(GtkWidget *widget, gpointer unused) {
|
||
|
||
SetVUmeters(0);
|
||
gtk_timeout_remove(VUtimer);
|
||
//@@@del gc and fnt
|
||
VUwindow=0;
|
||
return(TRUE);
|
||
}
|
||
|
||
|
||
|
||
gint GMwindow_delete(GtkWidget *widget, GdkEvent *event, gpointer geom) {
|
||
struct geometry *g=geom;
|
||
|
||
gdk_window_get_root_origin(widget->window, &g->x, &g->y);
|
||
g->st=0;
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->toggler), FALSE);
|
||
return(FALSE);
|
||
}
|
||
|
||
|
||
|
||
gint GMwindow_destroy(GtkWidget *widget, gpointer unused) {
|
||
|
||
SetVUmeters(0);
|
||
gtk_timeout_remove(Mixtimer);
|
||
//@@@del gc and fnt
|
||
GMwindow=0;
|
||
return(TRUE);
|
||
}
|
||
|
||
|
||
|
||
void VUmeters_button_click(GtkWidget *widget, gpointer unused) {
|
||
char str[64];
|
||
|
||
if (VUwindow && !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
|
||
VUw_geom.st=0;
|
||
gtk_widget_destroy(VUwindow);
|
||
} else if (!VUwindow && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
|
||
// Create VU-meter window
|
||
VUwidth=VU_XGRAF+(VU_BARWIDTH+VU_BARSEP)*(nIn+nLOut+1)+VU_BARSEP;
|
||
VUheight=160;
|
||
SetVUmeters(1);
|
||
VUwindow=gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||
sprintf(str, "%s VU-meters", cardId);
|
||
gtk_window_set_title (GTK_WINDOW (VUwindow), str);
|
||
gtk_window_set_wmclass(GTK_WINDOW(VUwindow), "vumeters", "Emixer");
|
||
gtk_signal_connect(GTK_OBJECT(VUwindow), "destroy", GTK_SIGNAL_FUNC(VUwindow_destroy), NULL);
|
||
gtk_signal_connect(GTK_OBJECT(VUwindow), "delete_event", GTK_SIGNAL_FUNC(VUwindow_delete), (gpointer)&VUw_geom);
|
||
gtk_window_set_policy(GTK_WINDOW(VUwindow), FALSE, FALSE, TRUE);
|
||
if (VUw_geom.st!=NOPOS)
|
||
gtk_widget_set_uposition(VUwindow, VUw_geom.x, VUw_geom.y);
|
||
gtk_widget_show(VUwindow);
|
||
|
||
VUdarea=gtk_drawing_area_new();
|
||
gtk_widget_set_events(VUdarea, GDK_EXPOSURE_MASK);
|
||
gtk_drawing_area_size(GTK_DRAWING_AREA(VUdarea), VUwidth, VUheight);
|
||
gtk_container_add(GTK_CONTAINER(VUwindow), VUdarea);
|
||
|
||
gtk_widget_show(VUdarea);
|
||
gtk_signal_connect(GTK_OBJECT(VUdarea), "expose_event", (GtkSignalFunc)VU_expose, NULL);
|
||
gtk_signal_connect(GTK_OBJECT(VUdarea), "configure_event", (GtkSignalFunc)VU_configure_event, NULL);
|
||
VUtimer=gtk_timeout_add(30, DrawVUmeters, 0); // The hw updates the meters about 30 times/s
|
||
gdk_window_clear_area(VUdarea->window, 0, 0, VUwidth, VUheight);
|
||
VUw_geom.st=1;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
void GMixer_button_click(GtkWidget *widget, gpointer unused) {
|
||
char str[64];
|
||
|
||
if (GMwindow && !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
|
||
GMw_geom.st=0;
|
||
gtk_widget_destroy(GMwindow);
|
||
} else if (!GMwindow && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
|
||
// Create graphic mixer window
|
||
Mixwidth=XCELLTOT*(nLOut+1);
|
||
Mixheight=YCELLTOT*(GMixerSection.LineOut+1)+9;
|
||
SetVUmeters(1);
|
||
GMwindow=gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||
sprintf(str, "%s Mixer", cardId);
|
||
gtk_window_set_title (GTK_WINDOW (GMwindow), str);
|
||
gtk_window_set_wmclass(GTK_WINDOW(GMwindow), "gridmixer", "Emixer");
|
||
gtk_signal_connect(GTK_OBJECT(GMwindow), "destroy", GTK_SIGNAL_FUNC(GMwindow_destroy), NULL);
|
||
gtk_signal_connect(GTK_OBJECT(GMwindow), "delete_event", GTK_SIGNAL_FUNC(GMwindow_delete), (gpointer)&GMw_geom);
|
||
gtk_window_set_policy(GTK_WINDOW(GMwindow), FALSE, FALSE, TRUE);
|
||
if (GMw_geom.st!=NOPOS)
|
||
gtk_widget_set_uposition(GMwindow, GMw_geom.x, GMw_geom.y);
|
||
gtk_widget_show(GMwindow);
|
||
|
||
Mixdarea=gtk_drawing_area_new();
|
||
gtk_widget_set_events(Mixdarea, GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
|
||
gtk_drawing_area_size(GTK_DRAWING_AREA(Mixdarea), Mixwidth, Mixheight);
|
||
gtk_container_add(GTK_CONTAINER(GMwindow), Mixdarea);
|
||
|
||
gtk_widget_show(Mixdarea);
|
||
gtk_signal_connect(GTK_OBJECT(Mixdarea), "expose_event", (GtkSignalFunc)Gmixer_expose, NULL);
|
||
gtk_signal_connect(GTK_OBJECT(Mixdarea), "configure_event", (GtkSignalFunc)Gmixer_configure_event, NULL);
|
||
gtk_signal_connect(GTK_OBJECT(Mixdarea), "motion_notify_event", (GtkSignalFunc)Gmixer_motion_notify, NULL);
|
||
gtk_signal_connect(GTK_OBJECT(Mixdarea), "button_press_event", (GtkSignalFunc)Gmixer_button_press, NULL);
|
||
gtk_signal_connect(GTK_OBJECT(Mixdarea), "button_release_event", (GtkSignalFunc)Gmixer_button_release, NULL);
|
||
Mixtimer=gtk_timeout_add(30, DrawMixer, 0); // The hw updates the meters about 30 times/s
|
||
gdk_window_clear_area(Mixdarea->window, 0, 0, Mixwidth, Mixheight);
|
||
GMw_geom.st=1;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
void ToggleWindow(GtkWidget *widget, gpointer window) {
|
||
|
||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
|
||
gtk_widget_show(GTK_WIDGET(window));
|
||
else
|
||
gtk_widget_hide(GTK_WIDGET(window));
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
int LockControls(snd_ctl_elem_id_t *id, int first_id, int num) {
|
||
int i, err;
|
||
|
||
for (i=0; i<num; i++) {
|
||
snd_ctl_elem_id_set_numid(id, first_id+i);
|
||
err=snd_ctl_elem_lock(ctlhandle, id);
|
||
if (err)
|
||
return(err);
|
||
}
|
||
return(0);
|
||
}
|
||
|
||
int LockControls(int first_id, int num) {
|
||
int i, err;
|
||
snd_ctl_elem_id_t *id;
|
||
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_id_set_interface(id, first_id==clocksrcId ? SND_CTL_ELEM_IFACE_PCM : SND_CTL_ELEM_IFACE_CARD);
|
||
|
||
for (i=0; i<num; i++) {
|
||
snd_ctl_elem_id_set_numid(id, first_id+i);
|
||
err=snd_ctl_elem_lock(ctlhandle, id);
|
||
if (err)
|
||
return(err);
|
||
}
|
||
return(0);
|
||
}
|
||
*/
|
||
|
||
|
||
|
||
// Scan all controls and store their ID's for later use.
|
||
int OpenControls(const char *card, const char *cardname) {
|
||
int err, i, o;
|
||
int numid, count, items, item;
|
||
snd_hctl_t *handle;
|
||
snd_hctl_elem_t *elem;
|
||
snd_ctl_elem_id_t *id;
|
||
snd_ctl_elem_info_t *info;
|
||
|
||
pcmoutId=lineoutId=vmixerId=p4InId=p4OutId=dmodeId=clocksrcId=spdifmodeId=vuswitchId=vumetersId=mixerId=0;
|
||
memset(&vmixerControl, 0, sizeof(vmixerControl));
|
||
memset(&mixerControl, 0, sizeof(mixerControl));
|
||
memset(&lineoutControl, 0, sizeof(struct VolumeControl));
|
||
memset(&lineinControl, 0, sizeof(struct VolumeControl));
|
||
memset(&pcmoutControl, 0, sizeof(struct VolumeControl));
|
||
ndmodes=nclocksrc=nspdifmodes=0;
|
||
snd_ctl_elem_id_alloca(&id);
|
||
snd_ctl_elem_info_alloca(&info);
|
||
|
||
if ((err=snd_hctl_open(&handle, card, 0))<0) {
|
||
printf("Control %s open error: %s", card, snd_strerror(err));
|
||
return err;
|
||
}
|
||
if ((err=snd_hctl_load(handle))<0) {
|
||
printf("Control %s local error: %s\n", card, snd_strerror(err));
|
||
return err;
|
||
}
|
||
for (elem=snd_hctl_first_elem(handle); elem; elem=snd_hctl_elem_next(elem)) {
|
||
if ((err=snd_hctl_elem_info(elem, info))<0) {
|
||
printf("Control %s snd_hctl_elem_info error: %s\n", card, snd_strerror(err));
|
||
return err;
|
||
}
|
||
if (snd_ctl_elem_info_is_inactive(info))
|
||
continue;
|
||
snd_hctl_elem_get_id(elem, id);
|
||
numid=snd_ctl_elem_id_get_numid(id);
|
||
count=snd_ctl_elem_info_get_count(info);
|
||
if (!strcmp("Monitor Mixer Volume", snd_ctl_elem_id_get_name(id))) {
|
||
if (!mixerId) {
|
||
mixerId=numid;
|
||
CTLID_DEBUG(("First Mixer id=%d\n", mixerId));
|
||
mixerControl.outputs=snd_ctl_elem_info_get_dimension(info, 0);
|
||
mixerControl.inputs=snd_ctl_elem_info_get_dimension(info, 1);
|
||
}
|
||
} else if (!strcmp("VMixer Volume", snd_ctl_elem_id_get_name(id))) {
|
||
if (!vmixerId) {
|
||
vmixerId=vmixerControl.id=numid;
|
||
CTLID_DEBUG(("First Vmixer id=%d\n", vmixerId));
|
||
vmixerControl.outputs=snd_ctl_elem_info_get_dimension(info, 0);
|
||
vmixerControl.vchannels=snd_ctl_elem_info_get_dimension(info, 1);
|
||
}
|
||
} else if (!strcmp("PCM Playback Volume", snd_ctl_elem_id_get_name(id))) {
|
||
pcmoutId=pcmoutControl.id=numid;
|
||
//printf("*** %d\n", LockControls(id, numid, 1));
|
||
//#warning ************* usare id gi<67> pronto ? controllo errori, eccc.
|
||
CTLID_DEBUG(("PCM Playback Volume id=%d [%d]\n", pcmoutId, count));
|
||
} else if (!strcmp("Line Playback Volume", snd_ctl_elem_id_get_name(id))) {
|
||
lineoutId=numid;
|
||
CTLID_DEBUG(("Line Volume id=%d\n", lineoutId));
|
||
} else if (!strcmp("Line Capture Volume", snd_ctl_elem_id_get_name(id))) {
|
||
lineinId=lineinControl.id=numid;
|
||
CTLID_DEBUG(("Capture Volume id=%d [%d]\n", lineinId, count));
|
||
} else if (!strcmp("Line Playback Switch (-10dBV)", snd_ctl_elem_id_get_name(id))) {
|
||
p4OutId=numid;
|
||
CTLID_DEBUG(("Playback nominal id=%d [%d]\n", p4OutId, count));
|
||
} else if (!strcmp("Line Capture Switch (-10dBV)", snd_ctl_elem_id_get_name(id))) {
|
||
p4InId=numid;
|
||
CTLID_DEBUG(("Capture nominal id=%d [%d]\n", p4InId, count));
|
||
} else if (!strcmp("Digital mode Switch", snd_ctl_elem_id_get_name(id))) {
|
||
dmodeId=numid;
|
||
items=snd_ctl_elem_info_get_items(info);
|
||
ndmodes=items;
|
||
for (item=0; item<items; item++) {
|
||
snd_ctl_elem_info_set_item(info, item);
|
||
if ((err=snd_hctl_elem_info(elem, info)) < 0) {
|
||
printf("Control %s element info error: %s\n", card, snd_strerror(err));
|
||
exit(err);
|
||
}
|
||
strncpy(dmodeName[item], snd_ctl_elem_info_get_item_name(info), 63);
|
||
dmodeName[item][63]=0;
|
||
CTLID_DEBUG(("Digital Mode id=%d item #%u '%s'\n", numid, item, snd_ctl_elem_info_get_item_name(info)));
|
||
}
|
||
} else if (!strcmp("Sample Clock Source", snd_ctl_elem_id_get_name(id))) {
|
||
clocksrcId=numid;
|
||
items=snd_ctl_elem_info_get_items(info);
|
||
nclocksrc=items;
|
||
for (item=0; item<items; item++) {
|
||
snd_ctl_elem_info_set_item(info, item);
|
||
if ((err=snd_hctl_elem_info(elem, info))<0) {
|
||
printf("Control %s element info error: %s\n", card, snd_strerror(err));
|
||
exit(err);
|
||
}
|
||
strncpy(clocksrcName[item], snd_ctl_elem_info_get_item_name(info), 63);
|
||
clocksrcName[item][63]=0;
|
||
CTLID_DEBUG(("Clock source id=%d item #%u '%s'\n", numid, item, snd_ctl_elem_info_get_item_name(info)));
|
||
}
|
||
} else if (!strcmp("S/PDIF mode Switch", snd_ctl_elem_id_get_name(id))) {
|
||
spdifmodeId=numid;
|
||
items=snd_ctl_elem_info_get_items(info);
|
||
nspdifmodes=items;
|
||
for (item=0; item<items; item++) {
|
||
snd_ctl_elem_info_set_item(info, item);
|
||
if ((err=snd_hctl_elem_info(elem, info)) < 0) {
|
||
printf("Control %s element info error: %s\n", card, snd_strerror(err));
|
||
}
|
||
strncpy(spdifmodeName[item], snd_ctl_elem_info_get_item_name(info), 63);
|
||
spdifmodeName[item][63]=0;
|
||
CTLID_DEBUG(("S/PDIF Mode id=%d item #%u '%s'\n", numid, item, snd_ctl_elem_info_get_item_name(info)));
|
||
}
|
||
} else if (!strcmp("Phantom power Switch", snd_ctl_elem_id_get_name(id))) {
|
||
phantomId=numid;
|
||
CTLID_DEBUG(("Phantom power Switch id=%d\n", numid));
|
||
} else if (!strcmp("VU-meters Switch", snd_ctl_elem_id_get_name(id))) {
|
||
vuswitchId=numid;
|
||
CTLID_DEBUG(("VU-meter switch id=%d\n", numid));
|
||
} else if (!strcmp("VU-meters", snd_ctl_elem_id_get_name(id))) {
|
||
vumetersId=numid;
|
||
metersStreams=snd_ctl_elem_info_get_dimension(info, 0); // 2 or 3: output, input and (vmixer cards only) pcm
|
||
metersNumber=snd_ctl_elem_info_get_dimension(info, 1); // Number of channels
|
||
metersTypes=snd_ctl_elem_info_get_dimension(info, 2); // 2: level and peak
|
||
CTLID_DEBUG(("VU-meters id=%d\n", numid));
|
||
} else if (!strcmp("Channels info", snd_ctl_elem_id_get_name(id))) {
|
||
channelsId=numid;
|
||
CTLID_DEBUG(("Channels info id=%d\n", numid));
|
||
}
|
||
}
|
||
|
||
GetChannels();
|
||
CTLID_DEBUG(("Input channels = %d (analog=%d digital=%d)\n", nIn, fdIn, nIn-fdIn));
|
||
CTLID_DEBUG(("Output channels = %d (analog=%d digital=%d)\n", nLOut, fdOut, nLOut-fdOut));
|
||
CTLID_DEBUG(("PCM channels out = %d\n", nPOut));
|
||
|
||
#ifndef REAL
|
||
vmixerId=1000;
|
||
vmixerControl.vchannels=12;
|
||
vmixerControl.outputs=mixerControl.outputs=10;
|
||
metersStreams=3;
|
||
metersNumber=16;
|
||
metersTypes=2;
|
||
nPOut=12;
|
||
nLOut=10;
|
||
fdOut=2;
|
||
nIn=10;
|
||
fdIn=2;
|
||
printf("nIn=%d fdIn=%d nLOut=%d nPOut=%d fdOut=%d\n", nIn,fdIn,nLOut,nPOut, fdOut);
|
||
#endif
|
||
|
||
if (mixerId && (mixerControl.inputs!=nIn || mixerControl.outputs!=nLOut)) {
|
||
printf("** Error - Mixer/channels mismatch !! nIn=%d mnIn=%d nLOut=%d mnLOut=%d\n", nIn, mixerControl.inputs, nLOut, mixerControl.outputs);
|
||
return(1);
|
||
}
|
||
if (lineoutId && !vmixerId)
|
||
printf("** Warning - Vmixer cards without LineOut volume control are not supported !\n");
|
||
|
||
if (vmixerId) {
|
||
if (vmixerControl.vchannels!=nPOut || vmixerControl.outputs!=nLOut) {
|
||
printf("** Error - vmixer/channels mismatch: vmp=%d npo=%d vmo=%d nlo=%d !!\n", vmixerControl.vchannels, nPOut, vmixerControl.outputs, nLOut);
|
||
return(1);
|
||
}
|
||
}
|
||
|
||
//@ Assumes all mixer and vmixer controls are contiguous
|
||
if (mixerId)
|
||
for (o=0, numid=mixerId; o<nLOut; o++) {
|
||
for (i=0; i<nIn; i++) {
|
||
mixerControl.mixer[o][i].id=numid++;
|
||
}
|
||
}
|
||
|
||
if (vmixerId)
|
||
for (o=0, numid=vmixerId; o<vmixerControl.outputs; o++) {
|
||
for (i=0; i<vmixerControl.vchannels; i++) {
|
||
vmixerControl.mixer[o][i].id=numid++;
|
||
}
|
||
}
|
||
|
||
snd_hctl_close(handle);
|
||
return(0);
|
||
}
|
||
|
||
|
||
|
||
int main(int argc, char *argv[]) {
|
||
gchar str[256];
|
||
GtkWidget *hbox, *vbox;
|
||
GtkWidget *mainbox;
|
||
GtkWidget *vbsel, *frame, *button;
|
||
GtkWidget *label, *menu, *menuitem;
|
||
GSList *bgroup;
|
||
int err, i, o, n, cardnum, value;
|
||
char hwname[8], cardname[32], load, save;
|
||
snd_ctl_card_info_t *hw_info;
|
||
|
||
load=save=1;
|
||
|
||
// Scans all installed cards
|
||
snd_ctl_card_info_alloca(&hw_info);
|
||
cardnum=-1;
|
||
ctlhandle=0;
|
||
|
||
if (argc>1)
|
||
cardnum=atoi(argv[1])-1;
|
||
|
||
while (snd_card_next(&cardnum)>=0 && cardnum>=0) {
|
||
sprintf(hwname, "hw:%d", cardnum);
|
||
if ((err=snd_ctl_open(&ctlhandle, hwname, 0))<0) {
|
||
printf("snd_ctl_open(%s) Error: %s\n", hwname, snd_strerror(err));
|
||
continue;
|
||
}
|
||
if ((err=snd_ctl_card_info(ctlhandle, hw_info))>=0) {
|
||
if (!strncmp(snd_ctl_card_info_get_driver(hw_info), "Echoaudio", 9)) {
|
||
strncpy(card, hwname, 7);
|
||
hwname[7]=0;
|
||
strncpy(cardname, snd_ctl_card_info_get_name(hw_info), 31);
|
||
cardname[31]=0;
|
||
strncpy(cardId, snd_ctl_card_info_get_name(hw_info), 15);
|
||
cardId[15]=0;
|
||
CTLID_DEBUG(("Card found: %s (%s)\n", snd_ctl_card_info_get_longname(hw_info), hwname));
|
||
/*printf("card = %d\n", snd_ctl_card_info_get_card(hw_info));
|
||
printf("id = %s\n", snd_ctl_card_info_get_id(hw_info));
|
||
printf("driver = %s\n", snd_ctl_card_info_get_driver(hw_info));
|
||
printf("name = %s\n", snd_ctl_card_info_get_name(hw_info));
|
||
printf("longname = %s\n", snd_ctl_card_info_get_longname(hw_info));
|
||
printf("mixername = %s\n", snd_ctl_card_info_get_mixername(hw_info));
|
||
printf("components = %s\n", snd_ctl_card_info_get_components(hw_info));*/
|
||
break;
|
||
}
|
||
} else {
|
||
printf("snd_ctl_card_info(%s) Error: %s\n", hwname, snd_strerror(err));
|
||
}
|
||
snd_ctl_close(ctlhandle);
|
||
ctlhandle=0;
|
||
}
|
||
|
||
if (!ctlhandle) {
|
||
printf("No Echoaudio cards found, sorry.\n");
|
||
return(0);
|
||
}
|
||
|
||
// Reads available controls
|
||
if (OpenControls(card, cardname))
|
||
exit(1);
|
||
|
||
mouseButton=0;
|
||
Gang=0; // Set the gang button off, because has annoying side effects during initialization
|
||
Mainw_geom.st=NOPOS;
|
||
PVw_geom.st=NOPOS;
|
||
LVw_geom.st=NOPOS;
|
||
VUw_geom.st=NOPOS;
|
||
Mixerw_geom.st=NOPOS;
|
||
Vmixerw_geom.st=NOPOS;
|
||
VUwindow=GMwindow=0;
|
||
GMixerSection.Monitor=fdIn+2-1; // The correct value is set by Digital_mode_activate()
|
||
GMixerSection.VmixerFirst=nIn;
|
||
GMixerSection.VmixerLast=nIn+vmixerControl.vchannels-1;
|
||
GMixerSection.LineOut=GMixerSection.VmixerLast+1;
|
||
memset(NominalIn, 0, sizeof(NominalIn));
|
||
memset(NominalOut, 0, sizeof(NominalOut));
|
||
|
||
// Read current mixer setting.
|
||
if (mixerId)
|
||
ReadMixer(&mixerControl);
|
||
if (vmixerId)
|
||
ReadMixer(&vmixerControl);
|
||
if (pcmoutId)
|
||
ReadControl(pcmoutControl.Gain, nPOut, pcmoutControl.id);
|
||
if (lineinId)
|
||
ReadControl(lineinControl.Gain, nIn, lineinControl.id);
|
||
if (lineoutId)
|
||
ReadControl(lineoutControl.Gain, nLOut, lineoutId);
|
||
if (p4InId)
|
||
ReadNominalLevels(NominalIn, p4InId);
|
||
if (p4OutId)
|
||
ReadNominalLevels(NominalOut, p4OutId);
|
||
|
||
//@@ check the values
|
||
if (load) {
|
||
FILE *f;
|
||
snprintf(str, 255, "%s/.Emixer_%s", getenv("HOME"), cardId);
|
||
str[255]=0;
|
||
if ((f=fopen(str, "r"))) {
|
||
str[255]=0;
|
||
while (fgets(str, 255, f)) {
|
||
if (!strncmp("LineOut ", str, 8)) {
|
||
sscanf(str+8, "%d %d", &o, &n);
|
||
if (o>=0 && o<nLOut)
|
||
lineoutControl.Gain[o]=n;
|
||
} else if (!strncmp("LineIn ", str, 7)) {
|
||
sscanf(str+7, "%d %d", &i, &n);
|
||
if (i>=0 && i<nIn)
|
||
lineinControl.Gain[i]=n;
|
||
} else if (!strncmp("PcmOut ", str, 7)) {
|
||
sscanf(str+7, "%d %d", &o, &n);
|
||
if (o>=0 && o<nPOut)
|
||
pcmoutControl.Gain[o]=n;
|
||
} else if (!strncmp("NominalOut ", str, 11)) {
|
||
sscanf(str+11, "%d %d", &o, &n);
|
||
if (o>=0 && o<fdOut)
|
||
NominalOut[o]=!!n;
|
||
} else if (!strncmp("NominalIn ", str, 10)) {
|
||
sscanf(str+10, "%d %d", &i, &n);
|
||
if (i>=0 && i<fdIn)
|
||
NominalIn[i]=!!n;
|
||
} else if (!strncmp("Mixer ", str, 6)) {
|
||
sscanf(str+6, "%d %d %d", &o, &i, &n);
|
||
if (o>=0 && o<nLOut && i>=0 && i<nIn)
|
||
mixerControl.mixer[o][i].Gain=n;
|
||
} else if (!strncmp("Vmixer ", str, 7)) {
|
||
sscanf(str+7, "%d %d %d", &o, &i, &n);
|
||
if (o>=0 && o<nLOut && i>=0 && i<nPOut)
|
||
vmixerControl.mixer[o][i].Gain=n;
|
||
} else if (!strncmp("MainWindow ", str, 11)) {
|
||
sscanf(str+11, "%d %d %d %d", &Mainw_geom.x, &Mainw_geom.y, &Mainw_geom.w, &Mainw_geom.h);
|
||
} else if (!strncmp("VUmetersWindow ", str, 15)) {
|
||
sscanf(str+15, "%d %d %d", &VUw_geom.x, &VUw_geom.y, &VUw_geom.st);
|
||
} else if (!strncmp("GfxMixerWindow ", str, 15)) {
|
||
sscanf(str+15, "%d %d %d", &GMw_geom.x, &GMw_geom.y, &GMw_geom.st);
|
||
} else if (!strncmp("PcmVolumeWindow ", str, 16)) {
|
||
sscanf(str+16, "%d %d %d %d %d", &PVw_geom.x, &PVw_geom.y, &PVw_geom.w, &PVw_geom.h, &PVw_geom.st);
|
||
} else if (!strncmp("LineVolumeWindow ", str, 17)) {
|
||
sscanf(str+17, "%d %d %d %d %d", &LVw_geom.x, &LVw_geom.y, &LVw_geom.w, &LVw_geom.h, &LVw_geom.st);
|
||
} else if (!strncmp("MixerWindow ", str, 12)) {
|
||
sscanf(str+12, "%d %d %d %d %d", &Mixerw_geom.x, &Mixerw_geom.y, &Mixerw_geom.w, &Mixerw_geom.h, &Mixerw_geom.st);
|
||
} else if (!strncmp("VmixerWindow ", str, 13)) {
|
||
sscanf(str+13, "%d %d %d %d %d", &Vmixerw_geom.x, &Vmixerw_geom.y, &Vmixerw_geom.w, &Vmixerw_geom.h, &Vmixerw_geom.st);
|
||
} else if (!strncmp("MiscControlsWindow ", str, 19)) {
|
||
sscanf(str+19, "%d %d %d %d %d", &Miscw_geom.x, &Miscw_geom.y, &Miscw_geom.w, &Miscw_geom.h, &Miscw_geom.st);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
gtk_init(&argc, &argv);
|
||
fnt=gdk_font_load("-misc-fixed-medium-r-*-*-10-*-*-*-*-*-*-*");
|
||
if (!fnt) {
|
||
printf("Cannot find the font\n");
|
||
exit(1);
|
||
}
|
||
|
||
/* Now assemble the control windows */
|
||
|
||
|
||
/* ********** Misc controls window ********** */
|
||
|
||
Miscwindow=gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||
sprintf(str, "%s Misc controls", cardId);
|
||
gtk_window_set_title(GTK_WINDOW(Miscwindow), str);
|
||
gtk_window_set_wmclass(GTK_WINDOW(Miscwindow), "misc", "Emixer");
|
||
gtk_signal_connect(GTK_OBJECT(Miscwindow), "delete_event", GTK_SIGNAL_FUNC(CloseWindow), (gpointer)&Miscw_geom);
|
||
gtk_container_set_border_width(GTK_CONTAINER(Miscwindow), BORDER);
|
||
if (Miscw_geom.st!=NOPOS) {
|
||
gtk_widget_set_uposition(Miscwindow, Miscw_geom.x, Miscw_geom.y);
|
||
gtk_window_set_default_size(GTK_WINDOW(Miscwindow), Miscw_geom.w, Miscw_geom.h);
|
||
}
|
||
|
||
mainbox=gtk_vbox_new(FALSE, SPACING);
|
||
gtk_widget_show(mainbox);
|
||
gtk_container_add(GTK_CONTAINER(Miscwindow), mainbox);
|
||
|
||
|
||
if (p4InId) {
|
||
// Consumer/professional analog input switches
|
||
frame=gtk_frame_new("Input +4dBu");
|
||
gtk_widget_show(frame);
|
||
gtk_box_pack_start(GTK_BOX(mainbox), frame, TRUE, FALSE, 0);
|
||
hbox=gtk_hbox_new(FALSE, 0);
|
||
gtk_widget_show(hbox);
|
||
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
||
|
||
for (i=0; i<fdIn; i++) {
|
||
sprintf(str, "%d", i);
|
||
p4dbuIn[i]=gtk_toggle_button_new_with_label(str);
|
||
gtk_box_pack_start(GTK_BOX(hbox), p4dbuIn[i], TRUE, FALSE, 1);
|
||
gtk_widget_show(p4dbuIn[i]);
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p4dbuIn[i]), NominalIn[i]); // Forces handler call
|
||
gtk_signal_connect(GTK_OBJECT(p4dbuIn[i]), "toggled", GTK_SIGNAL_FUNC(Nominal_level_toggled), (gpointer)i);
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p4dbuIn[i]), !NominalIn[i]);
|
||
}
|
||
}
|
||
|
||
|
||
if (p4OutId) {
|
||
// Consumer/professional analog output switches
|
||
frame=gtk_frame_new("Output +4dBu");
|
||
gtk_widget_show(frame);
|
||
gtk_box_pack_start(GTK_BOX(mainbox), frame, TRUE, FALSE, 0);
|
||
hbox=gtk_hbox_new(FALSE, 0);
|
||
gtk_widget_show(hbox);
|
||
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
||
|
||
for (i=0; i<fdOut; i++) {
|
||
sprintf(str, "%d", i);
|
||
p4dbuOut[i]=gtk_toggle_button_new_with_label(str);
|
||
gtk_box_pack_start(GTK_BOX(hbox), p4dbuOut[i], TRUE, FALSE, 1);
|
||
gtk_widget_show(p4dbuOut[i]);
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p4dbuOut[i]), NominalOut[i]);
|
||
gtk_signal_connect(GTK_OBJECT(p4dbuOut[i]), "toggled", GTK_SIGNAL_FUNC(Nominal_level_toggled), (gpointer)(i+ECHO_MAXAUDIOINPUTS));
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p4dbuOut[i]), !NominalOut[i]);
|
||
}
|
||
}
|
||
|
||
|
||
if (dmodeId && ndmodes>1) {
|
||
// Digital mode switch
|
||
frame=gtk_frame_new("Digital mode");
|
||
gtk_widget_show(frame);
|
||
gtk_box_pack_start(GTK_BOX(mainbox), frame, TRUE, FALSE, 0);
|
||
hbox=gtk_hbox_new(FALSE, 0);
|
||
gtk_widget_show(hbox);
|
||
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
||
|
||
dmodeOpt=gtk_option_menu_new();
|
||
gtk_widget_show(dmodeOpt);
|
||
menu=gtk_menu_new();
|
||
gtk_widget_show(menu);
|
||
for (i=0; i<ndmodes; i++) {
|
||
menuitem=gtk_menu_item_new_with_label(dmodeName[i]);
|
||
gtk_widget_show(menuitem);
|
||
gtk_signal_connect(GTK_OBJECT(menuitem), "activate", Digital_mode_activate, (gpointer)i);
|
||
gtk_menu_append(GTK_MENU(menu), menuitem);
|
||
}
|
||
gtk_option_menu_set_menu(GTK_OPTION_MENU(dmodeOpt), menu);
|
||
gtk_box_pack_start(GTK_BOX(hbox), dmodeOpt, TRUE, TRUE, 0);
|
||
gtk_option_menu_set_history(GTK_OPTION_MENU(dmodeOpt), dmodeVal=GetEnum(dmodeId));
|
||
}
|
||
|
||
|
||
if (clocksrcId && nclocksrc>1) {
|
||
// Clock source switch
|
||
frame=gtk_frame_new("Clock source");
|
||
gtk_widget_show(frame);
|
||
gtk_box_pack_start(GTK_BOX(mainbox), frame, TRUE, FALSE, 0);
|
||
hbox=gtk_hbox_new(FALSE, 0);
|
||
gtk_widget_show(hbox);
|
||
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
||
|
||
clocksrcOpt=gtk_option_menu_new();
|
||
gtk_widget_show(clocksrcOpt);
|
||
menu=gtk_menu_new();
|
||
gtk_widget_show(menu);
|
||
for (i=0; i<nclocksrc; i++) {
|
||
clocksrc_menuitem[i]=gtk_menu_item_new_with_label(clocksrcName[i]);
|
||
gtk_widget_show(clocksrc_menuitem[i]);
|
||
gtk_widget_set_sensitive(clocksrc_menuitem[i], FALSE);
|
||
gtk_signal_connect(GTK_OBJECT(clocksrc_menuitem[i]), "activate", Clock_source_activate, (gpointer)i);
|
||
gtk_menu_append(GTK_MENU(menu), clocksrc_menuitem[i]);
|
||
}
|
||
gtk_option_menu_set_menu(GTK_OPTION_MENU(clocksrcOpt), menu);
|
||
gtk_box_pack_start(GTK_BOX(hbox), clocksrcOpt, TRUE, TRUE, 0);
|
||
gtk_option_menu_set_history(GTK_OPTION_MENU(clocksrcOpt), clocksrcVal=GetEnum(clocksrcId));
|
||
clocksrctimer=gtk_timeout_add(2000, CheckInputs, 0);
|
||
}
|
||
|
||
|
||
if (spdifmodeId && nspdifmodes>1) {
|
||
// S/PDIF mode switch
|
||
frame=gtk_frame_new("S/PDIF mode");
|
||
gtk_widget_show(frame);
|
||
gtk_box_pack_start(GTK_BOX(mainbox), frame, TRUE, FALSE, 0);
|
||
hbox=gtk_hbox_new(FALSE, 0);
|
||
gtk_widget_show(hbox);
|
||
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
||
|
||
spdifmodeOpt=gtk_option_menu_new();
|
||
gtk_widget_show(spdifmodeOpt);
|
||
menu=gtk_menu_new();
|
||
gtk_widget_show(menu);
|
||
for (i=0; i<nspdifmodes; i++) {
|
||
menuitem=gtk_menu_item_new_with_label(spdifmodeName[i]);
|
||
gtk_widget_show(menuitem);
|
||
gtk_signal_connect(GTK_OBJECT(menuitem), "activate", SPDIF_mode_activate, (gpointer)i);
|
||
gtk_menu_append(GTK_MENU(menu), menuitem);
|
||
}
|
||
gtk_option_menu_set_menu(GTK_OPTION_MENU(spdifmodeOpt), menu);
|
||
gtk_box_pack_start(GTK_BOX(hbox), spdifmodeOpt, TRUE, TRUE, 0);
|
||
gtk_option_menu_set_history(GTK_OPTION_MENU(spdifmodeOpt), spdifmodeVal=GetEnum(spdifmodeId));
|
||
}
|
||
|
||
|
||
if (phantomId) {
|
||
// Phantom power switch
|
||
frame=gtk_frame_new("Phantom power");
|
||
gtk_widget_show(frame);
|
||
gtk_box_pack_start(GTK_BOX(mainbox), frame, TRUE, FALSE, 0);
|
||
hbox=gtk_hbox_new(FALSE, 0);
|
||
gtk_widget_show(hbox);
|
||
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
||
|
||
phantomToggle=gtk_toggle_button_new_with_label("On");
|
||
gtk_widget_show(phantomToggle);
|
||
gtk_box_pack_start(GTK_BOX(hbox), phantomToggle, TRUE, FALSE, 0);
|
||
gtk_signal_connect(GTK_OBJECT(phantomToggle), "toggled", PhantomPower_toggled, (gpointer)0);
|
||
InitPhantomPowerGUI(phantomId);
|
||
}
|
||
|
||
|
||
/* ********** PCM volume window ********** */
|
||
|
||
pcmoutControl.window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||
sprintf(str, "%s PCM volume", cardId);
|
||
gtk_window_set_title(GTK_WINDOW (pcmoutControl.window), str);
|
||
gtk_window_set_wmclass(GTK_WINDOW(pcmoutControl.window), "pcm", "Emixer");
|
||
gtk_signal_connect(GTK_OBJECT(pcmoutControl.window), "delete_event", GTK_SIGNAL_FUNC(CloseWindow), (gpointer)&PVw_geom);
|
||
gtk_container_set_border_width(GTK_CONTAINER(pcmoutControl.window), BORDER);
|
||
if (PVw_geom.st!=NOPOS) {
|
||
gtk_widget_set_uposition(pcmoutControl.window, PVw_geom.x, PVw_geom.y);
|
||
gtk_window_set_default_size(GTK_WINDOW(pcmoutControl.window), PVw_geom.w, PVw_geom.h);
|
||
}
|
||
|
||
mainbox=gtk_hbox_new(FALSE, SPACING);
|
||
gtk_widget_show(mainbox);
|
||
gtk_container_add(GTK_CONTAINER(pcmoutControl.window), mainbox);
|
||
|
||
|
||
if (pcmoutId) {
|
||
// PCM Output volume widgets
|
||
frame=gtk_frame_new("PCM Output volume");
|
||
gtk_widget_show(frame);
|
||
gtk_box_pack_start(GTK_BOX(mainbox), frame, TRUE, TRUE, 0);
|
||
hbox=gtk_hbox_new(TRUE, 1);
|
||
gtk_widget_show(hbox);
|
||
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
||
|
||
for (i=0; i<nPOut; i++) {
|
||
vbox=gtk_vbox_new(FALSE, 0);
|
||
gtk_widget_show(vbox);
|
||
gtk_container_add(GTK_CONTAINER(hbox), vbox);
|
||
// Channel label
|
||
if (i<fdOut)
|
||
sprintf(str, "A%d", i);
|
||
else
|
||
sprintf(str, "D%d", i-fdOut);
|
||
label=gtk_label_new(str);
|
||
gtk_widget_show(label);
|
||
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
|
||
// Volume
|
||
value = INVERT(pcmoutControl.Gain[i]);
|
||
pcmoutControl.adj[i]=gtk_adjustment_new(!value, ECHOGAIN_MINOUT, ECHOGAIN_MAXOUT, SHORTSTEP, LONGSTEP, 0);
|
||
pcmoutControl.volume[i]=gtk_vscale_new(GTK_ADJUSTMENT(pcmoutControl.adj[i]));
|
||
gtk_widget_show(pcmoutControl.volume[i]);
|
||
gtk_box_pack_start(GTK_BOX(vbox), pcmoutControl.volume[i], TRUE, TRUE, 0);
|
||
gtk_scale_set_draw_value(GTK_SCALE(pcmoutControl.volume[i]), 0);
|
||
gtk_signal_connect(GTK_OBJECT(pcmoutControl.adj[i]), "value_changed", GTK_SIGNAL_FUNC(PCM_volume_changed), (gpointer)(i+ECHO_MAXAUDIOINPUTS));
|
||
// Value label
|
||
pcmoutControl.label[i]=gtk_label_new("xxx");
|
||
gtk_widget_show(pcmoutControl.label[i]);
|
||
gtk_box_pack_start(GTK_BOX(vbox), pcmoutControl.label[i], FALSE, FALSE, 0);
|
||
gtk_adjustment_set_value(GTK_ADJUSTMENT(pcmoutControl.adj[i]), value);
|
||
}
|
||
gtk_widget_set_usize(GTK_WIDGET(pcmoutControl.volume[0]), 0, 170); // Set minimum y size
|
||
}
|
||
|
||
|
||
/* ********** Line volume window ********** */
|
||
|
||
LVwindow=gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||
sprintf(str, "%s Line volume", cardId);
|
||
gtk_window_set_title(GTK_WINDOW (LVwindow), str);
|
||
gtk_window_set_wmclass(GTK_WINDOW(LVwindow), "line", "Emixer");
|
||
gtk_signal_connect(GTK_OBJECT(LVwindow), "delete_event", GTK_SIGNAL_FUNC(CloseWindow), (gpointer)&LVw_geom);
|
||
gtk_container_set_border_width(GTK_CONTAINER(LVwindow), BORDER);
|
||
if (LVw_geom.st!=NOPOS) {
|
||
gtk_widget_set_uposition(LVwindow, LVw_geom.x, LVw_geom.y);
|
||
gtk_window_set_default_size(GTK_WINDOW(LVwindow), LVw_geom.w, LVw_geom.h);
|
||
}
|
||
|
||
mainbox=gtk_hbox_new(FALSE, SPACING);
|
||
gtk_widget_show(mainbox);
|
||
gtk_container_add(GTK_CONTAINER(LVwindow), mainbox);
|
||
|
||
// Line input volume widgets
|
||
if (lineinId) {
|
||
frame=gtk_frame_new("Analog input volume");
|
||
gtk_widget_show(frame);
|
||
gtk_box_pack_start(GTK_BOX(mainbox), frame, TRUE, TRUE, 0);
|
||
hbox=gtk_hbox_new(TRUE, 1);
|
||
gtk_widget_show(hbox);
|
||
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
||
|
||
for (i=0; i<fdIn; i++) {
|
||
vbox=gtk_vbox_new(FALSE, 0);
|
||
gtk_widget_show(vbox);
|
||
gtk_container_add(GTK_CONTAINER(hbox), vbox);
|
||
// Channel label
|
||
sprintf(str, "%d", i);
|
||
label=gtk_label_new(str);
|
||
gtk_widget_show(label);
|
||
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
|
||
// Volume (resolution is 0.5 dB)
|
||
value = IN_INVERT(lineinControl.Gain[i]);
|
||
lineinControl.adj[i]=gtk_adjustment_new(!value, ECHOGAIN_MININP, ECHOGAIN_MAXINP, SHORTSTEP, LONGSTEP*2, 0);
|
||
lineinControl.volume[i]=gtk_vscale_new(GTK_ADJUSTMENT(lineinControl.adj[i]));
|
||
gtk_widget_show(lineinControl.volume[i]);
|
||
gtk_box_pack_start(GTK_BOX(vbox), lineinControl.volume[i], TRUE, TRUE, 0);
|
||
gtk_scale_set_draw_value(GTK_SCALE(lineinControl.volume[i]), 0);
|
||
gtk_signal_connect(GTK_OBJECT(lineinControl.adj[i]), "value_changed", GTK_SIGNAL_FUNC(PCM_volume_changed), (gpointer)i);
|
||
// Value label
|
||
lineinControl.label[i]=gtk_label_new("xxx");
|
||
gtk_widget_show(lineinControl.label[i]);
|
||
gtk_box_pack_start(GTK_BOX(vbox), lineinControl.label[i], FALSE, FALSE, 0);
|
||
gtk_adjustment_set_value(GTK_ADJUSTMENT(lineinControl.adj[i]), value);
|
||
}
|
||
gtk_widget_set_usize(GTK_WIDGET(lineinControl.volume[0]), 0, 170); // Set minimum y size
|
||
}
|
||
|
||
|
||
// Line output volume widgets
|
||
if (1) {
|
||
frame=gtk_frame_new("Line output volume");
|
||
gtk_widget_show(frame);
|
||
gtk_box_pack_start(GTK_BOX(mainbox), frame, TRUE, TRUE, 0);
|
||
hbox=gtk_hbox_new(TRUE, 1);
|
||
gtk_widget_show(hbox);
|
||
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
||
|
||
for (i=0; i<nLOut; i++) {
|
||
vbox=gtk_vbox_new(FALSE, 0);
|
||
gtk_widget_show(vbox);
|
||
gtk_container_add(GTK_CONTAINER(hbox), vbox);
|
||
// Channel label
|
||
if (i<fdOut)
|
||
sprintf(str, "A%d", i);
|
||
else
|
||
sprintf(str, "D%d", i-fdOut);
|
||
label=gtk_label_new(str);
|
||
gtk_widget_show(label);
|
||
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
|
||
// Volume
|
||
value = INVERT(lineoutControl.Gain[i]);
|
||
lineoutControl.adj[i]=gtk_adjustment_new(!value, ECHOGAIN_MINOUT, ECHOGAIN_MAXOUT, SHORTSTEP, LONGSTEP, 0);
|
||
lineoutControl.volume[i]=gtk_vscale_new(GTK_ADJUSTMENT(lineoutControl.adj[i]));
|
||
gtk_widget_show(lineoutControl.volume[i]);
|
||
gtk_box_pack_start(GTK_BOX(vbox), lineoutControl.volume[i], TRUE, TRUE, 0);
|
||
gtk_scale_set_draw_value(GTK_SCALE(lineoutControl.volume[i]), 0);
|
||
gtk_signal_connect(GTK_OBJECT(lineoutControl.adj[i]), "value_changed", GTK_SIGNAL_FUNC(LineOut_volume_changed), (gpointer)i);
|
||
// Value label
|
||
lineoutControl.label[i]=gtk_label_new("xxx");
|
||
gtk_widget_show(lineoutControl.label[i]);
|
||
gtk_box_pack_start(GTK_BOX(vbox), lineoutControl.label[i], FALSE, FALSE, 0);
|
||
gtk_adjustment_set_value(GTK_ADJUSTMENT(lineoutControl.adj[i]), value);
|
||
}
|
||
gtk_widget_set_usize(GTK_WIDGET(lineoutControl.volume[0]), 0, 170); // Set minimum y size
|
||
}
|
||
|
||
|
||
|
||
/* ********** Mixer window ********** */
|
||
|
||
if (mixerId) {
|
||
mixerControl.window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||
sprintf(str, "%s Monitor mixer", cardId);
|
||
gtk_window_set_title(GTK_WINDOW(mixerControl.window), str);
|
||
gtk_window_set_wmclass(GTK_WINDOW(mixerControl.window), "mixer", "Emixer");
|
||
gtk_signal_connect(GTK_OBJECT(mixerControl.window), "delete_event", GTK_SIGNAL_FUNC(CloseWindow), (gpointer)&Mixerw_geom);
|
||
gtk_container_set_border_width(GTK_CONTAINER(mixerControl.window), BORDER);
|
||
if (Mixerw_geom.st!=NOPOS) {
|
||
gtk_widget_set_uposition(mixerControl.window, Mixerw_geom.x, Mixerw_geom.y);
|
||
gtk_window_set_default_size(GTK_WINDOW(mixerControl.window), Mixerw_geom.w, Mixerw_geom.h);
|
||
// gdk_window_move_resize(mixerControl.window->window, Mixerw_geom.x, Mixerw_geom.y, Mixerw_geom.w, Mixerw_geom.h);
|
||
/* gtk_widget_set_usize(mixerControl.window, Mixerw_geom.w, Mixerw_geom.h);
|
||
gtk_widget_set_usize(mixerControl.window, -1, -1);*/
|
||
}
|
||
|
||
mainbox=gtk_hbox_new(FALSE, SPACING);
|
||
gtk_widget_show(mainbox);
|
||
gtk_container_add(GTK_CONTAINER(mixerControl.window), mainbox);
|
||
|
||
#ifdef REVERSE
|
||
// Mixer volume widgets
|
||
frame=gtk_frame_new("Mixer input levels");
|
||
gtk_widget_show(frame);
|
||
gtk_box_pack_start(GTK_BOX(mainbox), frame, TRUE, TRUE, 0);
|
||
hbox=gtk_hbox_new(TRUE, 1);
|
||
gtk_widget_show(hbox);
|
||
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
||
|
||
for (i=0; i<nIn; i++) {
|
||
vbox=gtk_vbox_new(FALSE, 0);
|
||
gtk_widget_show(vbox);
|
||
gtk_container_add(GTK_CONTAINER(hbox), vbox);
|
||
// Channel label
|
||
if (i<fdIn)
|
||
sprintf(str, "A%d", i);
|
||
else
|
||
sprintf(str, "D%d", i-fdIn);
|
||
label=gtk_label_new(str);
|
||
gtk_widget_show(label);
|
||
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
|
||
// Volume
|
||
mixerControl.adj[i]=gtk_adjustment_new(0, ECHOGAIN_MINOUT, ECHOGAIN_MAXOUT, SHORTSTEP, LONGSTEP, 0);
|
||
mixerControl.volume[i]=gtk_vscale_new(GTK_ADJUSTMENT(mixerControl.adj[i]));
|
||
gtk_widget_show(mixerControl.volume[i]);
|
||
gtk_box_pack_start(GTK_BOX(vbox), mixerControl.volume[i], TRUE, TRUE, 0);
|
||
gtk_scale_set_draw_value(GTK_SCALE(mixerControl.volume[i]), 0);
|
||
gtk_signal_connect(GTK_OBJECT(mixerControl.volume[i]), "grab_focus", GTK_SIGNAL_FUNC(Monitor_volume_clicked), (gpointer)i);
|
||
gtk_signal_connect(GTK_OBJECT(mixerControl.adj[i]), "value_changed", GTK_SIGNAL_FUNC(Monitor_volume_changed), (gpointer)i);
|
||
// Value label
|
||
mixerControl.label[i]=gtk_label_new("xxx");
|
||
gtk_widget_show(mixerControl.label[i]);
|
||
gtk_box_pack_start(GTK_BOX(vbox), mixerControl.label[i], FALSE, FALSE, 0);
|
||
}
|
||
gtk_widget_set_usize(GTK_WIDGET(mixerControl.volume[0]), 0, 170); // Set minimum y size
|
||
|
||
// Output channel selectors
|
||
frame=gtk_frame_new("Mixer output");
|
||
gtk_widget_show(frame);
|
||
vbsel=gtk_vbox_new(FALSE, 2);
|
||
gtk_box_pack_start(GTK_BOX(mainbox), frame, FALSE, FALSE, 0);
|
||
gtk_widget_show(vbsel);
|
||
gtk_container_add(GTK_CONTAINER(frame), vbsel);
|
||
|
||
bgroup=0;
|
||
for (i=n=0; i<nLOut; i++) {
|
||
if (i<fdOut)
|
||
sprintf(str, "An-%d", i);
|
||
else
|
||
sprintf(str, "Di-%d", i-fdOut);
|
||
if (i)
|
||
bgroup=gtk_radio_button_group(GTK_RADIO_BUTTON(mixerControl.outsel[i-1]));
|
||
mixerControl.outsel[i]=gtk_radio_button_new_with_label(bgroup, str);
|
||
gtk_widget_show(mixerControl.outsel[i]);
|
||
gtk_box_pack_start(GTK_BOX(vbsel), mixerControl.outsel[i], FALSE, FALSE, 0);
|
||
gtk_signal_connect(GTK_OBJECT(mixerControl.outsel[i]), "toggled", GTK_SIGNAL_FUNC(Mixer_Output_selector_clicked), (gpointer)i);
|
||
}
|
||
mixerControl.input=0;
|
||
mixerControl.output=-1;
|
||
Mixer_Output_selector_clicked(0, 0);
|
||
|
||
#else // REVERSE
|
||
|
||
// Input channel selectors
|
||
frame=gtk_frame_new("Mixer input");
|
||
gtk_widget_show(frame);
|
||
gtk_box_pack_start(GTK_BOX(mainbox), frame, FALSE, FALSE, 0);
|
||
vbsel=gtk_vbox_new(FALSE, 2);
|
||
gtk_widget_show(vbsel);
|
||
gtk_container_add(GTK_CONTAINER(frame), vbsel);
|
||
|
||
bgroup=0;
|
||
for (i=n=0; i<nIn; i++) {
|
||
if (i<fdIn)
|
||
sprintf(str, "An-%d", i);
|
||
else
|
||
sprintf(str, "Di-%d", i-fdIn);
|
||
if (i)
|
||
bgroup=gtk_radio_button_group(GTK_RADIO_BUTTON(mixerControl.inpsel[i-1]));
|
||
mixerControl.inpsel[i]=gtk_radio_button_new_with_label(bgroup, str);
|
||
gtk_widget_show(mixerControl.inpsel[i]);
|
||
gtk_box_pack_start(GTK_BOX(vbsel), mixerControl.inpsel[i], FALSE, FALSE, 0);
|
||
gtk_signal_connect(GTK_OBJECT(mixerControl.inpsel[i]), "toggled", GTK_SIGNAL_FUNC(Mixer_Input_selector_clicked), (gpointer)i);
|
||
}
|
||
|
||
// Mixer volume widgets
|
||
frame=gtk_frame_new("Mixer output levels");
|
||
gtk_widget_show(frame);
|
||
gtk_box_pack_start(GTK_BOX(mainbox), frame, TRUE, TRUE, 0);
|
||
hbox=gtk_hbox_new(TRUE, 1);
|
||
gtk_widget_show(hbox);
|
||
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
||
|
||
for (i=0; i<nLOut; i++) {
|
||
vbox=gtk_vbox_new(FALSE, 0);
|
||
gtk_widget_show(vbox);
|
||
gtk_container_add(GTK_CONTAINER(hbox), vbox);
|
||
// Channel label
|
||
if (i<fdOut)
|
||
sprintf(str, "A%d", i);
|
||
else
|
||
sprintf(str, "D%d", i-fdOut);
|
||
label=gtk_label_new(str);
|
||
gtk_widget_show(label);
|
||
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
|
||
// Volume
|
||
mixerControl.adj[i]=gtk_adjustment_new(0, ECHOGAIN_MINOUT, ECHOGAIN_MAXOUT, SHORTSTEP, LONGSTEP, 0);
|
||
mixerControl.volume[i]=gtk_vscale_new(GTK_ADJUSTMENT(mixerControl.adj[i]));
|
||
gtk_widget_show(mixerControl.volume[i]);
|
||
gtk_box_pack_start(GTK_BOX(vbox), mixerControl.volume[i], TRUE, TRUE, 0);
|
||
gtk_scale_set_draw_value(GTK_SCALE(mixerControl.volume[i]), 0);
|
||
gtk_signal_connect(GTK_OBJECT(mixerControl.volume[i]), "grab_focus", GTK_SIGNAL_FUNC(Monitor_volume_clicked), (gpointer)i);
|
||
gtk_signal_connect(GTK_OBJECT(mixerControl.adj[i]), "value_changed", GTK_SIGNAL_FUNC(Monitor_volume_changed), (gpointer)i);
|
||
// Value label
|
||
mixerControl.label[i]=gtk_label_new("xxx");
|
||
gtk_widget_show(mixerControl.label[i]);
|
||
gtk_box_pack_start(GTK_BOX(vbox), mixerControl.label[i], FALSE, FALSE, 0);
|
||
}
|
||
gtk_widget_set_usize(GTK_WIDGET(mixerControl.volume[0]), 0, 170); // Set minimum y size
|
||
mixerControl.input=-1;
|
||
mixerControl.output=0;
|
||
Mixer_Input_selector_clicked(0, 0);
|
||
#endif
|
||
}
|
||
|
||
|
||
/* ********** Vmixer window ********** */
|
||
|
||
if (vmixerId) {
|
||
vmixerControl.window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||
sprintf(str, "%s Vmixer", cardId);
|
||
gtk_window_set_title(GTK_WINDOW(vmixerControl.window), str);
|
||
gtk_window_set_wmclass(GTK_WINDOW(vmixerControl.window), "vmixer", "Emixer");
|
||
gtk_signal_connect(GTK_OBJECT(vmixerControl.window), "delete_event", GTK_SIGNAL_FUNC(CloseWindow), (gpointer)&Vmixerw_geom);
|
||
gtk_container_set_border_width(GTK_CONTAINER(vmixerControl.window), BORDER);
|
||
if (Vmixerw_geom.st!=NOPOS) {
|
||
gtk_widget_set_uposition(vmixerControl.window, Vmixerw_geom.x, Vmixerw_geom.y);
|
||
gtk_window_set_default_size(GTK_WINDOW(vmixerControl.window), Vmixerw_geom.w, Vmixerw_geom.h);
|
||
}
|
||
|
||
mainbox=gtk_hbox_new(FALSE, SPACING);
|
||
gtk_widget_show(mainbox);
|
||
gtk_container_add(GTK_CONTAINER(vmixerControl.window), mainbox);
|
||
|
||
#ifdef REVERSE
|
||
|
||
// Vmixer volume widgets
|
||
frame=gtk_frame_new("Vmixer vchannels levels");
|
||
gtk_widget_show(frame);
|
||
gtk_box_pack_start(GTK_BOX(mainbox), frame, TRUE, TRUE, 0);
|
||
hbox=gtk_hbox_new(TRUE, 1);
|
||
gtk_widget_show(hbox);
|
||
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
||
|
||
for (i=0; i<vmixerControl.vchannels; i++) {
|
||
vbox=gtk_vbox_new(FALSE, 0);
|
||
gtk_widget_show(vbox);
|
||
gtk_container_add(GTK_CONTAINER(hbox), vbox);
|
||
// Channel label
|
||
sprintf(str, "V%d", i);
|
||
label=gtk_label_new(str);
|
||
gtk_widget_show(label);
|
||
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
|
||
// Volume
|
||
vmixerControl.adj[i]=gtk_adjustment_new(0, ECHOGAIN_MINOUT, ECHOGAIN_MAXOUT, SHORTSTEP, LONGSTEP, 0);
|
||
vmixerControl.volume[i]=gtk_vscale_new(GTK_ADJUSTMENT(vmixerControl.adj[i]));
|
||
gtk_widget_show(vmixerControl.volume[i]);
|
||
gtk_box_pack_start(GTK_BOX(vbox), vmixerControl.volume[i], TRUE, TRUE, 0);
|
||
gtk_scale_set_draw_value(GTK_SCALE(vmixerControl.volume[i]), 0);
|
||
gtk_signal_connect(GTK_OBJECT(vmixerControl.volume[i]), "grab_focus", GTK_SIGNAL_FUNC(Vmixer_volume_clicked), (gpointer)i);
|
||
gtk_signal_connect(GTK_OBJECT(vmixerControl.adj[i]), "value_changed", GTK_SIGNAL_FUNC(Vmixer_volume_changed), (gpointer)i);
|
||
// Value label
|
||
vmixerControl.label[i]=gtk_label_new("xxx");
|
||
gtk_widget_show(vmixerControl.label[i]);
|
||
gtk_box_pack_start(GTK_BOX(vbox), vmixerControl.label[i], FALSE, FALSE, 0);
|
||
}
|
||
gtk_widget_set_usize(GTK_WIDGET(vmixerControl.volume[0]), 0, 170); // Set minimum y size
|
||
|
||
// Input channel selectors
|
||
frame=gtk_frame_new("Output");
|
||
gtk_widget_show(frame);
|
||
gtk_box_pack_start(GTK_BOX(mainbox), frame, FALSE, FALSE, 0);
|
||
vbsel=gtk_vbox_new(FALSE, 2);
|
||
gtk_widget_show(vbsel);
|
||
gtk_container_add(GTK_CONTAINER(frame), vbsel);
|
||
|
||
bgroup=0;
|
||
for (i=0; i<vmixerControl.outputs; i++) {
|
||
if (i<fdOut)
|
||
sprintf(str, "A%d", i);
|
||
else
|
||
sprintf(str, "D%d", i);
|
||
if (i)
|
||
bgroup=gtk_radio_button_group(GTK_RADIO_BUTTON(vmixerControl.outsel[i-1]));
|
||
vmixerControl.outsel[i]=gtk_radio_button_new_with_label(bgroup, str);
|
||
gtk_widget_show(vmixerControl.outsel[i]);
|
||
gtk_box_pack_start(GTK_BOX(vbsel), vmixerControl.outsel[i], FALSE, FALSE, 0);
|
||
gtk_signal_connect(GTK_OBJECT(vmixerControl.outsel[i]), "toggled", GTK_SIGNAL_FUNC(Vmixer_output_selector_clicked), (gpointer)i);
|
||
}
|
||
vmixerControl.output=-1;
|
||
Vmixer_output_selector_clicked(0, 0);
|
||
|
||
#else // REVERSE
|
||
|
||
// Input channel selectors
|
||
frame=gtk_frame_new("Vchannel");
|
||
gtk_widget_show(frame);
|
||
gtk_box_pack_start(GTK_BOX(mainbox), frame, FALSE, FALSE, 0);
|
||
vbsel=gtk_vbox_new(FALSE, 2);
|
||
gtk_widget_show(vbsel);
|
||
gtk_container_add(GTK_CONTAINER(frame), vbsel);
|
||
|
||
bgroup=0;
|
||
for (i=0; i<vmixerControl.vchannels; i++) {
|
||
sprintf(str, "V%d", i);
|
||
if (i)
|
||
bgroup=gtk_radio_button_group(GTK_RADIO_BUTTON(vmixerControl.vchsel[i-1]));
|
||
vmixerControl.vchsel[i]=gtk_radio_button_new_with_label(bgroup, str);
|
||
gtk_widget_show(vmixerControl.vchsel[i]);
|
||
gtk_box_pack_start(GTK_BOX(vbsel), vmixerControl.vchsel[i], FALSE, FALSE, 0);
|
||
gtk_signal_connect(GTK_OBJECT(vmixerControl.vchsel[i]), "toggled", GTK_SIGNAL_FUNC(Vmixer_vchannel_selector_clicked), (gpointer)i);
|
||
}
|
||
|
||
// Vmixer volume widgets
|
||
frame=gtk_frame_new("Vmixer output levels");
|
||
gtk_widget_show(frame);
|
||
gtk_box_pack_start(GTK_BOX(mainbox), frame, TRUE, TRUE, 0);
|
||
hbox=gtk_hbox_new(TRUE, 1);
|
||
gtk_widget_show(hbox);
|
||
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
||
|
||
for (i=0; i<vmixerControl.outputs; i++) {
|
||
vbox=gtk_vbox_new(FALSE, 0);
|
||
gtk_widget_show(vbox);
|
||
gtk_container_add(GTK_CONTAINER(hbox), vbox);
|
||
// Channel label
|
||
if (i<fdOut)
|
||
sprintf(str, "A%d", i);
|
||
else
|
||
sprintf(str, "D%d", i-fdOut);
|
||
label=gtk_label_new(str);
|
||
gtk_widget_show(label);
|
||
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
|
||
// Volume
|
||
vmixerControl.adj[i]=gtk_adjustment_new(0, ECHOGAIN_MINOUT, ECHOGAIN_MAXOUT, SHORTSTEP, LONGSTEP, 0);
|
||
vmixerControl.volume[i]=gtk_vscale_new(GTK_ADJUSTMENT(vmixerControl.adj[i]));
|
||
gtk_widget_show(vmixerControl.volume[i]);
|
||
gtk_box_pack_start(GTK_BOX(vbox), vmixerControl.volume[i], TRUE, TRUE, 0);
|
||
gtk_scale_set_draw_value(GTK_SCALE(vmixerControl.volume[i]), 0);
|
||
gtk_signal_connect(GTK_OBJECT(vmixerControl.volume[i]), "grab_focus", GTK_SIGNAL_FUNC(Vmixer_volume_clicked), (gpointer)i);
|
||
gtk_signal_connect(GTK_OBJECT(vmixerControl.adj[i]), "value_changed", GTK_SIGNAL_FUNC(Vmixer_volume_changed), (gpointer)i);
|
||
// Value label
|
||
vmixerControl.label[i]=gtk_label_new("xxx");
|
||
gtk_widget_show(vmixerControl.label[i]);
|
||
gtk_box_pack_start(GTK_BOX(vbox), vmixerControl.label[i], FALSE, FALSE, 0);
|
||
}
|
||
gtk_widget_set_usize(GTK_WIDGET(vmixerControl.volume[0]), 0, 170); // Set minimum y size
|
||
vmixerControl.vchannel=-1;
|
||
Vmixer_vchannel_selector_clicked(0, 0);
|
||
#endif
|
||
}
|
||
|
||
|
||
/* ********** Main window ********** */
|
||
|
||
Mainwindow=gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||
sprintf(str, EM_VERSION, cardId);
|
||
gtk_window_set_title(GTK_WINDOW(Mainwindow), str);
|
||
gtk_window_set_wmclass(GTK_WINDOW(Mainwindow), "emixer", "Emixer");
|
||
gtk_signal_connect(GTK_OBJECT(Mainwindow), "delete_event", GTK_SIGNAL_FUNC(Mainwindow_delete), (gpointer)&Mainw_geom);
|
||
gtk_container_set_border_width(GTK_CONTAINER(Mainwindow), BORDER);
|
||
gtk_widget_show(Mainwindow);
|
||
if (Mainw_geom.x!=NOPOS) {
|
||
gtk_widget_set_uposition(Mainwindow, Mainw_geom.x, Mainw_geom.y);
|
||
gtk_window_set_default_size(GTK_WINDOW(Mainwindow), Mainw_geom.w, Mainw_geom.h);
|
||
}
|
||
|
||
mainbox=gtk_hbox_new(FALSE, SPACING);
|
||
gtk_widget_show(mainbox);
|
||
gtk_container_add(GTK_CONTAINER(Mainwindow), mainbox);
|
||
|
||
|
||
// Gang button and its frame
|
||
frame=gtk_frame_new("Gang");
|
||
gtk_widget_show(frame);
|
||
gtk_box_pack_start(GTK_BOX(mainbox), frame, FALSE, FALSE, 0);
|
||
hbox=gtk_hbox_new(FALSE, 0);
|
||
gtk_widget_show(hbox);
|
||
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
||
button=gtk_toggle_button_new_with_label("On");
|
||
gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), 1);
|
||
gtk_widget_show(button);
|
||
gtk_signal_connect(GTK_OBJECT(button), "toggled", Gang_button_toggled, 0);
|
||
|
||
// Controls frame
|
||
frame=gtk_frame_new("Controls");
|
||
gtk_widget_show(frame);
|
||
gtk_box_pack_end(GTK_BOX(mainbox), frame, FALSE, FALSE, 0);
|
||
hbox=gtk_hbox_new(FALSE, 0);
|
||
gtk_widget_show(hbox);
|
||
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
||
|
||
// VUmeters button
|
||
if (vumetersId && vuswitchId) {
|
||
button=gtk_toggle_button_new_with_label("VU");
|
||
gtk_widget_show(button);
|
||
gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 1);
|
||
gtk_signal_connect(GTK_OBJECT(button), "toggled", VUmeters_button_click, 0);
|
||
VUw_geom.toggler=button;
|
||
if (VUw_geom.st==1)
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
|
||
}
|
||
|
||
// Line volume button
|
||
button=gtk_toggle_button_new_with_label("Line");
|
||
gtk_widget_show(button);
|
||
gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 1);
|
||
gtk_signal_connect(GTK_OBJECT(button), "toggled", ToggleWindow, (gpointer)LVwindow);
|
||
LVw_geom.toggler=button;
|
||
if (LVw_geom.st==1)
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
|
||
|
||
// Misc controls button
|
||
button=gtk_toggle_button_new_with_label("Misc");
|
||
gtk_widget_show(button);
|
||
gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 1);
|
||
gtk_signal_connect(GTK_OBJECT(button), "toggled", ToggleWindow, (gpointer)Miscwindow);
|
||
Miscw_geom.toggler=button;
|
||
if (Miscw_geom.st==1)
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
|
||
|
||
if (mixerId) {
|
||
// Graphical mixer button
|
||
button=gtk_toggle_button_new_with_label("GrMix");
|
||
gtk_widget_show(button);
|
||
gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 1);
|
||
gtk_signal_connect(GTK_OBJECT(button), "toggled", GMixer_button_click, 0);
|
||
GMw_geom.toggler=button;
|
||
if (GMw_geom.st==1)
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
|
||
|
||
// Mixer button
|
||
button=gtk_toggle_button_new_with_label("Mixer");
|
||
gtk_widget_show(button);
|
||
gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 1);
|
||
gtk_signal_connect(GTK_OBJECT(button), "toggled", ToggleWindow, (gpointer)mixerControl.window);
|
||
Mixerw_geom.toggler=button;
|
||
if (Mixerw_geom.st==1)
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
|
||
}
|
||
|
||
if (vmixerId) {
|
||
// Vmixer button
|
||
button=gtk_toggle_button_new_with_label("Vmixer");
|
||
gtk_widget_show(button);
|
||
gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 1);
|
||
gtk_signal_connect(GTK_OBJECT(button), "toggled", ToggleWindow, (gpointer)vmixerControl.window);
|
||
Vmixerw_geom.toggler=button;
|
||
if (Vmixerw_geom.st==1)
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
|
||
}
|
||
|
||
if (pcmoutId) {
|
||
// PCM volume button
|
||
button=gtk_toggle_button_new_with_label("PCM");
|
||
gtk_widget_show(button);
|
||
gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 1);
|
||
gtk_signal_connect(GTK_OBJECT(button), "toggled", ToggleWindow, (gpointer)pcmoutControl.window);
|
||
PVw_geom.toggler=button;
|
||
if (PVw_geom.st==1)
|
||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
|
||
}
|
||
|
||
|
||
|
||
|
||
/* ********** GTK-main ********** */
|
||
|
||
Gang=1;
|
||
if (dmodeId)
|
||
Digital_mode_activate(dmodeOpt, (gpointer)dmodeVal); // Also calls SetSensitivity()
|
||
gtk_widget_show(Mainwindow);
|
||
gtk_main();
|
||
|
||
if (save) {
|
||
FILE *f;
|
||
if (snprintf(str, 255, "%s/.Emixer_%s", getenv("HOME"), cardId)>0) {
|
||
str[255]=0;
|
||
if ((f=fopen(str, "w"))) {
|
||
fprintf(f, "-- LineOut <channel> <gain>\n");
|
||
for (i=0; i<nLOut; i++)
|
||
fprintf(f, "LineOut %2d %d\n", i, lineoutControl.Gain[i]);
|
||
fprintf(f, "-- LineIn <channel> <gain>\n");
|
||
for (i=0; i<nIn; i++)
|
||
fprintf(f, "LineIn %2d %d\n", i, lineinControl.Gain[i]);
|
||
fprintf(f, "-- PcmOut <channel> <gain>\n");
|
||
for (i=0; i<nPOut; i++)
|
||
fprintf(f, "PcmOut %2d %d\n", i, pcmoutControl.Gain[i]);
|
||
if (p4InId) {
|
||
fprintf(f, "-- NominalIn <channel> <consumer level enabled>\n");
|
||
for (i=0; i<fdIn; i++)
|
||
fprintf(f, "NominalIn %2d %d\n", i, NominalIn[i]);
|
||
}
|
||
if (p4OutId) {
|
||
fprintf(f, "-- NominalOut <channel> <consumer level enabled>\n");
|
||
for (o=0; o<fdOut; o++)
|
||
fprintf(f, "NominalOut %2d %d\n", o, NominalOut[o]);
|
||
}
|
||
if (mixerId) {
|
||
fprintf(f, "-- Mixer <output> <input> <gain>\n");
|
||
for (o=0; o<nLOut; o++)
|
||
for (i=0; i<nIn; i++)
|
||
fprintf(f, "Mixer %2d %2d %d\n", o, i, mixerControl.mixer[o][i].Gain);
|
||
}
|
||
if (vmixerId) {
|
||
fprintf(f, "-- Vmixer <output> <vchannel> <gain>\n");
|
||
for (o=0; o<nLOut; o++)
|
||
for (i=0; i<nPOut; i++)
|
||
fprintf(f, "Vmixer %2d %2d %d\n", o, i, vmixerControl.mixer[o][i].Gain);
|
||
}
|
||
fprintf(f, "-- xxWindow <x> <y> <width> <height> <visible>\n");
|
||
fprintf(f, "MainWindow %d %d %d %d\n", Mainw_geom.x, Mainw_geom.y, Mainw_geom.w, Mainw_geom.h);
|
||
if (VUwindow)
|
||
gdk_window_get_root_origin(VUwindow->window, &VUw_geom.x, &VUw_geom.y);
|
||
fprintf(f, "VUmetersWindow %d %d %d\n", VUw_geom.x, VUw_geom.y, VUw_geom.st);
|
||
if (GMwindow)
|
||
gdk_window_get_root_origin(GMwindow->window, &VUw_geom.x, &VUw_geom.y);
|
||
fprintf(f, "GfxMixerWindow %d %d %d\n", GMw_geom.x, GMw_geom.y, GMw_geom.st);
|
||
if (pcmoutId) {
|
||
if (pcmoutControl.window->window) {
|
||
gdk_window_get_root_origin(pcmoutControl.window->window, &PVw_geom.x, &PVw_geom.y);
|
||
gdk_window_get_size(pcmoutControl.window->window, &PVw_geom.w, &PVw_geom.h);
|
||
}
|
||
fprintf(f, "PcmVolumeWindow %d %d %d %d %d\n", PVw_geom.x, PVw_geom.y, PVw_geom.w, PVw_geom.h, !!GTK_WIDGET_VISIBLE(pcmoutControl.window));
|
||
}
|
||
if (LVwindow->window) {
|
||
gdk_window_get_root_origin(LVwindow->window, &LVw_geom.x, &LVw_geom.y);
|
||
gdk_window_get_size(LVwindow->window, &LVw_geom.w, &LVw_geom.h);
|
||
}
|
||
fprintf(f, "LineVolumeWindow %d %d %d %d %d\n", LVw_geom.x, LVw_geom.y, LVw_geom.w, LVw_geom.h, !!GTK_WIDGET_VISIBLE(LVwindow));
|
||
if (Miscwindow->window) {
|
||
gdk_window_get_root_origin(Miscwindow->window, &Miscw_geom.x, &Miscw_geom.y);
|
||
gdk_window_get_size(Miscwindow->window, &Miscw_geom.w, &Miscw_geom.h);
|
||
}
|
||
fprintf(f, "MiscControlsWindow %d %d %d %d %d\n", Miscw_geom.x, Miscw_geom.y, Miscw_geom.w, Miscw_geom.h, !!GTK_WIDGET_VISIBLE(Miscwindow));
|
||
if (mixerId) {
|
||
if (mixerControl.window->window) {
|
||
gdk_window_get_root_origin(mixerControl.window->window, &Mixerw_geom.x, &Mixerw_geom.y);
|
||
gdk_window_get_size(mixerControl.window->window, &Mixerw_geom.w, &Mixerw_geom.h);
|
||
}
|
||
fprintf(f, "MixerWindow %d %d %d %d %d\n", Mixerw_geom.x, Mixerw_geom.y, Mixerw_geom.w, Mixerw_geom.h, !!GTK_WIDGET_VISIBLE(mixerControl.window));
|
||
}
|
||
if (vmixerId) {
|
||
if (vmixerControl.window->window) {
|
||
gdk_window_get_root_origin(vmixerControl.window->window, &Vmixerw_geom.x, &Vmixerw_geom.y);
|
||
gdk_window_get_size(vmixerControl.window->window, &Vmixerw_geom.w, &Vmixerw_geom.h);
|
||
}
|
||
fprintf(f, "VmixerWindow %d %d %d %d %d\n", Vmixerw_geom.x, Vmixerw_geom.y, Vmixerw_geom.w, Vmixerw_geom.h, !!GTK_WIDGET_VISIBLE(vmixerControl.window));
|
||
}
|
||
fprintf(f, "\n");
|
||
fclose(f);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (VUwindow) {
|
||
SetVUmeters(0);
|
||
gtk_timeout_remove(VUtimer);
|
||
}
|
||
if (GMwindow) {
|
||
SetVUmeters(0);
|
||
gtk_timeout_remove(Mixtimer);
|
||
}
|
||
snd_ctl_close(ctlhandle);
|
||
return(0);
|
||
}
|
||
|