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

View file

@ -37,53 +37,22 @@ extern int debugflag;
extern void error(const char *fmt,...); extern void error(const char *fmt,...);
struct ctl_switch { struct ctl_control {
int change; int change;
snd_switch_t s; snd_control_type_t type;
struct ctl_switch *next; snd_control_info_t info;
snd_control_t c;
struct ctl_control *next;
}; };
struct ctl { struct ctl {
snd_ctl_hw_info_t hwinfo; snd_ctl_hw_info_t hwinfo;
struct ctl_switch *switches; struct ctl_control *controls;
};
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 soundcard { struct soundcard {
int no; /* card number */ int no; /* card number */
struct ctl control; struct ctl control;
struct mixer *mixers;
struct pcm *pcms;
struct rawmidi *rawmidis;
struct soundcard *next; struct soundcard *next;
}; };
@ -94,11 +63,8 @@ void soundcard_setup_init(void);
void soundcard_setup_done(void); void soundcard_setup_done(void);
int soundcard_setup_load(const char *filename, int skip); int soundcard_setup_load(const char *filename, int skip);
int soundcard_setup_write(const char *filename, int cardno); int soundcard_setup_write(const char *filename, int cardno);
int soundcard_setup_collect_switches(int cardno); int soundcard_setup_collect_controls(int cardno);
int soundcard_setup_collect_data(int cardno); int soundcard_setup_merge_controls(int cardno);
int soundcard_setup_merge_switches(int cardno); int soundcard_setup_process_controls(int cardno);
int soundcard_setup_merge_data(int cardno);
int soundcard_setup_process_switches(int cardno);
int soundcard_setup_process_data(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; soundcard return L_SOUNDCARD;
control return L_CONTROL; control return L_CONTROL;
global return L_GLOBAL;
hwdep return L_HWDEP;
mixer return L_MIXER; mixer return L_MIXER;
element return L_ELEMENT;
switch return L_SWITCH;
rawdata return L_RAWDATA;
pcm return L_PCM; pcm return L_PCM;
rawmidi return L_RAWMIDI; rawmidi return L_RAWMIDI;
playback return L_PLAYBACK; timer return L_TIMER;
capture return L_CAPTURE; sequencer return L_SEQUENCER;
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;
/* boolean */ /* boolean */
@ -108,10 +69,8 @@ true|on|yes return L_TRUE;
/* integers */ /* integers */
[0-9]+ { yylval.i_value = atoi(yytext); return L_INTEGER; } [0-9]+ { yylval.i_value = strtol(yytext, (char **)NULL, 10); return L_INTEGER; }
0x[0-9a-f]+ { char *end; 0x[0-9a-f]+ { yylval.i_value = strtol(yytext, (char **)NULL, 0); return L_INTEGER; }
yylval.i_value = strtol(yytext, &end, 0);
return L_INTEGER; }
/* byte array */ /* byte array */

View file

@ -44,54 +44,18 @@ struct bytearray {
static void yyerror(char *, ...); static void yyerror(char *, ...);
static void build_soundcard(char *name); static void build_soundcard(char *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);
static void build_pcm(char *name); static void build_control_end(void);
static void build_rawmidi(char *name); static void set_control_boolean(int val);
static void set_control_integer(long val);
static void build_mixer_element(char *name, int index, int etype); static void set_control_bytearray(struct bytearray val);
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);
/* local variables */ /* local variables */
static struct soundcard *Xsoundcard = NULL; static struct soundcard *Xsoundcard = NULL;
static struct mixer *Xmixer = NULL; static struct ctl_control *Xcontrol = NULL;
static struct pcm *Xpcm = NULL; static int Xposition = 0;
static struct rawmidi *Xrawmidi = NULL; static snd_control_type_t Xtype = SND_CONTROL_TYPE_NONE;
static struct mixer_element *Xelement = NULL;
static struct ctl_switch *Xswitch = NULL;
static unsigned int Xswitchiec958ocs = 0;
static unsigned short Xswitchiec958ocs1[16];
%} %}
@ -99,7 +63,7 @@ static unsigned short Xswitchiec958ocs1[16];
%union { %union {
int b_value; int b_value;
int i_value; long i_value;
char *s_value; char *s_value;
struct bytearray a_value; struct bytearray a_value;
}; };
@ -116,19 +80,12 @@ static unsigned short Xswitchiec958ocs1[16];
/* misc */ /* misc */
%token L_DOUBLE1 %token L_DOUBLE1
/* other keywords */ /* other keywords */
%token L_SOUNDCARD L_MIXER L_ELEMENT L_SWITCH L_RAWDATA %token L_SOUNDCARD L_CONTROL L_RAWDATA
%token L_CONTROL L_PCM L_RAWMIDI L_PLAYBACK L_CAPTURE L_INPUT L_OUTPUT %token L_GLOBAL L_HWDEP L_MIXER L_PCM L_RAWMIDI L_TIMER L_SEQUENCER
%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
%type <b_value> boolean %type <b_value> boolean
%type <i_value> integer %type <i_value> integer iface
%type <s_value> string %type <s_value> string
%type <a_value> rawdata %type <a_value> rawdata
@ -147,224 +104,31 @@ soundcards :
| soundcards soundcard | soundcards soundcard
; ;
soundcard : L_CONTROL '{' controls '}' soundcard : L_CONTROL '(' iface ',' integer ',' integer ',' string ',' integer
| L_MIXER '(' string { build_mixer($3); } { build_control_begin($3, $5, $7, $9, $11); }
L_DOUBLE1 mixers '}' { build_mixer(NULL); } ',' controls ')' { build_control_end(); }
| L_PCM '(' string { build_pcm($3); }
L_DOUBLE1 pcms '}' { build_pcm(NULL); }
| L_RAWMIDI '(' string { build_rawmidi($3); }
L_DOUBLE1 rawmidis '}' { build_rawmidi(NULL); }
| error { yyerror( "an unknown keyword in the soundcard{} level"); } | error { yyerror( "an unknown keyword in the soundcard{} level"); }
; ;
controls : control controls : control
| controls control | controls ',' control
; ;
control : L_SWITCH '(' string { build_control_switch($3); } control : boolean { set_control_boolean($1); }
',' switches ')' { build_control_switch(NULL); } | integer { set_control_integer($1); }
| error { yyerror("an unknown keyword in the control{} level"); } | rawdata { set_control_bytearray($1); }
| error { yyerror( "an unknown keyword in the control() data parameter" ); }
; ;
iface : L_INTEGER { $$ = $1; }
mixers : /* empty */ | L_GLOBAL { $$ = SND_CONTROL_IFACE_CARD; }
| mixers mixer | L_HWDEP { $$ = SND_CONTROL_IFACE_HWDEP; }
; | L_MIXER { $$ = SND_CONTROL_IFACE_MIXER; }
| L_PCM { $$ = SND_CONTROL_IFACE_PCM; }
mixer : L_ELEMENT '(' string | L_RAWMIDI { $$ = SND_CONTROL_IFACE_RAWMIDI; }
',' integer ',' integer { build_mixer_element($3, $5, $7); } | L_TIMER { $$ = SND_CONTROL_IFACE_TIMER; }
',' etype ')' { build_mixer_element(NULL, -1, -1); } | L_SEQUENCER { $$ = SND_CONTROL_IFACE_SEQUENCER; }
| L_SWITCH '(' string { build_mixer_switch($3); } | error { yyerror( "an unknown keyword in the interface field"); }
',' 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" ); }
; ;
boolean : L_TRUE { $$ = 1; } boolean : L_TRUE { $$ = 1; }
@ -426,425 +190,86 @@ static void build_soundcard(char *name)
free(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) { first = &Xsoundcard->control.controls;
Xmixer = NULL; Xcontrol = (struct ctl_control *)malloc(sizeof(struct ctl_control));
return; if (!Xcontrol) {
}
Xmixer = (struct mixer *)malloc(sizeof(struct pcm));
if (!Xmixer) {
free(name); free(name);
error_nomem(); error_nomem();
return; return;
} }
bzero(Xmixer, sizeof(*Xmixer)); Xposition = 0;
for (mixer = Xsoundcard->mixers; mixer && mixer->next; mixer = mixer->next); Xtype = SND_CONTROL_TYPE_NONE;
if (mixer) { bzero(Xcontrol, sizeof(*Xcontrol));
mixer->next = Xmixer; for (ctl = *first; ctl && ctl->next; ctl = ctl->next);
if (ctl) {
ctl->next = Xcontrol;
} else { } 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); free(name);
} }
static void build_pcm(char *name) static void build_control_end(void)
{ {
struct pcm *pcm; Xcontrol = NULL;
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);
} }
static void build_rawmidi(char *name) static void set_control_boolean(int val)
{ {
struct rawmidi *rawmidi; switch (Xtype) {
case SND_CONTROL_TYPE_NONE:
if (!name) { case SND_CONTROL_TYPE_BOOLEAN:
Xrawmidi = NULL; Xtype = Xcontrol->type = SND_CONTROL_TYPE_BOOLEAN;
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;
break; break;
case SND_MIXER_EFF1_MONO_SW: case SND_CONTROL_TYPE_INTEGER:
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;
break; break;
default: default:
yyerror("Unknown effect 0x%x\n", effect); yyerror("Unexpected previous type (%i).\n", Xtype);
} }
if (Xposition < 512)
Xcontrol->c.value.integer.value[Xposition++] = val ? 1 : 0;
else
yyerror("Array overflow.");
} }
static void mixer_accu3(int end) static void set_control_integer(long val)
{
mixer_type_check(SND_MIXER_ETYPE_ACCU3);
}
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)
{ {
unsigned int xx; unsigned int xx;
Xswitch->s.type = SND_SW_TYPE_DWORD; 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; xx = val;
memcpy(&Xswitch->s.value, &xx, sizeof(xx)); Xcontrol->c.value.integer.value[Xposition++] = val;
}
} }
static void set_switch_bytearray(struct bytearray val) static void set_control_bytearray(struct bytearray val)
{ {
Xswitch->s.type = SND_SW_TYPE_USER; 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 > 32) if (val.datalen + Xposition > 512)
yyerror("Byte array too large for switch."); yyerror("Byte array too large for control.");
memcpy(Xswitch->s.value.data8, val.data, val.datalen); memcpy(&Xcontrol->c.value.bytes.data[Xposition], val.data, val.datalen);
} Xposition += 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;
}
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)
{
if (idx == 0) {
Xswitchiec958ocs = val ? 1 : 0;
return;
}
Xswitchiec958ocs1[idx] &= mask;
Xswitchiec958ocs1[idx] |= val;
} }

View file

@ -21,141 +21,98 @@
#include "alsactl.h" #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]; int idx;
sprintf(str, "%s %s card %i", name, id, cardno); if (!(cctl->info.access & SND_CONTROL_ACCESS_WRITE))
if (devno >= 0) return 0;
sprintf(str + strlen(str)," device %i", devno); switch (cctl->info.type) {
return str; 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));
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));
return 1; return 1;
} }
if (csw->s.value.enable != usw->s.value.enable) { for (idx = 0; idx < cctl->info.values_count; idx++) {
csw->change = 1; if (cctl->c.value.integer.value[idx] != uctl->c.value.integer.value[idx]) {
csw->s.value.enable = usw->s.value.enable; cctl->change = 1;
} cctl->c.value.integer.value[idx] = uctl->c.value.integer.value[idx];
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];
}
} }
} }
break; break;
case SND_SW_TYPE_BYTE: case SND_CONTROL_TYPE_INTEGER:
if (usw->s.type != SND_SW_TYPE_DWORD) { if (uctl->type != SND_CONTROL_TYPE_BOOLEAN && uctl->type != SND_CONTROL_TYPE_INTEGER) {
error("A wrong type for the switch %s. The type byte is expected. Skipping...", sw_id(usw->s.name, cardno, devno, id)); error("A wrong type %i for the control '%s'. The type integer is expected. Skipping...", uctl->type, control_id(&uctl->c.id));
return 1; return 1;
} }
if (csw->s.low > usw->s.value.data32[0] || for (idx = 0; idx < cctl->info.values_count; idx++) {
csw->s.high < usw->s.value.data32[0]) { if (cctl->info.value.integer.min > uctl->c.value.integer.value[idx] ||
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); 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; return 1;
} }
if (csw->s.value.data8[0] != (unsigned char)usw->s.value.data32[0]) { if (cctl->c.value.integer.value[idx] != uctl->c.value.integer.value[idx]) {
csw->change = 1; cctl->change = 1;
csw->s.value.data8[0] = (unsigned char)usw->s.value.data32[0]; cctl->c.value.integer.value[idx] = uctl->c.value.integer.value[idx];
}
} }
break; break;
case SND_SW_TYPE_WORD: case SND_CONTROL_TYPE_ENUMERATED:
if (usw->s.type != SND_SW_TYPE_DWORD) { if (uctl->type != SND_CONTROL_TYPE_BOOLEAN && uctl->type != SND_CONTROL_TYPE_INTEGER) {
error("A wrong type for the switch %s. The type word is expected. Skipping...", sw_id(usw->s.name, cardno, devno, id)); error("A wrong type %i for the control '%s'. The type integer is expected. Skipping...", uctl->type, control_id(&uctl->c.id));
return 1; return 1;
} }
if (csw->s.low > usw->s.value.data32[0] || for (idx = 0; idx < cctl->info.values_count; idx++) {
csw->s.high < usw->s.value.data32[0]) { if (cctl->info.value.enumerated.items <= uctl->c.value.integer.value[idx]) {
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); 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; return 1;
} }
if (csw->s.value.data16[0] != (unsigned short)usw->s.value.data32[0]) { if (cctl->c.value.enumerated.item[idx] != uctl->c.value.integer.value[idx]) {
csw->change = 1; cctl->change = 1;
csw->s.value.data16[0] = (unsigned short)usw->s.value.data32[0]; cctl->c.value.enumerated.item[idx] = uctl->c.value.integer.value[idx];
}
} }
break; break;
case SND_SW_TYPE_DWORD: case SND_CONTROL_TYPE_BYTES:
if (usw->s.type != SND_SW_TYPE_DWORD) { if (uctl->type != SND_CONTROL_TYPE_BYTES) {
error("A wrong type for the switch %s. The type dword is expected. Skipping...", sw_id(usw->s.name, cardno, devno, id)); error("A wrong type %i for the control %s. The type 'bytes' is expected. Skipping...", uctl->type, control_id(&uctl->c.id));
return 1; return 1;
} }
if (csw->s.low > usw->s.value.data32[0] || if (memcmp(cctl->c.value.bytes.data, uctl->c.value.bytes.data, uctl->info.values_count)) {
csw->s.high < usw->s.value.data32[0]) { cctl->change = 1;
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); memcpy(cctl->c.value.bytes.data, uctl->c.value.bytes.data, uctl->info.values_count);
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);
} }
break; break;
default: default:
error("The switch type %i is not known.", csw->s.type); error("The control type %i is not known.", cctl->type);
} }
return 0; 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 ( ; uctl; uctl = uctl->next) {
for (csw1 = csw; csw1; csw1 = csw1->next) { for (cctl1 = cctl; cctl1; cctl1 = cctl1->next) {
if (!strncmp(csw1->s.name, usw->s.name, sizeof(csw1->s.name))) { if (cctl1->c.id.iface == uctl->c.id.iface &&
merge_one_sw(csw1, usw, cardno, devno, id); 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; break;
} }
} }
if (!csw1) { if (!cctl1) {
error("Cannot find the switch %s...", sw_id(usw->s.name, cardno, devno, id)); error("Cannot find the control %s...", control_id(&uctl->c.id));
} }
} }
return 0; return 0;
} }
int soundcard_setup_merge_switches(int cardno) int soundcard_setup_merge_controls(int cardno)
{ {
struct soundcard *soundcard, *rsoundcard; struct soundcard *soundcard, *rsoundcard;
struct mixer *mixer, *rmixer;
struct pcm *pcm, *rpcm;
struct rawmidi *rawmidi, *rrawmidi;
for (rsoundcard = rsoundcards; rsoundcard; rsoundcard = rsoundcard->next) { for (rsoundcard = rsoundcards; rsoundcard; rsoundcard = rsoundcard->next) {
for (soundcard = soundcards; soundcard; soundcard = soundcard->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) if (cardno >= 0 && soundcard->no != cardno)
continue; continue;
soundcard_setup_merge_sw(soundcard->control.switches, rsoundcard->control.switches, soundcard->no, -1, "control"); soundcard_setup_merge_control(soundcard->control.controls, rsoundcard->control.controls, soundcard->no);
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");
}
} }
return 0; return 0;
} }
@ -405,110 +143,21 @@ static int soundcard_open_ctl(snd_ctl_t **ctlhandle, struct soundcard *soundcard
return 0; return 0;
} }
static int soundcard_open_mix(snd_mixer_t **mixhandle, struct soundcard *soundcard, struct mixer *mixer) int soundcard_setup_process_controls(int cardno)
{
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 err; int err;
snd_ctl_t *ctlhandle = NULL; snd_ctl_t *ctlhandle = NULL;
struct soundcard *soundcard; struct soundcard *soundcard;
struct ctl_switch *ctlsw; struct ctl_control *ctl;
struct mixer *mixer;
struct pcm *pcm;
struct rawmidi *rawmidi;
for (soundcard = soundcards; soundcard; soundcard = soundcard->next) { for (soundcard = soundcards; soundcard; soundcard = soundcard->next) {
if (cardno >= 0 && soundcard->no != cardno) if (cardno >= 0 && soundcard->no != cardno)
continue; continue;
for (ctlsw = soundcard->control.switches; ctlsw; ctlsw = ctlsw->next) { for (ctl = soundcard->control.controls; ctl; ctl = ctl->next) {
if (ctlsw->change) if (ctl->change)
if (!soundcard_open_ctl(&ctlhandle, soundcard)) { if (!soundcard_open_ctl(&ctlhandle, soundcard)) {
if ((err = snd_ctl_switch_write(ctlhandle, &ctlsw->s)) < 0) if ((err = snd_ctl_cwrite(ctlhandle, &ctl->c)) < 0)
error("Control switch '%s' write error: %s", ctlsw->s.name, snd_strerror(err)); 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) { if (ctlhandle) {

View file

@ -37,24 +37,13 @@ struct soundcard *rsoundcards = NULL;
* misc functions * 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 "???"; return "???";
strncpy(str, eid->name, sizeof(eid->name)); sprintf(str, "%i,%i,%i,%s,%i", id->iface, id->device, id->subdevice, id->name, id->index);
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);
return str; return str;
} }
@ -62,9 +51,9 @@ char *mixer_element_id(snd_mixer_eid_t *eid)
* free functions * 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) { while (first) {
next = first->next; 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) static void soundcard_free1(struct soundcard *soundcard)
{ {
if (!soundcard) if (!soundcard)
return; return;
soundcard_ctl_switch_free(soundcard->control.switches); soundcard_ctl_control_free(soundcard->control.controls);
soundcard_mixer_free(soundcard->mixers);
soundcard_pcm_free(soundcard->pcms);
soundcard_rawmidi_free(soundcard->rawmidis);
free(soundcard); free(soundcard);
} }
@ -205,77 +118,74 @@ void soundcard_setup_done(void)
soundcards = NULL; 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; int err, idx;
snd_switch_list_t list; snd_control_list_t list;
snd_switch_list_item_t *item; snd_control_id_t *item;
snd_switch_t sw; snd_control_t ctl;
struct ctl_switch *prev_csw; struct ctl_control *prev_control;
struct ctl_switch *new_csw; struct ctl_control *new_control;
*csw = NULL; *cctl = NULL;
bzero(&list, sizeof(list)); bzero(&list, sizeof(list));
list.iface = iface; if ((err = snd_ctl_clist(handle, &list)) < 0) {
list.device = device; error("Cannot determine controls: %s", snd_strerror(err));
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));
return 1; return 1;
} }
if (list.switches_over <= 0) if (list.controls <= 0)
return 0; return 0;
list.switches_size = list.switches_over + 16; list.controls_request = list.controls + 16;
list.switches = list.switches_over = 0; list.controls_offset = list.controls_count = 0;
list.pswitches = malloc(sizeof(snd_switch_list_item_t) * list.switches_size); list.pids = malloc(sizeof(snd_control_id_t) * list.controls_request);
if (!list.pswitches) { if (!list.pids) {
error("No enough memory..."); error("No enough memory...");
return 1; return 1;
} }
if ((err = snd_ctl_switch_list(handle, &list)) < 0) { if ((err = snd_ctl_clist(handle, &list)) < 0) {
error("Cannot determine switches (2) for interface %i and device %i and stream %i: %s", iface, device, stream, snd_strerror(err)); error("Cannot determine controls (2): %s", snd_strerror(err));
return 1; return 1;
} }
for (idx = 0, prev_csw = NULL; idx < list.switches; idx++) { for (idx = 0, prev_control = NULL; idx < list.controls_count; idx++) {
item = &list.pswitches[idx]; item = &list.pids[idx];
bzero(&sw, sizeof(sw)); bzero(&ctl, sizeof(ctl));
sw.iface = iface; ctl.id = *item;
sw.device = device; if ((err = snd_ctl_cread(handle, &ctl)) < 0) {
sw.stream = stream; error("Cannot read control '%s': %s", control_id(item), snd_strerror(err));
strncpy(sw.name, item->name, sizeof(sw.name)); free(list.pids);
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);
return 1; return 1;
} }
new_csw = malloc(sizeof(*new_csw)); new_control = malloc(sizeof(*new_control));
if (!new_csw) { if (!new_control) {
error("No enough memory..."); error("No enough memory...");
free(list.pswitches); free(list.pids);
return 1; return 1;
} }
bzero(new_csw, sizeof(*new_csw)); bzero(new_control, sizeof(*new_control));
memcpy(&new_csw->s, &sw, sizeof(new_csw->s)); memcpy(&new_control->c, &ctl, sizeof(new_control->c));
if (*csw) { new_control->info.id = ctl.id;
prev_csw->next = new_csw; if ((err = snd_ctl_cinfo(handle, &new_control->info)) < 0) {
prev_csw = new_csw; 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 { } else {
*csw = prev_csw = new_csw; *cctl = prev_control = new_control;
} }
} }
free(list.pswitches); free(list.pids);
return 0; return 0;
} }
static int soundcard_setup_collect_switches1(int cardno) static int soundcard_setup_collect_controls1(int cardno)
{ {
snd_ctl_t *handle; snd_ctl_t *handle;
snd_mixer_t *mhandle;
struct soundcard *card, *first, *prev; struct soundcard *card, *first, *prev;
int err, device; int err;
struct mixer *mixer, *mixerprev;
struct pcm *pcm, *pcmprev;
struct rawmidi *rawmidi, *rawmidiprev;
soundcard_remove(cardno); soundcard_remove(cardno);
if ((err = snd_ctl_open(&handle, cardno)) < 0) { if ((err = snd_ctl_open(&handle, cardno)) < 0) {
@ -316,125 +226,28 @@ static int soundcard_setup_collect_switches1(int cardno)
return 1; 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); snd_ctl_close(handle);
return 1; 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); snd_ctl_close(handle);
return 0; return 0;
} }
int soundcard_setup_collect_switches(int cardno) int soundcard_setup_collect_controls(int cardno)
{ {
int err; int err;
unsigned int mask; unsigned int mask;
if (cardno >= 0) { if (cardno >= 0) {
return soundcard_setup_collect_switches1(cardno); return soundcard_setup_collect_controls1(cardno);
} else { } else {
mask = snd_cards_mask(); mask = snd_cards_mask();
for (cardno = 0; cardno < SND_CARDS; cardno++) { for (cardno = 0; cardno < SND_CARDS; cardno++) {
if (!(mask & (1 << cardno))) if (!(mask & (1 << cardno)))
continue; continue;
err = soundcard_setup_collect_switches1(cardno); err = soundcard_setup_collect_controls1(cardno);
if (err) if (err)
return 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) int soundcard_setup_load(const char *cfgfile, int skip)
{ {
extern int yyparse(void); extern int yyparse(void);
extern int linecount; extern int linecount;
extern FILE *yyin; extern FILE *yyin;
#ifdef YYDEBUG
extern int yydebug; extern int yydebug;
#endif
int xtry; int xtry;
#ifdef YYDEBUG #ifdef YYDEBUG
@ -579,268 +286,98 @@ int soundcard_setup_load(const char *cfgfile, int skip)
return 0; 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]; char *s, v[16];
int idx, first, switchok = 0; int err, idx;
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";
}
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_ctl_t *handle;
snd_switch_t swi; snd_control_info_t info;
memset(&swi, 0, sizeof(swi));
swi.iface = sw->iface; memcpy(&info, &control->info, sizeof(info));
swi.device = sw->device; v[0] = '\0';
swi.stream = sw->stream; switch (info.type) {
strncpy(swi.name, sw->name, sizeof(swi.name)); case SND_CONTROL_TYPE_BOOLEAN: s = "bool"; break;
swi.type = SND_SW_TYPE_LIST_ITEM; case SND_CONTROL_TYPE_INTEGER: s = "integer"; break;
if (snd_ctl_open(&handle, card) >= 0) { case SND_CONTROL_TYPE_ENUMERATED: s = "enumerated"; break;
for (idx = sw->low; idx <= sw->high; idx++) { case SND_CONTROL_TYPE_BYTES: s = "bytes"; break;
swi.low = swi.high = idx; default: s = "unknown";
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); snd_ctl_close(handle);
} }
}
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]);
}
}
}
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; break;
default: default:
break; break;
} }
if (sw->value.data16[5] & 0x0020) switch (info.id.iface) {
fprintf(out, ",fsunlock"); case SND_CONTROL_IFACE_CARD: s = "global"; break;
fprintf(out, ",type(0x%x)", (sw->value.data16[5] >> 6) & 0x7f); case SND_CONTROL_IFACE_HWDEP: s = "hwdep"; break;
if (sw->value.data16[5] & 0x2000) case SND_CONTROL_IFACE_MIXER: s = "mixer"; break;
fprintf(out, ",gstatus"); case SND_CONTROL_IFACE_PCM: s = "pcm"; break;
fprintf(out, ")"); case SND_CONTROL_IFACE_RAWMIDI: s = "rawmidi"; break;
goto __end; 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);
fprintf(out, "%sswitch(\"%s\", ", space, sw->name); if (info.type == SND_CONTROL_TYPE_BYTES)
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(@"); fprintf(out, "rawdata(@");
for (idx = 0; idx < 31; idx++) { for (idx = 0; idx < info.values_count; idx++) {
fprintf(out, "%02x:", sw->value.data8[idx]); switch (info.type) {
} case SND_CONTROL_TYPE_BOOLEAN:
fprintf(out, "%02x@)", sw->value.data8[31]); 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;
} }
} }
__end: if (info.type == SND_CONTROL_TYPE_BYTES)
fprintf(out, ")");
fprintf(out, ")\n"); 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; return;
for (sw = *switches; sw; sw = sw->next) for (ctl = *controls; ctl; ctl = ctl->next)
soundcard_setup_write_switch(out, space, card, interface, &sw->s); soundcard_setup_write_control(out, space, card, ctl);
}
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));
}
} }
#define MAX_LINE (32 * 1024) #define MAX_LINE (32 * 1024)
@ -850,10 +387,6 @@ int soundcard_setup_write(const char *cfgfile, int cardno)
FILE *out, *out1, *out2, *in; FILE *out, *out1, *out2, *in;
char *tmpfile1, *tmpfile2; char *tmpfile1, *tmpfile2;
struct soundcard *first, *sel = NULL; 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; char *line, cardname[sizeof(first->control.hwinfo.name)+16], *ptr1;
int mark, size, ok; int mark, size, ok;
@ -904,49 +437,8 @@ int soundcard_setup_write(const char *cfgfile, int cardno)
continue; continue;
sel = first; sel = first;
fprintf(out, "soundcard(\"%s\") {\n", first->control.hwinfo.id); fprintf(out, "soundcard(\"%s\") {\n", first->control.hwinfo.id);
if (first->control.switches) { if (first->control.controls) {
fprintf(out, " control {\n"); soundcard_setup_write_controls(out, " ", first->no, &first->control.controls);
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");
} }
fprintf(out, "}\n%s", cardno < 0 && first->next ? "\n" : ""); fprintf(out, "}\n%s", cardno < 0 && first->next ? "\n" : "");
} }

View file

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

File diff suppressed because it is too large Load diff