Changes reflecting the new control API and kernel mixer API removal.

This commit is contained in:
Jaroslav Kysela 2000-07-15 10:21:59 +00:00
parent 54164096e3
commit 9d5b8f205d
8 changed files with 627 additions and 2993 deletions

View file

@ -79,11 +79,7 @@ static int store_setup(const char *cardname)
soundcard_setup_init();
for (idx = 0; idx < 32; idx++) {
if (card_mask & (1 << idx)) { /* find each installed soundcards */
if ((err = soundcard_setup_collect_switches(idx))) {
soundcard_setup_done();
return err;
}
if ((err = soundcard_setup_collect_data(idx))) {
if ((err = soundcard_setup_collect_controls(idx))) {
soundcard_setup_done();
return err;
}
@ -99,11 +95,7 @@ static int store_setup(const char *cardname)
error("Cannot find soundcard '%s'...", cardname);
return 1;
}
if ((err = soundcard_setup_collect_switches(cardno))) {
soundcard_setup_done();
return err;
}
if ((err = soundcard_setup_collect_data(cardno))) {
if ((err = soundcard_setup_collect_controls(cardno))) {
soundcard_setup_done();
return err;
}
@ -126,27 +118,15 @@ static int restore_setup(const char *cardname)
}
if ((err = soundcard_setup_load(cfgfile, 0)))
return err;
if ((err = soundcard_setup_collect_switches(cardno))) {
if ((err = soundcard_setup_collect_controls(cardno))) {
soundcard_setup_done();
return err;
}
if ((err = soundcard_setup_merge_switches(cardno))) {
if ((err = soundcard_setup_merge_controls(cardno))) {
soundcard_setup_done();
return err;
}
if ((err = soundcard_setup_process_switches(cardno))) {
soundcard_setup_done();
return err;
}
if ((err = soundcard_setup_collect_data(cardno))) {
soundcard_setup_done();
return err;
}
if ((err = soundcard_setup_merge_data(cardno))) {
soundcard_setup_done();
return err;
}
if ((err = soundcard_setup_process_data(cardno))) {
if ((err = soundcard_setup_process_controls(cardno))) {
soundcard_setup_done();
return err;
}

View file

@ -37,53 +37,22 @@ extern int debugflag;
extern void error(const char *fmt,...);
struct ctl_switch {
struct ctl_control {
int change;
snd_switch_t s;
struct ctl_switch *next;
snd_control_type_t type;
snd_control_info_t info;
snd_control_t c;
struct ctl_control *next;
};
struct ctl {
snd_ctl_hw_info_t hwinfo;
struct ctl_switch *switches;
};
struct mixer_element {
snd_mixer_element_info_t info;
snd_mixer_element_t element;
struct mixer_element *next;
};
struct mixer {
int no;
snd_mixer_info_t info;
struct mixer_element *elements;
struct ctl_switch *switches;
struct mixer *next;
};
struct pcm {
int no;
snd_pcm_info_t info;
struct ctl_switch *pswitches;
struct ctl_switch *rswitches;
struct pcm *next;
};
struct rawmidi {
int no;
snd_rawmidi_info_t info;
struct ctl_switch *iswitches;
struct ctl_switch *oswitches;
struct rawmidi *next;
struct ctl_control *controls;
};
struct soundcard {
int no; /* card number */
struct ctl control;
struct mixer *mixers;
struct pcm *pcms;
struct rawmidi *rawmidis;
struct soundcard *next;
};
@ -94,11 +63,8 @@ void soundcard_setup_init(void);
void soundcard_setup_done(void);
int soundcard_setup_load(const char *filename, int skip);
int soundcard_setup_write(const char *filename, int cardno);
int soundcard_setup_collect_switches(int cardno);
int soundcard_setup_collect_data(int cardno);
int soundcard_setup_merge_switches(int cardno);
int soundcard_setup_merge_data(int cardno);
int soundcard_setup_process_switches(int cardno);
int soundcard_setup_process_data(int cardno);
int soundcard_setup_collect_controls(int cardno);
int soundcard_setup_merge_controls(int cardno);
int soundcard_setup_process_controls(int cardno);
char *mixer_element_id(snd_mixer_eid_t *eid);
char *control_id(snd_control_id_t *id);

View file

@ -53,53 +53,14 @@ int linecount;
soundcard return L_SOUNDCARD;
control return L_CONTROL;
global return L_GLOBAL;
hwdep return L_HWDEP;
mixer return L_MIXER;
element return L_ELEMENT;
switch return L_SWITCH;
rawdata return L_RAWDATA;
pcm return L_PCM;
rawmidi return L_RAWMIDI;
playback return L_PLAYBACK;
capture return L_CAPTURE;
output return L_OUTPUT;
input return L_INPUT;
iec958ocs return L_IEC958OCS;
3d return L_3D;
reset return L_RESET;
user return L_USER;
valid return L_VALID;
data return L_DATA;
protect return L_PROTECT;
pre2 return L_PRE2;
fsunlock return L_FSUNLOCK;
type return L_TYPE;
gstatus return L_GSTATUS;
enable return L_ENABLE;
disable return L_DISABLE;
sw return L_SW;
mono_sw return L_MONO_SW;
wide return L_WIDE;
volume return L_VOLUME;
center return L_CENTER;
space return L_SPACE;
depth return L_DEPTH;
delay return L_DELAY;
feedback return L_FEEDBACK;
depth_rear return L_DEPTH_REAR;
bass return L_BASS;
treble return L_TREBLE;
/* element types */
Switch1 return L_SWITCH1;
Switch2 return L_SWITCH2;
Switch3 return L_SWITCH3;
Volume1 return L_VOLUME1;
Accu3 return L_ACCU3;
Mux1 return L_MUX1;
Mux2 return L_MUX2;
ToneControl1 return L_TONE_CONTROL1;
_3D_Effect1 return L_3D_EFFECT1;
timer return L_TIMER;
sequencer return L_SEQUENCER;
/* boolean */
@ -108,10 +69,8 @@ true|on|yes return L_TRUE;
/* integers */
[0-9]+ { yylval.i_value = atoi(yytext); return L_INTEGER; }
0x[0-9a-f]+ { char *end;
yylval.i_value = strtol(yytext, &end, 0);
return L_INTEGER; }
[0-9]+ { yylval.i_value = strtol(yytext, (char **)NULL, 10); return L_INTEGER; }
0x[0-9a-f]+ { yylval.i_value = strtol(yytext, (char **)NULL, 0); return L_INTEGER; }
/* byte array */

View file

@ -44,54 +44,18 @@ struct bytearray {
static void yyerror(char *, ...);
static void build_soundcard(char *name);
static void build_mixer(char *name);
static void build_pcm(char *name);
static void build_rawmidi(char *name);
static void build_mixer_element(char *name, int index, int etype);
static void build_control_switch(char *name);
static void build_mixer_switch(char *name);
static void build_pcm_playback_switch(char *name);
static void build_pcm_capture_switch(char *name);
static void build_rawmidi_output_switch(char *name);
static void build_rawmidi_input_switch(char *name);
static void mixer_switch1(int end);
static void mixer_switch1_value(int val);
static void mixer_switch2(int end);
static void mixer_switch2_value(int val);
static void mixer_switch3(int end);
static void mixer_switch3_value(int val);
static void mixer_volume1(int end);
static void mixer_volume1_value(int val);
static void mixer_3d_effect1(int end);
static void mixer_3d_effect1_value(unsigned int effect, int val);
static void mixer_accu3(int end);
static void mixer_accu3_value(int val);
static void mixer_mux1(int end);
static void mixer_mux1_value(char *str, int index, int type);
static void mixer_mux2(int end);
static void mixer_mux2_value(char *str, int index, int type);
static void mixer_tone_control1(int end);
static void mixer_tone_control1_value(unsigned int effect, int val);
static void set_switch_boolean(int val);
static void set_switch_integer(int val);
static void set_switch_bytearray(struct bytearray val);
static void set_switch_iec958ocs_begin(int end);
static void set_switch_iec958ocs(int idx, unsigned short val, unsigned short mask);
static void build_control_begin(int iface, unsigned int device, unsigned int subdevice, char *name, unsigned int index);
static void build_control_end(void);
static void set_control_boolean(int val);
static void set_control_integer(long val);
static void set_control_bytearray(struct bytearray val);
/* local variables */
static struct soundcard *Xsoundcard = NULL;
static struct mixer *Xmixer = NULL;
static struct pcm *Xpcm = NULL;
static struct rawmidi *Xrawmidi = NULL;
static struct mixer_element *Xelement = NULL;
static struct ctl_switch *Xswitch = NULL;
static unsigned int Xswitchiec958ocs = 0;
static unsigned short Xswitchiec958ocs1[16];
static struct ctl_control *Xcontrol = NULL;
static int Xposition = 0;
static snd_control_type_t Xtype = SND_CONTROL_TYPE_NONE;
%}
@ -99,7 +63,7 @@ static unsigned short Xswitchiec958ocs1[16];
%union {
int b_value;
int i_value;
long i_value;
char *s_value;
struct bytearray a_value;
};
@ -116,19 +80,12 @@ static unsigned short Xswitchiec958ocs1[16];
/* misc */
%token L_DOUBLE1
/* other keywords */
%token L_SOUNDCARD L_MIXER L_ELEMENT L_SWITCH L_RAWDATA
%token L_CONTROL L_PCM L_RAWMIDI L_PLAYBACK L_CAPTURE L_INPUT L_OUTPUT
%token L_SWITCH1 L_SWITCH2 L_SWITCH3 L_VOLUME1 L_3D_EFFECT1 L_ACCU3
%token L_MUX1 L_MUX2 L_TONE_CONTROL1
%token L_IEC958OCS L_3D L_RESET L_USER L_VALID L_DATA L_PROTECT L_PRE2
%token L_FSUNLOCK L_TYPE L_GSTATUS L_ENABLE L_DISABLE
%token L_SW L_MONO_SW L_WIDE L_VOLUME L_CENTER L_SPACE L_DEPTH L_DELAY
%token L_DEPTH_REAR
%token L_FEEDBACK L_BASS L_TREBLE
%token L_SOUNDCARD L_CONTROL L_RAWDATA
%token L_GLOBAL L_HWDEP L_MIXER L_PCM L_RAWMIDI L_TIMER L_SEQUENCER
%type <b_value> boolean
%type <i_value> integer
%type <i_value> integer iface
%type <s_value> string
%type <a_value> rawdata
@ -147,224 +104,31 @@ soundcards :
| soundcards soundcard
;
soundcard : L_CONTROL '{' controls '}'
| L_MIXER '(' string { build_mixer($3); }
L_DOUBLE1 mixers '}' { build_mixer(NULL); }
| L_PCM '(' string { build_pcm($3); }
L_DOUBLE1 pcms '}' { build_pcm(NULL); }
| L_RAWMIDI '(' string { build_rawmidi($3); }
L_DOUBLE1 rawmidis '}' { build_rawmidi(NULL); }
soundcard : L_CONTROL '(' iface ',' integer ',' integer ',' string ',' integer
{ build_control_begin($3, $5, $7, $9, $11); }
',' controls ')' { build_control_end(); }
| error { yyerror( "an unknown keyword in the soundcard{} level"); }
;
controls : control
| controls control
| controls ',' control
;
control : L_SWITCH '(' string { build_control_switch($3); }
',' switches ')' { build_control_switch(NULL); }
| error { yyerror("an unknown keyword in the control{} level"); }
control : boolean { set_control_boolean($1); }
| integer { set_control_integer($1); }
| rawdata { set_control_bytearray($1); }
| error { yyerror( "an unknown keyword in the control() data parameter" ); }
;
mixers : /* empty */
| mixers mixer
;
mixer : L_ELEMENT '(' string
',' integer ',' integer { build_mixer_element($3, $5, $7); }
',' etype ')' { build_mixer_element(NULL, -1, -1); }
| L_SWITCH '(' string { build_mixer_switch($3); }
',' switches ')' { build_mixer_switch(NULL); }
| error { yyerror("an unknown keyword in the mixer level"); }
;
etype : L_SWITCH1 '(' { mixer_switch1(0); }
m_switch1 ')' { mixer_switch1(1); }
| L_SWITCH2 '(' { mixer_switch2(0); }
m_switch2 ')' { mixer_switch2(1); }
| L_SWITCH3 '(' { mixer_switch3(0); }
m_switch3 ')' { mixer_switch3(1); }
| L_VOLUME1 '(' { mixer_volume1(0); }
m_volume1 ')' { mixer_volume1(1); }
| L_3D_EFFECT1 '(' { mixer_3d_effect1(0); }
m_3d_effect1 ')' { mixer_3d_effect1(1); }
| L_ACCU3 '(' { mixer_accu3(0); }
m_accu3 ')' { mixer_accu3(1); }
| L_MUX1 '(' { mixer_mux1(0); }
m_mux1 ')' { mixer_mux1(1); }
| L_MUX2 '(' { mixer_mux2(0); }
L_ELEMENT '('
string ','
integer ','
integer ')' { mixer_mux2_value($6, $8, $10); }
')' { mixer_mux2(1); }
| L_TONE_CONTROL1 '(' { mixer_tone_control1(0); }
m_tone_control1 ')' { mixer_tone_control1(1); }
| error { yyerror("an unknown keyword in the mixer element level"); }
;
m_switch1 : m_switch1_0
| m_switch1 ',' m_switch1_0
;
m_switch1_0 : boolean { mixer_switch1_value($1); }
| error { yyerror("an unknown keyword in the Switch1 element level"); }
;
m_switch2 : m_switch2_0
| m_switch2 ',' m_switch2_0
;
m_switch2_0 : boolean { mixer_switch2_value($1); }
| error { yyerror("an unknown keyword in the Switch2 element level"); }
;
m_switch3 : m_switch3_0
| m_switch3 ',' m_switch3_0
;
m_switch3_0 : boolean { mixer_switch3_value($1); }
| error { yyerror("an unknown keyword in the Switch3 element level"); }
;
m_volume1 : m_volume1_0
| m_volume1 ',' m_volume1_0
;
m_volume1_0 : integer { mixer_volume1_value($1); }
| error { yyerror("an unknown keyword in the Volume1 element level"); }
;
m_3d_effect1 : m_3d_effect1_0
| m_3d_effect1 ',' m_3d_effect1_0
;
m_3d_effect1_0 : L_SW '=' boolean { mixer_3d_effect1_value(SND_MIXER_EFF1_SW, $3); }
| L_MONO_SW '=' boolean { mixer_3d_effect1_value(SND_MIXER_EFF1_MONO_SW, $3); }
| L_WIDE '=' integer { mixer_3d_effect1_value(SND_MIXER_EFF1_WIDE, $3); }
| L_VOLUME '=' integer { mixer_3d_effect1_value(SND_MIXER_EFF1_VOLUME, $3); }
| L_CENTER '=' integer { mixer_3d_effect1_value(SND_MIXER_EFF1_CENTER, $3); }
| L_SPACE '=' integer { mixer_3d_effect1_value(SND_MIXER_EFF1_SPACE, $3); }
| L_DEPTH '=' integer { mixer_3d_effect1_value(SND_MIXER_EFF1_DEPTH, $3); }
| L_DELAY '=' integer { mixer_3d_effect1_value(SND_MIXER_EFF1_DELAY, $3); }
| L_FEEDBACK '=' integer { mixer_3d_effect1_value(SND_MIXER_EFF1_FEEDBACK, $3); }
| L_DEPTH_REAR '=' integer { mixer_3d_effect1_value(SND_MIXER_EFF1_DEPTH_REAR, $3); }
| error { yyerror("an unknown keyword in the 3D Effect1 element level"); }
;
m_accu3 : m_accu3_0
| m_accu3 ',' m_accu3_0
;
m_accu3_0 : integer { mixer_accu3_value($1); }
| error { yyerror("an unknown keyword in the Accu3 element level"); }
;
m_mux1 : m_mux1_0
| m_mux1 ',' m_mux1_0
;
m_mux1_0 : L_ELEMENT '(' string
',' integer ','
integer ')' { mixer_mux1_value($3, $5, $7); }
| error { yyerror("an unknown keyword in the Mux1 element level"); }
;
m_tone_control1 : m_tone_control1_0
| m_tone_control1 ',' m_tone_control1_0
;
m_tone_control1_0 : L_SW '=' boolean { mixer_tone_control1_value(SND_MIXER_TC1_SW, $3); }
| L_BASS '=' integer { mixer_tone_control1_value(SND_MIXER_TC1_BASS, $3); }
| L_TREBLE '=' integer { mixer_tone_control1_value(SND_MIXER_TC1_TREBLE, $3); }
| error { yyerror("an unknown keyword in the ToneControl1 element level"); }
;
pcms : pcm
| pcms pcm
;
pcm : L_PLAYBACK '{' playbacks '}'
| L_CAPTURE '{' captures '}'
| error { yyerror("an unknown keyword in the pcm{} section"); }
;
playbacks : playback
| playbacks playback
;
playback : L_SWITCH '(' string { build_pcm_playback_switch($3); }
',' switches ')' { build_pcm_playback_switch(NULL); }
| error { yyerror("an unknown keyword in the playback{} section"); }
;
captures : capture
| captures capture
;
capture : L_SWITCH '(' string { build_pcm_capture_switch($3); }
',' switches ')' { build_pcm_capture_switch(NULL); }
| error { yyerror("an unknown keyword in the capture{} section"); }
;
rawmidis : rawmidi
| rawmidis rawmidi
;
rawmidi : L_INPUT '{' inputs '}'
| L_OUTPUT '{' outputs '}'
;
inputs : input
| inputs input
;
input : L_SWITCH '(' string { build_rawmidi_input_switch($3); }
',' switches ')' { build_rawmidi_input_switch(NULL); }
| error { yyerror( "an unknown keyword in the input{} section" ); }
;
outputs : output
| outputs output
;
output : L_SWITCH '(' string { build_rawmidi_output_switch($3); }
',' switches ')' { build_rawmidi_output_switch(NULL); }
| error { yyerror( "an unknown keyword in the output{} section" ); }
;
switches : switch
| switches switch
;
switch : boolean { set_switch_boolean($1); }
| integer { set_switch_integer($1); }
| L_IEC958OCS '(' { set_switch_iec958ocs_begin(0); }
iec958ocs ')' { set_switch_iec958ocs_begin(1); }
| rawdata { set_switch_bytearray($1); }
| error { yyerror( "an unknown keyword in the switch() data parameter" ); }
;
iec958ocs : iec958ocs1
| iec958ocs ',' iec958ocs1
;
iec958ocs1 : L_ENABLE { set_switch_iec958ocs( 0, 1, 0 ); }
| L_DISABLE { set_switch_iec958ocs( 0, 0, 0 ); }
| L_3D { set_switch_iec958ocs( 4, 0x2000, ~0x2000 ); }
| L_RESET { set_switch_iec958ocs( 4, 0x0040, ~0x0040 ); }
| L_USER { set_switch_iec958ocs( 4, 0x0020, ~0x0020 ); }
| L_VALID { set_switch_iec958ocs( 4, 0x0010, ~0x0010 ); }
| L_DATA { set_switch_iec958ocs( 5, 0x0002, ~0x0002 ); }
| L_PROTECT { set_switch_iec958ocs( 5, 0, ~0x0004 ); }
| L_PRE2 { set_switch_iec958ocs( 5, 0x0008, ~0x0018 ); }
| L_FSUNLOCK { set_switch_iec958ocs( 5, 0x0020, ~0x0020 ); }
| L_TYPE '(' integer ')' { set_switch_iec958ocs( 5, ($3 & 0x7f) << 6, ~(0x7f<<6) ); }
| L_GSTATUS { set_switch_iec958ocs( 5, 0x2000, ~0x2000 ); }
| error { yyerror( "an unknown keyword in the iec958ocs1() arguments" ); }
iface : L_INTEGER { $$ = $1; }
| L_GLOBAL { $$ = SND_CONTROL_IFACE_CARD; }
| L_HWDEP { $$ = SND_CONTROL_IFACE_HWDEP; }
| L_MIXER { $$ = SND_CONTROL_IFACE_MIXER; }
| L_PCM { $$ = SND_CONTROL_IFACE_PCM; }
| L_RAWMIDI { $$ = SND_CONTROL_IFACE_RAWMIDI; }
| L_TIMER { $$ = SND_CONTROL_IFACE_TIMER; }
| L_SEQUENCER { $$ = SND_CONTROL_IFACE_SEQUENCER; }
| error { yyerror( "an unknown keyword in the interface field"); }
;
boolean : L_TRUE { $$ = 1; }
@ -426,425 +190,86 @@ static void build_soundcard(char *name)
free(name);
}
static void build_mixer(char *name)
static void build_control_begin(int iface, unsigned int device, unsigned int subdevice, char *name, unsigned int index)
{
struct mixer *mixer;
struct ctl_control **first;
struct ctl_control *ctl;
if (!name) {
Xmixer = NULL;
return;
}
Xmixer = (struct mixer *)malloc(sizeof(struct pcm));
if (!Xmixer) {
first = &Xsoundcard->control.controls;
Xcontrol = (struct ctl_control *)malloc(sizeof(struct ctl_control));
if (!Xcontrol) {
free(name);
error_nomem();
return;
}
bzero(Xmixer, sizeof(*Xmixer));
for (mixer = Xsoundcard->mixers; mixer && mixer->next; mixer = mixer->next);
if (mixer) {
mixer->next = Xmixer;
Xposition = 0;
Xtype = SND_CONTROL_TYPE_NONE;
bzero(Xcontrol, sizeof(*Xcontrol));
for (ctl = *first; ctl && ctl->next; ctl = ctl->next);
if (ctl) {
ctl->next = Xcontrol;
} else {
Xsoundcard->mixers = Xmixer;
*first = Xcontrol;
}
strncpy(Xmixer->info.name, name, sizeof(Xmixer->info.name));
Xcontrol->c.id.iface = iface;
Xcontrol->c.id.device = device;
Xcontrol->c.id.subdevice = subdevice;
strncpy(Xcontrol->c.id.name, name, sizeof(Xcontrol->c.id.name));
Xcontrol->c.id.index = index;
free(name);
}
static void build_pcm(char *name)
static void build_control_end(void)
{
struct pcm *pcm;
if (!name) {
Xpcm = NULL;
return;
}
Xpcm = (struct pcm *)malloc(sizeof(struct pcm));
if (!Xpcm) {
free(name);
error_nomem();
return;
}
bzero(Xpcm, sizeof(*Xpcm));
for (pcm = Xsoundcard->pcms; pcm && pcm->next; pcm = pcm->next);
if (pcm) {
pcm->next = Xpcm;
} else {
Xsoundcard->pcms = Xpcm;
}
strncpy(Xpcm->info.name, name, sizeof(Xpcm->info.name));
free(name);
Xcontrol = NULL;
}
static void build_rawmidi(char *name)
static void set_control_boolean(int val)
{
struct rawmidi *rawmidi;
if (!name) {
Xrawmidi = NULL;
return;
}
Xrawmidi = (struct rawmidi *)malloc(sizeof(struct rawmidi));
if (!Xrawmidi) {
free(name);
error_nomem();
return;
}
bzero(Xrawmidi, sizeof(*Xrawmidi));
for (rawmidi = Xsoundcard->rawmidis; rawmidi && rawmidi->next; rawmidi = rawmidi->next);
if (rawmidi) {
rawmidi->next = Xrawmidi;
} else {
Xsoundcard->rawmidis = Xrawmidi;
}
strncpy(Xrawmidi->info.name, name, sizeof(Xrawmidi->info.name));
free(name);
}
static void build_mixer_element(char *name, int index, int etype)
{
struct mixer_element *element;
if (!name) {
Xelement = NULL;
return;
}
Xelement = (struct mixer_element *)malloc(sizeof(struct mixer_element));
if (!Xelement) {
free(name);
error_nomem();
return;
}
bzero(Xelement, sizeof(*Xelement));
for (element = Xmixer->elements; element && element->next; element = element->next);
if (element) {
element->next = Xelement;
} else {
Xmixer->elements = Xelement;
}
strncpy(Xelement->element.eid.name, name, sizeof(Xelement->element.eid.name));
Xelement->element.eid.index = index;
Xelement->element.eid.type = etype;
Xelement->info.eid = Xelement->element.eid;
free(name);
}
static void mixer_type_check(int type)
{
if (Xelement->element.eid.type != type)
yyerror("The element has got the unexpected data type.");
}
static void mixer_switch1(int end)
{
mixer_type_check(SND_MIXER_ETYPE_SWITCH1);
}
static void mixer_switch1_value(int val)
{
unsigned int *ptr;
if (Xelement->element.data.switch1.sw_size <= Xelement->element.data.switch1.sw) {
Xelement->element.data.switch1.sw_size += 32;
ptr = (unsigned int *)realloc(Xelement->element.data.switch1.psw, ((Xelement->element.data.switch1.sw_size + 31) / 32) * sizeof(unsigned int));
if (ptr == NULL) {
error_nomem();
return;
}
Xelement->element.data.switch1.psw = ptr;
}
snd_mixer_set_bit(Xelement->element.data.switch1.psw, Xelement->element.data.switch1.sw++, val ? 1 : 0);
}
static void mixer_switch2(int end)
{
mixer_type_check(SND_MIXER_ETYPE_SWITCH2);
}
static void mixer_switch2_value(int val)
{
Xelement->element.data.switch2.sw = val ? 1 : 0;
}
static void mixer_switch3(int end)
{
mixer_type_check(SND_MIXER_ETYPE_SWITCH3);
}
static void mixer_switch3_value(int val)
{
unsigned int *ptr;
if (Xelement->element.data.switch3.rsw_size <= Xelement->element.data.switch3.rsw) {
Xelement->element.data.switch3.rsw_size += 32;
ptr = (unsigned int *)realloc(Xelement->element.data.switch1.psw, ((Xelement->element.data.switch3.rsw_size + 31) / 32) * sizeof(unsigned int));
if (ptr == NULL) {
error_nomem();
return;
}
Xelement->element.data.switch3.prsw = ptr;
}
snd_mixer_set_bit(Xelement->element.data.switch3.prsw, Xelement->element.data.switch3.rsw++, val ? 1 : 0);
}
static void mixer_volume1(int end)
{
mixer_type_check(SND_MIXER_ETYPE_VOLUME1);
}
static void mixer_volume1_value(int val)
{
int *ptr;
if (Xelement->element.data.volume1.channels_size <= Xelement->element.data.volume1.channels) {
Xelement->element.data.volume1.channels_size += 4;
ptr = (int *)realloc(Xelement->element.data.volume1.pchannels, Xelement->element.data.volume1.channels_size * sizeof(int));
if (ptr == NULL) {
error_nomem();
return;
}
Xelement->element.data.volume1.pchannels = ptr;
}
Xelement->element.data.volume1.pchannels[Xelement->element.data.volume1.channels++] = val;
}
static void mixer_3d_effect1(int end)
{
mixer_type_check(SND_MIXER_ETYPE_3D_EFFECT1);
}
static void mixer_3d_effect1_value(unsigned int effect, int val)
{
switch (effect) {
case SND_MIXER_EFF1_SW:
Xelement->element.data.teffect1.sw = val ? 1 : 0;
switch (Xtype) {
case SND_CONTROL_TYPE_NONE:
case SND_CONTROL_TYPE_BOOLEAN:
Xtype = Xcontrol->type = SND_CONTROL_TYPE_BOOLEAN;
break;
case SND_MIXER_EFF1_MONO_SW:
Xelement->element.data.teffect1.mono_sw = val ? 1 : 0;
break;
case SND_MIXER_EFF1_WIDE:
Xelement->element.data.teffect1.wide = val;
break;
case SND_MIXER_EFF1_VOLUME:
Xelement->element.data.teffect1.volume = val;
break;
case SND_MIXER_EFF1_CENTER:
Xelement->element.data.teffect1.center = val;
break;
case SND_MIXER_EFF1_SPACE:
Xelement->element.data.teffect1.space = val;
break;
case SND_MIXER_EFF1_DEPTH:
Xelement->element.data.teffect1.depth = val;
break;
case SND_MIXER_EFF1_DELAY:
Xelement->element.data.teffect1.delay = val;
break;
case SND_MIXER_EFF1_FEEDBACK:
Xelement->element.data.teffect1.feedback = val;
break;
case SND_MIXER_EFF1_DEPTH_REAR:
Xelement->element.data.teffect1.depth_rear = val;
case SND_CONTROL_TYPE_INTEGER:
break;
default:
yyerror("Unknown effect 0x%x\n", effect);
yyerror("Unexpected previous type (%i).\n", Xtype);
}
}
static void mixer_accu3(int end)
{
mixer_type_check(SND_MIXER_ETYPE_ACCU3);
if (Xposition < 512)
Xcontrol->c.value.integer.value[Xposition++] = val ? 1 : 0;
else
yyerror("Array overflow.");
}
static void mixer_accu3_value(int val)
{
int *ptr;
if (Xelement->element.data.accu3.channels_size <= Xelement->element.data.accu3.channels) {
Xelement->element.data.accu3.channels_size += 4;
ptr = (int *)realloc(Xelement->element.data.accu3.pchannels, Xelement->element.data.accu3.channels_size * sizeof(int));
if (ptr == NULL) {
error_nomem();
return;
}
Xelement->element.data.accu3.pchannels = ptr;
}
Xelement->element.data.accu3.pchannels[Xelement->element.data.accu3.channels++] = val;
}
static void mixer_mux1(int end)
{
mixer_type_check(SND_MIXER_ETYPE_MUX1);
}
static void mixer_mux1_value(char *name, int index, int type)
{
snd_mixer_eid_t *ptr;
snd_mixer_eid_t *eid;
if (Xelement->element.data.mux1.sel_size <= Xelement->element.data.mux1.sel) {
Xelement->element.data.mux1.sel_size += 4;
ptr = (snd_mixer_eid_t *)realloc(Xelement->element.data.mux1.psel, Xelement->element.data.mux1.sel_size * sizeof(snd_mixer_eid_t));
if (ptr == NULL) {
error_nomem();
free(name);
return;
}
Xelement->element.data.mux1.psel = ptr;
}
eid = &Xelement->element.data.mux1.psel[Xelement->element.data.mux1.sel++];
strncpy(eid->name, name, sizeof(eid->name));
eid->index = index;
eid->type = type;
free(name);
}
static void mixer_mux2(int end)
{
mixer_type_check(SND_MIXER_ETYPE_MUX2);
}
static void mixer_mux2_value(char *name, int index, int type)
{
snd_mixer_eid_t *eid;
eid = &Xelement->element.data.mux2.sel;
strncpy(eid->name, name, sizeof(eid->name));
eid->index = index;
eid->type = type;
free(name);
}
static void mixer_tone_control1(int end)
{
mixer_type_check(SND_MIXER_ETYPE_TONE_CONTROL1);
}
static void mixer_tone_control1_value(unsigned int effect, int val)
{
Xelement->element.data.tc1.tc |= effect;
switch (effect) {
case SND_MIXER_TC1_SW:
Xelement->element.data.tc1.sw = val ? 1 : 0;
break;
case SND_MIXER_TC1_BASS:
Xelement->element.data.tc1.bass = val;
break;
case SND_MIXER_TC1_TREBLE:
Xelement->element.data.tc1.treble = val;
break;
default:
yyerror("Unknown effect 0x%x\n", effect);
}
}
static void build_switch(struct ctl_switch **first, char *name)
{
struct ctl_switch *sw;
if (!name) {
Xswitch = NULL;
return;
}
Xswitch = (struct ctl_switch *)malloc(sizeof(struct ctl_switch));
if (!Xswitch) {
free(name);
error_nomem();
return;
}
bzero(Xswitch, sizeof(*Xswitch));
for (sw = *first; sw && sw->next; sw = sw->next);
if (sw) {
sw->next = Xswitch;
} else {
*first = Xswitch;
}
strncpy(Xswitch->s.name, name, sizeof(Xswitch->s.name));
free(name);
}
static void build_control_switch(char *name)
{
build_switch(&Xsoundcard->control.switches, name);
}
static void build_mixer_switch(char *name)
{
build_switch(&Xmixer->switches, name);
}
static void build_pcm_playback_switch(char *name)
{
build_switch(&Xpcm->pswitches, name);
}
static void build_pcm_capture_switch(char *name)
{
build_switch(&Xpcm->rswitches, name);
}
static void build_rawmidi_output_switch(char *name)
{
build_switch(&Xrawmidi->oswitches, name);
}
static void build_rawmidi_input_switch(char *name)
{
build_switch(&Xrawmidi->iswitches, name);
}
static void set_switch_boolean(int val)
{
Xswitch->s.type = SND_SW_TYPE_BOOLEAN;
Xswitch->s.value.enable = val ? 1 : 0;
}
static void set_switch_integer(int val)
static void set_control_integer(long val)
{
unsigned int xx;
Xswitch->s.type = SND_SW_TYPE_DWORD;
xx = val;
memcpy(&Xswitch->s.value, &xx, sizeof(xx));
}
static void set_switch_bytearray(struct bytearray val)
{
Xswitch->s.type = SND_SW_TYPE_USER;
if (val.datalen > 32)
yyerror("Byte array too large for switch.");
memcpy(Xswitch->s.value.data8, val.data, val.datalen);
}
static void set_switch_iec958ocs_begin(int end)
{
if (end) {
Xswitch->s.value.enable = Xswitchiec958ocs;
Xswitch->s.value.data16[4] = Xswitchiec958ocs1[4];
Xswitch->s.value.data16[5] = Xswitchiec958ocs1[5];
#if 0
printf("IEC958: enable = %i, ocs1[4] = 0x%x, ocs1[5] = 0x%x\n",
sw->value.enable,
sw->value.data16[4],
sw->value.data16[5]);
#endif
return;
switch (Xtype) {
case SND_CONTROL_TYPE_NONE:
case SND_CONTROL_TYPE_BOOLEAN:
case SND_CONTROL_TYPE_INTEGER:
Xtype = Xcontrol->type = SND_CONTROL_TYPE_INTEGER;
break;
default:
yyerror("Unexpected previous type (%i).\n", Xtype);
}
if (Xposition < 512) {
xx = val;
Xcontrol->c.value.integer.value[Xposition++] = val;
}
Xswitch->s.type = SND_SW_TYPE_BOOLEAN;
Xswitch->s.value.data32[1] = ('C' << 8) | 'S';
Xswitchiec958ocs = 0;
Xswitchiec958ocs1[4] = 0x0000;
Xswitchiec958ocs1[5] = 0x0004; /* copy permitted */
}
static void set_switch_iec958ocs(int idx, unsigned short val, unsigned short mask)
static void set_control_bytearray(struct bytearray val)
{
if (idx == 0) {
Xswitchiec958ocs = val ? 1 : 0;
return;
}
Xswitchiec958ocs1[idx] &= mask;
Xswitchiec958ocs1[idx] |= val;
if (Xtype != SND_CONTROL_TYPE_NONE && Xtype != SND_CONTROL_TYPE_BYTES)
yyerror("Unexpected previous type (%i).\n", Xtype);
Xtype = Xcontrol->type = SND_CONTROL_TYPE_BYTES;
if (val.datalen + Xposition > 512)
yyerror("Byte array too large for control.");
memcpy(&Xcontrol->c.value.bytes.data[Xposition], val.data, val.datalen);
Xposition += val.datalen;
}

View file

@ -21,141 +21,98 @@
#include "alsactl.h"
static char *sw_id(const char *name, int cardno, int devno, const char *id)
static int merge_one_control(struct ctl_control *cctl, struct ctl_control *uctl, int cardno)
{
static char str[256];
sprintf(str, "%s %s card %i", name, id, cardno);
if (devno >= 0)
sprintf(str + strlen(str)," device %i", devno);
return str;
}
int idx;
static int merge_one_sw(struct ctl_switch *csw, struct ctl_switch *usw, int cardno, int devno, const char *id)
{
switch (csw->s.type) {
case SND_SW_TYPE_BOOLEAN:
if (usw->s.type != SND_SW_TYPE_BOOLEAN) {
error("A wrong type for the switch %s. The type boolean is expected. Skipping...", sw_id(usw->s.name, cardno, devno, id));
if (!(cctl->info.access & SND_CONTROL_ACCESS_WRITE))
return 0;
switch (cctl->info.type) {
case SND_CONTROL_TYPE_BOOLEAN:
if (uctl->type != SND_CONTROL_TYPE_BOOLEAN && uctl->type != SND_CONTROL_TYPE_INTEGER) {
error("A wrong type %i for the control '%s'. The type integer is expected. Skipping...", uctl->type, control_id(&uctl->c.id));
return 1;
}
if (csw->s.value.enable != usw->s.value.enable) {
csw->change = 1;
csw->s.value.enable = usw->s.value.enable;
}
if (!strncmp(csw->s.name, SND_MIXER_SW_IEC958_OUTPUT, sizeof(csw->s.name))) {
if (usw->s.value.data32[1] == (('C' << 8) | 'S')) {
if (csw->s.value.data16[4] != usw->s.value.data16[4] ||
csw->s.value.data16[5] != usw->s.value.data16[5]) {
csw->change = 1;
csw->s.value.data16[4] = usw->s.value.data16[4];
csw->s.value.data16[5] = usw->s.value.data16[5];
}
for (idx = 0; idx < cctl->info.values_count; idx++) {
if (cctl->c.value.integer.value[idx] != uctl->c.value.integer.value[idx]) {
cctl->change = 1;
cctl->c.value.integer.value[idx] = uctl->c.value.integer.value[idx];
}
}
break;
case SND_SW_TYPE_BYTE:
if (usw->s.type != SND_SW_TYPE_DWORD) {
error("A wrong type for the switch %s. The type byte is expected. Skipping...", sw_id(usw->s.name, cardno, devno, id));
case SND_CONTROL_TYPE_INTEGER:
if (uctl->type != SND_CONTROL_TYPE_BOOLEAN && uctl->type != SND_CONTROL_TYPE_INTEGER) {
error("A wrong type %i for the control '%s'. The type integer is expected. Skipping...", uctl->type, control_id(&uctl->c.id));
return 1;
}
if (csw->s.low > usw->s.value.data32[0] ||
csw->s.high < usw->s.value.data32[0]) {
error("The value %u for the switch %s is out of range %i-%i.", usw->s.value.data32[0], sw_id(usw->s.name, cardno, devno, id), csw->s.low, csw->s.high);
return 1;
}
if (csw->s.value.data8[0] != (unsigned char)usw->s.value.data32[0]) {
csw->change = 1;
csw->s.value.data8[0] = (unsigned char)usw->s.value.data32[0];
for (idx = 0; idx < cctl->info.values_count; idx++) {
if (cctl->info.value.integer.min > uctl->c.value.integer.value[idx] ||
cctl->info.value.integer.max < uctl->c.value.integer.value[idx]) {
error("The value %li for the control '%s' is out of range %i-%i.", uctl->c.value.integer.value[idx], control_id(&uctl->c.id), cctl->info.value.integer.min, cctl->info.value.integer.max);
return 1;
}
if (cctl->c.value.integer.value[idx] != uctl->c.value.integer.value[idx]) {
cctl->change = 1;
cctl->c.value.integer.value[idx] = uctl->c.value.integer.value[idx];
}
}
break;
case SND_SW_TYPE_WORD:
if (usw->s.type != SND_SW_TYPE_DWORD) {
error("A wrong type for the switch %s. The type word is expected. Skipping...", sw_id(usw->s.name, cardno, devno, id));
case SND_CONTROL_TYPE_ENUMERATED:
if (uctl->type != SND_CONTROL_TYPE_BOOLEAN && uctl->type != SND_CONTROL_TYPE_INTEGER) {
error("A wrong type %i for the control '%s'. The type integer is expected. Skipping...", uctl->type, control_id(&uctl->c.id));
return 1;
}
if (csw->s.low > usw->s.value.data32[0] ||
csw->s.high < usw->s.value.data32[0]) {
error("The value %u for the switch %s is out of range %i-%i.", usw->s.value.data32[0], sw_id(usw->s.name, cardno, devno, id), csw->s.low, csw->s.high);
return 1;
}
if (csw->s.value.data16[0] != (unsigned short)usw->s.value.data32[0]) {
csw->change = 1;
csw->s.value.data16[0] = (unsigned short)usw->s.value.data32[0];
for (idx = 0; idx < cctl->info.values_count; idx++) {
if (cctl->info.value.enumerated.items <= uctl->c.value.integer.value[idx]) {
error("The value %u for the control '%s' is out of range 0-%i.", uctl->c.value.integer.value[idx], control_id(&uctl->c.id), cctl->info.value.enumerated.items-1);
return 1;
}
if (cctl->c.value.enumerated.item[idx] != uctl->c.value.integer.value[idx]) {
cctl->change = 1;
cctl->c.value.enumerated.item[idx] = uctl->c.value.integer.value[idx];
}
}
break;
case SND_SW_TYPE_DWORD:
if (usw->s.type != SND_SW_TYPE_DWORD) {
error("A wrong type for the switch %s. The type dword is expected. Skipping...", sw_id(usw->s.name, cardno, devno, id));
case SND_CONTROL_TYPE_BYTES:
if (uctl->type != SND_CONTROL_TYPE_BYTES) {
error("A wrong type %i for the control %s. The type 'bytes' is expected. Skipping...", uctl->type, control_id(&uctl->c.id));
return 1;
}
if (csw->s.low > usw->s.value.data32[0] ||
csw->s.high < usw->s.value.data32[0]) {
error("The value %u for the switch %s is out of range %i-%i.", usw->s.value.data32[0], sw_id(usw->s.name, cardno, devno, id), csw->s.low, csw->s.high);
return 1;
}
if (csw->s.value.data32[0] != usw->s.value.data32[0]) {
csw->change = 1;
csw->s.value.data32[0] = usw->s.value.data32[0];
}
break;
case SND_SW_TYPE_LIST:
if (usw->s.type != SND_SW_TYPE_DWORD) {
error("A wrong type for the switch %s. The type list is expected. Skipping...", sw_id(usw->s.name, cardno, devno, id));
return 1;
}
if (csw->s.low > usw->s.value.data32[0] ||
csw->s.high < usw->s.value.data32[0]) {
error("The value %i for the switch %s is out of range %i-%i.", usw->s.value.data32[0], sw_id(usw->s.name, cardno, devno, id), csw->s.low, csw->s.high);
return 1;
}
if (csw->s.value.item_number != usw->s.value.data32[0]) {
csw->change = 1;
csw->s.value.item_number = usw->s.value.data32[0];
}
break;
case SND_SW_TYPE_USER_READ_ONLY:
break;
case SND_SW_TYPE_USER:
if (usw->s.type != SND_SW_TYPE_USER) {
error("A wrong type %i for the switch %s. The type user is expected. Skipping...", usw->s.type, sw_id(usw->s.name, cardno, devno, id));
return 1;
}
if (memcmp(csw->s.value.data8, usw->s.value.data8, 32)) {
csw->change = 1;
memcpy(csw->s.value.data8, usw->s.value.data8, 32);
if (memcmp(cctl->c.value.bytes.data, uctl->c.value.bytes.data, uctl->info.values_count)) {
cctl->change = 1;
memcpy(cctl->c.value.bytes.data, uctl->c.value.bytes.data, uctl->info.values_count);
}
break;
default:
error("The switch type %i is not known.", csw->s.type);
error("The control type %i is not known.", cctl->type);
}
return 0;
}
static int soundcard_setup_merge_sw(struct ctl_switch *csw, struct ctl_switch *usw, int cardno, int devno, const char *id)
static int soundcard_setup_merge_control(struct ctl_control *cctl, struct ctl_control *uctl, int cardno)
{
struct ctl_switch *csw1;
struct ctl_control *cctl1;
for ( ; usw; usw = usw->next) {
for (csw1 = csw; csw1; csw1 = csw1->next) {
if (!strncmp(csw1->s.name, usw->s.name, sizeof(csw1->s.name))) {
merge_one_sw(csw1, usw, cardno, devno, id);
for ( ; uctl; uctl = uctl->next) {
for (cctl1 = cctl; cctl1; cctl1 = cctl1->next) {
if (cctl1->c.id.iface == uctl->c.id.iface &&
cctl1->c.id.device == uctl->c.id.device &&
cctl1->c.id.subdevice == uctl->c.id.subdevice &&
!strncmp(cctl1->c.id.name, uctl->c.id.name, sizeof(cctl1->c.id.name))) {
merge_one_control(cctl1, uctl, cardno);
break;
}
}
if (!csw1) {
error("Cannot find the switch %s...", sw_id(usw->s.name, cardno, devno, id));
if (!cctl1) {
error("Cannot find the control %s...", control_id(&uctl->c.id));
}
}
return 0;
}
int soundcard_setup_merge_switches(int cardno)
int soundcard_setup_merge_controls(int cardno)
{
struct soundcard *soundcard, *rsoundcard;
struct mixer *mixer, *rmixer;
struct pcm *pcm, *rpcm;
struct rawmidi *rawmidi, *rrawmidi;
for (rsoundcard = rsoundcards; rsoundcard; rsoundcard = rsoundcard->next) {
for (soundcard = soundcards; soundcard; soundcard = soundcard->next) {
@ -168,226 +125,7 @@ int soundcard_setup_merge_switches(int cardno)
}
if (cardno >= 0 && soundcard->no != cardno)
continue;
soundcard_setup_merge_sw(soundcard->control.switches, rsoundcard->control.switches, soundcard->no, -1, "control");
for (rmixer = rsoundcard->mixers; rmixer; rmixer = rmixer->next) {
for (mixer = soundcard->mixers; mixer; mixer = mixer->next) {
if (!strncmp(mixer->info.name, rmixer->info.name, sizeof(mixer->info.name)))
break;
}
if (!mixer) {
error("The mixer device '%s' from the soundcard %i was not found...\n", rmixer->info.name, soundcard->no);
continue;
}
soundcard_setup_merge_sw(mixer->switches, rmixer->switches, soundcard->no, mixer->no, "mixer");
}
for (rpcm = rsoundcard->pcms; rpcm; rpcm = rpcm->next) {
for (pcm = soundcard->pcms; pcm; pcm = pcm->next) {
if (!strncmp(pcm->info.name, rpcm->info.name, sizeof(pcm->info.name)))
break;
}
if (!rpcm) {
error("The PCM device '%s' from the soundcard %i was not found...\n", rpcm->info.name, soundcard->no);
continue;
}
soundcard_setup_merge_sw(pcm->pswitches, rpcm->pswitches, soundcard->no, pcm->no, "PCM playback");
soundcard_setup_merge_sw(pcm->rswitches, rpcm->rswitches, soundcard->no, pcm->no, "PCM capture");
}
for (rrawmidi = rsoundcard->rawmidis; rrawmidi; rrawmidi = rrawmidi->next) {
for (rawmidi = soundcard->rawmidis; rawmidi; rawmidi = rawmidi->next) {
if (!strncmp(rawmidi->info.name, rrawmidi->info.name, sizeof(rawmidi->info.name)))
break;
}
if (!rrawmidi) {
error("The rawmidi device '%s' from the soundcard %i was not found...\n", rrawmidi->info.name, soundcard->no);
continue;
}
soundcard_setup_merge_sw(rawmidi->iswitches, rrawmidi->iswitches, soundcard->no, rawmidi->no, "rawmidi input");
soundcard_setup_merge_sw(rawmidi->oswitches, rrawmidi->oswitches, soundcard->no, rawmidi->no, "rawmidi output");
}
}
return 0;
}
static char *element_id(snd_mixer_eid_t *eid, int cardno, int devno, const char *id)
{
static char str[256];
sprintf(str, "%s %s card %i", mixer_element_id(eid), id, cardno);
if (devno >= 0)
sprintf(str + strlen(str)," device %i", devno);
return str;
}
static int merge_one_element(struct mixer_element *celement, struct mixer_element *uelement, int cardno, int devno, const char *id)
{
int tmp;
if (snd_mixer_element_has_control(&celement->element.eid) != 1)
return 0;
switch (celement->element.eid.type) {
case SND_MIXER_ETYPE_SWITCH1:
if (celement->element.data.switch1.sw != uelement->element.data.switch1.sw) {
error("Element %s has got a wrong count of channels.", element_id(&celement->element.eid, cardno, devno, id));
return 1;
}
tmp = ((celement->element.data.switch1.sw + 31) / 32) * sizeof(unsigned int);
memcpy(celement->element.data.switch1.psw, uelement->element.data.switch1.psw, tmp);
break;
case SND_MIXER_ETYPE_SWITCH2:
celement->element.data.switch2.sw = uelement->element.data.switch2.sw;
break;
case SND_MIXER_ETYPE_SWITCH3:
if (celement->element.data.switch3.rsw != uelement->element.data.switch3.rsw) {
error("Element %s has got a wrong count of switches.", element_id(&celement->element.eid, cardno, devno, id));
return 1;
}
tmp = ((celement->element.data.switch3.rsw + 31) / 32) * sizeof(unsigned int);
memcpy(celement->element.data.switch3.prsw, uelement->element.data.switch3.prsw, tmp);
break;
case SND_MIXER_ETYPE_VOLUME1:
if (celement->element.data.volume1.channels != uelement->element.data.volume1.channels) {
error("Element %s has got a wrong count of channels.", element_id(&celement->element.eid, cardno, devno, id));
return 1;
}
tmp = celement->element.data.volume1.channels * sizeof(int);
memcpy(celement->element.data.volume1.pchannels, uelement->element.data.volume1.pchannels, tmp);
break;
case SND_MIXER_ETYPE_VOLUME2:
if (celement->element.data.volume2.achannels != uelement->element.data.volume2.achannels) {
error("Element %s has got a wrong count of channels.", element_id(&celement->element.eid, cardno, devno, id));
return 1;
}
tmp = celement->element.data.volume2.achannels * sizeof(int);
memcpy(celement->element.data.volume2.pachannels, uelement->element.data.volume2.pachannels, tmp);
break;
case SND_MIXER_ETYPE_ACCU3:
if (celement->element.data.accu3.channels != uelement->element.data.accu3.channels) {
error("Element %s has got a wrong count of channels.", element_id(&celement->element.eid, cardno, devno, id));
return 1;
}
tmp = celement->element.data.accu3.channels * sizeof(int);
memcpy(celement->element.data.accu3.pchannels, uelement->element.data.accu3.pchannels, tmp);
break;
case SND_MIXER_ETYPE_MUX1:
if (celement->element.data.mux1.psel)
free(celement->element.data.mux1.psel);
celement->element.data.mux1.sel_size = 0;
celement->element.data.mux1.sel = 0;
celement->element.data.mux1.sel_over = 0;
tmp = uelement->element.data.mux1.sel * sizeof(snd_mixer_eid_t);
if (tmp > 0) {
celement->element.data.mux1.psel = (snd_mixer_eid_t *)malloc(uelement->element.data.mux1.sel_size * sizeof(snd_mixer_eid_t));
if (!celement->element.data.mux1.psel) {
error("No enough memory...");
return 1;
}
celement->element.data.mux1.sel_size = uelement->element.data.mux1.sel_size;
celement->element.data.mux1.sel = uelement->element.data.mux1.sel;
memcpy(celement->element.data.mux1.psel, uelement->element.data.mux1.psel, tmp);
}
break;
case SND_MIXER_ETYPE_MUX2:
celement->element.data.mux2.sel = uelement->element.data.mux2.sel;
break;
case SND_MIXER_ETYPE_TONE_CONTROL1:
if ((uelement->element.data.tc1.tc & ~celement->info.data.tc1.tc) != 0) {
error("Wrong (unsupported) input for the element %s.", element_id(&celement->element.eid, cardno, devno, id));
return 1;
}
celement->element.data.tc1.tc = uelement->element.data.tc1.tc;
celement->element.data.tc1.sw = uelement->element.data.tc1.sw;
celement->element.data.tc1.bass = uelement->element.data.tc1.bass;
celement->element.data.tc1.treble = uelement->element.data.tc1.treble;
break;
case SND_MIXER_ETYPE_3D_EFFECT1:
if ((uelement->element.data.teffect1.effect & ~celement->info.data.teffect1.effect) != 0) {
error("Wrong (unsupported) input for the element %s.", element_id(&celement->element.eid, cardno, devno, id));
return 1;
}
celement->element.data.teffect1.effect = uelement->element.data.teffect1.effect;
celement->element.data.teffect1.sw = uelement->element.data.teffect1.sw;
celement->element.data.teffect1.mono_sw = uelement->element.data.teffect1.mono_sw;
celement->element.data.teffect1.wide = uelement->element.data.teffect1.wide;
celement->element.data.teffect1.volume = uelement->element.data.teffect1.volume;
celement->element.data.teffect1.center = uelement->element.data.teffect1.center;
celement->element.data.teffect1.space = uelement->element.data.teffect1.space;
celement->element.data.teffect1.depth = uelement->element.data.teffect1.depth;
celement->element.data.teffect1.delay = uelement->element.data.teffect1.delay;
celement->element.data.teffect1.feedback = uelement->element.data.teffect1.feedback;
celement->element.data.teffect1.depth_rear = uelement->element.data.teffect1.depth_rear;
break;
case SND_MIXER_ETYPE_PRE_EFFECT1:
if (celement->element.data.peffect1.pparameters)
free(celement->element.data.peffect1.pparameters);
celement->element.data.peffect1.parameters_size = 0;
celement->element.data.peffect1.parameters = 0;
celement->element.data.peffect1.parameters_over = 0;
celement->element.data.peffect1.item = uelement->element.data.peffect1.item;
if (celement->element.data.peffect1.item < 0) {
celement->element.data.peffect1.pparameters = (int *)malloc(uelement->element.data.peffect1.parameters_size * sizeof(int));
if (!celement->element.data.peffect1.pparameters) {
error("No enough memory..");
return 1;
}
celement->element.data.peffect1.parameters_size = uelement->element.data.peffect1.parameters_size;
celement->element.data.peffect1.parameters = uelement->element.data.peffect1.parameters;
tmp = celement->element.data.peffect1.parameters * sizeof(int);
memcpy(celement->element.data.peffect1.pparameters, uelement->element.data.peffect1.pparameters, tmp);
}
break;
default:
error("The element type %i for the element %s is not known.", celement->element.eid.type, mixer_element_id(&celement->element.eid));
}
return 0;
}
static int soundcard_setup_merge_element(struct mixer_element *celement, struct mixer_element *uelement, int cardno, int devno, const char *id)
{
struct mixer_element *element;
for ( ; uelement; uelement = uelement->next) {
for (element = celement; element; element = element->next) {
if (!strncmp(element->element.eid.name, uelement->element.eid.name, sizeof(element->element.eid.name)) &&
element->element.eid.index == uelement->element.eid.index &&
element->element.eid.type == uelement->element.eid.type) {
merge_one_element(element, uelement, cardno, devno, id);
break;
}
}
if (!element) {
error("Cannot find the element %s...", element_id(&uelement->element.eid, cardno, devno, id));
}
}
return 0;
}
int soundcard_setup_merge_data(int cardno)
{
struct soundcard *soundcard, *rsoundcard;
struct mixer *mixer, *rmixer;
for (rsoundcard = rsoundcards; rsoundcard; rsoundcard = rsoundcard->next) {
for (soundcard = soundcards; soundcard; soundcard = soundcard->next) {
if (!strncmp(soundcard->control.hwinfo.id, rsoundcard->control.hwinfo.id, sizeof(soundcard->control.hwinfo.id)))
break;
}
if (!soundcard) {
error("The soundcard '%s' was not found...\n", rsoundcard->control.hwinfo.id);
continue;
}
if (cardno >= 0 && soundcard->no != cardno)
continue;
for (rmixer = rsoundcard->mixers; rmixer; rmixer = rmixer->next) {
for (mixer = soundcard->mixers; mixer; mixer = mixer->next) {
if (!strncmp(mixer->info.name, rmixer->info.name, sizeof(mixer->info.name)))
break;
}
if (!mixer) {
error("The mixer device '%s' from the soundcard %i was not found...\n", rmixer->info.name, soundcard->no);
continue;
}
soundcard_setup_merge_element(mixer->elements, rmixer->elements, soundcard->no, mixer->no, "mixer");
}
soundcard_setup_merge_control(soundcard->control.controls, rsoundcard->control.controls, soundcard->no);
}
return 0;
}
@ -405,112 +143,23 @@ static int soundcard_open_ctl(snd_ctl_t **ctlhandle, struct soundcard *soundcard
return 0;
}
static int soundcard_open_mix(snd_mixer_t **mixhandle, struct soundcard *soundcard, struct mixer *mixer)
{
int err;
if (*mixhandle)
return 0;
if ((err = snd_mixer_open(mixhandle, soundcard->no, mixer->no)) < 0) {
error("Cannot open mixer interface for soundcard #%i.", soundcard->no + 1);
return 1;
}
return 0;
}
int soundcard_setup_process_switches(int cardno)
int soundcard_setup_process_controls(int cardno)
{
int err;
snd_ctl_t *ctlhandle = NULL;
struct soundcard *soundcard;
struct ctl_switch *ctlsw;
struct mixer *mixer;
struct pcm *pcm;
struct rawmidi *rawmidi;
struct ctl_control *ctl;
for (soundcard = soundcards; soundcard; soundcard = soundcard->next) {
if (cardno >= 0 && soundcard->no != cardno)
continue;
for (ctlsw = soundcard->control.switches; ctlsw; ctlsw = ctlsw->next) {
if (ctlsw->change)
for (ctl = soundcard->control.controls; ctl; ctl = ctl->next) {
if (ctl->change)
if (!soundcard_open_ctl(&ctlhandle, soundcard)) {
if ((err = snd_ctl_switch_write(ctlhandle, &ctlsw->s)) < 0)
error("Control switch '%s' write error: %s", ctlsw->s.name, snd_strerror(err));
if ((err = snd_ctl_cwrite(ctlhandle, &ctl->c)) < 0)
error("Control '%s' write error: %s", control_id(&ctl->c.id), snd_strerror(err));
}
}
for (mixer = soundcard->mixers; mixer; mixer = mixer->next) {
for (ctlsw = mixer->switches; ctlsw; ctlsw = ctlsw->next)
if (ctlsw->change)
if (!soundcard_open_ctl(&ctlhandle, soundcard)) {
if ((err = snd_ctl_switch_write(ctlhandle, &ctlsw->s)) < 0)
error("Mixer switch '%s' write error: %s", ctlsw->s.name, snd_strerror(err));
}
}
for (pcm = soundcard->pcms; pcm; pcm = pcm->next) {
for (ctlsw = pcm->pswitches; ctlsw; ctlsw = ctlsw->next) {
if (ctlsw->change)
if (!soundcard_open_ctl(&ctlhandle, soundcard)) {
if ((err = snd_ctl_switch_write(ctlhandle, &ctlsw->s)) < 0)
error("PCM playback switch '%s' write error: %s", ctlsw->s.name, snd_strerror(err));
}
}
for (ctlsw = pcm->rswitches; ctlsw; ctlsw = ctlsw->next) {
if (ctlsw->change)
if (!soundcard_open_ctl(&ctlhandle, soundcard)) {
if ((err = snd_ctl_switch_write(ctlhandle, &ctlsw->s)) < 0)
error("PCM capture switch '%s' write error: %s", ctlsw->s.name, snd_strerror(err));
}
}
}
for (rawmidi = soundcard->rawmidis; rawmidi; rawmidi = rawmidi->next) {
for (ctlsw = rawmidi->oswitches; ctlsw; ctlsw = ctlsw->next) {
if (ctlsw->change)
if (!soundcard_open_ctl(&ctlhandle, soundcard)) {
if ((err = snd_ctl_switch_write(ctlhandle, &ctlsw->s)) < 0)
error("RAWMIDI output switch '%s' write error: %s", ctlsw->s.name, snd_strerror(err));
}
}
for (ctlsw = rawmidi->iswitches; ctlsw; ctlsw = ctlsw->next) {
if (ctlsw->change)
if (!soundcard_open_ctl(&ctlhandle, soundcard)) {
if ((err = snd_ctl_switch_write(ctlhandle, &ctlsw->s)) < 0)
error("RAWMIDI input switch '%s' write error: %s", ctlsw->s.name, snd_strerror(err));
}
}
}
if (ctlhandle) {
snd_ctl_close(ctlhandle);
ctlhandle = NULL;
}
}
return 0;
}
int soundcard_setup_process_data(int cardno)
{
int err;
snd_ctl_t *ctlhandle = NULL;
snd_mixer_t *mixhandle = NULL;
struct soundcard *soundcard;
struct mixer *mixer;
struct mixer_element *element;
for (soundcard = soundcards; soundcard; soundcard = soundcard->next) {
if (cardno >= 0 && soundcard->no != cardno)
continue;
for (mixer = soundcard->mixers; mixer; mixer = mixer->next) {
for (element = mixer->elements; element; element = element->next)
if (snd_mixer_element_has_control(&element->element.eid) == 1) {
if (!soundcard_open_mix(&mixhandle, soundcard, mixer)) {
if ((err = snd_mixer_element_write(mixhandle, &element->element)) < 0)
error("Mixer element %s write error: %s", mixer_element_id(&element->element.eid), snd_strerror(err));
}
}
if (mixhandle) {
snd_mixer_close(mixhandle);
mixhandle = NULL;
}
}
if (ctlhandle) {
snd_ctl_close(ctlhandle);
ctlhandle = NULL;

View file

@ -37,24 +37,13 @@ struct soundcard *rsoundcards = NULL;
* misc functions
*/
static char *mixer_element_name(snd_mixer_eid_t *eid)
char *control_id(snd_control_id_t *id)
{
static char str[32];
static char str[128];
if (!eid)
if (!id)
return "???";
strncpy(str, eid->name, sizeof(eid->name));
str[sizeof(eid->name)] = '\0';
return str;
}
char *mixer_element_id(snd_mixer_eid_t *eid)
{
static char str[64];
if (!eid)
return "???";
sprintf(str, "%s:%i:%i", mixer_element_name(eid), eid->index, eid->type);
sprintf(str, "%i,%i,%i,%s,%i", id->iface, id->device, id->subdevice, id->name, id->index);
return str;
}
@ -62,9 +51,9 @@ char *mixer_element_id(snd_mixer_eid_t *eid)
* free functions
*/
static void soundcard_ctl_switch_free(struct ctl_switch *first)
static void soundcard_ctl_control_free(struct ctl_control *first)
{
struct ctl_switch *next;
struct ctl_control *next;
while (first) {
next = first->next;
@ -73,87 +62,11 @@ static void soundcard_ctl_switch_free(struct ctl_switch *first)
}
}
static void soundcard_mixer_element_free(struct mixer_element *first)
{
struct mixer_element *next;
while (first) {
next = first->next;
snd_mixer_element_info_free(&first->info);
snd_mixer_element_free(&first->element);
free(first);
first = next;
}
}
static void soundcard_mixer_free1(struct mixer *mixer)
{
if (!mixer)
return;
soundcard_mixer_element_free(mixer->elements);
soundcard_ctl_switch_free(mixer->switches);
free(mixer);
}
static void soundcard_mixer_free(struct mixer *first)
{
struct mixer *next;
while (first) {
next = first->next;
soundcard_mixer_free1(first);
first = next;
}
}
static void soundcard_pcm_free1(struct pcm *pcm)
{
if (!pcm)
return;
soundcard_ctl_switch_free(pcm->pswitches);
soundcard_ctl_switch_free(pcm->rswitches);
free(pcm);
}
static void soundcard_pcm_free(struct pcm *first)
{
struct pcm *next;
while (first) {
next = first->next;
soundcard_pcm_free1(first);
first = next;
}
}
static void soundcard_rawmidi_free1(struct rawmidi *rawmidi)
{
if (!rawmidi)
return;
soundcard_ctl_switch_free(rawmidi->iswitches);
soundcard_ctl_switch_free(rawmidi->oswitches);
free(rawmidi);
}
static void soundcard_rawmidi_free(struct rawmidi *first)
{
struct rawmidi *next;
while (first) {
next = first->next;
soundcard_rawmidi_free1(first);
first = next;
}
}
static void soundcard_free1(struct soundcard *soundcard)
{
if (!soundcard)
return;
soundcard_ctl_switch_free(soundcard->control.switches);
soundcard_mixer_free(soundcard->mixers);
soundcard_pcm_free(soundcard->pcms);
soundcard_rawmidi_free(soundcard->rawmidis);
soundcard_ctl_control_free(soundcard->control.controls);
free(soundcard);
}
@ -205,77 +118,74 @@ void soundcard_setup_done(void)
soundcards = NULL;
}
static int determine_switches(void *handle, struct ctl_switch **csw, int iface, int device, int stream)
static int determine_controls(void *handle, struct ctl_control **cctl)
{
int err, idx;
snd_switch_list_t list;
snd_switch_list_item_t *item;
snd_switch_t sw;
struct ctl_switch *prev_csw;
struct ctl_switch *new_csw;
snd_control_list_t list;
snd_control_id_t *item;
snd_control_t ctl;
struct ctl_control *prev_control;
struct ctl_control *new_control;
*csw = NULL;
*cctl = NULL;
bzero(&list, sizeof(list));
list.iface = iface;
list.device = device;
list.stream = stream;
if ((err = snd_ctl_switch_list(handle, &list)) < 0) {
error("Cannot determine switches for interface %i and device %i and stream %i: %s", iface, device, stream, snd_strerror(err));
if ((err = snd_ctl_clist(handle, &list)) < 0) {
error("Cannot determine controls: %s", snd_strerror(err));
return 1;
}
if (list.switches_over <= 0)
if (list.controls <= 0)
return 0;
list.switches_size = list.switches_over + 16;
list.switches = list.switches_over = 0;
list.pswitches = malloc(sizeof(snd_switch_list_item_t) * list.switches_size);
if (!list.pswitches) {
list.controls_request = list.controls + 16;
list.controls_offset = list.controls_count = 0;
list.pids = malloc(sizeof(snd_control_id_t) * list.controls_request);
if (!list.pids) {
error("No enough memory...");
return 1;
}
if ((err = snd_ctl_switch_list(handle, &list)) < 0) {
error("Cannot determine switches (2) for interface %i and device %i and stream %i: %s", iface, device, stream, snd_strerror(err));
if ((err = snd_ctl_clist(handle, &list)) < 0) {
error("Cannot determine controls (2): %s", snd_strerror(err));
return 1;
}
for (idx = 0, prev_csw = NULL; idx < list.switches; idx++) {
item = &list.pswitches[idx];
bzero(&sw, sizeof(sw));
sw.iface = iface;
sw.device = device;
sw.stream = stream;
strncpy(sw.name, item->name, sizeof(sw.name));
if ((err = snd_ctl_switch_read(handle, &sw)) < 0) {
error("Cannot read switch '%s' for interface %i and device %i and stream %i: %s", sw.name, iface, device, stream, snd_strerror(err));
free(list.pswitches);
for (idx = 0, prev_control = NULL; idx < list.controls_count; idx++) {
item = &list.pids[idx];
bzero(&ctl, sizeof(ctl));
ctl.id = *item;
if ((err = snd_ctl_cread(handle, &ctl)) < 0) {
error("Cannot read control '%s': %s", control_id(item), snd_strerror(err));
free(list.pids);
return 1;
}
new_csw = malloc(sizeof(*new_csw));
if (!new_csw) {
new_control = malloc(sizeof(*new_control));
if (!new_control) {
error("No enough memory...");
free(list.pswitches);
free(list.pids);
return 1;
}
bzero(new_csw, sizeof(*new_csw));
memcpy(&new_csw->s, &sw, sizeof(new_csw->s));
if (*csw) {
prev_csw->next = new_csw;
prev_csw = new_csw;
bzero(new_control, sizeof(*new_control));
memcpy(&new_control->c, &ctl, sizeof(new_control->c));
new_control->info.id = ctl.id;
if ((err = snd_ctl_cinfo(handle, &new_control->info)) < 0) {
error("Cannot read control info '%s': %s", control_id(item), snd_strerror(err));
free(new_control);
free(list.pids);
return 1;
}
if (*cctl) {
prev_control->next = new_control;
prev_control = new_control;
} else {
*csw = prev_csw = new_csw;
*cctl = prev_control = new_control;
}
}
free(list.pswitches);
free(list.pids);
return 0;
}
static int soundcard_setup_collect_switches1(int cardno)
static int soundcard_setup_collect_controls1(int cardno)
{
snd_ctl_t *handle;
snd_mixer_t *mhandle;
struct soundcard *card, *first, *prev;
int err, device;
struct mixer *mixer, *mixerprev;
struct pcm *pcm, *pcmprev;
struct rawmidi *rawmidi, *rawmidiprev;
int err;
soundcard_remove(cardno);
if ((err = snd_ctl_open(&handle, cardno)) < 0) {
@ -316,125 +226,28 @@ static int soundcard_setup_collect_switches1(int cardno)
return 1;
}
/* --- */
if (determine_switches(handle, &card->control.switches, SND_CTL_IFACE_CONTROL, 0, 0)) {
if (determine_controls(handle, &card->control.controls)) {
snd_ctl_close(handle);
return 1;
}
/* --- */
for (device = 0, mixerprev = NULL; device < card->control.hwinfo.mixerdevs; device++) {
mixer = (struct mixer *) malloc(sizeof(struct mixer));
if (!mixer) {
snd_ctl_close(handle);
error("malloc problem");
return 1;
}
bzero(mixer, sizeof(struct mixer));
mixer->no = device;
if (determine_switches(handle, &mixer->switches, SND_CTL_IFACE_MIXER, device, 0)) {
snd_ctl_close(handle);
return 1;
}
if (!mixerprev) {
card->mixers = mixer;
} else {
mixerprev->next = mixer;
}
mixerprev = mixer;
if ((err = snd_mixer_open(&mhandle, cardno, device)) < 0) {
snd_ctl_close(handle);
error("MIXER open error: %s", snd_strerror(err));
return 1;
}
if ((err = snd_mixer_info(mhandle, &mixer->info)) < 0) {
snd_mixer_close(mhandle);
snd_ctl_close(handle);
error("MIXER info error: %s", snd_strerror(err));
return 1;
}
snd_mixer_close(mhandle);
}
/* --- */
for (device = 0, pcmprev = NULL; device < card->control.hwinfo.pcmdevs; device++) {
pcm = (struct pcm *) malloc(sizeof(struct pcm));
if (!pcm) {
snd_ctl_close(handle);
error("malloc problem");
return 1;
}
bzero(pcm, sizeof(struct pcm));
pcm->no = device;
pcm->info.device = device;
pcm->info.stream = -1;
pcm->info.subdevice = -1;
if ((err = snd_ctl_pcm_info(handle, &pcm->info)) < 0) {
snd_ctl_close(handle);
error("PCM info error: %s", snd_strerror(err));
return 1;
}
if (determine_switches(handle, &pcm->pswitches, SND_CTL_IFACE_PCM, device, SND_PCM_STREAM_PLAYBACK)) {
snd_ctl_close(handle);
return 1;
}
if (determine_switches(handle, &pcm->rswitches, SND_CTL_IFACE_PCM, device, SND_PCM_STREAM_CAPTURE)) {
snd_ctl_close(handle);
return 1;
}
if (!pcmprev) {
card->pcms = pcm;
} else {
pcmprev->next = pcm;
}
pcmprev = pcm;
}
/* --- */
for (device = 0, rawmidiprev = NULL; device < card->control.hwinfo.mididevs; device++) {
rawmidi = (struct rawmidi *) malloc(sizeof(struct rawmidi));
if (!rawmidi) {
snd_ctl_close(handle);
error("malloc problem");
return 1;
}
bzero(rawmidi, sizeof(struct rawmidi));
rawmidi->no = device;
rawmidi->info.device = device;
if ((err = snd_ctl_rawmidi_info(handle, &rawmidi->info)) < 0) {
snd_ctl_close(handle);
error("RAWMIDI info error: %s", snd_strerror(err));
return 1;
}
if (determine_switches(handle, &rawmidi->oswitches, SND_CTL_IFACE_RAWMIDI, device, SND_RAWMIDI_STREAM_OUTPUT)) {
snd_ctl_close(handle);
return 1;
}
if (determine_switches(handle, &rawmidi->iswitches, SND_CTL_IFACE_RAWMIDI, device, SND_RAWMIDI_STREAM_INPUT)) {
snd_ctl_close(handle);
return 1;
}
if (!rawmidiprev) {
card->rawmidis = rawmidi;
} else {
rawmidiprev->next = rawmidi;
}
rawmidiprev = rawmidi;
}
}
/* --- */
snd_ctl_close(handle);
return 0;
}
int soundcard_setup_collect_switches(int cardno)
int soundcard_setup_collect_controls(int cardno)
{
int err;
unsigned int mask;
if (cardno >= 0) {
return soundcard_setup_collect_switches1(cardno);
return soundcard_setup_collect_controls1(cardno);
} else {
mask = snd_cards_mask();
for (cardno = 0; cardno < SND_CARDS; cardno++) {
if (!(mask & (1 << cardno)))
continue;
err = soundcard_setup_collect_switches1(cardno);
err = soundcard_setup_collect_controls1(cardno);
if (err)
return err;
}
@ -442,120 +255,14 @@ int soundcard_setup_collect_switches(int cardno)
}
}
static int soundcard_setup_collect_data1(int cardno)
{
snd_ctl_t *handle;
snd_mixer_t *mhandle;
struct soundcard *card;
int err, idx;
struct mixer *mixer;
snd_mixer_elements_t elements;
struct mixer_element *mixerelement, *mixerelementprev;
if ((err = snd_ctl_open(&handle, cardno)) < 0) {
error("SND CTL open error: %s", snd_strerror(err));
return 1;
}
/* --- */
for (card = soundcards; card && card->no != cardno; card = card->next);
if (!card) {
snd_ctl_close(handle);
error("The soundcard %i does not exist.", cardno);
return 1;
}
for (mixer = card->mixers; mixer; mixer = mixer->next) {
if ((err = snd_mixer_open(&mhandle, cardno, mixer->no)) < 0) {
snd_ctl_close(handle);
error("MIXER open error: %s", snd_strerror(err));
return 1;
}
if (mixer->elements)
soundcard_mixer_element_free(mixer->elements);
mixer->elements = NULL;
bzero(&elements, sizeof(elements));
if ((err = snd_mixer_elements(mhandle, &elements)) < 0) {
snd_mixer_close(mhandle);
snd_ctl_close(handle);
error("MIXER elements error: %s", snd_strerror(err));
return 1;
}
elements.elements_size = elements.elements_over + 16;
elements.elements = elements.elements_over = 0;
elements.pelements = (snd_mixer_eid_t *)malloc(elements.elements_size * sizeof(snd_mixer_eid_t));
if ((err = snd_mixer_elements(mhandle, &elements)) < 0) {
snd_mixer_close(mhandle);
snd_ctl_close(handle);
error("MIXER elements (2) error: %s", snd_strerror(err));
return 1;
}
for (idx = 0, mixerelementprev = NULL; idx < elements.elements; idx++) {
mixerelement = (struct mixer_element *) malloc(sizeof(struct mixer_element));
if (!mixerelement) {
snd_mixer_close(mhandle);
snd_ctl_close(handle);
error("malloc problem");
return 1;
}
bzero(mixerelement, sizeof(*mixerelement));
mixerelement->info.eid = elements.pelements[idx];
mixerelement->element.eid = elements.pelements[idx];
if (snd_mixer_element_has_info(&elements.pelements[idx]) == 1) {
if ((err = snd_mixer_element_info_build(mhandle, &mixerelement->info)) < 0) {
free(mixerelement);
error("MIXER element %s info error (%s) - skipping", mixer_element_id(&mixerelement->info.eid), snd_strerror(err));
break;
}
}
if (snd_mixer_element_has_control(&elements.pelements[idx]) == 1) {
if ((err = snd_mixer_element_build(mhandle, &mixerelement->element)) < 0) {
free(mixerelement);
error("MIXER element %s build error (%s) - skipping", mixer_element_id(&mixerelement->element.eid), snd_strerror(err));
break;
}
}
if (!mixerelementprev) {
mixer->elements = mixerelement;
} else {
mixerelementprev->next = mixerelement;
}
mixerelementprev = mixerelement;
}
free(elements.pelements);
snd_mixer_close(mhandle);
}
/* --- */
snd_ctl_close(handle);
return 0;
}
int soundcard_setup_collect_data(int cardno)
{
int err;
unsigned int mask;
if (cardno >= 0) {
return soundcard_setup_collect_data1(cardno);
} else {
mask = snd_cards_mask();
for (cardno = 0; cardno < SND_CARDS; cardno++) {
if (!(mask & (1 << cardno)))
continue;
err = soundcard_setup_collect_data1(cardno);
if (err)
return err;
}
return 0;
}
}
int soundcard_setup_load(const char *cfgfile, int skip)
{
extern int yyparse(void);
extern int linecount;
extern FILE *yyin;
#ifdef YYDEBUG
extern int yydebug;
#endif
int xtry;
#ifdef YYDEBUG
@ -579,268 +286,98 @@ int soundcard_setup_load(const char *cfgfile, int skip)
return 0;
}
static void soundcard_setup_write_switch(FILE * out, const char *space, int card, int interface, snd_switch_t *sw)
static void soundcard_setup_write_control(FILE * out, const char *space, int card, struct ctl_control *control)
{
char *s, v[16];
int idx, first, switchok = 0;
int err, idx;
snd_ctl_t *handle;
snd_control_info_t info;
memcpy(&info, &control->info, sizeof(info));
v[0] = '\0';
switch (sw->type) {
case SND_SW_TYPE_BOOLEAN:
s = "bool";
strcpy(v, sw->value.enable ? "true" : "false");
break;
case SND_SW_TYPE_BYTE:
s = "byte";
if (sw->subtype == SND_SW_SUBTYPE_HEXA) {
sprintf(v, "0x%x", (unsigned int) sw->value.data8[0]);
} else {
sprintf(v, "%u", (unsigned int) sw->value.data8[0]);
}
break;
case SND_SW_TYPE_WORD:
s = "word";
if (sw->subtype == SND_SW_SUBTYPE_HEXA) {
sprintf(v, "0x%x", (unsigned int) sw->value.data16[0]);
} else {
sprintf(v, "%u", (unsigned int) sw->value.data16[0]);
}
break;
case SND_SW_TYPE_DWORD:
s = "dword";
if (sw->subtype == SND_SW_SUBTYPE_HEXA) {
sprintf(v, "0x%x", sw->value.data32[0]);
} else {
sprintf(v, "%u", sw->value.data32[0]);
}
break;
case SND_SW_TYPE_USER:
s = "user";
break;
case SND_SW_TYPE_LIST:
s = "list";
sprintf(v, "%u", sw->value.item_number);
break;
case SND_SW_TYPE_USER_READ_ONLY:
return;
default:
s = "unknown";
switch (info.type) {
case SND_CONTROL_TYPE_BOOLEAN: s = "bool"; break;
case SND_CONTROL_TYPE_INTEGER: s = "integer"; break;
case SND_CONTROL_TYPE_ENUMERATED: s = "enumerated"; break;
case SND_CONTROL_TYPE_BYTES: s = "bytes"; break;
default: s = "unknown";
}
fprintf(out, "%s; The type is '%s'.\n", space, s);
if (sw->low != 0 || sw->high != 0)
fprintf(out, "%s; The accepted switch range is from %u to %u.\n", space, sw->low, sw->high);
if (sw->type == SND_SW_TYPE_LIST) {
snd_ctl_t *handle;
snd_switch_t swi;
memset(&swi, 0, sizeof(swi));
swi.iface = sw->iface;
swi.device = sw->device;
swi.stream = sw->stream;
strncpy(swi.name, sw->name, sizeof(swi.name));
swi.type = SND_SW_TYPE_LIST_ITEM;
if (snd_ctl_open(&handle, card) >= 0) {
for (idx = sw->low; idx <= sw->high; idx++) {
swi.low = swi.high = idx;
if (snd_ctl_switch_read(handle, &swi) >= 0)
fprintf(out, "%s; Item #%i - %s\n", space, swi.low, swi.value.item);
fprintf(out, "\n%s; The type is '%s'. Access:", space, s);
if (info.access & SND_CONTROL_ACCESS_READ)
fprintf(out, " read");
if (info.access & SND_CONTROL_ACCESS_WRITE)
fprintf(out, " write");
if (info.access & SND_CONTROL_ACCESS_INACTIVE)
fprintf(out, " inactive");
fprintf(out, ". Count is %i.\n", info.values_count);
switch (info.type) {
case SND_CONTROL_TYPE_BOOLEAN:
if (info.value.integer.min != 0 || info.value.integer.max != 1 ||
info.value.integer.step != 0)
error("Wrong control '%s' (boolean)\n", control_id(&info.id));
break;
case SND_CONTROL_TYPE_INTEGER:
fprintf(out, "%s; The range is %li-%li (step %li)\n", space, info.value.integer.min, info.value.integer.max, info.value.integer.step);
break;
case SND_CONTROL_TYPE_ENUMERATED:
if ((err = snd_ctl_open(&handle, card)) >= 0) {
for (idx = 0; idx < info.value.enumerated.items; idx++) {
info.value.enumerated.item = idx;
if (snd_ctl_cinfo(handle, &info) >= 0)
fprintf(out, "%s; Item #%i - %s\n", space, idx, info.value.enumerated.name);
}
snd_ctl_close(handle);
}
break;
default:
break;
}
if (interface == SND_INTERFACE_CONTROL && sw->type == SND_SW_TYPE_WORD &&
!strcmp(sw->name, SND_CTL_SW_JOYSTICK_ADDRESS)) {
for (idx = 1, first = 1; idx < 16; idx++) {
if (sw->value.data16[idx]) {
if (first) {
fprintf(out, "%s; Available addresses - 0x%x", space, sw->value.data16[idx]);
first = 0;
} else {
fprintf(out, ", 0x%x", sw->value.data16[idx]);
}
}
switch (info.id.iface) {
case SND_CONTROL_IFACE_CARD: s = "global"; break;
case SND_CONTROL_IFACE_HWDEP: s = "hwdep"; break;
case SND_CONTROL_IFACE_MIXER: s = "mixer"; break;
case SND_CONTROL_IFACE_PCM: s = "pcm"; break;
case SND_CONTROL_IFACE_RAWMIDI: s = "rawmidi"; break;
case SND_CONTROL_IFACE_TIMER: s = "timer"; break;
case SND_CONTROL_IFACE_SEQUENCER: s = "sequencer"; break;
default: sprintf(v, "%i", info.id.iface); s = v; break;
}
fprintf(out, "%scontrol(%s, %i, %i, \"%s\", %i", space, s, info.id.device, info.id.subdevice, info.id.name, info.id.index);
if (info.type == SND_CONTROL_TYPE_BYTES)
fprintf(out, "rawdata(@");
for (idx = 0; idx < info.values_count; idx++) {
switch (info.type) {
case SND_CONTROL_TYPE_BOOLEAN:
fprintf(out, ", %s", control->c.value.integer.value[idx] ? "true" : "false");
break;
case SND_CONTROL_TYPE_INTEGER:
fprintf(out, ", %li", control->c.value.integer.value[idx]);
break;
case SND_CONTROL_TYPE_ENUMERATED:
fprintf(out, ", %u", control->c.value.enumerated.item[idx]);
break;
case SND_CONTROL_TYPE_BYTES:
if (idx > 0)
fprintf(out, ":");
fprintf(out, "%02x", control->c.value.bytes.data[idx]);
break;
default:
break;
}
if (!first)
fprintf(out, "\n");
}
if (interface == SND_INTERFACE_MIXER && sw->type == SND_SW_TYPE_BOOLEAN &&
!strcmp(sw->name, SND_MIXER_SW_IEC958_OUTPUT)) {
fprintf(out, "%sswitch(\"%s\",", space, sw->name);
if (sw->value.data32[1] == (('C' << 8) | 'S')) { /* Cirrus Crystal */
switchok = 0;
fprintf(out, "iec958ocs(%s", sw->value.enable ? "enable" : "disable");
if (sw->value.data16[4] & 0x2000)
fprintf(out, ",3d");
if (sw->value.data16[4] & 0x0040)
fprintf(out, ",reset");
if (sw->value.data16[4] & 0x0020)
fprintf(out, ",user");
if (sw->value.data16[4] & 0x0010)
fprintf(out, ",valid");
if (sw->value.data16[5] & 0x0002)
fprintf(out, ",data");
if (!(sw->value.data16[5] & 0x0004))
fprintf(out, ",protect");
switch (sw->value.data16[5] & 0x0018) {
case 0x0008:
fprintf(out, ",pre2");
break;
default:
break;
}
if (sw->value.data16[5] & 0x0020)
fprintf(out, ",fsunlock");
fprintf(out, ",type(0x%x)", (sw->value.data16[5] >> 6) & 0x7f);
if (sw->value.data16[5] & 0x2000)
fprintf(out, ",gstatus");
fprintf(out, ")");
goto __end;
}
}
fprintf(out, "%sswitch(\"%s\", ", space, sw->name);
if (!switchok) {
fprintf(out, v);
if (sw->type < 0 || sw->type > SND_SW_TYPE_LAST) {
/* TODO: some well known types should be verbose */
fprintf(out, "rawdata(@");
for (idx = 0; idx < 31; idx++) {
fprintf(out, "%02x:", sw->value.data8[idx]);
}
fprintf(out, "%02x@)", sw->value.data8[31]);
}
}
__end:
}
if (info.type == SND_CONTROL_TYPE_BYTES)
fprintf(out, ")");
fprintf(out, ")\n");
}
static void soundcard_setup_write_switches(FILE *out, const char *space, int card, int interface, struct ctl_switch **switches)
static void soundcard_setup_write_controls(FILE *out, const char *space, int card, struct ctl_control **controls)
{
struct ctl_switch *sw;
struct ctl_control *ctl;
if (!(*switches))
if (!(*controls))
return;
for (sw = *switches; sw; sw = sw->next)
soundcard_setup_write_switch(out, space, card, interface, &sw->s);
}
static void soundcard_setup_write_mixer_element(FILE * out, struct mixer_element * xelement)
{
snd_mixer_element_info_t *info;
snd_mixer_element_t *element;
int idx;
info = &xelement->info;
element = &xelement->element;
if (snd_mixer_element_has_control(&element->eid) != 1)
return;
switch (element->eid.type) {
case SND_MIXER_ETYPE_SWITCH1:
fprintf(out, " element(\"%s\",%i,%i,Switch1(", mixer_element_name(&element->eid), element->eid.index, element->eid.type);
for (idx = 0; idx < element->data.switch1.sw; idx++)
fprintf(out, "%s%s", idx > 0 ? "," : "", snd_mixer_get_bit(element->data.switch1.psw, idx) ? "on" : "off");
fprintf(out, "))\n");
break;
case SND_MIXER_ETYPE_SWITCH2:
fprintf(out, " element(\"%s\",%i,%i,Switch2(%s))\n", mixer_element_name(&element->eid), element->eid.index, element->eid.type, element->data.switch2.sw ? "on" : "off");
break;
case SND_MIXER_ETYPE_SWITCH3:
fprintf(out, " element(\"%s\",%i,%i,Switch3(", mixer_element_name(&element->eid), element->eid.index, element->eid.type);
for (idx = 0; idx < element->data.switch3.rsw; idx++)
fprintf(out, "%s%s", idx > 0 ? "," : "", snd_mixer_get_bit(element->data.switch3.prsw, idx) ? "on" : "off");
fprintf(out, "))\n");
break;
case SND_MIXER_ETYPE_VOLUME1:
for (idx = 0; idx < info->data.volume1.range; idx++)
fprintf(out, " ; Channel %i : Min %i Max %i\n", idx, info->data.volume1.prange[idx].min, info->data.volume1.prange[idx].max);
fprintf(out, " element(\"%s\",%i,%i,Volume1(", mixer_element_name(&element->eid), element->eid.index, element->eid.type);
for (idx = 0; idx < element->data.volume1.channels; idx++)
fprintf(out, "%s%i", idx > 0 ? "," : "", element->data.volume1.pchannels[idx]);
fprintf(out, "))\n");
break;
case SND_MIXER_ETYPE_ACCU3:
for (idx = 0; idx < info->data.accu3.range; idx++)
fprintf(out, " ; Channel %i : Min %i Max %i\n", idx, info->data.accu3.prange[idx].min, info->data.accu3.prange[idx].max);
fprintf(out, " element(\"%s\",%i,%i,Accu3(", mixer_element_name(&element->eid), element->eid.index, element->eid.type);
for (idx = 0; idx < element->data.accu3.channels; idx++)
fprintf(out, "%s%i", idx > 0 ? "," : "", element->data.accu3.pchannels[idx]);
fprintf(out, "))\n");
break;
case SND_MIXER_ETYPE_MUX1:
fprintf(out, " element(\"%s\",%i,%i,Mux1(", mixer_element_name(&element->eid), element->eid.index, element->eid.type);
for (idx = 0; idx < element->data.mux1.sel; idx++) {
fprintf(out, "%selement(\"%s\",%i,%i)", idx > 0 ? "," : "", mixer_element_name(&element->data.mux1.psel[idx]), element->data.mux1.psel[idx].index, element->data.mux1.psel[idx].type);
}
fprintf(out, "))\n");
break;
case SND_MIXER_ETYPE_MUX2:
fprintf(out, " element(\"%s\",%i,%i,Mux2(", mixer_element_name(&element->eid), element->eid.index, element->eid.type);
fprintf(out, "element(\"%s\",%i,%i)", mixer_element_name(&element->data.mux2.sel), element->data.mux2.sel.index, element->data.mux2.sel.type);
fprintf(out, "))\n");
break;
case SND_MIXER_ETYPE_TONE_CONTROL1:
if (info->data.tc1.tc & SND_MIXER_TC1_SW)
fprintf(out, " ; The tone control has an on/off switch.\n");
if (info->data.tc1.tc & SND_MIXER_TC1_BASS)
fprintf(out, " ; Bass : Min %i Max %i\n", info->data.tc1.min_bass, info->data.tc1.max_bass);
if (info->data.tc1.tc & SND_MIXER_TC1_TREBLE)
fprintf(out, " ; Treble : Min %i Max %i\n", info->data.tc1.min_treble, info->data.tc1.max_treble);
fprintf(out, " element(\"%s\",%i,%i,ToneControl1(", mixer_element_name(&element->eid), element->eid.index, element->eid.type);
idx = 0;
if (element->data.tc1.tc & SND_MIXER_TC1_SW)
fprintf(out, "%ssw=%s", idx++ > 0 ? "," : "", element->data.tc1.sw ? "on" : "off");
if (element->data.tc1.tc & SND_MIXER_TC1_BASS)
fprintf(out, "%sbass=%i", idx++ > 0 ? "," : "", element->data.tc1.bass);
if (element->data.tc1.tc & SND_MIXER_TC1_TREBLE)
fprintf(out, "%streble=%i", idx++ > 0 ? "," : "", element->data.tc1.treble);
fprintf(out, "))\n");
break;
case SND_MIXER_ETYPE_3D_EFFECT1:
if (info->data.teffect1.effect & SND_MIXER_EFF1_SW)
fprintf(out, " ; The 3D effect has an on/off switch.\n");
if (info->data.teffect1.effect & SND_MIXER_EFF1_MONO_SW)
fprintf(out, " ; The 3D effect has an mono processing on/off switch.\n");
if (info->data.teffect1.effect & SND_MIXER_EFF1_WIDE)
fprintf(out, " ; Wide : Min %i Max %i\n", info->data.teffect1.min_wide, info->data.teffect1.max_wide);
if (info->data.teffect1.effect & SND_MIXER_EFF1_VOLUME)
fprintf(out, " ; Volume : Min %i Max %i\n", info->data.teffect1.min_volume, info->data.teffect1.max_volume);
if (info->data.teffect1.effect & SND_MIXER_EFF1_CENTER)
fprintf(out, " ; Center : Min %i Max %i\n", info->data.teffect1.min_center, info->data.teffect1.max_center);
if (info->data.teffect1.effect & SND_MIXER_EFF1_SPACE)
fprintf(out, " ; Space : Min %i Max %i\n", info->data.teffect1.min_space, info->data.teffect1.max_space);
if (info->data.teffect1.effect & SND_MIXER_EFF1_DEPTH)
fprintf(out, " ; Depth : Min %i Max %i\n", info->data.teffect1.min_depth, info->data.teffect1.max_depth);
if (info->data.teffect1.effect & SND_MIXER_EFF1_DELAY)
fprintf(out, " ; Delay : Min %i Max %i\n", info->data.teffect1.min_delay, info->data.teffect1.max_delay);
if (info->data.teffect1.effect & SND_MIXER_EFF1_FEEDBACK)
fprintf(out, " ; Feedback : Min %i Max %i\n", info->data.teffect1.min_feedback, info->data.teffect1.max_feedback);
if (info->data.teffect1.effect & SND_MIXER_EFF1_DEPTH_REAR)
fprintf(out, " ; Depth rear : Min %i Max %i\n", info->data.teffect1.min_depth_rear, info->data.teffect1.max_depth_rear);
fprintf(out, " element(\"%s\",%i,%i,_3D_Effect1(", mixer_element_name(&element->eid), element->eid.index, element->eid.type);
idx = 0;
if (element->data.teffect1.effect & SND_MIXER_EFF1_SW)
fprintf(out, "%ssw=%s", idx++ > 0 ? "," : "", element->data.teffect1.sw ? "on" : "off");
if (element->data.teffect1.effect & SND_MIXER_EFF1_MONO_SW)
fprintf(out, "%smono_sw=%s", idx++ > 0 ? "," : "", element->data.teffect1.mono_sw ? "on" : "off");
if (element->data.teffect1.effect & SND_MIXER_EFF1_WIDE)
fprintf(out, "%swide=%i", idx++ > 0 ? "," : "", element->data.teffect1.wide);
if (element->data.teffect1.effect & SND_MIXER_EFF1_VOLUME)
fprintf(out, "%svolume=%i", idx++ > 0 ? "," : "", element->data.teffect1.volume);
if (element->data.teffect1.effect & SND_MIXER_EFF1_CENTER)
fprintf(out, "%scenter=%i", idx++ > 0 ? "," : "", element->data.teffect1.center);
if (element->data.teffect1.effect & SND_MIXER_EFF1_SPACE)
fprintf(out, "%sspace=%i", idx++ > 0 ? "," : "", element->data.teffect1.space);
if (element->data.teffect1.effect & SND_MIXER_EFF1_DEPTH)
fprintf(out, "%sdepth=%i", idx++ > 0 ? "," : "", element->data.teffect1.depth);
if (element->data.teffect1.effect & SND_MIXER_EFF1_DELAY)
fprintf(out, "%sdelay=%i", idx++ > 0 ? "," : "", element->data.teffect1.delay);
if (element->data.teffect1.effect & SND_MIXER_EFF1_FEEDBACK)
fprintf(out, "%sfeedback=%i", idx++ > 0 ? "," : "", element->data.teffect1.feedback);
if (element->data.teffect1.effect & SND_MIXER_EFF1_DEPTH_REAR)
fprintf(out, "%sdepth_rear=%i", idx++ > 0 ? "," : "", element->data.teffect1.depth_rear);
fprintf(out, "))\n");
break;
default:
fprintf(out, " ; Unknown element %s\n", mixer_element_id(&element->eid));
}
for (ctl = *controls; ctl; ctl = ctl->next)
soundcard_setup_write_control(out, space, card, ctl);
}
#define MAX_LINE (32 * 1024)
@ -850,10 +387,6 @@ int soundcard_setup_write(const char *cfgfile, int cardno)
FILE *out, *out1, *out2, *in;
char *tmpfile1, *tmpfile2;
struct soundcard *first, *sel = NULL;
struct mixer *mixer;
struct mixer_element *mixerelement;
struct pcm *pcm;
struct rawmidi *rawmidi;
char *line, cardname[sizeof(first->control.hwinfo.name)+16], *ptr1;
int mark, size, ok;
@ -904,49 +437,8 @@ int soundcard_setup_write(const char *cfgfile, int cardno)
continue;
sel = first;
fprintf(out, "soundcard(\"%s\") {\n", first->control.hwinfo.id);
if (first->control.switches) {
fprintf(out, " control {\n");
soundcard_setup_write_switches(out, " ", first->no, SND_INTERFACE_CONTROL, &first->control.switches);
fprintf(out, " }\n");
}
for (mixer = first->mixers; mixer; mixer = mixer->next) {
fprintf(out, " mixer(\"%s\") {\n", mixer->info.name);
soundcard_setup_write_switches(out, " ", first->no, SND_INTERFACE_MIXER, &mixer->switches);
for (mixerelement = mixer->elements; mixerelement; mixerelement = mixerelement->next)
soundcard_setup_write_mixer_element(out, mixerelement);
fprintf(out, " }\n");
}
for (pcm = first->pcms; pcm; pcm = pcm->next) {
if (!pcm->pswitches && !pcm->rswitches)
continue;
fprintf(out, " pcm(\"%s\") {\n", pcm->info.name);
if (pcm->pswitches) {
fprintf(out, " playback {\n");
soundcard_setup_write_switches(out, " ", first->no, SND_INTERFACE_PCM, &pcm->pswitches);
fprintf(out, " }\n");
}
if (pcm->rswitches) {
fprintf(out, " capture {\n");
soundcard_setup_write_switches(out, " ", first->no, SND_INTERFACE_PCM, &pcm->rswitches);
fprintf(out, " }\n");
}
fprintf(out, " }\n");
}
for (rawmidi = first->rawmidis; rawmidi; rawmidi = rawmidi->next) {
if (!rawmidi->oswitches && !rawmidi->iswitches)
continue;
fprintf(out, " rawmidi(\"%s\") {\n", rawmidi->info.name);
if (rawmidi->oswitches) {
fprintf(out, " output {\n");
soundcard_setup_write_switches(out, " ", first->no, SND_INTERFACE_RAWMIDI, &rawmidi->oswitches);
fprintf(out, " }\n");
}
if (rawmidi->iswitches) {
fprintf(out, " input {\n");
soundcard_setup_write_switches(out, " ", first->no, SND_INTERFACE_RAWMIDI, &rawmidi->iswitches);
fprintf(out, " }\n");
}
fprintf(out, " }\n");
if (first->control.controls) {
soundcard_setup_write_controls(out, " ", first->no, &first->control.controls);
}
fprintf(out, "}\n%s", cardno < 0 && first->next ? "\n" : "");
}

View file

@ -18,6 +18,11 @@
*
* ChangeLog:
*
* Fri Jun 23 14:10:00 MEST 2000 Jaroslav Kysela <perex@suse.cz>
*
* * ported to new mixer 0.6.x API (simple control)
* * improved error handling (mixer_abort)
*
* Thu Mar 9 22:54:16 MET 2000 Takashi iwai <iwai@ww.uni-erlangen.de>
*
* * a group is split into front, rear, center and woofer elements.
@ -26,7 +31,7 @@
*
* * version 1.00
*
* * ported to new mixer API (group control)
* * ported to new mixer API (scontrol control)
*
* Sun Feb 21 19:55:01 1999 Tim Janik <timj@gtk.org>
*
@ -121,7 +126,7 @@
#define PRGNAME "alsamixer"
#define PRGNAME_UPPER "AlsaMixer"
#define VERSION "v1.00"
#define CHECK_ABORT(e,s) ({ if (errno != EINTR) mixer_abort ((e), (s)); })
#define CHECK_ABORT(e,s,n) ({ if ((n) != -EINTR) mixer_abort ((e), (s), (n)); })
#define GETCH_BLOCK(w) ({ timeout ((w) ? -1 : 0); })
#undef MAX
@ -174,10 +179,9 @@ static float mixer_extra_space = 0;
static int mixer_cbar_height = 0;
static int card_id = 0;
static int mixer_id = 0;
static snd_mixer_t *mixer_handle;
static char *mixer_card_name = NULL;
static char *mixer_device_name = NULL;
static char mixer_card_name[128];
static char mixer_device_name[128];
/* mixer bar channel : left or right */
#define MIXER_CHN_LEFT 0
@ -210,10 +214,10 @@ static int mixer_elem_chn[][2] = {
{ SND_MIXER_CHN_WOOFER, -1 },
};
static snd_mixer_gid_t *mixer_gid = NULL;
static int mixer_n_groups = 0;
static snd_mixer_sid_t *mixer_sid = NULL;
static int mixer_n_scontrols = 0;
/* split groups */
/* split scontrols */
static int mixer_n_elems = 0;
static int mixer_n_vis_elems = 0;
static int mixer_first_vis_elem = 0;
@ -349,7 +353,8 @@ typedef enum
/* --- prototypes --- */
static void
mixer_abort (ErrType error,
const char *err_string)
const char *err_string,
int xerrno)
__attribute__
((noreturn));
@ -376,7 +381,8 @@ mixer_clear (int full_redraw)
static void
mixer_abort (ErrType error,
const char *err_string)
const char *err_string,
int xerrno)
{
if (mixer_window)
{
@ -393,16 +399,15 @@ mixer_abort (ErrType error,
{
case ERR_OPEN:
fprintf (stderr,
PRGNAME ": failed to open mixer #%i/#%i: %s\n",
PRGNAME ": failed to open mixer #%i: %s\n",
card_id,
mixer_id,
snd_strerror (errno));
snd_strerror (xerrno));
break;
case ERR_FCN:
fprintf (stderr,
PRGNAME ": function %s failed: %s\n",
err_string,
snd_strerror (errno));
snd_strerror (xerrno));
break;
case ERR_SIGNAL:
fprintf (stderr,
@ -464,23 +469,23 @@ mixer_conv(int val, int omin, int omax, int nmin, int nmax)
}
static int
mixer_calc_volume(snd_mixer_group_t *group, int vol, int chn)
mixer_calc_volume(snd_mixer_simple_control_t *scontrol, int vol, int chn)
{
int vol1;
vol1 = (vol < 0) ? -vol : vol;
if (vol1 > 0) {
if (vol1 > 100)
vol1 = group->max;
vol1 = scontrol->max;
else
vol1 = mixer_conv(vol1, 0, 100, group->min, group->max);
vol1 = mixer_conv(vol1, 0, 100, scontrol->min, scontrol->max);
if (vol1 <= 0)
vol1 = 1;
if (vol < 0)
vol1 = -vol1;
}
vol1 += group->volume.values[chn];
return CLAMP(vol1, group->min, group->max);
vol1 += scontrol->volume.values[chn];
return CLAMP(vol1, scontrol->min, scontrol->max);
}
/* set new channel values
@ -488,22 +493,24 @@ mixer_calc_volume(snd_mixer_group_t *group, int vol, int chn)
static void
mixer_write_cbar (int elem_index)
{
snd_mixer_group_t group;
snd_mixer_simple_control_t scontrol;
int vleft, vright, vbalance;
int type, chn_left, chn_right;
int i, changed;
int i, err, changed;
bzero(&group, sizeof(group));
group.gid = mixer_gid[mixer_grpidx[elem_index]];
if (snd_mixer_group_read (mixer_handle, &group) < 0)
CHECK_ABORT (ERR_FCN, "snd_mixer_group_read()");
bzero(&scontrol, sizeof(scontrol));
if (mixer_sid == NULL)
return;
scontrol.sid = mixer_sid[mixer_grpidx[elem_index]];
if ((err = snd_mixer_simple_control_read (mixer_handle, &scontrol)) < 0)
CHECK_ABORT (ERR_FCN, "snd_mixer_simple_control_read()", err);
type = mixer_type[elem_index];
chn_left = mixer_elem_chn[type][MIXER_CHN_LEFT];
if (! (group.channels & (1 << chn_left)))
if (! (scontrol.channels & (1 << chn_left)))
return; /* ..??.. */
chn_right = mixer_elem_chn[type][MIXER_CHN_RIGHT];
if (chn_right >= 0 && ! (group.channels & (1 << chn_right)))
if (chn_right >= 0 && ! (scontrol.channels & (1 << chn_right)))
chn_right = -1;
changed = 0;
@ -513,31 +520,31 @@ mixer_write_cbar (int elem_index)
if ((mixer_volume_delta[MIXER_CHN_LEFT] ||
mixer_volume_delta[MIXER_CHN_RIGHT] ||
mixer_balance_volumes) &&
(group.caps & SND_MIXER_GRPCAP_VOLUME)) {
(scontrol.caps & SND_MIXER_SCTCAP_VOLUME)) {
int mono =
(chn_right < 0 || (group.caps & SND_MIXER_GRPCAP_JOINTLY_VOLUME));
(chn_right < 0 || (scontrol.caps & SND_MIXER_SCTCAP_JOINTLY_VOLUME));
if (mono && !mixer_volume_delta[MIXER_CHN_LEFT])
mixer_volume_delta[MIXER_CHN_LEFT] = mixer_volume_delta[MIXER_CHN_RIGHT];
vleft = mixer_calc_volume(&group, mixer_volume_delta[MIXER_CHN_LEFT], chn_left);
vleft = mixer_calc_volume(&scontrol, mixer_volume_delta[MIXER_CHN_LEFT], chn_left);
vbalance = vleft;
if (! mono) {
vright = mixer_calc_volume(&group, mixer_volume_delta[MIXER_CHN_RIGHT], chn_right);
vright = mixer_calc_volume(&scontrol, mixer_volume_delta[MIXER_CHN_RIGHT], chn_right);
vbalance += vright;
vbalance /= 2;
} else
vright = vleft;
if (vleft >= 0 && vright >= 0) {
if (group.caps & SND_MIXER_GRPCAP_JOINTLY_VOLUME) {
if (scontrol.caps & SND_MIXER_SCTCAP_JOINTLY_VOLUME) {
for (i = 0; i < SND_MIXER_CHN_LAST; i++) {
if (group.channels & (1 << i))
group.volume.values[i] = vleft;
if (scontrol.channels & (1 << i))
scontrol.volume.values[i] = vleft;
}
} else {
if (mixer_balance_volumes)
vleft = vright = vbalance;
group.volume.values[chn_left] = vleft;
scontrol.volume.values[chn_left] = vleft;
if (! mono)
group.volume.values[chn_right] = vright;
scontrol.volume.values[chn_right] = vright;
}
changed = 1;
}
@ -547,15 +554,15 @@ mixer_write_cbar (int elem_index)
/* mute
*/
if (mixer_toggle_mute && (group.caps & SND_MIXER_GRPCAP_MUTE)) {
group.mute &= group.channels;
if (group.caps & SND_MIXER_GRPCAP_JOINTLY_MUTE)
group.mute = group.mute ? 0 : group.channels;
if (mixer_toggle_mute && (scontrol.caps & SND_MIXER_SCTCAP_MUTE)) {
scontrol.mute &= scontrol.channels;
if (scontrol.caps & SND_MIXER_SCTCAP_JOINTLY_MUTE)
scontrol.mute = scontrol.mute ? 0 : scontrol.channels;
else {
if (mixer_toggle_mute & MIXER_MASK_LEFT)
group.mute ^= (1 << chn_left);
scontrol.mute ^= (1 << chn_left);
if (chn_right >= 0 && (mixer_toggle_mute & MIXER_MASK_RIGHT))
group.mute ^= (1 << chn_right);
scontrol.mute ^= (1 << chn_right);
}
changed = 1;
}
@ -563,23 +570,23 @@ mixer_write_cbar (int elem_index)
/* capture
*/
if (mixer_toggle_capture && (group.caps & SND_MIXER_GRPCAP_CAPTURE)) {
group.capture &= group.channels;
if (group.caps & SND_MIXER_GRPCAP_JOINTLY_CAPTURE)
group.capture = group.capture ? 0 : group.channels;
if (mixer_toggle_capture && (scontrol.caps & SND_MIXER_SCTCAP_CAPTURE)) {
scontrol.capture &= scontrol.channels;
if (scontrol.caps & SND_MIXER_SCTCAP_JOINTLY_CAPTURE)
scontrol.capture = scontrol.capture ? 0 : scontrol.channels;
else {
if (mixer_toggle_capture & MIXER_MASK_LEFT)
group.capture ^= (1 << chn_left);
scontrol.capture ^= (1 << chn_left);
if (chn_right >= 0 && (mixer_toggle_capture & MIXER_MASK_RIGHT))
group.capture ^= (1 << chn_right);
scontrol.capture ^= (1 << chn_right);
}
changed = 1;
}
mixer_toggle_capture = 0;
if (changed) {
if (snd_mixer_group_write (mixer_handle, &group) < 0)
CHECK_ABORT (ERR_FCN, "snd_mixer_group_write()");
if ((err = snd_mixer_simple_control_write (mixer_handle, &scontrol)) < 0)
CHECK_ABORT (ERR_FCN, "snd_mixer_simple_control_write()", err);
}
}
@ -588,37 +595,42 @@ static void
mixer_update_cbar (int elem_index)
{
char string[64], string1[64];
int dc;
snd_mixer_group_t group;
int err, dc;
snd_mixer_simple_control_t scontrol;
int vleft, vright;
int type, chn_left, chn_right;
int x, y, i;
/* set new group indices and read info
fprintf(stderr, "update cbar\n");
/* set new scontrol indices and read info
*/
bzero(&group, sizeof(group));
group.gid = mixer_gid[mixer_grpidx[elem_index]];
if (snd_mixer_group_read (mixer_handle, &group) < 0)
CHECK_ABORT (ERR_FCN, "snd_mixer_group_read()");
bzero(&scontrol, sizeof(scontrol));
if (mixer_sid == NULL)
return;
scontrol.sid = mixer_sid[mixer_grpidx[elem_index]];
if ((err = snd_mixer_simple_control_read (mixer_handle, &scontrol)) < 0)
CHECK_ABORT (ERR_FCN, "snd_mixer_simple_control_read()", err);
fprintf(stderr, "scontrol.channels = 0x%x\n", scontrol.channels);
type = mixer_type[elem_index];
chn_left = mixer_elem_chn[type][MIXER_CHN_LEFT];
if (! (group.channels & (1 << chn_left)))
if (! (scontrol.channels & (1 << chn_left)))
return; /* ..??.. */
chn_right = mixer_elem_chn[type][MIXER_CHN_RIGHT];
if (chn_right >= 0 && ! (group.channels & (1 << chn_right)))
if (chn_right >= 0 && ! (scontrol.channels & (1 << chn_right)))
chn_right = -1;
/* first, read values for the numbers to be displayed
*/
if (snd_mixer_group_read (mixer_handle, &group) < 0)
CHECK_ABORT (ERR_FCN, "snd_mixer_group_read()");
if ((err = snd_mixer_simple_control_read (mixer_handle, &scontrol)) < 0)
CHECK_ABORT (ERR_FCN, "snd_mixer_simple_control_read()", err);
vleft = group.volume.values[chn_left];
vleft = mixer_conv(vleft, group.min, group.max, 0, 100);
vleft = scontrol.volume.values[chn_left];
vleft = mixer_conv(vleft, scontrol.min, scontrol.max, 0, 100);
if (chn_right >= 0) {
vright = group.volume.values[chn_right];
vright = mixer_conv(vright, group.min, group.max, 0, 100);
vright = scontrol.volume.values[chn_right];
vright = mixer_conv(vright, scontrol.min, scontrol.max, 0, 100);
} else {
vright = vleft;
}
@ -631,10 +643,10 @@ mixer_update_cbar (int elem_index)
/* channel bar name
*/
mixer_dc (elem_index == mixer_focus_elem ? DC_CBAR_FOCUS_LABEL : DC_CBAR_LABEL);
if (group.gid.index > 0)
sprintf(string1, "%s %d", group.gid.name, group.gid.index);
if (scontrol.sid.index > 0)
sprintf(string1, "%s %d", scontrol.sid.name, scontrol.sid.index);
else
strcpy(string1, group.gid.name);
strcpy(string1, scontrol.sid.name);
string1[8] = 0;
for (i = 0; i < 8; i++)
{
@ -695,10 +707,10 @@ mixer_update_cbar (int elem_index)
mvaddstr (y, x, " ");
mixer_dc (DC_CBAR_FRAME);
mvaddch (y, x + 2, ACS_ULCORNER);
dc = group.mute & (1 << chn_left) ? DC_CBAR_MUTE : DC_CBAR_NOMUTE;
dc = scontrol.mute & (1 << chn_left) ? DC_CBAR_MUTE : DC_CBAR_NOMUTE;
mvaddch (y, x + 3, mixer_dc (dc));
if (chn_right >= 0)
dc = group.mute & (1 << chn_right) ? DC_CBAR_MUTE : DC_CBAR_NOMUTE;
dc = scontrol.mute & (1 << chn_right) ? DC_CBAR_MUTE : DC_CBAR_NOMUTE;
mvaddch (y, x + 4, mixer_dc (dc));
mixer_dc (DC_CBAR_FRAME);
mvaddch (y, x + 5, ACS_URCORNER);
@ -706,20 +718,20 @@ mixer_update_cbar (int elem_index)
/* capture input?
*/
if ((group.capture & (1 << chn_left)) ||
(chn_right >= 0 && (group.capture & (1 << chn_right))))
if ((scontrol.capture & (1 << chn_left)) ||
(chn_right >= 0 && (scontrol.capture & (1 << chn_right))))
{
mixer_dc (DC_CBAR_CAPTURE);
mvaddstr (y, x + 1, "CAPTUR");
if (group.capture & (1 << chn_left)) {
if (scontrol.capture & (1 << chn_left)) {
mvaddstr (y + 1, x + 1, "L");
if (chn_right < 0)
mvaddstr (y + 1, x + 6, "R");
}
if (chn_right >= 0 && (group.capture & (1 << chn_right)))
if (chn_right >= 0 && (scontrol.capture & (1 << chn_right)))
mvaddstr (y + 1, x + 6, "R");
}
else if (group.caps & SND_MIXER_GRPCAP_CAPTURE)
else if (scontrol.caps & SND_MIXER_SCTCAP_CAPTURE)
for (i = 0; i < 6; i++)
mvaddch (y, x + 1 + i, mixer_dc (DC_CBAR_NOCAPTURE));
else
@ -746,6 +758,7 @@ mixer_update_cbars (void)
mixer_cbar_get_pos (mixer_focus_elem, &x, &y);
}
mixer_write_cbar(mixer_focus_elem);
fprintf(stderr, "mixer_n_vis_elems = %i\n", mixer_n_vis_elems);
for (i = 0; i < mixer_n_vis_elems; i++)
mixer_update_cbar (i + mixer_first_vis_elem);
@ -1178,75 +1191,78 @@ mixer_show_procinfo (void)
static void
mixer_init (void)
{
static snd_mixer_info_t mixer_info = { 0, };
static struct snd_ctl_hw_info hw_info;
snd_ctl_hw_info_t hw_info;
snd_ctl_t *ctl_handle;
int err;
if (snd_ctl_open (&ctl_handle, card_id) < 0)
mixer_abort (ERR_OPEN, "snd_ctl_open");
if (snd_ctl_hw_info (ctl_handle, &hw_info) < 0)
mixer_abort (ERR_FCN, "snd_ctl_hw_info");
if ((err = snd_ctl_open (&ctl_handle, card_id)) < 0)
mixer_abort (ERR_OPEN, "snd_ctl_open", err);
if ((err = snd_ctl_hw_info (ctl_handle, &hw_info)) < 0)
mixer_abort (ERR_FCN, "snd_ctl_hw_info", err);
snd_ctl_close (ctl_handle);
/* open mixer device
*/
if (snd_mixer_open (&mixer_handle, card_id, mixer_id) < 0)
mixer_abort (ERR_OPEN, "snd_mixer_open");
if ((err = snd_mixer_open (&mixer_handle, card_id)) < 0)
mixer_abort (ERR_OPEN, "snd_mixer_open", err);
/* setup global variables
*/
if (snd_mixer_info (mixer_handle, &mixer_info) < 0)
mixer_abort (ERR_FCN, "snd_mixer_info");
mixer_card_name = hw_info.name;
mixer_device_name = mixer_info.name;
strcpy(mixer_card_name, hw_info.name);
strcpy(mixer_device_name, hw_info.mixername);
}
static void
mixer_reinit (void)
{
snd_mixer_groups_t groups;
int idx, elem_index, i;
snd_mixer_gid_t focus_gid;
snd_mixer_simple_control_list_t scontrols;
int idx, err, elem_index, i;
snd_mixer_sid_t focus_gid;
int focus_type = -1;
if (mixer_gid) {
focus_gid = mixer_gid[mixer_grpidx[mixer_focus_elem]];
if (mixer_sid) {
focus_gid = mixer_sid[mixer_grpidx[mixer_focus_elem]];
focus_type = mixer_type[mixer_focus_elem];
}
while (1) {
bzero(&groups, sizeof(groups));
if (snd_mixer_groups(mixer_handle, &groups) < 0)
mixer_abort (ERR_FCN, "snd_mixer_groups");
mixer_n_groups = groups.groups_over;
if (mixer_n_groups > 0) {
groups.groups_size = mixer_n_groups;
groups.pgroups = (snd_mixer_gid_t *)malloc(sizeof(snd_mixer_gid_t) * mixer_n_groups);
if (groups.pgroups == NULL)
mixer_abort (ERR_FCN, "malloc");
groups.groups_over = 0;
groups.groups = 0;
if (snd_mixer_groups(mixer_handle, &groups) < 0)
mixer_abort (ERR_FCN, "snd_mixer_groups");
if (groups.groups_over > 0) {
free(groups.pgroups);
bzero(&scontrols, sizeof(scontrols));
if ((err = snd_mixer_simple_control_list(mixer_handle, &scontrols)) < 0)
mixer_abort (ERR_FCN, "snd_mixer_simple_control_list", err);
mixer_n_scontrols = scontrols.controls;
fprintf(stderr, "controls = %i\n", scontrols.controls);
if (mixer_n_scontrols > 0) {
scontrols.controls_request = mixer_n_scontrols;
scontrols.pids = (snd_mixer_sid_t *)malloc(sizeof(snd_mixer_sid_t) * mixer_n_scontrols);
if (scontrols.pids == NULL)
mixer_abort (ERR_FCN, "malloc", 0);
scontrols.controls_offset = 0;
scontrols.controls_count = 0;
if ((err = snd_mixer_simple_control_list(mixer_handle, &scontrols)) < 0)
mixer_abort (ERR_FCN, "snd_mixer_simple_control_list", err);
if (scontrols.controls > scontrols.controls_count) {
free(scontrols.pids);
continue;
}
}
if (mixer_gid)
free(mixer_gid);
mixer_gid = groups.pgroups;
if (mixer_sid)
free(mixer_sid);
mixer_sid = scontrols.pids;
fprintf(stderr, "mixer_sid = 0x%x\n", (int)mixer_sid);
break;
}
snd_mixer_sort_gid_table(mixer_gid, mixer_n_groups, snd_mixer_default_weights);
#if 0
snd_mixer_sort_gid_table(mixer_sid, mixer_n_scontrols, snd_mixer_default_weights);
#endif
mixer_n_elems = 0;
for (idx = 0; idx < mixer_n_groups; idx++) {
snd_mixer_group_t group;
bzero(&group, sizeof(group));
group.gid = mixer_gid[idx];
if (snd_mixer_group_read(mixer_handle, &group) < 0)
CHECK_ABORT (ERR_FCN, "snd_mixer_group_read()");
for (idx = 0; idx < mixer_n_scontrols; idx++) {
snd_mixer_simple_control_t scontrol;
bzero(&scontrol, sizeof(scontrol));
scontrol.sid = mixer_sid[idx];
if ((err = snd_mixer_simple_control_read(mixer_handle, &scontrol)) < 0)
CHECK_ABORT (ERR_FCN, "snd_mixer_simple_control_read()", 0);
fprintf(stderr, "scontrol.channels = 0x%x\n", scontrol.channels);
for (i = 0; i < MIXER_ELEM_END; i++) {
if (group.channels & mixer_elem_mask[i])
if (scontrol.channels & mixer_elem_mask[i])
mixer_n_elems++;
}
}
@ -1255,21 +1271,21 @@ mixer_reinit (void)
free(mixer_type);
mixer_type = (int *)malloc(sizeof(int) * mixer_n_elems);
if (mixer_type == NULL)
mixer_abort(ERR_FCN, "malloc");
mixer_abort(ERR_FCN, "malloc", 0);
if (mixer_grpidx)
free(mixer_grpidx);
mixer_grpidx = (int *)malloc(sizeof(int) * mixer_n_elems);
if (mixer_grpidx == NULL)
mixer_abort(ERR_FCN, "malloc");
mixer_abort(ERR_FCN, "malloc", 0);
elem_index = 0;
for (idx = 0; idx < mixer_n_groups; idx++) {
snd_mixer_group_t group;
bzero(&group, sizeof(group));
group.gid = mixer_gid[idx];
if (snd_mixer_group_read(mixer_handle, &group) < 0)
CHECK_ABORT (ERR_FCN, "snd_mixer_group_read()");
for (idx = 0; idx < mixer_n_scontrols; idx++) {
snd_mixer_simple_control_t scontrol;
bzero(&scontrol, sizeof(scontrol));
scontrol.sid = mixer_sid[idx];
if ((err = snd_mixer_simple_control_read(mixer_handle, &scontrol)) < 0)
CHECK_ABORT (ERR_FCN, "snd_mixer_simple_control_read()", err);
for (i = 0; i < MIXER_ELEM_END; i++) {
if (group.channels & mixer_elem_mask[i]) {
if (scontrol.channels & mixer_elem_mask[i]) {
mixer_grpidx[elem_index] = idx;
mixer_type[elem_index] = i;
elem_index++;
@ -1282,7 +1298,7 @@ mixer_reinit (void)
mixer_focus_elem = 0;
if (focus_type >= 0) {
for (elem_index = 0; elem_index < mixer_n_elems; elem_index++) {
if (!memcmp(&focus_gid, &mixer_gid[mixer_grpidx[elem_index]], sizeof(focus_gid)) &&
if (!memcmp(&focus_gid, &mixer_sid[mixer_grpidx[elem_index]], sizeof(focus_gid)) &&
mixer_type[elem_index] == focus_type) {
mixer_focus_elem = elem_index;
break;
@ -1371,7 +1387,7 @@ mixer_resize (void)
}
static void
mixer_callback_rebuild (void *private_data)
mixer_callback_rebuild (snd_mixer_t *handle, void *private_data)
{
/* we don't actually need to update the individual channels because
* we redraw the whole screen upon every main iteration anyways.
@ -1380,7 +1396,7 @@ mixer_callback_rebuild (void *private_data)
}
static void
mixer_callback_group (void *private_data, int cmd, snd_mixer_gid_t *gid)
mixer_callback_scontrol (snd_mixer_t *handle, void *private_data, snd_mixer_sid_t *gid)
{
mixer_reinit ();
}
@ -1407,7 +1423,7 @@ static int
mixer_iteration (void)
{
struct timeval delay = { 0, };
snd_mixer_callbacks_t callbacks = { 0, };
snd_mixer_simple_callbacks_t callbacks = { 0, };
int mixer_fd;
fd_set rfds;
int finished = 0;
@ -1415,7 +1431,10 @@ mixer_iteration (void)
int old_view;
callbacks.rebuild = mixer_callback_rebuild;
callbacks.group = mixer_callback_group;
callbacks.value = mixer_callback_scontrol;
callbacks.change = mixer_callback_scontrol;
callbacks.add = mixer_callback_scontrol;
callbacks.remove = mixer_callback_scontrol;
/* setup for select on stdin and the mixer fd */
mixer_fd = snd_mixer_file_descriptor (mixer_handle);
@ -1438,7 +1457,7 @@ mixer_iteration (void)
mixer_resize ();
if (FD_ISSET (mixer_fd, &rfds))
snd_mixer_read (mixer_handle, &callbacks);
snd_mixer_simple_read (mixer_handle, &callbacks);
if (FD_ISSET (fileno (stdin), &rfds))
key = getch ();
@ -1676,7 +1695,7 @@ static void
mixer_signal_handler (int signal)
{
if (signal != SIGSEGV)
mixer_abort (ERR_SIGNAL, sys_siglist[signal]);
mixer_abort (ERR_SIGNAL, sys_siglist[signal], 0);
else
{
fprintf (stderr, "\nSegmentation fault.\n");
@ -1694,23 +1713,20 @@ main (int argc,
*/
do
{
opt = getopt (argc, argv, "c:m:shg");
opt = getopt (argc, argv, "c:shg");
switch (opt)
{
case '?':
case 'h':
fprintf (stderr, "%s %s\n", PRGNAME_UPPER, VERSION);
fprintf (stderr, "Usage: %s [-c <card: 1..%i>] [-m <mixer: 0..1>] [-z]\n", PRGNAME, snd_cards ());
mixer_abort (ERR_NONE, "");
fprintf (stderr, "Usage: %s [-c <card: 0..%i>] [-z]\n", PRGNAME, snd_cards () - 1);
mixer_abort (ERR_NONE, "", 0);
case 'c':
card_id = snd_card_name (optarg);
break;
case 'g':
mixer_do_color = !mixer_do_color;
break;
case 'm':
mixer_id = CLAMP (optarg[0], '0', '1') - '0';
break;
case 's':
mixer_minimize = 1;
break;
@ -1766,5 +1782,5 @@ main (int argc,
}
while (!mixer_iteration ());
mixer_abort (ERR_NONE, "");
mixer_abort (ERR_NONE, "", 0);
};

File diff suppressed because it is too large Load diff